在 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.