为什么 gdb 不能访问 ret 指令的内存?

Why cannot gdb access memory of ret instruction?

asm 中的每个 call 都会导致该指令 pushes return 值,因此一旦 ret 被调用,程序就知道从哪里继续。所以我想检查调用 ret 的地址:

有这个:

#include <stdio.h>
int main()
{
printf("a=%d; b=%d; c=%d", 1, 2, 3);
return 0;
}

我使用 gdb:

(gdb) b printf
+b printf
Breakpoint 1 at 0x1030
(gdb) run
+run
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d")
    at printf.c:28
28  printf.c: No such file or directory.
(gdb) x/10x $rsp
+x/10x $rsp
0x7fffffffdc28: 0x55555159  0x00005555  0x55555160  0x00005555
0x7fffffffdc38: 0xf7e1c09b  0x00007fff  0x00000000  0x00000000
0x7fffffffdc48: 0xffffdd18  0x00007fff

(gdb) x/i 0x55555159
+x/i 0x55555159
   0x55555159:  Cannot access memory at address 0x55555159
(gdb) 

这里我试图从 return 地址读取指令,但不知何故无法访问该地址。为什么,什么时候它应该是 ret 的有效地址?

正如 Eric Postpischil 评论的那样,您只检查了 return 地址的 一半 x86_64 上的 64 位地址。

使用您的程序:

(gdb) b printf
Breakpoint 1 at 0x1030
(gdb) run
Starting program: /tmp/a.out 

Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
28      printf.c: No such file or directory.
(gdb) bt
#0  __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
#1  0x0000555555555159 in main () at t.c:4

这说明我们期望在栈上找到的return地址是0x0000555555555159。的确,那正是地址@$rsp:

(gdb) x/gx $rsp
0x7fffffffdbd8: 0x0000555555555159

查看该地址的指令:

(gdb) x/i 0x0000555555555159
   0x555555555159 <main+36>:    mov    [=12=]x0,%eax

你也可以把整个main拆开看看你在哪儿,你要去哪儿return:

(gdb) disas main
Dump of assembler code for function main:
   0x0000555555555135 <+0>:     push   %rbp
   0x0000555555555136 <+1>:     mov    %rsp,%rbp
   0x0000555555555139 <+4>:     mov    [=13=]x3,%ecx
   0x000055555555513e <+9>:     mov    [=13=]x2,%edx
   0x0000555555555143 <+14>:    mov    [=13=]x1,%esi
   0x0000555555555148 <+19>:    lea    0xeb5(%rip),%rdi        # 0x555555556004
   0x000055555555514f <+26>:    mov    [=13=]x0,%eax
   0x0000555555555154 <+31>:    callq  0x555555555030 <printf@plt>
   0x0000555555555159 <+36>:    mov    [=13=]x0,%eax
   0x000055555555515e <+41>:    pop    %rbp
   0x000055555555515f <+42>:    retq   
End of assembler dump.

如你所见,printf 将 return 到的指令确实在地址 0x0000555555555159.