0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

printk函数的地址问题怎么解决

麦辣鸡腿堡 来源:嵌入式Linux充电站 作者:Vincent 2023-09-26 16:49 次阅读

不知大家有没有想过,在一个内核模块代码中,会用到printk函数,而这个函数不是我们实现的,它是内核代码的一部分,但我们为什么能够编译通过呢?

我们的代码之所以能够编译通过,是因为对模块的编译 仅仅是编译,并没有链接

编译出来的.ko文件是一个普通的ELF文件 ,使用file命令和nm命令,我们可以看到相关的信息

# file vser.ko
vser.ko ELF 32-bit LSB relocatable, Intel 80386, vserion 1 (SYSV), BuildID[sha1]=0x09ca747e6f75c65v19a5da9102113v98d7cea24, not stripped
# nm vser.ko
......
00000004 d port
    U printk
00000000 t vser_exit
00000000 t vser_init

vser_initvser_exit分别是模块的入口函数和出口函数,使用nm命令查看模块目标文件的符号信息时,可以看到vser_exitvser_init的符号类型是t,表示它们是 函数

printk的 符号类型是U,表示它是一个 未决符号 。意思是说在编译阶段不知道这个符号的地址,因为它被定义在其他文件中,没有放在模块代码一起编译。

那printk函数的地址问题怎么解决呢?答案是用EXPORT_SYMBOL宏将printk导出即可。

EXPORT_SYMBOL导出符号

大致原理:利用EXPORT_SYMBOL宏生成一个特定的结构并放在ELF文件的一个特定段中,在 内核的启动过程中,会将符号的确切地址填充到这个结构的特定成员中

模块加载时,加载程序将去处理未决符号,在特殊段中搜索符号的名字,如果找到,则将获得的地址填充在被加载模块的相应段中,这样符号的地址就可以确定。

使用这种方式处理未决符号,其实相当于把链接的过程推后,进行了动态链接,和普通的应用程序使用共享库函数的道理是类似的 。可以发现,内核将会有大量的符号导出,为模块提供了丰富的基础设施。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    3

    文章

    1362

    浏览量

    40221
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208886
  • 函数
    +关注

    关注

    3

    文章

    4304

    浏览量

    62416
  • 编译
    +关注

    关注

    0

    文章

    653

    浏览量

    32803
收藏 人收藏

    评论

    相关推荐

    C代码实现程序的跳转|函数指针

    凡是学过C语言函数的应该都知道,函数名其实就是个地址,是函数的入口地址。如果用 %p 来输出函数
    发表于 01-17 09:26 1410次阅读

    Linux内核学习笔记:printk调试

    很多内核开发者喜欢的调试工具是printk,在Linux内核中,使用printk()函数来打印信息,它与C库的printf()函数类似。
    发表于 06-01 15:14 1097次阅读

    四种获取内核函数地址的方法

    在内核调试中,经常需要知道某个函数地址,或者根据函数地址找到对应的函数,从而进行更深一步的debug。
    的头像 发表于 11-17 16:58 1236次阅读
    四种获取内核<b class='flag-5'>函数</b><b class='flag-5'>地址</b>的方法

    printk()函数的总结

    我们在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。对程序的调试起到了很重要的作用。(下文中的日志级别和控制台日志控制级别
    发表于 07-09 03:47

    linux内核打印函数printk的方法

    1.linux内核打印函数printk一、函数有头文件二、定义的关键宏三、函数原型合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你
    发表于 12-20 07:02

    如何配置和使用Linux内核printk功能

    了解如何配置和使用Linux内核printk功能,包括其动态调试功能。 这样可以选择性地打印调试消息,而无需重新编译内核。
    的头像 发表于 11-27 06:40 3067次阅读

    内核日志及printk结构浅析

    做DPDK项目时,调试rte_kni.ko时,发现printk并不会向我们想想的那样把log信息显示在我们的终端上。
    发表于 04-22 17:45 1103次阅读

    你知道Linux内核调试关键技术之一的printk

    在内核调试技术之中,最简单的就是printk的使用了,它的用法和C语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中,使用这个printk就要对内核的实现有一定的了解。
    发表于 05-10 11:18 1663次阅读

    Linux中的Printk与dmesg功能

    结:        Printf在终端显示,printk()函数为内核空间里边的信息打印函数,就像c编程时用的printf()函数一样,专供内核中的信息展示用,他没有调用printf(
    发表于 04-02 14:39 457次阅读

    PMT函数与相对绝对地址引用的资料说明

    PMT函数与相对绝对地址
    发表于 05-12 14:47 0次下载
    PMT<b class='flag-5'>函数</b>与相对绝对<b class='flag-5'>地址</b>引用的资料说明

    C语言-内联函数、递归函数、指针函数

    这篇文章介绍C语言的内联函数、递归函数函数指针、指针函数、局部地址、const关键字、extern关键字等知识点;这些知识点在实际项目开发
    的头像 发表于 08-14 10:03 1655次阅读

    使用LPNDR_ReadGlobalInfo函数块读取IP地址和MAC地址

    使用 LPNDR_ReadGlobalInfo 函数块可以读取 PROFINET 设备的 IP 地址和 MAC 地址
    的头像 发表于 11-14 10:09 4033次阅读

    C语言如何获得自身定义函数的实际地址和大小吗

    我们先看地址。C语言无法定义函数外标签,函数内标签从使用到访问处处受限,我们好像只剩函数名可以用。但函数名表达式未必等同于
    发表于 12-02 10:52 1048次阅读

    如何使用函数指针?

    在程序中定义一个函数,则编译时系统就会为这段代码分配一段存储空间,这段存储空间的首地址称为函数地址,且函数名代表的就是这个
    的头像 发表于 03-30 15:09 832次阅读

    Linux内核pr_xx()函数封装

    pr_xx( )封装 在使用printk的时候需要手动添加输出等级KERN_INFO、KERN_WARNING等,这样还是有些麻烦。因此,Linux内核也对printk进行了进一步的封装
    的头像 发表于 09-27 15:58 743次阅读