ELF文件——动态链接
前言
下文所示案例为运行在armV7架构、linux平台之下的动态库文件。
ELF文件格式
链接器以ELF文件的固定格式对目标程序进行链接,程序加载器以ELF文件的固定格式对其进行解析。ELF文件的组成框架在链接器和加载器的视角中分别如下:
如上图所示,链接器以section为单位对数据进行组织,以section header table对section进行描述,而忽略program header table中的内容;加载器以segment为单位对数据进行组织,以program header table对segment进行描述,而忽略section header table中的内容。其中,加载器中的segment实际由单个或多个链接器中的section组成。ELF文件包含三种类型:可重定位文件(relocatable)—编译器和汇编器产生的.o文件,被Linker所处理;可执行文件(executable)—Linker对.o文件进行处理输出的文件,进程映像;共享对象文件(shared object)—动态库文件.so。
ELF Header
通过readelf工具,查看ELF Header中的内容如下:
ELF Header:Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32Data: 2's complement, little endianVersion: 1 (current)OS/ABI: UNIX - System VABI Version: 0Type: DYN (Shared object file)Machine: ARMVersion: 0x1Entry point address: 0x2154Start of program headers: 52 (bytes into file)Start of section headers: 660064 (bytes into file)Flags: 0x5000400, Version5 EABI, hard-float ABISize of this header: 52 (bytes)Size of program headers: 32 (bytes)Number of program headers: 8Size of section headers: 40 (bytes)Number of section headers: 38Section header string table index: 37
ELF Header记录了该文件的基本信息:该文件类型为动态库文件;程序入口地址为0x2154(偏移),Program Header Table位于文件偏移量为52字节处,包含8个program header,每个program header占用32个字节描述一个segment;Section Header Table位于文件偏移量为660064字节处,包含38个section header,每个section header占用40个字节,用于描述对应的section;section header string table 对应的section header 在Section Header Table中的索引为37(即最后一个,索引值从0开始),该section为记录了各个section名称的符号表。
Section Header Table
Section Header Table中每个section header由如下结构体进行描述:
typedef struct {Elf32_Word sh_name; //section 名称,为section header string table的一个偏移量,在该偏移量处保存的以‘\0’结束的字符串即为该section的名称Elf32_Word sh_type; //section 类型,不同的section类型保存有不同的数据,Elf32_Word sh_flags; //section 属性标志Elf32_Addr sh_addr; //section 地址,该section映射到虚拟地址空间的地址,该地址也是文件加载的虚拟地址的偏移Elf32_Off sh_offset; //section 偏移,该section在elf文件中的偏移量,为物理偏移,sh_addr可以理解为虚拟地址偏移Elf32_Word sh_size; //section 大小Elf32_Word sh_link; //与sh_info一样,对于不同的section有不同的含义,但是一般是指本section引用到的section的索引Elf32_Word sh_info;Elf32_Word sh_addralign; //section 地址对齐Elf32_Word sh_entsize; //当section为一个table表时,记录该table表中每一个entry的大小
} Elf32_Shdr;
通过readelf工具查看该文件的Section Header Table,其内容如下:
There are 38 section headers, starting at offset 0xa1260:Section Headers:[Nr] Name Type Addr Off Size ES Flg Lk Inf Al[ 0] NULL 00000000 000000 000000 00 0 0 0[ 1] .note.gnu.build-i NOTE 00000134 000134 000024 00 A 0 0 4[ 2] .gnu.hash GNU_HASH 00000158 000158 000144 04 A 3 0 4[ 3] .dynsym DYNSYM 0000029c 00029c 0007a0 10 A 4 3 4[ 4] .dynstr STRTAB 00000a3c 000a3c 000c0b 00 A 0 0 1[ 5] .gnu.version VERSYM 00001648 001648 0000f4 02 A 3 0 2[ 6] .gnu.version_r VERNEED 0000173c 00173c 000130 00 A 4 6 4[ 7] .rel.dyn REL 0000186c 00186c 000140 08 A 3 0 4[ 8] .rel.plt REL 000019ac 0019ac 0002f8 08 AI 3 22 4[ 9] .init PROGBITS 00001ca4 001ca4 00000c 00 AX 0 0 4[10] .plt PROGBITS 00001cb0 001cb0 0004a4 04 AX 0 0 4[11] .text PROGBITS 00002154 002154 003d90 00 AX 0 0 4[12] .fini PROGBITS 00005ee4 005ee4 000008 00 AX 0 0 4[13] .rodata PROGBITS 00005eec 005eec 0004f4 00 A 0 0 4[14] .ARM.extab PROGBITS 000063e0 0063e0 00030c 00 A 0 0 4[15] .ARM.exidx ARM_EXIDX 000066ec 0066ec 0001a0 00 AL 11 0 4[16] .eh_frame PROGBITS 0000688c 00688c 000004 00 A 0 0 4[17] .tbss NOBITS 00016cb4 006cb4 000001 00 WAT 0 0 1[18] .init_array INIT_ARRAY 00016cb4 006cb4 000004 04 WA 0 0 4[19] .fini_array FINI_ARRAY 00016cb8 006cb8 000004 04 WA 0 0 4[20] .data.rel.ro PROGBITS 00016cbc 006cbc 000028 00 WA 0 0 4[21] .dynamic DYNAMIC 00016ce4 006ce4 000120 08 WA 4 0 4[22] .got PROGBITS 00016e04 006e04 0001fc 04 WA 0 0 4[23] .data PROGBITS 00017000 007000 000004 00 WA 0 0 4[24] .bss NOBITS 00017008 007004 000040 00 WA 0 0 8[25] .comment PROGBITS 00000000 007004 000011 01 MS 0 0 1[26] .ARM.attributes ARM_ATTRIBUTES 00000000 007015 000035 00 0 0 1[27] .debug_aranges PROGBITS 00000000 007050 000150 00 0 0 8[28] .debug_info PROGBITS 00000000 0071a0 0418d6 00 0 0 1[29] .debug_abbrev PROGBITS 00000000 048a76 002f89 00 0 0 1[30] .debug_line PROGBITS 00000000 04b9ff 00a72a 00 0 0 1[31] .debug_frame PROGBITS 00000000 05612c 00079c 00 0 0 4[32] .debug_str PROGBITS 00000000 0568c8 029b60 01 MS 0 0 1[33] .debug_loc PROGBITS 00000000 080428 016b48 00 0 0 1[34] .debug_ranges PROGBITS 00000000 096f70 006d78 00 0 0 8[35] .symtab SYMTAB 00000000 09dce8 001880 10 36 273 4[36] .strtab STRTAB 00000000 09f568 001b84 00 0 0 1[37] .shstrtab STRTAB 00000000 0a10ec 000173 00 0 0 1
Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),y (purecode), p (processor specific)
其中,对于动态库文件而言,上表所述的Addr为虚拟地址,但是并不是该文件加载到内存中实际的虚拟地址,而是虚拟地址的偏移,若文件的加载地址为x,则对应的实际地址为x + Addr,Off为ELF文件内的物理偏移量。以section header 1为例,以HEX格式查看ELF文件的内容,以section header的结构体对数据进行解析,对比通过ELF工具读取的如下内容:
Section Headers:[Nr] Name Type Addr Off Size ES Flg Lk Inf Al[ 1] .note.gnu.build-i NOTE 00000134 000134 000024 00 A 0 0 4
已知Section Header Table位于ELF文件的660064(A1260)字节处,每个section header大小为40个字节,得到其附近的16进制内容如下:
section header 1的名称在section header string table 中的索引为0x1b(28)。此时section header string table处于文件偏移量为 0xa10ec处,则section header 1的名称位于偏移0xa10ec+0x1b=0xa1107处,对应的字符为node.gun.build-id,与readelf中显示的名称一致。
同样的,symtab section中的符号名称也只是指向string table中的一个偏移量,需要在string table中查找。
Program Header Table
Program Header Table中每一个program header均由如下数据结构进行描述:
typedef struct {Elf32_Word p_type; //segment类型Elf32_Off p_offset; //segment偏移,是指该segment在程序文件内的偏移Elf32_Addr p_vaddr; //segment虚拟地址,是指程序加载的虚拟地址基础上的偏移量Elf32_Addr p_paddr; //segment物理地址,一般与p_vaddr相同Elf32_Word p_filesz; //segment实际占用的物理文件大小Elf32_Word p_memsz; //segment加载到内存之后占用的大小,由于字节对齐,其一般会比p_filesz大Elf32_Word p_flags; //segment属性标志,R/W/XElf32_Word p_align; //segment对齐
} Elf32_Phdr;
通过readelf工具查看的program header内容显示如下:
Elf file type is DYN (Shared object file)
Entry point 0x2154
There are 8 program headers, starting at offset 52Program Headers:Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg AlignEXIDX 0x0066ec 0x000066ec 0x000066ec 0x001a0 0x001a0 R 0x4LOAD 0x000000 0x00000000 0x00000000 0x06890 0x06890 R E 0x10000LOAD 0x006cb4 0x00016cb4 0x00016cb4 0x00350 0x00394 RW 0x10000DYNAMIC 0x006ce4 0x00016ce4 0x00016ce4 0x00120 0x00120 RW 0x4NOTE 0x000134 0x00000134 0x00000134 0x00024 0x00024 R 0x4TLS 0x006cb4 0x00016cb4 0x00016cb4 0x00000 0x00001 R 0x1GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10GNU_RELRO 0x006cb4 0x00016cb4 0x00016cb4 0x0034c 0x0034c R 0x1Section to Segment mapping:Segment Sections...00 .ARM.exidx 01 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.extab .ARM.exidx .eh_frame 02 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss 03 .dynamic 04 .note.gnu.build-id 05 .tbss 06 07 .init_array .fini_array .data.rel.ro .dynamic .got
根据前文所述,一个segment由一个或多个section组成,根据readelf读取出来的program header内容,segment 1和segment 2均需要64K(0x10000)对齐,此时加载到内存中的segment1其在程序文件中的偏移范围为0-0x10000,因此根据各个section在程序文件内的偏移量值即虚拟地址,该segment就包含了 .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.extab .ARM.exidx .eh_frame在内的多个section的内容,这与通过readelf工具得到的section到segment的映射关系一致。同理可知其他segment包含的sections。
动态链接
可执行程序的链接包括静态链接和动态链接两种方式:静态链接是指将所有包含符号引用和定义的文件都编译到一个可执行文件;动态链接则是在编译阶段只包含对符号的引用,符号的定义存在于其他库文件,在程序运行时由动态库解释器ld-linux-armhf.so.3(不同平台使用的解释器可能不同,如i386平台使用的ld-linux.so.2)将符号的引用和符号的定义联系到一起。为了将符号的引用与符号的定义联系在一起,ELF文件中使用dynamic section(同时也是dynamic segment)来描述与动态链接相关的信息,该节为一个表格,每一个表项由如下数据结构进行描述:
typedef struct {Elf32_Sword d_tag; //该标志决定d_un的解析union {Elf32_Word d_val; //数值Elf32_Addr d_ptr; //指针} d_un;
} Elf32_Dyn;
其中,几个较为重要的标志如下:
d_tag | d_un | 含义 |
---|---|---|
DT_NEEDED | d_val | 该可执行程序依赖的动态库名称,d_val为字符串表的一个偏移 |
DT_RPATH | d_val | 查找动态库的搜索路径,d_val为字符串表的一个偏移 |
DT_SYMBOLIC | ingnored | dynamic section中包含此entry时,动态连接器解析符号时先从动态库中搜素,再从可执行程序中搜索,反之,搜索顺序相反 |
DT_STRTAB | d_ptr | 指向字符串表的地址 |
DT_STRSZ | d_val | 字符串表的大小,单位为字节 |
DT_SYMTAB | d_ptr | 指向符号表的地址 |
DT_SYMENT | d_val | 符号表项的大小,单位为字节 |
DT_REL | d_ptr | 指向重定位表的地址 |
DT_RELSZ | d_val | 重定位表的大小,单位为字节 |
DT_RELENT | d_val | 重定位表项的大小,大小为字节 |
DT_RELA | d_ptr | 与DT_REL含义相同,也是一个重定位表,只是重定位表项的结构有所不同,一般和DT_REL中二选一存在一个 |
DT_RELASZ | d_val | 重定位表的大小,单位为字节 |
DT_RELAENT | d_val | 重定位表的大小,单位为字节 |
DT_JMPREL | d_ptr | 指向重定位表的地址,该重定位表包含与函数连接表相关的重定位表项 |
DT_PLTREL | d_val | JMP重定位表的类型,可以时REL或者RELA类型,一般文件中包含有REL重定位表时,JMP重定位表即为REL重定位表类型 |
DT_PLTRELSZ | d_val | JMP重定位表项的大小,单位为字节 |
DT_PLTGOT | d_ptr | 指向函数连接表或者全局偏移量表的地址,在本例中指向全局偏移量表的地址 |
DT_TEXTREL | ingnored | 该entry存在时,允许动态库解释器在重定位过程中修改只读段的内容 |
DT_BIND_NOW | ingnored | 该entry存在时表示符号重定位需在程序开始执行之前完成,否则,在符号被使用时才进行符号重定位 |
DT_NULL | ingnored | 该表现标识该section table的结束,一直存在于该section table的最后一项 |
dynamic section中记录了其依赖的动态库文件,依赖的动态库文件需要在编译时通过编译选项指定( -l 后接库文件名,库文件名需要去掉后缀和lib前缀),如:
gcc -o main main.o -lpthread (原则上,越底层的库越要放在后面,所以-lpthread必须放在main.o的后面)
gcc -o main main.o -L./lib -ltest(-L 表示动态库的搜索路径,此时是指编译时的搜索路径,下文提到的”-WL,-rpath“为动态库加载时的搜索路径)
链接完成之后,可执行程序依赖的动态库将在ELF文件的dynamic section中以DT_NEEDED项存在。(当动态库在可执行程序中被dlopen、dlsym、dlerror、dlclose等系统函数显示调用时,则在编译阶段无需指定其依赖的动态库文件?如果可执行程序依赖的动态库又依赖于其他动态库,则其他动态库也应该出现在编译时指定的动态库搜索路径中,否则会提示undefined symbol的错误,如果可以确定这些动态库在可执行程序运行时一定存在,也可以使用allow-shlib-undefined编译选项使其忽略该错误)。动态库解释器在执行可执行程序之前会先加载其所依赖的动态库到进程空间,当依赖的动态库同样依赖于其他的动态库文件时,动态库解释器将依次查找,直到所有处于依赖链中的动态库文件加载完毕。DT_NEEDED 项中指示的只是动态库的名称,并不包含其路径,动态库解释器将按照如下的路径搜索顺序对动态库进行查找并加载:
DT_RPATH指定的路径 > LD_LIBRATY_PATH > /etc/ld.so.cache > /lib/,/usr/lib
其中,DT_RPATH中指定的路径为编译时通过编译参数”-WL,-rpath“指定;LD_LIBRATY_PATH为系统环境变量;/etc/ld.so.cache由ldconfig生成,可在配置文件/etc/ld.so.conf中加入搜索路径后运行ldconfig,生成/etc/ld.so.cache。通过readelf工具得到的dynamic section的内容如下:
Dynamic section at offset 0x6ce4 contains 32 entries:Tag Type Name/Value0x00000001 (NEEDED) Shared library: [libdl.so.2]0x00000001 (NEEDED) Shared library: [libpthread.so.0]0x00000001 (NEEDED) Shared library: [libunwind.so.8]0x00000001 (NEEDED) Shared library: [libstdc++.so.6]0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]0x00000001 (NEEDED) Shared library: [libc.so.6]0x00000001 (NEEDED) Shared library: [ld-linux-armhf.so.3]0x0000000c (INIT) 0x1ca40x0000000d (FINI) 0x5ee40x00000019 (INIT_ARRAY) 0x16cb40x0000001b (INIT_ARRAYSZ) 4 (bytes)0x0000001a (FINI_ARRAY) 0x16cb80x0000001c (FINI_ARRAYSZ) 4 (bytes)0x6ffffef5 (GNU_HASH) 0x1580x00000005 (STRTAB) 0xa3c //根据地址可知,实际指向的是dynstr 0x00000006 (SYMTAB) 0x29c //指向的是dynsym0x0000000a (STRSZ) 3083 (bytes)0x0000000b (SYMENT) 16 (bytes)0x00000003 (PLTGOT) 0x16e040x00000002 (PLTRELSZ) 760 (bytes)0x00000014 (PLTREL) REL0x00000017 (JMPREL) 0x19ac0x00000011 (REL) 0x186c0x00000012 (RELSZ) 320 (bytes)0x00000013 (RELENT) 8 (bytes)0x00000018 (BIND_NOW) 0x6ffffffb (FLAGS_1) Flags: NOW0x6ffffffe (VERNEED) 0x173c0x6fffffff (VERNEEDNUM) 60x6ffffff0 (VERSYM) 0x16480x6ffffffa (RELCOUNT) 100x00000000 (NULL) 0x0
根据DT_SYMTAB项的地址可知,动态库解释器查找动态库时使用的符号表为dynstr,即动态符号表。动态符号表实际上是符号表的子集,只包含与动态链接相关的符号表项,为了节省ELF文件的文件大小,可以将符号表(strtab)strip掉,只保留动态符号表而不影响程序的链接和运行。当可执行程序依赖的动态库加载到内存空间之后,动态库解释器开始进行符号重定位,也就是确定符号对应的内存地址。重定位表项包含有REL和RELA两种类型,其各自数据结构定义如下:
typedef struct {Elf32_Addr r_offset; //重定位作用的位置,对于重定位文件来说,该值为文件中的偏移量,对于可执行程序和共享文件,该值为虚拟地址(其实是虚拟地址偏移量)Elf32_Word r_info; //重定位信息:符号表索引、重定位类型
} Elf32_Rel;typedef struct {Elf32_Addr r_offset; //重定位作用的位置Elf32_Word r_info; //重定位信息:符号表索引、重定位类型Elf32_Sword r_addend; //加数,用于计算需要重定位的域的值
} Elf32_Rela;对于r_info成员,其数据解析定义如下
#define ELF32_R_SYM(i) ((i)>>8) //符号表索引,指向待重定位的符号
#define ELF32_R_TYPE(i) ((unsigned char)(i)) //重定位类型,不同的重定位类型,r_offset中存储的内容的计算方式不同
#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
通过readelf查看部分重定位表的内容如下:
Relocation section '.rel.dyn' at offset 0x186c contains 40 entries:Offset Info Type Sym.Value Sym. Name
00016fb8 00002f15 R_ARM_GLOB_DAT 00000000 realloc@GLIBC_2.4Relocation section '.rel.plt' at offset 0x19ac contains 95 entries:Offset Info Type Sym.Value Sym. Name
00016e1c 00000716 R_ARM_JUMP_SLOT 00000000 _ULarm_get_reg
以_ULarm_get_reg为例,跟踪符号的重定位过程:通过objdump查看调用_ULarm_get_reg时的汇编,根据汇编代码定位符号的地址。通过objdump工具得到调用_ULarm_get_reg时的汇编如下:
5dbe: f7fb ef94 blx 1ce8 <_ULarm_get_reg@plt>00001ce8 <_ULarm_get_reg@plt>:1ce8: e28fc600 add ip, pc, #0, 12 //ip = pc + 0 = 0x1ce8 + 8 = 0x1cf01cec: e28cca15 add ip, ip, #86016 ; 0x15000 //ip = ip + 0x15000 = 0x1cf0 + 0x15000 = 0x16cf01cf0: e5bcf12c ldr pc, [ip, #300]! ; 0x12c //pc = [ip + 300 ] = 0x16cf0 + 0x12c = 0x16e1c
由上可知,当程序引用_ULarm_get_reg符号时,并不是直接跳转到该符号的地址,而是跳转到_ULarm_get_reg@plt,该符号为一个过程链接表项(PLT entry),用于将位置无关的函数调用转移到绝对地址。通过上面列举的_ULarm_get_reg@plt汇编代码可知,最终PC的值为地址0x16e1c中存储的内容。地址0x16e1c则正好是rel重定位表中_ULarm_get_reg重定位项中r_offset的值,并且该地址处于全局偏移量表(.got section)的范围之内:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[10] .plt PROGBITS 00001cb0 001cb0 0004a4 04 AX 0 0 4
[22] .got PROGBITS 00016e04 006e04 0001fc 04 WA 0 0 4
由于符号为动态链接,所以LEF文件内该地址存储的内容并不是符号的实际地址,查看该地址的内容(虚拟地址0x16e1c对应的elf文件偏移量为0x6e1c)为0x1cb0,该地址指向PLT section的首地址。
在objdump工具产生的文件中包含有PLT表项的反汇编内容,其首地址对应的反汇编如下:
Disassembly of section .plt:00001cb0 <.plt>:1cb0: e52de004 push {lr} ; (str lr, [sp, #-4]!)1cb4: e59fe004 ldr lr, [pc, #4] ; 1cc0 <.plt+0x10> //lr = [0x1cb4 + 8 + 4] = [0x1cc0] = 0x151441cb8: e08fe00e add lr, pc, lr //lr = lr + pc = 0x15144 + 0x1cb8 +8 = 0x16e041cbc: e5bef008 ldr pc, [lr, #8]! //pc = lr + 8 = 0x16e04 + 8 = 0x16e0c ->对应的elf文件偏移为6e0c1cc0: 00015144 .word 0x00015144
地址0x16e0c(ELF偏移为0x6e04)为GOT表的第二项,GOT表中的前三项为保留项,用于保存特殊的数据结构地址,其他各项则保存各个符号的实际地址。其中,GOT[0]保存了dynamic section的地址,当ELF文件加载到内存之后,GOT[1]将保存已经加载的动态库的链表地址(所有加载的动态库将形成一个链表link_map),GOT[2]将保存_dl_runtime_resolve函数的地址,该函数的作用就是找到某个符号的地址,并将其写到与对应符号相关的GOT项中。即在符号首次引用时都会跳转到GOT[2]表项中去查询该符号的实际地址,并将符号写到对应的重定位表项,当符号再次引用时,此时的重定位表项已经为符号的实际地址,无需再次查找。在编译阶段GOT[1]和GOT[2]将填充为0,为了验证ELF文件加载之后GOT[1]和GOT[2]中的内容,可以通过gdb对一个可执行程序进行跟踪(动态库中的GTO[2]和GOT[3]貌似不会在加载时发生改变,直接用所在的可执行程序的GOT[2]和GOT[3]中的内容即可)。
当进行符号查找时,同样按照动态库的查找顺序进行查找,只是如果此时在环境变量中设置了LD_PRELOAD变量,则将首先搜索LD_PRELOAD变量指定的动态库,即:
LD_PRELOAD > LD_LIBRATY_PATH
综上,动态链接的流程可以大致概括为:当dynamic section中的DT_BIND_NOW项没有被使能时,可执行程序在加载到内存空间之后,便加载动态库解释器到内存空间,同时开始符号重定位:根据DT_NEEDED项依次将可执行程序依赖的动态库加载到内存空间;根据DT_REL/DT_JMPREL项找到重定位表,结合DT_DT_SYMTAB指向的符号表定位到需要重定位的符号,当动态库解释器找到对应符号的地址,则将地址写回到重定位表项作用的位置。当ynamic section中的DT_BIND_NOW项被使能时,当符号被首次引用时,根据汇编代码此时程序将跳转到对应的PLT表项中,由PLT表项指向其对应的GOT表项,GOT表项中的内容统一为初始化的值,该值为一个指向公共的PLT项的地址,对应的PLT项指向GOT[2],其内容为_dl_runtime_resolve函数的地址,该函数将在动态库中查找对应的符号,当符号被查找到时,将符号的地址写到对应的GOT项中,当可执行程序再次访问该符号时,由于GOT表项中已经为符号的实际地址,则无需再进行符号的查找过程。
参考
- https://os.51cto.com/art/202105/663698.htm
- https://blog.csdn.net/farmwang/article/details/73556017
- https://tinylab-1.gitbook.io/cbook/02-chapter4#toc_23258_14315_8
- https://www.freesion.com/article/190711925/
ELF文件——动态链接相关推荐
- linux程序卸载动态库,Intel平台下linux中ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载...
在 IBM Bluemix 云平台上开发并部署您的下一个应用. 相信读者已经看过了 Intel平台下Linux中ELF文件动态链接的加载.解析及实例分析(一): 加载的内容了,了解了ELF文件被加载的 ...
- ELF 文件 动态链接 - 地址无关代码(GOT)
Linux 系统中,ELF动态链接文件被称为 动态共享对象(DSO,Dynamic Shared Object),简称共享对象 文件拓展名为".so" 动态链接下 一个程序可以被分 ...
- Linux下的ELF文件、链接、加载与库(含大量图文解析及例程)
Linux下的ELF文件.链接.加载与库 链接是将将各种代码和数据片段收集并组合为一个单一文件的过程,这个文件可以被加载到内存并执行.链接可以执行与编译时,也就是在源代码被翻译成机器代码时:也可以执行 ...
- ELF文件装载链接过程及hook原理
ELF文件格式解析 可执行和可链接格式(Executable and Linkable Format,缩写为ELF),常被称为ELF格式,在计算机科学中,是一种用于执行档.目的档.共享库和核心转储的标 ...
- 计算机系统基础第四篇-6 elf文件的链接
链接两步 elf文件链接分成两个步骤,第一步是符号解析,第二步是重定位. 1.1 符号解析 1.2 重定位 可重定位目标文件 linux平台下,可重定位目标文件为elf文件,elf由多个节构成. 3. ...
- yzh 第十一课 ELF文件和链接
啊 啊 啊 啊 注意:addr2line需要可执行文件有调试信息才能工作的原因,就是它使用了调试信息 啊a 啊 mprotect 系统调用可以修改内存的权限 啊 注意:objcopy可以生成Veril ...
- OpenSBI ELF rela.dyn和.dynsym动态链接过程
在OpenSBI中重定位分成了两种,根据是否配置了FW_PIC宏来区分, 配置了FW_PIC,即本文描述的rela.dyn和.dynsym的动态链接. 未配置FW_PIC是加载地址和链接地址不相等情况 ...
- 动态链接一:ELF文件格式
ELF是Executable and Linkable Format的缩写,Linkable:可链接,表示ELF文件是链接工作的重要参与者,Excutable:可执行,表示ELF将参与程序的执行工作, ...
- 程序员的自我修养--链接、装载与库笔记:Windows下的动态链接
Windows下的PE的动态链接与Linux下的ELF动态链接相比,有很多类似的地方,但也有很多不同的地方. 1. DLL简介 DLL即动态链接库(Dynamic-Link Library)的缩写,它 ...
最新文章
- java 自动装箱自动拆箱_自动装箱和自动拆箱
- python恶搞表情包-Python开发个人专属表情包网站,表情在手,天下我有
- 搭建LAMP环境示例
- linux 分区下的两主要硬盘的意思
- html 树状折叠,折叠树状页.html
- 营销大数据分析 关键技术_营销分析的3个最关键技能
- (五)EasyUI使用——datagrid数据表格
- React开发(175):注意在回调里面重新渲染列表
- 数据体系建设的开端,该如何规划平台? 1
- 电脑开机进不了桌面拒绝访问怎么办
- 电商兴桃,打造乡村振兴新样本
- python爬取上海链家网二手房数据
- COMSOL仿真软件入门学习(一)
- 实体连锁电商会员运营方案
- WPF/WinForm 如何生成单文件的EXE
- Environment 概述
- phython学习笔记1
- 信息过剩而注意力稀缺的时代需要的是专注
- 算法学习-素数与合数小结
- n与9n--char3
热门文章
- zabbix监控方式(02) - zabbix通过IPMI监控硬件环境(温度和风扇)
- Swordfish【prim算法】
- 2011中国国际金融展隆重举行
- Java如何抛出异常
- 120 以太坊 ethereum truffle : 编写自动化智能合约测试
- c++初级(本人scdn)
- 【代码审计篇】 代码审计工具Fortify基本用法详解
- xamarin android 布局,Xamarin.Android 上中下布局
- 计算机考研王道408【数据结构/计算机组成原理/操作系统/计算机网络】知识点总结(PDF版)
- c语言经典01背包问题——洛谷P2871