多个文件在编译时是怎样生成符号表的

回答这个问题你应该首先弄清楚编译的过程。首先,对于程序员(非编译方向)们通常所说的"编译",尤其是生成可执行文件的编译过程。其实是由两个过程组成的。即编译(compile)和链接(link)。而对于搞编译的同学而言,通常所说的编译仅指前面所说的compile。其次,编译和链接实际上是相当不同的两个过程。具体的其他区别这里不提了,仅围绕你的问题而言,编译通常是逐个文件进行的,所以对于编译器而言,每次仅能看见一个文件的内容。而链接则将所有的源文件聚集在一起最后生成一个目标文件,其可见范围包含所有的源文件(也包括库)。因此,编译器通常不会也无法产生整个工程的全局符号表,其可见范围仅为单个被编译文件。而链接器读取所有输入文件,并按照一定的规则寻找每一个符号的定义并计算其地址(或者留下可重定位符号交由加载器在运行时计算)
■网友
一般来说 编译是一个文件一个文件编译的 一个预编译后的文件称之为编译单元(CU)
■网友
泻药,GNU工具链中的binutils创建了一个完整的符号hash表:
struct bfd_hash_entry *bfd_hash_lookup (struct bfd_hash_table *table,\t\t const char *string,\t\t bfd_boolean create,\t\t bfd_boolean copy){ unsigned long hash; struct bfd_hash_entry *hashp; unsigned int len; unsigned int _index; hash = bfd_hash_hash (string, \u0026amp;len); _index = hash % table-\u0026gt;size; for (hashp = table-\u0026gt;table; hashp != NULL; hashp = hashp-\u0026gt;next) { if (hashp-\u0026gt;hash == hash\t \u0026amp;\u0026amp; strcmp (hashp-\u0026gt;string, string) == 0)\treturn hashp; // 找到了该Symbol } if (! create) return NULL; if (copy) { char *new_string; new_string = (char *) objalloc_alloc ((struct objalloc *) table-\u0026gt;memory,\t\t\t\t\t len + 1); if (!new_string)\t{\t bfd_set_error (bfd_error_no_memory);\t return NULL;\t} memcpy (new_string, string, len + 1); string = new_string; } return bfd_hash_insert (table, string, hash); // 没找到Symbol创建之}Clang前端生成的抽象语法树,通过中间代码生成(编译原理第6章),转换成LLVM IR的Module是面向单个文件的,在DragonEgg(将GIMPLE翻译成LLVM IR)xiangzhai/dragonegg 的代码中可以清楚看到:
/// CreateTargetMachine - Create the TargetMachine we will generate code with.static void CreateTargetMachine(const std::string \u0026amp;TargetTriple) { // Create the module itself. // ModuleID使用的是单个文件 StringRef ModuleID = main_input_filename ? main_input_filename : ""; TheModule = new Module(ModuleID, TheContext); ...}也可以查看LLVM IR Module的构造函数的定义:
/// The Module constructor. Note that there is no default constructor. You/// must provide a name for the module upon construction.explicit Module(StringRef ModuleID, LLVMContext\u0026amp; C);甚至可以直接看LLVM IR文件:
; ModuleID = \u0026#39;foo.c\u0026#39; 单个文件source_filename = "foo.c"target datalayout = "e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"target triple = "avr"define i16 @foo() { %n = alloca i16, align 1 %call = call i16 bitcast (i16 (...)* @bar to i16 ()*)() store i16 %call, i16* %n, align 1 %0 = load i16, i16* %n, align 1 ret i16 %0}


推荐阅读