在大型C语言项目工程或者linux内核中我们都会经常见到两个FASTCALL和asmlinkage
两个标识符(修饰符),那么它们各有什么不同呢?今天就给大家共同分享一下自己的心得.
大家都知道在标准C系中函数的形参在实际传入参数的时候会涉及到参数存放的问题,那么这些参数存放在哪里呢? 有一定理论基础的朋友一定会肯定地回答:这些函数参数和函数内部局部变量一起被分配到了函数的局部堆栈中,真的是这样吗?其实还有例外的情况:
首
先作为linux操作系统,它不一定就只运行在X86平台下面,还有其他平台例如ARM,PPC,达芬奇等等,所以在不同的处理器结构上不能保证都是通过
局部栈传递参数的,可能此时就有朋友就会问:不放在栈中能放在哪里呢?熟悉ARM的朋友一定知道ARM对函数调用过程中的传参定义了一套规则,叫
ATPCS(内地叫AAPCS),规则中明确指出ARM中R0-R4都是作为通用寄存器使用,在函数调用时处理器从R0-R4中获取参数,在函数返回时再
将需要返回的参数一次存到R0-R4中,也就是说可以将函数参数直接存放在寄存器中,所以为了严格区别函数参数的存放位置,引入了两个标记,即
asmlinkage和FASTCALL,前者表示将函数参数存放在局部栈中,后者则是通知编译器将函数参数用寄存器保存起来
我们在搜索
一些额外的线索,ARM中R0-R4用于存放传入参数,隐约告诉我们,作为高水平嵌入式系统开发者,或者高水平C语言程序员,函数的参数不应
该大于5个,那么有人就会反过来问:超过5个的那些参数又何去何从?我的回答是:传入参数如果超过5个,多余的参数还是被存放到局部栈中,此时有人可能又
会问:将函数参数传入局部栈有什么不好?我的回答是:表面上没什么不好,但是如果你是一名具有linux内核修养的程序员,你就会隐约记得linux中,
不管是系统调用,还是系统陷阱都会引起用户空间陷入内核空间,我们知道,系统空间的权限级是0,用户空间的权限级为3,系统调用从权限级为3的用户空间陷
到权限级为0的内核空间,必然引起堆栈切换,linux系统将从全局任务状态栈TSS中找到一个合适的内核栈信息保存覆盖当前SP,SS两个寄存器的内
容,以完成堆栈切换,此时处于内核空间所看到的栈已不是用户空间那个栈,所以在调用的时候压入用户栈的数据就在陷入内核的那个瞬间,被滞留在用户空间栈,
内核根本不知道它的存在了,所以作为安全考虑或者作为高水平程序员的切身修养出发,都不应该向系统调用级函数传入过多的参数。
from:
二:它是GCC对C程序的一种扩展, #define asmlinkage __attribute__((regparm(0)))
表示用0个寄存器传递函数参数,这样,所有的函数参数强迫从栈中提取。
这个asmlinkage大都用在系统调用中,系统调用需要在entry.s文件中用汇编语言调用,所以必须要保证它符合C语言的参数传递规则,才能用汇编语言正确调用它。
这也是为何使用asmlinkage的原因吧!这是我的理解。仔细看一下有asmlinkage的地方通常是系统调用的函数,因为在系统调用中,寄存器从用户空间传过来后SAVE_ALL压入堆栈,接着调用相应的系统调用函数,这样系统调用函数一定要保证是通过堆栈传递参数的
阅读(633) | 评论(0) | 转发(0) |