内核版本:2.6.14
在linux内核中我们都会经常见到FASTCALL和armlinkage,它们各有什么不同呢?下面我们来具体分析一下。
在标准C系中函数的形参在实际传入参数的时候会涉及到参数存放的问题,那么这些参数存放在哪里呢?对x86比较了解的话,应该知道这些函数参数和函数内部局部变量一起被分配到了函数的局部堆栈中。linux操作系统支持多种CPU架构,比如x86、ppc和arm等,在不同的处理器结构上不能保证都是通过 局部栈传递参数的。ARM对函数调用过程中的传参定义了一套规则,即 ATPCS,规则中明确指出ARM中R0-R4都是作为通用寄存器使用,在函数调用时处理器从R0-R4中获取参数,在函数返回时再 将需要返回的参数一次存到R0-R4中,也就是说可以将函数参数直接存放在寄存器中,所以为了严格区别函数参数的存放位置,引入了两个标记,即 asmlinkage和FASTCALL,前者表示将函数参数存放在局部栈中,后者则是通知编译器将函数参数用寄存器保存起来。
1.x86平台
- #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
- #define FASTCALL(x) x __attribute__((regparm(3)))
- #define fastcall __attribute__((regparm(3)))
函数定义前加宏asmlinkage,表示这些函数通过堆栈而不是通过寄存器传递参数。gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过堆栈传递参数,你定义的c函数时要在函数前加上宏asmlinkage。
其中 __attribute__是关键字,是gcc的c语言扩展。__attribute__机制是GNU C的一大特色,它可以设置函数属性、变量属性和类型属性等。可以通过它们向编译器提供更多数据,帮助编译器执行优化等。
__attribute__((regparm(0))):告诉gcc编译器该函数不需要通过任何寄存器来传递参数,参数只是通过堆栈来传递。
__attribute__((regparm(3))):告诉gcc编译器这个函数可以通过寄存器传递多达3个的参数,这3个寄存器依次为EAX、EDX 和 ECX。更多的参数才通过堆栈传递。这样可以减少一些入栈出栈操作,因此调用比较快。
asmlinkage大都用在系统调用中。有一些情况下是需要明确的告诉编译器,我们是使用stack来传递参数的,比如x86中的系统调用,是先将参数压入stack以后调用sys_*函数的,所以所有的sys_*函数都有asmlinkage来告诉编译器不要使用寄存器来编译。
2.arm平台
对于arm处理器的,没有定义FASTCALL和armlinkage,所以没有意义(对于ARM平台来说,要符合ATPCS过程调用标准,即通过寄存器传递的。ARM中R0-R4用于存放传入参数,所有函数的参数不应该大于5个,如果超过5个,多余的参数被存放到局部栈中。)。
- #ifndef FASTCALL
- #define FASTCALL(x) x
- #define fastcall
- #endif
-
- #ifndef asmlinkage
- #define asmlinkage CPP_ASMLINKAGE
- #endif
3.CPP_ASMLINKAGE
- #ifdef __cplusplus
- #define CPP_ASMLINKAGE extern "C"
- #else
- #define CPP_ASMLINKAGE
- #endif
extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。
(1) 被extern "C"限定的函数或变量是extern类型的extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
(2) 被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
关键字:linux内核 fastcall asmlinkage宏
引用地址:
linux内核中的fastcall和asmlinkage宏
推荐阅读最新更新时间:2024-03-16 14:45
linux内核对S3C2410睡眠模式的支持
一、S3C2410支持4种供电模式 (1)NORMAL MODE 耗电最大、可以通过关闭具体控制器的时钟来节电 (2)SLOW MODE 在此模式下可以没有内部PLL,耗电情况依赖于外部时钟的频率 (3)IDLE MODE FCLK被关断,主要由于CPU core节电。可以任何通过外部中断唤醒 (4)Power_OFF MODE 除了处理器唤醒逻辑单元外,处理器不损耗任何电量。可以通过EINT 或 RTC alarm interrupt唤醒系统 二、S3C2410各种节电模式的进入 (1)慢速模式(SLOW) CLKSLOW的SLOW_BI
[单片机]
导出在Linux内核ARM平台驱动可用的函数
进入arch/arm/目录,然后用grep EXPORT_SYMBOL * -r 命令将那些被EXPROT_SYMBOL宏导出的ARM平台驱动可用的函数打印出来,用户程序不能使用EXPORT_SYMBOL导出的函数,通过观察和了解这些导出的函数可以有助于驱动的编写。其中对于s3c2440可以的有: common/scoop.c:32:EXPORT_SYMBOL(platform_scoop_config); common/scoop.c:139:EXPORT_SYMBOL(reset_scoop); common/scoop.c:140:EXPORT_SYMBOL(read_scoop_reg); common/scoop.c:1
[单片机]
基于嵌入式操作系统的磁场测量系统的设计
引言 随着科技的发展,嵌入式操作系统在越来越多的领域发挥着重要的作用,目前已成为产品技术水平的标志之一。其中Linux因为其拥有开放性、多用户、多任务、良好的用户界面、丰富的网络功能、可靠的系统安全和良好的可移植等特性被广泛的应用到仪器测量设备中。 传统的磁场测量设备(持斯拉计、高斯计)普遍存在精度低(典型测量精度为1.5%)、操作不便等缺点。本文提出一种基于嵌入式Linux的中频磁场测量系统,它不但可以满足当前磁场测量数据采集的需要,还因为其嵌入了操作系统Linux,使具有可靠性好、升级方便的特点,既提高了磁场测量的准确性,又为仪器的功能升级带来便利。可应用于实验室仪器,医疗仪器,姿态控制,安全检测等需磁场检测的领域。
[单片机]
stm32f429的u-boot、uclinux内核烧写说明
最近比较忙,针对前面的留言说有怎么download u-boot、uclinux到stm32,我翻了翻以前记录下的笔记,特意贴上来,其实有些步骤我都已经忘记了。。。 一、搭建嵌入式linux开发环境 1. 准备一台Linux系统(Fedora,CentOS,Ubuntu等)的电脑,将BSP压缩包(linux-cortexm-2.0.0.tar.gz)拷贝到一个目录; 2. 解压BSP包: tar -xzvf linux-cortexm-2.0.0.tar.gz 3. 解压arm工具链: cd linux-cortexm-2.0.0/tools tar xvfj arm-2010q1-189-arm-uc
[单片机]
arm驱动linux内核时钟
《 linux内核时钟》涉及内核驱动函数四个,内核结构体一个,分析了内核驱动函数一个;可参考的相关应用程序模板或内核驱动模板一个,可参考的相关应用程序模板或内核驱动一个 一、内核定时器 意义:内核定时器是软件意义上的定时器,最终依赖定时器来实现。时钟中断处理程序会唤起Timer_softirq软中断,运行当前处理器上到期的所有定时器。 二、linux设备驱动编程 linux内核提供一组函数,时钟数据结构;这组函数和数据结构使驱动工程师不用关心具体的软件定时器究竟对应着怎样的内核和硬件行为。 三、数据结构和函数: 1)数据结构 结构体一)Linux在include/linux/timer.h头文件中定义了数据结构timer_list来
[单片机]
ARMv8 Linux内核head.S源码分析
ARMv8Linux内核head.S主要工作内容: 1、 从el2特权级退回到el1 2、 确认处理器类型 3、 计算内核镜像的起始物理地址及物理地址与虚拟地址之间的偏移 4、 验证设备树的地址是否有效 5、 创建页表,用于启动内核 6、 设置CPU(cpu_setup),用于使能MMU 7、 使能MMU 8、 交换数据段 9、 跳转到start_kernel函数继续运行。 /* *Low-level CPU initialisation *Based on arch/arm/kernel/head.S * *Copyright (C) 1994-2002 Russell K
[单片机]