目标文件平台是否独立?

时间:2010-01-23 14:34:04

标签: c++ c operating-system

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

9 个答案:

答案 0 :(得分:22)

没有。通常,目标文件格式可能相同,例如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

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

<小时/> 编辑:

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

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

答案 1 :(得分:17)

  

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

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

  

目标文件包含什么?

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

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

答案 2 :(得分:5)

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

查询ABI以获取更多信息。

答案 3 :(得分:4)

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

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

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

答案 4 :(得分:4)

没有。它们不是平台独立的。例如,生成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:     file format elf32-i386

Contents of section .text:
 0000 8d4c2404 83e4f0ff 71fc5589 e55183ec  .L$.....q.U..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.j.h.......
 0070 ffff83c4 10c745f8 01000000 eb5a8b45  ......E......Z.E
 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 j.h(....
 00c0 fcffffff 83c410c7 45f80100 0000eb08  ........E.......
 00d0 e8fcffff ff8945f8 8b45f88b 4dfcc98d  ......E..E..M...
 00e0 61fcc3                               a..
Contents of section .rodata:
 0000 72000000 4552524f 52202d20 63616e6e  r...ERROR - cann
 0010 6f74206f 70656e20 696e7075 74206669  ot open input fi
 0020 6c650a00 77000000 4552524f 52202d20  le..w...ERROR -
 0030 63616e6e 6f74206f 70656e20 6f757470  cannot open outp
 0040 75742066 696c650a 00                 ut file..
Contents of section .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 Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Documents and Settings\Tom\My Documents\Visual Studio 2008\Projects\SimpleLib\Release\SimpleLib.dll

File Type: DLL

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text

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

希望这有帮助, 最好的祝福, 汤姆。

答案 5 :(得分:3)

它们与平台有关。例如,file-command打印出以下内容:

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

答案 6 :(得分:2)

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

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

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

答案 7 :(得分:2)

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

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

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

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

答案 8 :(得分:1)

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

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

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

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

函数名称错误:由于C ++编译器中的函数重载,会破坏函数名称。每个编译器的详细信息可以在Agner Fog的手册calling convetions中找到。 GCC和Visual Studio mangle函数名称不同。要解决此问题,请使用extern "C"

继续执行功能定义

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