1 / 237

嵌入式系统程序设计

嵌入式系统程序设计. 大连理工大学软件学院 嵌入式系统工程系 赖晓晨. L inux库. ★. ★. ★. ★. L inux库概述 库操作工具 静态库 共享库 动态链接库. 一、 L inux库概述. 库的概念:库 是操作系统或者编译器提供的一种目标文件,是可以被多个软件项目使用的二进制 代码集。 库是代码重用思想的体现。 使用库可以节约编程人员大量的时间 。. 库分类. 静态库,是在执行程序运行前就已经加入到执行码中,在物理上成为执行程序的一部分。 共享库,是在执行程序启动时加载到执行程序中,可以被多个执行程序共享使用。

Download Presentation

嵌入式系统程序设计

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 嵌入式系统程序设计 大连理工大学软件学院 嵌入式系统工程系 赖晓晨

  2. Linux库 ★ ★ ★ ★ • Linux库概述 • 库操作工具 • 静态库 • 共享库 • 动态链接库

  3. 一、Linux库概述 • 库的概念:库是操作系统或者编译器提供的一种目标文件,是可以被多个软件项目使用的二进制代码集。 • 库是代码重用思想的体现。 • 使用库可以节约编程人员大量的时间。

  4. 库分类 • 静态库,是在执行程序运行前就已经加入到执行码中,在物理上成为执行程序的一部分。 • 共享库,是在执行程序启动时加载到执行程序中,可以被多个执行程序共享使用。 • 动态链接库,其实并不是一种真正的库类型,应该是一种库的使用技术,应用程序可以在运行过程中随时加载和使用库。

  5. 库命名约定 • 所有库都以lib开头,表示一个库文件; • 文件名以.a结尾的是静态库,以.so结尾的是共享库。

  6. 共享库库名称约定 • 共享库命名规则稍显繁琐,我们来区分一下一下命名: • real name:包含库名、主版本号、次版本号以及发布号等字段,它代表文件中包含了库的代码,这是库的实体文件。 • soname(shared object name):库文件的一个符号链接,一般仅包括库名和主版本号。 • linkername:库文件的符号链接,它仅包含库名,一般供编译器使用。

  7. 共享库库名称约定(续) • 看下面的例子: 在以上信息中: • libpng.so.2.1.0.12是共享库的实名(realname) • libpng.so.2是共享库so名(soname) • libpng.so则是连接名(linkername),用于编译连接。 #ls -l *png* lrwxrwxrwx1rootrootlibpng.so->libpng12.so lrwxrwxrwx1rootrootlibpng.so.2->libpng.so.2.1.0.12 -rw-r--r--1rootrootlibpng.so.2.1.0.12

  8. 常用库 库 头文件 描述 libc.so 无 标准C库 libdb.so db.h 数据库库 libm.so math.h 数学库 libpthread.so pthread.h 多线程库 libz.so zlib.h 压缩例程库 libvga.so vga.h 底层图形库 libcom_err.so com_err.h 出错处理库 libdl.so dlfcn.h 动态加载库

  9. 二、库操作工具 • Linux系统提供很多对库进行操作的工具,具体如下: • nm命令 • ar命令 • ldd命令 • ldconfig命令

  10. 1. nm命令 • 用途:列出库或目标文件的所有符号。 • 查看程序调用什么函数 • 查看一个给定的库或者目标文件是否提供了所需的函数。 • 举例:下图列出了libc.so.6中所有包含sprintf的字符串的符号。

  11. nm命令(续)

  12. 2. ar命令 • 用途:可以建立一个归档文件,通常用来创建静态库。 • 举例:建立静态库 ar rc libmy.a file1.o file2.o …

  13. 3. ldd命令 • 用途:列出为程序正常运行所需要的共享库。 • 举例:利用ldd命令查看bash所依赖的库文件,如下图所示:

  14. ldd命令(续)

  15. 4. ldconfig命令 • 当为系统安装好库文件之后,需要运行ldconfig命令,其功能是根据/etc/ld.so.conf中的路径检查库文件,并为它们创建相应的soname,然后更改ld.so.cache文件。

  16. ldconfig命令(续) • 应用程序执行时,/lib目录下的程序ld-linux.so.X(X是版本号)会首先被运行,这就是Linux系统的程序装载器。 • 装载器负责检查应用程序需要使用的共享库,从ld.so.conf指定的目录中找到这些库并加载,然后把加载信息写入缓存文件/lib/ld.conf.cache中供其他程序使用,以提高系统运行效率。

  17. ldconfig命令(续) • Linux系统下的一个环境变量: • $LD_LIBRARY_PATH:是一个由冒号分隔的目录清单,包含了运行时的共享库,可以指示ld.so到何处搜索没有保存在标准位置的库。 (对应文件为:/etc/ld.so.conf)

  18. 三、静态库 • 静态库一般命名为libxxx.a,采用静态编译得到的程序文件比较大,因为整个函数库都已经被链接到程序中。 • 静态库实质是目标文件的集合,采用ar命令可以创建静态库。首先编写源文件,然后把源文件分别编译为目标文件,注意使用-c选项,然后用ar命令把目标文件归档为一个静态库文件。

  19. 【例6-1】 /* ch6_1 main.c */ void hello(); void bye(); #include <stdio.h> int main() { hello(); bye(); return 0; } 静态库源文件:

  20. 【例6-1】(续) /* ch6_1 hello.c */ #include <stdio.h> void hello () { printf("hello everybody!\n"); } /* ch6_1 bye.c */ #include <stdio.h> void bye() { printf("goodbye!\n"); } 静态库源文件:

  21. 【例6-1】(续)

  22. 四、共享库 • 共享库一般命名为libxxx.so,与静态库不同,共享库并不会在程序编译时被添加到可执行文件中,而是在程序执行时才会被链接,因此采用动态编译方式得到的可执行程序文件比较小,但是程序的执行依赖于环境,当前操作系统中必须存在程序需要的共享库,否则程序不能执行。 • 编译共享库时要用gcc的-shared和-fPIC选项,前者表示编译为共享库,后者表示把库文件编译成位置无关代码,否则将来程序无法运行。

  23. 共享库的生成和使用方法

  24. 共享库(续) 用ldd命令检查main程序运行时所需要的动态库,结果如下图所示:

  25. 库依赖关系

  26. 五、动态链接库 • 打开共享库 • 提取函数地址 • 关闭共享库 • 共享库错误函数

  27. 1. 打开共享库 • 函数原型: void *dlopen ( const char *libname, int flag); • 功能描述:将libname代表的库装载到内存,flag是打开共享库的方式。如果函数调用成功,返回库句柄,如果该库已经被装载过,则返回同样的句柄,如果调用失败,返回NULL。如果要装载的库依赖其他库,必须先装载依赖库。

  28. 打开共享库(续) • 功能描述:参数中的libname一般是库的绝对路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻: • 根据环境变量LD_LIBRARY_PATH查找; • 根据/etc/ld.so.cache查找; • 依次在/lib和/usr/lib目录查找。 • flag参数表示处理未定义函数的方式 • RTLD_LAZY:暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再报错 • RTLD_NOW:马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。 • RTLD_GLOBL:使共享库定义的符号全局可见。

  29. 2. 提取函数地址 • 函数原型: void *dlsym(void *handle, char *symbol) • 功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。

  30. 3. 关闭共享库 • 函数原型为: int dlclose (void *handle); • 功能描述:将已经装载的库句柄减一,如果句柄减至零,则该库会被卸载。

  31. 4. 共享库错误函数 • 函数原型: const char *dlerror(void); • 功能描述:当动态链接库操作函数(dlopen、dlsym、dlclose)执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

  32. 【例6-2】 /* ch6_2 sub.h */ #ifndef SUB_H #define SUB_H int square(int); #endif /* ch6_2 sub.c */ #include <stdio.h> int square(int a) { printf("the square of the number is:"); return a*a; } 源文件

  33. 【例6-2】(续) /* ch6_2 main.c */ #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include "sub.h" int main() { void *handle; int (*fp)(int); char *error; int n; int result; printf("please input a number.\n"); scanf("%d",&n); 声明函数指针,将来用来执行希望使用的函数

  34. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 打开动态链接库 RTLD_LAZY: 只有在使用时才检查错误

  35. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 如未成功,handle为NULL,则显示错误信息

  36. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 找到需要的函数

  37. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 如未找到函数,显示error中的错误信息

  38. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 用函数指针调用相应函数

  39. handle=dlopen("/lib/libmydll.so", RTLD_LAZY); if(!handle) { printf("%s\n",dlerror()); } fp=dlsym(handle, "square"); if((error=dlerror())!=NULL) { printf("%s\n",error); dlclose(handle); exit(1); } printf("now call the function square.\n"); result = (*fp)(n); printf(" %d\n",result); dlclose(handle); return 0; } 关闭库

  40. 动态链接库建立步骤 • 建立动态链接库 gcc –shared –fPIC –o libmydll.so sub.c -wall

  41. 动态链接库建立步骤 • 建立动态链接库 • 移动动态链接库到系统标准库目录 gcc –shared –fPIC –o libmydll.so sub.c -wall mv libmydll.so /lib

  42. 动态链接库建立步骤 • 建立动态链接库 • 移动动态链接库到系统标准库目录 • 生成可执行文件 gcc –shared –fPIC –o libdy2.so k1.c k2.c mv libdy2.so /lib gcc main.c –o main –lmydll -ldl -Wall

  43. 动态链接库建立步骤 • 建立动态链接库 • 移动动态链接库到系统标准库目录 • 生成可执行文件 • 执行文件 gcc –shared –fPIC –o libmydll.so sub.c -wall mv libdy2.so /lib gcc main.c –o main–lmydll2 -ldl -Wall ./main

  44. 执行结果

  45. 嵌入式Linux操作系统 • 嵌入式Linux操作系统简介 • 启动引导程序vivi • CRAMFS文件系统 • 构建嵌入式Linux系统

  46. 一、嵌入式Linux操作系统简介 • 嵌入式Linux是以Linux为基础,经过裁剪之后适用于嵌入式设备的操作系统,广泛应用在移动电话、PDA、媒体播放器、消费性电子产品以及航空航天等领域。Linux系统具有开源、可裁剪、免费、完全支持TCP/IP协议、可移植性好、运行稳定等特点,嵌入式Linux继承了这些特性。

  47. 嵌入式Linux操作系统简介(续) • 与uClinux系统相同,基本的嵌入式Linux操作系统包括三个组成部分:Bootloader,负责引导系统;操作系统内核,负责管理硬件,为上层软件提供运行环境;文件系统,负责管理文件。

  48. Linux内核源码目录树 • arch:包含所有体系结构相关的内核代码,可以在其中找到Linux目前支持的所有硬件体系结构; • kernel:包含Linux内核代码。 • drivers:包含设备驱动程序源代码; • fs:包含文件系统实现代码;

  49. Linux内核源码目录树(续) • include:包含各种体系结构下编译内核所需要的头文件; • init:包含内核初始化源代码; • ipc:包含进程间通信源代码; • mm:包含内存管理源代码; • net:包括网络相关源代码。

  50. 二、启动引导程序vivi • vivi简介 • vivi的工作过程 • vivi的工作模式 • vivi的命令接口 • vivi命令实现的数据结构

More Related