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

查看:145
本文介绍了如何在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.)

要执行此操作,您需要使用SEGMENT指令的AT address属性的MASM很少使用且不为人所理解的功能. 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天全站免登陆