linux笔记归纳8:库制作与原理

📅 2026/7/12 23:58:19
linux笔记归纳8:库制作与原理
库制作与原理目录库制作与原理一、库的概念二、静态库.a2.1.静态库的本质2.2.静态库的生成2.3.静态库的使用三、动态库.so3.1.动态库的生成3.2.动态库的使用四、目标文件.o五、ELF文件二进制5.1.ELF格式文件的类型5.2.ELF格式文件的组成六、ELF从形成到加载6.1.ELF形成可执行文件6.2.ELF可执行文件加载七、链接与加载7.1.静态链接7.2.ELF加载与进程地址空间7.3.动态链接与动态库加载7.3.1.动态链接7.3.2.动态库的相对地址7.3.3.动态库的函数调用7.3.4.加载地址重定位7.3.5.全局偏移量表GOT7.3.6.PIC地址无关代码7.3.7.库间依赖7.3.8.延迟绑定一、库的概念库写好的现有的成熟的可复用的代码一种二进制形式的代码可以被操作系统载入内存执行静态库.aLinux 、.libwindows动态库.soLinux、.dllwindows动静态库中不需要包含main函数动静态库的本质是源文件(.c)对应的目标文件(.o)// ubuntu 动静态库 // C $ ls -l /lib/x86_64-linux-gnu/libc-2.31.so -rwxr-xr-x 1 root root 2029592 May 1 02:20 /lib/x86_64-linux-gnu/libc-2.31.so $ ls -l /lib/x86_64-linux-gnu/libc.a -rw-r--r-- 1 root root 5747594 May 1 02:20 /lib/x86_64-linux-gnu/libc.a // C $ ls /usr/lib/gcc/x86_64-linux-gnu/9/libstdc.so -l lrwxrwxrwx 1 root root 40 Oct 24 2022 /usr/lib/gcc/x86_64-linux-gnu/9/libstdc.so $ ls /usr/lib/gcc/x86_64-linux-gnu/9/libstdc.a /usr/lib/gcc/x86_64-linux-gnu/9/libstdc.a二、静态库.a2.1.静态库的本质目标文件的打包一种归档文件不需要用户解包而是用gcc/g直接进行链接2.2.静态库的生成ararchive命令归档常用选项-rcreplace and createmakefile文件2.3.静态库的使用常用选项-L指定库路径-I指定头文件搜索路径-l指定库名//1头⽂件和库⽂件安装到系统路径下 $ gcc main.c -lmystdio //2头⽂件和库⽂件和我们⾃⼰的源⽂件在同⼀个路径下 $ gcc main.c -L. -lmymath //3头⽂件和库⽂件有⾃⼰的独立路径 $ gcc main.c -I头⽂件路径 -L库⽂件路径 -lmymath生成目标文件静态库删除程序照样运行库文件名去掉前缀lib去掉后缀.so或.a库是要被安装到系统中的系统中默认的头文件路径在/usr/include路径下系统中默认的库文件路径在/lib64路径下三、动态库.so3.1.动态库的生成makefile文件3.2.动态库的使用只告诉gcc动态库的路径但系统无法找到动态库而静态库在链接时直接将库的实现内容拷贝到了可执行程序一旦形成可执行程序可执行程序不再依赖静态库方法1用cp指令将动态库拷贝到操作系统内部方法2将动态库的软链接存放在操作系统内部方法3使用环境变量$LD_LIBRARY_PATHOS在运行程序的时候要查找动态库也会在环境变量LD_LIBRARY_PATH下查找动态库该环境变量经常是空的需要用户自己添加的动态库所在的路径方法4系统配置文件/etc/ld.so.conf.d/中创建.conf文件将动态库路径写入文件输入ldconfiggcc/g默认使用动态库如果必须要用静态链接需要加-static一旦带了-static就必须要有对应的静态库否则会链接报错只存在静态库可执行程序对于该库只能进行静态链接在Linux系统下默认情况下安装的大部分库都是静态库库应用程序 1 nvs不仅可以形成可执行程序也可以形成动静态库四、目标文件.o.o/.obj可重定位目标文件五、ELF文件二进制5.1.ELF格式文件的类型可重定位文件.o、可执行文件.exe共享目标文件.so内核转储进程上下文5.2.ELF格式文件的组成ELF头ELF header描述文件的主要特性程序头表program header table列举所有的有效段和它们的属性节头表section header table描述节的属性节sectionELF文件中的基本组成单位包含了特定的数据.text节程序代码指令.data节初始化的全局变量局部静态变量.rodata节只读的数据C语言的字符串存储在text段中.bssbetter save space节未初始化的全局变量未初始化的静态局部变量.symtab节Symbol Table符号表源码中函数名变量名和代码的对应关系.got.plt节.got保存全局偏移表.got节与.plt节一起提供了动态库的访问入口磁盘上只存储未初始化全局变量的描述等程序加载到内存后再在内存中申请空间并且初始化为0减少了可执行程序占据的磁盘空间符号表的形式char lable[] helloworld\0func\0libc\0六、ELF从形成到加载6.1.ELF形成可执行文件第一步将多份C/C源代码翻译成目标.o文件 动静态库第二步将多份.o文件的section进行合并6.2.ELF可执行文件加载一个ELF有多种不同的section加载到内存时会进行合并形成segment合并原则相同属性可读可写可执行需要加载时申请空间合并方式记录在ELF的程序表头合并原因减少页面碎片提高内存使用率实现不同权限的访问控制示例页面大小为4096字节4KB.text为4097字节.init为512字节如果不合并要占用3个页面如果合并只要占用2个页面查看可执行文件的section的内容查看可执行文件合并segment的方式查看ELF头magic用来表面文件的类型链接视图对应节头表合并section形成segment在链接的时候作用执行视图对应程序头表告诉操作系统如何加载可执行文件完成进程的内存初始化以及加载进内存后的哪些分段是可读可写只读和可执行的七、链接与加载7.1.静态链接静态链接的本质把.o文件进行链接查看编译后的.o目标文件对.o文件进行反汇编未链接时调用的库函数与其他目标文件函数的地址都为00 00 00 00查看code.o的符号表puts方法UDF未定义查看hello.o的符号表puts方法和run方法UDF未定义两个文件合并后hello文件会找到code文件中的run方法和库文件合并后两个文件都会找到库文件中的puts方法查看main.exe的符号表两个.o文件的run函数与main函数代码被合并到代码段并且进行统一的编址查看main.exe的反汇编链接的时候会修改,o中未定义的函数地址合并完成后会进行call地址静态链接就是将所有目标文件和用到的静态库拼装成一个可执行文件所有的模块组合在一起后链接器会根据重定位表修正函数变量地址7.2.ELF加载与进程地址空间一个可执行程序在未加载到内存前也有地址磁盘上的可执行程序它的代码与数据的编址是逻辑地址起始地址偏移量segments、函数、变量的起始地址设为0就成了线性地址平坦模式编址线性地址加载进内存后从进程的视角来看就是虚拟地址空间Linux中main函数的入口程序是start函数mm_struct和vm_area_struct在进程创建的时候根据ELF文件中s egments的起始地址和长度来初始化[startend]范围数据然后再用详细的地址填充页表7.3.动态链接与动态库加载7.3.1.动态链接动态链接的本质将链接的整个过程推迟到程序加载被进程看到将动态库映射进程的虚拟地址空间被进程调用在进程的虚拟地址空间中进行跳转多进程共享动态库在C/C程序中程序的入口点是start函数是一个由链接器提供的特殊函数设置堆栈为程序创建一个初始的堆栈环境初始化数据段将程序的数据段从初始化的数据段复制到相应的内存位置清零未初始化的数据段动态链接调用动态链接器的代码解析程序所依赖的动态库并且加载这些动态库到内存Linux通过环境变量和配置文件来指定动态库的搜索路径调用_libc_start_main设置信号处理函数初始化线程库调用main函数_libc_start_main调用main函数将执行控制权交给用户代码处理main函数返回值_libc_start_main处理main函数返回值调用_exit函数终止程序7.3.2.动态库的相对地址动态库为了随时进行加载为了支持映射到任意进程的任意位置对动态库中的方法进行了统一的编址采用相对编址的方法进行7.3.3.动态库的函数调用动态库映射到当前进程的虚拟地址空间中已知库在虚拟地址空间的起始地址库中每个方法的偏移量通过库的起始虚拟地址方法偏移量就可以定位库中的方法从代码区跳转到共享区调用完毕后再返回到代码区7.3.4.加载地址重定位在程序运行之前先把所有的动态库加载并映射获取动态库的起始虚拟地址然后再对加载到内存中的程序的库函数调用地址进行修改在内存中二次设置7.3.5.全局偏移量表GOT加载地址重定位会修改代码区的数据而代码区的数据不可被修改动态链接在.data中专门预留了一片用来存放函数的跳转地址的空间全局偏移量表global offset table库函数偏移量库起始地址7.3.6.PIC地址无关代码动态库不需要做任何修改被加载到任意内存地址都能够正常运行并且能够被所有进程共享所以动态链接时需给编译器指定-fPICPIC 相对编址GOT表与.text的相对位置 GOT库函数偏移量 动态库起始地址7.3.7.库间依赖不仅仅由可执行程序调用库库也会调用其他的库所以库也有.GOT7.3.8.延迟绑定PLTProcedure Linkage Table延迟绑定动态链接在程序加载的时候需要对大量的函数进行重定位为了降低开销操作系统提供延迟绑定进行优化将重定位的过程延迟到函数第一次被调用的时候因为绝大多数动态库中的函数在运行时不会用到