【问题标题】:GDB disassemble for a simple program一个简单程序的 GDB 反汇编
【发布时间】:2013-02-28 13:29:06
【问题描述】:

这是一个简单的 C 语言程序,我使用 gdb 对其进行反汇编以了解发生了什么。

#include <stdio.h>
#include <string.h>
int main(){
    printf("%d", sizeof(foo("HELLOWORLD")));
}

int foo(char* c)
{
   printf("%s\n",c);
}

下面是disassemble main

对应的汇编代码
0x08048414 <+0>:    push   %ebp
   0x08048415 <+1>: mov    %esp,%ebp
   0x08048417 <+3>: and    $0xfffffff0,%esp
   0x0804841a <+6>: sub    $0x10,%esp
   0x0804841d <+9>: mov    $0x8048520,%eax
   0x08048422 <+14>:    movl   $0x4,0x4(%esp)
   0x0804842a <+22>:    mov    %eax,(%esp)
   0x0804842d <+25>:    call   0x8048320 <printf@plt>
   0x08048432 <+30>:    leave  
   0x08048433 <+31>:    ret   

下面是disassemble foo

0x08048434 <+0>:    push   %ebp
   0x08048435 <+1>: mov    %esp,%ebp
   0x08048437 <+3>: sub    $0x18,%esp
   0x0804843a <+6>: mov    0x8(%ebp),%eax
   0x0804843d <+9>: mov    %eax,(%esp)
   0x08048440 <+12>:    call   0x8048330 <puts@plt>
   0x08048445 <+17>:    leave  
   0x08048446 <+18>:    ret  

我对这些说明感到困惑:

  1. 0x08048417 &lt;+3&gt; and $0xfffffff0,%esp 为什么栈指针之前没有被修改过需要对齐?

  2. 0x0804841a &lt;+6&gt;:sub $0x10,%esp 这条指令到底对程序做了什么?

  3. 0x0804841d &lt;+9&gt;:mov $0x8048520,%eax 这条指令对程序有什么特别的作用?

  4. mov %eax,(%esp) %esp 周围的括号是什么意思?

如果有人解释这一点会很有帮助。

【问题讨论】:

  • 1) 对齐堆栈,2) 保留堆栈空间,3) “hello world”的地址,4) 参见调用约定。
  • 为什么正好是 16 个字节的空格?
  • Wrt 对齐:你不知道指针之前的位置。 Wrt 括号,它们类似于 C 指针的*
  • @ZhangYuan: foo 根本没有被调用,因为它在 sizeof 运算符中使用,而后者完全在编译时进行评估。
  • @ZhangYuan:是相对于Procedure Linkage Table的地址。当程序启动时,这个地址将被 OS 加载器“修复”为指向共享库中printf 的实际代码。

标签: c gcc assembly x86 gdb


【解决方案1】:
  1. 属于(函数)序言,它通过对 SP 进行位掩码,将 SP 对齐到 16 字节边界。

  2. 堆栈帧的内存已创建,因为您的指针需要传递给函数。地址将从堆栈传递给函数。然而,似乎表达式是在编译时评估的,因此不需要实际调用。

  3. 0x8048520 可能是您的字符串“%d”的地址。它被放入 eax,然后使用堆栈指针将其放入堆栈。

周围有很多资料,比如this

【讨论】:

  • 但是由于函数 foo 没有被调用(main 中没有调用指令)为什么 Hello world 被添加到堆栈中..每次调用新函数时是否需要对齐 SP?
  • @bash.d:不是“HELLOWORLD”的地址,很可能是printf格式字符串的地址。 foo 根本没有被调用,因为整个 sizeof 运算符在编译时被评估为 4
  • printf的地址是0x0804832b
  • @vindhya:and 操作与堆栈指针“向下舍入”到最接近的 16 字节边界。将数据放在这样的边界使计算机能够更有效地获取和处理这些数据。
  • 并非所有的 16 字节都被实际使用。堆栈用于将参数从一个函数传递到另一个函数。调用函数在堆栈上分配空间(创建堆栈帧),被调用者(被调用的函数)可以访问堆栈中的参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 2021-06-22
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
相关资源
最近更新 更多