//strong.c
#include <stdio.h>
void symbol1()
{
printf("%s.%s\n",__FILE__,__FUNCTION__);
}
//weak.c
#include <stdio.h>
void symbol1() __attribute__ ((weak,alias("symbol222")));
//void symbol1() __attribute__ ((weak));
void symbol222()
{
printf("%s.%s\n",__FILE__,__FUNCTION__);
}
int main()
{
//asm(".weak symbol1\n\t .set symbol1, symbol222\n\t");
if(symbol1)
symbol1();
return 0;
}
//gcc weak.c strong.c -o weak
//./weak
//输出:strong.c.symbol1
//gcc weak.c -o weak
//./weak
//输出:weak.c.symbol222
//总结weak属性
//(1)asm(".weak symbol1\n\t .set symbol1, symbol222\n\t");与
// void symbol1() __attribute__ ((weak,alias("symbol222")));等效。
//(2)给函数加上weak属性时,即使函数没定义,函数被调用也可以编译成功。
//(3)当有两个函数同名时,则使用强符号(也叫全局符号,即没有加weak的函数)来代替弱符号(加weak的函数)。
//(4)当函数没有定义,但如果是“某个函数”的别名时,如果该函数被调用,就间接调用“某个函数”。
- __attribute__
__attribute__(section),用来修饰函数时,可以使你把代码放在image的不同段,如:
void
f(void)
__attribute__((section(“new_section”)));函数f()将被放到只读new_section段中,而不是.text中。
__attribute((regparm(0))),表示不从寄存器中传递参数,如果是regparm(3)则调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数。gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器,缺省使用寄存器,假如想通过堆栈传递,定义的c函数时要在函数前加上宏asmlinkage
- asmlinkage
在看内核源代码start_kernel函数时,第一个遇到的疑问是asmlinkage,原来asmlinkage是一个宏,它定义在文件include/asm-i386/linkage.h中,具体如下:
#define
asmlinkage CPP_ASMLINKAGE
__attribute__((regparm(0))),其中CPP_ASMLINKAGE也是一个宏,定义在include/linux/linkage.h头文件中,具体为:
#define
CPP_ASMLINKAGE extern "C",extern
“C”是用来实现C++和C的混合编程,而__attribute__是关键字,是gcc的C语言扩展,它可以设置函数属性(Function
Attribute)、变量属性(Variable
Attribute)和类型属性(Type
Attribute),总的来说,asmlinkage是个宏,使用它是为了保持参数在stack中,因为从汇编语言到C语言代码参数的传递是通过stack的,它也可能从stack中得到一些不需要的参数,asmlinkage将要解析那些参数。
- __init是一个宏定义,定义在arch/um/include/init.h文件中,具体如:
#define
__init __attribute__ ((__section__ (".init.text")))
这个标志符和函数声明放在一起,它表示gcc编译器在编译的时候需要把这个函数放在.init.text中,而这个section在内核完成初始化之后会被释放掉。
- __weak是一个宏定义,定义在include/asm-mips/linkage.h文件中,具体如:#define
__weak __attribute__((weak)),它常用于函数和变量的声明和函数的定义,是GNU
compiler的扩展,被ARM
compiler支持,可以将一个函数声明为weak,
当没有其他同名函数声明时调用weak,
有其他同名函数时调用其他同名函数。
- __va(x) 是个宏,定义在include/asm-alpha/page.h文件中,具体如下:
#define
__va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
__pa(x)也是个宏,定义在include/asm-alpha/page.h文件中,具体如下:
#define
__pa(x) ((unsigned
long)(x)-PAGE_OFFSET),其中的PAGE_OFFSET定义为0xffff800000000000UL或0xfffffc0000000000UL
- register可以用来修饰变量,表示寄存器变量,只能用于整型和字符变量,表示变量被存储在CPU的寄存器中,而不像普通变量被存储在内存中,这样可以提高运算速度,它常用于在同一变量名频繁出现的地方,且它只适用于局部变量和函数的形式参数,它属于auto型变量,不能作为全局变量
- EXPORT_SYMBOL:若内核函数或变量要被内核模块调用,则必须使用EXPORT_SYMBOL宏进行处理,作用之一是将该符号连接到二进制文件的各个__ksymtab_xx_xx
section,内核加载模块时,会先确认该模块调用的各内核函数是否已export,也就是说EXPORT_SYMBOL可以将一个函数或变量以符号的方式导出给其他模块使用。