如何在MASM中编写远绝对JMP / CALL指令?

时间:2015-09-22 01:06:02

标签: assembly x86 masm

如何使用MASM编写远绝对JMP或CALL指令?具体来说,如何使用EA和CA操作码发出这些指令,而无需使用DB或其他数据指令手动发出这些指令?

例如,考虑在引导扇区中跳转到FFFF:0000的BIOS复位入口点的情况。如果我使用NASM,我可以用一个明显的方式在一条指令中对此进行编码:

jmp 0xffff:0

使用GNU汇编程序时,语法不太明显,但以下内容将完成此任务:

jmp 0xffff, 0

然而,当我尝试使用MASM的明显解决方案时:

jmp 0ffffh:0

我收到以下错误:

t206b.asm(3) : error A2096:segment, group, or segment register expected

我试图避免

的变通办法

我可以在MASM中使用多种可能的解决方法,如下所示:

手动组装指令,手动发出机器代码:

    DB 0EAh, 0, 0, 0FFh, 0FFh

使用远距离间接跳转:

bios_reset DD 0ffff0000h
    ...
    jmp bios_reset   ; FF 2E opcode: indirect far jump

或者推送堆栈上的地址并使用远RET指令来"返回"它:

    push 0ffffh
    push 0
    retf

但是,无论如何我可以使用实际的JMP指令并让MASM生成正确的操作码(EA)吗?

3 个答案:

答案 0 :(得分:4)

有一种方法可以做到,但你需要使用MASM的/omf开关,以便它以OMF格式生成目标文件。这意味着目标文件需要与OMF兼容的链接器链接,例如Microsoft的旧分段链接器(而不是它们当前的32位链接器。)

要做到这一点,您需要使用MASM的一个很少使用且不太清楚的功能,即SEGMENT指令的AT address属性。 AT属性告诉链接器该段位于内存中的固定段落地址,由address给出。它还告诉链接器丢弃该段,这意味着段的内容不会被使用,只是它的标签。这也是必须使用/omf开关的原因。 MASM的默认目标文件格式PECOFF不支持此功能。

AT属性为您提供我们要跳转到的地址的细分部分。要获得偏移部分,您需要做的就是在段内使用LABEL指令。结合ORG指令,您可以在特定段的特定偏移处创建标签。您需要做的就是在JMP或CALL指令中使用此标签。

例如,如果要跳转到BIOS重置例程,可以执行以下操作:

bios_reset_seg SEGMENT USE16 AT 0ffffh
bios_reset LABEL FAR
bios_reset_seg ENDS

_TEXT SEGMENT USE16 'CODE'
    jmp bios_reset
_TEXT ENDS

或者,如果要调用引导加载程序的第二阶段部分,其入口点为0000:7E00:

zero_seg SEGMENT USE16 AT 0
    ORG 7e00h
second_stage LABEL FAR
zero_seg ENDS

_TEXT SEGMENT USE16 'CODE'
    call second_stage
_TEXT ENDS

答案 1 :(得分:0)

我一直在测试MASM 6.15这段代码,我想这可以帮到你。

    .model small
    .386
    .stack 100h

    .DATA
     Message    DB  'hello','$'
     JMPPOS DB  78h,56h,34h,12h  ;the address to be jumped to  1234:5678

    .code
    .startup

     JMP  dword  ptr [JMPPOS]

    .exit
    END

答案 2 :(得分:0)

您是否考虑过使用__emit伪指令?

https://msdn.microsoft.com/en-us/library/1b80826t.aspx

我曾经不得不使用内联汇编程序来编写远程跳转代码。我不记得跳远的操作码,但你可以做这样的事情

__emit      0eah
__emit      0
__emit      0
__emit      0
__emit      0
__emit      8h
__emit      0