可以说我有一个A.c
文件并将其编译为一个 A.o
文件。该A.c
文件如下:
int a;
void add(void)
{
}
该A.o
文件与一个B.o
表格一起成为一个1.exe
文件。该A.o
文件与一个C.o
表格一起成为一个2.exe
文件。
我的问题是,如果我同时运行1.exe
,这两个文件2.exe
的地址a
和地址是否相同?换句话说,内存中有两个还是只有一个?add()
.exe
A.o
可以说我有一个A.c
文件并将其编译为一个 A.o
文件。该A.c
文件如下:
int a;
void add(void)
{
}
该A.o
文件与一个B.o
表格一起成为一个1.exe
文件。该A.o
文件与一个C.o
表格一起成为一个2.exe
文件。
我的问题是,如果我同时运行1.exe
,这两个文件2.exe
的地址a
和地址是否相同?换句话说,内存中有两个还是只有一个?add()
.exe
A.o
a
和的地址add
不会相同。您有两个进程,因此在此实例中内存中有两个副本。
您在内存中没有任何重定位的目标文件。
我猜你有一个Linux系统。如果在 Windows 上,原则保持不变,但细节不同。
链接器(调用来构建1.exe
和2.exe
)构建一个可执行的ELF文件(由几个段组成,特别是机器代码和只读常量数据的所谓“文本”段,以及可变数据的“数据”段)。启动该程序的execve(2)系统调用是内存映射 ELF 文件的几个段(几乎就像某些mmap(2)
系统调用一样)。
请注意,.exe
对 Linux 可执行文件使用文件后缀是令人困惑且不常见的。按照惯例,Linux 可执行文件根本没有后缀,并且以小写字母开头。
链接器已将两个文件复制并重定位A.o
到不同的东西(因为relocation)。所以通常会发生a
or的地址在和 inadd
中不同的情况,处理它们的机器指令也是如此。1.exe
2.exe
每个进程都有自己的地址空间(可以通过例如mmap(2)系统调用进行更改)。键入cat /proc/1234/maps
以了解 pid 1234 的进程的地址空间。还尝试cat /proc/self/maps
获取运行该cat
.
如果A.o
你有一个共享对象(或动态库)而不是对象,则libA.so
它的一些(mmap
-ed)段将被共享(而另一些将使用写入时复制技术),并且一些重定位发生在动态链接时(例如,dlopen
如果它是一个插件)。
另请阅读Levine 关于链接器和加载器的书。
它取决于链接...。默认情况下,链接始终是动态的,因此当您将两个 exe 文件加载到内存中时,文件 Ao 将表现为可重入函数,并且它的唯一一个实例将在内存中,由这两个 exe 文件共享。 .
它就像 printf 函数......有这么多 printf 任何差异差异文件,但一次只有一个实例在内存中运行......
可重入函数不应提供您必须处理的任何数据损坏