能力值:
( LV2,RANK:10 )
|
-
-
2 楼
关注一下啊~
|
能力值:
(RANK:260 )
|
-
-
3 楼
1.不管系统调用也好,还是一般的函数调用也好,只是某种形式的“控制转移”。而“调用”与“分支(或叫做跳转)”这两种*转移*,本质上的区别就是“调用”必有“返回”,因此需要某种途径保存返回地址。
在x86中,一般的过程调用,返回地址被直接压入堆栈。而系统调用有很多途径,对于int 0x2E方式的系统调用,CPU通过异常处理机制转到ring0的ISR处执行,硬件按照中断发生时的行为执行的对现场的保存动作,包括ring3的cs:eip压栈,ring3的ss:esp压栈,当然还有eflags压栈。对于sysenter的系统调用方式,根据手册描述,sysenter指令并不保存返回地址,但系统可以使用ring3堆栈上的返回地址(即从KiFastSystemCall返回的地址)来返回调用处。
在amd64上,手册中提到syscall指令,而我在调试运行在32位兼容模式下的程序时,发现系统调用是先call一个ring3的占位函数,然后直接一个far jmp进入内核了,应该是通过call gate了。
2.任何一本汇编语言的书里都会讲到,call指令执行的动作是把下一条指令的地址压入堆栈,然后转到目标地址去执行;而ret指令可以理解为pop eip,也就是把栈顶的值弹出,装入程序计数器。
3.函数调用栈帧的平衡是由程序自身维护的,硬件没有任何特殊的机制。而程序代码自己是知道使用了多少栈空间的。在函数返回之前,只需要将自己使用的局部空间释放,堆栈自然就平衡了。
实际上,“堆栈平衡”只是一种约定,或者说习惯,并不是规定,更没有硬件检查机制。只要你愿意,写的程序可以随意使用堆栈,或根本不使用堆栈,只要你自己清楚程序的执行流程就行。
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
谢谢 ,受教了
|
|
|