/* NOTE: the same name space as C labels is used to avoid using too much memory when storing labels in TokenStrings */ static void asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value) { Sym *sym; sym = label_find(label); if (sym) { if (sym->r) { /* the label is already defined */ if (!is_local) { tcc_error("assembler label '%s' already defined", get_tok_str(label, NULL)); } else { /* redefinition of local labels is possible */ goto new_label; } } } else { new_label: sym = label_push(&s1->asm_labels, label, 0); sym->type.t = VT_STATIC | VT_VOID; } sym->r = sh_num; sym->jnext = value; }
static int negcc(int cc) { switch(cc) { case TOK_ULT: return TOK_UGE; case TOK_UGE: return TOK_ULT; case TOK_EQ: return TOK_NE; case TOK_NE: return TOK_EQ; case TOK_ULE: return TOK_UGT; case TOK_UGT: return TOK_ULE; case TOK_Nset: return TOK_Nclear; case TOK_Nclear: return TOK_Nset; case TOK_LT: return TOK_GE; case TOK_GE: return TOK_LT; case TOK_LE: return TOK_GT; case TOK_GT: return TOK_LE; } tcc_error("unexpected condition code"); return TOK_NE; }
static void exec_other_tcc(TCCState *s, char **argv, const char *optarg) { char child_path[4096], *child_name; const char *target; switch (atoi(optarg)) { #ifdef TCC_TARGET_I386 case 32: break; case 64: target = "x86_64"; #else case 64: break; case 32: target = "i386"; #endif pstrcpy(child_path, sizeof child_path - 40, argv[0]); child_name = tcc_basename(child_path); strcpy(child_name, target); #ifdef TCC_TARGET_PE strcat(child_name, "-win32"); #endif strcat(child_name, "-tcc"); if (strcmp(argv[0], child_path)) { if (s->verbose > 0) printf("tcc: using '%s'\n", child_name), fflush(stdout); execvp(argv[0] = child_path, argv); } tcc_error("'%s' not found", child_name); case 0: /* ignore -march etc. */ break; default: tcc_warning("unsupported option \"-m%s\"", optarg); } }
static void gen_makedeps(TCCState *s, const char *target, const char *filename) { FILE *depout; char buf[1024], *ext; int i; if (!filename) { /* compute filename automatically * dir/file.o -> dir/file.d */ pstrcpy(buf, sizeof(buf), target); ext = tcc_fileextension(buf); pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); filename = buf; } if (s->verbose) printf("<- %s\n", filename); /* XXX return err codes instead of error() ? */ depout = fopen(filename, "w"); if (!depout) tcc_error("could not open '%s'", filename); fprintf(depout, "%s : \\\n", target); for (i=0; i<s->nb_target_deps; ++i) fprintf(depout, " %s \\\n", s->target_deps[i]); fprintf(depout, "\n"); fclose(depout); }
static uint32_t mapcc(int cc) { switch(cc) { case TOK_ULT: return 0x30000000; /* CC/LO */ case TOK_UGE: return 0x20000000; /* CS/HS */ case TOK_EQ: return 0x00000000; /* EQ */ case TOK_NE: return 0x10000000; /* NE */ case TOK_ULE: return 0x90000000; /* LS */ case TOK_UGT: return 0x80000000; /* HI */ case TOK_Nset: return 0x40000000; /* MI */ case TOK_Nclear: return 0x50000000; /* PL */ case TOK_LT: return 0xB0000000; /* LT */ case TOK_GE: return 0xA0000000; /* GE */ case TOK_LE: return 0xD0000000; /* LE */ case TOK_GT: return 0xC0000000; /* GT */ } tcc_error("unexpected condition code"); return 0xE0000000; /* AL */ }
static void asm_expr_logic(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_prod(s1, pe); for(;;) { op = tok; if (op != '&' && op != '|' && op != '^') break; next(); asm_expr_prod(s1, &e2); if (pe->sym || e2.sym) tcc_error("invalid operation with label"); switch(op) { case '&': pe->v &= e2.v; break; case '|': pe->v |= e2.v; break; default: case '^': pe->v ^= e2.v; break; } } }
static uint32_t intr(int r) { if(r==4) return 12; if((r<0 || r>4) && r!=14) tcc_error("compiler error! register %i is no int register",r); return r; }
/* push function parameter which is in (vtop->t, vtop->c). Stack entry is then popped. */ void gfunc_param(GFuncContext *c) { if ((vtop->t & VT_BTYPE) == VT_STRUCT) { tcc_error("structures passed as value not handled yet"); } else { /* simply push on stack */ gv(RC_ST0); } vtop--; }
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) { const char *ext; int ret; /* find source file type with extension */ ext = tcc_fileextension (filename); if (ext[0]) { ext++; } /* open the file */ ret = tcc_open (s1, filename); if (ret < 0) { if (flags & AFF_PRINT_ERROR) { tcc_error ("file '%s' not found", filename); } return ret; } /* update target deps */ dynarray_add ((void ***) &s1->target_deps, &s1->nb_target_deps, strdup (filename)); if (flags & AFF_PREPROCESS) { ret = tcc_preprocess (s1); goto the_end; } if (!ext[0] || !PATHCMP (ext, "c") || !PATHCMP (ext, "h") || !PATHCMP (ext, "cparse")) { /* C file assumed */ ret = tcc_compile (s1); goto the_end; } if (ret < 0) { tcc_error ("unrecognized file type"); } the_end: tcc_close (); return ret; }
ST_FUNC uint32_t encbranch(int pos, int addr, int fail) { addr-=pos+8; addr/=4; if(addr>=0x1000000 || addr<-0x1000000) { if(fail) tcc_error("FIXME: function bigger than 32MB"); return 0; } return 0x0A000000|(addr&0xffffff); }
static void asm_expr_prod(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_unary(s1, pe); for(;;) { op = tok; if (op != '*' && op != '/' && op != '%' && op != TOK_SHL && op != TOK_SAR) break; next(); asm_expr_unary(s1, &e2); if (pe->sym || e2.sym) tcc_error("invalid operation with label"); switch(op) { case '*': pe->v *= e2.v; break; case '/': if (e2.v == 0) { div_error: tcc_error("division by zero"); } pe->v /= e2.v; break; case '%': if (e2.v == 0) goto div_error; pe->v %= e2.v; break; case TOK_SHL: pe->v <<= e2.v; break; default: case TOK_SAR: pe->v >>= e2.v; break; } } }
Section *FindSection(TCCState * s1, const char *sname) { Section *s; int i; for (i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if (!strcmp(sname, s->name)) return s; } tcc_error("could not find section %s", sname); return 0; }
void o(uint32_t i) { /* this is a good place to start adding big-endian support*/ int ind1; ind1 = ind + 4; if (!cur_text_section) tcc_error("compiler error! This happens f.ex. if the compiler\n" "can't evaluate constant expressions outside of a function."); if (ind1 > cur_text_section->data_allocated) section_realloc(cur_text_section, ind1); cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i; }
static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) { int op; ExprValue e2; asm_expr_logic(s1, pe); for(;;) { op = tok; if (op != '+' && op != '-') break; next(); asm_expr_logic(s1, &e2); if (op == '+') { if (pe->sym != NULL && e2.sym != NULL) goto cannot_relocate; pe->v += e2.v; if (pe->sym == NULL && e2.sym != NULL) pe->sym = e2.sym; } else { pe->v -= e2.v; /* NOTE: we are less powerful than gas in that case because we store only one symbol in the expression */ if (!pe->sym && !e2.sym) { /* OK */ } else if (pe->sym && !e2.sym) { /* OK */ } else if (pe->sym && e2.sym) { if (pe->sym == e2.sym) { /* OK */ } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) { /* we also accept defined symbols in the same section */ pe->v += pe->sym->jnext - e2.sym->jnext; } else { goto cannot_relocate; } pe->sym = NULL; /* same symbols can be subtracted to NULL */ } else { cannot_relocate: tcc_error("invalid operation with label"); } } } }
/* patch pointer addition in vtop so that pointer dereferencing is also tested */ ST_FUNC void gen_bounded_ptr_deref(void) { int func; int size, align; Elf32_Rel *rel; Sym *sym; size = 0; /* XXX: put that code in generic part of tcc */ if (!is_float(vtop->type.t)) { if (vtop->r & VT_LVAL_BYTE) size = 1; else if (vtop->r & VT_LVAL_SHORT) size = 2; } if (!size) size = type_size(&vtop->type, &align); switch(size) { case 1: func = TOK___bound_ptr_indir1; break; case 2: func = TOK___bound_ptr_indir2; break; case 4: func = TOK___bound_ptr_indir4; break; case 8: func = TOK___bound_ptr_indir8; break; case 12: func = TOK___bound_ptr_indir12; break; case 16: func = TOK___bound_ptr_indir16; break; default: tcc_error("unhandled size when dereferencing bounded pointer"); func = 0; break; } /* patch relocation */ /* XXX: find a better solution ? */ rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul); sym = external_global_sym(func, &func_old_type, 0); if (!sym->c) put_extern_sym(sym, NULL, 0, 0); rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); }
int main(int argc, char **argv) { TCCState *s; int ret, optind, i; int64_t start_time = 0; s = tcc_new(); optind = tcc_parse_args(s, argc - 1, argv + 1); if (s->do_bench) start_time = getclock_us(); tcc_set_environment(s); if (optind == 0) { help(); return 1; } if (s->option_m) exec_other_tcc(s, argv, s->option_m); if (s->verbose) display_info(s, 0); if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) { tcc_set_output_type(s, TCC_OUTPUT_MEMORY); display_info(s, 1); return 0; } if (s->verbose && optind == 1) return 0; if (s->nb_files == 0) tcc_error("no input files\n"); /* check -c consistency : only single file handled. XXX: checks file type */ if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { if (s->nb_libraries != 0) tcc_error("cannot specify libraries with -c"); /* accepts only a single input file */ if ((s->nb_files != 1) && s->outfile) { tcc_error("cannot specify multiple files with -c and -o"); } } if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (!s->outfile) { s->ppfp = stdout; } else { s->ppfp = fopen(s->outfile, "w"); if (!s->ppfp) tcc_error("could not write '%s'", s->outfile); } } tcc_set_output_type(s, s->output_type); /* compile or add each files or library */ for(i = ret = 0; i < s->nb_files && ret == 0; i++) { int filetype = *(unsigned char *)s->files[i]; const char *filename = s->files[i] + 1; if (filename[0] == '-' && filename[1] == 'l') { if (tcc_add_library(s, filename + 2) < 0) { tcc_error_noabort("cannot find library 'lib%s'", filename+2); ret = 1; } } else { if (1 == s->verbose) printf("-> %s\n", filename); if (!s->outfile) s->outfile = default_outputfile(s, filename); if (tcc_add_file(s, filename, filetype) < 0) ret = 1; else if (s->output_type == TCC_OUTPUT_OBJ) { ret = !!tcc_output_file(s, s->outfile); if (s->gen_deps && !ret) gen_makedeps(s, s->outfile, s->deps_outfile); if (!ret) { if ((i+1) < s->nb_files) { tcc_delete(s); s = tcc_new(); tcc_parse_args(s, argc - 1, argv + 1); tcc_set_environment(s); if (s->output_type != TCC_OUTPUT_OBJ) tcc_error("interlnal error"); tcc_set_output_type(s, s->output_type); } } } } } if (0 == ret) { if (s->output_type == TCC_OUTPUT_MEMORY) { #ifdef TCC_IS_NATIVE ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); #else tcc_error_noabort("-run is not available in a cross compiler"); ret = 1; #endif } else if (s->output_type == TCC_OUTPUT_EXE || s->output_type == TCC_OUTPUT_DLL) { ret = !!tcc_output_file(s, s->outfile); if (s->gen_deps && !ret) gen_makedeps(s, s->outfile, s->deps_outfile); } } if (s->do_bench) tcc_print_stats(s, getclock_us() - start_time); tcc_delete(s); return ret; }
/* XXX: not complete */ static void il_type_to_str(char *buf, int buf_size, int t, const char *varstr) { int bt; Sym *s, *sa; char buf1[256]; const char *tstr; t = t & VT_TYPE; bt = t & VT_BTYPE; buf[0] = '\0'; if (t & VT_UNSIGNED) pstrcat(buf, buf_size, "unsigned "); switch(bt) { case VT_VOID: tstr = "void"; goto add_tstr; case VT_BOOL: tstr = "bool"; goto add_tstr; case VT_BYTE: tstr = "int8"; goto add_tstr; case VT_SHORT: tstr = "int16"; goto add_tstr; case VT_ENUM: case VT_INT: case VT_LONG: tstr = "int32"; goto add_tstr; case VT_LLONG: tstr = "int64"; goto add_tstr; case VT_FLOAT: tstr = "float32"; goto add_tstr; case VT_DOUBLE: case VT_LDOUBLE: tstr = "float64"; add_tstr: pstrcat(buf, buf_size, tstr); break; case VT_STRUCT: tcc_error("structures not handled yet"); break; case VT_FUNC: s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); il_type_to_str(buf, buf_size, s->t, varstr); pstrcat(buf, buf_size, "("); sa = s->next; while (sa != NULL) { il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); pstrcat(buf, buf_size, buf1); sa = sa->next; if (sa) pstrcat(buf, buf_size, ", "); } pstrcat(buf, buf_size, ")"); goto no_var; case VT_PTR: s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); pstrcpy(buf1, sizeof(buf1), "*"); if (varstr) pstrcat(buf1, sizeof(buf1), varstr); il_type_to_str(buf, buf_size, s->t, buf1); goto no_var; } if (varstr) { pstrcat(buf, buf_size, " "); pstrcat(buf, buf_size, varstr); } no_var: ; }
ST_FUNC int tcc_load_coff(TCCState * s1, int fd) { // tktk TokenSym *ts; FILE *f; unsigned int str_size; char *Coff_str_table, *name; int i, k; struct syment csym; char name2[9]; FILHDR file_hdr; /* FILE HEADER STRUCTURE */ f = fdopen(fd, "rb"); if (!f) { tcc_error("Unable to open .out file for input"); } if (fread(&file_hdr, FILHSZ, 1, f) != 1) tcc_error("error reading .out file for input"); if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1) tcc_error("error reading .out file for input"); // first read the string table if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET)) tcc_error("error reading .out file for input"); if (fread(&str_size, sizeof(int), 1, f) != 1) tcc_error("error reading .out file for input"); Coff_str_table = (char *) tcc_malloc(str_size); if (fread(Coff_str_table, str_size - 4, 1, f) != 1) tcc_error("error reading .out file for input"); // read/process all the symbols // seek back to symbols if (fseek(f, file_hdr.f_symptr, SEEK_SET)) tcc_error("error reading .out file for input"); for (i = 0; i < file_hdr.f_nsyms; i++) { if (fread(&csym, SYMESZ, 1, f) != 1) tcc_error("error reading .out file for input"); if (csym._n._n_n._n_zeroes == 0) { name = Coff_str_table + csym._n._n_n._n_offset - 4; } else { name = csym._n._n_name; if (name[7] != 0) { for (k = 0; k < 8; k++) name2[k] = name[k]; name2[8] = 0; name = name2; } } // if (strcmp("_DAC_Buffer",name)==0) // tktk // name[0]=0; if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures (csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure (csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles (csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats { // strip off any leading underscore (except for other main routine) if (name[0] == '_' && strcmp(name, "_main") != 0) name++; tcc_add_symbol(s1, name, (void*)(uplong)csym.n_value); } // skip any aux records if (csym.n_numaux == 1) { if (fread(&csym, SYMESZ, 1, f) != 1) tcc_error("error reading .out file for input"); i++; } } return 0; }
ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f) { Section *tcc_sect; SCNHDR *coff_sec; int file_pointer; char *Coff_str_table, *pCoff_str_table; int CoffTextSectionNo, coff_nb_syms; FILHDR file_hdr; /* FILE HEADER STRUCTURE */ Section *stext, *sdata, *sbss; int i, NSectionsToOutput = 0; Coff_str_table = pCoff_str_table = NULL; stext = FindSection(s1, ".text"); sdata = FindSection(s1, ".data"); sbss = FindSection(s1, ".bss"); nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1"); file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */ file_hdr.f_timdat = 0; /* time & date stamp */ file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */ file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */ file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */ o_filehdr.magic = 0x0108; /* see magic.h */ o_filehdr.vstamp = 0x0190; /* version stamp */ o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */ o_filehdr.dsize = sdata->data_offset; /* initialized data " " */ o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */ o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */ o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */ o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */ // create all the section headers file_pointer = FILHSZ + sizeof(AOUTHDR); CoffTextSectionNo = -1; for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { NSectionsToOutput++; if (CoffTextSectionNo == -1 && tcc_sect == stext) CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is strcpy(coff_sec->s_name, tcc_sect->name); /* section name */ coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */ coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */ coff_sec->s_size = tcc_sect->data_offset; /* section size */ coff_sec->s_scnptr = 0; /* file ptr to raw data for section */ coff_sec->s_relptr = 0; /* file ptr to relocation */ coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */ coff_sec->s_nreloc = 0; /* number of relocation entries */ coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */ coff_sec->s_reserved = 0; /* reserved byte */ coff_sec->s_page = 0; /* memory page id */ file_pointer += sizeof(SCNHDR); } } file_hdr.f_nscns = NSectionsToOutput; /* number of sections */ // now loop through and determine file pointer locations // for the raw data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { // put raw data coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */ file_pointer += coff_sec->s_size; } } // now loop through and determine file pointer locations // for the relocation data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { // put relocations data if (coff_sec->s_nreloc > 0) { coff_sec->s_relptr = file_pointer; /* file ptr to relocation */ file_pointer += coff_sec->s_nreloc * sizeof(struct reloc); } } } // now loop through and determine file pointer locations // for the line number data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; coff_sec->s_nlnno = 0; coff_sec->s_lnnoptr = 0; if (s1->do_debug && tcc_sect == stext) { // count how many line nos data // also find association between source file name and function // so we can sort the symbol table Stab_Sym *sym, *sym_end; char func_name[MAX_FUNC_NAME_LENGTH], last_func_name[MAX_FUNC_NAME_LENGTH]; unsigned long func_addr, last_pc, pc; const char *incl_files[INCLUDE_STACK_SIZE]; int incl_index, len, last_line_num; const char *str, *p; coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */ func_name[0] = '\0'; func_addr = 0; incl_index = 0; last_func_name[0] = '\0'; last_pc = 0xffffffff; last_line_num = 1; sym = (Stab_Sym *) stab_section->data + 1; sym_end = (Stab_Sym *) (stab_section->data + stab_section->data_offset); nFuncs = 0; while (sym < sym_end) { switch (sym->n_type) { /* function start or end */ case N_FUN: if (sym->n_strx == 0) { // end of function coff_sec->s_nlnno++; file_pointer += LINESZ; pc = sym->n_value + func_addr; func_name[0] = '\0'; func_addr = 0; EndAddress[nFuncs] = pc; FuncEntries[nFuncs] = (file_pointer - LineNoFilePtr[nFuncs]) / LINESZ - 1; LastLineNo[nFuncs++] = last_line_num + 1; } else { // beginning of function LineNoFilePtr[nFuncs] = file_pointer; coff_sec->s_nlnno++; file_pointer += LINESZ; str = (const char *) stabstr_section->data + sym->n_strx; p = strchr(str, ':'); if (!p) { pstrcpy(func_name, sizeof(func_name), str); pstrcpy(Func[nFuncs], sizeof(func_name), str); } else { len = p - str; if (len > sizeof(func_name) - 1) len = sizeof(func_name) - 1; memcpy(func_name, str, len); memcpy(Func[nFuncs], str, len); func_name[len] = '\0'; } // save the file that it came in so we can sort later pstrcpy(AssociatedFile[nFuncs], sizeof(func_name), incl_files[incl_index - 1]); func_addr = sym->n_value; } break; /* line number info */ case N_SLINE: pc = sym->n_value + func_addr; last_pc = pc; last_line_num = sym->n_desc; /* XXX: slow! */ strcpy(last_func_name, func_name); coff_sec->s_nlnno++; file_pointer += LINESZ; break; /* include files */ case N_BINCL: str = (const char *) stabstr_section->data + sym->n_strx; add_incl: if (incl_index < INCLUDE_STACK_SIZE) { incl_files[incl_index++] = str; } break; case N_EINCL: if (incl_index > 1) incl_index--; break; case N_SO: if (sym->n_strx == 0) { incl_index = 0; /* end of translation unit */ } else { str = (const char *) stabstr_section->data + sym->n_strx; /* do not add path */ len = strlen(str); if (len > 0 && str[len - 1] != '/') goto add_incl; } break; } sym++; } } } file_hdr.f_symptr = file_pointer; /* file pointer to symtab */ if (s1->do_debug) file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */ else file_hdr.f_nsyms = 0; file_pointer += file_hdr.f_nsyms * SYMNMLEN; // OK now we are all set to write the file fwrite(&file_hdr, FILHSZ, 1, f); fwrite(&o_filehdr, sizeof(o_filehdr), 1, f); // write section headers for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { fwrite(coff_sec, sizeof(SCNHDR), 1, f); } } // write raw data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f); } } // write relocation data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (OutputTheSection(tcc_sect)) { // put relocations data if (coff_sec->s_nreloc > 0) { fwrite(tcc_sect->reloc, coff_sec->s_nreloc * sizeof(struct reloc), 1, f); } } } // group the symbols in order of filename, func1, func2, etc // finally global symbols if (s1->do_debug) SortSymbolTable(); // write line no data for (i = 1; i < s1->nb_sections; i++) { coff_sec = §ion_header[i]; tcc_sect = s1->sections[i]; if (s1->do_debug && tcc_sect == stext) { // count how many line nos data Stab_Sym *sym, *sym_end; char func_name[128], last_func_name[128]; unsigned long func_addr, last_pc, pc; const char *incl_files[INCLUDE_STACK_SIZE]; int incl_index, len, last_line_num; const char *str, *p; LINENO CoffLineNo; func_name[0] = '\0'; func_addr = 0; incl_index = 0; last_func_name[0] = '\0'; last_pc = 0; last_line_num = 1; sym = (Stab_Sym *) stab_section->data + 1; sym_end = (Stab_Sym *) (stab_section->data + stab_section->data_offset); while (sym < sym_end) { switch (sym->n_type) { /* function start or end */ case N_FUN: if (sym->n_strx == 0) { // end of function CoffLineNo.l_addr.l_paddr = last_pc; CoffLineNo.l_lnno = last_line_num + 1; fwrite(&CoffLineNo, 6, 1, f); pc = sym->n_value + func_addr; func_name[0] = '\0'; func_addr = 0; } else { // beginning of function str = (const char *) stabstr_section->data + sym->n_strx; p = strchr(str, ':'); if (!p) { pstrcpy(func_name, sizeof(func_name), str); } else { len = p - str; if (len > sizeof(func_name) - 1) len = sizeof(func_name) - 1; memcpy(func_name, str, len); func_name[len] = '\0'; } func_addr = sym->n_value; last_pc = func_addr; last_line_num = -1; // output a function begin CoffLineNo.l_addr.l_symndx = FindCoffSymbolIndex(func_name); CoffLineNo.l_lnno = 0; fwrite(&CoffLineNo, 6, 1, f); } break; /* line number info */ case N_SLINE: pc = sym->n_value + func_addr; /* XXX: slow! */ strcpy(last_func_name, func_name); // output a line reference CoffLineNo.l_addr.l_paddr = last_pc; if (last_line_num == -1) { CoffLineNo.l_lnno = sym->n_desc; } else { CoffLineNo.l_lnno = last_line_num + 1; } fwrite(&CoffLineNo, 6, 1, f); last_pc = pc; last_line_num = sym->n_desc; break; /* include files */ case N_BINCL: str = (const char *) stabstr_section->data + sym->n_strx; add_incl2: if (incl_index < INCLUDE_STACK_SIZE) { incl_files[incl_index++] = str; } break; case N_EINCL: if (incl_index > 1) incl_index--; break; case N_SO: if (sym->n_strx == 0) { incl_index = 0; /* end of translation unit */ } else { str = (const char *) stabstr_section->data + sym->n_strx; /* do not add path */ len = strlen(str); if (len > 0 && str[len - 1] != '/') goto add_incl2; } break; } sym++; } } } // write symbol table if (s1->do_debug) { int k; struct syment csym; AUXFUNC auxfunc; AUXBF auxbf; AUXEF auxef; int i; Elf32_Sym *p; const char *name; int nstr; int n = 0; Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE); pCoff_str_table = Coff_str_table; nstr = 0; p = (Elf32_Sym *) symtab_section->data; for (i = 0; i < nb_syms; i++) { name = symtab_section->link->data + p->st_name; for (k = 0; k < 8; k++) csym._n._n_name[k] = 0; if (strlen(name) <= 8) { strcpy(csym._n._n_name, name); } else { if (pCoff_str_table - Coff_str_table + strlen(name) > MAX_STR_TABLE - 1) tcc_error("String table too large"); csym._n._n_n._n_zeroes = 0; csym._n._n_n._n_offset = pCoff_str_table - Coff_str_table + 4; strcpy(pCoff_str_table, name); pCoff_str_table += strlen(name) + 1; // skip over null nstr++; } if (p->st_info == 4) { // put a filename symbol csym.n_value = 33; // ????? csym.n_scnum = N_DEBUG; csym.n_type = 0; csym.n_sclass = C_FILE; csym.n_numaux = 0; fwrite(&csym, 18, 1, f); n++; } else if (p->st_info == 0x12) { // find the function data for (k = 0; k < nFuncs; k++) { if (strcmp(name, Func[k]) == 0) break; } if (k >= nFuncs) { tcc_error("debug info can't find function: %s", name); } // put a Function Name csym.n_value = p->st_value; // physical address csym.n_scnum = CoffTextSectionNo; csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0); csym.n_sclass = C_EXT; csym.n_numaux = 1; fwrite(&csym, 18, 1, f); // now put aux info auxfunc.tag = 0; auxfunc.size = EndAddress[k] - p->st_value; auxfunc.fileptr = LineNoFilePtr[k]; auxfunc.nextsym = n + 6; // tktk auxfunc.dummy = 0; fwrite(&auxfunc, 18, 1, f); // put a .bf strcpy(csym._n._n_name, ".bf"); csym.n_value = p->st_value; // physical address csym.n_scnum = CoffTextSectionNo; csym.n_type = 0; csym.n_sclass = C_FCN; csym.n_numaux = 1; fwrite(&csym, 18, 1, f); // now put aux info auxbf.regmask = 0; auxbf.lineno = 0; auxbf.nentries = FuncEntries[k]; auxbf.localframe = 0; auxbf.nextentry = n + 6; auxbf.dummy = 0; fwrite(&auxbf, 18, 1, f); // put a .ef strcpy(csym._n._n_name, ".ef"); csym.n_value = EndAddress[k]; // physical address csym.n_scnum = CoffTextSectionNo; csym.n_type = 0; csym.n_sclass = C_FCN; csym.n_numaux = 1; fwrite(&csym, 18, 1, f); // now put aux info auxef.dummy = 0; auxef.lineno = LastLineNo[k]; auxef.dummy1 = 0; auxef.dummy2 = 0; auxef.dummy3 = 0; auxef.dummy4 = 0; fwrite(&auxef, 18, 1, f); n += 6; } else { // try an put some type info if ((p->st_other & VT_BTYPE) == VT_DOUBLE) { csym.n_type = T_DOUBLE; // int csym.n_sclass = C_EXT; } else if ((p->st_other & VT_BTYPE) == VT_FLOAT) { csym.n_type = T_FLOAT; csym.n_sclass = C_EXT; } else if ((p->st_other & VT_BTYPE) == VT_INT) { csym.n_type = T_INT; // int csym.n_sclass = C_EXT; } else if ((p->st_other & VT_BTYPE) == VT_SHORT) { csym.n_type = T_SHORT; csym.n_sclass = C_EXT; } else if ((p->st_other & VT_BTYPE) == VT_BYTE) { csym.n_type = T_CHAR; csym.n_sclass = C_EXT; } else { csym.n_type = T_INT; // just mark as a label csym.n_sclass = C_LABEL; } csym.n_value = p->st_value; csym.n_scnum = 2; csym.n_numaux = 1; fwrite(&csym, 18, 1, f); auxfunc.tag = 0; auxfunc.size = 0x20; auxfunc.fileptr = 0; auxfunc.nextsym = 0; auxfunc.dummy = 0; fwrite(&auxfunc, 18, 1, f); n++; n++; } p++; } } if (s1->do_debug) { // write string table // first write the size i = pCoff_str_table - Coff_str_table; fwrite(&i, 4, 1, f); // then write the strings fwrite(Coff_str_table, i, 1, f); tcc_free(Coff_str_table); } return 0; }
void SortSymbolTable(void) { int i, j, k, n = 0; Elf32_Sym *p, *p2, *NewTable; char *name, *name2; NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym)); p = (Elf32_Sym *) symtab_section->data; // find a file symbol, copy it over // then scan the whole symbol list and copy any function // symbols that match the file association for (i = 0; i < nb_syms; i++) { if (p->st_info == 4) { name = (char *) symtab_section->link->data + p->st_name; // this is a file symbol, copy it over NewTable[n++] = *p; p2 = (Elf32_Sym *) symtab_section->data; for (j = 0; j < nb_syms; j++) { if (p2->st_info == 0x12) { // this is a func symbol name2 = (char *) symtab_section->link->data + p2->st_name; // find the function data index for (k = 0; k < nFuncs; k++) { if (strcmp(name2, Func[k]) == 0) break; } if (k >= nFuncs) { tcc_error("debug (sort) info can't find function: %s", name2); } if (strcmp(AssociatedFile[k], name) == 0) { // yes they match copy it over NewTable[n++] = *p2; } } p2++; } } p++; } // now all the filename and func symbols should have been copied over // copy all the rest over (all except file and funcs) p = (Elf32_Sym *) symtab_section->data; for (i = 0; i < nb_syms; i++) { if (p->st_info != 4 && p->st_info != 0x12) { NewTable[n++] = *p; } p++; } if (n != nb_syms) tcc_error("Internal Compiler error, debug info"); // copy it all back p = (Elf32_Sym *) symtab_section->data; for (i = 0; i < nb_syms; i++) { *p++ = NewTable[i]; } tcc_free(NewTable); }
static void asm_expr_unary(TCCState *s1, ExprValue *pe) { Sym *sym; int op, n, label; const char *p; switch(tok) { case TOK_PPNUM: p = tokc.cstr->data; n = strtoul(p, (char **)&p, 0); if (*p == 'b' || *p == 'f') { /* backward or forward label */ label = asm_get_local_label_name(s1, n); sym = label_find(label); if (*p == 'b') { /* backward : find the last corresponding defined label */ if (sym && sym->r == 0) sym = sym->prev_tok; if (!sym) tcc_error("local label '%d' not found backward", n); } else { /* forward */ if (!sym || sym->r) { /* if the last label is defined, then define a new one */ sym = label_push(&s1->asm_labels, label, 0); sym->type.t = VT_STATIC | VT_VOID; } } pe->v = 0; pe->sym = sym; } else if (*p == '\0') { pe->v = n; pe->sym = NULL; } else { tcc_error("invalid number syntax"); } next(); break; case '+': next(); asm_expr_unary(s1, pe); break; case '-': case '~': op = tok; next(); asm_expr_unary(s1, pe); if (pe->sym) tcc_error("invalid operation with label"); if (op == '-') pe->v = -pe->v; else pe->v = ~pe->v; break; case TOK_CCHAR: case TOK_LCHAR: pe->v = tokc.i; pe->sym = NULL; next(); break; case '(': next(); asm_expr(s1, pe); skip(')'); break; default: if (tok >= TOK_IDENT) { /* label case : if the label was not found, add one */ sym = label_find(tok); if (!sym) { sym = label_push(&s1->asm_labels, tok, 0); /* NOTE: by default, the symbol is global */ sym->type.t = VT_VOID; } if (sym->r == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ pe->v = sym->jnext; pe->sym = NULL; } else { pe->v = 0; pe->sym = sym; } next(); } else { tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); } break; } }
static void asm_parse_directive(TCCState *s1) { int n, offset, v, size, tok1; Section *sec; uint8_t *ptr; /* assembler directive */ next(); sec = cur_text_section; switch(tok) { case TOK_ASM_align: case TOK_ASM_p2align: case TOK_ASM_skip: case TOK_ASM_space: tok1 = tok; next(); n = asm_int_expr(s1); if (tok1 == TOK_ASM_p2align) { if (n < 0 || n > 30) tcc_error("invalid p2align, must be between 0 and 30"); n = 1 << n; tok1 = TOK_ASM_align; } if (tok1 == TOK_ASM_align) { if (n < 0 || (n & (n-1)) != 0) tcc_error("alignment must be a positive power of two"); offset = (ind + n - 1) & -n; size = offset - ind; /* the section must have a compatible alignment */ if (sec->sh_addralign < n) sec->sh_addralign = n; } else { size = n; } v = 0; if (tok == ',') { next(); v = asm_int_expr(s1); } zero_pad: if (sec->sh_type != SHT_NOBITS) { sec->data_offset = ind; ptr = section_ptr_add(sec, size); memset(ptr, v, size); } ind += size; break; case TOK_ASM_quad: next(); for(;;) { uint64_t vl; const char *p; p = tokc.cstr->data; if (tok != TOK_PPNUM) { error_constant: tcc_error("64 bit constant"); } vl = strtoll(p, (char **)&p, 0); if (*p != '\0') goto error_constant; next(); if (sec->sh_type != SHT_NOBITS) { /* XXX: endianness */ gen_le32(vl); gen_le32(vl >> 32); } else { ind += 8; } if (tok != ',') break; next(); }
static uint32_t fpr(int r) { if(r<TREG_F0 || r>TREG_F3) tcc_error("compiler error! register %i is no fpa register",r); return r-5; }