代码之家  ›  专栏  ›  技术社区  ›  Gordon Gustafson

在汇编语言中调用方法/函数时会发生什么?

  •  17
  • Gordon Gustafson  · 技术社区  · 15 年前

    如果我有一个C++/C程序(语言并不重要,只需要说明一个概念):

    #include <iostream>    
    
    void foo() {
        printf("in foo");
    }
    
    int main() {
        foo();
        return 0;
    }
    

    装配中发生了什么?我实际上并不是在寻找汇编代码,因为我在这方面还没有走那么远,但基本原则是什么?

    11 回复  |  直到 14 年前
        1
  •  45
  •   Isak Savo    14 年前

    一般来说,情况就是这样:

    1. 返回值的位置在堆栈上被“分配”
    2. 函数的返回地址也存储在堆栈或专用CPU寄存器中。
    3. 函数(或者实际上是函数的地址)通过特定于CPU的 call jmp br 指令(跳转/分支)
    4. 执行跳回调用方,堆栈被清除(通过将堆栈指针恢复到其初始值)。

        2
  •  13
  •   Tim Cooper    11 年前

    您可以亲自查看:

    在Linux下,使用以下命令“编译”您的程序:

    gcc -S myprogram.c
    

    您将在assembler(myprogram.s)中获得一个程序列表。

    当然,为了理解汇编程序,您应该了解一点汇编程序(但它值得学习,因为它有助于理解您的计算机是如何工作的)。调用函数(在x86体系结构上)基本上是:

    • 将变量放在堆栈上
    • 将变量b放在堆栈上
    • 将变量n放在堆栈上
    • 从堆栈加载变量
    • 在函数中做一些事情
    • 干净的堆栈
    • 跳回主站
        3
  •  3
  •   dirkgently    15 年前

    装配中发生了什么?

    简要说明:保存当前堆栈状态,创建新堆栈,加载并运行要执行的函数的代码。这涉及到给微处理器的几个寄存器带来不便,一些疯狂地来回读/写内存,一旦完成,调用函数的堆栈状态就会恢复。

        4
  •  2
  •   mrduclaw    15 年前

    会发生什么?在x86中,主函数的第一行可能类似于:

    call foo

    call 指令将在堆栈上推送返回地址,然后 jmp 到富的位置。

        5
  •  1
  •   Valentin Golev    15 年前

    调用是一个简单的“jmp”,将指令地址推入堆栈(方法末尾的“ret”弹出并跳到堆栈上)

        6
  •  1
  •   vehomzzz    15 年前

    我认为您需要查看调用堆栈,以便更好地了解函数调用期间发生的情况: http://en.wikipedia.org/wiki/Call_stack

        7
  •  1
  •   Tanuj    15 年前
        8
  •  1
  •   sth Wojciech Parzych    15 年前

    会发生什么?

    C模拟将在汇编中发生的情况。。。

    它离机器如此之近,以至于你们可以意识到将会发生什么

    void foo() {
        printf("in foo");
    
    /*
    
    db mystring 'in foo'
    mov eax, dword ptr mystring
    mov edx , dword ptr _printf
    push eax
    call edx
    add esp, 8
    ret
    //thats it
    */
    
    }
    
    int main() {
        foo();
        return 0;
    }
    
        9
  •  0
  •   jldupont    15 年前

    1-在堆栈上建立调用上下文

    3-对方法执行“调用”

        10
  •  0
  •   Joey    15 年前

    一般的 我的想法是你需要

    1. 保存当前的本地状态
    2. 调用实际函数。这涉及到将回信地址放在某个地方,以便 RET

    Wikipedia article on calling conventions . 例如,在x86上,堆栈几乎总是用于向函数传递参数。然而,在许多RISC体系结构上,寄存器主要使用,而堆栈仅在例外情况下才需要。

        11
  •  0
  •   Abel    15 年前

    通常的想法是调用方法中使用的寄存器被推送到堆栈上(堆栈指针位于 ESP 寄存器),此过程称为“推送寄存器”。有时它们也被归零,但这要视情况而定。汇编程序员倾向于释放比普通4更多的寄存器( EAX , EBX , ECX EDX

    当函数结束时,反过来也会发生同样的情况:堆栈将恢复到调用前的状态。这称为“弹出寄存器”。

    更新: 通常,函数的参数按相反的顺序推送到堆栈上,当从堆栈中检索时,它们的显示顺序似乎正常。此订单不由C担保(裁判: Inner Loops