3

当我执行以下命令时,我
(gdb) break function()
在 function() 0x804834a 处得到 function() Breakpoint 1 的不同地址。
(gdb) print function()
function() 0x8048344 处的断点 1。
为什么两个地址有区别?

4

2 回答 2

4

这个输出不可能是正确的,如果你做了一些事情:

int func(void) {
  int a = 10;
  printf("%d\n", a);
  return 1;
}

将其加载到 gdb 后:

(gdb) p func
$1 = {int (void)} 0x4016b0 <func>
(gdb) b func
Breakpoint 1 at 0x4016b6: file file.c, line 4.
(gdb) disassemble func
Dump of assembler code for function func:
   0x004016b0 <+0>:     push   %ebp
   0x004016b1 <+1>:     mov    %esp,%ebp
   0x004016b3 <+3>:     sub    $0x28,%esp
   0x004016b6 <+6>:     movl   $0xa,-0xc(%ebp)
   0x004016bd <+13>:    mov    -0xc(%ebp),%eax
   0x004016c0 <+16>:    mov    %eax,0x4(%esp)
   0x004016c4 <+20>:    movl   $0x405064,(%esp)
   0x004016cb <+27>:    call   0x403678 <printf>
   0x004016d0 <+32>:    mov    $0x1,%eax
   0x004016d5 <+37>:    leave
   0x004016d6 <+38>:    ret
End of assembler dump.
(gdb)

这里func指向函数中确切的第一条指令push %ebp,但是当您设置断点时,gdb 在堆栈帧初始化指令之后设置它:

   0x004016b0 <+0>:     push   %ebp
   0x004016b1 <+1>:     mov    %esp,%ebp
   0x004016b3 <+3>:     sub    $0x28,%esp

函数指令实际开始的地方:

=> 0x004016b6 <+6>:     movl   $0xa,-0xc(%ebp)
   0x004016bd <+13>:    mov    -0xc(%ebp),%eax
   0x004016c0 <+16>:    mov    %eax,0x4(%esp)
   0x004016c4 <+20>:    movl   $0x405064,(%esp)
   0x004016cb <+27>:    call   0x403678 <printf>
   0x004016d0 <+32>:    mov    $0x1,%eax
   0x004016d5 <+37>:    leave
   0x004016d6 <+38>:    ret

这里是这个指令:

movl   $0xa,-0xc(%ebp) ; 0xa = 10

这部分是:

int a = 10;
于 2013-10-23T16:20:37.267 回答
3

Gdb 在函数 prologue之后设置断点,因为在正确设置之前它无法显示预期的状态,如局部变量等。

为此,Break 设置断点并在序言之后打印第一条指令的地址,而 print 打印函数中实际第一条指令的地址。

您可以通过执行 break *0x8048344 将断点设置为实际的第一条指令,然后观察那里和序言之后的局部变量的值。

于 2013-10-23T16:13:28.710 回答