我们天天写python,写C;写函数,写if分支语句,写for循环;我们也知道什么是全局变量,什么是局部变量。但我们是否真正思考过:这些语言的实现,在计算机最底层,也就是汇编语言上是怎么实现的呢?
有人可能会说,我从不用汇编,学它何用?我以前也这么认为。
一个不懂汽车体系结构的车手当然也能开车,可当车在高速上突然熄火,那就很难堪了。而且不懂汽车结构的车手,开起车来还费油。我认为学汇编也是这样,你可能不是专业的“汽车修理工”,但哪天程序突然“熄火”,你有更多解决bug的思路,能从底层看到问题。你也能从底层优化程序。这是学汇编的理由之一。
其二,学汇编能培养我们对计算机的兴趣,人天性喜欢刨根问底,只是因为后天应试教育,一点点磨掉了。而通过汇编能让我们脱掉它身上的外衣,甚至“内裤”,直达它的灵魂。其三,说不定有了底层的知识,你可以发明出自己的语言。《道德经》有言:一生二,二生三,三生万物。
自从看了《编码》《程序是怎样跑起来的》,我也开始学汇编,学计算机的底层知识,正在路上,水平很有限。但自从开始学这些,我对编程更有兴趣,也能体会到计算机科学的一点点美感 。这才是更有意义的,兴趣可以保证大周期时间地专研,精进…
今天先说函数的调用过程:
我们定义两个函数:
int AddNum(int a, int b)
{
return a + b
}
//调用AddNum函数
void MyFunc()
{
int c;
c = AddNum(123, 456);
}
如何转换成汇编语言?不同的编译器,翻译成的汇编语言不同。不同的操作系统,不同的cpu都会得到不同的汇编语言,当然也会有不同的机器码。
对应的汇编语言如下:
_TEXT segment dword public use32 'CODE'
_TEXT ends
_DATA segment dword public use32 'DATA'
_DATA ends _BSS segment dword public use32 'BSS'
_BSS ends DGROUP group
_BSS,_DATA
_TEXT segment dword public use32 'CODE'
_AddNum proc near
;
;
push ebp
mov ebp,esp
;
;
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+12]
;
;
pop ebp
ret
_AddNum endp
_MyFunc proc near
;
;
push ebp
mov ebp,esp
;
; {
push 456
push 123
call _AddNum
add esp,8
;
; }
;
pop ebp
ret
_MyFunc endp
_TEXT ends
end
我先提出几个问题:
- 1调用函数后,如何返回到原来的函数代码处?
- 2系统中只有一个esp,ebp寄存器,每个函数都要有ebp,esp,如果实现呢?把旧的,原来调用函数的值保存一下,存在哪呢?栈中?
- 3这里是一个什么思想呢?cpu中的寄存器有限。如果实现不同的函数共享这些寄存器?如何管理?这种思想可以用在其它什么地方吗?我以前碰到过吗?
- 4程序一般是按顺序执行的,那么如何实现不按顺序执行呢。比如分支跳转,比如函数调用,它们都是不按顺序执行的。我觉得有两种,一种是改变程序计数器的值,一种是是通过地址。那么函数调用用的是哪种?
- 5函数里定义的变量,在汇编语言里是用什么来表示呢?
先说说栈的使用,在函数调用过程中,栈发挥了重大作用。比如如何把参数传给被调用函数,被调用函数如何接收参数,以及调用完函数之后,如何返回到下句继续执行?这些都要通过栈来实现。我们一边分析汇编代码一边画出栈的状态演化图。
解读:
- 1如上图所示,在进入被调用函数之前,先把ebp压入栈中,这是因为每个函数在调用其它函数之前,ebp里面都有值。而ebp只有一个,被调用函数会改变它的值。在调用函数之后再把它弹出,就可以实现恢复它之前的值了。
- 2然后再压入123,456,这是因为它们是局部变量,不用存入在内存中占用空间,放在栈中,函数实现完可以弹出释放内存空间。
- 3在进入被调用函数之前,系统会自动把下一句的内存地址压入栈中,记住现在的地址,这样等执行完被调用函数后,就可以“记得”回来执行原函数的下一句了。
解读:
现在进入了被调用函数AddNum,同样的,它也有自己的ebp,也要先保存起来
解读:
执行完加法运算之后。弹出ebp,恢复它的在运算之前的值
解读:
ret,这条指令让系统pop出add,esp,8的内存地址,程序计数器回到原调用函数去了
解读:
调用完之后,清空栈空间,释放内存空间
解读:
弹出原调用函数的ebp
至此,整个调用过程分析完了,在分析之前提出的几个问题,是不是可以解答了呢?