GDB:如何解释 x86_64 调用堆栈和寄存器(特别是 $rbp)
GDB: how to interpret x86_64 call stack & registers (specifically $rbp)
根据我的理解,x86_64 调用约定指定 return address
a.k.a saved $rip
应该位于当前框架基础 $rbp
的正上方 - 例如:
8(%rbp) return address
0(%rbp) previous %rbp value
x86_64 调用约定的参考资料:
http://6.035.scripts.mit.edu/sp16/x86-64-architecture-guide.html
http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
但是,我从进程的 gdb
获得的框架和 $rbp
寄存器对我来说没有意义:
注册:
(gdb) info registers
rax 0xfffffffffffffffc -4
rbx 0x7ff7143fbc40 140699173370944
rcx 0xffffffffffffffff -1
rdx 0x80 128
rsi 0x7ff7143fb4e0 140699173369056
rdi 0x9 9
rbp 0x7ff7143fbb00 0x7ff7143fbb00
rsp 0x7ff7143fb4c0 0x7ff7143fb4c0
r8 0x7ff715e2a630 140699200824880
r9 0xa072 41074
r10 0x493e0 300000
r11 0x293 659
r12 0x7ff715e2a600 140699200824832
r13 0x7ff715e2a630 140699200824880
r14 0x7ff7143fb4e0 140699173369056
r15 0x7ff715c73078 140699199025272
rip 0x7ff71d466f33 0x7ff71d466f33 <epoll_wait+51>
eflags 0x293 [ CF AF SF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
帧数:
(gdb) info frame
Stack level 0, frame at 0x7ff7143fb4d0:
rip = 0x7ff71d466f33 in epoll_wait; saved rip = 0x459347
called by frame at 0x7ff7143fbb10
Arglist at 0x7ff7143fb4b8, args:
Locals at 0x7ff7143fb4b8, Previous frame's sp is 0x7ff7143fb4d0
Saved registers:
rip at 0x7ff7143fb4c8
如果我从堆栈指针($rsp
、$rsp+0x8
、$rsp+0x10
等)向后遍历,我应该能够在堆栈上找到 saved $rip
。好事是 - 我做到了!
(gdb) x/8x 0x7ff7143fb4c8
0x7ff7143fb4c8: 0x47 0x93 0x45 0x00 0x00 0x00 0x00 0x00
问题:
正如你在这里看到的,地址 0x7ff7143fb4c8
处的 8 字节内存与 gdb 中 info frame
中的 saved $rip
完全相同。据此,根据 x86_64 调用约定 $rbp
的值不应该是 0x7ff7143fb4c0
吗?为什么现在的$rbp
是0x7ff7143fbb00
?有人可以帮忙填补这里的空白吗?
In my understanding, x86_64 calling convention specifies that return address a.k.a saved $rip should be right above the current frame base $rbp
你的理解完全错误:x86_64
ABI没有指定$RBP
为帧寄存器。 $RBP
的值可以是任何值。
现在,当编译时没有优化,或使用 -fno-omit-frame-pointer
,或在使用 alloca
的例程中,或在参数数量可变的例程中,$RBP
通常 是用作帧指针。但是在其他例程中没有,在libc.so.6
里面没有,等等
你没有说你在哪个例程中停止了 GDB,或者那个例程是如何编译的,甚至你在那个例程中的 哪里 停止了,所以大部分 GDB 输出您提供的内容缺乏任何有意义的内容。
根据我的理解,x86_64 调用约定指定 return address
a.k.a saved $rip
应该位于当前框架基础 $rbp
的正上方 - 例如:
8(%rbp) return address
0(%rbp) previous %rbp value
x86_64 调用约定的参考资料: http://6.035.scripts.mit.edu/sp16/x86-64-architecture-guide.html http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
但是,我从进程的 gdb
获得的框架和 $rbp
寄存器对我来说没有意义:
注册:
(gdb) info registers
rax 0xfffffffffffffffc -4
rbx 0x7ff7143fbc40 140699173370944
rcx 0xffffffffffffffff -1
rdx 0x80 128
rsi 0x7ff7143fb4e0 140699173369056
rdi 0x9 9
rbp 0x7ff7143fbb00 0x7ff7143fbb00
rsp 0x7ff7143fb4c0 0x7ff7143fb4c0
r8 0x7ff715e2a630 140699200824880
r9 0xa072 41074
r10 0x493e0 300000
r11 0x293 659
r12 0x7ff715e2a600 140699200824832
r13 0x7ff715e2a630 140699200824880
r14 0x7ff7143fb4e0 140699173369056
r15 0x7ff715c73078 140699199025272
rip 0x7ff71d466f33 0x7ff71d466f33 <epoll_wait+51>
eflags 0x293 [ CF AF SF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
帧数:
(gdb) info frame
Stack level 0, frame at 0x7ff7143fb4d0:
rip = 0x7ff71d466f33 in epoll_wait; saved rip = 0x459347
called by frame at 0x7ff7143fbb10
Arglist at 0x7ff7143fb4b8, args:
Locals at 0x7ff7143fb4b8, Previous frame's sp is 0x7ff7143fb4d0
Saved registers:
rip at 0x7ff7143fb4c8
如果我从堆栈指针($rsp
、$rsp+0x8
、$rsp+0x10
等)向后遍历,我应该能够在堆栈上找到 saved $rip
。好事是 - 我做到了!
(gdb) x/8x 0x7ff7143fb4c8
0x7ff7143fb4c8: 0x47 0x93 0x45 0x00 0x00 0x00 0x00 0x00
问题:
正如你在这里看到的,地址 0x7ff7143fb4c8
处的 8 字节内存与 gdb 中 info frame
中的 saved $rip
完全相同。据此,根据 x86_64 调用约定 $rbp
的值不应该是 0x7ff7143fb4c0
吗?为什么现在的$rbp
是0x7ff7143fbb00
?有人可以帮忙填补这里的空白吗?
In my understanding, x86_64 calling convention specifies that return address a.k.a saved $rip should be right above the current frame base $rbp
你的理解完全错误:x86_64
ABI没有指定$RBP
为帧寄存器。 $RBP
的值可以是任何值。
现在,当编译时没有优化,或使用 -fno-omit-frame-pointer
,或在使用 alloca
的例程中,或在参数数量可变的例程中,$RBP
通常 是用作帧指针。但是在其他例程中没有,在libc.so.6
里面没有,等等
你没有说你在哪个例程中停止了 GDB,或者那个例程是如何编译的,甚至你在那个例程中的 哪里 停止了,所以大部分 GDB 输出您提供的内容缺乏任何有意义的内容。