代码之家  ›  专栏  ›  技术社区  ›  Emilio M Bumachar

如何从编译器获取指针和变量的大小-从编译代码的外部?

  •  0
  • Emilio M Bumachar  · 技术社区  · 14 年前

    我希望编译器输出一个文件,其中包含指向它正在编译的源代码中所有全局变量的指针,以及它们的大小。

    这可能吗?在任何一个c编译器中都有这样的方法吗?

    4 回复  |  直到 14 年前
        1
  •  1
  •   Commodore Jaeger    14 年前

    这些信息可以在二进制文件的符号表中找到,尽管它可能不是您所期望的那样。

    链接器获取一个或多个对象文件,组合这些部分(将每个对象文件中的所有代码和数据放入一个大的代码和数据部分),并编写一个输出文件。此输出文件可以是可执行文件,也可以是共享库。磁盘上的可执行文件仍然没有每个变量的指针;它仍然存储从节开始到变量的偏移量。

    运行可执行文件时,操作系统的动态加载程序读取可执行文件,查找每个节,并为该节分配内存(它还可以在每个部分上设置不同的权限,“.text”段通常被标记为只读,并且(在支持它的处理器上)数据段有时被标记为不可执行。)只有这样,当代码需要访问特定变量时,变量才会获得指针,它将节开头的地址添加到距节开头的偏移量,以获取指针。

    您可以使用各种工具来研究每个二进制文件的符号表。GNU工具链的 objdump (在Linux上使用)就是这样一个工具。

    对于一个简单的C hello world程序:

    #include <stdio.h>
    
    const char message[] = "Hello world!\n";
    
    int main(int argc, char ** argv) {
            printf(message);
            return 0;
    }
    

    我在Linux上编译(但不链接):

    $ gcc -c hello.c -o hello.o
    

    现在我可以看看符号表:

    $ objdump -t hello.o
    hello.o:     file format elf32-i386
    
    SYMBOL TABLE:
    00000000 l    df *ABS*  00000000 hello.c
    00000000 l    d  .text  00000000 .text
    00000000 l    d  .data  00000000 .data
    00000000 l    d  .bss   00000000 .bss
    00000000 l    d  .rodata        00000000 .rodata
    00000000 l    d  .note.GNU-stack        00000000 .note.GNU-stack
    00000000 l    d  .comment       00000000 .comment
    00000000 g     O .rodata        0000000e message
    00000000 g     F .text  0000002b main
    00000000         *UND*  00000000 puts
    

    第一列是每个符号相对于节开头的地址。每个符号都有不同的标志,其中一些符号被用作工具链和调试器其余部分的提示(如果我使用调试符号构建,我也会看到许多专门用于调试符号的条目。)我的简单程序只有一个变量:

    00000000 g     O .rodata        0000000e message
    

    message

        2
  •  3
  •   Michael Dorgan    14 年前

        3
  •  1
  •   MSN    14 年前

    虽然不需要编译器来输出这些数据,但大多数 链接器 我可以把这些信息都倒出来。例如,Microsoft的链接器映射文件包含可执行文件/dll中的所有公共符号,以及它们相对于所在节的地址(只读、读写、代码、零初始化等)。尺寸可以从中导出,尽管它主要是一个近似值。

    您还可以找到一种方法来检查为可执行文件生成的调试符号,因为这正是调试器必须要做的。

        4
  •  1
  •   Jerry Coffin    14 年前

    通常情况下,你会从链接器而不是编译器那里得到这些信息——链接器是为事物分配地址的工具。大多数链接器可以生成包含全局变量地址的映射文件