为什么我不能使用寄存器作为偏移来访问数组?

时间:2018-03-20 17:25:31

标签: arrays assembly shared-libraries x86-64 position-independent-code

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

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链接并创建共享库时:

  

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

我找到了" R_X86_64_32S"错误:How does C++ linking work in practice?

但是我不明白为什么我不能使用" rax"作为一个偏移,而我可以用一个数字。

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

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

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

1 个答案:

答案 0 :(得分:3)

在长模式(64位模式)下,AMD向x86引入了rip相对寻址。如果您输入

mov  al, BYTE [rel array + 3]

汇编程序生成一个内存操作数以实现

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

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

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

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

lea rbx, [rel array]
mov al, byte [rbx + rax]