《程序员的自我修养》读书笔记3——使用KEIL研究ELF文件的重定位

空间和地址分配

仍然采用上一节的代码。看生成的代码段。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文件,确实变了:

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值