16 驱动模块的符号表与符号导出

查看elf文件的信息
readelf test.ko -a

ko文件组成:

1). elf文件头
    ELF Header:
      Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
      Class:                             ELF32
      Data:                              2's complement, little endian
      Version:                           1 (current)
      OS/ABI:                            UNIX - System V
        ...

2). 记录各个段的信息
    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .text             PROGBITS        00000000 000034 000000 00  AX  0   0  1
      [ 2] .init.text        PROGBITS        00000000 000034 00004c 00  AX  0   0  4
        ...

3). 各个段的具体内容


4). Symbol table
       Symbol table '.symtab' contains 64 entries:
        Num:    Value  Size Type    Bind   Vis      Ndx Name
        ...
    56: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND gpio_free
    57: 00000000    76 FUNC    GLOBAL DEFAULT    2 init_module
    58: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND gpio_direction_output
    59: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printk
    60: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND __gpio_set_value
    61: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND gpio_request

//注意 UND标识的意思是此驱动模块里使用了这些函数,但这些函数的函数体并不在驱动模块里的,所以它们的函数地址还不确定的,现只存为0地址. 这些UND标识函数会由内核在加载驱动模块时在内核符号表里查找到它们的函数地址,并替换驱动模块里的函数地址.

//注意,UND标识的函数在内核符号表里都是”T”, 表示是全局函数. 也就是说只有全局函数,内核才会帮我们把相应的函数地址转换好.

///
驱动模块里默认情况下不管是函数还是全局变量都是作局部使用(相当于在函数/变量名前加了”static”).
如果需要作为全局使用,需要使用导出符号”EXPORT_SYMBOL(函数名/变量)”,声明函数/变量为全局使用.

如实现一个内核里的全局函数”myfunc”,在其它驱动模块里调用.

myfunc.c:

    #include <linux/init.h>
    #include <linux/module.h>

    void myfunc(char *str)
    {
        printk("in myfunc: %s\n", str);
    }

    EXPORT_SYMBOL(myfunc);

    MODULE_LICENSE("GPL");

编译加载模块后,可以内核符号表里查看到myfunc函数:

    cat /proc/kallsyms | grep myfunc
    输出的内容:   
        bf081000 T myfunc       [myfunc]

调用myfunc的test模块:
test.c:

    #include <linux/init.h>
    #include <linux/module.h>

    extern void myfunc(char *);

    static int __init test_init(void)
    {
        myfunc("test init");
        return 0;
    }

    static void __exit test_exit(void)
    {
        myfunc("test exit");
    }

    module_init(test_init);
    module_exit(test_exit);

    MODULE_LICENSE("GPL");  

编译后,加载和卸载test驱动模块时都会调用到myfunc函数.
//需注意加载驱动模块的顺序, 如果myfunc驱动模块不先加载,则test模块会加载不成功.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值