gcc源码分析
文章平均质量分 94
ashimida@
这个作者很懒,什么都没留下…
展开
-
AArch64中va_list/va_start/va_arg/...的实现
一、背景[3]1. 可变参函数可变参函数指的是一个可以接受可变个参数的函数, 调用此函数时只有caller知道为此函数传入了多少个参数, 可变参函数callee只知道caller最少传入了多少个参数:callee中可以确定的参数称为命名参数(Named arguments) callee中不确定的参数称为匿名参数(Anonymous arguments) 对于可变参函数(callee), 其需要:在其函数栈中预留空间存储所有可能的匿名寄存器参数(否则由于不确定传入了多少个寄存器参数,不.原创 2022-04-04 23:03:39 · 3383 阅读 · 1 评论 -
AArch64函数栈的分配,指令生成与GCC实现(下)
上一篇AArch64函数栈的分配,指令生成与GCC实现(上)_ashimida@的博客-CSDN博客主要说明原理,本篇主要介绍gcc中的实现.一、函数栈中的位置标记 gcc编译过程中会为当前函数布局函数栈,函数栈中的每一个元素位置最终都会对应当基于硬件寄存器sp或fp的偏移,但在编译过程中这些偏移不是一次性确定的。gcc在编译过程中内部会使用一些虚拟寄存器/伪寄存器作为标记位来代表函数栈中的各个位置,这些标记位最终被转换为sp/fp + offset并在最终输出的汇编代码中不可见,但这些标记...原创 2022-04-04 22:42:59 · 3271 阅读 · 0 评论 -
AArch64函数栈的分配,指令生成与GCC实现(上)
一、术语定义 为便于理解,本文中后续术语含义解释如下:首地址: 一个变量/内存的首地址指的是此变量/内存最低位的地址 尾地址: 一个变量/内存的尾地址指的是此变量/内存最高地址(+1), 如变量存储空间为[0x0, 0x10), 则此变量首地址为0x0, 尾地址为0x10 GPR/FPR: AArch64中的通用寄存器(R0-R30)后面称为GPR(General Purpose Register); 浮点寄存器称为FPR(Floating Point Register)二、AArch64函.原创 2022-04-04 22:20:12 · 5053 阅读 · 0 评论 -
GCC源码分析—shrink-wrapping
一、shrink-wrapping基本概念 pro/epilogue是函数开始/结束时编译器为其插入的指令序列, shrink-warpping是针对pro/epilogue插入位置的优化,包括两个步骤:1. 将pro/epilogue收缩到其实际需要的当前函数最小cfg子集中(此过程是在try_shrink_wrapping函数中完成的,后续称之为shrink-wrapping): pro/epilogue未必总是要发送到函数的开始和结束的,比如函数的某个流程中可能没有使用pro/ep...原创 2022-02-15 23:06:39 · 1623 阅读 · 0 评论 -
C++异常处理源码与安全性分析
C++异常处理需要DWARF的支持,其业界实际标准是 IA-64 C++ABI[1],本文主要描述整个异常处理的流程以及在libgcc中的实现.关于基于DWARF的栈回溯可参考 [2], 关于C++异常处理其他分析可参考[3-8]。一、异常处理代码举例 先以一个简单的C++程序为例:1 #include <stdio.h>2 #include <stdlib.h>34 class x {5 public:6 x(voi...原创 2021-12-10 21:56:22 · 5059 阅读 · 3 评论 -
AARCH64平台的栈回溯
一、术语解释:1.栈顶/栈底[1]: 栈中最后一个push,第一个被pop的位置是栈顶;栈中最后一个被pop,且pop后当前栈为空的位置是栈底;2.Current Function Frame Address[2]: 当前函数栈帧,在aarch64中是当前函数执行完prologue后的栈顶地址, 其可以通过__builtin_frame_address(0)函数获取.3.Canonical Frame Address(CFA)[3]:标准/规范栈帧地址,在aarch64中是当前...原创 2021-12-08 23:02:17 · 4247 阅读 · 1 评论 -
GCC源码分析(十七) — rtl expand之后
ps: 这是源码分析系列最后一篇文章, 从<GCC源码分析(一) — 输入参数解析>到本文只是大体介绍了整个cc1编译的基本流程, 而实际上其中的细节十分复杂,尤其各个优化的pass更是gcc的精髓,因笔者了解有限,故这些内容在此系列中尚未涉及,后续有机会再加以补充. 由前可知,函数expand过程中执行了all_passes链表中的所有pass,其中pass_expand负责将gimple指令序列expand为rtl指令序列, pass_expand是一级pass中的倒数第二个,...原创 2021-08-31 23:39:37 · 1282 阅读 · 5 评论 -
GCC源码分析(十六) — gimple转RTL(pass_expand)(下)
上接 <GCC源码分析(十五) — gimple转RTL(pass_expand)(上)>一、pass_expand的基本流程二、pass_expand-局部,临时变量的展开与空间分配三、pass_expand-caller的参数传入和callee的参数接收四、pass_expand-gimple指令序列的展开五、pass_expand-init_block和exit_block的展开六、pass_expand-边指令的插入和硬件寄存器初值的保存四、pass_expa原创 2021-08-31 22:18:57 · 805 阅读 · 0 评论 -
GCC源码分析(十五) — gimple转RTL(pass_expand)(上)
由前可知,函数的expand(cgraph_node::expand)过程实际上是执行了all_passes中的所有passes,这些pass中:首先执行了一系列的GIMPLE_PASS(如优化) 然后通过pass "expand"将gimple指令序列转化为rtl指令序列 之后执行了一系列RTL_PASS 最终通过RTL_PASS "final"将函数的RTX指令序列输出为汇编代码而本文主要记录在pass "expand"中是如何将gimple指令序列转化为rtl指令序列的....原创 2021-08-31 22:08:25 · 1372 阅读 · 1 评论 -
GCC源码分析(十四) — rtx结构体,指令与栈分配
一、rtx表达式 RTL(Register Transfer Language)全称叫寄存器传输语言,其采用类似LISP语言的列表形式描述了每一条指令的语义动作.RTL语言中最基础的数据结构体就是RTX(struct rtx_def),类似于树节点(tree)在AST中的作用,RTX(rtx_def)表达式节点是RTL语言中最基本的数据类型(RTX 是 RTLeXpression). 在gcc中,rtx结构体实际上是一个指向rtx_def结构体的指针,其类似AST中树节点(tree)是用来...原创 2021-08-30 23:54:06 · 2067 阅读 · 0 评论 -
GCC源码分析(十三) — 机器描述文件
在gcc中,各个平台都有自己的机器描述文件,机器描述文件主要包括两种:${target}.[md]:在aarch64平台为 ./config/aarch64/aarch64.md文件,此文件中主要记录的是aarch64平台的指令模板,此模板用来决定最终RTL是如何生成汇编代码的. ${target}.[ch]:在aarch64平台中为 ./config/aarch64/aarch64.h, ./config/aarch64/aarch64.c 两个文件.除了RTL=>汇编代码的指令...原创 2021-08-30 23:18:00 · 3080 阅读 · 0 评论 -
GCC源码分析(十二) — gimplify之后的基本流程
一、gimplify之后 gimplify之后的所有流程主要都是在函数 symbol_table::compile中完成的,此过程中除了IPA_PASS的执行外,还完成了:gimple=>rtl的转换,以及最终rtl=>汇编代码的输出:void symbol_table::finalize_compilation_unit (void){ ...... current_function_decl = NULL; /* 全局的 cfun, current_functi..原创 2021-08-29 23:40:41 · 867 阅读 · 0 评论 -
GCC源码分析(十一) — 函数节点的gimple低端化
一、gimple低端化 在gimple高端化时已经说过,整个编译单元所有外部声明的AST树节点生成完毕后会遍历符号表中的所有符号节点进行分析,而对于函数节点最终会执行到 cgraph_node::analyze对其进行gimple高端化和gimple低端化分析,gimple高端化的分析是通过函数gimplify_function_tree(decl)来完成的,而同样是在此流程中,gimple低端化则是通过一系列pass的执行完成的,代码如下:void cgraph_node::analyze (.原创 2021-08-29 23:26:25 · 967 阅读 · 0 评论 -
GCC源码分析(十) — 函数节点的gimple高端化
一、gimple高端化 前面提到整个编译单元所有外部声明的AST树节点生成完毕后会遍历符号表中的所有符号节点进行分析,对于函数节点最终会执行到 cgraph_node::analyze对其进行gimple高端化和低端化分析,其中gimple高端化是通过函数gimplify_function_tree(decl)来完成的,此函数用来分析一个具体的函数声明节点,其代码大体如下:/* 此函数负责整个gimple高端化,其创建了一个gbind节点,其中: .body记录当前函数形参和函.原创 2021-08-29 22:38:45 · 1320 阅读 · 0 评论 -
GCC源码分析(九) — gcc全局符号表与符号的分析(gimplify)
一、全局符号表 在gcc中有一个全局变量symbol_table *symtab; 此变量是用来记录整个编译过程中产生的所有函数和符号的, symbol_table类的关键元素记录如下:class symbol_table{public: friend class symtab_node; friend class cgraph_node; friend class cgraph_edge; int cgraph_count; /* 记录当前全局符号表中的函数...原创 2021-08-29 13:22:56 · 3213 阅读 · 0 评论 -
GCC源码分析(八) — 语法/语义分析之声明与函数定义的解析
一、概述 由前可知, c_parser_declaration_or_fndef负责对声明和函数定义的解析, 对于声明的解析其整体流程是:解析声明说明符(c_parser_declspecs) 解析出第一个声明符(c_parser_declarator) 根据声明说明符 +声明符为声明构建声明节点(XXX_DECL),并将新创建的声明绑定到当前scope(start_decl) 若下一个符号是等号(=)则解析此声明符的初值(c_parser_initializer); 不论是否有=,当前声..原创 2021-08-29 13:11:04 · 1248 阅读 · 1 评论 -
GCC源码分析(七) — 语法/语义分析之声明符解析(下)
在<GCC源码分析(五) — 语法/语义分析之声明符解析(上)>中已经大体介绍了声明符的解析流程,其中没有完成的一部分就是参数列表的解析,也就是下面产生式中的 parameter-type-list的解析: declarator: pointer[opt] direct-declarator direct-declarator: identifier T4 (attributes[opt] ...原创 2021-08-28 23:24:20 · 668 阅读 · 1 评论 -
GCC源码分析(六) — 符号绑定,作用域与block树节点
gcc中的符号绑定(c_binding)作用于(scope)和block树节点,根据c语言语法可知在不同的作用于中是可以对标识符重新声明的:int x;void fun(){int x;} 如上的定义中函数func内部的x和全局变量x是两个不同的声明,但在gcc中二者的标识符实际上都是x. 在gcc源码中相同字符串的标识符节点是全局唯一的(只有一个), 因为仅仅在词法和语法层面是没法区分出相同字符串的不同含义的. 而在解析到源码不同位置时则需要区分出一个标识符到...原创 2021-08-28 22:59:12 · 949 阅读 · 0 评论 -
GCC源码分析(五) — 语法/语义分析之声明符解析(上)
c_parser_declaration_or_fndef在解析完声明说明符之后接着要解析的就是声明符,对于函数和声明来说,虽然产生式不一样但这一步基本是一样的(除了断言在之前已经处理过了),函数定义和声明的组成都是 "声明说明符声明符 ... "开头的,所以在声明说明符解析完毕后不论是函数还是声明的解析,下一步都是要解析声明符,而声明符的解析函数是:c_parser_declaration_or_fndef => c_parser_declarator 声明符实际上指的是如具体...原创 2021-08-28 22:23:37 · 760 阅读 · 3 评论 -
GCC源码分析(四) — 语法/语义分析之声明说明符的解析
一、GCC中的语法/语义分析 在gcc中词法分析是作为接口函数供语法分析调用的, 每当语法分析需要一个新的语法符号时其内部则会调用词法分析接口来获取一个新的token. 语法分析 = >语义分析后会将源代码转换成一个一个AST树节点, 之后此AST树节点即可代表整个源码中的所有内容了, 在gcc中函数c_common_parse_file则负责语法分析直到AST树结点的生成:/*toplev::main=> do_compile => compile...原创 2021-08-28 11:22:17 · 2447 阅读 · 0 评论 -
GCC源码分析(三) — 词法符号转语法符号
语法分析要解决的主要问题是对词法分析得到的词法符号序列进行语法的推导,如果推到成功则源代码就是满足语法规范的源代码。 常见的语法分析工具包括Yacc, Bison等,早期的GCC中使用Yacc及Bison进行C语言的语法分析,而在较高的版本中不再使用二者,而是使用gcc/c-parser.c中定义的专门函数完成c语言语法分析。 C语言发展至今,其语法经历了多次修订,包含多个版本,gcc中均予以支持, 总体来讲GCC对C语言的语法分析采用一种【自顶向下】的语法推导过程,由于部分推导...原创 2021-08-27 00:18:12 · 948 阅读 · 0 评论 -
GCC源码分析(二) — 词法分析
GCC的词法分析是在伴随语法分析完成的,当语法分析过程中找不到下一个token时,就会调用词法分析来解析后续的token。词法分析的代码在./gcc/c-family目录;而C语言语法分析的目录在./gcc/c目录下,词法分析是给所有C家族的语言共用的。GCC的词法分析的主要代码是从cc1(如./gcc/c-family/c-lex.c) => libcpp(如./gcc/libcpp/lex.c)中的,对于cc1来说这些代码都编译进其二进制了。 lex是LEXical compi...原创 2021-08-27 00:06:44 · 3190 阅读 · 2 评论 -
GCC源码分析(一) — 输入参数解析
只以编译阶段为例的话,gcc的参数解析分为两部分: 一部分是参数从命令行到gcc 一部分是参数从gcc到最终的编译程序cc1 1.从命令行到gcc 编译出来的gcc二进制程序实际上只是起到一个桩代码的作用,或者说只是一个编译的驱动,其内部实际上是要分别调用cc1,as,collect来进行编译,汇编与连接。gcc的基本流程如下图: gcc在解析了输入参数后,会为每一个输入文件启动一次cc1来做具体的编译,而cc1一次只能处理一个源码的编译,如果输入多...原创 2021-08-26 23:48:02 · 5200 阅读 · 11 评论 -
静态单赋值(二)—gcc中的SSA化算法
一、基本概念[1] 许多数据流分析需要寻找表达式中每个定值变量的使用点,或者每个使用变量的定值点. 定值-使用链表(def-use chain)是一种能够高效获取这些信息的数据结构: 对于流图中的每条语句,编译器能够保存两个由指针组成的列表: * 其中一个列表中的指针指向在该语句中定值的变量的所有使用点 * 另一个列表中的指针指向该语句中所使用变量的所有定值点 通过这个方法编译器能够快速地从使用跳到定值, 从定值跳到使用. 对定值-使用链思想的一种改进是静态...原创 2021-08-02 23:40:59 · 1530 阅读 · 0 评论 -
静态单赋值(一)—gcc中的支配树
一、需要了解的基本概念在gcc优化的过程中,不论是循环的优化还是数据流分析,支配树在其中都起到至关重要的作用: *对于循环来说,支配树对找出代码中的循环非常有用 *对数据流分析来说,支配树对计算SSA_NAME中的phi函数插入点十分重要支配树中的主要概念包括: 1)必经结点(Dominator,又称支配结点):如果从(如函数的)起始节点S0到结点n的所有有效路径都经过结点d,那么结点d则成为结点n的必经结点,同时每一个结点都是自己的必经结点简单的说,必经...原创 2021-08-02 23:25:39 · 1447 阅读 · 1 评论