【发布时间】:2020-11-26 06:52:59
【问题描述】:
我有一个m.c:
extern void a(char*);
int main(int ac, char **av){
static char string [] = "Hello , world!\n";
a(string);
}
还有一个a.c:
#include <unistd.h>
#include <string.h>
void a(char* s){
write(1, s, strlen(s));
}
我将这些编译和构建为:
g++ -c -g -std=c++14 -MMD -MP -MF "m.o.d" -o m.o m.c
g++ -c -g -std=c++14 -MMD -MP -MF "a.o.d" -o a.o a.c
g++ -o linux m.o a.o -lm -lpthread -ldl
然后,我检查可执行文件 linux,因此:
objdump -drwxCS -Mintel linux
我的Ubuntu 16.04.6 上的输出以:
start address 0x0000000000400540
然后是init 部分:
00000000004004c8 <_init>:
4004c8: 48 83 ec 08 sub rsp,0x8
最后是fini 部分:
0000000000400704 <_fini>:
400704: 48 83 ec 08 sub rsp,0x8
400708: 48 83 c4 08 add rsp,0x8
40070c: c3 ret
程序引用了通过命令获得的.data段中的字符串Hello , world!\n:
objdump -sj .data linux
Contents of section .data:
601030 00000000 00000000 00000000 00000000 ................
601040 48656c6c 6f202c20 776f726c 64210a00 Hello , world!..
所有这些都告诉我,可执行文件已被创建,以便加载到从0x0000000000400540(.init 的地址)开始的实际内存地址中,并且程序访问实际内存地址中的数据,直到至少 @987654341 @(.data的地址)
我基于"Linkers & Loaders" by John R Levine 的第 7 章,其中他说:
链接器将一组输入文件组合成一个输出文件 已准备好在特定地址加载。
我的问题是关于下一行的。
如果在加载程序时,该地址的存储不是 可用,加载程序必须重新定位加载的程序以反映 实际加载地址。
(1) 假设我的机器上正在运行的另一个可执行文件已经使用了400540 和601040 之间的内存空间,那么如何决定在哪里启动我的新可执行文件linux?
(2) 与此相关,在第 4 章中说:
..ELF 对象...被加载在地址空间的中间,所以 堆栈可以向下增长到文本段下方,而堆可以增长 从数据末尾开始,保持总地址空间在使用中 比较紧凑。
假设以前运行的应用程序从200000 开始,现在linux 开始在400540 附近。内存地址没有冲突或重叠。但是随着程序的继续,假设前一个应用程序的堆上升到300000,而新启动的linux 的堆下降到310000。很快,内存地址就会发生冲突/重叠。当冲突最终发生时会发生什么?
【问题讨论】:
标签: c linux assembly memory linker