.o 文件是目标文件。它是最终程序的中间表示。
具体来说,.o 文件通常具有已编译的代码,但它没有的是所有不同例程或数据的最终地址。
程序在运行之前需要的东西之一是类似于内存映像的东西。
例如。
如果你有你的主程序,它调用了一个例程 A。(这是假的 fortran,我几十年没碰过,所以在这里和我一起工作。)
PROGRAM MAIN
INTEGER X,Y
X = 10
Y = SQUARE(X)
WRITE(*,*) Y
END
然后你就有了 SQUARE 函数。
FUNCTION SQUARE(N)
SQUARE = N * N
END
它们是单独编译的单元。您可以看到,编译 MAIN 时,它不知道“SQUARE”在哪里,它在什么地址。它需要知道,所以当它调用微处理器 JUMP SUBROUTINE (JSR) 指令时,该指令有可去处。
.o 文件已经有 JSR 指令,但它没有实际值。这在链接或加载阶段的后期出现(取决于您的应用程序)。
因此,MAINS .o 文件包含 main 的所有代码,以及它想要解析的引用列表(特别是 SQUARE)。SQUARE 基本上是独立的,它没有任何引用,但同时它还没有关于它在内存中的位置的地址。
链接器将删除所有 .o 文件并将它们组合成一个 exe。在过去,编译后的代码实际上就是一个内存映像。该程序将从某个地址开始并简单地批量加载到 RAM 中,然后执行。因此,在场景中,您可以看到链接器获取两个 .o 文件,将它们连接在一起(以获取 SQUARE 的实际地址),然后它会返回并在 MAIN 中找到 SQUARE 引用,并填写地址。
现代链接器并没有走那么远,并将大部分最终处理推迟到程序实际加载时。但是这个概念是相似的。
通过编译为 .o 文件,您最终会得到可重用的逻辑单元,然后在执行之前由链接和加载过程组合这些逻辑单元。
另一个不错的方面是 .o 文件可以来自不同的语言。只要调用机制是兼容的(即参数是如何传递给函数和过程的),那么一旦编译成.o,源语言就变得不那么相关了。例如,您可以将 C 代码与 FORTRAN 代码链接、组合。
在 PHP 等中,该过程是不同的,因为所有代码在运行时都加载到单个图像中。您可以考虑 FORTRANs .o 文件,类似于使用 PHPs 包含机制将文件组合成一个大的、有凝聚力的整体。