1

我有以下代码:

.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.................................^

为什么我会收到此错误?

4

2 回答 2

1

call #0x0似乎在 as86 中指定了一个与 IP(指令指针)相关的调用(相对于下一条指令的偏移量)。那是故意的吗?as86 可能会抱怨,因为它需要一个标签或一个符号,如果需要,链接器将能够解析(重定位)。

as86 手册页有以下内容:

“near”和“far”不允许多段编程,所有“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。

于 2015-03-15T12:45:19.030 回答
0

我认为在调用之前设置 cs 不是一个好主意,被调用的过程不知道如何返回。你必须执行一个远调用,调用segment:offset。这会将 ip 和 cs 寄存器的值压入堆栈以供返回。对于您的代码,例如: call cs:0x00 esag 也是 x86 指令吗?

这个链接

于 2015-03-15T10:17:45.970 回答