前几篇文章我们探讨了静态链接
、动态链接
、静态库
、动态库
等,这里我们再来回顾一下我们用到的一些编译命令。
生成目标文件:
目标文件包含了机器指令代码、数据、链接时需要的信息,符号表、调试信息,字符串表。
- 1、不指定
target
,默认是Mach-O 64-bit object x86_64
:
clang -x c -g -c a.c -o a.o
指令 | 注释 |
---|---|
-x |
指定编译文件语言类型 |
-g |
生成调试信息 |
-c |
生成目标文件,只运行preprocess , compile , assemble ,不链接 |
-o |
输出文件 |
-I |
在指定目录中寻找头文件 |
-L |
指定库文件路径(.a/.dylib 库文件) |
-l |
指定链接的库文件名称(.a/.dylib 库文件) |
-F |
在指定目录寻找framework 文件 |
-framework |
在指定链接的framework 名称,生成相应的LLVM 文件格式,来进行链接时间优化。当我们配合-S 使用是,生成汇编语言文件。否则生成bitcode 格式的目标文件 |
-flto= |
设置LTO的模式:full or thin |
-flto |
设置LTO的模式:full |
-flto=full |
默认值,单片(monolithic)LTO通过将所有初入合并到单个模块中来实现此目的 |
-flto=thin |
使用ThinLTO代替-emit-llvm |
-install_name |
指定动态库初次安装时的默认路径,向LC_ID_DYLIB 添加安装路径,该路径作为dyld 定位该库。 |
clang -o
是将.c
源文件编译生吃一个可执行的二进制代码(-o
选项其实是指定输出文件的文件名;如果不加-c
选项,clang
默认会编译链接生成可执行文件,文件名称由-o
选项指定)。
clang -c
是使用LLVM
汇编器将源文件转化为目标文件。
- 2、指定生成
Mach-O 64-bit x86-64
目标文件格式:
clang -x c -target x86_64-apple-macos10.15 -g -c a.c -o a.o
- 3、如果指定
target
不带Apple
系统版本(包括macOS
,ipadOS
,iOS
, 真机和模拟器);例如x86_64
,那么生成的目标问价是Linux
的ELF 64-bit
:
clang -x c -target x86_64 -g -c a.c -o a.o
- 4、编译
.m
clang -x objective-c -target x86_64-apple-macos10.15 -fobjc-arc -fmodules -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -c test.m -o test.o
clang -x c -g -target arm64-apple-ios13.5 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk -c a.c -o a.o
- 5、编译
.mm
在Mac
上编译:
clang -x objective-c++ -target x86_64-apple-macos10.15 -std=c++11 -stdlib=libc++ -fobjc-arc -fmodules -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -c te st.mm -o test.o
在模拟器上编译:
clang -x objective-c -target x86_64-apple-ios13.5-simulator -fobjc-arc -fmodules -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.6.sdk -c test.m -o test.o
在模拟器上链接其他三方库:
clang -x objective-c -target x86_64-apple-ios13.5-simulator -fobjc-arc -fmodules -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.6.sdk -I/Users/ws/Desktop/课程/Library/代码库/AFNetworking.framework/Headers -F/Users/ws/Desktop/课程/Library/代码库 -c test.m -o test.o
clang -target x86_64-apple-ios13.5-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/i PhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.6.sdk -F/Users/ws/Desktop/课程/Library/代码库 -fobjc- arc -framework AFNetworking -v test.o -o test
clang -target x86_64-apple-ios13.5-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/i PhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.6.sdk -L/Users/ws/Desktop/课程/Library/代码库 -fobjc- arc -lAFNetworking -dead-strip test.o -o test
编译成arm64
真机:
clang -target arm64-apple-ios13.5 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk -L/Users/ws/Desktop/课程/Library/代码库 -fobjc-arc -lAFNetworking test.o -o test
clang -target arm64-apple-ios13.5 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.pla tform/Developer/SDKs/iPhoneOS13.6.sdk -F/Users/ws/Desktop/课程/Library/代码库 -fobjc-arc -framework AFNetworking test.o -o test
生成dSYM
文件:
clang -x c -g1 a.c -o a.o
-g1: 将调试信息写入`DWARF`格式文件
查看调试信息
swarfdump
取出并验证DWARF
格式调试信息:
dwarfdump a.o
dwarfdump a.dSYM
dwarfdump --lookup 0x100000f20 --arch=x86_64 a.dSYM
--lookup 查看地址的调试信息。将显示出所在目录,文件,函数等信息。
查看文件内容
otool
用来查看Mach-O
文件内部结构:
otool -l liba.dylib
otool -h libTest.a
-l : 显示解析后的 mach header 和 load command
-h : 显示未解析的 mach header
-L : 打印所有链接的动态库路径
-D : 打印当前动态库的`install_name`
objdump
用来查看文件内部结构,包括ELF
和 Mach-O
:
objdump --macho -h a.o
objdump --macho -x a.o
objdump --macho -s -d a.o
objdump --macho --syms a.o
--macho : 指定 Mach-O 类型
-h : 打印各个段的基本信息
-x : 打印各个段更详细的信息
-d : 将所有包含指定的段反汇编
-s: 将所有段的内容以16进制的方式打印出来
--lazy-bind : 打印 lazy binding info
--syms 打印符号表
静态库的压缩和解压缩
ar
压缩目标文件,并对其进行编号和索引,形成静态库。同时也可以解压缩静态库,查看有哪些目标文件:
ar -rc a.a a.o
-r : 添加 或 替换文件
-c : 不输出任何信息
-t : 列出包含的目标文件
创建静态库
创建库命令:libtool
。可以创建静态库和动态库:
libtool -static -arch_only x86_64 a.o -o a.a
libtool -static -arch_only arm64 -D syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk test.o -o libTest.a
创建动态库
clang -dynamiclib -target arm64-apple-ios13.5 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.6.sdk a.o -o a.dylib
查看符号表
nm
命令:
nm -pa a.o
-a : 显示符号表的所有内容
-g : 显示全局符号
-p : 不排序。显示符号表本来的顺序
-r : 逆转顺序
-u : 显示未定义符号
生成dSYM文件
dsymutil
可以被理解为是调试信息链接器。它按照上面的步骤执行:
- 读取
debug map
- 从
.o
文件中加载DWARF
- 重新定位所有地址
- 最后将全部的
DWARF
打包成dSYM Bundle
有了dSYM
后,我们就拥有了最标准的DWARF
的文件,任何可以dwarf
读取的工具(可以处理Mach-O
二进制文件)都可以处理该标准DWARF
。
dsymutil
操作 DWARF
格式的 debug symbol
。可以将可执行文件 debug symbol
生成 DWARF
格式的文件:
dsymutil -f a -o a.dSYM
-f : .dwarf格式文件
-o : 输出.dSYM格式文件
移出符号
strip
用来移出和修改符号表:
strip -S a.o
-S : 删除调试符号
-X : 移除本地符号,‘L’开头的
-x : 移除全部的本地符号,只保留全局符号
链接器
ld
-all_load : 加载静态库包含的所有文件
-Objc : 加载静态库包含的所有的 Objective-C 和 Category
-force_load : 加载静态库中指定的文件
链接动态库与静态库
ld -dylib -arch x86_64 -macosx_version_min 10.13 a.dylib -o a
ld -static -arch x86_64 -e _main a.a -o a
Xcode 打印加载的库
Pre-main Time
指 main
函数执行之前的加载时间,包括 dylib
动态库加载, Mach-O
文件加载,Rebase/Binding
,Objective-C Runtime
加载等。
Xcode
自身提供了一个在控制台打印这些时间的方法:在 Xcode
中 Edit Scheme -> Run -> Auguments
添加环境变量 DYLD_PRINT_STATISTICS
并把其值设为 1
。
DYLD_PRINT_LIBRARIES
: 打印出所有被加载的库。
DYLD_PRINT_LIBRARIES_POST_LAUNCH
: 打印的是通过dlopen
调用返回的库,包括动态库的依赖库,主要发生在main
函数运行之后。
二进制重排
- 链接order.file
ld -o test test.o -lsystem -order_file test.order
ld -o test test.o -lsystem -lc++ -framework Foundation -order_file test.order
ld -map output.map -lsystem -o output a.o
- 生成Link Map 文件
ld -map output.map -lsystem -lc++ -framework Foundation test.o -o output
-map map_file_path 生成map文件。
主要包括三大部分:
Object Files : 生成二进制调用的 link 单元的路径 和 文件编号
Sections : 记录 Mach-O 每个 Segment/section 的地址范围
Symbols : 按顺序记录每个符号的地址范围
- install_name_tool
更改动态共享库的安装名称,并操纵运行路线
install_name_tool -add_rpath libs_File
install_name_tool -delete_rpath libs_File
install_name_tool -rpath libs_File