操作系统真相还原 第六章 完善内核
第六章 完善内核
函数调用约定简介
函数约定主要包括:
- 参数的传递方式,放在寄存器还是栈中?
- 如果参数放在栈中,调用完后,栈中的参数由谁来清理?
- 参数的传递顺序,从右往左还是从左往右?
- 返回值,放在哪里?
- 调用函数时,寄存器环境由谁保存,调用者还是被调用者?
cdecl调用约定:
cdel(c declaration,即c声明),c语言使用的调用约定。
参数的传递方式,使用栈(linux中,当参数个数小于等于5个时,使用寄存器,大于5时使用栈)
参数的传递顺序,从右往左顺序入栈
eax,ecx,edx寄存器由调用者保存,其他的寄存器由被调用者保存。
函数返回值,放在eax寄存器。
调用者清理栈中参数。
int subtract(int a, int b); //被调用者
int sub = subtract(3,2); //主调用者
;主调用者:
; 从右到左将参数入栈
push 2 ;压入参数b
push 3 ;压入参数a
call subtract ;调用函数subtract
add esp, 8 ;回收栈空间
;被调用者:
push ebp ;压ebp备份
mov ebp,esp ;将esp赋值给ebp
mov eax,[ebp+0x8] ;偏移8字节处为第一个参数a
add eax,[ebp+0xc] ;偏移0xc字节处为第二个参数b,参数a和b相加后存入eax
mov esp,ebp ;为防止中间有入栈操作,用ebp恢复esp
pop ebp ;将ebp恢复
ret
call指令和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP。它们经常被共同用来实现子程序的设计。
call
CPU执行call指令时,进行两步操作:
(1) 将当前的IP或CS和IP压入栈中;
(2) 转移。
ret和retf
ret指令用栈中的数据,修改IP的内容,从而实现近转移;
retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
CPU执行ret指令时,相当于进行:
pop IP
CPU执行retf指令时,相当于进行:
pop IP
pop CS
汇编语言和c语言混合编程
汇编和c语言可以相互调用。
c语言函数声明为外部函数,在汇编中调用函数。汇编文件和c文件分别编译,然后链接到一起生产可执行文件。
c语言调用汇编函数也是类似流程。