堆栈,esp寄存器

时间:2011-10-18 11:45:27

标签: c assembly

我从一本书中复制了这段代码。在每个评论中我都放了一个数字,然后问你问题(1,2,3,4)与该数字评论的代码行有关。希望没问题。

1)ESP指向这些缓冲区值。为什么我们在这里看不到'A'的0x41 ????

2)ESP指向标记变量内存,该内存必须包含31337,十六进制为0x7a69。为什么它不包含这个数字0xbffff89c ???

3)指向前一个堆栈帧指针,这种情况包含正确的地址。

4)寄回地址。也正确。

5)争论。也正确的值。

那么1)和2)会发生什么?是填充吗?

非常感谢你。

void test_function(int a, int b, int c, int d) {
  int flag;
  char buffer[10];
  flag = 31337;
  buffer[0] = 'A';
}

int main() {
  test_function(1, 2, 3, 4);
}


GDB debug session
Breakpoint 2, test_function (a=1, b=2, c=3, d=4) at stack_example.c:5
5 flag = 31337;
(gdb) i r esp ebp eip
esp 0xbffff7c0 0xbffff7c0
ebp 0xbffff7e8 0xbffff7e8
eip 0x804834a 0x804834a <test_function+6>
(gdb) disass test_function
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump.
(gdb) print $ebp-12
$1 = (void *) 0xbffff7dc
(gdb) print $ebp-40
$2 = (void *) 0xbffff7c0
  (gdb) x/16xw $esp  
    0xbffff7c0: 0x00000000 0x08049548 0xbffff7d8 0x08048249  // 1
    0xbffff7d0: 0xb7f9f729 0xb7fd6ff4 0xbffff808 0x080483b9  // 1 
    0xbffff7e0: 0xb7fd6ff4                                   // 1
    0xbffff89c                                               // 2
    0xbffff808                                               // 3
    0x0804838b                                               // 4
    0xbffff7f0:                                              // 4
    0x00000001 0x00000002 0x00000003 0x00000004              // 5




reader@hacking:~/booksrc $ gcc -g stack_example.c
reader@hacking:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main():
0x08048357 <main+0>: push ebp
0x08048358 <main+1>: mov ebp,esp
0x0804835a <main+3>: sub esp,0x18
0x0804835d <main+6>: and esp,0xfffffff0
0x08048360 <main+9>: mov eax,0x0
0x08048365 <main+14>: sub esp,eax
0x08048367 <main+16>: mov DWORD PTR [esp+12],0x4
0x0804836f <main+24>: mov DWORD PTR [esp+8],0x3
0x08048377 <main+32>: mov DWORD PTR [esp+4],0x2
0x0804837f <main+40>: mov DWORD PTR [esp],0x1
0x08048386 <main+47>: call 0x8048344 <test_function>
0x0804838b <main+52>: leave
0x0804838c <main+53>: ret
End of assembler dump
(gdb) disass test_function()
Dump of assembler code for function test_function:
0x08048344 <test_function+0>: push ebp
0x08048345 <test_function+1>: mov ebp,esp
0x08048347 <test_function+3>: sub esp,0x28
0x0804834a <test_function+6>: mov DWORD PTR [ebp-12],0x7a69
0x08048351 <test_function+13>: mov BYTE PTR [ebp-40],0x41
0x08048355 <test_function+17>: leave
0x08048356 <test_function+18>: ret
End of assembler dump
(gdb)

1 个答案:

答案 0 :(得分:5)

'A'31337是文字。他们没有理由被放在堆栈上。

如果您打印出该代码块的反汇编以确切了解编译器正在发出的内容,那么对您来说会更有趣。然后,您可以在运行时交叉检查堆栈包含的内容。

鉴于您的功能没有副作用,它可以优化为无操作。

以下是我在您更熟悉的环境中使用代码获得的内容:

Breakpoint 1, test_function (a=1, b=2, c=3, d=4) at t.c:4
4     flag = 31337;
(gdb) disass test_function
Dump of assembler code for function test_function:
   0x080483a4 <+0>: push   %ebp
   0x080483a5 <+1>: mov    %esp,%ebp
   0x080483a7 <+3>: sub    $0x10,%esp
=> 0x080483aa <+6>: movl   $0x7a69,-0x4(%ebp)
   0x080483b1 <+13>:    movb   $0x41,-0xe(%ebp)
   0x080483b5 <+17>:    leave  
   0x080483b6 <+18>:    ret    
End of assembler dump.
(gdb) display $ebp
2: $ebp = (void *) 0xffffcd70
(gdb) display $esp
3: $esp = (void *) 0xffffcd60
(gdb) x/16xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00000000
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
0xffffcd80: 0x00000003  0x00000004  0xffffcdf8  0xf7e66cc6
0xffffcd90: 0x00000001  0xffffce24  0xffffce2c  0x00000001

除了ASM语法之外,与你的情况不同的是,我的编译器在堆栈上保留了较少的松弛,但这就是它。

因此,在您的情况下,文字最终在指令流中,而不是在堆栈上。本地人的堆栈地址和内容(解释为32位整数,注意字节顺序):

(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00000000
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7

现在让我们分配给flag

(gdb) n
5     buffer[0] = 'A';
(gdb) x/8xw $esp
0xffffcd60: 0xf7e7dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f7e7

一切顺利,正确的堆栈插槽已更新($ebp-4 x / 8xw第1行的最后32位插槽。

然后设置buffer的第一项:

(gdb) n
6   }
(gdb)  x/4x $ebp-0xe
0xffffcd62: 0x41    0xf7    0x24    0x73
(gdb) x/8xw $esp
0xffffcd60: 0xf741dcdd  0xf7fa7324  0xf7fa6ff4  0x00007a69
0xffffcd70: 0xffffcd88  0x080483e1  0x00000001  0x00000002
(gdb)  x/1xw $ebp-4
0xffffcd6c: 0x00007a69
(gdb)  x/1xw $ebp-0xe
0xffffcd62: 0x7324f741

一切都好。当以32位整数查看时,字节序使得事情看起来有点奇怪,但如果你逐字节地看它,它看起来很好。

相关问题