C .o文件中的内存共享

C .o文件中的内存共享,c,memory,compiler-construction,linker,C,Memory,Compiler Construction,Linker,假设我有一个a.c文件,并将其编译成a.o文件。 A.c文件如下: int a; void add(void) { } A.o文件与B.o一起构成A1.exe文件。 A.o文件与C.o一起构成2.exe文件 我的问题是,如果我同时运行1.exe和2.exe,这两个.exe文件的a和add()地址是否相同?换句话说,内存中有两个A.o,还是只有一个?内存中没有任何重新定位的对象文件 我猜你有一个Linux系统。如果安装在Windows上,则原理保持不变,但细节不同 链接器(被调用来构建1.exe

假设我有一个
a.c
文件,并将其编译成
a.o
文件。
A.c
文件如下:

int a;
void add(void)
{
}
A.o
文件与
B.o
一起构成A
1.exe
文件。
A.o
文件与
C.o
一起构成
2.exe
文件


我的问题是,如果我同时运行
1.exe
2.exe
,这两个
.exe
文件的
a
add()
地址是否相同?换句话说,内存中有两个
A.o
,还是只有一个?

内存中没有任何重新定位的对象文件

我猜你有一个Linux系统。如果安装在Windows上,则原理保持不变,但细节不同

链接器(被调用来构建
1.exe
2.exe
)构建一个可执行文件(由几个段组成,特别是所谓的机器代码和只读常量数据段,以及可变数据段)。启动该程序的系统调用是ELF文件的几个段的内存映射(类似于一些
mmap(2)
syscall)

请注意,对Linux可执行文件使用
.exe
文件后缀既令人困惑又不常见。按照惯例,Linux可执行文件根本没有后缀,而是以小写字母开头

链接器已将两个
A.o
文件复制并重新定位到不同的位置(因为存在错误)。因此通常情况下,
a
add
的地址在
1.exe
2.exe
中不同,处理它们的机器指令也不同

每个都有自己的(可以随系统调用而更改)。键入
cat/proc/1234/maps
以了解pid 1234进程的地址空间。还可以尝试
cat/proc/self/maps
获取运行该
cat
的进程的地址空间

如果您有一个共享对象(或动态库)
libA,而不是
A.o
object,那么
它的一些(
mmap
-ed)段将被共享(其他部分将使用技术),并且一些重定位在动态链接时发生(例如,在
dlopen
期间,如果它是一个插件)


另请阅读。

a和
add
的地址将不相同。您有两个进程,因此在此实例中内存中有两个副本。

这取决于链接。默认情况下,链接始终是动态的,因此当您将两个exe文件加载到内存中时,文件A.o将表现为可重入函数,它的唯一一个实例将位于由这两个exe文件共享的内存中

它类似于printf函数…有太多printf任何diff-diff文件,但一次只有一个实例在内存中运行


可重入函数不应产生任何必须注意的数据损坏

为什么要使用.exe后缀?因为原始海报使用了
.exe
后缀,那么OP可能在Windows上使用了GCC,而您关于
mmap
和ELF的所有内容都与此无关。