构建Mach-O文件

构建和运行Mach-O文件的工具

为了在运行时展示实际加载和绑定程序的工作,内核会使用动态链接器(一个路径在/usr/lib/dylib被标记为dynamic shared library的工具)。内核会在新的线程中加载程序和动态链接器并且运行他们。
通过这些文件,下面的工具会被抽象地介绍:

  1. 编译器是一个把高级语言源代码转换成中间对象文件的工具,中间对象文件中包含了机器二进制代码和数据。没有特别情况的话,这边文章会默认把编译器默认当成是机器语言的assembler(把汇编语言转化成机器语言)。
  2. 静态链接器是一个把中间对象文件组合成最终产品程序的工具。

Xcode工具包含了几个命令行工具用作于构建和分析你的应用程序,其中包括编译器和ld(静态链接器)。当你使用xcode时,这些标准的命令行工具或者一些第三方的工具被设置成xcode开发过程中的底层实现。以下列出标准的工具:

  1. compiler driver,/usr/bin/gcc,它支持的功能有编译、汇编和把c、c++,oc源代码模块链接在一起。编译器驱动调用了其他一些能够实际实现编译、汇编和静态链接功能的工具。实际工作的这些工具的实现细节被编译器驱动隐藏起来,他们的作用是把输入的高级语言源代码转化成汇编语言,然后这些汇编语言是作为assembler的输入。
  2. c++的编译器驱动,/usr/bin/c++,功能像gcc,但是会自动链接c++的运行时功能到输出文件中(这样做是为了支持exceptions,运行时类型的消息和其它先进的语言特性)
  3. assembler,/usr/bin/as,从汇编语言代码中创建中间对象文件,它最开始是被用于compiler driver中,编译驱动会把实际编译器产生的汇编语言源代码输出到assembler中。
  4. 静态连接器,/usr/bin/ld,作为一个独立的工具被编译器驱动使用作于整合Mach-O的可执行文件(在生成.o中间对象文件后使用)。你能够使用静态连接器去静态地或动态地去绑定程序。静态绑定程序完全是系统自身的事情,他们除了能调用系统框架和分享库外之外不能调用别的东西。在OS X中,内核扩展时被静态地绑定的,但是其它所有的程序类型是被动态绑定的,甚至是传统的UNIX和BSD的命令行工具也是动态绑定。所有在内核外通过程序对OS X内核的调用都是通过shared libraries的,而且只有动态绑定的程序能够访问shared libraries。(为什么静态链接器能够动态地去绑定程序,需要弄清这个概念)
    6.library creation tool,/usr/bin/libtool,可以依赖参数创建静态压缩库(.a)和动态分享库(dynamic shared libraries, .dylib),libtool取代了一个老的工具ranlib。当构建shared libraries时,libtool调用了静态链接器ld。

分析Mach-O文件的分析工具有以下几个:

  1. /user/bin/lipo lipo命令允许你创建和分析包含多个架构映射的二进制文件。其中一个二进制文件的例子是universal binary.Universal binaries能够被基于PowePC的基于Intel的苹果电脑使用。
  2. /user/bin/file 显示文件的类型,对于多个架构的文件,它显示组成archive的每种反应的类型。
  3. 对象文件展示工具,/usr/bin/otool,展示Mach-O文件里的每个特定sections和segments的内容,它包含每个支持架构的符号反编译器(symbolic disassemblers),并且它知道如何格式化大多数通用section类型的内容。
  4. page分析工具,/usr/bin/pagestuff,展示每一个组成反射(image)的每个逻辑页面的内容,其中包含了sections的名字和每个page里的符号。这个工具不能在有多个架构的包含映射的二进制文件中运行。
  5. symbol table的展示工具,/usr/bin/nm,允许你查看对象文件符号表的内容。
  6. dwarfdump 用于调试时使用,导出DWARF的测试信息,如uuid或反编译测试数据
  7. atos 也是调试时使用,转换数字化的地址信息到进程或二进制映射中的symbols
  8. size 输出任意一个对象文件的任意section的大小

你能够构建Mach-O文件的类型

在OS X中,一个典型的应用程序的可执行代码时源自于多个类型的文件。主要的可执行文件通常包含了程序的核心逻辑,如main函数的入口。程序的主要功能通常被主要执行文件的代码实现。,而其它的包含可执行代码的文件有:

  1. 中间对象文件,这些文件不是最终产品,他们是更大的对象文件的基本构建快,编译器会从每一个输入高级源代码文件中产生输出的代码和数据到中间对象文件中,你能够使用静态链接器去整合对象文件到动态链接器。
  2. dynamic shared libraries.这些文件包含能在应用程序中动态引用的可重用执行代码模块,并且他们会在程序启动时时被动态链接器动态加载,shared libraries通常被用作能被多个应用程序使用的大量代码。 See Using Shared Libraries and Frameworks in Loading Code at Runtime
  3. Frameworks,这些目录包含了shared libraries和有关的资源,如图片文件,开发文档和程序接口等。See Using Shared Libraries and Frameworks in Loading Code at Runtime
  4. Unbrella frameworks。这些事frameworks的的特殊类型,它们含有一个或多个sub framework。例如,Cocoa umbrella framework包含了Application Kit framework和Foundation framework. See Using Shared Libraries and Frameworks in Loading Code at Runtime.
  5. static archive libraries(静态归档库),这些文件包含了静态链接器在构建期间能加入到应用程序的可重用代码模块。静态归档库通常含有只会被少量应用程序使用的非常少量的代码,或者由于某些原因很难在shared libraries中被维护的代码。See Static Archive Libraries。
  6. Bundles。这些是程序在运行时使用动态链接功能加载的执行文件,Bundle实现了插件功能,如文字处理器的文件格式输入,bundle这个术语在OS X中有两个相关的意思:一是含有执行代码的实际对象文件。而是含有对象文件和相关资源的目录。See Loading Plug-in Code With Bundles in Loading Code at Runtime for more information
  7. 内核扩展被静态绑定到了Mach-O文件,它们类似于bundles被打包封装。内核扩展被加载到了内核的地址空间,而且因此比其它的Mach-O文件类型更难构建。

Modules—The Smallest Unit of Code

在最高等级,你能够把OS X的shared library 当成是一群module的集合,一个module是机器代码和数据的最少单元,它能够独立地链接其它单元的代码。通常来说,一个module时一个产生自单个C源代码文件的对象文件。例如,特定的源代码main.c,thing.c和foo.c,编译器可能产生对象文件main.o,thing.o和foo.o。每个这些输出对象文件都是单个module。当静态链接器被用于整合所有的三个对象文件到dynamic shared library时,每个对象文件被作为一个独立单元的代码和数据引用。当链接程序和bundles时,静态链接器通常联合所有的对象文件到一个module中。
静态链接器同样能够减少数个输入modules到单个module中,当构建大多数dynamic shared libraries时,在创建最终share library之前通常是一个好的方法(把多个modules输出到单个module中),因为在多个modules间调用函数会产生少量的额外开销。使用ld,你能够通过下面命令行优化这些性能:
ld -r -o things.o thing1.o thing2.o thing3.o
使用Xcode的话会自动进行这些优化。

Static Archive Libraries

为了聚集模块,你可以使用static archive library,这个是一个拥有内容入口的表的归档文件。格式是使用了ar命令,你可以使用libtool命令去构建一个静态归档库,而且你可以使用ar命令去操作库里的单独模块。
除了Mach-O文件外,静态链接器和其他开发工具都接受静态归档库作为输入。你可以使用静态归档库去打包一些你不想在shared library里包含但是又想在多个程序中重复使用的modules。
虽然一个ar arvhive能包含任意类型的文件,但经典的原因是以一张内容表把多个对象文件聚合在一起,从而形成一个静态归档库。静态链接器能够把保存在静态归档库中的对象文件链接到Mach-O的执行文件和动态库中。注意你必须在static archive library被使用之前使用libtool命令去创建静态库的内容表,如下:
你可以通过libtool命令的static参数去创建一个静态归档库,如下面的命令从中间对象文件thing1.o和thing2.o创建一个名为libting.a静态归档库:
libtool -static thing1.o thing2.o -o libthing.a
注意如果你不传-static或者-dynamic作为参数,libtool默认是-static参数。