3

我正在编写一些汇编代码(英特尔),但我不明白为什么当我尝试创建共享库时这段代码不起作用:

BITS 64
SECTION .text
GLOBAL test
test:
push rbp
mov  rbp, rsp

mov rax, 3
mov  al, BYTE [rel array + rax]

pop  rbp
ret

SECTION  .data
array times 256 db 0

而如果您通过使用数字更改寄存器来修改带有“mov”的行,则它可以工作:

mov  al, BYTE [rel array + 3]

我对 nasm 没有任何错误,但是当我尝试使用 ld 链接并创建共享库时:

重定位 R_X86_64_32S 对 `.data' 在制作共享对象时不能使用;使用 -fPIC 重新编译

我找到了“R_X86_64_32S”错误的答案:C++ 链接在实践中如何工作?

但是我不明白为什么我不能使用“rax”作为偏移量,而我可以使用数字。

有没有办法浏览思想数组?

这是我用来创建共享库的命令:

nasm -f elf64 test.s
ld -shared test.o -o test.so
4

1 回答 1

3

通过长模式(64 位模式),AMD 将rip相对寻址引入了 x86。如果你输入

mov  al, BYTE [rel array + 3]

汇编器生成一个内存操作数

mov  al, BYTE [array + 3 - $ + rip]

这意味着当机器代码被加载到不同的地址时,内存操作数仍然会到达正确的位置,因为只有array它被引用的指令的相对偏移量被编码,而不是 的绝对地址array,这是未知的在链接时。

现在,使用索引寄存器时链接失败的原因是这种新的寻址模式取代了以前的寻址disp32模式(modr/m byte 05 +r)。它不适用于 SIB (scale/index/base) 寻址模式(实际上,之前的disp32寻址模式仍然可以通过既没有 base 也没有索引的 SIB 操作数获得),因此汇编器无法为位置生成适当的内存操作数独立代码。

解决方案是首先使用将绝对地址加载array到某个寄存器中lea,然后访问相对于刚刚加载的地址的数组成员:

lea rbx, [rel array]
mov al, byte [rbx + rax]
于 2018-03-20T17:41:50.277 回答