我有一个用 C 编写的小程序,echo():

/* Read input line and write it back */
void echo() {
    char buf[8];  /* Way too small! */
    gets(buf);
    puts(buf);
}

对应的汇编代码:
1 echo:
2 pushl %ebp                //Save %ebp on stack
3 movl  %esp, %ebp
4 pushl %ebx                //Save %ebx
5 subl  $20, %esp           //Allocate 20 bytes on stack
6 leal  -12(%ebp), %ebx     //Compute buf as %ebp-12
7 movl  %ebx, (%esp)        //Store buf at top of stack
8 call  gets                //Call gets
9 movl  %ebx, (%esp)        //Store buf at top of stack
10 call puts                //Call puts
11 addl $20, %esp           //Deallocate stack space
12 popl %ebx                //Restore %ebx
13 popl %ebp                //Restore %ebp
14 ret                      //Return

我有几个问题。
  • 为什么 %esp 分配 20 个字节? buf 是 8 个字节,为什么多出 12 个字节?
  • 返回地址就在我们推送 %ebp 的正上方,对吗? (假设我们将堆栈倒置,它向下增长)旧的 %ebp (当前 %ebp 指向的,作为第 3 行的结果)的目的是什么?
  • 如果我想更改返回地址(通过输入超过 12 个字节的任何内容),它将更改 echo() 返回的位置。更改旧的 %ebp(又名返回地址前 4 个字节)的后果是什么?是否有可能通过更改旧的 %ebp 来更改返回地址或回声返回的位置?
  • %ebp 的目的是什么?我知道它的帧指针,但那是什么?
  • 编译器是否有可能将缓冲区放在与旧 %ebp 存储位置不相邻的位置?就像我们声明 buf[8] 但它在第 6 行将它存储在 -16(%ebp) 而不是 -12(%ebp) ?

  • *c 代码和程序集复制自 Computer Systems - A Programmer's Perspective 2nd ed。

    ** 使用 gets() 因为缓冲区溢出

    最佳答案

    分配 20 个字节的原因是为了堆栈对齐。 GCC 4.5+ 生成的代码可确保被调用者的本地堆栈空间与 16 字节边界对齐,以确保编译后的代码可以以明确定义的方式在堆栈上执行对齐的 SSE 加载和存储。出于这个原因,在这种情况下,编译器需要丢弃一些堆栈空间以确保 gets/puts 获得正确对齐的帧。

    本质上,这就是堆栈的外观,其中每一行都是一个 4 字节的字,除了表示 16 字节地址边界的 --- 行:

    ...
    Saved EIP from caller
    Saved EBP
    ---
    Saved EBX       # This is where echo's frame starts
    buf
    buf
    Unused
    ---
    Unused
    Parameter to gets/puts
    Saved EIP
    Saved EBP
    ---
    ...             # This is where gets'/puts' frame starts
    

    正如您希望从我出色的 ASCII 图形中看到的那样,如果不是“未使用”部分,gets/puts 将获得未对齐的帧。但是也要注意,不是 12 个字节是未使用的;其中 4 个是为参数保留的。



    当然。编译器可以随意组织堆栈,但感觉如何。为了可预测地进行缓冲区溢出,您必须查看程序的特定编译二进制文件。

    至于 EBP 的目的是什么(从而回答您的问题 2、3 和 5),请参阅有关如何组织调用堆栈的任何介绍性文本,例如 the Wikipedia article

    关于c - 插入和改变 %esp 帧指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30161249/

    10-11 21:07