您的位置首页>企业动态>

你了解linux驱动的入口?

导读 大家好,我是极客范的本期栏目编辑小友,现在为大家讲解你了解linux驱动的入口?问题。以module _ init(Demo _ init);为例定义文

音频解说

大家好,我是极客范的本期栏目编辑小友,现在为大家讲解你了解linux驱动的入口?问题。

以module _ init(Demo _ init);为例

定义文件:

包括\linux\init.h

#定义module _ init(x)_ init调用(x);

#定义__initcall(fn)设备_initcall(fn)

# define device _ init call(fn)_ define _ init call(' 6 ',fn,6)

#define __define_initcall(级别,fn,id) \

静态init call _ t _ _ init call _ # # fn # # id _ _ attribute _ used _ _ \

_ _属性_ _(_ _ SeCOnd _ _(').初始化调用“级别”.init ')=fn

展开为

staTIc init call _ t _ _ init call _ Demo _ init _ 6 _ _ attribute _ used _ _ attribute _(_ _ SeCOnd _(。初始化呼叫6。init’)=Demo _ init;

typedef int(* init call _ t)(void);

这里

typedef int(init _ fnc _ t)(void);定义一种函数类型

typedef int(* init _ fnc _ t)(void);定义一种类型的函数指针

所以展开的宏定义就是定义名为__initcall_Demo_init6的函数指针

属性有两个:

1.

在gcc 3.4之前的编译器被展开成__属性_ _((未使用))来禁止编译器弹出有关函数没有被用到的的警告信息

在gcc 3.4之后被展开成__属性_ _((已使用))功能一样

2.加载到段。initcall6.init,其地址为演示_初始化的地址

段的分布顺序在链接脚本中有

编译内核后,会有vmlinux.lds的打印信息,里面有各段位置

__initcall_start=.

*(.最初。init)_ early _ init call _ end=.

*(.initcall0.init)

*(.initcall0s.init)

*(.initcall1.init)

*(.initcall1s.init)

*(.initcall2.init)

*(.initcall2s.init)

*(.initcall3.init)

*(.initcall3s.init)

*(.initcall4.init)

*(.initcall4s.init)

*(.initcall5.init)

*(.initcall5s.init)

*(.initcallrootfs.init)

*(.initcall6.init)

*(.initcall6s.init)

*(.initcall7.init)

*(.initcall7s.init)

__initcall_end=.

当insmod的时候,内核从initcall6.init段中读取到驱动入口地址,然后跳转到该地址去执行入口函数,

一般入口函数会进行注册驱动,例如

寄存器_chrdev(无符号int major,const char * name,const struct file _ OPERATIONs * fops)

usb _寄存器(结构usb_driver *驱动程序)

spi _寄存器_驱动器(结构spi_driver * sdrv)

等等注册函数,再依次调用相应设备结构体中的ioctl或者直接调用文件操作结构体

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。