ILD

u-boot中的arm重定向
作者:Herbert Yuan 邮箱:yuanjp@hust.edu.cn
发布时间:2018-1-7 站点:Inside Linux Development

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-gnueabi
TOOLCHAIN_PREFIX := arm-unknown-linux-gnueabi
TOOLCHAIN_BIN_PREFIX := $(TOOLCHAIN_DIR)/bin/$(TOOLCHAIN_PREFIX)
CC := $(TOOLCHAIN_BIN_PREFIX)-gcc
READELF := $(TOOLCHAIN_BIN_PREFIX)-readelf
OBJDUMP := $(TOOLCHAIN_BIN_PREFIX)-objdump
CFLAGS :=
 
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


1 可重定向文件

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  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 (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. Name
00000018  00000028 R_ARM_V4BX       
00000034  00000028 R_ARM_V4BX       
00000054  00000028 R_ARM_V4BX       
00000058  00001802 R_ARM_ABS32       00000000   c
00000074  00000028 R_ARM_V4BX       
00000078  00001802 R_ARM_ABS32       00000000   c
00000084  0000191c R_ARM_CALL        00000000   d
00000098  00000028 R_ARM_V4BX       
000000b4  00000028 R_ARM_V4BX       
000000b8  00001902 R_ARM_ABS32       00000000   d
000000d8  00000028 R_ARM_V4BX       
000000dc  00000302 R_ARM_ABS32       00000000   .data
000000f8  00000028 R_ARM_V4BX       
000000fc  00000302 R_ARM_ABS32       00000000   .data
0000011c  00000028 R_ARM_V4BX       
00000138  00000028 R_ARM_V4BX       
0000013c  00000802 R_ARM_ABS32       0000001c   f
00000158  00000028 R_ARM_V4BX


R_ARM_V4BX的目的是标记BX指令。armv4不支持BX指令,这样在armv4上,使用其它指令替换。除R_ARM_V4BX之外,上述存在两种重定向,R_ARM_ABS32和R_ARM_CALL。下面根据反汇编来分析。


1.1 访问全局变量

汇编代码

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 访问全局变量的地址

和访问全局变量的值类似,只是少了取内容的指令。


1.3 调用全局函数

汇编代码

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.4 访问全局函数的地址

和访问全局变量的地址一样。


1.5 访问静态变量

汇编代码

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就得到了静态变量的地址。


1.6 访问静态变量地址

重定向方式和访问静态变量类似,只不过少了取值指令。


1.7 访问静态函数

无需重定向,在.text内部跳转。


1.8 访问静态函数地址

汇编代码

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加偏移的方式。


2 可执行文件

就是按照目标文件中的重定向内容进行重定向,如访问全局变量:

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. Name
000001dc  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.


Copyright © insidelinuxdev.net 2017-2021. Some Rights Reserved.