免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234下一页
最近访问板块 发新帖
查看: 27286 | 回复: 39
打印 上一主题 下一主题

[内核模块] 分享两个很简单的编译问题(1)对ko进行strip -S(2)使用KBUILD_EXTRA_SYMBOLS [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-12-09 22:58 |只看该作者 |倒序浏览
本帖最后由 lofeng410 于 2010-12-09 23:02 编辑

可能很多高手早就知道这样处理,但是俺是最近才琢磨明白,呵呵

(1)对编译所得的.ko进行strip -S,处理掉调试信息,这样可以大大缩小ko文件的大小

(2)使用KBUILD_EXTRA_SYMBOLS
主要使用于下面这样的场合:
有两个我们自己的模块,其中Module B使用了Module A中export的函数,因此在Module B的Makefile中必须加上这样的选项
KBUILD_EXTRA_SYMBOLS += /path/to/Module A/Module.symvers
export KBUILD_EXTRA_SYMBOLS

这样在编译Module B时,才不会出现Warning,提示说func1这个符号找不到,而编译得到的ko加载时也会出错。

需要注意的是:
(1)KBUILD_EXTRA_SYMBOLS 赋值时必须使用+=,而不能使用=及:=,这个是实验出来的,至于为什么必须这样,还不明白。如果哪位高手知道,还请指教~~
(2)KBUILD_EXTRA_SYMBOLS 必须使用export处理一下
  1. // Module A (mod_a.c)
  2. #include<linux/init.h>
  3. #include<linux/module.h>
  4. #include<linux/kernel.h>

  5. static int func1(void)
  6. {
  7.        printk("In Func: %s...\n",__func__);
  8.        return 0;
  9. }

  10. // Export symbol func1
  11. EXPORT_SYMBOL(func1);

  12. static int __init hello_init(void)
  13. {
  14.        printk("Module 1,Init!\n");
  15.        return 0;
  16. }

  17. static void __exit hello_exit(void)
  18. {
  19.        printk("Module 1,Exit!\n");
  20. }

  21. module_init(hello_init);
  22. module_exit(hello_exit);
复制代码
  1. // Module B (mod_b.c)
  2. #include<linux/init.h>
  3. #include<linux/kernel.h>
  4. #include<linux/module.h>

  5. static int func2(void)
  6. {
  7.        extern int func1(void);
  8.        func1();
  9.        printk("In Func: %s...\n",__func__);
  10.        return 0;
  11. }

  12. static int __init hello_init(void)
  13. {
  14.        printk("Module 2,Init!\n");
  15.        func2();
  16.        return 0;
  17. }

  18. static void __exit hello_exit(void)
  19. {
  20.        printk("Module 2,Exit!\n");
  21. }

  22. module_init(hello_init);
  23. module_exit(hello_exit);
复制代码

评分

参与人数 1可用积分 +18 收起 理由
Godbach + 18 欢迎分享

查看全部评分

论坛徽章:
2
IT运维版块每日发帖之星
日期:2016-07-27 06:20:0015-16赛季CBA联赛之福建
日期:2017-03-23 18:32:41
2 [报告]
发表于 2017-03-24 12:18 |只看该作者
本帖最后由 HazeC 于 2017-03-24 12:29 编辑
Godbach 发表于 2017-03-23 22:56
回复 29# HazeC
解决就好,恭喜!

回复 26# Godbach
1、导出函数的内核模块(A.ko)
  1. int export_hello_kernel(void){
  2.         int i = 0;
  3.         printk("%s-%pS\n" ,__FUNCTION__ ,(void *)export_hello_kernel);
  4. }

  5. EXPORT_SYMBOL(export_hello_kernel);
复制代码
2、引用函数的内核模块(B.ko)
首先是读取 /proc/kallsyms,找到export_hello_kernel的函数地址。
代码来自4.4.1版本内核文件"kernel/livepatch/core.c"
  1. struct klp_verify_args args = {
  2.                 .name = name,
  3.                 .addr = addr,
  4.         };
复制代码
  1. static int klp_verify_callback(void *data, const char *name,
  2.                                struct module *mod, unsigned long addr)
  3. {
  4.         struct klp_verify_args *args = data;

  5.         if (!mod &&
  6.             !strcmp(args->name, name) &&
  7.             args->addr == addr)
  8.                 return 1;

  9.         return 0;
  10. }
复制代码
  1. static int klp_verify_vmlinux_symbol(const char *name, unsigned long addr)
  2. {
  3.         int ret;

  4.         mutex_lock(&module_mutex);
  5.         ret = kallsyms_on_each_symbol(klp_verify_callback, &args);
  6.         mutex_unlock(&module_mutex);

  7.         if (!ret) {
  8.                 pr_err("symbol '%s' not found at specified address 0x%016lx, kernel mismatch?\n",
  9.                         name, addr);
  10.                 return -EINVAL;
  11.         }

  12.         return 0;
  13. }
复制代码


调用klp_verify_vmlinux_symbol,name为"export_hello_kernel" ,addr是输出变量,保存的就是导出函数的地址。
找到函数地址之后
  1. int (*run)(void) = addr;
复制代码
run即为export_hello_kernel的指针了,可以直接调用了。


这样内核模块的开发就可以把核心的功能放在一个模块,其他功能可以以插件的形式挂载了。


啊哈。。直接拿来内核的代码,献丑了。CU排版真心不好用啊。


评分

参与人数 1可用积分 +8 收起 理由
Godbach + 8 赞一个!

查看全部评分

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
3 [报告]
发表于 2010-12-10 09:37 |只看该作者
KBUILD_EXTRA_SYMBOLS += /path/to/Module A/Module.symvers
export KBUILD_EXTRA_SYMBOLS

你是在哪个内核版本上实现的。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2010-12-10 09:39 |只看该作者
测试一下对Module A 中:
EXPORT_SYMBOL(func1);

替换为:
EXPORT_SYMBOL_GPL(func1);


然后在 Module B 直接调用的情形。

论坛徽章:
0
5 [报告]
发表于 2010-12-10 15:34 |只看该作者
回复 1# lofeng410


    我用的 linux-2.6.34 内核,似乎没有 这样的问题啊。 可以直接用啊。

论坛徽章:
0
6 [报告]
发表于 2010-12-10 20:52 |只看该作者
本帖最后由 lofeng410 于 2010-12-10 20:59 编辑

回复 2# Godbach


    内核版本为2.6.32


测试一下对Module A 中:

替换为:


然后在 Module B 直接调用的情形。
Godbach 发表于 2010-12-10 09:39


之前就已经试过,这样不行的

论坛徽章:
0
7 [报告]
发表于 2010-12-10 21:11 |只看该作者
回复 4# linyunxian


我的场景是这样的,有两个模块,编译时都是任意找了个地方放置,编译时只使用了内核源码目录下的modpost以及Modules.sym

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
8 [报告]
发表于 2010-12-10 21:25 |只看该作者
回复  linyunxian


我的场景是这样的,有两个模块,编译时都是任意找了个地方放置,编译时只使用了内核 ...
lofeng410 发表于 2010-12-10 21:11


就是那种普通的编译出来的内核模块吧

论坛徽章:
0
9 [报告]
发表于 2010-12-10 21:32 |只看该作者
回复 6# lofeng410


    嗯,我实验的时候也是两个不同的模块。trip -S foo.ko 后可以直接使用的哟。

论坛徽章:
0
10 [报告]
发表于 2010-12-10 23:30 |只看该作者
回复 7# Godbach


    是的,只不过完全都是我们自己编码的,之前采用的是笨办法,将Module A的Modules.sym拷贝到Module B所在的目录,然后编译Module B

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
11 [报告]
发表于 2010-12-11 09:29 |只看该作者
我之前也测试过一个模块导出符号,另一个模块调用。并不存在你说的情况。顶多内核版本不一样。
你可以不用 strip,编译出来之后,看能否加载A 和B
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP