静态连接2-hello.o

来源:互联网 发布:网页设计程序员培训 编辑:程序博客网 时间:2024/05/26 22:58
 看一下hello.o的符号表
[root@localhost mhello]# readelf -S  hello.o
There are 11 section headers, starting at offset 0x144:
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 000034 000068 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 000448 000048 08      9   1  4
  [ 3] .data             PROGBITS        00000000 00009c 000000 00  WA  0   0  4
  [ 4] .bss              NOBITS          00000000 00009c 000000 00  WA  0   0  4
  [ 5] .rodata           PROGBITS        00000000 00009c 000029 00   A  0   0  1
  [ 6] .comment          PROGBITS        00000000 0000c5 00002d 00      0   0  1
  [ 7] .note.GNU-stack   PROGBITS        00000000 0000f2 000000 00      0   0  1
  [ 8] .shstrtab         STRTAB          00000000 0000f2 000051 00      0   0  1
  [ 9] .symtab           SYMTAB          00000000 0002fc 0000f0 10     10   8  4
  [10] .strtab           STRTAB          00000000 0003ec 00005a 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

[root@localhost mhello]# readelf -s hello.o
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 hello.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 SECTION LOCAL  DEFAULT    3
     4: 00000000     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000000     0 SECTION LOCAL  DEFAULT    7
     7: 00000000     0 SECTION LOCAL  DEFAULT    6
     8: 00000000    20 FUNC    GLOBAL DEFAULT    1 func_hello
     9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
    10: 00000014    84 FUNC    GLOBAL DEFAULT    1 main
    11: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND func_file_a
    12: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND func_file_b
    13: 00000004     4 OBJECT  GLOBAL DEFAULT  COM var_public_file_a
    14: 00000004     4 OBJECT  GLOBAL DEFAULT  COM var_public_file_b
//func_hello,main都是在本模块hello.o内部定义的,所以符号位置在1段,即代码段
//func_file_a,func_file_b是外部符号,前者是一个来自另外一个.o的符号,后者是来自另外一个.so的符号,
//但对于hello.o而言二者都是外部符号,hello.o无力判断他们的出身,将他们视为und--undefined
//var_public_file_a,var_public_file_b放在common块中,在hello.o中还不确定他们到底是不是
//在本模块定义的,因为没有初始化,也没有加extern,现将其是为弱符号,留校观察

 

看一下hello.o的重定位表
[root@localhost mhello]# readelf -r hello.o

Relocation section '.rel.text' at offset 0x424 contains 9 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000009  00000501 R_386_32          00000000   .rodata
0000000e  00000902 R_386_PC32        00000000   puts
00000028  00000501 R_386_32          00000000   .rodata
0000002d  00000902 R_386_PC32        00000000   puts
00000032  00000802 R_386_PC32        00000000   func_hello
0000003e  00000b02 R_386_PC32        00000000   func_file_a
0000004a  00000c02 R_386_PC32        00000000   func_file_b
00000051  00000501 R_386_32          00000000   .rodata
00000056  00000902 R_386_PC32        00000000   puts
//看来不管内部符号,还是外部.o的符号,还是外部.so的符号都是需要重定位的,所以才叫重定位文件嘛
//内部符号和外部.o的符号在链接时由链接器重定位
//外部.so的符号由...........
//虽此时没能定位,但是所有符号在.text(和.data)section的位置--offset已定|
//这个表的作用是指示链接器,你需要在代码段中的这些Offset处重新塞进一些数据,
//这个新的数据却不是外部符号已确定的虚拟地址,而是一个偏移量
//通过这个偏移量可以找到想要的符号的虚拟地址,见后面-------

看一下hello.o的反汇编
[root@localhost mhello]# objdump -S hello.o
hello.o:     file format elf32-i386
Disassembly of section .text:
00000000 <func_hello>:
   0: 55                    push   %ebp
   1: 89 e5                 mov    %esp,%ebp
   3: 83 ec 08              sub    $0x8,%esp
   6: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
   d: e8 fc ff ff ff        call   e <func_hello+0xe>
  12: c9                    leave 
  13: c3                    ret   

00000014 <main>:
  14: 8d 4c 24 04           lea    0x4(%esp),%ecx
  18: 83 e4 f0              and    $0xfffffff0,%esp
  1b: ff 71 fc              pushl  -0x4(%ecx)
  1e: 55                    push   %ebp
  1f: 89 e5                 mov    %esp,%ebp
  21: 51                    push   %ecx
  22: 83 ec 04              sub    $0x4,%esp
  25: c7 04 24 15 00 00 00  movl   $0x15,(%esp)
  2c: e8 fc ff ff ff        call   2d <main+0x19>
  31: e8 fc ff ff ff        call   32 <main+0x1e>
  36: c7 04 24 06 00 00 00  movl   $0x6,(%esp)
  3d: e8 fc ff ff ff        call   3e <main+0x2a>
  42: c7 04 24 06 00 00 00  movl   $0x6,(%esp)
  49: e8 fc ff ff ff        call   4a <main+0x36>
  4e: c7 04 24 20 00 00 00  movl   $0x20,(%esp)
  55: e8 fc ff ff ff        call   56 <main+0x42>
  5a: b8 00 00 00 00        mov    $0x0,%eax
  5f: 83 c4 04              add    $0x4,%esp
  62: 59                    pop    %ecx
  63: 5d                    pop    %ebp
  64: 8d 61 fc              lea    -0x4(%ecx),%esp
  67: c3                    ret   

出现了几个call   3e <main+0x2a>之类的代码,3e是相对本段即text段的偏移,2a是相对main符号的偏移,main:14,3e=2a+14
他们的二进制是清一色的e8 fc ff ff ff   ,e8是近地址相对位移调用指令,fc ff ff ff  (=-4) 是被调用函数的相对于调用指令的下一条指定的偏移量
此时,即
2c: e8 fc ff ff ff     // 地址为-4+31=2d,所以其汇编为 call 2d
31: e8 fc ff ff ff  
36: c7 04 24 06 00 00 00
3d: e8 fc ff ff ff     //3e 3f 40 41保存的是一个相对于42的偏移量X,而42+X便是要cpu去拜访的符号的地址
                             //,X现在暂定为-4
                             //所以地址为-4+42=3e,所以其汇编为 call 3e,(3e是目标地址,即跳转到地址3e去执行)-
                             //----巧的是本指令地址后面就是地址3e,
                            //这个巧合,却让我误以为3e里面以后会放一些虚拟地址之类的东东,现在知道额错了,
                             //3e-3f-40-41里面放的仅仅是偏移---
 3e   fc                 //在hello.o中3e处的值没有意义,因为hello.o不能执行,所以管你是
 3f     ff                //多少呢,我又不去你那玩
 40   ff                //为什么是偏偏是-4(fc ff ff ff )呢?或许用100便不会引起我之前的误会了,
 41   ff               //便是cpu跳到42+100处执行任务
             

42: c7 04 24 06 00 00 00
49: e8 fc ff ff ff        
4e: c7 04 24 20 00 00 00 
55: e8 fc ff ff ff