该文档主要翻译苹果关于Mach-o编程,可以查看Mach-O programming查看英文版本
介绍
构建Mach-o文件
创建程序时,开发者需要将源代码转为目标文件,这些目标文件被包裹成可执行代码或则静态库,OSX将源代码转为可运行的程序或则静态库提供给更多的应用程序调用。
这篇文章主要描述Mac应用程序构建和讨论,更深一步,你可以构建应用程序的类别。它描述了工具所包含的Mach-O文件的构建过程,解释你所构建的Mach-O的文件类型及探讨的模块,它是在OSX运行环境独立可连接小单元和数据。它同样描述静态的archive库,它是一些集合模块的文件
工具-构建和运行Mach-O文件
在运行时完美的运行和构建程序,内核使用动态连接器(专指位于/usr/lib/dyld下的动态共享库)。内核加载程序并且动态链接器导入进新的进程空间并执行他们。
思考这篇文档,将会抽象的讨论一下工具
- 编译器是可以将高级语言写的源代码转化为包含机器二进制代码和数据的中间对象文件的工具,除非特殊指明,本书将机器语言汇编器作为编译器
- 静态连接器将连接中间对象文件为最终可执行文件(查看The Products-Types of Match-O Files You Can Build)
Xcode的CD工具包含各种终端工具(本文件系统成为标准工具)构建、分析你的应用程序,包含编译器和id,标准静态分析器。无论你使用Xcode应用程序,标准命令行工具或则第三方工具去开发医用程序,理解这些工具的能够提高你对Mach-O架构的理解和方便与其他OSX开发人员沟通相关主题。标准工具包含以下:
- 编译驱动程序,
/usr/bin/gcc
包含所支持的编译、组装、连接C、C++和Objective-C所写的源代码模块。编译启动程序调用各种其它工具实现真实编译、组装、静态连接功能。没门语言的真实编译器工具被编译驱动程序所隐藏而无法查看;他们的作用是将源代码转化为汇编语言输入到汇编器。 - C++编译驱动程序,
/usr/bin/c++
和/usr/bin/cc
类似,但是确实自动将C++运行函数连接到输出文件(从而支持异常,运行类型信息和其他高级语言特性)。 - 汇编器,
usr/bin/as
从汇编语言创建中间对象文件。编译驱动程序使用它调用真实的编译器去组合汇编语言 - 静态分型器,
/usr/bin/ld
被编译驱动程序使用(作为独立的工具)连接成Mach-O可执行文件。你可以使用静态分析器连接程序成静态或则动态。静态绑定是所有的系统和自身文件,他们不能框架和共享库,除系统库。在OSX,核心扩展是静态的,其他所有程序都是动态绑定,甚至是传统的UNIX和BSD命令行工具。所有外层应用调用的OSX核心都被当成共享库,并且只有动态绑定的程序可以进入共享库 - 库生成工具,
/usr/bin/libtool
即可以创建静态归档库也可以创建动态共享库,它依赖于外层所提供的参数。libtool
取代了一个称为ranlib
的旧工具,它联合ar
工具生成静态库。当创建共享库时,libtool被静态连接器(ld)调用。
注意:同样GNU也有名字为libtool 工具,它允许合适的源代码去构建各种UNIX系统库。不要和OSXlibtool 工具所混淆,当完成相同的目标时,他们并无关联且不能接受相同的参数 |
---|
分析Mach-O文件的工具:
-
usr/bin/lipo
工具允许你创建和分析包含多种构架的图像二进制文件。一个是通用二进制的例子。通用二进制能够别用于PowerPC-based和Intel-based的mac电脑。另一个是PPC/PPC64二进制,他可以在32位PowerPC-based和64位PowerPC-based的mac电脑。 - 文件类型分析工具,
usr/bin/file
能够展示文件类型。对于多架构文件。它能显示你所归档的图像 - 对象文件展示工具,
usr/bin/otool
列举了一个Mach-O文件的具体节和段。它包含所支持的架构的文件符号地址并且可以知道如何格式化需用通用节类型 - 章节分析工具,
usr/bin/pagestuff
显示了组成图像的每个逻辑段信息,包含在每个段中的节名称和符号,该工具不能使用在多架构的图像 - 符号表展示工具,
usr/bin/nm
允许你去展示一个目标文件符号表的内容
产品-你构建Mach-O文件类型
在OSX,一个典型的应用程序执行内部许多类型的文件。主要的可执行文件包含程序的核心逻辑,包含入口函数main
函数。程序的主要功能通常在朱可执行文件的代码实现。查看Excuting Mach-O Files详细内容。在可执行文件还包含其他的文件:
Intermediate object files,这些文件并不是最终的产品,他们是打对象文件的基本构建块。通常,编译器为每个来至于源代码文件的代码和数据生成输出的中间对象文件。你可以使用静态分析工具将目标文件连接成动态连接器集成到开发环境中(通常Xcode隐藏了该层的详细)
Dynamic shared libraries,这些文件包含可重复执行的代码块,你的应用程序通常在启动时动态引用由动态连接器加载的动态共享库。共享库通常存储在大量的代码可以被许多程序所使用。查看Loading Code at Runtime下的Using Shared Libraries and Frameworks更多信息
Frameworks,这些目录包含共享库和相关的资源,如图像文件,开发文档和编程接口,Loading Code at Runtime下的Using Shared Libraries and Frameworks更多信息
Umbrella frameworks,这些特殊类型的框架包含很多单个子框架。例如,Cocoa散框架包含Application Kit(使用界面类)的框架和Foundation(无界面相关类)的框架,查看Using Shared Libraries and Frameworks更多信息
Static archive libraries,这些文件包含在程序编译阶段添加到应用程序的可重复代码块。静态归档文件一般包含许多小代码仅仅在部分应用程序重复利用或则因默写原因不同于共享库的代码,查看Static Archive Libraries更多信息
-
Bundles,这些可执行文件是在运行时通过动态链接函数导入到你的应用程序中。Bundles实现即插功能,如文件格式导入器。在OSX中这些软件包有以下相关含义:
- 包含可执行代码的实际的对象文件
- 包含对象文件和相关的资源的目录,例如,在OSX被包裹成软件包的应用程序。因为这些软件包在多单个文件在Finder展示而不是个目录,应用程序软件包也被称为应用程序包。一个软件包并不包含目标文件。查看Bundle Programing Guide更多消息
Kernel extensions are statically bound Mach-O files,与bundle一样包裹。核心扩展被加载到核心地址空间并且与Mach-O文件类型不同的构建方式;核心运行环境和用户的运行环境不同,因此本文并不包含
在OSX中,所有的对象文件除了系统扩展意外必须是动态绑定————即使用动态引用去共享库
默认静态连接器搜寻库和unberra库在/System/Library/Frameworks
并且共享库及静态库在/usr/lib
。Bundles通常位于应用程序包的Resources
目录下。然而,你可以在连接期指定一个不同的目录
Modules——最小的代码单元
在高级层面上,你可以将OSX共享库称为模块的集合。一个模块是最小的机器代码和数据的单元,它能独立连接到其它的代码单元中。通常一个模块是一个通过编译单个C原文建的对象文件。例如,将源文件main.c
,thing.c
和foo.c
,编译器可以产生对应的main.o
,thing.o
和foo.o
目标对象。每个输出对象文件是一个模块。当静态连接器将这个文件连接成为一个动态共享库,这些每个输出对象组成一个module。当静态连接库将这个文件打包成个动态链接库,这些每个对象独立的代码和数据单元。当连接应用程序和包时,静态编译器长此昂将这些对象文件连接成一个模块
静态连接器也可以将多个多个输入块改为单个模块。当构建大多数动态共享库时,通常在创建最终共享库之前执行此操作,因为模块之间的函数调用会带有少量的系统开销,使用ld
,你可以使用此命令执行改优化
ld -r -o thing.o thing1.o thing2.o
static Archive Libraries
建立一组模块集合,你可以使用青静态归档库,它是一个拥有内容入口的归档文件表。该格式可以使用ar
命令。你可以使用libtool
命令构建静态的归档库,并且你可以使用ar
名利去库里的各个模块
除了Mach-O文件
除了Mach-O文件,静态连接器和其他的开发工具接受静态归档库作为输入。你可以使用静态归档库区支配一系列你不想要包含在动态库中却希望能多次操作的模块。
虽然ar
归档可以包含任何文件,一个典型的例子是将多个对象文件组成一个内容标的形式,形成静态归档库。静态链接库能够连接对象文件存储在静态归档库变为一个Mach-O的可执行或动态库。注意在归档被用作静态归档库之前你必须使用libtool
命令去创建静态库内容表。
采用标准同居,你可以在libtool
命令里传入-static
选项去创建一个静态归档库。下面的例子显示创建一个名为libthing.a
的静态归档库通过使用一些了的中间对象文件,thing1.o
和thing2.o
libtool -static thing1.o thing2.o -o libthing.a
注意到你也可以传入-static
或则dynamic
,libtool
默认使用-static
运行Mach-O文件
为了运行这些对象,程序必须先启动进程且连接到动态库,为了调用其他库和模块,你的应用程序必须有这些模块的符号表引用;这个引用都是在运行时解决的。你应用程序在运行时所使用的模块的符号表加载到共享空间,类似于目录。为了提高他们将来使用的应用程序和库,应用程序和库的开发者必须确保他们为函数和数据所选择的名字不能够和其他模块的名字冲突。
在OSX10.1的二级域名下,且然后将模块名作为符号表的表名的一部分。这种方法能够确保模块的不好名不会和使用其他模块的符号名相互冲突。为了特有任务或提供一致用户体验,你的应用程序需要运行命令行工具去启动其他应用程序或则创建进程。为了保存高集成和提供一致的用户体验,应用程序需要使用特有的系统函数和框架去执行进程和启动应用程序。
本文提供OSX动态加载进程的描述,在OSX中加载进程和连接程序主要包含两个实体:OSX核心和动态链接库。当你执行启动一个项目,内核为项目创建进程,且加载项目和动态连接共享库,通常/usr/lib/dyld
在程序的地址空间。内核执行在动态链接库里执行代码并且导入程序库的引用。本文描述了