Linux 我如何使用;“纳米睡眠”;在x86汇编中?
我对Linux的nanosleep系统调用有一些问题。此代码应等待2秒后退出,但不会:Linux 我如何使用;“纳米睡眠”;在x86汇编中?,linux,assembly,x86,Linux,Assembly,X86,我对Linux的nanosleep系统调用有一些问题。此代码应等待2秒后退出,但不会: .text .globl _start _start: pushq %rbp movq %rsp,%rbp pushq $0 #0 nanoseconds pushq $2 #2 seconds leaq (%rbp),%rdi #the time structure on the stack movq $35,%rax #nanosleep s
.text
.globl _start
_start:
pushq %rbp
movq %rsp,%rbp
pushq $0 #0 nanoseconds
pushq $2 #2 seconds
leaq (%rbp),%rdi #the time structure on the stack
movq $35,%rax #nanosleep syscall
movq $0,%rsi #disable useless parameter
syscall
leave
我自己想出来的。这项工作:
#call nanosleep
movq $35,%rax
subq $16, %rbp
movq %rbp,%rdi
movq $0,%rsi
syscall
leave
我自己想出来的。这项工作:
#call nanosleep
movq $35,%rax
subq $16, %rbp
movq %rbp,%rdi
movq $0,%rsi
syscall
leave
在
将内容推到堆栈上后,使用mov%rsp,%rdi
RSP(当前堆栈指针)指向的是新推送的结构,而不是RBP(帧指针)lea(%rsp),%rdi
是一种效率较低的编写方法,但也可以
您正在将RBP
作为指针传递,但它仍然指向生成“堆栈帧”时保存的RBP值。请注意,这是\u start
,不是一个函数,因此您实际上只是终止已保存RBP值的链接列表。SystemV ABI建议通过显式地将RBP设置为零来实现这一点,但Linux会在进程启动时将寄存器(而不是RSP)设置为零,这样就可以了
无论如何,在\u start
,(rsp)
是argc
,然后按下0
(保存的RBP)并将RBP设置为指向那里。因此,要传递给sys\u nanosleep的结构是{0,argc}
。或argc
纳秒。(用strace
测试,看看我是否做对了;我没有试过。)
这就是你应该做的:
pushq $0 #0 nanoseconds
pushq $2 #2 seconds
### RSP instead of RBP in the next instruction:
mov %rsp, %rdi #the time structure we just pushed
mov $35, %eax #SYS_nanosleep
xor %esi, %esi #rem=NULL, we don't care if we wake early
syscall
# RSP is 16 bytes lower than it was before this fragment, in case that matters for later code.
我还通过在不需要时不使用64位操作数大小进行了优化(因为写入32位寄存器会将高32位归零)。我喜欢让寄存器大小暗示操作数大小,而不是像英特尔语法那样使用movq
。我还使用惯用的方法将寄存器归零,并改进注释
你建议的答案被打破了:subq$16,%rbp
在离开之前
是个坏主意
如果您想相对于RBP堆栈帧寻址新推送的结构,可以lea-16(%RBP),%rdi
但是修改%rbp
会将RSP
设置为更新的rbp
,然后将结构的低位qword弹出到rbp
,而不是调用方保存的rbp
。RSP向左指向结构的高qword,而不是函数返回地址
这可能只是因为在离开
之后使用sys\u exit
,因为您不在函数中,所以无法ret
。在\u start
中使用leave
没有任何意义,因为它不是一个函数。您只需sys\u exit
或sys\u exit\u group
但是,如果在实际函数中使用此片段,它将破坏堆栈。在推送堆栈上的内容后,使用mov%rsp,%rdi
RSP(当前堆栈指针)指向的是新推送的结构,而不是RBP(帧指针)lea(%rsp),%rdi
是一种效率较低的编写方法,但也可以
您正在将RBP
作为指针传递,但它仍然指向生成“堆栈帧”时保存的RBP值。请注意,这是\u start
,不是一个函数,因此您实际上只是终止已保存RBP值的链接列表。SystemV ABI建议通过显式地将RBP设置为零来实现这一点,但Linux会在进程启动时将寄存器(而不是RSP)设置为零,这样就可以了
无论如何,在\u start
,(rsp)
是argc
,然后按下0
(保存的RBP)并将RBP设置为指向那里。因此,要传递给sys\u nanosleep的结构是{0,argc}
。或argc
纳秒。(用strace
测试,看看我是否做对了;我没有试过。)
这就是你应该做的:
pushq $0 #0 nanoseconds
pushq $2 #2 seconds
### RSP instead of RBP in the next instruction:
mov %rsp, %rdi #the time structure we just pushed
mov $35, %eax #SYS_nanosleep
xor %esi, %esi #rem=NULL, we don't care if we wake early
syscall
# RSP is 16 bytes lower than it was before this fragment, in case that matters for later code.
我还通过在不需要时不使用64位操作数大小进行了优化(因为写入32位寄存器会将高32位归零)。我喜欢让寄存器大小暗示操作数大小,而不是像英特尔语法那样使用movq
。我还使用惯用的方法将寄存器归零,并改进注释
你建议的答案被打破了:subq$16,%rbp
在离开之前
是个坏主意
如果您想相对于RBP堆栈帧寻址新推送的结构,可以lea-16(%RBP),%rdi
但是修改%rbp
会将RSP
设置为更新的rbp
,然后将结构的低位qword弹出到rbp
,而不是调用方保存的rbp
。RSP向左指向结构的高qword,而不是函数返回地址
这可能只是因为在离开
之后使用sys\u exit
,因为您不在函数中,所以无法ret
。在\u start
中使用leave
没有任何意义,因为它不是一个函数。您只需sys\u exit
或sys\u exit\u group
但如果在实际函数中使用此片段,则会破坏堆栈。int$0x80
用于进行32位系统调用。在64位汇编中,您应该使用使用不同号码和不同调用约定的64位系统调用。很可能您的代码无法工作,因为堆栈不在地址空间的前4 GiB内。如果您使用实际的64位系统调用,它应该可以工作。对我来说,它不适用于“syscall”。请参阅我编辑的代码。对于未来的读者:这是的一个副本,但是OP在回复评论时编辑使用syscall
将其更改为一个不同的问题,因为它引入了一个新的错误:使用%rbp
而不是%rsp
(以及删除sys\u exit
,因此这现在是一个不完整的代码片段…)。无论如何,这个新问题就是我回答的问题;重新打开。int$0x80
用于