最近我在维护一个使用VC++ 6.0编写的遗留项目。该代码使用了许多这个编译器的独特特性,因此将其移植到更高版本的编译器中变得异常艰巨。
项目中有数千行代码,其中包括四个汇编文件。由于某种我不理解的原因,MASM615和TASM都无法编译它们(会出错),但是我有目标文件。然而,当我链接库时,我收到一条消息
警告 LNK4033:从OMF格式转换为COFF格式的对象
库按预期工作,但我一直在想这些二进制格式之间的区别,或者我是否应该从这种转换中期待某些问题。
最近我在维护一个使用VC++ 6.0编写的遗留项目。该代码使用了许多这个编译器的独特特性,因此将其移植到更高版本的编译器中变得异常艰巨。
项目中有数千行代码,其中包括四个汇编文件。由于某种我不理解的原因,MASM615和TASM都无法编译它们(会出错),但是我有目标文件。然而,当我链接库时,我收到一条消息
警告 LNK4033:从OMF格式转换为COFF格式的对象
库按预期工作,但我一直在想这些二进制格式之间的区别,或者我是否应该从这种转换中期待某些问题。
自个人电脑时代诞生以来,一直到微软的Win32编程工具问世前,几乎所有的个人电脑编译器都使用英特尔目标模块格式(OMF)标准生成目标文件。后来,英特尔推出了386处理器和32位保护模式,他们也扩展了OMF规范以支持32位,形成了“OMF-386”,并成为大多数个人电脑保护模式环境的标准。与此同时,最初的Windows NT开发团队不仅设计代码支持英特尔处理器,还要支持其他厂商的处理器。微软NT团队选择了更便携的对象模块格式,称为通用对象文件格式(COFF),该格式派生自UNIX System V的官方目标代码格式。COFF目标模块后来成为所有微软Win32开发工具的事实标准,并且由于其格式与Win32的本地可执行文件格式Portable Executable文件非常接近(使用COFF格式链接器创建32位EXE或DLL所需的工作量比使用OMF格式文件少得多),因此它具备优势。
就像有OMF格式和COFF格式的目标文件(.obj),还有OMF格式和COFF格式的库文件(.lib)。幸运的是,库基本上只是包含对象文件的集合,以及一些头文件信息,用于让链接器从库中确定要使用哪些对象文件。然而,为了增加难度,OMF和COFF都使用相同的文件名扩展名.obj和.lib来引用这两种不同类型的目标和库文件格式(因此您不能仅通过文件名扩展名判断目标模块或库文件是OMF还是COFF)。
混合使用来自不同编译器供应商的目标文件和库文件存在问题,因为一些供应商支持COFF,另一些供应商使用OMF,还有少数可以处理两者。例如,Borland仍然使用OMF目标文件和库文件,而Microsoft的32位编译器生成COFF格式文件。Watcom C/C++ v11.0在编译和链接Windows应用程序时似乎更喜欢使用COFF,但是为了与其DOS4GW 32位保护模式DOS扩展器一起使用,会生成OMF目标文件。此外,Microsoft MASM 6.13默认生成OMF文件,但可以通过/coff开关发出COFF目标文件。