U-Boot会对自己重定向,对于ARM架构,它只支持R_ARM_RELATIVE重定向类型。编译可重定向目标文件时,使用-fno-pic和-mword-relocations选项。前者关闭pic,后者只产生32位绝对重定向。链接可执行文件时,使用-pie选项,产生位置无关可执行文件。
uboot-arm-reloc.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22  | int c = 1;int d() { return 1; }static int e = 1;static int f() { return 1; }/* global var and function */int access_global_var()       { return c; }int access_global_var_addr()  { return (int)&c; }int access_global_fun()       { return d(); }int access_global_fun_ptr()   { return (int)d; }/* static var and function in this file */int access_static_var()       { return e; }int access_static_var_addr()  { return (int)&e; }int access_static_fun()       { return f(); }int access_static_fun_ptr()   { return (int)f; }int _start(){    return 0;} | 
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  | TOOLCHAIN_DIR := /work/toolchain/arm-unknown-linux-gnueabiTOOLCHAIN_PREFIX := arm-unknown-linux-gnueabiTOOLCHAIN_BIN_PREFIX := $(TOOLCHAIN_DIR)/bin/$(TOOLCHAIN_PREFIX)CC := $(TOOLCHAIN_BIN_PREFIX)-gccREADELF := $(TOOLCHAIN_BIN_PREFIX)-readelfOBJDUMP := $(TOOLCHAIN_BIN_PREFIX)-objdumpCFLAGS :=all:    $(CC) -fno-pic -mword-relocations -c -o uboot-arm-reloc.o uboot-arm-reloc.c    $(CC) -pie -nostdlib -o uboot-arm-reloc uboot-arm-reloc.o     $(OBJDUMP) -d uboot-arm-reloc.o > obj.objdump    $(OBJDUMP) -d uboot-arm-reloc > exe.objdump    $(READELF) -a uboot-arm-reloc.o > obj.readelf    $(READELF) -a uboot-arm-reloc > exe.readelf | 
uboot-arm-reloc.o的elf信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43  | Section Headers:  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al  [ 0]                   NULL            00000000 000000 000000 00      0   0  0  [ 1] .text             PROGBITS        00000000 000034 00015c 00  AX  0   0  4  [ 2] .rel.text         REL             00000000 0004f0 000090 08   I  9   1  4  [ 3] .data             PROGBITS        00000000 000190 000008 00  WA  0   0  4  [ 4] .bss              NOBITS          00000000 000198 000000 00  WA  0   0  1  [ 5] .comment          PROGBITS        00000000 000198 00002f 01  MS  0   0  1  [ 6] .note.GNU-stack   PROGBITS        00000000 0001c7 000000 00      0   0  1  [ 7] .ARM.attributes   ARM_ATTRIBUTES  00000000 0001c7 00002f 00      0   0  1  [ 8] .shstrtab         STRTAB          00000000 000580 000059 00      0   0  1  [ 9] .symtab           SYMTAB          00000000 0001f8 000230 10     10  24  4  [10] .strtab           STRTAB          00000000 000428 0000c6 00      0   0  1Key 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 (noread), p (processor specific)There are no section groups in this file.There are no program headers in this file.Relocation section '.rel.text' at offset 0x4f0 contains 18 entries: Offset     Info    Type            Sym.Value  Sym. Name00000018  00000028 R_ARM_V4BX       00000034  00000028 R_ARM_V4BX       00000054  00000028 R_ARM_V4BX       00000058  00001802 R_ARM_ABS32       00000000   c00000074  00000028 R_ARM_V4BX       00000078  00001802 R_ARM_ABS32       00000000   c00000084  0000191c R_ARM_CALL        00000000   d00000098  00000028 R_ARM_V4BX       000000b4  00000028 R_ARM_V4BX       000000b8  00001902 R_ARM_ABS32       00000000   d000000d8  00000028 R_ARM_V4BX       000000dc  00000302 R_ARM_ABS32       00000000   .data000000f8  00000028 R_ARM_V4BX       000000fc  00000302 R_ARM_ABS32       00000000   .data0000011c  00000028 R_ARM_V4BX       00000138  00000028 R_ARM_V4BX       0000013c  00000802 R_ARM_ABS32       0000001c   f00000158  00000028 R_ARM_V4BX | 
R_ARM_V4BX的目的是标记BX指令。armv4不支持BX指令,这样在armv4上,使用其它指令替换。除R_ARM_V4BX之外,上述存在两种重定向,R_ARM_ABS32和R_ARM_CALL。下面根据反汇编来分析。
汇编代码
1 2 3 4 5 6 7 8 9 10  | 00000038 <access_global_var>:  38: e52db004   push    {fp}        ; (str fp, [sp, #-4]!)  3c: e28db000   add fp, sp, #0  40: e59f3010   ldr r3, [pc, #16] ; 58 <access_global_var+0x20>  44: e5933000   ldr r3, [r3]  48: e1a00003   mov r0, r3  4c: e28bd000   add sp, fp, #0  50: e49db004   pop {fp}        ; (ldr fp, [sp], #4)  54: e12fff1e   bx  lr  58: 00000000   .word   0x00000000 | 
重定向条目:
1  | 00000058  00001802 R_ARM_ABS32       00000000   c | 
可以看到,将c的地址存储到函数之后,使用pc相对位置,将其地址载入到r3,然后将内容载入到r3,再将r3复制到r0。
和访问全局变量的值类似,只是少了取内容的指令。
汇编代码
1 2 3 4 5 6 7 8 9  | 0000007c <access_global_fun>:  7c: e92d4800   push    {fp, lr}  80: e28db004   add fp, sp, #4  84: ebfffffe   bl  0 <d>  88: e1a03000   mov r3, r0  8c: e1a00003   mov r0, r3  90: e24bd004   sub sp, fp, #4  94: e8bd4800   pop {fp, lr}  98: e12fff1e   bx  lr | 
重定向条目
1  | 00000084  0000191c R_ARM_CALL        00000000   d | 
根据ARM ELF,R_ARM_CALL的定义如下:
28 R_ARM_CALL Static ARM ((S + A) | T) – P
可见这个一个相对PC的重定向。
和访问全局变量的地址一样。
汇编代码
1 2 3 4 5 6 7 8 9 10  | 000000bc <access_static_var>:  bc: e52db004   push    {fp}        ; (str fp, [sp, #-4]!)  c0: e28db000   add fp, sp, #0  c4: e59f3010   ldr r3, [pc, #16] ; dc <access_static_var+0x20>  c8: e5933000   ldr r3, [r3]  cc: e1a00003   mov r0, r3  d0: e28bd000   add sp, fp, #0  d4: e49db004   pop {fp}        ; (ldr fp, [sp], #4)  d8: e12fff1e   bx  lr  dc: 00000004   .word   0x00000004 | 
重定向条目
1  | 000000dc  00000302 R_ARM_ABS32       00000000   .data | 
套路和x86是一样的,访问静态变量,重定向的符号是.data section,静态变量在.data中的偏移作为加数存储到要重定向的内容中。通过S+A就得到了静态变量的地址。
重定向方式和访问静态变量类似,只不过少了取值指令。
无需重定向,在.text内部跳转。
汇编代码
1 2 3 4 5 6 7 8 9  | 00000120 <access_static_fun_ptr>: 120:  e52db004   push    {fp}        ; (str fp, [sp, #-4]!) 124:  e28db000   add fp, sp, #0 128:  e59f300c   ldr r3, [pc, #12] ; 13c <access_static_fun_ptr+0x1c> 12c:  e1a00003   mov r0, r3 130:  e28bd000   add sp, fp, #0 134:  e49db004   pop {fp}        ; (ldr fp, [sp], #4) 138:  e12fff1e   bx  lr 13c:  00000000   .word   0x00000000 | 
重定向条目
1  | 0000013c  00000802 R_ARM_ABS32       0000001c   f | 
可见,直接重定向为符号f的绝对地址,没有通过.text加偏移的方式。
就是按照目标文件中的重定向内容进行重定向,如访问全局变量:
1 2 3 4 5 6 7 8 9 10  | 000001bc <access_global_var>: 1bc:  e52db004   push    {fp}        ; (str fp, [sp, #-4]!) 1c0:  e28db000   add fp, sp, #0 1c4:  e59f3010   ldr r3, [pc, #16] ; 1dc <access_global_var+0x20> 1c8:  e5933000   ldr r3, [r3] 1cc:  e1a00003   mov r0, r3 1d0:  e28bd000   add sp, fp, #0 1d4:  e49db004   pop {fp}        ; (ldr fp, [sp], #4) 1d8:  e12fff1e   bx  lr 1dc:  00010374   .word   0x00010374 | 
重定向为:0x10374,再看c的符号表条目:
1  | 41: 00010374     4 OBJECT  GLOBAL DEFAULT    9 c | 
但是添加了.rel.dyn section,这个section包含了所有的目标文件中的绝对重定向:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26  | Section Headers:  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al  [ 0]                   NULL            00000000 000000 000000 00      0   0  0  [ 1] .interp           PROGBITS        000000f4 0000f4 000013 00   A  0   0  1  [ 2] .hash             HASH            00000108 000108 000018 04   A  3   0  4  [ 3] .dynsym           DYNSYM          00000120 000120 000030 10   A  4   3  4  [ 4] .dynstr           STRTAB          00000150 000150 000001 00   A  0   0  1  [ 5] .rel.dyn          REL             00000154 000154 000030 08   A  3   0  4  [ 6] .text             PROGBITS        00000184 000184 00015c 00  AX  0   0  4  [ 7] .dynamic          DYNAMIC         000102e0 0002e0 000088 08  WA  4   0  4  [ 8] .got              PROGBITS        00010368 000368 00000c 04  WA  0   0  4  [ 9] .data             PROGBITS        00010374 000374 000008 00  WA  0   0  4  [10] .comment          PROGBITS        00000000 00037c 00002e 01  MS  0   0  1  [11] .ARM.attributes   ARM_ATTRIBUTES  00000000 0003aa 00002f 00      0   0  1  [12] .shstrtab         STRTAB          00000000 000814 000075 00      0   0  1  [13] .symtab           SYMTAB          00000000 0003dc 000320 10     14  32  4  [14] .strtab           STRTAB          00000000 0006fc 000118 00      0   0  1   Relocation section '.rel.dyn' at offset 0x154 contains 6 entries: Offset     Info    Type            Sym.Value  Sym. Name000001dc  00000017 R_ARM_RELATIVE   000001fc  00000017 R_ARM_RELATIVE   0000023c  00000017 R_ARM_RELATIVE   00000260  00000017 R_ARM_RELATIVE   00000280  00000017 R_ARM_RELATIVE   000002c0  00000017 R_ARM_RELATIVE | 
根据ARM ELF手册:
23 R_ARM_RELATIVE Dynamic Data B(S) + A
重定向为新的基准地址加加数,因为原来的基准地址为0。
注意:在可执行文件中,R_ARM_CALL不需要重定向,因为它使用PC相对位置访问,该相对位置在链接阶段即可确定。
参考:
ARM IHI 0044F, current through ABI release 2.10. ELF for the ARM ® Architecture. 24 November 2015.