? ? ? ? 在 GCC 編譯一個 C 源代碼時,先會通過宏處理,形成 一個叫轉譯單元(translation_unit),接著進行語法分析,C 的語法分析入口是
static void c_parser_translation_unit(c_parser *parser);
? ? ? ? 接著就通過類似遞歸下降解析器(Recursive descent parser)的方式進行語法解析。當完成一個函數的解析后,會將該函數加入到符號表(Symbol Table)中的調用圖(Call Graph)的節點集(nodes)中。通過下面 gdb 的 backtrace 可以看到:
#0 cgraph_node::get_create (decl=0x7ffff79b2700) at <gcc-project>/gcc/cgraph.cc:537
#1 0x00000000012d06d4 in c_genericize (fndecl=0x7ffff79b2700) at <gcc-project>/gcc/c-family/c-gimplify.cc:796
#2 0x00000000011587ec in finish_function (end_loc=33408) at <gcc-project>/gcc/c/c-decl.cc:11501
#3 0x00000000011d9734 in c_parser_declaration_or_fndef at <gcc-project>/gcc/c/c-parser.cc:3010
#4 0x00000000011d680e in c_parser_external_declaration (parser=0x7ffff7fbc5b0) at <gcc-project>/gcc/c/c-parser.cc:2088
#5 0x00000000011d6254 in c_parser_translation_unit (parser=0x7ffff7fbc5b0) at <gcc-project>/gcc/c/c-parser.cc:1952
#6 0x000000000123cf9e in c_parse_file () at <gcc-project>/gcc/c/c-parser.cc:29613
#7 0x00000000012f68c8 in c_common_parse_file () at <gcc-project>/gcc/c-family/c-opts.cc:1379
#8 0x0000000001bd64d3 in compile_file () at <gcc-project>/gcc/toplev.cc:452
#9 0x0000000001bd9b1e in do_compile () at <gcc-project>/gcc/toplev.cc:2200
#10 0x0000000001bd9fb9 in toplev::main (this=0x7fffffffd3d2, argc=19, argv=0x7fffffffd518) at <gcc-project>/gcc/toplev.cc:2354
#11 0x0000000004482a35 in main (argc=19, argv=0x7fffffffd518) at <gcc-project>/gcc/main.cc:39
? ? ? ? cgraph_node::get_create 就是對于一個解析后的函數所構建的調用圖中的節點,調用節點(cgraph_node)。
? ? ? ? 由此可見,符號表(Symbol Table)會包含整個轉譯單元中的符號,對于函數的話,會形成對應的調用節點(cgraph_node:symtab_node)。
? ? ? ? 此時,加入以調用節點加入到符號表中的函數是已經解析好,以GENERIC 中間語言所表示的。
? ? ? ? 加入后,cc1 調用?cgraph_node::finalize_function 進一步處理。如下圖所描述的。
? ? ? ? 這里,關鍵是說明 C 源代碼在解析(Parse)后,所存在的形式,如何提供到后面基于過程(Pass)機制的處理。
? ? ? ? 那么此時,在compile_file函數中,如下圖:
? ? ? ? 經過?lang_hooks.parse_file (); 后,gcc 已經將C的源代碼解析完畢(Parsed)并以調用圖的方式存放符號表(Symbol Table)中。
? ? ? ? 在接著的 symtab->finalize_compilation_unit (); 就開始通過以處理過程(Passes)的方式,將GENERIC中間語言轉換成最終的匯編語言。?
?