如何在 MASM 中编写远绝对 JMP/CALL 指令?
How to code a far absolute JMP/CALL instruction in MASM?
如何使用 MASM 编写远绝对 JMP 或 CALL 指令?具体来说,我如何让它使用 EA 和 CA 操作码发出这些指令,而不使用 DB 或其他数据指令手动发出它们?
例如,考虑跳转到引导扇区中 FFFF:0000 处的 BIOS 重置入口点的情况。如果我使用 NASM,我可以用一条指令以显而易见的方式编写代码:
jmp 0xffff:0
在 GNU assembler 中,语法不太明显,但以下内容可以完成工作:
jmp 0xffff, 0
然而,当我尝试使用 MASM 的明显解决方案时:
jmp 0ffffh:0
我收到以下错误:
t206b.asm(3) : error A2096:segment, group, or segment register expected
我试图避免的解决方法
我可以在 MASM 中使用许多可能的解决方法,例如以下任何一种:
手动 assemble 指令,手动发出机器码:
DB 0EAh, 0, 0, 0FFh, 0FFh
使用远间接跳转:
bios_reset DD 0ffff0000h
...
jmp bios_reset ; FF 2E opcode: indirect far jump
或者将地址压入栈中,用far RET指令"return"给它:
push 0ffffh
push 0
retf
但是无论如何我可以使用实际的 JMP 指令并让 MASM 生成正确的操作码 (EA) 吗?
有一种方法可以做到,但您需要使用 MASM 的 /omf
开关,以便它生成 OMF 格式的目标文件。这意味着目标文件需要与 OMF 兼容的链接器链接,例如 Microsoft 的旧分段链接器(而不是他们当前的 32 位链接器)。
要做到这一点,您需要使用 MASM 的一个很少使用且不太了解的功能,即 SEGMENT
指令的 AT <i>address</i>
属性。 AT
属性告诉链接器该段位于内存中的固定段落地址,由 <i>address</i>
给出。它还告诉链接器丢弃该段,这意味着不使用该段的内容,只使用它的标签。这也是必须使用 /omf
开关的原因。 MASM 的默认对象文件格式 PECOFF 不支持此格式。
AT
属性给出了我们要跳转到的地址的you段部分。要获得偏移部分,您需要做的就是在段内使用 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
我一直在用 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
您是否考虑过使用 __emit 伪指令?
https://msdn.microsoft.com/en-us/library/1b80826t.aspx
我曾经不得不使用内联汇编程序来编写远跳代码。我不记得远跳的操作码,但你可以这样做
__emit 0eah
__emit 0
__emit 0
__emit 0
__emit 0
__emit 8h
__emit 0
如何使用 MASM 编写远绝对 JMP 或 CALL 指令?具体来说,我如何让它使用 EA 和 CA 操作码发出这些指令,而不使用 DB 或其他数据指令手动发出它们?
例如,考虑跳转到引导扇区中 FFFF:0000 处的 BIOS 重置入口点的情况。如果我使用 NASM,我可以用一条指令以显而易见的方式编写代码:
jmp 0xffff:0
在 GNU assembler 中,语法不太明显,但以下内容可以完成工作:
jmp 0xffff, 0
然而,当我尝试使用 MASM 的明显解决方案时:
jmp 0ffffh:0
我收到以下错误:
t206b.asm(3) : error A2096:segment, group, or segment register expected
我试图避免的解决方法
我可以在 MASM 中使用许多可能的解决方法,例如以下任何一种:
手动 assemble 指令,手动发出机器码:
DB 0EAh, 0, 0, 0FFh, 0FFh
使用远间接跳转:
bios_reset DD 0ffff0000h
...
jmp bios_reset ; FF 2E opcode: indirect far jump
或者将地址压入栈中,用far RET指令"return"给它:
push 0ffffh
push 0
retf
但是无论如何我可以使用实际的 JMP 指令并让 MASM 生成正确的操作码 (EA) 吗?
有一种方法可以做到,但您需要使用 MASM 的 /omf
开关,以便它生成 OMF 格式的目标文件。这意味着目标文件需要与 OMF 兼容的链接器链接,例如 Microsoft 的旧分段链接器(而不是他们当前的 32 位链接器)。
要做到这一点,您需要使用 MASM 的一个很少使用且不太了解的功能,即 SEGMENT
指令的 AT <i>address</i>
属性。 AT
属性告诉链接器该段位于内存中的固定段落地址,由 <i>address</i>
给出。它还告诉链接器丢弃该段,这意味着不使用该段的内容,只使用它的标签。这也是必须使用 /omf
开关的原因。 MASM 的默认对象文件格式 PECOFF 不支持此格式。
AT
属性给出了我们要跳转到的地址的you段部分。要获得偏移部分,您需要做的就是在段内使用 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
我一直在用 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
您是否考虑过使用 __emit 伪指令?
https://msdn.microsoft.com/en-us/library/1b80826t.aspx
我曾经不得不使用内联汇编程序来编写远跳代码。我不记得远跳的操作码,但你可以这样做
__emit 0eah
__emit 0
__emit 0
__emit 0
__emit 0
__emit 8h
__emit 0