• [iOS开发]编译过程


    参考链接:https://juejin.cn/post/6844903742785978376

    前言


    iOS 开发中使用的是编译语言,所谓编译语言是在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高,是使用 Clang / LLVM 来编译的。LLVM是一个模块化和可重用的编译器和工具链技术的集合,Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,目的是提供惊人的快速编译。下面我们来看看编译过程,总的来说编译过程分为几个阶段:预处理 -> 词法分析 -> 语法分析 -> 静态分析 -> 生成中间代码和优化 -> 汇编 -> 链接

    具体过程


    命令行查看编译的过程:

    clang -ccc-print-phases main.m
    
    • 1

    结果:
    请添加图片描述

    (一)预处理

    对下面代码进行预处理

    #import "AppDelegate.h"
    #define NUMBER 1
    
    int main(int argc, char * argv[]) {
        NSString * appDelegateClassName;
        @autoreleasepool {
            // Setup code that might create autoreleased objects goes here.
            appDelegateClassName = NSStringFromClass([AppDelegate class]);
            
            NSLog(@"%d", NUMBER);
        }
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    使用终端到main.m所在文件夹,使用命令:clang -E main.m -F /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks ,结果如下:

    # 9 "./AppDelegate.h" 2
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    
    @end
    # 9 "main.m" 2
    
    
    int main(int argc, char * argv[]) {
        NSString * appDelegateClassName;
        @autoreleasepool {
    
            appDelegateClassName = NSStringFromClass([AppDelegate class]);
    
            NSLog(@"%d", 1);
        }
        return UIApplicationMain(argc, argv, ((void *)0), appDelegateClassName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这一步编译器所做的处理是:

    • 宏替换(在源码中使用的宏定义会被替换为对应#define的内容)
      建议大家不要在需要预处理的代码中加入内联代码逻辑。
    • 头文件引入(#include#import
      使用对应文件.h的内容替换这一行的内容,所以尽量减少头文件中的#import,使用@class替代,把#import放到.m文件中。
    • 处理条件编译指令 (#if#else#endif)

    (二)词法解析

    使用clang -Xclang -dump-tokens main.m词法分析,结果如下:

    at '@'	 [StartOfLine]	Loc=<./AppDelegate.h:10:1>
    identifier 'interface'		Loc=<./AppDelegate.h:10:2>
    identifier 'AppDelegate'	 [LeadingSpace]	Loc=<./AppDelegate.h:10:12>
    colon ':'	 [LeadingSpace]	Loc=<./AppDelegate.h:10:24>
    identifier 'UIResponder'	 [LeadingSpace]	Loc=<./AppDelegate.h:10:26>
    less '<'	 [LeadingSpace]	Loc=<./AppDelegate.h:10:38>
    identifier 'UIApplicationDelegate'		Loc=<./AppDelegate.h:10:39>
    greater '>'		Loc=<./AppDelegate.h:10:60>
    at '@'	 [StartOfLine]	Loc=<./AppDelegate.h:13:1>
    identifier 'end'		Loc=<./AppDelegate.h:13:2>
    int 'int'	 [StartOfLine]	Loc=<main.m:11:1>
    identifier 'main'	 [LeadingSpace]	Loc=<main.m:11:5>
    l_paren '('		Loc=<main.m:11:9>
    int 'int'		Loc=<main.m:11:10>
    identifier 'argc'	 [LeadingSpace]	Loc=<main.m:11:14>
    comma ','		Loc=<main.m:11:18>
    char 'char'	 [LeadingSpace]	Loc=<main.m:11:20>
    star '*'	 [LeadingSpace]	Loc=<main.m:11:25>
    identifier 'argv'	 [LeadingSpace]	Loc=<main.m:11:27>
    l_square '['		Loc=<main.m:11:31>
    r_square ']'		Loc=<main.m:11:32>
    r_paren ')'		Loc=<main.m:11:33>
    l_brace '{'	 [LeadingSpace]	Loc=<main.m:11:35>
    identifier 'NSString'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:12:5>
    star '*'	 [LeadingSpace]	Loc=<main.m:12:14>
    identifier 'appDelegateClassName'	 [LeadingSpace]	Loc=<main.m:12:16>
    semi ';'		Loc=<main.m:12:36>
    at '@'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:13:5>
    identifier 'autoreleasepool'		Loc=<main.m:13:6>
    l_brace '{'	 [LeadingSpace]	Loc=<main.m:13:22>
    identifier 'appDelegateClassName'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:15:9>
    equal '='	 [LeadingSpace]	Loc=<main.m:15:30>
    identifier 'NSStringFromClass'	 [LeadingSpace]	Loc=<main.m:15:32>
    l_paren '('		Loc=<main.m:15:49>
    l_square '['		Loc=<main.m:15:50>
    identifier 'AppDelegate'		Loc=<main.m:15:51>
    identifier 'class'	 [LeadingSpace]	Loc=<main.m:15:63>
    r_square ']'		Loc=<main.m:15:68>
    r_paren ')'		Loc=<main.m:15:69>
    semi ';'		Loc=<main.m:15:70>
    identifier 'NSLog'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:17:9>
    l_paren '('		Loc=<main.m:17:14>
    at '@'		Loc=<main.m:17:15>
    string_literal '"%d"'		Loc=<main.m:17:16>
    comma ','		Loc=<main.m:17:20>
    numeric_constant '1'	 [LeadingSpace]	Loc=<main.m:17:22 <Spelling=main.m:9:16>>
    r_paren ')'		Loc=<main.m:17:28>
    semi ';'		Loc=<main.m:17:29>
    r_brace '}'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:18:5>
    return 'return'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:19:5>
    identifier 'UIApplicationMain'	 [LeadingSpace]	Loc=<main.m:19:12>
    l_paren '('		Loc=<main.m:19:29>
    identifier 'argc'		Loc=<main.m:19:30>
    comma ','		Loc=<main.m:19:34>
    identifier 'argv'	 [LeadingSpace]	Loc=<main.m:19:36>
    comma ','		Loc=<main.m:19:40>
    identifier 'nil'	 [LeadingSpace]	Loc=<main.m:19:42>
    comma ','		Loc=<main.m:19:45>
    identifier 'appDelegateClassName'	 [LeadingSpace]	Loc=<main.m:19:47>
    r_paren ')'		Loc=<main.m:19:67>
    semi ';'		Loc=<main.m:19:68>
    r_brace '}'	 [StartOfLine]	Loc=<main.m:20:1>
    eof ''		Loc=<main.m:20:2>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    这一步把源文件中的代码转化为特殊的标记流,源码被分割成一个一个的字符和单词,在行尾Loc中都标记出了源码所在的对应源文件和具体行数,方便在报错时定位问题。Clang定义的所有Token类型。 可以分为下面这4类:

    • 关键字:语法中的关键字,比如 if、else、while、for 等;
    • 标识符:变量名;
    • 字面量:值、数字、字符串;
    • 特殊符号:加减乘除等符号。

    (三)语法分析

    执行 clang 命令 clang -Xclang -ast-dump -fsyntax-only main.m,主要得到如下结果:

    |-ObjCInterfaceDecl 0x11f8b46e8 <./AppDelegate.h:10:1, line:13:2> line:10:12 AppDelegate
    |-FunctionDecl 0x11f8b4a60 <main.m:11:1, line:20:1> line:11:5 main 'int (int, char **)'
    | |-ParmVarDecl 0x11f8b4810 <col:10, col:14> col:14 used argc 'int'
    | |-ParmVarDecl 0x11f8b4940 <col:20, col:32> col:27 used argv 'char **':'char **'
    | `-CompoundStmt 0x11f8e0188 <col:35, line:20:1>
    |   `-ObjCAutoreleasePoolStmt 0x11f8e0038 <line:13:5, line:18:5>
    |     `-CompoundStmt 0x11f8e0020 <line:13:22, line:18:5>
    |       `-CallExpr 0x11f8dffd8 <line:17:9, col:28> 'void'
    |         |-ImplicitCastExpr 0x11f8dffc0 <col:9> 'void (*)(id, ...)' <FunctionToPointerDecay>
    |         | `-DeclRefExpr 0x11f8dfdb8 <col:9> 'void (id, ...)' Function 0x11f8dfc18 'NSLog' 'void (id, ...)'
    |         |-ImplicitCastExpr 0x11f8e0008 <col:15, col:16> 'id':'id' <BitCast>
    |         | `-ObjCStringLiteral 0x11f8dff18 <col:15, col:16> 'NSString *'
    |         |   `-StringLiteral 0x11f8dfe18 <col:16> 'char [3]' lvalue "%d"
    |         `-IntegerLiteral 0x11f8dff38 <line:9:16> 'int' 1
    `-FunctionDecl 0x11f8dfc18 <line:17:9> col:9 implicit used NSLog 'void (id, ...)' extern
      |-ParmVarDecl 0x11f8dfd10 <<invalid sloc>> <invalid sloc> 'id':'id'
      |-BuiltinAttr 0x11f8dfcb8 <<invalid sloc>> Implicit 883
      `-FormatAttr 0x11f8dfd80 <col:9> Implicit NSString 1 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这一步是把词法分析生成的标记流,解析成一个抽象语法树(abstract syntax tree -- AST),同样地,在这里面每一节点也都标记了其在源码中的位置。

    (四)静态分析

    把源码转化为抽象语法树之后,编译器就可以对这个树进行分析处理。静态分析会对代码进行错误检查,如出现方法被调用但是未定义、定义但是未使用的变量等,以此提高代码质量。当然,还可以通过使用 Xcode 自带的静态分析工具(Product -> Analyze)

    • 类型检查
      在此阶段clang会做检查,最常见的是检查程序是否发送正确的消息给正确的对象,是否在正确的值上调用了正常函数。如果你给一个单纯的 NSObject* 对象发送了一个 hello 消息,那么 clang 就会报错,同样,给属性设置一个与其自身类型不相符的对象,编译器会给出一个可能使用不正确的警告。
      一般会把类型分为两类:动态的和静态的。动态的在运行时做检查,静态的在编译时做检查。以往,编写代码时可以向任意对象发送任何消息,在运行时,才会检查对象是否能够响应这些消息。由于只是在运行时做此类检查,所以叫做动态类型。
      至于静态类型,是在编译时做检查。当在代码中使用 ARC 时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。
    • 其他分析
      ObjCUnusedIVarsChecker.cpp是用来检查是否有定义了,但是从未使用过的变量。(
      This file defines a CheckObjCUnusedIvars, a checker that analyzes an Objective-C class's interface/implementation to determine if it has any ivars that are never accessed.
      ObjCSelfInitChecker.cpp是检查在 你的初始化方法中中调用 self 之前,是否已经调用 [self initWith...][super init] 了(
      This checks initialization methods to verify that they assign 'self' to the result of an initialization call (e.g. [super init], or [self initWith..]) before using 'self' or any instance variable.)。
      请添加图片描述

    (五)中间代码生成和优化

    LLVM IR有3种表示形式,但本质上是等价的。

    • text:便于阅读的文本格式,类似于汇编语言,拓展名 .ll
    • memory:内存格式
    • bitcode:二进制格式,拓展名 .bc

    我们对下面代码使用clang -O3 -S -emit-llvm main.m -o main.ll,生成main.ll

    #import <Foundation/Foundation.h>
    #define a1 1
    
    int sum(int a, int b) {
        int c = a + b;
        return c;
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            NSLog(@"Hello, World!");
            int a = 5;
            NSLog(@"%d", sum(a1, a));
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    ; ModuleID = 'main.m'
    source_filename = "main.m"
    target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
    target triple = "arm64-apple-macosx12.0.0"
    
    %struct.__NSConstantString_tag = type { i32*, i32, i8*, i64 }
    
    @__CFConstantStringClassReference = external global [0 x i32]
    @.str = private unnamed_addr constant [14 x i8] c"Hello, World!\00", section "__TEXT,__cstring,cstring_literals", align 1
    @_unnamed_cfstring_ = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i32 0, i32 0), i64 13 }, section "__DATA,__cfstring", align 8 #0
    @.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", section "__TEXT,__cstring,cstring_literals", align 1
    @_unnamed_cfstring_.2 = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, section "__DATA,__cfstring", align 8 #0
    
    ; Function Attrs: norecurse nounwind readnone ssp uwtable willreturn
    define i32 @sum(i32 %0, i32 %1) local_unnamed_addr #1 {
      %3 = add nsw i32 %1, %0
      ret i32 %3
    }
    
    ; Function Attrs: ssp uwtable
    define i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
      %3 = tail call i8* @llvm.objc.autoreleasePoolPush() #3
      notail call void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*))
      notail call void (i8*, ...) @NSLog(i8* bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_.2 to i8*), i32 6)
      tail call void @llvm.objc.autoreleasePoolPop(i8* %3)
      ret i32 0
    }
    
    ; Function Attrs: nounwind
    declare i8* @llvm.objc.autoreleasePoolPush() #3
    
    declare void @NSLog(i8*, ...) local_unnamed_addr #4
    
    ; Function Attrs: nounwind
    declare void @llvm.objc.autoreleasePoolPop(i8*) #3
    
    attributes #0 = { "objc_arc_inert" }
    attributes #1 = { norecurse nounwind readnone ssp uwtable willreturn "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
    attributes #2 = { ssp uwtable "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
    attributes #3 = { nounwind }
    attributes #4 = { "disable-tail-calls"="false" "frame-pointer"="non-leaf" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.5a,+zcm,+zcz" "unsafe-fp-math"="false" "use-soft-float"="false" }
    
    !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
    !llvm.ident = !{!12}
    
    !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 1]}
    !1 = !{i32 1, !"Objective-C Version", i32 2}
    !2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
    !3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
    !4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
    !5 = !{i32 1, !"Objective-C Class Properties", i32 64}
    !6 = !{i32 1, !"wchar_size", i32 4}
    !7 = !{i32 1, !"branch-target-enforcement", i32 0}
    !8 = !{i32 1, !"sign-return-address", i32 0}
    !9 = !{i32 1, !"sign-return-address-all", i32 0}
    !10 = !{i32 1, !"sign-return-address-with-bkey", i32 0}
    !11 = !{i32 7, !"PIC Level", i32 2}
    !12 = !{!"Apple clang version 13.0.0 (clang-1300.0.29.30)"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    接下来 LLVM 会对代码进行编译优化,例如针对全局变量优化、循环优化、尾递归优化等,最后输出汇编代码。使用xcrun clang -S -o - main.m | open -f生成汇编代码:

    	.section	__TEXT,__text,regular,pure_instructions
    	.build_version macos, 12, 0	sdk_version 12, 1
    	.globl	_sum                            ; -- Begin function sum
    	.p2align	2
    _sum:                                   ; @sum
    	.cfi_startproc
    ; %bb.0:
    	sub	sp, sp, #16                     ; =16
    	.cfi_def_cfa_offset 16
    	str	w0, [sp, #12]
    	str	w1, [sp, #8]
    	ldr	w8, [sp, #12]
    	ldr	w9, [sp, #8]
    	add	w8, w8, w9
    	str	w8, [sp, #4]
    	ldr	w0, [sp, #4]
    	add	sp, sp, #16                     ; =16
    	ret
    	.cfi_endproc
                                            ; -- End function
    	.globl	_main                           ; -- Begin function main
    	.p2align	2
    _main:                                  ; @main
    	.cfi_startproc
    ; %bb.0:
    	sub	sp, sp, #64                     ; =64
    	stp	x29, x30, [sp, #48]             ; 16-byte Folded Spill
    	add	x29, sp, #48                    ; =48
    	.cfi_def_cfa w29, 16
    	.cfi_offset w30, -8
    	.cfi_offset w29, -16
    	mov	w8, #0
    	str	w8, [sp, #24]                   ; 4-byte Folded Spill
    	stur	wzr, [x29, #-4]
    	stur	w0, [x29, #-8]
    	stur	x1, [x29, #-16]
    	bl	_objc_autoreleasePoolPush
    	str	x0, [sp, #16]                   ; 8-byte Folded Spill
    	adrp	x0, l__unnamed_cfstring_@PAGE
    	add	x0, x0, l__unnamed_cfstring_@PAGEOFF
    	bl	_NSLog
    	mov	w8, #5
    	stur	w8, [x29, #-20]
    	ldur	w1, [x29, #-20]
    	mov	w0, #1
    	bl	_sum
    	mov	x10, x0
    	adrp	x0, l__unnamed_cfstring_.2@PAGE
    	add	x0, x0, l__unnamed_cfstring_.2@PAGEOFF
    	mov	x9, sp
                                            ; implicit-def: $x8
    	mov	x8, x10
    	str	x8, [x9]
    	bl	_NSLog
    	ldr	x0, [sp, #16]                   ; 8-byte Folded Reload
    	bl	_objc_autoreleasePoolPop
    	ldr	w0, [sp, #24]                   ; 4-byte Folded Reload
    	ldp	x29, x30, [sp, #48]             ; 16-byte Folded Reload
    	add	sp, sp, #64                     ; =64
    	ret
    	.cfi_endproc
                                            ; -- End function
    	.section	__TEXT,__cstring,cstring_literals
    l_.str:                                 ; @.str
    	.asciz	"Hello, World!"
    
    	.section	__DATA,__cfstring
    	.p2align	3                               ; @_unnamed_cfstring_
    l__unnamed_cfstring_:
    	.quad	___CFConstantStringClassReference
    	.long	1992                            ; 0x7c8
    	.space	4
    	.quad	l_.str
    	.quad	13                              ; 0xd
    
    	.section	__TEXT,__cstring,cstring_literals
    l_.str.1:                               ; @.str.1
    	.asciz	"%d"
    
    	.section	__DATA,__cfstring
    	.p2align	3                               ; @_unnamed_cfstring_.2
    l__unnamed_cfstring_.2:
    	.quad	___CFConstantStringClassReference
    	.long	1992                            ; 0x7c8
    	.space	4
    	.quad	l_.str.1
    	.quad	2                               ; 0x2
    
    	.section	__DATA,__objc_imageinfo,regular,no_dead_strip
    L_OBJC_IMAGE_INFO:
    	.long	0
    	.long	64
    
    .subsections_via_symbols
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    看前面几行:

    	.section	__TEXT,__text,regular,pure_instructions
    	.build_version macos, 12, 0	sdk_version 12, 1
    	.globl	_sum                            ; -- Begin function sum
    	.p2align	2
    
    • 1
    • 2
    • 3
    • 4

    他们是汇编指令而不是汇编代码。

    • .section指令指定了接下来会执行哪一个段
    • .globl指令说明_main是一个外部符号。这就是我们的main()函数。这个函数对外部是可见的,因为系统要调用它来运行可执行文件。
    • .p2align指令指出了后面代码的对齐方式。在我们的代码中,后面的代码会按照 16(2^4) 字节对齐,如果需要的话,用 0x90 补齐。

    (六)汇编

    在这一阶段,汇编器将上一步生成的可读的汇编代码转化为机器代码。最终产物就是 以 .o 结尾的目标文件。使用Xcode构建的程序会在DerivedData目录中找到这个文件。请添加图片描述

    (七)链接

    这一阶段是将上个阶段生成的目标文件和引用的静态库链接起来,最终生成可执行文件,链接器解决了目标文件和库之间的链接。
    可执行文件类型为 Mach-O 类型,在 MAC OS 和 iOS 平台的可执行文件都是这种类型。因为我使用的是模拟器,所以处理器指令集为 x86_64。
    至此,编译过程结束。

  • 相关阅读:
    力扣(LeetCode)116. 填充每个节点的下一个右侧节点指针(C++)
    Gin项目实战
    C++学习笔记(十四)
    Weblogic+Oracle11g设置开机自启动
    Linux MyFile
    Android SdkManager简介
    【MindSpore易点通机器人-02】设计与技术选型
    DQL(数据库查询)
    【JUC】CompletableFuture
    这个 MySQL bug 99% 的人会踩坑!
  • 原文地址:https://blog.csdn.net/weixin_52192405/article/details/125866961