訊息
|
檔案列表
檔案 |
必要性 |
說明 |
tcc.c |
O |
編譯器主程式 (參數處理) |
tcc.h |
O |
tcc.c 的定義檔 |
tccpp.c |
O* |
巨集處理器 (PreProcessor) (2935 行) |
tccgen.c |
O* |
程式碼產生與 Parser 剖析函數 (5121 行) |
libtcc.h |
O* |
雜湊表、符號表、字串函數,還包含 tcc_compile() 等編譯器函數,Parser 等 (2260 行) |
tcctok.h |
O |
Tokenizer (Scanner) |
il-gen.c |
O |
中間碼產生 (Intermediate Language) |
tccasm.c |
X |
組譯器 (Assembler) |
tcccoff.c |
X |
COFF 目的碼產生 |
tccelf.c |
X |
ELF 目的碼產生 |
tccpe.c |
X |
PE 目的碼產生 |
arm-gen.c |
X |
ARM 目的碼產生 |
c67-gen.c |
X |
C67 目的碼產生 |
x86_64-gen.c |
X |
x86 64 bit 程式碼產生 |
i386-gen.c |
X |
i386 程式碼產生 |
i386-asm.c |
X |
i386 組譯器 |
i386-asm.h |
X |
i386 組譯器定義檔 |
elf.h |
X |
ELF 定義檔 |
il-opcodes.h |
X |
中間碼定義檔 |
stab.h |
X |
Indicate the GNU stab.h is in use. |
必要性指的是對開放電腦的必要性。
功能 |
檔案 |
說明 |
編譯器 (Compiler) |
tcc.c, |
|
剖析器 (Parser) |
tccpp.c |
|
組譯器 (Assembler) |
tccasm.c , i386-asm.c |
|
中間碼產生 (P-Code) |
tccgen.c, il-gen.c |
|
目的檔格式 (ObjCode) |
tccelf.c, tcccoff.c, tccpe.c |
|
程式碼產生 (Code-Gen) |
tccgen.c, il-gen.c, arm-gen.c, c67-gen.c, x86_64-gen.c, i386-gen.c |
|
TinyCC 架構追蹤解讀:
tcc.c:main() => tcc_add_file() => libtcc:tcc_add_file_internal() => tcc_preprocess() or tcc_compile() or tcc_assemble()
tcc_compile() => 奇怪的事情,tcc_compile() 當中竟然找不到剖析動作的開始點。???
但事實上不是,真正的剖析起始點是 tcc_compile() 中位於 libtcc:1216 行的 decl(VT_CONST) 這個指令。
而 decl() 的宣告在 tccgen:4942 行的 static void decl(int l) ,其中的參數 l 可能是 VT_LOCAL or VT_CONST ,代表是在全域變數區還是區域變數區。
看來像是 tccgen:gen_inline_functions() => gen_function() /* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */
=> i386-gen.c:gfunc_prolog(&sym->type); … libtcc:block(NULL, NULL, NULL, NULL, 0, 0);… i386-gen.c:gfunc_epilog();
=> 賓果:真正的剖析器主程式在 block 函數當中,剖析 { …. } 的程式區塊。(tccgen.c:3790~4132行, 後續到 5121 行檔案結束都是剖析程式)
很可惜 TinyCC 在程式中沒有列出對應 C 語言的 EBNF 語法,這使得程式並不容易讀懂。可惜阿可惜!
若要將 TinyCC 移植到新的 CPU 上,似乎只要加入一個 xxx-gen.c 就行了,不知道這樣的猜測對不對呢?
移植時似乎必須有下列函數。
void o(unsigned int c)
void gsym_addr(int t, int a)
void gsym(int t)
void load(int r, SValue *sv)
void store(int r, SValue *v)
static void gadd_sp(int val)
static void gcall_or_jmp(int is_jmp)
void gfunc_call(int nb_args)
void gfunc_prolog(CType *func_type)
void gfunc_epilog(void)
int gjmp(int t)
void gjmp_addr(int a)
int gtst(int inv, int t)
void gen_opi(int op)
void gen_opf(int op)
void gen_cvt_itof(int t) // arm-gen.c 當中沒有
void gen_cvt_ftoi(int t)
void gen_cvt_ftof(int t)
void ggoto(void)
void gen_bounded_ptr_add(void) // arm-gen.c 當中沒有
/* compile the C file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1)
{
Sym *define_start;
char buf[512];
volatile int section_sym;
#ifdef INC_DEBUG
printf("%s: **** new file\n", file->filename);
#endif
preprocess_init(s1);
cur_text_section = NULL;
funcname = "";
anon_sym = SYM_FIRST_ANOM;
/* file info: full path + filename */
section_sym = 0; /* avoid warning */
if (s1->do_debug) {
section_sym = put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
text_section->sh_num, NULL);
getcwd(buf, sizeof(buf));
#ifdef _WIN32
normalize_slashes(buf);
#endif
pstrcat(buf, sizeof(buf), "/");
put_stabs_r(buf, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
put_stabs_r(file->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
}
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
symbols can be safely used */
put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
SHN_ABS, file->filename);
/* define some often used types */
int_type.t = VT_INT;
char_pointer_type.t = VT_BYTE;
mk_pointer(&char_pointer_type);
func_old_type.t = VT_FUNC;
func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
float_type.t = VT_FLOAT;
double_type.t = VT_DOUBLE;
func_float_type.t = VT_FUNC;
func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
func_double_type.t = VT_FUNC;
func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
#endif
#if 0
/* define 'void *alloca(unsigned int)' builtin function */
{
Sym *s1;
p = anon_sym++;
sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
s1->next = NULL;
sym->next = s1;
sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
}
#endif
define_start = define_stack;
nocode_wanted = 1;
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
next();
decl(VT_CONST);
if (tok != TOK_EOF)
expect("declaration");
/* end of translation unit info */
if (s1->do_debug) {
put_stabs_r(NULL, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
}
}
s1->error_set_jmp_enabled = 0;
/* reset define stack, but leave -Dsymbols (may be incorrect if
they are undefined) */
free_defines(define_start);
gen_inline_functions();
sym_pop(&global_stack, NULL);
sym_pop(&local_stack, NULL);
return s1->nb_errors != 0 ? -1 : 0;
}
Facebook
|
TCC为了加速,直接手工分析,当然也没必要列出EBEF了。TCC最精彩的部分就是“编译期虚拟机”,用这个虚拟机来构造代码。
Post preview:
Close preview