函数调用如何在 Linux 上的 x86 32 位程序集中工作? [英] How do function calls work in x86 32-bit assembly on Linux?

查看:31
本文介绍了函数调用如何在 Linux 上的 x86 32 位程序集中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从 Jonathan Bartlett 的从头开始编程"一书中学习 GNU 汇编.

I am learning GNU assembly from Jonathan Bartlett's "Programming from ground up" book.

在讨论函数调用和堆栈的主题时,我无法理解它的工作原理.

While going through the topic of a function call and stack, I'm unable to understand its working.

以下是书中的内容:

在执行函数之前,程序将函数的所有参数按与记录相反的顺序压入堆栈.然后程序发出一个调用指令,指示它希望启动哪个函数.call 指令做了两件事.首先它将下一条指令的地址,即返回地址,压入堆栈.然后它修改指令指针 (%eip) 以指向函数的开头.因此,在函数启动时,堆栈看起来像这样(堆栈的顶部"在此示例中位于底部):

Before executing a function, a program pushes all of the parameters for the function onto the stack in the reverse order that they are documented. Then the program issues a call instruction indicating which function it wishes to start. The call instruction does two things. First it pushes the address of the next instruction, which is the return address, onto the stack. Then it modifies the instruction pointer (%eip) to point to the start of the function. So, at the time the function starts, the stack looks like this (the "top" of the stack is at the bottom on this example):

Parameter #N
...
Parameter 2
Parameter 1
Return Address <--- (%esp)

函数的每个参数都被压入栈中,最后返回地址就在那里.现在函数本身有一些工作要做.

Each of the parameters of the function have been pushed onto the stack, and finally the return address is there. Now the function itself has some work to do.

它做的第一件事是通过执行 pushl %ebp 保存当前的基址指针寄存器 %ebp.基指针是一个特殊的寄存器,用于访问函数参数和局部变量.接下来,它通过执行 movl %esp, %ebp 将堆栈指针复制到 %ebp.这使您能够从基指针访问作为固定索引的函数参数.您可能认为可以为此使用堆栈指针.但是,在您的程序中,您可以对堆栈执行其他操作,例如将参数推送到其他函数.将堆栈指针复制到函数开头的基指针中,可以让您始终知道参数在哪里(正如我们将看到的,局部变量也是如此),即使您可能正在将内容推入和推出堆栈.%ebp 将始终是堆栈指针在函数开头的位置,因此它或多或少是对堆栈帧的常量引用(堆栈帧由函数中使用的所有堆栈变量组成,包括参数、本地变量和返回地址).

The first thing it does is save the current base pointer register, %ebp, by doing pushl %ebp. The base pointer is a special register used for accessing function parameters and local variables. Next,it copies the stack pointer to %ebp by doing movl %esp, %ebp. This allows you to be able to access the function parameters as fixed indexes from the base pointer. You may think that you can use the stack pointer for this. However, during your program you may do other things with the stack such as pushing arguments to other functions. Copying the stack pointer into the base pointer at the beginning of a function allows you to always know where your parameters are (and as we will see, local variables too), even while you may be pushing things on and off the stack. %ebp will always be where the stack pointer was at the beginning of the function, so it is more or less a constant reference to the stack frame (the stack frame consists of all of the stack variables used within a function, including parameters, local variables, and the return address).

此时,堆栈是这样的:

Parameter #N <--- N*4+4(%ebp)
...
Parameter 2 <--- 12(%ebp)
Parameter 1 <--- 8(%ebp)
Return Address <--- 4(%ebp)
Old %ebp <--- (%esp) and (%ebp)

如您所见,可以使用 %ebp 寄存器使用基指针寻址模式访问每个参数.

As you can see, each parameter can be accessed using base pointer addressing mode using the %ebp register.

我能在第二段之后得到一个关于作者想说的内容的简明介绍吗?我显然在 %esp、%ebp 寄存器和 %ebp 在这里工作时感到困惑.非常感谢任何帮助.

Can I get a concise intro on what the author wants to tell after the second paragraph. I am clearly confusing among the %esp, %ebp registers and %ebp's working here. Any help is highly appreciated.

推荐答案

在第二个图中,有这个旧的 %ebp <--- (%esp) 和 (%ebp)".什么意思?

In the second diagram, there is this "Old %ebp <--- (%esp) and (%ebp)". What does it mean ?

这意味着保存的 %ebp 值(您的函数保存/恢复的调用者的值)由 %esp 和新的 %ebp 指向 在那一点.

It means the saved %ebp value (the caller's value that your function saves/restores) is pointed to by both %esp and your new %ebp at that point.

您刚刚运行了 push %ebp,它执行了 esp -= 4 并将 %ebp 存储到 (%esp).这会保存您的呼叫者的 %ebp,以便您以后可以恢复它.

You just ran push %ebp, which did esp -= 4 and stored %ebp to (%esp). This saves your caller's %ebp so you can restore it later.

然后您运行 mov %esp, %ebp%ebp 设置为帧指针.所以 %ebp = %esp,它们都指向你推送的最后一个东西.

Then you ran mov %esp, %ebp to set up %ebp as a frame pointer. So %ebp = %esp, and they're both pointing at the last thing you pushed.

这篇关于函数调用如何在 Linux 上的 x86 32 位程序集中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆