如果我在C ++ / C中有一个程序(语言无关紧要,只需说明一个概念):
#include <iostream>
void foo() {
printf("in foo");
}
int main() {
foo();
return 0;
}
装配中会发生什么?我实际上并不是在寻找汇编代码,因为我还没有那么远,但基本原理是什么?
答案 0 :(得分:43)
一般情况下,会发生这种情况:
call
指令或通过普通jmp
或br
指令(跳转/分支)调用函数(或实际上,函数的地址) 上述细节因平台而异,甚至从编译器到编译器也有所不同(参见例如STDCALL与CDECL调用约定)。例如,在某些情况下,使用CPU寄存器而不是在堆栈上存储东西。一般的想法是相同的,但
答案 1 :(得分:12)
你可以自己看看:
在Linux下“编译”您的程序:
gcc -S myprogram.c
你将在汇编程序(myprogram.s)中获得程序列表。
当然你应该对汇编程序有一点了解它(但它值得学习,因为它有助于理解你的计算机是如何工作的)。调用函数(在x86架构上)基本上是:
答案 2 :(得分:3)
装配中会发生什么?
简要说明:保存当前堆栈状态,创建新堆栈并加载并运行要执行的函数的代码。这会给微处理器的一些寄存器带来不便,有些会对存储器进行疯狂的读/写操作,一旦完成,就会恢复调用函数的堆栈状态。
答案 3 :(得分:1)
参数被推入堆栈并且“调用”指令被
调用是一个简单的“jmp”,它将指令的地址压入堆栈(“ret”在方法的末尾弹出并跳转到它上面)
答案 4 :(得分:1)
我想你想看看调用堆栈,以便更好地了解函数调用期间发生的事情:http://en.wikipedia.org/wiki/Call_stack
答案 5 :(得分:1)
会发生什么?在x86中,main函数的第一行可能类似于:
call foo
call
指令将推送堆栈上的返回地址,然后将jmp
推送到foo的位置。
答案 6 :(得分:1)
答案 7 :(得分:1)
会发生什么?
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;
}
答案 8 :(得分:0)
常见的想法是调用方法中使用的寄存器被压入堆栈(堆栈指针位于ESP
寄存器中),此过程称为“推送寄存器”。有时他们也被归零,但这取决于。汇编程序员倾向于释放更多的寄存器,然后在x86上释放公共4(EAX
,EBX
,ECX
和EDX
),以便在函数中有更多的可能性。
当函数结束时,反过来也会发生这种情况:堆栈恢复到调用之前的状态。这称为“弹出寄存器”。
更新:此过程不一定必须发生。编译器可以优化它并内联您的功能。
更新:通常,函数的参数以相反的顺序被压入堆栈,当从堆栈中检索它们时,它们看起来就像正常顺序一样。 C不保证此订单(参考:Rick Booth的Inner Loops
)
答案 9 :(得分:0)
1-在堆栈上建立调用上下文
2-参数被压入堆栈
3-对方法执行“调用”
答案 10 :(得分:0)
一般的想法是你需要
RET
指令知道继续的位置。具体情况因架构而异。更具体的细节可能因各种语言而异。虽然通常有一些方法可以在一定程度上控制这种情况,以允许不同语言之间的互操作性。
一个非常有用的起点是Wikipedia article on calling conventions。例如,在x86上,堆栈几乎总是用于将参数传递给函数。但是,在许多RISC架构中,主要使用寄存器,而只在特殊情况下才需要堆栈。