Assembly MASM:不重新定位的强制偏移指令
我正在用MASM for DOS编写一个多模块组装项目。特别是,我想做一个非常简单的DOS,比如操作系统 我有几个这样定义的片段Assembly MASM:不重新定位的强制偏移指令,assembly,dos,masm,Assembly,Dos,Masm,我正在用MASM for DOS编写一个多模块组装项目。特别是,我想做一个非常简单的DOS,比如操作系统 我有几个这样定义的片段 fileseg segment byte public 'code' fileseg ends memseg segment byte public 'code' memseg ends diskseg segment byte public 'code' diskseg ends bootseg segment byte public 'code' boots
fileseg segment byte public 'code'
fileseg ends
memseg segment byte public 'code'
memseg ends
diskseg segment byte public 'code'
diskseg ends
bootseg segment byte public 'code'
bootseg ends
正如您所看到的,它们都是字节对齐的(设计决策)。此外,我还有一个cseg小组,包括上述所有部分
cseg group fileseg, memseg, diskseg, bootseg, ...
因此,当我想引用一个公共标签时,无论它是在不同的部分中定义的,我都会做如下操作:
assume ds:cseg, es:cseg, ss:cseg
mov si, offset label_in_this_segment
mov bx, offset label_in_another_segment
它将得到cseg中的“全局”偏移量,这是正确的。但是,当您编写一些需要在固定位置执行的代码时,就会出现问题,例如启动扇区,它在0000:7C00h(在我的例子中是07C0:0)执行
所以我这样写:
bootseg segment byte public 'code'
; Want all data references to be relative to this segment, not CSEG
assume ds:bootseg
boot_start::
jmp start
boot_data t_bootloader_data <>
start:
; make IP point to 0000h
mov ax, 07C0h
push ax
mov ax, offset ds:real_start ; "BAD" offset
push ax
retf
real_start:
mov ax, cs
mov ds, ax
...
bootseg segment byte public 'code'
assume ds:bootseg
boot_start::
jmp start
; ...
start:
jmp real_start_abs
real_start:
mov ax, cs
mov ds, ax
; ...
bootseg ENDS
bootseg_abs SEGMENT USE16 AT 07c0h
ORG (real_start - boot_start)
real_start_abs LABEL FAR
bootseg_abs ENDS
bootseg段字节公共“代码”
; 希望所有数据引用都与此段相关,而不是CSEG
假设ds:bootseg
启动启动::
jmp启动
启动数据启动加载程序启动数据
开始:
; 使IP指向0000h
mov ax,07C0h
推斧
mov ax,offset ds:real_start;“坏”偏移量
推斧
翻新
真正的开始:
mov-ax,cs
mov-ds,ax
...
我在引号中加上“BAD”,因为MASM实际上做得很好,因为bootseg也是cseg
组的一部分(因为boot_data
它是从一些其他段引用的),所以链接器将“real_start”标记为可重定位的
所以问题是:我如何告诉汇编程序我希望real\u start
与bootseg
本身相抵消
我尝试了一些有效的技巧,比如让bootseg
成为定义的第一个段,或者让它与段落对齐,但这些对我来说似乎有点不太对劲
我还试图将
bootseg
从cseg组中移出,但在将引导扇区写入磁盘之前,我需要从其他段引用boot\u数据。您可以通过在符号前面加段:
来指定要偏移的相对段。例如:
mov ax, offset bootseg:real_start
但是,这不起作用,因为您使用的是字节对齐,所以段有两个不同的起始地址。在实模式中,段必须与段落(16字节)对齐,因此链接器将起始bootseg
向下舍入到最近的段落边界,然后调整任何偏移量以相对于新的起始地址。因为当bootseg实际加载并执行时,它实际上启动了一个段落边界,这意味着所有调整的偏移量都不正确
请注意,它不仅限于OFFSET指令,还包括对bootseg
中地址的任何绝对引用。你应该考虑制作<代码> BooTeSG < /代码> PARA对齐。
如果仍要使用字节对齐,则需要自己计算偏移量:
mov ax, real_start - boot_start
请注意,由于您的目标是80286处理器,因此可以改为:
push real_start - boot_start
PUSH immediate指令是通过80186引入x86体系结构的
如果在bootseg
中有这样的绝对引用:
mov al, [boot_data.foo]
在执行引导扇区时,您需要将其更改为这样的值,以使偏移量正确:
mov al, BYTE PTR ds:[boot_data.foo - boot_start]
最后,您可以避免整个PUSH/RETF无意义,直接在MASM中编写如下代码:
bootseg segment byte public 'code'
; Want all data references to be relative to this segment, not CSEG
assume ds:bootseg
boot_start::
jmp start
boot_data t_bootloader_data <>
start:
; make IP point to 0000h
mov ax, 07C0h
push ax
mov ax, offset ds:real_start ; "BAD" offset
push ax
retf
real_start:
mov ax, cs
mov ds, ax
...
bootseg segment byte public 'code'
assume ds:bootseg
boot_start::
jmp start
; ...
start:
jmp real_start_abs
real_start:
mov ax, cs
mov ds, ax
; ...
bootseg ENDS
bootseg_abs SEGMENT USE16 AT 07c0h
ORG (real_start - boot_start)
real_start_abs LABEL FAR
bootseg_abs ENDS
通过在符号前面加上段:
,可以指定要偏移的相对段。例如:
mov ax, offset bootseg:real_start
但是,这不起作用,因为您使用的是字节对齐,所以段有两个不同的起始地址。在实模式中,段必须与段落(16字节)对齐,因此链接器将起始bootseg
向下舍入到最近的段落边界,然后调整任何偏移量以相对于新的起始地址。因为当bootseg实际加载并执行时,它实际上启动了一个段落边界,这意味着所有调整的偏移量都不正确
请注意,它不仅限于OFFSET指令,还包括对bootseg
中地址的任何绝对引用。你应该考虑制作<代码> BooTeSG < /代码> PARA对齐。
如果仍要使用字节对齐,则需要自己计算偏移量:
mov ax, real_start - boot_start
请注意,由于您的目标是80286处理器,因此可以改为:
push real_start - boot_start
PUSH immediate指令是通过80186引入x86体系结构的
如果在bootseg
中有这样的绝对引用:
mov al, [boot_data.foo]
在执行引导扇区时,您需要将其更改为这样的值,以使偏移量正确:
mov al, BYTE PTR ds:[boot_data.foo - boot_start]
最后,您可以避免整个PUSH/RETF无意义,直接在MASM中编写如下代码:
bootseg segment byte public 'code'
; Want all data references to be relative to this segment, not CSEG
assume ds:bootseg
boot_start::
jmp start
boot_data t_bootloader_data <>
start:
; make IP point to 0000h
mov ax, 07C0h
push ax
mov ax, offset ds:real_start ; "BAD" offset
push ax
retf
real_start:
mov ax, cs
mov ds, ax
...
bootseg segment byte public 'code'
assume ds:bootseg
boot_start::
jmp start
; ...
start:
jmp real_start_abs
real_start:
mov ax, cs
mov ds, ax
; ...
bootseg ENDS
bootseg_abs SEGMENT USE16 AT 07c0h
ORG (real_start - boot_start)
real_start_abs LABEL FAR
bootseg_abs ENDS
问题是:bootseg有两个值:启动时和跳远后。你可以做一个补偿差。(在两个cs上都有效且相同)并使用该值。不要试图让MASM了解偏移量。如果这是正确的语法(而不是push/push/retf的东西,那么可以做一些类似于jmp 07C0h:(real\u start-start)
的事情。IDK如果在到达real\u start
后不打算利用AX中仍然存在的值,那么为什么要使用AX呢@彼得命令它是为.286编译的,因此既不能写入jmp XXXX:XXXX,也不能推送立即数。@Trap 80286最肯定的是jmp far ptr16:16
指令。是的,你可以使用它。如果你的问题解决了你的实际问题,不用仔细研究,直接的答案是使用OFFSET bootseg:real\u start
。至于如何让MASM生成到特定固定段和偏移量的跳远,请参见以下问题:问题:bootseg有两个值:启动时和跳远后。你可以做一个补偿差。(在两个cs上都有效且相同)并使用该值。不要试图让MASM了解偏移量。也许可以做一些类似于jmp 07C0h:(rea