Elf的.rel.text部分中R_386_32/R_386_PC32的含义

mez*_*zda 11 c linux x86 assembly

要了解重定位的概念,我写了一个简单的chk.c程序如下:

  1 #include<stdio.h>
  2 main(){
  3         int x,y,sum;
  4         x = 3;
  5         y = 4;
  6         sum = x + y;
  7         printf("sum = %d\n",sum);
  8 }
Run Code Online (Sandbox Code Playgroud)

它的等效汇编代码,使用"objdump -d chk.o"是:

00000000 <main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 e4 f0                and    $0xfffffff0,%esp
   6:   83 ec 20                sub    $0x20,%esp
   9:   c7 44 24 1c 03 00 00    movl   $0x3,0x1c(%esp)
  10:   00 
  11:   c7 44 24 18 04 00 00    movl   $0x4,0x18(%esp)
  18:   00 
  19:   8b 44 24 18             mov    0x18(%esp),%eax
  1d:   8b 54 24 1c             mov    0x1c(%esp),%edx
  21:   8d 04 02                lea    (%edx,%eax,1),%eax
  24:   89 44 24 14             mov    %eax,0x14(%esp)
  28:   b8 00 00 00 00          mov    $0x0,%eax
  2d:   8b 54 24 14             mov    0x14(%esp),%edx
  31:   89 54 24 04             mov    %edx,0x4(%esp)
  35:   89 04 24                mov    %eax,(%esp)
  38:   e8 fc ff ff ff          call   39 <main+0x39>
  3d:   c9                      leave  
  3e:   c3                      ret    
Run Code Online (Sandbox Code Playgroud)

使用readelf看到的.rel.text部分如下:

Relocation section '.rel.text' at offset 0x360 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000029  00000501 R_386_32          00000000   .rodata
00000039  00000902 R_386_PC32        00000000   printf
Run Code Online (Sandbox Code Playgroud)

我有以下问题:

1)从.rel.text部分的第二个条目,我能够理解.text部分(这里是0xfcffffff)的偏移量0x39处的值必须替换为与符号表的索引9相关联的符号的地址(&这就是printf).但我在这里无法清楚地理解0x02(ELF32_R_TYPE)的含义.R_386_PC32在这里指定了什么?任何人都可以清楚地解释其含义.

2)我也无法理解第一项.什么需要在.text部分的偏移量为0x29时替换,为什么不清楚这里.我想再次知道R_386_32的含义.我发现了一个pdf elf_format.pdf,但是我无法清楚地理解.rel.text部分中"Type"的含义.

3)我也想知道汇编inst"lea(%edx,%eax,1),%eax"的含义.虽然我找到了一个非常好的链接(LEA指令的目的是什么?),描述了lea的含义,但是lea的格式(括号内的3个arg)并不清楚.

如果有人能够清楚地解释上述问题的答案,将不胜感激.我仍在努力寻找这些问题的答案,尽管我已经尝试了很多谷歌.

还有一个问题.我已经显示了下面的偏移5和9的符号表条目.

 Num: Value Size Type Bind Vis Ndx Name 
 5: 00000000 0 SECTION LOCAL DEFAULT 5 
 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf' 
Run Code Online (Sandbox Code Playgroud)

.rel.text表中第一个条目的info字段是0x05,表示符号表的索引.我已经在上面显示了索引5的符号表条目,但是无法理解它是如何告诉我们它是.rodata的.

nne*_*neo 14

1),2):R_386_32是一个重定位,它将符号绝对32位地址放入指定的存储单元.R_386_PC32是一个重定位,它将符号PC相关32位地址放入指定的内存位置.R_386_32对于静态数据很有用,如此处所示,因为编译器只是将重定位的符号地址加载到某个寄存器中,然后将其视为指针.R_386_PC32对函数引用很有用,因为它可以用作直接参数call.有关如何处理重定位的示例,请参阅elf_machdep.c.

3)lea (%edx,%eax,1),%eax意味着简单地%eax = %edx + 1*%eax用C语法表达.在这里,它基本上被用作add操作码的替代品.

编辑:这是一个例子.

假设您的代码从0x401000开始加载到内存中,该字符串"sum = %d\n"最终在0x401800(在该.rodata部分的开头),并且printf在libc中为0x1400ab80.

然后,R_386_320x29处的重定位将字节00 18 40 00置于0x401029(只需复制符号的绝对地址),使指令位于0x401028

  401028:   b8 00 18 40 00          mov    $0x401800,%eax
Run Code Online (Sandbox Code Playgroud)

R_386_PC32在0x39地方字节重定位43 9b c0 13在0x401039(值0x1400ab80 - 0x40103d =十六进制0x13c09b43),从而使该指令

  401038:   e8 43 9b c0 13          call   $0x1400ab80 <printf>
Run Code Online (Sandbox Code Playgroud)

我们减去0x40103d以考虑%pc的值(后面是指令的地址call).

  • 只是 nneonneo 的好答案的一个小补充:根据 ELF 规范,R_386_PC32 模式下的重定位值计算为 S + A - P,其中 S 是符号值,A 是当前存在于重定位所采用的地址处的值place,其中 P 是重定位地址。这里,S - P 是从重定位点 0x401029 到函数入口点的跳转偏移量,加上 A=0xfcffffff 导致递减 4 个字节,说明 call 指令期望从下一条指令开始测量的偏移量. (2认同)

twa*_*erg 5

第一个重定位条目是"sum = ..."在设置调用的过程中获取指向格式字符串()的指针printf.由于该.rodata部分以及部分都是重定位的.text,因此对字符串和其他常量数据的引用将需要修复.

考虑到这一点,似乎R_386_32重定位处理数据,R_386_PC32处理代码地址,但ELF规范(我没有方便的副本)可能解释了各种细节.

lea指令是编译器选择为此例程执行添加的指令.它本可以选择add或其他几种可能性,但这种形式lea似乎经常用于某些情况,因为它可以将加法与乘法相结合.指令的结果lea (%edx,%eax,1),%eax%eax将得到的值%edx + 1 * %eax.1可以用一组有限的小整数代替.该lea指令的最初目的是"加载有效地址" - 获取基指针,索引和大小,并产生数组中元素的地址.但是,正如您所看到的,编译器可以选择将其用于其他事情,以及......