我了解地址空间如何划分为:代码、数据、堆栈和堆。但是,我无法将给定 C 代码的内容映射到何处。
我知道:全局变量在数据部分。静态变量在数据部分。局部变量在堆栈部分。动态分配的空间在堆部分。我的问题是,当将库包含到程序中时,它在地址空间中的位置是什么?
我希望这个问题有意义..
我了解地址空间如何划分为:代码、数据、堆栈和堆。但是,我无法将给定 C 代码的内容映射到何处。
我知道:全局变量在数据部分。静态变量在数据部分。局部变量在堆栈部分。动态分配的空间在堆部分。我的问题是,当将库包含到程序中时,它在地址空间中的位置是什么?
我希望这个问题有意义..
实际上,如果您有基于 linux 的 pc,您可以通过以下方式自行检查:
编译
$ gcc -o 主 ./main.c -g
发射
$ gdb ./main
显示映射信息
(gdb) r
(gdb) info proc 映射
映射地址空间:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /tmp/main
0x600000 0x601000 0x1000 0x0 /tmp/main
0x601000 0x602000 0x1000 0x1000 /tmp/main
0x602000 0x623000 0x21000 0x0 [heap]
0x7ffff7a0d000 0x7ffff7bcd000 0x1c0000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bcd000 0x7ffff7dcd000 0x200000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dcd000 0x7ffff7dd1000 0x4000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dd1000 0x7ffff7dd3000 0x2000 0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dd3000 0x7ffff7dd7000 0x4000 0x0
0x7ffff7dd7000 0x7ffff7dfd000 0x26000 0x0 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7fd4000 0x7ffff7fd7000 0x3000 0x0
0x7ffff7ff6000 0x7ffff7ff8000 0x2000 0x0
0x7ffff7ff8000 0x7ffff7ffa000 0x2000 0x0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffdd000 0x7ffffffff000 0x22000 0x0 [stack]
所以我们看到,ld-so已经把 c 库放到了地址中0x7ffff7bcd000 - 0x7ffff7dd5000
。偏移量字段 - 是 ELF 文件本身的偏移量。我们可以使用 readelf 检查哪些部分对应于哪个偏移量:
$ readelf -a /lib/x86_64-linux-gnu/libc-2.23.so | less
敌人示例:
[13] .text PROGBITS 000000000001f8b0 0001f8b0
0000000000153214 0000000000000000 AX 0 0 16
这意味着该.text
部分有 offset 0x1f8b0
。从上面的映射我们可以得出,主应用程序地址空间中.text部分开头的虚拟地址将是0x7ffff7bcd000 + 0x1f8b0
你是从一个糟糕的前提开始的:
我了解地址空间如何划分为:代码、数据、堆栈和堆。但是,我无法将给定 C 代码的内容映射到何处。
地址空间不是以这种方式划分的。地址空间包含内存。用于堆栈的内存与用于堆的内存无法区分。使堆栈成为堆栈的唯一原因是它在应用程序中使用堆栈指针进行分配。使堆成为堆的唯一原因是应用程序中有一个堆管理器。您可以从堆中分配内存并将其分配给硬件堆栈指针,并且您的内存既是堆又是堆栈。
这是另一个误解:
我知道:全局变量在数据部分。静态变量在数据部分。局部变量在堆栈部分。动态分配的空间在堆部分。
汇编器、链接器和系统之间的工作人员有何不同。然而,有理汇编器允许用户定义他们自己的命名节。在许多汇编程序中,我可以创建 Bobs_Data_Section、Freds_Data_Section 和 Sams_Data_section,并将全局变量放入其中。
对于大多数(但不是全部)编译器,程序员无法控制如何创建节。不能保证编译器会将全局变量放在称为“数据”的部分中。实际上,全局变量和静态局部变量可以在同一段中。
这样的“部分”通常只输入到链接器。链接器将汇编器和编译器定义的段组合到具有公共访问属性的内存区域中。例如,作为“数据”部分进入链接器的内容作为可执行文件中的指令从链接器中出来,以创建可读/写的页面。
我的问题是,当将库包含到程序中时,它在地址空间中的位置是什么?
因此,现在您遇到了如何尝试了解事物如何工作的问题。如果您将进程地址空间视为内存,则可以在任何地方加载库。程序加载器读取可执行文件中的指令,并在地址空间中任何可用的地方创建具有正确属性(例如,只读/不执行、读/写、只读/执行)的页面。
如果您将地址空间视为被划分为代码、数据等,那么加载库就会出现问题。这让我想知道为什么学校和书籍坚持使用这些荒谬的概念进行教学。