Arrays 为什么可以';我不能用寄存器作为偏移量访问数组吗?
我正在编写一些汇编代码(英特尔),但我不明白为什么在尝试创建共享库时此代码不起作用:Arrays 为什么可以';我不能用寄存器作为偏移量访问数组吗?,arrays,assembly,shared-libraries,x86-64,position-independent-code,Arrays,Assembly,Shared Libraries,X86 64,Position Independent Code,我正在编写一些汇编代码(英特尔),但我不明白为什么在尝试创建共享库时此代码不起作用: 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 nasm -f elf64 test.s ld -shared test.o -o test.s
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
nasm -f elf64 test.s
ld -shared test.o -o test.so
然而,如果您通过更改带有数字的寄存器来修改带有“mov”的行,则它可以工作:
mov al, BYTE [rel array + 3]
nasm没有任何错误,但当我尝试使用ld链接并创建共享库时:
在进行更改时,无法使用针对“.data”的重新定位R_X86_64_32S
共享对象;用-fPIC重新编译
我找到了“R_X86_64_32S”错误的答案:
但我不明白的是,为什么我不能使用“rax”作为偏移量,而我可以使用数字
有没有办法浏览阵列
以下是我用于创建共享库的命令:
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
nasm -f elf64 test.s
ld -shared test.o -o test.so
在长模式(64位模式)下,AMD引入了相对于x86的rip
寻址。如果你打字
mov al, BYTE [rel array + 3]
汇编程序生成一个内存操作数,效果如下
mov al, BYTE [array + 3 - $ + rip]
这意味着,当机器代码加载到不同的地址时,内存操作数仍然会转到正确的位置,因为只有数组
相对于它引用的指令的相对偏移量被编码,而不是数组
的绝对地址,这在链接时是未知的
现在,使用索引寄存器时链接失败的原因是,这种新的寻址模式取代了以前的disp32
寻址模式(modr/m byte05+r
)。SIB(缩放/索引/基)寻址模式不可用(事实上,以前的disp32
寻址模式仍然可以通过既没有基也没有索引的SIB操作数使用),因此汇编程序无法为位置无关代码生成适当的内存操作数
解决方案是首先使用lea
将array
的绝对地址加载到某个寄存器中,然后访问与刚刚加载的地址相关的数组成员:
lea rbx, [rel array]
mov al, byte [rbx + rax]
如果nasm没有为
[rel array+rax]
生成错误,那么它就是一个bug。它应该告诉您这是一个无效的寻址模式。@fuz-thx的答案,但要知道,如果您使用gcc来生成二进制文件,它是有效的,为什么?gcc需要进行链接并且应该失败吗?[array+3-$+rip]
也不太正确$
是当前指令的开始,但RIP相对寻址是相对于指令的结束(即下一条指令的开始)。@PeterCordes我知道。然而,添加这一点会有点复杂和乏味。@PeterCordes我的回答是“这种新的寻址模式取代了以前的disp32
寻址模式。”这到底是怎么回事?我还明确指出,rip相对寻址模式仅在没有SIB的情况下可用。请再次阅读我的回答,您可能误解了倒数第二段。相关::PIE可执行文件对使用[array+rax]
具有相同的限制,因为它要求地址适合32位符号扩展值。正如Jester所说,奇怪的是NASM没有在[rel-array+rax]
上发出警告,因为rel不是一个选项,所以它被编码为[abs-array+rax]
。顺便说一句,您可以使用defaultrel
使NASM尽可能使用RIP relative。