2010-07-01 37 views
0

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

这可能吗?有没有办法在任何C编译器中做到这一点?

+0

指针是在运行时定义的“数字”(地址)。你所问的是无意义的。 – 2010-07-01 17:17:26

+0

你想达到什么目的?告诉我们你的问题,而不是你的解决方案。 – philant 2010-07-01 17:20:05

+1

@Alexandre:指针是在编译时定义的,相对于分配给进程的内存的开始 – 2010-07-01 17:20:19

回答

1

该信息在二进制文件的符号表中可用,但它可能并不意味着您期望它。

编译器需要一个或多个源文件,将代码编译为目标代码,并生成目标文件(在Unix上为.o,在Windows上为.obj)。在符号表中提到了源文件中引用的所有变量和函数。源文件中定义的变量和函数具有特定的地址和大小,而未在源文件中定义的符号标记为未定义,并且必须稍后进行链接。所有符号都是相对于特定部分列出的。常见部分是可执行代码的“.text”,程序启动时初始化为零的变量的“.bss”,以及用非零值初始化的变量的“.data”。

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

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

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

对于一个简单的C你好世界程序:

#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是大小0xe - 14字节。

3

像是一个地图文件?这将显示全局和静态分配的位置,但不是它们指向的位置。大多数编译器(链接器)会自动输出一个或用简单的语句输出。只需在文档中搜索地图文件即可。

1

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

您也可以想出一种方法来检查为可执行文件生成的调试符号,因为这正是调试器必须执行的操作。

1

通常情况下,你会从链接器而不是编译器得到这个 - 链接器是指定地址的东西。大多数链接器可以生成一个映射文件,其中包含全局变量函数的地址(以及其创建的可执行文件中的任何其他符号)。这将由你来决定哪个是哪个。我见过的所有这些都包含一些东西来告诉你,但确切的格式因链接器而异。