Linux 我如何使用;“纳米睡眠”;在x86汇编中?

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

我对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 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
用于