欢迎来到天天文库
浏览记录
ID:52299015
大小:77.00 KB
页数:15页
时间:2020-03-26
《嵌入式Linux开发视频教程配套PPT课件主讲熊伟 第二章.doc》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、第2章编写和运行模块非常高兴现在终于可以开始编程了。本章将介绍模块编程和内核编程所需的所有必要的概念。我们将要不多的篇幅来编写和运行一个完整的模块。这种专业技术(expertise)是编写如何模块化设备驱动程序的基础。为了避免一下子给你很多概念,本章仅介绍模块,不介绍任何类别的设备。这里介绍的所有内核内容(函数,变量,头文件和宏)也将在本章最后的参考部分再次介绍。如果你已经座不住了,下面的代码是一个完整的“Hello,World”模块(这个模块事实上并没什么功能)。它可以在Linux2.0或以上版本上编译通过,但不能
2、低于或等于1.2,关于这一点本章将在稍后的部分解释*正如第1章,“Linux内核简介”,中所述,这个例子和本书中的所有其他例子都可以从O’Reilly的FTP站点上下载。。(代码)函数printk是由Linux内核定义的,功能与printf相似;模块可以调用printk,这是因为在insmod加载了模块后,模块就被连编到内核中了,也就可以调用内核的符号了。字符串<1>是消息的优先级。我之所以在模块中使用了高优先级是因为,如果你使用的是内核2.0.x和旧的klogd守护进程,默认优先级的消息可能不能显示在控制台上(关于
3、这个问题,你可以暂且忽略,我们将在第4章,“调试技术”,的“Printk”小节中详细解释)。通过执行insmod和rmmod命令,你可以试试这个模块,其过程如下面的屏幕输出所示。注意,只有超级用户才能加载和卸载模块。(代码)正如你所见,编写一个模块很容易。通过本章我们将深入探讨这个内容。模块与应用程序在深入探讨模块之前,很有必要先看一看内核模块与应用程序之间的区别。一个应用从头到尾完成一个任务,而模块则是为以后处理某些请求而注册自己,完成这个任务后它的“主”函数就立即中止了。换句话说就是,init_module()(
4、模块的入口点)的任务就是为以后调用模块的函数做准备;这就好比模块在说,“我在这,这是我能做的。”模块的第二个入口点,cleanup_module,仅当模块被下载前才被调用。它应该跟内核说,“我不在这了,别再让我做任何事了。”能够卸载也许是你最喜爱的模块化的特性之一,它可以让你减少开发时间;你无需每次都花很长的时间开机关机就可以测试你的设备驱动程序。作为一个程序员,你一定知道一个应用程序可以调用应用程序本身没有定义的函数:前后的连编过程可以用相应的函数库解析那些外部引用。printf就是这样一个函数,它定义在libc中
5、。然而,内核要仅能连编到内核中,它能调用的仅是由内核开放出来的那些函数。例如,上面的helllo.c中的printk函数就是内核版的printf,并由内核开放给模块给使用;除了没有浮点支持外,它和原函数几乎一模一样。如图2-1所示,它勾画了为了在运行的内核中加入新函数,是如何调用函数以及如何使用函数指针的。由于没有库连接到模块中,源码文件不应该模块任何常规头文件。与内核有关的所有内容都定义在目录/usr/include/linux和/usr/include/asm下的头文件中。在编译应用程序也会间接使用这些头文件;其
6、中的内核代码通过#ifdef__KERNEL__保护起来。这两个内核头文件目录通常都是到内核源码所在位置的符号连接。如果你根本就想要整个内核源码,你至少还要这两个目录的头文件。在比较新的内核中,你还可以在内核源码中发现net和scsi头文件目录,但很少有模块会需要这两个目录。内核头文件的作用将稍后需要它们的地方再做介绍,内核模块与应用程序的另一个区别是,你得小心“名字空间污染”问题。程序员在写小程序时,往往不注意程序的名字空间,但当这些小程序成为大程序的一部分时就会造成许多问题了。名字空间污染是指当存在很多函数和全局
7、变量时,它们的名字已不再富有足够的意义来很容易的区分彼此的问题。不得不处理这种应用程序的程序员必须花很大的精力来单单记住这些“保留”名,并为新符号寻找新的唯一的名字。如果在写内核代码时出现这样的错误,这对我们来说是无法忍受的,因为即便最小的模块也要连编到整个内核中。防止名字空间污染的最佳方法是把所有你自己的符号都声明为static的,而且给所有的全局量加一个well-defined前缀。此外,你还可以通过声明一个符号表来避免使用static声明,这些内容将在本章的“注册符号表”小节中介绍。即便是模块内的私有符号也最好
8、使用选定的前缀,这样有时会减轻调试的工作。通常,内核中使用的前缀都是小写的,今后我们将贯彻这一约定。内核编程和应用程序编程的最后一个区别是如何处理失效:在应用程序开发期间,段违例是无害的,利用调试器可以轻松地跟踪到引起问题的错误之处,然而内核失效却是致命的,如果不是整个系统,至少对于当前进程是这样的。我们将在第4章“调试系统失效”小节中介绍如何
此文档下载收益归作者所有