空间和地址分配
仍然采用上一节的代码。看生成的代码段。3个中间目标文件的代码段:
fromelf -v a.o
========================================================================
** Section #1
Name : i.main
Type : SHT_PROGBITS (0x00000001)
Flags : SHF_ALLOC + SHF_EXECINSTR (0x00000006)
Addr : 0x00000000
File Offset : 52 (0x34)
Size : 24 bytes (0x18)
Link : SHN_UNDEF
Info : 0
Alignment : 4
Entry Size : 0
====================================
fromelf -v b.o
========================================================================
** Section #1
Name : i.swap
Type : SHT_PROGBITS (0x00000001)
Flags : SHF_ALLOC + SHF_EXECINSTR (0x00000006)
Addr : 0x00000000
File Offset : 52 (0x34)
Size : 22 bytes (0x16)
Link : SHN_UNDEF
Info : 0
Alignment : 2
Entry Size : 0
====================================
fromelf -v startup_stm32f10x_xl.o
====================================
** Section #3
Name : RESET
Type : SHT_PROGBITS (0x00000001)
Flags : SHF_ALLOC (0x00000002)
Addr : 0x00000000
File Offset : 52 (0x34)
Size : 304 bytes (0x130)
Link : SHN_UNDEF
Info : 0
Alignment : 4
Entry Size : 0
====================================
====================================
** Section #5
Name : .text
Type : SHT_PROGBITS (0x00000001)
Flags : SHF_ALLOC + SHF_EXECINSTR (0x00000006)
Addr : 0x00000000
File Offset : 924 (0x39c)
Size : 56 bytes (0x38)
Link : SHN_UNDEF
Info : 0
Alignment : 4
Entry Size : 0
====================================
可以看到,目标文件中的代码段地址都是0。
链接后生成的axf文件:
fromelf -v STM32F103_study.axf
========================================================================
** Section #1
Name : ER_IROM1
Type : SHT_PROGBITS (0x00000001)
Flags : SHF_ALLOC + SHF_EXECINSTR (0x00000006)
Addr : 0x08000000
File Offset : 52 (0x34)
Size : 720 bytes (0x2d0)
Link : SHN_UNDEF
Info : 0
Alignment : 4
Entry Size : 0
====================================
已经分配了实际的地址:0x08000000
重定位表
由于a.c文件中引用了shared全局变量和外部函数swap(),在链接过程中需要对其重定位。
看a.o的重定位表:
在文件偏移0x02F0处,共16个字节。
共2个表项,每个重定位表项占用8个字节:
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef struct
{
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;
前面4个字节为重定位符号在段中的偏移地址。后面4个字节为信息项。
r_info中包含重定位类型和需要重定位的符号在符号表中的索引值。
举例来说,一个跟函数重定位相关的重定位项中的r_info会给出该函数符号在符号表中的索引值。如果索引值是STN_UNDEF(0),证明符号是未定义的,那么重定位过程中将使用0作为该符号的符号数值(st_value)。
重定位类型是处理器相关的一种属性。
可以使用宏ELF32_R_SYM(或者ELF64_R_SYM)和宏ELF32_R_TYPE(或者ELF64_R_TYPE)分别得到需要重定位的符号的符号表索引值以及重定位类型。
#define ELF32_R_SYM(val) ((val) >> 8) //得到符号表的索引
#define ELF32_R_TYPE(val) ((val) & 0xff) //得到type
#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
低8位(1个字节)为类型,高24位为符号索引。
对照a.o文件,第1个重定位表项的地址为0x0000000A,类型为10(0x0A),索引为10(0x0A);
第2个重定位表项的地址为0x00000014,类型为2,索引为9.
fromelf -r a.o
** Section #6 '.reli.main' (SHT_REL)
Size : 16 bytes (alignment 4)
Symbol table #5 '.symtab'
2 relocations applied to section #1 'i.main'
# Offset Relocation Type Wrt Symbol Defined in
========================================================================
0 0x0000000a 10 R_ARM_THM_CALL 10 swap Ref
1 0x00000014 2 R_ARM_ABS32 9 shared Ref
对照a.o中的汇编看看这两个位置的内容:
fromelf -c a.o
========================================================================
** Section #1 'i.main' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
Size : 24 bytes (alignment 4)
Address: 0x00000000
$t
i.main
main
0x00000000: b508 .. PUSH {r3,lr}
0x00000002: 2064 d MOVS r0,#0x64
0x00000004: 9000 .. STR r0,[sp,#0]
0x00000006: 4903 .I LDR r1,[pc,#12] ; [shared = 0x14] = 0
0x00000008: 4668 hF MOV r0,sp
0x0000000a: f7fffffe .... BL swap
0x0000000e: 2000 . MOVS r0,#0
0x00000010: bd08 .. POP {r3,pc}
$d
0x00000012: 0000 .. DCW 0
0x00000014: 00000000 .... DCD 0 ; shared
从中可以看出,0x0000000A为调用swap函数,函数地址偏移量暂时为-1。0x00000014处为shared的地址,暂时为0.
地址更新与代码修正
和链接后的axf文件对比一下,BL swap的二进制代码由F7FFFFFE变成了F805F000;shared变量的地址也由00000000变成了0x20000000。
如果在b.c文件中,shared变量前面再加一个变量,比如:int x = 2,则变量x会占用0x20000000的位置,shared变量的地址会变成0x20000004.再来看看axf文件,确实变了: