str
的地址存储在堆栈中(可以使用pop
来获取它,并且它与位置无关):
.text
str:
.string "test\n"
但是现在str
的地址不在堆栈中(不能使用pop
来获取它,但是str(%rip)
(RIP相对寻址)是PIC):
.text
str:
.skip 64
这是我在上一个问题中找到的,
但我不明白汇编程序如何决定str
的地址是否应该在堆栈中?
我应该何时使用RIP相对寻址,还是使用pop
使其成为PIC?
更新
这是有效的:
.text
call start
str:
.string "test\n"
start:
movq $1, %rax
movq $1, %rdi
popq %rsi
movq $5, %rdx
syscall
ret
但如果我将popq %rsi
更改为lea str(%rip),%rsi
,则会导致细分错误...
答案 0 :(得分:1)
完全清楚:CALL
指令将其后面的指令地址压入堆栈并跳转到目标地址。这意味着
x: call start
y:
在道德上等同于(忽略我们在此处废弃%rax
):
x: lea y(%rip), %rax
push %rax
jmp start
y:
相反RET
从堆栈中弹出一个地址并跳转到它。
现在,在您的代码中,您执行popq %rsi
,然后ret
跳回到您的任何内容。如果您只是将popq
更改为lea str(%rip), %rsi
以加载地址为%rsi
的{{1}},您仍然拥有返回值(地址{{ 1}})在堆栈上!要修复代码,只需手动弹出堆栈中的返回值(str
)或者在函数后更加明智地移动str
,这样您就不需要进行笨拙的调用。
更新了完整的独立示例:
add $8, %rsp
使用str
反汇编代码可以发现代码确实与位置无关,即使使用# p.s
#
# Compile using:
# gcc -c -fPIC -o p.o p.s
# gcc -fPIC -nostdlib -o p -Wl,-estart p.o
.text
.global start # So we can use it as an entry point
start:
movq $1, %rax #sys_write
movq $1, %rdi
lea str(%rip), %rsi
movq $5, %rdx
syscall
mov $60, %rax #sys_exit
mov $0, %rdi
syscall
.data
str:
.string "test\n"
也是如此。
objdump -d p