- 浏览: 664434 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
sztime:
可以在文本框上绑定事件来禁用回车键, 我就是这样做的.在IE中 ...
form 回车自动提交问题 -
damoqiongqiu:
非常好的文章,很透彻不过有一句话小僧腆着脸补充一下:“1111 ...
为什么要用补码来做存储 -
wuyizhong:
原来如此啊。
form 回车自动提交问题 -
luliangy:
谢楼主~!
用C语言扩展Python的功能 -
kwong:
很有用,谢谢
火狐和IE 对css 样式解释的差异
不知道在什幺时候,Linux 出现了 module 这种东西,的确,它是 Linux 的一大革新。有了 module 之后,写 device driver 不再是一项恶梦,修改 kernel 也不再是一件痛苦的事了。因为你不需要每次要测试 driver 就重新 compile kernel 一次。那简直是会累死人。Module 可以允许我们动态的改变 kernel,加载 device driver,而且它也能缩短我们 driver development 的时间。在这篇文章里,我将要跟各位介绍一下 module 的原理,以及如何写一个 module。
module 翻译成中文就是模块,不过,事实上去翻译这个字一点都没意义。在讲模块之前,我先举一个例子。相信很多人都用过 RedHat。在 RedHat 里,我们可以执行 sndconfig,它可以帮我们 config 声卡。config 完之后如果捉得到你的声卡,那你的声卡马上就可以动了,而且还不用重新激活计算机。这是怎幺做的呢 ? 就是靠module。module 其实是一般的程序。但是它可以被动态载到 kernel 里成为 kernel的一部分。载到 kernel 里的 module 它具有跟 kernel 一样的权力。可以 access 任何 kernel 的 data structure。你听过 kdebug 吗 ? 它是用来 debug kernel 的。它就是先将它本身的一个 module 载到 kernel 里,而在 user space 的 gdb 就可以经由跟这个 module 沟通,得知 kernel 里的 data structure 的值,除此之外,还可以经由载到 kernel 的 module 去更改 kernel 里 data structure。
我们知道,在写 C 程序的时候,一个程序只能有一个 main。Kernel 本身其实也是一个程序,它本身也有个 main,叫 start_kernel()。当我们把一个 module 载到 kernel 里的时候,它会跟 kernel 整合在一起,成为 kernel 的一部分。请各位想想,那 module 可以有 main 吗 ? 答案很明显的,是 No。理由很简单。一个程序只能有一个 main。在使用 module 时,有一点要记住的是 module 是处于被动的角色。它是提供某些功能让别人去使用的。
Kernel 里有一个变量叫 module_list,每当 user 将一个 module 载到 kernel 里的时候,这个 module 就会被记录在 module_list 里面。当 kernel 要使用到这个 module 提供的 function 时,它就会去 search 这个 list,找到 module,然后再使用其提供的 function 或 variable。每一个 module 都可以 export 一些 function 或变量来让别人使用。除此之外,module 也可以使用已经载到 kernel 里的 module 提供的 function。这种情形叫做 module stack。比方说,module A 用到 module B 的东西,那在加载 module A 之前必须要先加载 module B。否则 module A 会无法加载。除了 module 会 export 东西之外,kernel 本身也会 export 一些 function 或 variable。同样的,module 也可以使用 kernel 所 export 出来的东西。由于大家平时都是撰写 user space 的程序,所以,当突然去写 module 的时候,会把平时写程序用的 function 拿到 module 里使用。像是 printf 之类的东西。我要告诉各位的是,module 所使用的 function 或 variable,要嘛就是自己写在 module 里,要嘛就是别的 module 提供的,再不就是 kernel 所提供的。你不能使用一般 libc 或 glibc所提供的 function。像 printf 之类的东西。这一点可能是各位要多小心的地方。(也许你可以先 link 好,再载到 kernel,我好象试过,但是忘了)
刚才我们说到 kernel 本身会 export 出一些 function 或 variable 来让 module 使用,但是,我们不是万能的,我们怎幺知道 kernel 有开放那里东西让我们使用呢 ? Linux 提供一个 command,叫 ksyms,你只要执行 ksyms -a 就可以知道 kernel 或目前载到 kernel 里的 module 提供了那些 function 或 variable。底下是我的系统的情形:
c0216ba0 drive_info_R744aa133
c01e4a44 boot_cpu_data_R660bd466
c01e4ac0 EISA_bus_R7413793a
c01e4ac4 MCA_bus_Rf48a2c4c
c010cc34 __verify_write_R203afbeb
. . . . .
在 kernel 里,有一个 symbol table 是用来记录 export 出去的 function 或 variable。除此之外,也会记录着那个 module export 那些 function。上面几行中,表示 kernel 提供了 drive_info 这个 function/variable。所以,我们可以在 kernel 里直接使用它,等载到 kernel 里时,会自动做好 link 的动作。由此,我们可以知道,module 本身其实是还没做 link 的一些 object code。一切都要等到 module 被加载 kernel 之后,link 才会完成。各位应该可以看到 drive_info 后面还接着一些奇怪的字符串。_R744aa133,这个字符串是根据目前 kernel 的版本再做些 encode 得出来的结果。为什幺额外需要这一个字符串呢 ?
Linux 不知道从那个版本以来,就多了一个 config 的选项,叫做 Set version number in symbols of module。这是为了避免对系统造成不稳定。我们知道 Linux 的 kernel 更新的很快。在 kernel 更新的过程,有时为了效率起见,会对某些旧有的 data structure 或 function 做些改变,而且一变可能有的 variable 被拿掉,有的 function 的 prototype 跟原来的都不太一样。如果这种情形发生的时候,那可能以前 2.0.33 版本的 module 拿到 2.2.1 版本的 kernel 使用,假设原来 module 使用了 2.0.33 kernel 提供的变量叫 A,但是到了 2.2.1 由于某些原因必须把 A 都设成 NULL。那当此 module 用在 2.2.1 kernel 上时,如果它没去检查 A 的值就直接使用的话,就会造成系统的错误。也许不会整个系统都死掉,但是这个 module 肯定是很难发挥它的功能。为了这个原因,Linux 就在 compile module 时,把 kernel 版本的号码 encode 到各个 exported function 和 variable 里。
所以,刚才也许我们不应该讲 kernel 提供了 drive_info,而应该说 kernel 提供了 driver_info_R744aa133 来让我们使用。这样也许各位会比较明白。也就是说,kernel 认为它提供的 driver_info_R744aa133 这个东西,而不是 driver_info。所以,我们可以发现有的人在加载 module 时,系统都一直告诉你某个 function 无法 resolved。这就是因为 kernel 里没有你要的 function,要不然就是你的 module 里使用的 function 跟 kernel encode 的结果不一样。所以无法 resolve。解决方式,要嘛就是将 kernel 里的 set version 选项关掉,要嘛就是将 module compile 成 kernel 有办法接受的型式。
那 有人就会想说,如果 kernel 认定它提供的 function 名字叫做 driver_info_R744aa133 的话,那我们写程序时,是不是用到这个 funnction 的地方都改成 driver_info_R744aa133 就可以了。答案是 Yes。但是,如果每个 function 都要你这样写,你不会觉得很烦吗 ? 比方说,我们在写 driver 时,很多人都会用到 printk 这个 function。这是 kernel 所提供的 function。它的功能跟 printf 很像。用法也几乎都一样。是 debug 时很好用的东西。如果我们 module 里用了一百次 printk,那是不是我们也要打一百次的 printk_Rdd132261 呢 ? 当然不是,聪明的人马上会想到用 #define printk printk_Rdd132261 就好了嘛。所以啰,Linux 很体贴的帮我们做了这件事。
如果各位的系统有将 set version 的选项打开的话,那大家可以到 /usr/src/linux/include/linux/modules 这个目录底下。这个目录底下有所多的 ..ver档案。这些档案其实就是用来做 #define 用的。我们来看看 ksyms.ver 这个档案里,里面有一行是这样子的 :
#define printk _set_ver(printk)
set_ver 是一个 macro,就是用来在 printk 后面加上 version number 的。有兴趣的朋友可以自行去观看这个 macro 的写法。用了这些 ver 檔,我们就可以在 module 里直接使用 printk 这样的名字了。而这些 ver 档会自动帮我们做好 #define 的动作。可是,我们可以发现这个目录有很多很多的 ver 檔。有时候,我们怎幺知道我们要呼叫的 function 是在那个 ver 档里有定义呢 ? Linux 又帮我们做了一件事。/usr/src/linux/include/linux/modversions.h 这个档案已经将全部的 ver 档都加进来了。所以在我们的 module 里只要 include 这个档,那名字的问题都解决了。但是,在此,我们奉劝各位一件事,不要将 modversions.h 这个档在 module 里 include 进来,如果真的要,那也要加上以下数行:
#ifdef MODVERSIONS
#include
#endif
加 入这三行的原因是,避免这个 module 在没有设定 kernel version 的系统上,将 modversions.h 这个档案 include 进来。各位可以去试试看,当你把 set version 的选项关掉时,modversions.h 和 modules 这个目录都会不见。如果没有上面三行,那 compile 就不会过关。所以一般来讲,modversions.h 我们会选择在 compile 时传给 gcc 使用。就像下面这个样子。
gcc -c -D__KERNEL__ -DMODULE -DMODVERSIONS main.c \
-include usr/src/linux/include/linux/modversions.h
在 这个 command line 里,我们看到了 -D__KERNEL__,这是说要定义 __KERNEL__ 这个 constant。很多跟 kernel 有关的 header file,都必须要定义这个 constant 才能 include 的。所以建议你最好将它定义起来。另外还有一个 -DMODVERSIONS。这个 constant 我刚才忘了讲。刚才我们说要解决 fucntion 或 variable 名字 encode 的方式就是要 include modversions.h,其实除此之外,你还必须定义 MODVERSIONS 这个 constant。再来就是 MODULE 这个 constant。其实,只要是你要写 module 就一定要定义这个变量。而且你还要 include module.h 这个档案,因为 _set_ver 就是定义在这里的。
讲到这里,相信各位应该对 module 有一些认识了,以后遇到 module unresolved 应该不会感到困惑了,应该也有办法解决了。
刚 才讲的都是使用别人的 function 上遇到的名字 encode 问题。但是,如果我们自己的 module 想要 export 一些东西让别的 module 使用呢。很简单。在 default 上,在你的 module 里所有的 global variable 和 function 都会被认定为你要 export 出去的。所以,如果你的 module 里有 10 个 global variable,经由 ksyms,你可以发现这十个 variable 都会被 export 出去。这当然是个很方便的事啦,但是,你知道,有时候我们根本不想把所有的 variable 都 export 出去,万一有个 module 没事乱改我们的 variable 怎幺办呢 ? 所以,在很多时候,我们都只会限定几个必要的东西 export 出去。在 2.2.1 之前的 kernel (不是很确定) 可以利用 register_symtab 来帮我们。但是,现在更新的版本早就出来了。所以,在此,我会介绍 kernel 2.2.1 里所提供的。kernel 2.2.1 里提供了一个 macro,叫做 EXPORT_SYMBOL,这是用来帮我们选择要 export 的 variable 或 function。比方说,我要 export 一个叫 full 的 variable,那我只要在 module 里写:
EXPORT_SYMBOL(full);
就 会自动将 full export 出去,你马上就可以从 ksyms 里发现有 full 这个变量被 export 出去。在使用 EXPORT_SYMBOL 之前,要小心一件事,就是必须在 gcc 里定义 EXPORT_SYMTAB 这个 constant,否则在 compile 时会发生 parser error。所以,要使用 EXPORT_SYMBOL 的话,那 gcc 应该要下:
gcc -c -D__KERNEL__ -DMODULE -DMODVERSIONS -DEXPORT_SYMTAB \
main.c -include /usr/src/linux/include/linux/modversions.h
如果我们不想 export 任何的东西,那我们只要在 module 里下
EXPORT_NO_SYMBOLS;
就 可以了。使用 EXPORT_NO_SYMBOLS 用不着定义任何的 constant。其实,如果各位使用过旧版的 register_symbol 的话,一定会觉得新版的方式比较好用。至少我是这样觉得啦。因为使用 register_symbol 还要先定义出自己的 symbol_table,感觉有点麻烦。
发表评论
-
strlcpy 的历史
2012-11-05 18:51 711strlcpy 并不属于 ANSI C,至今也还不是标准 ... -
c中的移位操作
2012-04-12 18:18 1013位移位运算符是将数据看成二进制数,对其进行向左或向 ... -
为什么要用补码来做存储
2012-04-12 18:02 2241看了些补码的知识,摘抄了些,自己整理了些。 顺便带着两个 ... -
google test 使用
2009-01-03 13:59 3554安装: 下载Google C++ Testi ... -
string 的 data() 和c_str()
2008-12-24 01:17 1257data 是字符数组,里面有 '\0 '当然也不会 ... -
C/C++ unit testing tools (18 found)
2008-12-19 01:27 1979C/C++ unit testing tools (18 f ... -
climits中的符号常量
2008-12-10 11:43 1152climits中的符号常量 符号常量 ... -
ICE初次
2008-09-02 01:48 1901按照某人的说法:跨平台的C++网络编程ICE才是王道。于是,我 ... -
对 pthread_cond_wait 的错误理解
2008-08-28 15:52 2098在线程的调度中经常会用到 pthread_cond_wait ... -
环形缓冲
2008-08-27 17:20 960/** * Copyright (c) 2008, ×××研 ... -
Linux下C语言编程的 RPC远程调用编程
2008-07-17 15:38 3423在查看libc6-dev软件包提供的工具(用 dpkg -L ... -
C++中重载操作符时什么时候定义成友元,什么时候定义为成员方法
2008-07-10 18:05 3550在C++语言中,可以用关键字operator加上运算符来表示函 ... -
c++中的存储类型
2008-07-06 00:46 1923存储类型是从变量的存 ... -
libevent 一个time server
2008-05-19 11:20 1307#include <netinet/in.h> # ... -
自己动手改写komodo sourcetree插件 对C/C++的支持
2008-04-16 22:11 1405其实很简单了, 找到sourcetree.js 的 ... -
GNU C的 __attribute__ 机制
2008-04-15 15:34 774GNU C 的一大特色(却不被初学者所知)就是 __attri ... -
dynamic_cast、static_cast、const_cast 和 reinterp
2008-04-10 15:16 1392dynamic_cast、static_cast、co ... -
static_cast、dynamic_cast、reinterpret_cast、和const_c
2008-04-10 15:14 6243static_cast、dynamic_cast、reinte ... -
关于Linux下C/C++程序编译
2007-08-23 18:15 3687在编译之前我们需要 ... -
使用 setfill、setw 和 setprecision 基数的示例
2007-08-23 19:00 2731使用 setfill、setw 和 setprecision ...
相关推荐
这不仅能够有效地训练学生的听力理解能力,还能够通过生动有趣的方式让学生认识和理解诸多基础词汇和句型。例如,自我介绍“I’m…”、日常问候语“Hello, Good morning/afternoon”、询问姓名“What’s your name?...
这篇文档是关于小学六年级英语下册Module 4 Unit 1的教学教案,主题为"I’m making Daming’s birthday card.",旨在帮助学生掌握特定的英语语句和词汇,同时培养他们的语言运用能力。 教学目标主要包含三个方面: ...
测试题目精选自3A模块第一单元“认识你”,通过对词汇、句子以及基本问答对答的理解和书写能力的考核,为学生和教师提供了学习和教学的重要反馈。 在听力部分,测试题特别设计了四个环节以全面考察学生的听力能力。...
句子排序题型要求学生在听懂录音的基础上,运用逻辑思维能力对句子进行合理排序,这不仅锻炼了学生的听力和理解力,也加强了他们对英语句子结构的认识。学生需要依靠对日常活动的熟练掌握,完成此类题型。 此外,...
学生需要书写正确的句子,例如"We visited lots of places.",这不仅考察了学生的书写规范性和拼写准确性,更是对所学知识的实际应用。将单词组成句子,如"Daming goes to the park on Tuesday.",则检验了学生对...
写出听到的数字环节,进一步巩固了学生对数字的认识和书写能力。而听录音选择号码则是对学生快速反应和听力理解的检验。学生需要根据录音内容,迅速而准确地选出正确的号码,这不仅考验了他们的听力,也检验了快速做...
这样的练习题不仅能够让学生在书写的过程中思考和运用所学的词汇,还能够激发学生对英语学习的兴趣。比如,在描述动物的名字时,学生需要使用到"its name is"或"he/she is called"等句型,这不仅练习了名词的所有格...
单词拼写是学习英语的基石,对于提高阅读理解能力和书写表达能力至关重要。 随后,学生将接触到英语学习中的核心内容——时态和语法规则。本单元的练习包括了形容词比较级、虚拟语气、动词不定式、现在分词作定语...
通过这样的分类,学生不仅能提高记忆单词的效率,还能在学习过程中,对英语的词性有一个初步的认识和区分,这对于构建他们的语言框架是非常有帮助的。 总结来说,这套外研版(一起)一年级英语下册Module 3 Unit 1 ...
综上所述,Module 1 Unit 1 的练习题设计精巧,涵盖了英语学习的多个基础方面,旨在帮助二年级学生在轻松愉快的氛围中逐渐建立起对英语的基本认识和使用能力。教师在教学过程中应当采取有效的引导方法,鼓励学生积极...
写的练习则是通过填空和造句等方式,加强学生对所学语法和词汇的书写应用。 教案的设计从一个简单的热身活动开始,让学生通过提问和回答熟悉"Whose + 名词 + is this?"的句型。这种方法不仅让学生在实际情境中练习...
在笔试部分,第一题的连线题,要求学生通过视觉和逻辑的双重匹配,建立起对基础英语数字词汇的认识。例如,学生需要将“one”与“一”这一对中英文数字配对,通过这一过程,学生不仅能够巩固对数字单词的记忆,还能...
I like it very much." 这是一个开放性的写作练习,目的是提高学生的描述能力和创造力,同时加深对植物特性的认识。 总结来说,这份练习涵盖了英语的基础语法、词汇、读写、听力和口语技能的综合训练,对于提升三...
这个练习让学生熟悉并正确书写人物名字、名词和动词短语,如"Mr Li"(李老师)、"leaf"(叶子)、"plant"(植物)、"look at"(看)以及描述植物特征的词组"some roots"(一些根)和"a big trunk"(一个大树干)。...
正确识别单词是理解语句和句子的基础,也是培养学生对英语音标有深刻认识的重要步骤。 接下来是反义词选择。这类题目要求学生听出单词后,选择它的反义词,如"small"与"tall"。这样的练习不仅能够加深学生对词汇的...
其次,要求学生将小写字母连接到对应的大写字母,这不仅锻炼了学生对字母表顺序的记忆,还加强了他们对字母书写规则的认识。 第三,根据英文名字首字母的字母表顺序进行排序,这不仅测试学生对字母顺序的掌握程度,...
对于二年级的孩子来说,外研版(一起)英语二年级上册的Module1 Unit2 "I like football" 课件,就是这样一个充满魔力的教学工具。它不仅仅是一套PPT演示文稿,更是一次全新的语言探索旅程。 当孩子们跟随“the ABC...
笔试部分同样重要,它从书写和认知两个维度对学生的英语能力进行评估。第五题的单词拼写练习,要求学生填写适当的字母或字母组合,如“grn”、“h__”,这是对学生单词拼写能力的直接检测。第六题的图片与词汇匹配,...
这一题型考察学生对单词形态的认识及书写规范,比如“cake”是否能正确书写,是否理解单词的单复数形式。而第六题则侧重于检验学生对英语基础语法知识的掌握,如名词的复数形式,“sweets”的复数是“sweet”,还有...
黑板书写将展示本单元的主题及重点词汇,以帮助学生复习和记忆。 课后作业是完成工作簿中的练习,包括Ex. 1, 2, 3 & 4,以巩固课堂所学知识。 这堂课的设计旨在全方位提升学生的语言技能,并结合实际生活情境,使...