一个小型链接器的实现,主要功能为obj文件符号重定位,可用作内存载入ELF的hotpatch。以下为一些实现的原理和思路
Why hotpatch?
Compile entire product image/package costly
- Just modify one line of one function
- Accelerate dev’s debugging
Reboot system to upgrade will suspend traffic
- Apply and valid instantly
Only support memory load ELF currently
Procedure(offline)
Compile .c to .o with functions which need to be patched
Link .o(obj) file by executable file
- ELF analyze
- Symbol relocate
- Instruction modify
- Section layout(.text/.data/.bss/.rodata)
- output image
Pack image and patch info to a single package
- Comply with regular patch format(user-defined)
Procedure(online)
- Load patch package into box
- Parser patch (patch format)
- Alloc patch memory area and copy image body
- Drop Process into idle state
- Modify two instructions of entrance of patched function
- j target
- nop
- Invalid ICACHE and DCACHE
- Restore into running state
Compile obj
- test.c
1 | xxx-gcc -mlong-calls -Wno-pointer-sign -Wno-error=address …… –c test.c |
- test.o
ELF background
- Header
- Section
- Symbol table
- String table
ELF Header
1 | readelf -h test_mips.o |
1 |
|
Section Header
1 | readelf -S test_mips.o |
1 | typedef struct |
sh_type
1 |
sh_flags
1 |
|
.txt
1 | xxx-objdump -d test.o |
.strtab 字符串表
ELF文件中用到很多字符串,比如段名、变量名。因为字符串的长度往往是不固定的,所以用固定的结构来表示它比较困难。一种常见的做法就是把字符串集中起来存放到一个表,然后使用字符串在表中的偏移来引用。
.symtab 符号表
1 | typedef struct |
- sh_value:符号的地址
- sh_shndx: 符号所在的段在段表中的下标
st_info
1 |
强/弱符号
- 函数和初始化了的全局变量为强符号
- 未初始化的全局变量为弱符号
- attribute((weak))
- 强弱针对定义,而不针对声明
强/弱符号的链接选择
- 不允许多次定义强符号
“multiple definition of “xxx”” - 如果一个符号在某个.o中是强符号,在其它.o中是弱符号,那么选择强符号
- 如果一个符号在所有.o中是弱符号,选择占用空间最大的一个
1
2int global;
double global;
case
1 | __attribute__ ((weak)) void foo(); |
COMMON块
未初始化的全局变量
1
23: 00000004 4 OBJECT GLOBAL DEFAULT COM global_undef
Why not BSS?
- obj_allocate_commons
- Find the bss section, if not exist, create one
- Allocate the COMMONS
- Allocate space for BSS
.rel.text 重定位表
1 | readelf -r test_mips.o |
1 | typedef struct |
- r_offset: 重定位入口的偏移,重定位入口所要修正的位置的第一个字节相对于段起始的偏移
- r_info: 低8位表示重定位入口的类型,高24位表示重定位入口的符号在符号表中的下标
- r_addend: 保存在被修正位置的值
重定位入口的类型
1 |
-mlong-calls
1 | gcc -mlong-calls -Wno-pointer-sign -Wno-error=address …… –c test.c |
R_MIPS_26
1 | 00000000 <function_handler>: |
R_MIPS_HI16/ R_MIPS_LO16
1 | 00000000 <function_handler>: |
jal/jalr
Variable relocate
1 | static_yyy = 0; |
Advanced topic
- Dynamic Link
- –fPIC, Position-independent Code
- GOT, Global Offset Table
- PLT, Procedure Linkage Table
Resource
- https://github.com/royhunter/hotpatch_linker
- 程序员的自我修养—链接 装载与库
- insmod.c
- modutils 2.4.27
- ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.4/
- readelf.c