iOS之LLVM 四

76 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

书接上文,今天继续LLVM的学习。

生成目标文件(汇编器)

目标文件的生成,是汇编器以汇编代码作为输入,将汇编代码转换为机器代码,最后输出目标文件(object file

命令:

clang -fmodules -c main.s -o main.o

通过nm命令,查看main.o中的符号:

xcrun nm -nm main.o

-------------------------
//输出以下内容:
                 (undefined) external _printf
0000000000000000 (__TEXT,__text) external _main
  • _printf函数,被标记为undefined external
    • undefined:表示在当前文件中,暂时找不到符号。因为printf为外部函数,链接后才能找到符号所属动态库
    • external:表示这个符号在外部是可以被访问的

生成可执行文件(链接)

链接:将多个目标文件合并,符号表(包括重定位符号表)合并成一张表,经过链接最后,会分配虚拟内存地址,最终生成可执行文件或动态库

这个过程还会链接需要的动态库和静态库

  • 静态库,和可执行文件合并
  • 动态库,独立存在,运行时,由dyld动态加载

使用以下命令,生成可执行文件:

clang main.o -o main

查看链接后可执行文件的符号:

xcrun nm -nm main

-------------------------
//输出以下内容:
                 (undefined) external _printf (from libSystem)
                 (undefined) external dyld_stub_binder (from libSystem)
0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header
0000000100003f77 (__TEXT,__text) external _main
0000000100008008 (__DATA,__data) non-external __dyld_private
  • 链接后,_printf符号可以找到所属的动态库,但依然被标记为undefined。因为libSystem属于系统动态库,在运行时进行动态绑定
  • 链接后,还多了dyld_stub_binder符号,它在运行时用于符号的重绑定
    • printf函数为例,printf函数存在于libSystem系统库中,它存在于懒加载符号表中。它的函数地址在运行时,首次对printf函数进行调用,才会通过dyld_stub_binder进行重绑定
    • dyld_stub_binder函数地址的绑定时机:当dyld加载主程序时,符号被dyld直接绑定。

LLVM的编译流程暂时就告一段落,明天我们来继续看一下Clang插件相关的内容。