【勘误】《编译、链接与库》 5.5 大家都有符号表

​ 在输出结果的最左列是符号的编号,也是符号在符号表中的下标。接着是符号的大小,即符号所表示的对象所占用的空间。第三列是符号所在的位置,……

SimpleSection.c源程序代码:

int printf(const char *format, ...);

int global_init_var = 84;
int global_uninit_var;

void func1(int i)
{
    printf("%d\n", i);
}

int main(void)
{
    static int static_var = 85;
    static int static_var2;

    int a = 1;
    int b;

    func1(static_var + static_var2 + a + b);
    return a;
}

命令行命令:

cl /c /Za .\SimpleSection.c
dumpbin /ALL .\SimpleSection.obj > .\SimpleSection.txt

关于符号表的输出摘录:

COFF SYMBOL TABLE
000 01047558 ABS    notype       Static       | @comp.id
001 80010190 ABS    notype       Static       | @feat.00
002 00000001 ABS    notype       Static       | @vol.md
003 00000000 SECT1  notype       Static       | .drectve
    Section length   18, #relocs    0, #linenums    0, checksum        0
005 00000000 SECT2  notype       Static       | .debug$S
    Section length   94, #relocs    0, #linenums    0, checksum        0
007 00000000 SECT3  notype       Static       | .data
    Section length    C, #relocs    0, #linenums    0, checksum AC5AB941
009 00000000 SECT3  notype       External     | global_init_var
00A 00000004 UNDEF  notype       External     | global_uninit_var
00B 00000000 SECT4  notype       Static       | .text$mn
    Section length   64, #relocs    5, #linenums    0, checksum  D696A53
00D 00000000 UNDEF  notype ()    External     | printf
00E 00000000 SECT4  notype ()    External     | func1
00F 00000030 SECT4  notype ()    External     | main
010 00000000 SECT4  notype       Label        | $LN3
011 00000030 SECT4  notype       Label        | $LN3
012 00000000 SECT5  notype       Static       | .xdata
    Section length   10, #relocs    0, #linenums    0, checksum 434E1581
014 00000000 SECT5  notype       Static       | $unwind$func1
015 00000000 SECT6  notype       Static       | .pdata
    Section length   18, #relocs    6, #linenums    0, checksum 5710F00F
017 00000000 SECT6  notype       Static       | $pdata$func1
018 00000008 SECT5  notype       Static       | $unwind$main
019 0000000C SECT6  notype       Static       | $pdata$main
01A 00000004 SECT3  notype       Static       | $SG6143
01B 00000008 SECT3  notype       Static       | ?static_var@?1??main@@9@9 (`main'::`2'::static_var)
01C 00000000 SECT7  notype       Static       | .bss
    Section length    4, #relocs    0, #linenums    0, checksum        0
01E 00000000 SECT7  notype       Static       | ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2)
01F 00000000 SECT8  notype       Static       | .chks64
    Section length   40, #relocs    0, #linenums    0, checksum        0

String Table Size = 0x8F bytes

  Summary

           4 .bss
          40 .chks64
           C .data
          94 .debug$S
          18 .drectve
          18 .pdata
          64 .text$mn
          10 .xdata

可是对照global_init_var那一行的信息,第二列是00000000,如果这一列表示符号的大小,那显示的应该是00000004,这显然与书上说的矛盾,这让我很困惑。

对照.data中的数据:

SECTION HEADER #3
   .data name
       0 physical address
       0 virtual address
       C size of raw data
     200 file pointer to raw data (00000200 to 0000020B)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0300040 flags
         Initialized Data
         4 byte align
         Read Write

RAW DATA #3
  00000000: 54 00 00 00 25 64 0A 00 55 00 00 00              T...%d..U...

54 00 00 00的十进制是84,那么这个是变量global_init_var,而25 64 0A 00这个显然是字符串"%d\n"了,55 00 00 00是变量static_var

再次结合之前讲到的关于ELF文件关于符号的内容:

符号值(st_value)我们前面已经介绍过,每个符号都有一个对应的值,如果这个符号是一个函数或变量的定义,那么符号的值就是这个函数或变量的地址……在目标文件中,如果是符号的定义并且该符号不是“COMMON块”类型的,则st_value表示该符号在段中的偏移。即符号所对应的函数或变量位于由st_shndx指定的段,偏移st_value的位置。这也是目标文件中定义全局变量的符号的最常见情况……

那么可以初步断定这一列表示的意义实际上是变量或函数在该段中的偏移量,再结合代码段看看:

SECTION HEADER #4
.text$mn name
       0 physical address
       0 virtual address
      64 size of raw data
     20C file pointer to raw data (0000020C to 0000026F)
     270 file pointer to relocation table
       0 file pointer to line numbers
       5 number of relocations
       0 number of line numbers
60500020 flags
         Code
         16 byte align
         Execute Read

RAW DATA #4
  00000000: 89 4C 24 08 48 83 EC 28 8B 54 24 30 48 8D 0D 00  .L$.H.?.T$0H...
  00000010: 00 00 00 E8 00 00 00 00 48 83 C4 28 C3 CC CC CC  ...?...H.?锰烫
  00000020: CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  烫烫烫烫烫烫烫烫
  00000030: 48 83 EC 38 C7 44 24 20 01 00 00 00 8B 05 00 00  H.?荄$ ........
  00000040: 00 00 8B 0D 00 00 00 00 03 C8 8B C1 03 44 24 20  .........??D$ 
  00000050: 03 44 24 24 8B C8 E8 00 00 00 00 8B 44 24 20 48  .D$$.辱.....D$ H
  00000060: 83 C4 38 C3                                      .??

RELOCATIONS #4
                                                Symbol    Symbol
 Offset    Type              Applied To         Index     Name
 --------  ----------------  -----------------  --------  ------
 0000000F  REL32                      00000000        1A  $SG6143
 00000014  REL32                      00000000         D  printf
 0000003E  REL32                      00000000        1E  ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2)
 00000044  REL32                      00000000        1B  ?static_var@?1??main@@9@9 (`main'::`2'::static_var)
 00000057  REL32                      00000000         E  func1

将目标文件反汇编:

dumpbin /disasm .\SimpleSection.obj > .\SimpleSection.asm

反汇编文件内容:

Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file .\SimpleSection.obj

File Type: COFF OBJECT

func1:
  0000000000000000: 89 4C 24 08        mov         dword ptr [rsp+8],ecx
  0000000000000004: 48 83 EC 28        sub         rsp,28h
  0000000000000008: 8B 54 24 30        mov         edx,dword ptr [rsp+30h]
  000000000000000C: 48 8D 0D 00 00 00  lea         rcx,[$SG6143]
                    00
  0000000000000013: E8 00 00 00 00     call        printf
  0000000000000018: 48 83 C4 28        add         rsp,28h
  000000000000001C: C3                 ret
  000000000000001D: CC                 int         3
  000000000000001E: CC                 int         3
  000000000000001F: CC                 int         3
  0000000000000020: CC                 int         3
  0000000000000021: CC                 int         3
  0000000000000022: CC                 int         3
  0000000000000023: CC                 int         3
  0000000000000024: CC                 int         3
  0000000000000025: CC                 int         3
  0000000000000026: CC                 int         3
  0000000000000027: CC                 int         3
  0000000000000028: CC                 int         3
  0000000000000029: CC                 int         3
  000000000000002A: CC                 int         3
  000000000000002B: CC                 int         3
  000000000000002C: CC                 int         3
  000000000000002D: CC                 int         3
  000000000000002E: CC                 int         3
  000000000000002F: CC                 int         3
main:
  0000000000000030: 48 83 EC 38        sub         rsp,38h
  0000000000000034: C7 44 24 20 01 00  mov         dword ptr [rsp+20h],1
                    00 00
  000000000000003C: 8B 05 00 00 00 00  mov         eax,dword ptr [?static_var2@?1??main@@9@9]
  0000000000000042: 8B 0D 00 00 00 00  mov         ecx,dword ptr [?static_var@?1??main@@9@9]
  0000000000000048: 03 C8              add         ecx,eax
  000000000000004A: 8B C1              mov         eax,ecx
  000000000000004C: 03 44 24 20        add         eax,dword ptr [rsp+20h]
  0000000000000050: 03 44 24 24        add         eax,dword ptr [rsp+24h]
  0000000000000054: 8B C8              mov         ecx,eax
  0000000000000056: E8 00 00 00 00     call        func1
  000000000000005B: 8B 44 24 20        mov         eax,dword ptr [rsp+20h]
  000000000000005F: 48 83 C4 38        add         rsp,38h
  0000000000000063: C3                 ret

  Summary

           4 .bss
          40 .chks64
           C .data
          94 .debug$S
          18 .drectve
          18 .pdata
          64 .text$mn
          10 .xdata

可以看到func1确实是以00000000开头,main以00000030开头,那么可以确定之前的结论是正确的。对于变量和函数来说,符号表输出的第二列是其在段内的偏移量。而对于global_uninit_var这样的(COMMON块)变量才表示是符号的大小,即符号所表示的对象所占用的空间:

// ...
long long global_uninit_var;
int global_uninit_var2;
// ...
int main()
{
	// ...
}
00A 00000008 UNDEF  notype       External     | global_uninit_var
00B 00000004 UNDEF  notype       External     | global_uninit_var2
上一篇:AE快速景深模糊插件Fast Bokeh破解版


下一篇:mysql存储过程教程视频,附答案