[hellogcc] Re: [hellogcc] Re: [hellogcc] [投稿] 一个关于重定位的例子

  • From: Mingjie Xing <mingjie.xing@xxxxxxxxx>
  • To: hellogcc@xxxxxxxxxxxxx
  • Date: Wed, 24 Aug 2011 15:03:28 +0800

在 2011年8月24日 下午2:27,Yao Qi <qiyaoltc@xxxxxxxxx> 写道:
> 2011/8/24 Mingjie Xing <mingjie.xing@xxxxxxxxx>:
>> $ mipsel-linux-objdump -Dr sysconf.o
>>
>> Disassembly of section .rodata:
>>
>> 00000000 <.rodata>:
>>   0:   ffffc064        0xffffc064
>>                        0: R_MIPS_GPREL32       .text
>
> ".text" 在这里什么意思?

前面提到了,重定位项的结构体为:

typedef struct {
  Elf32_Addr r_offset;
  Elf32_Word r_info;
} Elf32_Rel;

其中,r_info有两部分组成,一部分是所对应的符号表中的索引,一部分是重定位类型。

#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))

这里,
 Offset              Info    Type                       Sym.Value  Sym. Name
00000000  0000020c R_MIPS_GPREL32    00000000   .text

20c中的2是索引,c是类型R_MIPS_GPREL32,符号表如下,

Symbol table '.symtab' contains 15 entries:
   Num:  Value  Size         Type    Bind           Vis      Ndx       Name
   0: 00000000     0       NOTYPE  LOCAL  DEFAULT  UND
   1: 00000000     0       FILE         LOCAL  DEFAULT  ABS sysconf.c
   2: 00000000     0       SECTION LOCAL  DEFAULT    1

索引为2的符号是,
   2: 00000000     0       SECTION LOCAL  DEFAULT    1
其中,Ndx表示其所在的section header索引,

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 000040 0004e0 00  AX  0   0 16

即.text。

表明这个重定位项对应的符号是.text段(似乎是这么理解)。

>> 这里将.rodata中需要重定位的地方和对应的重定位项结合在一起打印出来。可以看出,对于.rodata中的第一个字,其保存的addend值为0xffffc064。
>>
>> 3、MIPS ABI文档如下描述R_MIPS_GPREL_32:
>>
>> Name                        Value    Field     Symbol       Calculation
>> R_MIPS_GPREL_32    12    T-word32    local    A + S + GP0 - GP
>>
>> A
>>  Represents the addend used to compute the value of the relocatable
>>  field.
>>
>> S
>>  Represents the value of the symbol whose index resides in the relocation
>>  entry, unless the the symbol is STB_LOCAL and is of type
>>  STT_SECTION in which case S represents the original sh_addr minus
>>  the final sh_addr.
>>
>> GP
>>  Represents the final gp value to be used for the relocatable, executable,
>>  or shared object file being produced.
>>
>> GP0
>>  Represents the gp value used to create the relocatable object.
>>
>> $ mipsel-linux-objdump -Dr sysconf.o
>>
>> Disassembly of section .reginfo:
>>
>> 00000000 <.reginfo>:
>>   0:   b200001e        0xb200001e
>>        ...
>>  14:   00004000        sll     t0,zero,0x0
>>
>> .reginfo段中记录了ri_gp_value,可以看到,GP0的值为0x4000。
>>
>
> ri_gp_value是什么? 我还是不理解gp0为啥是0x4000。我的理解是0x00004000 就只这个位置指令的binary,对吗?
>
> 我的理解是这个指令是要将来在reloc的时候,被修改的吧。

MIPS通过reginfo保存一些寄存器信息,其结构体为:

typedef struct {
Elf32_Word ri_gprmask;
Elf32_Word ri_cprmask[4];
Elf32_SWord ri_gp_value;
} ELF_RegInfo;

其中最后一个域是记录了GP0的值。

ri_gp_value
         This member contains the gp register value. In relocatable ob-
          ject files it is used for relocation of the R_MIPS_GPREL and
          R_MIPS_LITERAL relocation types.

>> 4、当链接成可执行程序时,依照同样的方法,我们可以找到
>>
>> 00400094 <.reginfo>:
>>  400094:       b20000f4        0xb20000f4
>>        ...
>>  4000a8:       10008a70        b       3e2a6c <__start-0x1d6a4>
>>
>> 所以,gp的值为0x10008a70,
>>
>
> 0x10008a70是指令的binary吗?
>
>> 00425c70 <__sysconf>:
>>  425c70:       3c1c0fbe        lui     gp,0xfbe
>>
>> 所以,S的值为0x425c70,
>>
>
> 这里有点confusing,根据你前边对R_MIPS_GPREL_32 的描述,S是syombl的地址,那么你这里的symbol应该就是__sysconf。

哦,如果是理解成symbol的地址,那就正好是0x425c70。

00425c70 g     F .text  00000000 __sysconf

因为,这里
   Num:  Value  Size         Type    Bind           Vis      Ndx       Name
   2: 00000000     0       SECTION LOCAL  DEFAULT    1

Type和Bind分别为SECTION和LOCAL,所以,我是按照后半句来理解的。

>> 根据公式"A + S + GP0 - GP",可以计算出.rodata中需要重定位的地方的最终内容。比如,对于.rodata中的第一个字,
>>
>> 0xffffc064 + 0x425c70 + 0x4000 - 0x10008a70 = 0xf041d264
>>
>> 5、附注
>>
>> 如果查看一下binutils/bfd/elf32-mips.c,就可以找到R_MIPS_GPREL32相应的HOWTO数据结构,以及处理函数。
>>
>> 6、其它
>>
>> 这里,我个人有一个地方没有搞明白,MIPS ABI中介绍说S是初始的sh_addr减去最终的sh_addr,但是,看起来,似乎应该反过来才正确。
>
> 你在mips abi哪里看到的?原话是怎样的?

relocation章节

S
 Represents the value of the symbol whose index resides in the relocation
 entry, unless the the symbol is STB_LOCAL and is of type
 STT_SECTION in which case S represents the original sh_addr minus
 the final sh_addr.

Other related posts: