保留寄存器?
Preserving Registers?
好的,所以在 C 代码中,我让它循环遍历命令行参数并打印出每个参数。我编译它并在 GDB 中打开它以查看主要功能的样子,因为我试图在汇编中做同样的事情。我最终弄清楚了我的问题所在——我的打印函数使用的寄存器与主函数使用的寄存器相同。我最终只是在函数调用之前将每个推入堆栈,然后将它们弹出。我唯一不明白的是为什么这段代码似乎没有那样做,为什么它没有 运行 遇到和我一样的问题。
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub [=10=]x20,%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 [=10=]x1,-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 [=11=]x0
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 [=11=]x40,%al
0x000000000060101b <+3>: add %al,(%rax)
0x000000000060101d <+5>: add %al,(%rax)
0x000000000060101f <+7>: add %ah,(%rsi)
End of assembler dump.
事实上,我什至无法找到它在 puts 中打印的位置。我一定是错过了什么,只是不知道是什么。
您为 puts 显示的反汇编不正确。动态加载库的库符号是动态解析的。编译器生成对存根的调用(过程链接 table 或 PLT),加载程序在 运行 解析该调用时间,您第二次调用该函数时,地址已解析并且速度 运行s。在第 2 次迭代时反汇编它,您将看到实际的 puts 代码为 运行,并且您将看到寄存器被压入。
更多信息here。
这条指令:
jmpq *0x200c02(%rip) # 0x601018 <puts@got.plt>
从指令指针的偏移量给定的地址读取四字(8 字节)并跳转到那里。所以要看这是怎么回事,你不想用disas 0x601018
,你想用x /1xg 0x601018
看看那些字节里有什么(读取指针),然后调用disas
在该值上查看 puts
的实际代码
这玩意儿都是动态链接的玩意儿,就是为了调用动态库中的函数而设置的。 plt
是 "program linkage table" 的缩写,是每当对象调用其他动态库中的函数时由链接器创建的一组蹦床。 got
是"global object table"的缩写,是链接器构建的函数指针table,程序加载时由动态链接器填充。
好的,所以在 C 代码中,我让它循环遍历命令行参数并打印出每个参数。我编译它并在 GDB 中打开它以查看主要功能的样子,因为我试图在汇编中做同样的事情。我最终弄清楚了我的问题所在——我的打印函数使用的寄存器与主函数使用的寄存器相同。我最终只是在函数调用之前将每个推入堆栈,然后将它们弹出。我唯一不明白的是为什么这段代码似乎没有那样做,为什么它没有 运行 遇到和我一样的问题。
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub [=10=]x20,%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 [=10=]x1,-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 [=11=]x0
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 [=11=]x40,%al
0x000000000060101b <+3>: add %al,(%rax)
0x000000000060101d <+5>: add %al,(%rax)
0x000000000060101f <+7>: add %ah,(%rsi)
End of assembler dump.
事实上,我什至无法找到它在 puts 中打印的位置。我一定是错过了什么,只是不知道是什么。
您为 puts 显示的反汇编不正确。动态加载库的库符号是动态解析的。编译器生成对存根的调用(过程链接 table 或 PLT),加载程序在 运行 解析该调用时间,您第二次调用该函数时,地址已解析并且速度 运行s。在第 2 次迭代时反汇编它,您将看到实际的 puts 代码为 运行,并且您将看到寄存器被压入。
更多信息here。
这条指令:
jmpq *0x200c02(%rip) # 0x601018 <puts@got.plt>
从指令指针的偏移量给定的地址读取四字(8 字节)并跳转到那里。所以要看这是怎么回事,你不想用disas 0x601018
,你想用x /1xg 0x601018
看看那些字节里有什么(读取指针),然后调用disas
在该值上查看 puts
这玩意儿都是动态链接的玩意儿,就是为了调用动态库中的函数而设置的。 plt
是 "program linkage table" 的缩写,是每当对象调用其他动态库中的函数时由链接器创建的一组蹦床。 got
是"global object table"的缩写,是链接器构建的函数指针table,程序加载时由动态链接器填充。