美文网首页
了解-clang编译过程

了解-clang编译过程

作者: ibingewin | 来源:发表于2019-11-26 01:20 被阅读0次

    clang编译过程

    clang是一个 CC++Objective-C的编译器, 包含了预处理语法解析代码生成优化汇编链接阶段, 尽管clang是高度集成的, 但是理解编译的各个阶段, 仍然很有必要.
    过程:

    预处理 -> 语法解析 -> 代码生成&优化 -> 汇编 -> 链接
    .c -> AST -> .s -> .o -> .out

    编译过程

    驱动

    clang可执行文件实际上是一个小的驱动程序, 控制其他工具(如编译器、汇编器和链接器)的总体执行. 通常你不需要直接和驱动程序交互, 就可以使用clang来运行其他工具.

    预处理

    这个阶段会对输入的源文件进行标记化处理、宏扩展、#include扩展和其他预处理器指令的处理. 对C输出.i, 对C++输出 .ii, 对 OC 输出 .mi, 对Objective-C++ 输出 .mii, 分别对应如下:

    输入: .c.cpp.m.mm
    输出: .i.ii.mi.mii

    语法分析和语义分析

    这个阶段会解析输入文件, 将预处理标记转换为解析树. 一旦以解析树的形式出现, 它也会用语义分析来计算表达式的类型, 确认代码格式是否正确.
    该阶段负责生成大多数的编译警告错误, 输出为 AST(抽象语法树, Abstract Syntax Tree)

    输出: AST

    代码生成和优化

    这个阶段会将AST转换为底层的中间代码(称为 LLVM IR), 再最终转换为机器码.该阶段负责优化生成的代码, 并处理特定目标的代码生成. 输出通常称为 .s 文件或者 汇编文件.

    输出: .s汇编文件

    汇编

    这个阶段将编译器的输出转换为目标文件, 输出为 .o 文件 或者 object 文件

    输出: .oobject文件

    链接

    这个阶段会将多个目标文件合并为一个可执行文件或动态库.输出为 a.out 或者 .so 文件

    输出: .out.so

    示例

    下面用一个简单的hello world来演示一下:

    第1步: 创建源码文件hello.c如下:

    //
    //  hello.c
    //
    
    #include <stdio.h>
    
    #define ADD(x,y) (x+y)
    #define ADD10(x, y) ADD(x+10, y)
    
    
    int main() {
    #if A
        printf("hello world A"); // A
    #else
        printf("hello world B"); // B
    #endif
        printf("result:%d", ADD10(1, 2));
    }
    
    
    

    第2步: 对其进行预编译, 得到.i输出文件, 使用命令:

    $ clang -E hello.c -o hello.i
    

    -E 选项为进行预编译 (更多的编译选项可以在查看这里)
    hello.i 文件内容如下:

    # 1 "hello.c"
    # 1 "<built-in>" 1
    # 1 "<built-in>" 3
    # 362 "<built-in>" 3
    # 1 "<command line>" 1
    # 1 "<built-in>" 2
    # 1 "hello.c" 2
    .
    .
    .
    # 10 "hello.c" 2
    
    
    
    int main() {
    
    
    
        printf("hello world B");
    
        printf("result:%d", (1 +10 +2));
    }
    

    从中可以看到预处理做的一些工作

    • include 扩展: # 10 "hello.c 2"上边的均为stdio.h中的内容
    • 标记化处理: .i 文件中行首行末的数字
    • 去除注释: hello.c 的注释都没有了
    • 条件编译: 未定义宏A, 故删除#if A分支下的代码块,并保留该空行
    • 宏删除: ADD10ADD 宏被删除; 条件编译的宏指令也被删除
    • 宏替换: ADD10ADD宏直接替换为(1+10+2), 并删除宏定义,保留该空行

    第3步:编译,得到.s文件, 使用命令

    $ clang -S hello.i -o hello.s
    

    -S 选项为进行汇编之前的所有阶段(代码生成优化指定目标的代码生成), 产生一个汇编文件 (更多的编译选项可以在查看这里)
    hello.s文件内容如下:

        .section    __TEXT,__text,regular,pure_instructions
        .build_version macos, 10, 15    sdk_version 10, 15
        .globl  _main                   ## -- Begin function main
        .p2align    4, 0x90
    _main:                                  ## @main
        .cfi_startproc
    ## %bb.0:
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        subq    $16, %rsp
        leaq    L_.str(%rip), %rdi
        movb    $0, %al
        callq   _printf
        leaq    L_.str.1(%rip), %rdi
        movl    $13, %esi
        movl    %eax, -4(%rbp)          ## 4-byte Spill
        movb    $0, %al
        callq   _printf
        xorl    %esi, %esi
        movl    %eax, -8(%rbp)          ## 4-byte Spill
        movl    %esi, %eax
        addq    $16, %rsp
        popq    %rbp
        retq
        .cfi_endproc
                                            ## -- End function
        .section    __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
        .asciz  "hello world B"
    
    L_.str.1:                               ## @.str.1
        .asciz  "result:%d"
    
    
    .subsections_via_symbols
    
    

    第4步: 汇编,得到.o文件, 使用命令

    $ clang -c hello.s -o hello.o
    

    -c 选项为执行汇编及之前的所有阶段, 生成机器码0101, 产生一个目标文件 (更多的编译选项可以在查看这里)
    hello.o文件内容如下:

    cffa edfe 0700 0001 0300 0000 0100 0000
    0400 0000 0802 0000 0020 0000 0000 0000
    1900 0000 8801 0000 0000 0000 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    b800 0000 0000 0000 2802 0000 0000 0000
    .
    .
    .
    68ff ffff ffff ffff 3900 0000 0000 0000
    0041 0e10 8602 430d 0600 0000 0000 0000
    2800 0000 0100 002d 1900 0000 0200 0015
    1200 0000 0100 002d 0b00 0000 0200 0015
    0000 0000 0100 0006 0100 0000 0f01 0000
    0000 0000 0000 0000 0700 0000 0100 0000
    0000 0000 0000 0000 005f 6d61 696e 005f
    7072 696e 7466 0000 
    

    相关文章

      网友评论

          本文标题:了解-clang编译过程

          本文链接:https://www.haomeiwen.com/subject/epbswctx.html