回答
该信息在二进制文件的符号表中可用,但它可能并不意味着您期望它。
编译器需要一个或多个源文件,将代码编译为目标代码,并生成目标文件(在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字节。
像是一个地图文件?这将显示全局和静态分配的位置,但不是它们指向的位置。大多数编译器(链接器)会自动输出一个或用简单的语句输出。只需在文档中搜索地图文件即可。
虽然不需要编译器输出此数据,但大多数连接器可以转储出此信息。例如,Microsoft的链接器映射文件包含可执行文件/ dll中的所有公共符号以及它们相对于该节的地址(只读,读写,代码,零初始化等)。尺寸可以从尽管这主要是一种近似。
您也可以想出一种方法来检查为可执行文件生成的调试符号,因为这正是调试器必须执行的操作。
通常情况下,你会从链接器而不是编译器得到这个 - 链接器是指定地址的东西。大多数链接器可以生成一个映射文件,其中包含全局变量和函数的地址(以及其创建的可执行文件中的任何其他符号)。这将由你来决定哪个是哪个。我见过的所有这些都包含一些东西来告诉你,但确切的格式因链接器而异。
- 1. 在编译时检查指针大小
- 2. 指针编译器问题
- 3. 如何编译高级代码以获取汇编代码?
- 4. 编译C90代码时在gcc编译器中获取警告“ISO C90禁止使用可变大小的数组”在编译C90代码时
- 5. 用C++编译器编译c代码
- 6. 如何使用autoconf获取“编译”和“目标”C编译器
- 7. 我如何获得编译指令来侦听其范围之外的变量?
- 8. 获取已编译类的源代码
- 9. 如何使用插口编译器为Android编译代码?
- 10. 编译错误的代码的编译
- 11. 如何编译java代码?
- 12. 如何编译cython代码
- 13. LINQPad如何编译代码?
- 14. 某些GCC编译器如何修改常量字符指针?
- 15. 有选择地编译宏代码之外的代码
- 16. 使用Windows编译器之间的编译库编译器,cygwin和linux g ++
- 17. 编译器如何对待extern变量
- 18. 衍生代码编译器
- 19. SML编译器源代码?
- 20. 从python代码编译DLL
- 21. 从反编译java代码
- 22. 从IntelliJ编译代码
- 23. nginx从源代码编译
- 24. 如何从源代码编译Blender?
- 25. 如何从源代码编译XBMC
- 26. 如何以编程方式从使用mingw32-gcc编译器的c#代码编译c代码
- 27. 编译器编译外部包含
- 28. 代码合同和编译
- 29. Java代码和JIT编译
- 30. erlang-如何编译和代码
指针是在运行时定义的“数字”(地址)。你所问的是无意义的。 – 2010-07-01 17:17:26
你想达到什么目的?告诉我们你的问题,而不是你的解决方案。 – philant 2010-07-01 17:20:05
@Alexandre:指针是在编译时定义的,相对于分配给进程的内存的开始 – 2010-07-01 17:20:19