2010-01-23 91 views

回答

18

否。一般来说,目标文件格式可能是相同的,例如, 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的系统制作程序。我这样做here

16

是否有可能编译在一个平台上,并链接与其他计划?

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

什么是目标文件包含哪些内容?

符号表,代码,搬迁,链接和调试信息。

如果你是后是便携性,那么编写可移植的C/C++,让特定于平台的兼容性的编译器做的工作。

+4

我不认为我竟然说交叉编译是危险的。很少iPhone应用程序直接在iPhone上编译。或Wii应用程序。 ;-) – 2010-01-23 15:13:53

+0

@Richard,是的,但是您使用不同的编译“模式”来编译OS X应用程序的Iphone应用程序。它正在被编译在不同的平台上,但它的具体目的是为了做到这一点。 :D – 2010-01-23 15:52:20

+4

@CrazyJugglerDrummer:我的确切点。交叉编译是一件非常常见而且安全的事情。 – 2010-01-23 15:58:51

3

它们依赖于平台。例如文件命令输出如下:

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

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

查找ABI了解更多信息。

4

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

另一方面,ANSI C是最便携的语言之一。你可能无法拿起你的目标文件,但如果你坚持ANSI C标准,重新编译源代码很可能会起作用。 C++也是如此。

我不知道GNU C++如何万能是的,但如果你可以用一台计算机上的gcc编译,你是好去任何其他机器也已安装GCC上。几乎所有你能想到的机器都有一个C编译器。 这就是的便携性。

+1

Java更好! :p – abc 2010-01-23 14:49:19

+5

正确...编译一次,在任何地方运行......慢慢地;-) – 2010-01-23 15:00:25

+2

几乎所有你能想到的机器都有一个Java VM? Nah ... – Frunsi 2010-01-23 15:55:47

4

不。他们不是平台独立的。以GNU C编译器(gcc)为例,它生成ELF二进制文件。 Windows编译器(Borland,Microsoft,Open Watcom)可以生成Windows Binary PE(可移植可执行文件)格式。 Novell二进制文件是NLM(Netware Loadabable模块)格式。

上面这些依赖于编译器的不同输出的例子,Windows平台上的链接器无法知道ELF格式和NLM格式的任何内容,因此不可能将不同的格式组合起来以生成可执行文件可以在任何平台上运行。

拿苹果的Mac OSX(在Intel芯片投入使用之前),他们在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. 

现在比较,给PE格式简单的DLL

 
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,并且是一个ELF格式为i386处理器。

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

2

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

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

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

+0

MSVC++ 6与MSVC++ 7并不真正兼容;不在ABI水平,也不在名义上。后者可防止事故发生。 – MSalters 2010-01-25 13:36:44

2

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

但是,即使在C语言中,编译器也会对某些库函数(如我所知)存在的某些库函数做出一些假设,而这些函数在两个平台上都不必相同。在生成这种代码的情况下,这些对象不会直接兼容。

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

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

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手册。但到目前为止,这种方法对我来说效果很好。