如何在 MASM 中编写远绝对 JMP/CALL 指令? [英] How to code a far absolute JMP/CALL instruction in MASM?

查看:30
本文介绍了如何在 MASM 中编写远绝对 JMP/CALL 指令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How can I write a far absolute JMP or CALL instruction using MASM? Specifically how do I get it to emit these instruction using the EA and CA opcodes, without manually emitting them using DB or other data directives?

例如,考虑跳转到引导扇区中 FFFF:0000 处的 BIOS 重置入口点的情况.如果我使用 NASM,我可以以一种显而易见的方式在一条指令中对此进行编码:

For example consider the case of jumping to the BIOS reset entry point at FFFF:0000 in a boot sector. If I were using NASM I could code this in one instruction in the obvious way:

jmp 0xffff:0

使用 GNU 汇编器时,语法不那么明显,但以下内容可以完成这项工作:

With the GNU assembler the syntax is less obvious, but the following will do the job:

jmp 0xffff, 0

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

However when I try the obvious solution with MASM:

jmp 0ffffh:0

我收到以下错误:

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

我试图避免的解决方法

我可以在 MASM 中使用许多可能的解决方法,例如以下任何一种:

Workarounds I'm trying to avoid

There are a number of possible workarounds I could use in MASM, like any of the following:

手工汇编指令,手工发出机器码:

Hand assemble the instruction, emitting the machine code manually:

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

使用远间接跳转:

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

或者将地址压入栈中,使用远RET指令返回":

Or push the address on the stack and use a far RET instruction to "return" to it:

    push 0ffffh
    push 0
    retf

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

But is there anyway I can use an actual JMP instruction and have MASM generate the right opcode (EA)?

推荐答案

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

There's one way you can do it, but you need to use MASM's /omf switch so that it generates object files in the OMF format. This means the object files need to be linked with an OMF compatible linker, like Microsoft's old segmented linker (and not their current 32-bit linker.)

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

To do it you need to use a rarely used and not well understood feature of MASM, the SEGMENT directive's AT address attribute. The AT attribute tells linker that the segment lives at a fixed paragraph address in memory, as given by address. It also tells the linker to discard the segment, meaning the contents of the segment aren't used, just its labels. This is also why the /omf switch has to be used. MASM's default object file format, PECOFF, doesn't support this.

AT 属性给出了我们想要跳转到的地址的你段部分.要获得偏移部分,您需要做的就是在段内使用 LABEL 指令.结合 ORG 指令,您可以在特定段中的特定偏移量处创建标签.然后您需要做的就是在 JMP 或 CALL 指令中使用这个标签.

The AT attribute gives the you segment part of the address we want to jump to. To get the offset part all you need to do is use the LABEL directive inside the segment. Combined with the ORG directive, this lets you create a label at the specific offset in the specific segment. All you then need to do is use this label in the JMP or CALL instruction.

例如,如果您想跳转到 BIOS 重置程序,您可以这样做:

For example if you want to jump to the BIOS reset routine you can do this:

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 的引导加载程序的第二阶段:

Or if you want to call the second stage part of your boot loader whose entry point is at 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 中编写远绝对 JMP/CALL 指令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆