关于汇编中的push ebp和pop ebp指令的解释

发布于 2024-09-17 23:24:02 字数 681 浏览 7 评论 0原文

我在汇编中使用了堆栈,但我不知道push ebp和pop ebp。

.intel_syntax noprefix

.include "console.i"

.text

askl:   .asciz  "Enter length: "
askb:   .asciz  "Enter breadth: "
ans:    .asciz  "Perimeter = "

_entry:

    push    ebp     # establishing stack-frame
    mov ebp, esp
    sub esp, 12

    Prompt  askl
    GetInt  [ebp-4]     # length
    Prompt  askb
    GetInt  [ebp-8]     # breadth

    mov eax, [ebp-4]    # eax = l
    add eax, [ebp-8]    # eax = l + b
    add eax, eax    # eax = 2 * (l + b)
    mov [ebp-12], eax

    Prompt  ans
    PutInt  [ebp-12]
    PutEoL

    mov esp, ebp
    pop ebp     # unwinding stack-frame
    ret

.global _entry

.end

i used stack in assembly but i didn't got idea about push ebp and pop ebp.

.intel_syntax noprefix

.include "console.i"

.text

askl:   .asciz  "Enter length: "
askb:   .asciz  "Enter breadth: "
ans:    .asciz  "Perimeter = "

_entry:

    push    ebp     # establishing stack-frame
    mov ebp, esp
    sub esp, 12

    Prompt  askl
    GetInt  [ebp-4]     # length
    Prompt  askb
    GetInt  [ebp-8]     # breadth

    mov eax, [ebp-4]    # eax = l
    add eax, [ebp-8]    # eax = l + b
    add eax, eax    # eax = 2 * (l + b)
    mov [ebp-12], eax

    Prompt  ans
    PutInt  [ebp-12]
    PutEoL

    mov esp, ebp
    pop ebp     # unwinding stack-frame
    ret

.global _entry

.end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白芷 2024-09-24 23:24:02

也许您想知道这一点:

push    ebp
mov ebp, esp
sub esp, 12

这些行被称为汇编函数序言。前 2 条指令保存前一个基指针 (ebp) 并将 EBP 设置为指向堆栈上的该位置(返回地址的正下方)。这将 EBP 设置为 帧指针

sub esp,12 行为函数中的局部变量节省空间。该空间可以使用 [ebp - 4] 等寻址模式来寻址。函数参数的任何压入/弹出,或者调用返回地址的指令本身,或者我们调用的函数的堆栈帧,都将发生在当前 ESP 的保留空间之下。

最后你会得到:

mov esp, ebp         ; restore ESP
pop ebp              ; restore caller's EBP
ret                  ; pop the return address into EIP

这是序言所做的相反(即尾声),因此可以恢复之前的上下文。这有时称为“拆除”堆栈框架。

(EBP 在所有标准 x86 调用约定中都是非易失性的,即调用保留:如果修改它,则必须恢复调用者的值。)

leave 指令的作用与这两条指令完全相同,并且某些编译器使用它来节省代码大小。 (输入 0,0 非常慢并且从未使用过(https://agner.org/optimize /); leave 与 mov + pop 一样高效。)


请注意,使用 EBP 作为帧指针是可选,编译器不会这样做对于优化代码中的大多数功能。相反,它们保存单独的元数据以允许堆栈展开/回溯。

Maybe you're wondering about this:

push    ebp
mov ebp, esp
sub esp, 12

These lines are known as the assembly function prologue. The first 2 instructions save the previous base pointer (ebp) and set EBP to point at that position on the stack (right below the return address). This sets up EBP as a frame pointer.

The sub esp,12 line is saving space for local variables in the function. That space can be addressed with addressing modes like [ebp - 4]. Any push/pop of function args, or the call instruction itself pushing a return address, or stack frames for functions we call, will happen below this reserved space, at the current ESP.

At the end you have:

mov esp, ebp         ; restore ESP
pop ebp              ; restore caller's EBP
ret                  ; pop the return address into EIP

This is the inverse the prologue does (i.e. the epilogue), so the previous context can be restored. This is sometimes called "tearing down" the stack frame.

(EBP is non-volatile aka call-preserved in all standard x86 calling conventions: if you modify it, you have to restore your caller's value.)

The leave instruction does exactly what these two instructions do, and is used by some compilers to save code size. (enter 0,0 is very slow and never used (https://agner.org/optimize/); leave is about as efficient as mov + pop.)


Note that using EBP as a frame pointer is optional, and compilers don't do it for most functions in optimized code. Instead they save separate metadata to allow stack unwinding / backtrace.

坐在坟头思考人生 2024-09-24 23:24:02

ebp 称为基指针或帧指针。在进入您的函数时,您将其推送(以保存调用函数的值)。然后,将堆栈指针 esp 复制到 ebp 中,以便 ebp 现在指向函数的堆栈帧。在函数结束时,您将弹出 ebp 以便恢复调用函数的值。

为了澄清到底发生了什么 - push 指令将指定寄存器(本例中为 ebp)中的值放入堆栈,并递减堆栈指针适量。 pop 操作相反 - 它递增堆栈指针并从堆栈中获取一个值并将其放入指定的寄存器中。

ebp is known as the base pointer or the frame pointer. On entry to your function, you push it (to save the value for the calling function). Then, you copy esp, the stack pointer, into ebp, so that ebp now points to your function's stack frame. At the end of your function, you then pop ebp so that the calling function's value is restored.

For some clarification on exactly what is going on - the push instruction puts the value from the specified register (ebp in this case), onto the stack, and decrements the stack pointer by the appropriate amount. The pop operation is the opposite - it increments the stack pointer and takes a value from the stack and puts it in the specified register.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文