我有以下代码:
.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.................................^
为什么我收到此错误?
答案 0 :(得分:1)
您的call #0x0
似乎在as86中指定了一个IP(指令指针) - 相对调用(相对于下一条指令的偏移量)。这是故意的吗? as86可能会抱怨,因为它需要一个标签或符号,如果需要,链接器可以解析(重新定位)。
as86手册页包含以下内容:
'near'和'far'不允许多段编程,所有'远' 通过使用指令明确指定操作:jmpi, jmpf,callf,retf等.'Near'运算符可用于强制使用 80386 16bit条件分支。 'Dword'和'word'操作符可以控制 跳远和呼叫的操作数大小。
如果我改为使用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生成一个相对call
,它与你想要做的相同(不确定这是否有意义) - 你可能从任何IP碰巧得到随机位),那么你可以做到以下几点:
eseg
call zero_offset
zero_offset: pop bx
输出
53: 26 e8 00 00 es call 0x57
,其中00 00
部分显示偏移为0。
答案 1 :(得分:0)
我不认为在通话前设置cs是一个好主意,被叫程序不知道如何返回。你必须执行一个远程呼叫, 呼叫段:偏移量。这将推送堆栈上的ip和cs寄存器的值以返回。对于你的代码类似:call cs:0x00 esag是x86指令吗?
Se this链接