我有以下代码:
.global _launchProgram
_launchProgram:
push bp
mov bp, sp
push cs
mov bx, [bp + 4]
mov cs, bx
mov es, bx
eseg
call #0x0
pop bx
mov cs, bx
pop bp
ret
在这段代码中,我试图让它跳转到另一段代码并执行它。从 C 调用此代码,如下所示:
launchProgram(segment) //Here segment is an integer which holds the
//memory segment where I have loaded my code
因此在这个函数中,我使 cs 寄存器等于段变量,并使用 call 0x0
跳转到该段的开头。但是当我运行它时使用:
as86 launchProgram.asm -o launchProgram.o
我收到以下错误:
00010 000C E8 0000 call #0x0
***** relocation impossible.................................^
为什么会出现此错误?
最佳答案
您的call #0x0
似乎在 as86 中指定了一个 IP(指令指针)相对调用(相对于下一条指令的偏移量)。那是故意的吗? as86 可能会提示,因为它需要一个标签或符号,而不是链接器可以在需要时解析(重新定位)。
as86 手册页具有以下内容:
The 'near and 'far' do not allow multi-segment programming, all 'far' operations are specified explicitly through the use of the instructions: jmpi, jmpf, callf, retf, etc. The 'Near' operator can be used to force the use of 80386 16bit conditional branches. The 'Dword' and 'word' operators can control the size of operands on far jumps and calls.
如果我改用 callf 0x12345678,0x1234
,代码将进行汇编,生成以下指令:
$ as86 a.asm -o a.o
$ objdump -D -b binary -mi386 -Maddr16,data16,intel a.o
...
3b: 8e cb mov cs,bx
3d: 8e c3 mov es,bx
3f: 26 66 9a 78 56 34 12 es call 0x1234:0x12345678
46: 34 12
48: 5b pop bx
48: 5b pop %bx
...
(-b binary
它需要,因为它是原始代码,-mi386
选择指令集,-Maddr16,data16,intel
选择Intel 语法和 16 位代码,这似乎是 as86 默认生成的。)
callf
的第二个操作数似乎是地址的段选择器部分(callf
有一个操作数会导致 as86 报错)。我的 x86-fu 太弱了,无法说明调用中的段覆盖是否真的有意义。当然,您需要在代码中callf#0x0,#0x0
。
如果你想“欺骗”as86 生成一个与你正在尝试做的相同的相对调用
(不确定这是否有意义 - 你可能会从任何 IP 获得随机位恰好是),那么您可以执行以下操作:
eseg
call zero_offset
zero_offset: pop bx
输出是
53: 26 e8 00 00 es call 0x57
,其中00 00
部分表示偏移量为0。
关于c - 在 x86 Assembly 中组装代码时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29059030/