C 保存寄存器?

C 保存寄存器?,c,linux,assembly,gdb,x86-64,C,Linux,Assembly,Gdb,X86 64,好的,在C代码中,我让它循环通过命令行参数,并打印出每个参数。我编译它并在GDB中打开它,以查看主函数的外观,因为我试图在汇编中执行相同的操作。我最终发现了我的问题所在——我的打印函数使用了与主函数相同的寄存器。最后,我只是在函数调用之前将它们推到堆栈上,然后在函数调用之后将它们弹出。我唯一不明白的是,为什么这段代码似乎没有做到这一点,为什么它没有遇到和我一样的问题 0x000000000040052d <+0>: push %rbp 0x0000000000

好的,在C代码中,我让它循环通过命令行参数,并打印出每个参数。我编译它并在GDB中打开它,以查看主函数的外观,因为我试图在汇编中执行相同的操作。我最终发现了我的问题所在——我的打印函数使用了与主函数相同的寄存器。最后,我只是在函数调用之前将它们推到堆栈上,然后在函数调用之后将它们弹出。我唯一不明白的是,为什么这段代码似乎没有做到这一点,为什么它没有遇到和我一样的问题

   0x000000000040052d <+0>:     push   %rbp
   0x000000000040052e <+1>:     mov    %rsp,%rbp
   0x0000000000400531 <+4>:     sub    $0x20,%rsp
   0x0000000000400535 <+8>:     mov    %edi,-0x14(%rbp)
   0x0000000000400538 <+11>:    mov    %rsi,-0x20(%rbp)
   0x000000000040053c <+15>:    jmp    0x400561 <main+52>
   0x000000000040053e <+17>:    mov    -0x4(%rbp),%eax
   0x0000000000400541 <+20>:    cltq   
   0x0000000000400543 <+22>:    lea    0x0(,%rax,8),%rdx
   0x000000000040054b <+30>:    mov    -0x20(%rbp),%rax
   0x000000000040054f <+34>:    add    %rdx,%rax
   0x0000000000400552 <+37>:    mov    (%rax),%rax
   0x0000000000400555 <+40>:    mov    %rax,%rdi
   0x0000000000400558 <+43>:    callq  0x400410 <puts@plt>
   0x000000000040055d <+48>:    addl   $0x1,-0x4(%rbp)
   0x0000000000400561 <+52>:    mov    -0x4(%rbp),%eax
   0x0000000000400564 <+55>:    cmp    -0x14(%rbp),%eax
   0x0000000000400567 <+58>:    jl     0x40053e <main+17>
   0x0000000000400569 <+60>:    leaveq 
   0x000000000040056a <+61>:    retq   
0x000000000040052d:推送%rbp
0x000000000040052e:mov%rsp,%rbp
0x0000000000400531:子$0x20,%rsp
0x0000000000400535:mov%edi,-0x14(%rbp)
0x0000000000400538:mov%rsi,-0x20(%rbp)
0x000000000040053c:jmp 0x400561
0x000000000040053e:mov-0x4(%rbp),%eax
0x0000000000400541:cltq
0x0000000000400543:lea0x0(,%rax,8),%rdx
0x000000000040054b:mov-0x20(%rbp),%rax
0x000000000040054f:添加%rdx,%rax
0x0000000000400552:mov(%rax),%rax
0x0000000000400555:mov%rax,%rdi
0x0000000000400558:callq 0x400410
0x000000000040055d:添加$0x1,-0x4(%rbp)
0x0000000000400561:mov-0x4(%rbp),%eax
0x0000000000400564:cmp-0x14(%rbp),%eax
0x0000000000400567:jl 0x40053e
0x0000000000400569:LEVEQ
0x000000000040056a:retq
欢迎您的任何意见,谢谢

(gdb) disass 0x400410
Dump of assembler code for function puts@plt:
   0x0000000000400410 <+0>:     jmpq   *0x200c02(%rip)        # 0x601018 <puts@got.plt>
   0x0000000000400416 <+6>:     pushq  $0x0
   0x000000000040041b <+11>:    jmpq   0x400400
End of assembler dump.
(gdb) disass 0x601018
Dump of assembler code for function puts@got.plt:
   0x0000000000601018 <+0>:     (bad)  
   0x0000000000601019 <+1>:     add    $0x40,%al
   0x000000000060101b <+3>:     add    %al,(%rax)
   0x000000000060101d <+5>:     add    %al,(%rax)
   0x000000000060101f <+7>:     add    %ah,(%rsi)
End of assembler dump.
(gdb)disass 0x400410
函数的汇编代码转储puts@plt:
0x000000000040410:jmpq*0x200c02(%rip)#0x601018
0x000000000040416:pushq$0x0
0x00000000004041B:jmpq 0x400400
汇编程序转储结束。
(gdb)disass 0x601018
函数的汇编代码转储puts@got.plt:
0x00000000000601018:(坏)
0x00000000000601019:添加$0x40,%al
0x0000000000060101B:添加%al,(%rax)
0x0000000000060101D:添加%al,(%rax)
0x0000000000060101F:添加%ah,(%rsi)
汇编程序转储结束。

事实上,我甚至找不到它的打印位置。我一定是遗漏了什么,只是不知道是什么。

您为puts显示的拆解不正确。动态加载库的库符号是动态解析的。编译器生成对存根的调用(过程链接表或PLT),加载程序在运行时解析该地址,第二次调用该函数时,地址已解析,运行速度更快。在第二次迭代中反汇编它,您将看到实际的puts代码正在运行,您将看到寄存器正在被推送

更多信息。

此说明:

 jmpq   *0x200c02(%rip)        # 0x601018 <puts@got.plt>
jmpq*0x200c02(%rip)#0x601018
从指令指针的偏移量给定的地址读取四字(8字节),并跳到那里。因此,要查看这是怎么回事,您不想使用
disas 0x601018
,而是想使用
x/1xg 0x601018
查看这些字节中的内容(读取指针),然后对该值调用
disas
,查看
put


这些东西都是动态链接的东西,用来调用动态库中的函数
plt
是“程序链接表”的缩写,是链接器在对象调用其他动态库中的函数时创建的一组蹦床
got
是“全局对象表”的缩写,是链接器生成的函数指针表,在加载程序时由动态链接器填写。

检查
puts@plt
没有。一个明智的猜测是,它首先推送它将要使用的寄存器。这是有道理的,我检查了,但它看起来不像,我会在一秒钟内更新我的帖子,以显示我发现了什么。非常感谢,这现在是有道理的。我知道我不明白什么。