- 浏览: 228455 次
- 性别:
- 来自: 北京
最新评论
-
qq452739204:
如果构造的报文大于mtu值,是否需要分片之后再发送出去列?
Linux内核构造数据包并发送(二)(dev_queue_xmit方式) -
xingzengmou:
你好,我搞的原理跟你差不多,但播放的时候有papapa的声音, ...
AudioRecord和AudioTrack类的使用 -
wenjiefeng:
楼主,你有录制pcm格式和播放pcm格式的录音器的demo吗, ...
AudioRecord和AudioTrack类的使用 -
lovepeakingA:
...
AudioRecord和AudioTrack类的使用 -
ZaneLee007:
假的,不学无术
Android禁用键盘的所有按键
库的作用
大体上库的存在,有两方面的原因,一是代码的复用,二是声明和实现的分离。将功能相近的使用模块封装成库,使代码的复用、管理和分发变得简单了许多,例如著名的开源图形库ncurses,你可以自行编译,更可以直接使用已经编译好的现成的库文件。另外,由于库是二进制文件,某种意义上讲,将功能的实现部分隐藏了起来,这就为商业代码的保护提供了一种方式。
库文件按照链接方式和时机,可以分为动态库和静态库,下面分别介绍它们在Linux环境中的创建和使用方法。
静态链接库
静态库是指在程序的链接阶段,其中被用到的代码会被直接链接到可执行文件中的库。静态链接的可执行程序包含了其所需的全部库函数:所有库函数都连接到程序中。 这类程序是完整的,其运行不需要外部库的支持。 静态链接程序的优点之一是其安装之前不需要做环境准备工作 。
Linux中,静态库的扩展名通常为.a,它仅仅是一些目标文件(.o)的归档(archive)或者说打包,另外,为了链接时能够快速地定位其中的符号(函数、变量名等),静态库还会包含一个对其中符号的索引。
创建静态库的过程十分简单,除编译所必须的工具之外,要用到的命令只有两个ar和ranlib。ar可以将各个目标文件进行归档,ranlib对ar生成的归档文件(即静态库文件)进行索引。假设现在有这样几个源文件:plus.c, sub.c及相应的头文件,另外还有一个用来调用库文件中函数的主文件main.c,它们的内容分别是:
plus.c,
#include "plus.h" int plus(int a, int b) { return a + b; }
sub.c,
#include "sub.h" int sub(int a, int b) { return a - b; }
main.c,
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include "plus.h" int main(int argc, char **argv) { int a = plus(1, 2); printf("%d\n", a); return 0; }
下面将plus.c和sub.c编译,制作成静态库libmath.a,依次执行:
$ cc main.c -L. -lmath -o main
$ ./main
动态链接库
动态库和静态库相似,也是各个目标文件的集合。但相比静态链接的程序,动态链接可执行程序要小得多:这类程序运行时需要外部共享 函数库的支持,因此好像并不完整。除了程序体小之外,动态链接允许程序包指定必须的库,而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库,这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因,当前多数程序采用动态链接技术。
在Linux中的扩展名通常为.so。但在链接时,并不会被链接到可执行文件中,而是在执行时(需要时)由操作系统的动态加载模块动态地加载到内存,并链接到可执行文件地址空间的相应位置。
动态链接库的创建也分为编译和”归档”两个阶段,但不同的是在这两个阶段需要使用一些不同的命令选项。首先,需要将源文件编译成一种成为位置无关码(PIC: Position Independent Code)的目标文件,这种代码可以被加入到内存的任何位置却不需要加载器对其进行重定位,关于这种格式可以参考《链接器与加载器》和《程序员的自我修养–链接装载与库》中较为详尽的描述。接下来需要将这些位置无关码“归档”为.so文件。整个过程只需一个工具即可,即gcc。还是上面的源文件,执行以下命令:
$ cc -c -fpic plus.c sub.c $ cc -shared -o libmath.so *.o |
这样,包含plus.o和sub.o的动态库文件libmath.so就创建完成了。其中cc(gcc的符号链接)命令的-fpic或-fPIC选项使之创建位置无关的目标文件,使用-shared选项可以创建最终的动态库文件。
使用动态库文件有两种方法,一种是让操作系统的动态加载模块(如ld-linux.so.2)在执行时加载动态库。另一种是在代码中使用dl库动态加载库文件。
先介绍下第一种方法。使用这种方法需要在编译可执行文件时指明库名及其路径(对于自己的编写的动态库而言):
|
$ cc main.c -L. -lmath -o main |
这时可执行文件main就被创建了,上面的命令并没有将libmath.so中相应的目标代码链接到main中(你可以对比一下这里的main和静态链接的main的大小),只是在库中查找和确认main.c中用到的符号而已。但通常这个main现在还无法正常执行,这涉及到系统查找动态库的路径问题,系统通常只在某些指定的目录(标准路径)下查找所需的库文件,若在标准路径中无法找到所需的库,则会到环境变量LD_LIBRARY_PATH(如果存在的话)指定的目录下查找,若仍无法找到就会报错。因为libmath.so在main的当前目录中,而当前目录通常并不在标准路径之列。为了使libmath.so能够被找到和加载,你可以把它放到标准路径中,但更好的方法是将其所在目录加入到LD_LIBRARY_PATH变量中。执行下面的命令:
|
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. # 添加当前目录 $ export LD_LIBRARY_PATH # 将环境变量导出,使其在子shell中可用 $ ./main 3 |
下面介绍使用dl库加载动态库,dl库中函数很少很简练,看main.c代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <dlfcn.h> #include "plus.h" int main(int argc, char **argv) { void * lib_handle = dlopen("./libmath.so", RTLD_LAZY); if(lib_handle) { int (*plus_ptr)(int, int) = dlsym(lib_handle, "plus"); if(plus_ptr) { int a = plus_ptr(1, 2); printf("%d\n", a); } dlclose(lib_handle); } return 0; }
main.c中,首先使用dlopen打开需要的动态库,其中参数RTLD_LAZY指明仅当需要调用该库时才进行加载。dlopen返回一个句柄,dlsym使用该句柄和符号来取得相应函数的地址,这里使用int (*)(int, int)函数指针来接收plus函数的地址。接下来使用得到的函数指针调用相应的函数,最后通过dlclose函数来关闭句柄。编译这个程序需要使用dl动态链接库,因此需要使用gcc的-ldl选项:
$ cc main.c -ldl -o main
$ ./main
so与.a文件的对比
最后附上libmath.a和libmath.so文件的内容,使用objdump的-d选项查看的:
libmath.a,
In archive libmath.a: plus.o: file format elf32-i386 Disassembly of section .text: 00000000 <plus>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 8b 45 0c mov 0xc(%ebp),%eax 6: 8b 55 08 mov 0x8(%ebp),%edx 9: 8d 04 02 lea (%edx,%eax,1),%eax c: 5d pop %ebp d: c3 ret sub.o: file format elf32-i386 Disassembly of section .text: 00000000 <sub>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 8b 45 0c mov 0xc(%ebp),%eax 6: 8b 55 08 mov 0x8(%ebp),%edx 9: 89 d1 mov %edx,%ecx b: 29 c1 sub %eax,%ecx d: 89 c8 mov %ecx,%eax f: 5d pop %ebp 10: c3 ret
libmath.so:
libmath.so: file format elf32-i386 Disassembly of section .init: 00000324 <_init>: 324: 55 push %ebp 325: 89 e5 mov %esp,%ebp 327: 53 push %ebx 328: 83 ec 04 sub $0x4,%esp ...... 0000044c <plus>: 44c: 55 push %ebp 44d: 89 e5 mov %esp,%ebp 44f: 8b 45 0c mov 0xc(%ebp),%eax 452: 8b 55 08 mov 0x8(%ebp),%edx 455: 8d 04 02 lea (%edx,%eax,1),%eax 458: 5d pop %ebp 459: c3 ret 45a: 90 nop 45b: 90 nop 0000045c <sub>: 45c: 55 push %ebp 45d: 89 e5 mov %esp,%ebp 45f: 8b 45 0c mov 0xc(%ebp),%eax 462: 8b 55 08 mov 0x8(%ebp),%edx 465: 89 d1 mov %edx,%ecx 467: 29 c1 sub %eax,%ecx 469: 89 c8 mov %ecx,%eax 46b: 5d pop %ebp 46c: c3 ret 46d: 90 nop 46e: 90 nop 46f: 90 nop ...... Disassembly of section .fini: 000004a8 <_fini>: 4a8: 55 push %ebp 4a9: 89 e5 mov %esp,%ebp 4ab: 53 push %ebx 4ac: 83 ec 04 sub $0x4,%esp 4af: e8 00 00 00 00 call 4b4 <_fini+0xc> 4b4: 5b pop %ebx 4b5: 81 c3 40 1b 00 00 add $0x1b40,%ebx 4bb: e8 d0 fe ff ff call 390 <__do_global_dtors_aux> 4c0: 59 pop %ecx 4c1: 5b pop %ebx 4c2: c9 leave 4c3: c3 ret
可见,相对.a,.so有很多额外的代码段,其中比较重要的是<_init>段和<_fini>段。它们分别进行一些前期和后期处理工作,例如<_init>通常在dlopen返回之前执行一些.so库中的一些初始化工作(C++中就可能是全局构造或者静态对象的构造函数)。
转自:http://www.dutor.net/index.php/2010/07/dynamic-static-library/
发表评论
-
Netfilter 地址转换的实现
2011-03-17 23:04 0作者:九贱内核版本:2 ... -
Linux内核构造数据包并发送(二)(dev_queue_xmit方式)
2011-03-03 12:24 8900linux内核太构造数据包 ... -
Linux内核构造数据包并发送(Netfilter方式)
2011-03-03 12:21 5144一、构造数据包简析 这里并不详细介绍如何在内核中构造数据包,下 ... -
iphdr与tcphdr详解(skb_header_pointer函数分析)
2011-03-01 12:25 4656linux 2.6.26 下获取tcp信息: tcph=sk ... -
unp.h文件内容
2010-11-28 15:33 2153/* Our own header. Tabs are se ... -
inet_pton和inet_ntop函数
2010-11-28 15:03 1937Linux下这2个IP地址转换函数,可以在将IP地址在“点分十 ... -
linux类原版电子书589本
2010-10-27 16:13 4218ftp://202.96.64.144/pub/books/( ... -
Linux下线程同步对象——互斥量
2010-10-09 10:47 1618进程是Linux资源分配的对象,Linux会为进程分配虚 ... -
系统信息相关命令
2010-09-27 15:55 833系统 # uname -a ... -
Linux中实现30分钟无操作自动关机
2010-09-27 15:42 1722这是一个自动关机的小程序。该程序可以守护进程的方式运行, ... -
linux IPC-消息队列
2010-09-27 14:02 2388几乎所有的 Linux 发行版本都包含 ipcs 命 ... -
8)Linux程序设计入门--网络编程(下)
2010-09-26 14:12 1097网络编程(7) 7. TCP/IP协议 你也许听说过T ... -
8)Linux程序设计入门--网络编程 (上)
2010-09-26 14:07 1232Linux系统的一个主要 ... -
7)Linux程序设计入门--线程操作
2010-09-26 13:58 946前言:Linux下线程的创 ... -
6)Linux程序设计入门--消息管理
2010-09-26 13:56 987前言:Linux下的进程通 ... -
5)Linux程序设计入门--信号处理
2010-09-26 13:54 1025Linux下的信号事件 前 ... -
4)程序设计入门--时间概念
2010-09-26 13:50 794前言:Linux下的时间概 ... -
3)Linux程序设计入门--文件操作
2010-09-26 13:48 1004Linux下文件的操作 前言: 我们在这一节将要讨论 ... -
2)Linux程序设计入门--进程介绍
2010-09-26 11:05 915前言: 这篇文章是用 ... -
1)Linux程序设计入门--基础知识
2010-09-26 11:02 847Linux下C语言编程基础知识 前言: 这篇文章介绍 ...
相关推荐
在Unix/Linux环境下,创建进程池通常使用`fork()`系统调用,通过复制父进程来创建子进程。`fork()`成功后,父进程继续处理新的请求,而子进程则成为工作进程。另外,`pthread`库也可以用于创建线程池,但线程池与...
《理解Unix/Linux编程源代码》是Bruce Molay撰写的一本实战型教程,旨在帮助读者深入理解和掌握Unix/Linux系统下的编程技巧。这本书通过丰富的实例和源代码解析,将复杂的系统编程概念化,使得初学者和有经验的...
《Unix/Linux 编程实践教程》是一本深入探讨Unix和Linux操作系统编程的宝贵资源,旨在帮助读者理解系统组件的工作原理并掌握实际编程技巧。通过本书的学习,你可以深入了解这两个广泛使用的开源操作系统,从而提升你...
在UNIX和LINUX操作系统中,C函数库是编程的基础,为开发者提供了丰富的系统调用和标准库函数。这篇手册详细介绍了这些函数库,是C语言学习者和实践者的重要参考资料。下面将对其中的关键知识点进行深入阐述。 1. **...
在Unix/Linux环境下,C和C++编程是系统级开发的核心技术。这个"UNIX/Linux下C/C++函数速查手册"提供了全面的C和C++函数参考,帮助开发者快速找到所需的函数信息,提升开发效率。以下是一些关键的知识点: 1. **...
在Unix/Linux操作系统中,进程池(Process Pool)是一种高效的资源管理策略,用于处理大量并发请求。它通过预先创建一组固定数量的子进程来提供服务,而不是每次请求到来时都创建新的进程,这样可以减少进程创建和...
《Linux/Unix系统编程手册》是一本深受程序员和系统管理员喜爱的经典著作,它详细阐述了在Linux和Unix操作系统上进行低级编程的各种技术。附录中的代码是书中的实例,旨在帮助读者深入理解和掌握这些系统编程的核心...
《Linux/UNIX系统编程手册》是一本经典的教材,它深入浅出地介绍了Linux和UNIX操作系统下的编程接口。这本书涵盖了各种核心API,包括文件操作、进程管理、网络通信、信号处理等,是学习系统级编程的重要参考资料。...
Linux下C语言开发笔记整理涵盖了从基础知识到网络通信的多个方面,主要围绕在Unix/Linux系统环境下使用C语言进行软件开发的各项技术与理论。以下是从文件提供的信息中提炼的知识点。 ### Unix/Linux系统基本命令和...
本文将深入探讨在Unix和Linux环境下如何有效地管理和维护Oracle数据库。 一、Oracle数据库基础 Oracle数据库是一种关系型数据库管理系统(RDBMS),它支持SQL语言,提供了数据存储、查询、更新和管理的强大功能。在...
总的来说,理解和掌握Linux和Unix下的静态库和动态库的创建和使用方法,对于进行系统级编程和软件开发至关重要。正确选择和管理库可以帮助优化程序性能,减少资源消耗,同时提高代码的复用性和维护性。
6. **线程编程**:多线程是现代程序设计的常见模式,理解和使用pthread库进行线程管理,如线程创建、同步(互斥锁、条件变量)、通信(线程间信号)等。 7. **内存管理**:了解动态内存分配(malloc、calloc、...
9. **编译与构建**:GCC是Unix/Linux下的主要编译器,Makefile用于自动化编译过程,而编译链接时的动态库和静态库也是需要理解的部分。 10. **课后习题解答**:这部分通常包含对上述知识点的实践应用,通过解决实际...
1. **Shell和命令行**:讲解如何使用Bash shell以及命令行工具,这是Linux和UNIX系统中的基本操作环境。 2. **文件I/O**:详述文件操作函数,如open(), read(), write(), close()等,以及文件描述符的概念。 3. **...
本章主要探讨了在Unix/Linux环境下进行程序设计的关键概念和技术,包括系统调用、进程管理、文件I/O、网络编程等方面。 1. **系统调用**:Unix/Linux系统的功能通过系统调用来实现,如创建进程、读写文件、网络通信...
在UNIX/Linux环境下进行C语言编程时,集成MySQL数据库能够提供数据存储和处理能力。要进行MySQL数据库开发,首先需要安装相应的软件包,包括MySQL服务器(如mysql-server-3.23.54a-11)、客户端(如mysql-3.23.54a-...
9. **线程与同步**:在Unix/Linux下,`pthread`库提供了线程创建、同步和互斥锁等功能,如`pthread_create`、`pthread_join`、`pthread_mutex_lock`等。 10. **网络编程**:`socket`函数用于创建套接字,`bind`、`...
在UNIX和Linux系统中,C语言作为一种强大的编程工具,被广泛用于系统开发、软件构建以及各种应用程序的编写。本文将深入探讨在这些操作系统环境下进行C语言程序设计的基础知识和实践技巧。 一、编译器与环境搭建 在...
《Unix环境高级编程》是Unix/Linux系统开发领域的一本经典著作,它深入讲解了在Unix/Linux环境下进行系统级编程的各种技术和方法。对于任何希望在这一领域深入研究的程序员来说,这本书都是不可或缺的参考资料。 ...