保留寄存器?

时间:2015-01-28 16:51:21

标签: c linux assembly gdb x86-64

好的,所以在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   

感谢任何意见,谢谢。

(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.

事实上,我甚至无法找到它在put中的打印位置。我一定错过了什么,只是不知道是什么。

2 个答案:

答案 0 :(得分:4)

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

更多信息here

答案 1 :(得分:3)

这条指令:

 jmpq   *0x200c02(%rip)        # 0x601018 <puts@got.plt>

从指令指针偏移量给出的地址读取四字(8字节)并跳转到那里。因此,要查看其发生的位置,您不想使用disas 0x601018,您希望使用x /1xg 0x601018来查看这些字节中的内容(读取指针),然后调用{{1} }在该值上查看disas

的实际代码

这个东西都是动态链接的东西,它被设置为调用动态库中的函数。 puts是“程序链接表”的缩写,是一个对象在某个其他动态库中调用函数时由链接器创建的一组trampolines。 plt是“全局对象表”的缩写,是一个由链接器构建的函数指针表,在加载程序时由动态链接器填充。