对象文件平台是否独立?

是否可以在一个平台上编译程序并与其他平台链接? 对象文件包含什么? 我们可以将可执行文件脱钩以生成目标文件吗?

不可以。一般来说,目标文件格式可能相同,例如ELF,但目标文件的内容因系统而异。

目标文件包含以下内容:

Object code that implements the desired functionality A symbol table that can be used to resolve references Relocation information to allow the linker to locate the object code in memory Debugging information 

目标代码通常不仅是处理器特定的,而且例如,如果它包含系统调用,则还特定于OS。


编辑:

 Is it possible to compile program on one platform and link with other ? 

绝对。 如果您使用交叉编译器。 此编译器专门针对平台并生成与目标平台兼容的目标文件(和程序)。 因此,您可以使用X86 Linux系统,例如,使用适当的交叉编译器为powerpc或基于ARM的系统创建程序。 我在这里做。

是否可以在一个平台上编译程序并与其他平台链接?

一般来说,没有。 目标文件是编译器特定的。 一些编译器吐出COFF ,其他编译器吐出ELF等。最重要的是,你必须担心调用约定,系统调用等。这是依赖于平台的。

对象文件包含什么?

符号表,代码,重定位,链接和调试信息。

如果您追求的是可移植性,那么编写可移植的C / C ++并让特定于平台的兼容编译器完成工作。

在实践中,没有。 有几件事必须是相同的: – OS接口(相同的系统调用) – 数据的内存布局(字节序,结构填充等) – 调用约定 – 目标文件格式(例如ELF在Linux上非常标准)

查找ABI以获取更多信息。

它不需要再说:C / C ++目标文件不可移植。

另一方面,ANSI C是最便携的语言之一。 您可能无法获取目标文件,但如果您坚持使用ANSI C标准,则重新编译源代码可能会起作用。 这也可能适用于C ++。

我不知道GNU C ++是如何通用的,但是如果你可以在一台计算机上使用gcc进行编译,那么你可以选择安装了gcc的任何其他机器。 几乎每台你能想到的机器都有一个C编译器。 那是便携性。

不,他们不是平台独立的。 例如,生成ELF二进制文件的GNU C编译器(gcc)。 Windows编译器(Borland,Microsoft,Open Watcom)可以生成Windows二进制PE(Portable Executable)格式。 Novell二进制文件是NLM(Netware Loadabable Module)格式。

以上这些与编译器相关的不同输出的例子,没有办法,Windows平台上的链接器,不会知道有关ELF格式或NLM格式的任何内容,因此不可能组合不同的格式来生成可以运行的可执行文件任何平台。

以Apple的Mac OSX为例(在推出英特尔芯片之前),他们在PowerPC平台上运行,即使它有GNU C编译器,二进制文件专门针对PowerPC平台,如果您要采用该二进制文件并进行复制它在Linux平台上,由于平台微处理器即PowerPC的指令不同而无法运行。

同样,同样的原则也适用于OS / 390大型机系统,为该平台生成二进制文件的GNU C编译器不能在英特尔Apple Mac OSX上运行。

编辑:为了进一步阐明ELF格式的外观如下所示,这是通过在Linux下运行objdump -s main.o获得的。

 main.o:文件格式为elf32-i386

 section。的内容.text:
  0000 8d4c2404 83e4f0ff 71fc5589 e55183ec .L $ ..... qU.Q ..
  0010 14894df4 a1000000 00a30000 0000a100 ..M .............
  0020 000000a3 00000000 8b45f483 38010f8e ......... E..8 ......
  0030 9c000000 8b55f48b 420483c0 048b0083 ..... U..B .......
  0040 ec086800 00000050 e8fcffff ff83c410 ..h .... P ........
  0050 a3000000 00a10000 000085c0 7520a100 ............ u ..
  0060 00000050 6a1f6a01 68040000 00e8fcff ... Pj.jh ......
  0070 ffff83c4 10c745f8 01000000 eb5a8b45 ...... E ...... ZE
  0080 f4833802 7e218b55 f48b4204 83c0088b ..8.~!.U..B .....
  0090 0083ec08 68240000 0050e8fc ffffff83 .... h $ ... P ......
  00a0 c410a300 000000a1 00000000 85c07520 .............. u
  00b0 a1000000 00506a20 6a016828 000000e8 ..... Pj jh(....
  00c0 fcffffff 83c410c7 45f80100 0000eb08 ........ E .......
  00d0 e8fcffff ff8945f8 8b45f88b 4dfcc98d ...... E..E..M ......
  00e0 61fcc3 a ..
部分内容.rodata:
  0000 72000000 4552524f 52202d20 63616e6e r ...错误 - 大麻
  0010 6f74206f 70656e20 696e7075 74206669 ot open input fi
  0020 6c650a00 77000000 4552524f 52202d20 le..w ...错误 - 
  0030 63616e6e 6f74206f 70656e20 6f757470无法打开输出
  0040 75742066 696c650a 00文件..
部分内容.comment:
  0000 00474343 3a202847 4e552920 342e322e .GCC:(GNU)4.2。
  0010 3400 4。

现在将其与简单DLL的PE格式进行比较

 C:\ Program Files \ Microsoft Visual Studio 9.0 \ VC \ bin> dumpbin / summary“C:\ Documents and Settings \ Tom \ My Documents \ Visual Studio 2008 \ Projects \ SimpleLib \ Release \ SimpleLib.dll”
 Microsoft(R)COFF / PE Dumper版本9.00.30729.01
版权所有(C)Microsoft Corporation。 版权所有。


转储文件C:\ Documents and Settings \ Tom \ My Documents \ Visual Studio 2008 \ Projects \ SimpleLib \ Release \ SimpleLib.dll

文件类型:DLL

  摘要

         1000。数据
         1000 .rdata
         1000 .reloc
         1000 .rsrc
         1000 .text

注意ELF下各部分的差异,有.bss.text.rodata.comment ,是i386处理器的ELF格式。

希望这会有所帮助,最好的问候,汤姆。

它们取决于平台。 例如,file-command打印出来:

 $ file foo.o foo.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped 

C ++有一个额外的细节,它放在一个目标文件中的名称通常被“修改”,以便为重载的名称处理类型安全。 用于破坏名称的方法不是C ++标准的一部分(实际上,名称修改是一个实现细节,如果供应商可以提出不同的方法来实现重载,则根本不需要)。 因此,即使对于相同的平台目标,您也不能指望能够将目标文件从一个编译器供应商链接到另一个编译器供应商。

有时编译器供应商可能会将名称修改方案从一个编译器版本更改为另一个编译器版本。 例如,我相信有些版本的MSVC无法将C ++目标文件从旧版本可靠地链接到较新版本。

某些平台在平台的ABI标准中指定了名称mangling(例如ARM,它使用最初为Itanium上的SVr4开发的通用C ++ ABI中指定的名称修改),但其他平台没有(Windows)。 即使对于ARM,我也不确定ABI标准如何互相连接,以便链接由不同编译器创建的C ++目标文件。

我只想说,只要它们使用相同的处理器体系结构和对象格式,以及调用约定(通常现在,处理器制造商创建一个),对象文件有很多机会可以互换。

然而,即使在C语言中,编译器也会对某些库函数做出一些假设,例如堆栈保护(我知道)存在,这两个平台上的函数不一定相同。 在生成此类代码的情况下,对象将不会直接兼容。

只要系统共享它们,系统调用就不是真正相关的,因为通常它们是通过标准库中的C包装器调用的。

最后,这仅适用于C和非常类似的操作系统,如Linux和BSD,但它可能会发生。

可以使用GCC进行编译并以ELF文件格式创建目标文件,并将目标文件转换为在Visual Studio中工作。 我现在多次这样做了。

要执行此操作,您需要了解三件事: 函数调用约定,目标文件格式和函数名称修改。

函数调用约定:对于32位模式,函数调用约定很简单:对于Windows和Unix,它们是相同的。 对于64位模式,Windows和Unix使用不同的调用约定。 因此,在64位模式下,您必须使调用约定正确。 您可以在编译时执行此操作,也可以从目标文件本身执行此操作。 编译时,这样做要容易得多。 要让GCC使用Windows调用约定,请使用-mabi=ms 。 要从目标文件执行此操作,您需要一个工具。 Agner Fog的objconv工具可以为某些function执行此操作。

异议文件格式:要转换目标文件格式,您需要一个工具。 我使用Agner Fog的objconv工具。 它可以转换为几种不同的目标文件格式。 例如,要将ELF64转换为COFF64(PE32 +),请执行objconv -fcoff64 foo.o foo.obj

函数名称错误:由于C ++编译器中的函数重载,会破坏函数名称。 每个编译器的详细信息可以在Agner Fog的手动呼叫对话中找到 。 GCC和Visual Studio mangle函数名称不同。 要解决此问题,请使用extern "C"继续执行函数定义

如果您将所有这三个都正确并且您没有进行任何特定于操作系统的调用,那么您可以成功地在编译器之间使用目标文件。 当然还有其他问题可能发生。 有关详细信息,请参阅objconv中的手册。 但到目前为止,这种方法对我来说效果很好。