diff --git a/libtcc/Makefile.am b/libtcc/Makefile.am index e5d18acb..e4250274 100644 --- a/libtcc/Makefile.am +++ b/libtcc/Makefile.am @@ -1,6 +1,7 @@ noinst_LIBRARIES = libtcc.a -libtcc_a_SOURCES = libtcc.c option.c path.c memory.c tccpp.c tccgen.c \ - tccasm.c tccelf.c \ - i386/gen.c i386/link.c \ - i386/asm.c tcccoff.c +libtcc_a_SOURCES = libtcc.c option.c path.c io.c memory.c \ + cc/tccpp.c cc/tccgen.c \ + cc/tccasm.c tccelf.c \ + cc/i386/gen.c cc/i386/link.c \ + cc/i386/asm.c tcccoff.c libtcc_a_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) -I$(srcdir)/include \ No newline at end of file diff --git a/libtcc/cc/cc.h b/libtcc/cc/cc.h new file mode 100644 index 00000000..4cc9e26b --- /dev/null +++ b/libtcc/cc/cc.h @@ -0,0 +1,275 @@ +#ifndef TCC_CC_H +# define TCC_CC_H + +# include + +/* ------------ tccpp.c ------------ */ + +extern struct BufferedFile *file; +extern int tok; +extern CValue tokc; +extern const int *macro_ptr; +extern int parse_flags; +extern int tok_flags; +extern CString tokcstr; /* current parsed string, if any */ + +/* display benchmark infos */ +extern int tok_ident; +extern TokenSym **table_ident; +extern int pp_expr; + +#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ +#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ +#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ + +#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ +#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ +#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a + token. line feed is also + returned at eof */ +#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */ +#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ +#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */ +#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */ + +/* isidnum_table flags: */ +#define IS_SPC 1 +#define IS_ID 2 +#define IS_NUM 4 + +enum line_macro_output_format { + LINE_MACRO_OUTPUT_FORMAT_GCC, + LINE_MACRO_OUTPUT_FORMAT_NONE, + LINE_MACRO_OUTPUT_FORMAT_STD, + LINE_MACRO_OUTPUT_FORMAT_P10 = 11 +}; + +TokenSym *tok_alloc(const char *str, int len); +int tok_alloc_const(const char *str); +const char *get_tok_str(int v, CValue *cv); +void begin_macro(TokenString *str, int alloc); +void end_macro(void); +int set_idnum(int c, int val); +void tok_str_new(TokenString *s); +TokenString *tok_str_alloc(void); +void tok_str_free(TokenString *s); +void tok_str_free_str(int *str); +void tok_str_add(TokenString *s, int t); +void tok_str_add_tok(TokenString *s); +void define_push(int v, int macro_type, int *str, Sym *first_arg); +void define_undef(Sym *s); +Sym *define_find(int v); +void free_defines(Sym *b); +void parse_define(void); +void skip_to_eol(int warn); +void preprocess(int is_bof); +void next(void); +void unget_tok(int last_tok); +void preprocess_start(TCCState *s1, int filetype); +void preprocess_end(TCCState *s1); +void tccpp_new(TCCState *s); +void tccpp_delete(TCCState *s); +void tccpp_putfile(const char *filename); +int tcc_preprocess(TCCState *s1); +void skip(int c); +__attribute__((noreturn)) void expect(const char *msg); +void pp_error(CString *cs); + + +/* space excluding newline */ +static inline int is_space(int ch) { + return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; +} +static inline int isid(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; +} +static inline int isnum(int c) { + return c >= '0' && c <= '9'; +} +static inline int isoct(int c) { + return c >= '0' && c <= '7'; +} + +/* ------------ tccgen.c ------------ */ + +#define SYM_POOL_NB (8192 / sizeof(Sym)) + +extern Sym *global_stack; +extern Sym *local_stack; +extern Sym *local_label_stack; +extern Sym *global_label_stack; +extern Sym *define_stack; +extern CType int_type, func_old_type, char_pointer_type; +extern SValue *vtop; +extern int rsym, anon_sym, ind, loc; +extern char debug_modes; + +extern int nocode_wanted; /* true if no code generation wanted for an expression */ +extern int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ +extern CType func_vt; /* current function return type (used by return instruction) */ +extern int func_var; /* true if current function is variadic */ +extern int func_vc; +extern int func_ind; +extern const char *funcname; + +void tccgen_init(TCCState *s1); +int tccgen_compile(TCCState *s1); +void tccgen_finish(TCCState *s1); +void check_vstack(void); + +int is_float(int t); +int ieee_finite(double d); +int exact_log2p1(int i); +void test_lvalue(void); + +ElfSym *elfsym(Sym *); +void update_storage(Sym *sym); +void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore); +void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size); +#if PTR_SIZE == 4 +void greloc(Section *s, Sym *sym, unsigned long offset, int type); +#endif +void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); + +void sym_free(Sym *sym); +Sym *sym_push(int v, CType *type, int r, int c); +void sym_pop(Sym **ptop, Sym *b, int keep); +Sym *sym_push2(Sym **ps, int v, int t, int c); +Sym *sym_find2(Sym *s, int v); +Sym *sym_find(int v); +Sym *label_find(int v); +Sym *label_push(Sym **ptop, int v, int flags); +void label_pop(Sym **ptop, Sym *slast, int keep); +Sym *struct_find(int v); + +Sym *global_identifier_push(int v, int t, int c); +Sym *external_global_sym(int v, CType *type); +Sym *external_helper_sym(int v); +void vpush_helper_func(int v); +void vset(CType *type, int r, int v); +void vset_VT_CMP(int op); +void vpushi(int v); +void vpushv(SValue *v); +void vpushsym(CType *type, Sym *sym); +void vswap(void); +void vrott(int n); +void vrotb(int n); +void vrev(int n); +void vpop(void); +#if PTR_SIZE == 4 +void lexpand(void); +#endif +void save_reg(int r); +void save_reg_upstack(int r, int n); +int get_reg(int rc); +void save_regs(int n); +void gaddrof(void); +int gv(int rc); +void gv2(int rc1, int rc2); +void gen_op(int op); +int type_size(CType *type, int *a); +void mk_pointer(CType *type); +void vstore(void); +void inc(int post, int c); +CString* parse_mult_str(const char *msg); +CString* parse_asm_str(void); +void indir(void); +void unary(void); +void gexpr(void); +int expr_const(void); + +/* ------------ xxx-link.c ------------ */ + +#if !defined ELF_OBJ_ONLY +int code_reloc (int reloc_type); +#define NEED_RELOC_TYPE + +#endif + +void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val); + + +/* ------------ xxx-gen.c ------------ */ +extern const char * const target_machine_defs; +extern const int reg_classes[NB_REGS]; + +void gsym_addr(int t, int a); +void gsym(int t); +void load(int r, SValue *sv); +void store(int r, SValue *v); +int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); +void gfunc_call(int nb_args); +void gfunc_prolog(Sym *func_sym); +void gfunc_epilog(void); +void gen_fill_nops(int); +int gjmp(int t); +void gjmp_addr(int a); +int gjmp_cond(int op, int t); +int gjmp_append(int n, int t); +void gen_opi(int op); +void gen_opf(int op); +void gen_cvt_ftoi(int t); +void gen_cvt_itof(void); +void gen_cvt_ftof(void); +void ggoto(void); +void o(unsigned int c); +void gen_vla_sp_save(int addr); +void gen_vla_sp_restore(int addr); +void gen_vla_alloc(CType *type, int align); + +static inline uint16_t read16le(unsigned char *p) { + return p[0] | (uint16_t)p[1] << 8; +} +static inline void write16le(unsigned char *p, uint16_t x) { + p[0] = x & 255; p[1] = x >> 8 & 255; +} +static inline uint32_t read32le(unsigned char *p) { + return read16le(p) | (uint32_t)read16le(p + 2) << 16; +} +static inline void write32le(unsigned char *p, uint32_t x) { + write16le(p, x); write16le(p + 2, x >> 16); +} +static inline void add32le(unsigned char *p, int32_t x) { + write32le(p, read32le(p) + x); +} +static inline uint64_t read64le(unsigned char *p) { + return read32le(p) | (uint64_t)read32le(p + 4) << 32; +} +static inline void write64le(unsigned char *p, uint64_t x) { + write32le(p, x); write32le(p + 4, x >> 32); +} +static inline void add64le(unsigned char *p, int64_t x) { + write64le(p, read64le(p) + x); +} + +/* ------------ i386-gen.c ------------ */ +void g(int c); +void gen_le16(int c); +void gen_le32(int c); + +void gen_addr32(int r, Sym *sym, int c); +void gen_addrpc32(int r, Sym *sym, int c); +void gen_cvt_csti(int t); + +/* ------------ tccasm.c ------------ */ +void asm_instr(TCCState *s1); +void asm_global_instr(TCCState *s1); +int tcc_assemble(TCCState *s1, int do_preprocess); +int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); +Sym* get_asm_sym(TCCState *s1, int name, Sym *csym); +void asm_expr(TCCState *s1, ExprValue *pe); +int asm_int_expr(TCCState *s1); + +/* ------------ i386-asm.c ------------ */ +void gen_expr32(ExprValue *pe); +void asm_opcode(TCCState *s1, int opcode); +int asm_parse_regvar(int t); +void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); +void subst_asm_operand(CString *add_str, SValue *sv, int modifier); +void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); +void asm_clobber(uint8_t *clobber_regs, const char *str); + +#define ST_ASM_SET 0x04 + + +#endif /* !TCC_CC_H */ \ No newline at end of file diff --git a/libtcc/i386/asm.c b/libtcc/cc/i386/asm.c similarity index 99% rename from libtcc/i386/asm.c rename to libtcc/cc/i386/asm.c index 75ed9605..d73357ea 100644 --- a/libtcc/i386/asm.c +++ b/libtcc/cc/i386/asm.c @@ -25,7 +25,9 @@ #define USING_GLOBALS #include "tcc.h" -#include "token.h" +#define USING_GLOBALS +#include "cc/cc.h" +#include "cC/token.h" #define MAX_OPERANDS 3 @@ -1268,7 +1270,7 @@ void subst_asm_operand(CString *add_str, in the C symbol table when later looking up this name. So enter them now into the asm label list when we still know the symbol. */ - get_asm_sym(tok_alloc_const(name), sv->sym); + get_asm_sym(tcc_state, tok_alloc_const(name), sv->sym); } if (tcc_state->leading_underscore) cstr_ccat(add_str, '_'); diff --git a/libtcc/i386/asm.inc b/libtcc/cc/i386/asm.inc similarity index 100% rename from libtcc/i386/asm.inc rename to libtcc/cc/i386/asm.inc diff --git a/libtcc/i386/gen.c b/libtcc/cc/i386/gen.c similarity index 99% rename from libtcc/i386/gen.c rename to libtcc/cc/i386/gen.c index a745aa36..7e5fa354 100644 --- a/libtcc/i386/gen.c +++ b/libtcc/cc/i386/gen.c @@ -20,7 +20,9 @@ #define USING_GLOBALS #include -#include "token.h" +#include "cc/token.h" +#define USING_GLOBALS +#include "cc/cc.h" const char * const target_machine_defs = "__i386__\0" diff --git a/libtcc/i386/link.c b/libtcc/cc/i386/link.c similarity index 54% rename from libtcc/i386/link.c rename to libtcc/cc/i386/link.c index 7cf6e56c..c2ef395a 100644 --- a/libtcc/i386/link.c +++ b/libtcc/cc/i386/link.c @@ -1,4 +1,5 @@ #include +#include "cc/cc.h" #ifdef NEED_RELOC_TYPE /* Returns 1 for a code relocation, 0 for a data relocation. For unknown @@ -9,10 +10,6 @@ int code_reloc (int reloc_type) case R_386_RELATIVE: case R_386_16: case R_386_32: - case R_386_GOTPC: - case R_386_GOTOFF: - case R_386_GOT32: - case R_386_GOT32X: case R_386_GLOB_DAT: case R_386_COPY: case R_386_TLS_GD: @@ -23,126 +20,12 @@ int code_reloc (int reloc_type) case R_386_PC16: case R_386_PC32: - case R_386_PLT32: case R_386_JMP_SLOT: return 1; } return -1; } -/* Returns an enumerator to describe whether and when the relocation needs a - GOT and/or PLT entry to be created. See tcc.h for a description of the - different values. */ -int gotplt_entry_type (int reloc_type) -{ - switch (reloc_type) { - case R_386_RELATIVE: - case R_386_16: - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - case R_386_COPY: - return NO_GOTPLT_ENTRY; - - case R_386_32: - /* This relocations shouldn't normally need GOT or PLT - slots if it weren't for simplicity in the code generator. - See our caller for comments. */ - return AUTO_GOTPLT_ENTRY; - - case R_386_PC16: - case R_386_PC32: - return AUTO_GOTPLT_ENTRY; - - case R_386_GOTPC: - case R_386_GOTOFF: - return BUILD_GOT_ONLY; - - case R_386_GOT32: - case R_386_GOT32X: - case R_386_PLT32: - case R_386_TLS_GD: - case R_386_TLS_LDM: - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - return ALWAYS_GOTPLT_ENTRY; - } - return -1; -} - -#ifdef NEED_BUILD_GOT -unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr) -{ - Section *plt = s1->plt; - uint8_t *p; - int modrm; - unsigned plt_offset, relofs; - - modrm = 0x25; - - /* empty PLT: create PLT0 entry that pushes the library identifier - (GOT + PTR_SIZE) and jumps to ld.so resolution routine - (GOT + 2 * PTR_SIZE) */ - if (plt->data_offset == 0) { - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* pushl got + PTR_SIZE */ - p[1] = modrm + 0x10; - write32le(p + 2, PTR_SIZE); - p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ - p[7] = modrm; - write32le(p + 8, PTR_SIZE * 2); - } - plt_offset = plt->data_offset; - - /* The PLT slot refers to the relocation entry it needs via offset. - The reloc entry is created below, so its offset is the current - data_offset */ - relofs = s1->plt->reloc ? s1->plt->reloc->data_offset : 0; - - /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ - p = section_ptr_add(plt, 16); - p[0] = 0xff; /* jmp *(got + x) */ - p[1] = modrm; - write32le(p + 2, got_offset); - p[6] = 0x68; /* push $xxx */ - write32le(p + 7, relofs - sizeof (ElfW_Rel)); - p[11] = 0xe9; /* jmp plt_start */ - write32le(p + 12, -(plt->data_offset)); - return plt_offset; -} - -/* relocate the PLT: compute addresses and offsets in the PLT now that final - address for PLT and GOT are known (see fill_program_header) */ -void relocate_plt(TCCState *s1) -{ - uint8_t *p, *p_end; - - if (!s1->plt) - return; - - p = s1->plt->data; - p_end = p + s1->plt->data_offset; - - if (p < p_end) { - add32le(p + 2, s1->got->sh_addr); - add32le(p + 8, s1->got->sh_addr); - p += 16; - while (p < p_end) { - add32le(p + 2, s1->got->sh_addr); - p += 16; - } - } - - if (s1->plt->reloc) { - ElfW_Rel *rel; - int x = s1->plt->sh_addr + 16 + 6; - p = s1->got->data; - for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) { - write32le(p + rel->r_offset, x); - x += 16; - } - } -} -#endif #endif void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) @@ -158,24 +41,10 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t case R_386_PC32: add32le(ptr, val - addr); return; - case R_386_PLT32: - add32le(ptr, val - addr); - return; case R_386_GLOB_DAT: case R_386_JMP_SLOT: write32le(ptr, val); return; - case R_386_GOTPC: - add32le(ptr, s1->got->sh_addr - addr); - return; - case R_386_GOTOFF: - add32le(ptr, val - s1->got->sh_addr); - return; - case R_386_GOT32: - case R_386_GOT32X: - /* we load the got offset */ - add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset); - return; case R_386_16: if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { output_file: @@ -220,7 +89,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t memcpy(ptr-3, replace, sizeof(replace)); rel[1].r_info = ELFW(R_INFO)(0, R_386_NONE); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + sym = &((ElfW(Sym) *)s1->symtab_section->data)[sym_index]; sec = s1->sections[sym->st_shndx]; x = sym->st_value - sec->sh_addr - sec->data_offset; add32le(ptr + 5, -x); @@ -259,7 +128,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t Section *sec; int32_t x; - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + sym = &((ElfW(Sym) *)s1->symtab_section->data)[sym_index]; sec = s1->sections[sym->st_shndx]; x = val - sec->sh_addr - sec->data_offset; add32le(ptr, x); diff --git a/libtcc/i386/token.inc b/libtcc/cc/i386/token.inc similarity index 100% rename from libtcc/i386/token.inc rename to libtcc/cc/i386/token.inc diff --git a/libtcc/tccasm.c b/libtcc/cc/tccasm.c similarity index 94% rename from libtcc/tccasm.c rename to libtcc/cc/tccasm.c index 245697a3..a24b71f4 100644 --- a/libtcc/tccasm.c +++ b/libtcc/cc/tccasm.c @@ -17,16 +17,23 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "libtcc.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include -#define USING_GLOBALS #include "tcc.h" #include "utils/string.h" #include "token.h" +#include "cc/cc.h" + +#undef tcc_error +#undef _tcc_error +#define tcc_error _tcc_error +#undef tcc_warning +#define tcc_warning _tcc_warning static Section *last_text_section; /* to handle .previous asm directive */ static int asmgoto_n; @@ -53,11 +60,11 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, in the global C symbol table to track ASM names as well, so we need to transform those into ones that don't conflict with a C name, so prepend a '.' for them, but force the ELF asm name to be set. */ -static int asm2cname(int v, int *addeddot) +static int asm2cname(TCCState *s1, int v, int *addeddot) { const char *name; *addeddot = 0; - if (!tcc_state->leading_underscore) + if (!s1->leading_underscore) return v; name = get_tok_str(v, NULL); if (!name) @@ -73,20 +80,20 @@ static int asm2cname(int v, int *addeddot) return v; } -static Sym *asm_label_find(int v) +static Sym *asm_label_find(TCCState *s1, int v) { Sym *sym; int addeddot; - v = asm2cname(v, &addeddot); + v = asm2cname(s1, v, &addeddot); sym = sym_find(v); while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC)) sym = sym->prev_tok; return sym; } -static Sym *asm_label_push(int v) +static Sym *asm_label_push(TCCState *s1, int v) { - int addeddot, v2 = asm2cname(v, &addeddot); + int addeddot, v2 = asm2cname(s1, v, &addeddot); /* We always add VT_EXTERN, for sym definition that's tentative (for .set, removed for real defs), for mere references it's correct as is. */ @@ -106,11 +113,11 @@ static Sym *asm_label_push(int v) are anonymous in C, in this case CSYM can be used to transfer all information from that symbol to the (possibly newly created) asm symbol. */ -Sym* get_asm_sym(int name, Sym *csym) +Sym* get_asm_sym(TCCState *s1, int name, Sym *csym) { - Sym *sym = asm_label_find(name); + Sym *sym = asm_label_find(s1, name); if (!sym) { - sym = asm_label_push(name); + sym = asm_label_push(s1, name); if (csym) sym->c = csym->c; } @@ -122,7 +129,7 @@ static Sym* asm_section_sym(TCCState *s1, Section *sec) char buf[100]; int label; Sym *sym; snprintf(buf, sizeof buf, "L.%s", sec->old_name); label = tok_alloc_const(buf); - sym = asm_label_find(label); + sym = asm_label_find(s1, label); return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0); } @@ -143,7 +150,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) if (*p == 'b' || *p == 'f') { /* backward or forward label */ label = asm_get_local_label_name(s1, n); - sym = asm_label_find(label); + sym = asm_label_find(s1, label); if (*p == 'b') { /* backward : find the last corresponding defined label */ if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF)) @@ -154,7 +161,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) /* forward */ if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) { /* if the last label is defined, then define a new one */ - sym = asm_label_push(label); + sym = asm_label_push(s1, label); } } pe->v = 0; @@ -199,7 +206,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) break; case '.': pe->v = ind; - pe->sym = asm_section_sym(s1, tcc_state->cur_text_section); + pe->sym = asm_section_sym(s1, s1->cur_text_section); pe->pcrel = 0; next(); break; @@ -207,7 +214,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe) if (tok >= TOK_IDENT) { ElfSym *esym; /* label case : if the label was not found, add one */ - sym = get_asm_sym(tok, NULL); + sym = get_asm_sym(s1, tok, NULL); esym = elfsym(sym); if (esym && esym->st_shndx == SHN_ABS) { /* if absolute symbol, no need to put a symbol value */ @@ -336,7 +343,7 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) /* we also accept defined symbols in the same section */ pe->v += esym1->st_value - esym2->st_value; pe->sym = NULL; - } else if (esym2->st_shndx == tcc_state->cur_text_section->sh_num) { + } else if (esym2->st_shndx == s1->cur_text_section->sh_num) { /* When subtracting a defined symbol in current section this actually makes the value PC-relative. */ pe->v += 0 - esym2->st_value; @@ -413,7 +420,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, Sym *sym; ElfSym *esym; - sym = asm_label_find(label); + sym = asm_label_find(s1, label); if (sym) { esym = elfsym(sym); /* A VT_EXTERN symbol, even if it has a section is considered @@ -430,7 +437,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, } } else { new_label: - sym = asm_label_push(label); + sym = asm_label_push(s1, label); } if (!sym->c) put_extern_sym2(sym, SHN_UNDEF, 0, 0, 1); @@ -444,7 +451,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, static Sym* asm_new_label(TCCState *s1, int label, int is_local) { - return asm_new_label1(s1, label, is_local, tcc_state->cur_text_section->sh_num, ind); + return asm_new_label1(s1, label, is_local, s1->cur_text_section->sh_num, ind); } /* Set the value of LABEL to that of some expression (possibly @@ -468,9 +475,9 @@ static Sym* set_symbol(TCCState *s1, int label) static void use_section1(TCCState *s1, Section *sec) { - tcc_state->cur_text_section->data_offset = ind; - tcc_state->cur_text_section = sec; - ind = tcc_state->cur_text_section->data_offset; + s1->cur_text_section->data_offset = ind; + s1->cur_text_section = sec; + ind = s1->cur_text_section->data_offset; } static void use_section(TCCState *s1, const char *name) @@ -483,16 +490,16 @@ static void use_section(TCCState *s1, const char *name) static void push_section(TCCState *s1, const char *name) { Section *sec = find_section(s1, name); - sec->prev = tcc_state->cur_text_section; + sec->prev = s1->cur_text_section; use_section1(s1, sec); } static void pop_section(TCCState *s1) { - Section *prev = tcc_state->cur_text_section->prev; + Section *prev = s1->cur_text_section->prev; if (!prev) tcc_error(".popsection without .pushsection"); - tcc_state->cur_text_section->prev = NULL; + s1->cur_text_section->prev = NULL; use_section1(s1, prev); } @@ -503,7 +510,7 @@ static void asm_parse_directive(TCCState *s1, int global) uint8_t *ptr; /* assembler directive */ - sec = tcc_state->cur_text_section; + sec = s1->cur_text_section; switch(tok) { case TOK_ASMDIR_align: case TOK_ASMDIR_balign: @@ -682,7 +689,7 @@ static void asm_parse_directive(TCCState *s1, int global) n = e.v; esym = elfsym(e.sym); if (esym) { - if (esym->st_shndx != tcc_state->cur_text_section->sh_num) + if (esym->st_shndx != s1->cur_text_section->sh_num) expect("constant or same-section symbol"); n += esym->st_value; } @@ -710,7 +717,7 @@ static void asm_parse_directive(TCCState *s1, int global) do { Sym *sym; next(); - sym = get_asm_sym(tok, NULL); + sym = get_asm_sym(s1, tok, NULL); if (tok1 != TOK_ASMDIR_hidden) sym->type.t &= ~VT_STATIC; if (tok1 == TOK_ASMDIR_weak) @@ -806,7 +813,7 @@ static void asm_parse_directive(TCCState *s1, int global) Sym *sym; next(); - sym = asm_label_find(tok); + sym = asm_label_find(s1, tok); if (!sym) { tcc_error("label not found: %s", get_tok_str(tok, NULL)); } @@ -826,7 +833,7 @@ static void asm_parse_directive(TCCState *s1, int global) int st_type; next(); - sym = get_asm_sym(tok, NULL); + sym = get_asm_sym(s1, tok, NULL); next(); skip(','); if (tok == TOK_STR) { @@ -894,7 +901,7 @@ static void asm_parse_directive(TCCState *s1, int global) next(); } } - last_text_section = tcc_state->cur_text_section; + last_text_section = s1->cur_text_section; if (tok1 == TOK_ASMDIR_section) use_section(s1, sname); else @@ -903,8 +910,8 @@ static void asm_parse_directive(TCCState *s1, int global) 1. new_section normally acts for GCC compatibility and sets alignment to PTR_SIZE. The assembler behaves different. */ if (old_nb_section != s1->nb_sections) { - tcc_state->cur_text_section->sh_addralign = 1; - tcc_state->cur_text_section->sh_flags = flags; + s1->cur_text_section->sh_addralign = 1; + s1->cur_text_section->sh_flags = flags; } } break; @@ -914,7 +921,7 @@ static void asm_parse_directive(TCCState *s1, int global) next(); if (!last_text_section) tcc_error("no previous section referenced"); - sec = tcc_state->cur_text_section; + sec = s1->cur_text_section; use_section1(s1, last_text_section); last_text_section = sec; } @@ -926,13 +933,11 @@ static void asm_parse_directive(TCCState *s1, int global) case TOK_ASMDIR_code16: { next(); - s1->seg_size = 16; } break; case TOK_ASMDIR_code32: { next(); - s1->seg_size = 32; } break; /* TODO: Implement symvar support. FreeBSD >= 14 needs this */ @@ -1015,11 +1020,11 @@ int tcc_assemble(TCCState *s1, int do_preprocess) { int ret; /* default section is text */ - tcc_state->cur_text_section = tcc_state->text_section; - ind = tcc_state->cur_text_section->data_offset; + s1->cur_text_section = s1->text_section; + ind = s1->cur_text_section->data_offset; nocode_wanted = 0; ret = tcc_assemble_internal(s1, do_preprocess, 1); - tcc_state->cur_text_section->data_offset = ind; + s1->cur_text_section->data_offset = ind; return ret; } @@ -1187,7 +1192,7 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, } /* parse the GCC asm() instruction */ -void asm_instr(void) +void asm_instr(TCCState *s1) { CString astr, *astr1; @@ -1262,11 +1267,11 @@ void asm_instr(void) csym->r = LABEL_FORWARD; } next(); - asmname = asm_get_prefix_name(tcc_state, "LG.", + asmname = asm_get_prefix_name(s1, "LG.", ++asmgoto_n); if (!csym->c) put_extern_sym2(csym, SHN_UNDEF, 0, 0, 1); - get_asm_sym(asmname, csym); + get_asm_sym(s1, asmname, csym); operands[nb_operands + nb_labels - 1].is_label = asmname; if (tok != ',') @@ -1312,13 +1317,13 @@ void asm_instr(void) /* We don't allow switching section within inline asm to bleed out to surrounding code. */ - sec = tcc_state->cur_text_section; + sec = s1->cur_text_section; /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 0); + tcc_assemble_inline(s1, astr.data, astr.size - 1, 0); cstr_free_s(&astr); - if (sec != tcc_state->cur_text_section) { + if (sec != s1->cur_text_section) { tcc_warning("inline asm tries to change current section"); - use_section1(tcc_state, sec); + use_section1(s1, sec); } /* restore the current C token */ @@ -1335,7 +1340,7 @@ void asm_instr(void) } -void asm_global_instr(void) +void asm_global_instr(TCCState *s1) { CString *astr; int saved_nocode_wanted = nocode_wanted; @@ -1353,13 +1358,13 @@ void asm_global_instr(void) #ifdef ASM_DEBUG printf("asm_global: \"%s\"\n", (char *)astr->data); #endif - tcc_state->cur_text_section = tcc_state->text_section; - ind = tcc_state->cur_text_section->data_offset; + s1->cur_text_section = s1->text_section; + ind = s1->cur_text_section->data_offset; /* assemble the string with tcc internal assembler */ - tcc_assemble_inline(tcc_state, astr->data, astr->size - 1, 1); + tcc_assemble_inline(s1, astr->data, astr->size - 1, 1); - tcc_state->cur_text_section->data_offset = ind; + s1->cur_text_section->data_offset = ind; /* restore the current C token */ next(); diff --git a/libtcc/tccgen.c b/libtcc/cc/tccgen.c similarity index 98% rename from libtcc/tccgen.c rename to libtcc/cc/tccgen.c index 16b975c1..128f99b3 100644 --- a/libtcc/tccgen.c +++ b/libtcc/cc/tccgen.c @@ -26,6 +26,8 @@ #define USING_GLOBALS #include +#define USING_GLOBALS +#include "cc/cc.h" #include #include "utils/string.h" #include "token.h" @@ -408,7 +410,7 @@ ElfSym *elfsym(Sym *s) { if (!s || !s->c) return NULL; - return &((ElfSym *)symtab_section->data)[s->c]; + return &((ElfSym *)tcc_state->symtab_section->data)[s->c]; } /* apply storage attributes to Elf symbol */ @@ -435,23 +437,6 @@ void update_storage(Sym *sym) if (sym_bind != old_sym_bind) { esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); } - -#ifdef TCC_TARGET_PE - if (sym->a.dllimport) - esym->st_other |= ST_PE_IMPORT; - if (sym->a.dllexport) - esym->st_other |= ST_PE_EXPORT; -#endif - -#if 0 - printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n", - get_tok_str(sym->v, NULL), - sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', - sym->a.visibility, - sym->a.dllexport, - sym->a.dllimport - ); -#endif } /* ------------------------------------------------------------------------- */ @@ -512,7 +497,7 @@ void put_extern_sym2(Sym *sym, int sh_num, } info = ELFW(ST_INFO)(sym_bind, sym_type); - sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); + sym->c = put_elf_sym(tcc_state->symtab_section, value, size, info, other, sh_num, name); } else { esym = elfsym(sym); @@ -546,7 +531,7 @@ void greloca(Section *s, Sym *sym, unsigned long offset, int type, } /* now we can add ELF relocation info */ - put_elf_reloca(symtab_section, s, offset, type, c, addend); + put_elf_reloca(tcc_state->symtab_section, s, offset, type, c, addend); } #if PTR_SIZE == 4 @@ -5186,7 +5171,7 @@ void unary(void) t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; goto push_tokc; case TOK___FUNCTION__: - if (!gnu_ext) + if (!tcc_state->gnu_ext) goto tok_identifier; /* fall thru */ case TOK___FUNC__: @@ -5462,7 +5447,7 @@ void unary(void) } break; case TOK_LAND: - if (!gnu_ext) + if (!tcc_state->gnu_ext) goto tok_identifier; next(); /* allow to take the address of a label */ @@ -5598,13 +5583,6 @@ special_math_val: if (r & VT_SYM) { vtop->c.i = 0; -#ifdef TCC_TARGET_PE - if (s->a.dllimport) { - mk_pointer(&vtop->type); - vtop->r |= VT_LVAL; - indir(); - } -#endif } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { vtop->c.i = s->enum_val; } @@ -6035,7 +6013,7 @@ static void expr_cond(void) if (tok == '?') { next(); c = condition_3way(); - g = (tok == ':' && gnu_ext); + g = (tok == ':' && tcc_state->gnu_ext); tt = 0; if (!g) { if (c < 0) { @@ -6776,7 +6754,7 @@ again: dynarray_add(&cur_switch->p, &cur_switch->n, cr); t = cur_switch->sv.type.t; cr->v1 = cr->v2 = value64(expr_const64(), t); - if (tok == TOK_DOTS && gnu_ext) { + if (tok == TOK_DOTS && tcc_state->gnu_ext) { next(); cr->v2 = value64(expr_const64(), t); if (case_cmp(cr->v2, cr->v1) < 0) @@ -6800,7 +6778,7 @@ again: } else if (t == TOK_GOTO) { vla_restore(cur_scope->vla.locorig); - if (tok == '*' && gnu_ext) { + if (tok == '*' && tcc_state->gnu_ext) { /* computed goto */ next(); gexpr(); @@ -6837,7 +6815,7 @@ again: skip(';'); } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) { - asm_instr(); + asm_instr(tcc_state); } else { if (tok == ':' && t >= TOK_UIDENT) { @@ -6954,11 +6932,7 @@ static void parse_init_elem(int expr_type) (compound literals). */ if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL) - || vtop->sym->v < SYM_FIRST_ANOM)) -#ifdef TCC_TARGET_PE - || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport) -#endif - ) + || vtop->sym->v < SYM_FIRST_ANOM))) tcc_error("initializer element is not constant"); break; case EXPR_ANY: @@ -7047,7 +7021,7 @@ static int decl_designator(init_params *p, CType *type, unsigned long c, if (flags & DIF_HAVE_ELEM) goto no_designator; - if (gnu_ext && tok >= TOK_UIDENT) { + if (tcc_state->gnu_ext && tok >= TOK_UIDENT) { l = tok, next(); if (tok == ':') goto struct_field; @@ -7061,7 +7035,7 @@ static int decl_designator(init_params *p, CType *type, unsigned long c, expect("array type"); next(); index = index_last = expr_const(); - if (tok == TOK_DOTS && gnu_ext) { + if (tok == TOK_DOTS && tcc_state->gnu_ext) { next(); index_last = expr_const(); } @@ -7093,7 +7067,7 @@ static int decl_designator(init_params *p, CType *type, unsigned long c, if (!cur_field) { if (tok == '=') { next(); - } else if (!gnu_ext) { + } else if (!tcc_state->gnu_ext) { expect("="); } } else { @@ -7234,7 +7208,7 @@ static void init_putv(init_params *p, CType *type, unsigned long c) continue; if (rel->r_offset < esym->st_value) break; - put_elf_reloca(symtab_section, sec, + put_elf_reloca(tcc_state->symtab_section, sec, c + rel->r_offset - esym->st_value, ELFW(R_TYPE)(rel->r_info), ELFW(R_SYM)(rel->r_info), @@ -7728,17 +7702,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sec = tcc_state->rodata_section; } else if (has_init) { sec = tcc_state->data_section; - } else if (tcc_state->nocommon) + } else { sec = tcc_state->bss_section; + } } - - if (sec) { - addr = section_add(sec, size, align); - - } else { - addr = align; /* SHN_COMMON is special, symbol value is align */ - sec = common_section; - } + addr = section_add(sec, size, align); if (v) { if (!sym) { @@ -7997,7 +7965,7 @@ static int decl(int l) break; if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { /* global asm block */ - asm_global_instr(); + asm_global_instr(tcc_state); continue; } if (tok >= TOK_UIDENT) { @@ -8063,34 +8031,12 @@ static int decl(int l) tcc_warning("type defaults to int"); } - if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { + if (tcc_state->gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { ad.asm_label = asm_label_instr(); /* parse one last attribute list, after asm label */ parse_attribute(&ad); - #if 0 - /* gcc does not allow __asm__("label") with function definition, - but why not ... */ - if (tok == '{') - expect(";"); - #endif } -#ifdef TCC_TARGET_PE - if (ad.a.dllimport || ad.a.dllexport) { - if (type.t & VT_STATIC) - tcc_error("cannot have dll linkage with static"); - if (type.t & VT_TYPEDEF) { - tcc_warning("'%s' attribute ignored for typedef", - ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") : - (ad.a.dllexport = 0, "dllexport")); - } else if (ad.a.dllimport) { - if ((type.t & VT_BTYPE) == VT_FUNC) - ad.a.dllimport = 0; - else - type.t |= VT_EXTERN; - } - } -#endif if (tok == '{') { if (l != VT_CONST) tcc_error("cannot use local functions"); diff --git a/libtcc/tccpp.c b/libtcc/cc/tccpp.c similarity index 99% rename from libtcc/tccpp.c rename to libtcc/cc/tccpp.c index 31a9a4db..d0f59699 100644 --- a/libtcc/tccpp.c +++ b/libtcc/cc/tccpp.c @@ -23,9 +23,12 @@ #endif /* HAVE_CONFIG_H */ #include +#include #define USING_GLOBALS #include +#define USING_GLOBALS +#include "cc/cc.h" #include #include #include "utils/string.h" @@ -1555,7 +1558,7 @@ void parse_define(void) if (varg == TOK_DOTS) { varg = TOK___VA_ARGS__; is_vaargs = 1; - } else if (tok == TOK_DOTS && gnu_ext) { + } else if (tok == TOK_DOTS && tcc_state->gnu_ext) { is_vaargs = 1; next_nomacro(); } @@ -2066,7 +2069,7 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long c = '\v'; break; case 'e': - if (!gnu_ext) + if (!tcc_state->gnu_ext) goto invalid_escape; c = 27; break; @@ -2357,7 +2360,7 @@ static void parse_number(const char *p) /* XXX: should patch directly float number */ d = (double)bn[1] * 4294967296.0 + (double)bn[0]; d = ldexp(d, exp_val - frac_bits); - t = toup(ch); + t = toupper(ch); if (t == 'F') { ch = *p++; tok = TOK_CFLOAT; @@ -2412,7 +2415,7 @@ static void parse_number(const char *p) } } *q = '\0'; - t = toup(ch); + t = toupper(ch); errno = 0; if (t == 'F') { ch = *p++; @@ -2469,7 +2472,7 @@ static void parse_number(const char *p) lcount = ucount = 0; p1 = p; for(;;) { - t = toup(ch); + t = toupper(ch); if (t == 'L') { if (lcount >= 2) tcc_error("three 'l's in integer constant"); @@ -2737,7 +2740,7 @@ maybe_newline: && !(parse_flags & PARSE_FLAG_ASM_FILE /* 0xe+1 is 3 tokens in asm */ && ((char*)tokcstr.data)[0] == '0' - && toup(((char*)tokcstr.data)[1]) == 'X')) + && toupper(((char*)tokcstr.data)[1]) == 'X')) || t == 'p' || t == 'P')))) break; t = c; @@ -3036,7 +3039,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) if (t2 == TOK_PPJOIN || t1 == TOK_PPJOIN) { /* special case for var arg macros : ## eats the ',' if empty VA_ARGS variable. */ - if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) { + if (t1 == TOK_PPJOIN && t0 == ',' && tcc_state->gnu_ext && s->type.t) { int c = str.str[str.len - 1]; while (str.str[--str.len] != ',') ; @@ -3305,7 +3308,7 @@ static int macro_subst_tok( break; /* special case for gcc var args: add an empty var arg argument if it is omitted */ - if (sa->type.t && gnu_ext) + if (sa->type.t && tcc_state->gnu_ext) goto empty_arg; tcc_error("macro '%s' used with too few args", get_tok_str(v, 0)); @@ -3554,8 +3557,6 @@ static void tcc_predefs(TCCState *s1, CString *cs, int is_asm) putdef(cs, "__ASSEMBLER__"); if (s1->output_type == TCC_OUTPUT_PREPROCESS) putdef(cs, "__TCC_PP__"); - if (s1->output_type == TCC_OUTPUT_MEMORY) - putdef(cs, "__TCC_RUN__"); if (s1->char_is_unsigned) putdef(cs, "__CHAR_UNSIGNED__"); if (s1->optimize > 0) @@ -3832,7 +3833,7 @@ static int pp_need_space(int a, int b) /* maybe hex like 0x1e */ static int pp_check_he0xE(int t, const char *p) { - if (t == TOK_PPNUM && toup(strchr(p, 0)[-1]) == 'E') + if (t == TOK_PPNUM && toupper(strchr(p, 0)[-1]) == 'E') return 'E'; return t; } diff --git a/libtcc/token.h b/libtcc/cc/token.h similarity index 100% rename from libtcc/token.h rename to libtcc/cc/token.h diff --git a/libtcc/token.inc b/libtcc/cc/token.inc similarity index 100% rename from libtcc/token.inc rename to libtcc/cc/token.inc diff --git a/libtcc/include/libtcc.h b/libtcc/include/libtcc.h index cce32834..9dd48c59 100644 --- a/libtcc/include/libtcc.h +++ b/libtcc/include/libtcc.h @@ -81,14 +81,6 @@ void tcc_undefine_symbol(TCCState *s, const char *sym); */ int tcc_add_file(TCCState *s, const char *filename); -/** - * @brief compile a string containing a C source. Return -1 if error. - * - * Tip: to have more specific errors/warnings from tcc_compile_string(), - * you can prefix the string with "#line \"\"\n" - */ -int tcc_compile_string(TCCState *s, const char *buf); - /** * @} */ @@ -97,7 +89,6 @@ int tcc_compile_string(TCCState *s, const char *buf); * @defgroup linking Linking commands * @{ */ -# define TCC_OUTPUT_MEMORY 1 /** output will be run in memory */ # define TCC_OUTPUT_EXE 2 /** executable file */ # define TCC_OUTPUT_OBJ 3 /** object file */ # define TCC_OUTPUT_PREPROCESS 5 /** only preprocess */ @@ -117,35 +108,11 @@ int tcc_add_library_path(TCCState *s, const char *pathname); */ int tcc_add_library(TCCState *s, const char *libraryname); -/** - * @brief add a symbol to the compiled program. - */ -int tcc_add_symbol(TCCState *s, const char *name, const void *val); - /** * @brief output an executable, library or object file. - * - * DO NOT call tcc_relocate() before. */ int tcc_output_file(TCCState *s, const char *filename); -/** - * @brief do all relocations (needed before using tcc_get_symbol()). - */ -int tcc_relocate(TCCState *s1); - -/** - * @brief return symbol value or NULL if not found. - */ -void *tcc_get_symbol(TCCState *s, const char *name); - -typedef void (TCCSymbolFunc)(void *ctx, const char *name, const void *val); - -/** - * @brief list all (global) symbols and their values via 'symbol_cb()'. - */ -void tcc_list_symbols(TCCState *s, void *ctx, TCCSymbolFunc *symbol_cb); - /** * @} */ diff --git a/libtcc/include/tcc.h b/libtcc/include/tcc.h index 7cc68146..307dffdb 100644 --- a/libtcc/include/tcc.h +++ b/libtcc/include/tcc.h @@ -57,12 +57,6 @@ extern long double strtold (const char *__nptr, char **__endptr); #define countof(tab) (sizeof(tab) / sizeof((tab)[0])) #endif -/* -------------------------------------------- */ - -#ifdef CONFIG_TCC_PIE -# define CONFIG_TCC_PIC 1 -#endif - /* ------------ path configuration ------------ */ #ifndef CONFIG_SYSROOT @@ -348,28 +342,7 @@ typedef struct Section { #define TYPE_PARAM 4 /* type declares function parameter */ #define TYPE_NEST 8 /* nested call to post_type */ -#define IO_BUF_SIZE 8192 - -typedef struct BufferedFile { - uint8_t *buf_ptr; - uint8_t *buf_end; - int fd; - struct BufferedFile *prev; - int line_num; /* current line number - here to simplify code */ - int line_ref; /* tcc -E: last printed line */ - int ifndef_macro; /* #ifndef macro / #endif search */ - int ifndef_macro_saved; /* saved ifndef_macro */ - int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ - int include_next_index; /* next search path */ - int prev_tok_flags; /* saved tok_flags */ - char filename[1024]; /* filename */ - char *true_filename; /* filename not modified by # line directive */ - unsigned char unget[4]; - unsigned char buffer[1]; /* extra size for CH_EOB char */ -} BufferedFile; - -#define CH_EOB '\\' /* end of buffer or '\0' char in file */ -#define CH_EOF (-1) /* end of file */ +#include /* used to record tokens */ typedef struct TokenString { @@ -436,24 +409,14 @@ typedef struct ASMOperand { int is_label; /* for asm goto */ } ASMOperand; -/* extra symbol attributes (not in symbol table) */ -struct sym_attr { - unsigned got_offset; - unsigned plt_offset; - int plt_sym; - int dyn_index; -}; - struct TCCState { unsigned char verbose; /* if true, display some information during compilation */ unsigned char nostdinc; /* if true, no standard headers are added */ unsigned char nostdlib; /* if true, no standard libraries are added */ - unsigned char nocommon; /* if true, do not use common symbols for .bss data */ unsigned char symbolic; /* if true, resolve symbols in the current module first */ unsigned char filetype; /* file type for compilation (NONE,C,ASM) */ unsigned char optimize; /* only to #define __OPTIMIZE__ */ unsigned char option_pthread; /* -pthread option */ - unsigned char enable_new_dtags; /* -Wl,--enable-new-dtags */ unsigned int cversion; /* supported C ISO version, 199901 (the default), 201112, ... */ /* C language options */ @@ -464,7 +427,6 @@ struct TCCState { unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ unsigned char reverse_funcargs; /* if true, evaluate last function arg first */ unsigned char gnu89_inline; /* treat 'extern inline' like 'static inline' */ - unsigned char unwind_tables; /* create eh_frame section */ /* warning switches */ unsigned char warn_none; @@ -496,10 +458,7 @@ struct TCCState { addr_t text_addr; /* address of text section */ unsigned section_align; /* section alignment */ - int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */ - char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */ - char *rpath; /* as specified on the command line (-Wl,-rpath=) */ char *entryname; /* "_start" unless set */ /* output type, see TCC_OUTPUT_XXX */ @@ -573,47 +532,23 @@ struct TCCState { /* predefined sections */ Section *text_section, *data_section, *rodata_section, *bss_section; - Section *common_section; Section *cur_text_section; /* current section where function code is generated */ /* symbol section */ - union { Section *symtab_section, *symtab; }; /* historical alias */ - /* exported dynamic symbol section */ - Section *dynsym; - /* got & plt handling */ - Section *got, *plt; - /* exception handling */ - Section *eh_frame_section; - Section *eh_frame_hdr_section; - unsigned long eh_start; + Section *symtab_section; /* Is there a new undefined sym since last new_undef_sym() */ int new_undef_sym; - /* extra attributes (eg. GOT/PLT value) for symtab symbols */ - struct sym_attr *sym_attrs; - int nb_sym_attrs; + /* ptr to next reloc entry reused */ ElfW_Rel *qrel; #define qrel s1->qrel -#ifndef ELF_OBJ_ONLY - int nb_sym_versions; - struct sym_version *sym_versions; - int nb_sym_to_version; - int *sym_to_version; - int dt_verneednum; - Section *versym_section; - Section *verneed_section; -#endif - /* benchmark info */ int total_idents; int total_lines; unsigned int total_bytes; unsigned int total_output[4]; - /* used by tcc_load_ldscript */ - int fd, cc; - /* for warnings/errors for object files */ const char *current_filename; @@ -772,184 +707,6 @@ char *tcc_load_text(int fd); /* for #pragma once */ int normalized_PATHCMP(const char *f1, const char *f2); -/* ------------ tccpp.c ------------ */ - -extern struct BufferedFile *file; -extern int tok; -extern CValue tokc; -extern const int *macro_ptr; -extern int parse_flags; -extern int tok_flags; -extern CString tokcstr; /* current parsed string, if any */ - -/* display benchmark infos */ -extern int tok_ident; -extern TokenSym **table_ident; -extern int pp_expr; - -#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ -#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ -#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ - -#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ -#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ -#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a - token. line feed is also - returned at eof */ -#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */ -#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */ -#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */ -#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */ - -/* isidnum_table flags: */ -#define IS_SPC 1 -#define IS_ID 2 -#define IS_NUM 4 - -enum line_macro_output_format { - LINE_MACRO_OUTPUT_FORMAT_GCC, - LINE_MACRO_OUTPUT_FORMAT_NONE, - LINE_MACRO_OUTPUT_FORMAT_STD, - LINE_MACRO_OUTPUT_FORMAT_P10 = 11 -}; - -TokenSym *tok_alloc(const char *str, int len); -int tok_alloc_const(const char *str); -const char *get_tok_str(int v, CValue *cv); -void begin_macro(TokenString *str, int alloc); -void end_macro(void); -int set_idnum(int c, int val); -void tok_str_new(TokenString *s); -TokenString *tok_str_alloc(void); -void tok_str_free(TokenString *s); -void tok_str_free_str(int *str); -void tok_str_add(TokenString *s, int t); -void tok_str_add_tok(TokenString *s); -void define_push(int v, int macro_type, int *str, Sym *first_arg); -void define_undef(Sym *s); -Sym *define_find(int v); -void free_defines(Sym *b); -void parse_define(void); -void skip_to_eol(int warn); -void preprocess(int is_bof); -void next(void); -void unget_tok(int last_tok); -void preprocess_start(TCCState *s1, int filetype); -void preprocess_end(TCCState *s1); -void tccpp_new(TCCState *s); -void tccpp_delete(TCCState *s); -void tccpp_putfile(const char *filename); -int tcc_preprocess(TCCState *s1); -void skip(int c); -__attribute__((noreturn)) void expect(const char *msg); -void pp_error(CString *cs); - - -/* space excluding newline */ -static inline int is_space(int ch) { - return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; -} -static inline int isid(int c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} -static inline int isnum(int c) { - return c >= '0' && c <= '9'; -} -static inline int isoct(int c) { - return c >= '0' && c <= '7'; -} -static inline int toup(int c) { - return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; -} - -/* ------------ tccgen.c ------------ */ - -#define SYM_POOL_NB (8192 / sizeof(Sym)) - -extern Sym *global_stack; -extern Sym *local_stack; -extern Sym *local_label_stack; -extern Sym *global_label_stack; -extern Sym *define_stack; -extern CType int_type, func_old_type, char_pointer_type; -extern SValue *vtop; -extern int rsym, anon_sym, ind, loc; -extern char debug_modes; - -extern int nocode_wanted; /* true if no code generation wanted for an expression */ -extern int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ -extern CType func_vt; /* current function return type (used by return instruction) */ -extern int func_var; /* true if current function is variadic */ -extern int func_vc; -extern int func_ind; -extern const char *funcname; - -void tccgen_init(TCCState *s1); -int tccgen_compile(TCCState *s1); -void tccgen_finish(TCCState *s1); -void check_vstack(void); - -int is_float(int t); -int ieee_finite(double d); -int exact_log2p1(int i); -void test_lvalue(void); - -ElfSym *elfsym(Sym *); -void update_storage(Sym *sym); -void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore); -void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size); -#if PTR_SIZE == 4 -void greloc(Section *s, Sym *sym, unsigned long offset, int type); -#endif -void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend); - -void sym_free(Sym *sym); -Sym *sym_push(int v, CType *type, int r, int c); -void sym_pop(Sym **ptop, Sym *b, int keep); -Sym *sym_push2(Sym **ps, int v, int t, int c); -Sym *sym_find2(Sym *s, int v); -Sym *sym_find(int v); -Sym *label_find(int v); -Sym *label_push(Sym **ptop, int v, int flags); -void label_pop(Sym **ptop, Sym *slast, int keep); -Sym *struct_find(int v); - -Sym *global_identifier_push(int v, int t, int c); -Sym *external_global_sym(int v, CType *type); -Sym *external_helper_sym(int v); -void vpush_helper_func(int v); -void vset(CType *type, int r, int v); -void vset_VT_CMP(int op); -void vpushi(int v); -void vpushv(SValue *v); -void vpushsym(CType *type, Sym *sym); -void vswap(void); -void vrott(int n); -void vrotb(int n); -void vrev(int n); -void vpop(void); -#if PTR_SIZE == 4 -void lexpand(void); -#endif -void save_reg(int r); -void save_reg_upstack(int r, int n); -int get_reg(int rc); -void save_regs(int n); -void gaddrof(void); -int gv(int rc); -void gv2(int rc1, int rc2); -void gen_op(int op); -int type_size(CType *type, int *a); -void mk_pointer(CType *type); -void vstore(void); -void inc(int post, int c); -CString* parse_mult_str(const char *msg); -CString* parse_asm_str(void); -void indir(void); -void unary(void); -void gexpr(void); -int expr_const(void); - /* ------------ tccelf.c ------------ */ #define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ @@ -988,10 +745,7 @@ int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); int tcc_load_archive(TCCState *s1, int fd, int alacarte); void add_array(TCCState *s1, const char *sec, int c); -struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc); -void list_elf_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)); int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs); /* Browse each elem of type in section starting at elem @@ -1001,7 +755,6 @@ int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs); elem < (type *) (sec->data + sec->data_offset); elem++) #ifndef ELF_OBJ_ONLY -int tcc_load_ldscript(TCCState *s1, int fd); void tccelf_add_crtbegin(TCCState *s1); void tccelf_add_crtend(TCCState *s1); #endif @@ -1011,120 +764,7 @@ void tcc_add_runtime(TCCState *s1); int coff_load_file(TCCState *s1, int fd, const char *fname); -/* ------------ xxx-link.c ------------ */ - -#if !defined ELF_OBJ_ONLY -int code_reloc (int reloc_type); -int gotplt_entry_type (int reloc_type); -/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so - that unknown relocation don't create a GOT or PLT entry */ -enum gotplt_entry { - NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */ - BUILD_GOT_ONLY, /* only build GOT (eg. TPOFF relocs) */ - AUTO_GOTPLT_ENTRY, /* generate if sym is UNDEF */ - ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */ -}; -#define NEED_RELOC_TYPE - -unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); -void relocate_plt(TCCState *s1); -void build_got_entries(TCCState *s1, int got_sym); /* in tccelf.c */ -#define NEED_BUILD_GOT - -#endif - -void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val); - -/* ------------ xxx-gen.c ------------ */ -extern const char * const target_machine_defs; -extern const int reg_classes[NB_REGS]; - -void gsym_addr(int t, int a); -void gsym(int t); -void load(int r, SValue *sv); -void store(int r, SValue *v); -int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); -void gfunc_call(int nb_args); -void gfunc_prolog(Sym *func_sym); -void gfunc_epilog(void); -void gen_fill_nops(int); -int gjmp(int t); -void gjmp_addr(int a); -int gjmp_cond(int op, int t); -int gjmp_append(int n, int t); -void gen_opi(int op); -void gen_opf(int op); -void gen_cvt_ftoi(int t); -void gen_cvt_itof(void); -void gen_cvt_ftof(void); -void ggoto(void); -void o(unsigned int c); -void gen_vla_sp_save(int addr); -void gen_vla_sp_restore(int addr); -void gen_vla_alloc(CType *type, int align); - -static inline uint16_t read16le(unsigned char *p) { - return p[0] | (uint16_t)p[1] << 8; -} -static inline void write16le(unsigned char *p, uint16_t x) { - p[0] = x & 255; p[1] = x >> 8 & 255; -} -static inline uint32_t read32le(unsigned char *p) { - return read16le(p) | (uint32_t)read16le(p + 2) << 16; -} -static inline void write32le(unsigned char *p, uint32_t x) { - write16le(p, x); write16le(p + 2, x >> 16); -} -static inline void add32le(unsigned char *p, int32_t x) { - write32le(p, read32le(p) + x); -} -static inline uint64_t read64le(unsigned char *p) { - return read32le(p) | (uint64_t)read32le(p + 4) << 32; -} -static inline void write64le(unsigned char *p, uint64_t x) { - write32le(p, x); write32le(p + 4, x >> 32); -} -static inline void add64le(unsigned char *p, int64_t x) { - write64le(p, read64le(p) + x); -} - -/* ------------ i386-gen.c ------------ */ -void g(int c); -void gen_le16(int c); -void gen_le32(int c); - -void gen_addr32(int r, Sym *sym, int c); -void gen_addrpc32(int r, Sym *sym, int c); -void gen_cvt_csti(int t); - -/* ------------ tccasm.c ------------ */ -void asm_instr(void); -void asm_global_instr(void); -int tcc_assemble(TCCState *s1, int do_preprocess); -int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); -Sym* get_asm_sym(int name, Sym *csym); -void asm_expr(TCCState *s1, ExprValue *pe); -int asm_int_expr(TCCState *s1); -/* ------------ i386-asm.c ------------ */ -void gen_expr32(ExprValue *pe); -void asm_opcode(TCCState *s1, int opcode); -int asm_parse_regvar(int t); -void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); -void subst_asm_operand(CString *add_str, SValue *sv, int modifier); -void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); -void asm_clobber(uint8_t *clobber_regs, const char *str); - -#define ST_ASM_SET 0x04 - - /* ------------ tccdbg.c ------------ */ -#define eh_frame_hdr_section s1->eh_frame_hdr_section - -#define common_section TCC_STATE_VAR(common_section) -#define bounds_section TCC_STATE_VAR(bounds_section) -#define lbounds_section TCC_STATE_VAR(lbounds_section) -#define symtab_section TCC_STATE_VAR(symtab_section) -#define gnu_ext TCC_STATE_VAR(gnu_ext) #define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort) #define tcc_error TCC_SET_STATE(_tcc_error) #define tcc_warning TCC_SET_STATE(_tcc_warning) diff --git a/libtcc/include/tcc/elf.h b/libtcc/include/tcc/elf.h index f5c2c0c9..4310be01 100644 --- a/libtcc/include/tcc/elf.h +++ b/libtcc/include/tcc/elf.h @@ -371,7 +371,6 @@ typedef struct #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ -#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_LOSUNW 0x6ffffffa @@ -432,19 +431,6 @@ typedef struct #define NT_VERSION 1 /* Contains a version string. */ - -/* Dynamic section entry. */ - -typedef struct -{ - Elf32_Sword d_tag; /* Dynamic entry type */ - union - { - Elf32_Word d_val; /* Integer value */ - Elf32_Addr d_ptr; /* Address value */ - } d_un; -} Elf32_Dyn; - /* Legal values for d_tag (dynamic entry type). */ #define DT_NULL 0 /* Marks end of dynamic section */ @@ -462,7 +448,6 @@ typedef struct #define DT_INIT 12 /* Address of init function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Name of shared object */ -#define DT_RPATH 15 /* Library search path (deprecated) */ #define DT_SYMBOLIC 16 /* Start symbol search here */ #define DT_REL 17 /* Address of Rel relocs */ #define DT_RELSZ 18 /* Total size of Rel relocs */ @@ -837,14 +822,10 @@ typedef struct #define R_386_NONE 0 /* No reloc */ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ -#define R_386_GOT32 3 /* 32 bit GOT entry */ -#define R_386_PLT32 4 /* 32 bit PLT address */ #define R_386_COPY 5 /* Copy symbol at runtime */ #define R_386_GLOB_DAT 6 /* Create GOT entry */ #define R_386_JMP_SLOT 7 /* Create PLT entry */ #define R_386_RELATIVE 8 /* Adjust by program base */ -#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ -#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ #define R_386_32PLT 11 #define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ #define R_386_TLS_IE 15 /* Address of GOT entry for static TLS @@ -896,17 +877,5 @@ typedef struct /* Keep this the last entry. */ #define R_386_NUM 44 -/* AMD x86-64 relocations. */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative - offset to GOT */ -#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with - linker optimizations */ -#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix - is present */ - -/* x86-64 sh_type values. */ -#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */ #endif /* elf.h */ diff --git a/libtcc/include/tcc/i386/link.h b/libtcc/include/tcc/i386/link.h index 1a6f7c30..878fb637 100644 --- a/libtcc/include/tcc/i386/link.h +++ b/libtcc/include/tcc/i386/link.h @@ -14,7 +14,4 @@ # define ELF_START_ADDR 0x08048000 # define ELF_PAGE_SIZE 0x1000 -# define PCRELATIVE_DLLPLT 0 -# define RELOCATE_DLLPLT 1 - #endif /* !TCC_I386_LINK_H */ \ No newline at end of file diff --git a/libtcc/include/tcc/io.h b/libtcc/include/tcc/io.h index 188f02b8..ef72f3e3 100644 --- a/libtcc/include/tcc/io.h +++ b/libtcc/include/tcc/io.h @@ -17,7 +17,7 @@ typedef struct BufferedFile { int *ifdef_stack_ptr; /** ifdef_stack value at the start of the file */ int include_next_index; /** next search path */ int prev_tok_flags; /** saved tok_flags */ - char *filename[1024]; /** filename */ + char filename[1024]; /** filename */ char *true_filename; /** filename not modified by # line directive */ unsigned char unget[4]; unsigned char buffer[1]; /** extra size for CH_EOB char */ diff --git a/libtcc/include/tcc/object/coff.h b/libtcc/include/tcc/object/coff.h index d508355a..265a4a31 100644 --- a/libtcc/include/tcc/object/coff.h +++ b/libtcc/include/tcc/object/coff.h @@ -71,6 +71,7 @@ typedef struct COFFSectionHeader { # define COFF_STYP_TEXT 0x020 # define COFF_STYP_DATA 0x040 # define COFF_STYP_BSS 0x080 +# define COFF_STYP_RODATA 0x100 /** stupidos extension */ # define COFF_STYP_INFO 0x200 # define COFF_STYP_OVER 0x400 # define COFF_STYP_LIB 0x800 @@ -103,6 +104,9 @@ typedef struct COFFSym { int8_t numaux; } COFFSym; +# define COFF_N_UNDEF 0 +# define COFF_N_ABS -1 + /** * @} */ diff --git a/libtcc/include/tcc/option.h b/libtcc/include/tcc/option.h index 4609089e..6f51e5c1 100644 --- a/libtcc/include/tcc/option.h +++ b/libtcc/include/tcc/option.h @@ -10,7 +10,6 @@ # define TCC_OPT_HELP_MORE 'm' # define TCC_OPT_ARCHIVE 'a' # define TCC_OPT_VERSION 'V' -# define TCC_OPT_PRINT_DIRS 'P' typedef struct TCCOption { const char *name; diff --git a/libtcc/include/tcc/state.h b/libtcc/include/tcc/state.h index 97a2b23b..63d3711f 100644 --- a/libtcc/include/tcc/state.h +++ b/libtcc/include/tcc/state.h @@ -22,7 +22,7 @@ typedef struct InlineFunc InlineFunc; typedef struct TCCStrtab { size_t len; - uint8_t *tab; + char *tab; } TCCStrtab; typedef struct TCCSymtab { @@ -41,6 +41,8 @@ typedef struct TCCSection { char name[8]; /** section name */ int32_t flags; int16_t secnum; + int16_t addralign; + size_t offset; } TCCSection; struct TCCState2 { @@ -89,8 +91,6 @@ struct TCCState2 { uint32_t text_addr; /** address of text section */ unsigned section_align; /** section alignment */ - int seg_size; /** 32. Can be 16 with i386 assembler (.code16) */ - char *tcc_lib_path; /** CONFIG_TCCDIR or -B option */ char *entryname; /** "_start" unless set */ @@ -161,12 +161,7 @@ struct TCCState2 { TCCSection *cur_text_section; /** current section where function code is generated */ /* symbol data */ - TCCSymtab symtab; - - /* exception handling */ - TCCSection *eh_frame_section; - TCCSection *eh_frame_hdr_section; - uint32_t eh_start; + TCCSymtab *symtab; /* benchmark info */ int total_idents; @@ -174,10 +169,6 @@ struct TCCState2 { uint32_t total_bytes; uint32_t total_output[4]; - /* used by tcc_load_ldscript */ - int fd; - int cc; - /* for warnings/errors for object files */ const char *current_filename; }; diff --git a/libtcc/io.c b/libtcc/io.c new file mode 100644 index 00000000..f686b19a --- /dev/null +++ b/libtcc/io.c @@ -0,0 +1,53 @@ + +#include "libtcc.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include "utils/string.h" +#include "cc/cc.h" + +void +tcc_open_bf(TCCState *s1, const char *filename, int initlen) +{ + BufferedFile *bf; + int buflen; + + buflen = initlen ? initlen : IO_BUF_SIZE; + bf = tcc_mallocz(sizeof(BufferedFile) + buflen); + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + initlen; + bf->buf_end[0] = CH_EOB; /* put eob symbol */ + pstrcpy(bf->filename, sizeof(bf->filename), filename); + + bf->true_filename = bf->filename; + bf->line_num = 1; + bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; + bf->fd = -1; + bf->prev = file; + bf->prev_tok_flags = tok_flags; + file = bf; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; +} + +void tcc_close(void) +{ + TCCState *s1 = tcc_state; + BufferedFile *bf = file; + + if (bf->fd > 0) + { + close(bf->fd); + total_lines += bf->line_num - 1; + } + if (bf->true_filename != bf->filename) + { + tcc_free(bf->true_filename); + } + file = bf->prev; + tok_flags = bf->prev_tok_flags; + tcc_free(bf); +} diff --git a/libtcc/libtcc.c b/libtcc/libtcc.c index 8a8ac9ea..f59eda93 100644 --- a/libtcc/libtcc.c +++ b/libtcc/libtcc.c @@ -29,6 +29,7 @@ #include #include #include "utils/string.h" +#include "cc/cc.h" /********************************************************/ /* global variables */ @@ -64,9 +65,6 @@ char *tcc_load_text(int fd) return buf; } -/********************************************************/ -/* memory management */ - #ifdef _WIN32 # define realpath(file, buf) _fullpath(buf, file, 260) #endif @@ -278,42 +276,6 @@ PUB_FUNC void _tcc_warning(const char *fmt, ...) /********************************************************/ /* I/O layer */ -void tcc_open_bf(TCCState *s1, const char *filename, int initlen) -{ - BufferedFile *bf; - int buflen = initlen ? initlen : IO_BUF_SIZE; - - bf = tcc_mallocz(sizeof(BufferedFile) + buflen); - bf->buf_ptr = bf->buffer; - bf->buf_end = bf->buffer + initlen; - bf->buf_end[0] = CH_EOB; /* put eob symbol */ - pstrcpy(bf->filename, sizeof(bf->filename), filename); - - bf->true_filename = bf->filename; - bf->line_num = 1; - bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; - bf->fd = -1; - bf->prev = file; - bf->prev_tok_flags = tok_flags; - file = bf; - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; -} - -void tcc_close(void) -{ - TCCState *s1 = tcc_state; - BufferedFile *bf = file; - if (bf->fd > 0) { - close(bf->fd); - total_lines += bf->line_num - 1; - } - if (bf->true_filename != bf->filename) - tcc_free(bf->true_filename); - file = bf->prev; - tok_flags = bf->prev_tok_flags; - tcc_free(bf); -} - static int _tcc_open(TCCState *s1, const char *filename) { int fd; @@ -384,11 +346,6 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd) return s1->nb_errors != 0 ? -1 : 0; } -int tcc_compile_string(TCCState *s, const char *str) -{ - return tcc_compile(s, s->filetype, str, -1); -} - /* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */ void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) { @@ -419,22 +376,16 @@ TCCState *tcc_new(void) #undef gnu_ext s->gnu_ext = 1; s->tcc_ext = 1; - s->nocommon = 1; s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ s->cversion = 199901; /* default unless -std=c11 is supplied */ s->warn_implicit_function_declaration = 1; s->warn_discarded_qualifiers = 1; s->ms_extensions = 1; - s->unwind_tables = 1; #ifdef __CHAR_UNSIGNED__ s->char_is_unsigned = 1; #endif - s->seg_size = 32; -#ifdef CONFIG_NEW_DTAGS - s->enable_new_dtags = 1; -#endif s->ppfp = stdout; /* might be used in error() before preprocess_start() */ s->include_stack_ptr = s->include_stack; @@ -457,7 +408,6 @@ void tcc_delete(TCCState *s1) dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); tcc_free(s1->tcc_lib_path);; - tcc_free(s1->rpath); tcc_free(s1->entryname); tcc_free(s1->outfile); tcc_free(s1->deps_outfile); @@ -501,7 +451,7 @@ int tcc_set_output_type(TCCState *s, int output_type) /* paths for crt objects */ tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); - if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) + if (!s->nostdlib) tccelf_add_crtbegin(s); return 0; } @@ -564,9 +514,7 @@ int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) default: /* as GNU ld, consider it is an ld script if not recognized */ - ret = tcc_load_ldscript(s1, fd); - if (ret < 0) - tcc_error_noabort("%s: unrecognized file type", filename); + tcc_error_noabort("%s: unrecognized file type", filename); break; } close(fd); @@ -660,6 +608,7 @@ int tcc_add_library(TCCState *s, const char *libraryname) static const char * const libs[] = { "%s/lib%s.a", NULL }; const char * const *pp = libs; int flags = s->filetype & AFF_WHOLE_ARCHIVE; + while (*pp) { int ret = tcc_add_library_internal(s, *pp, libraryname, flags, s->library_paths, s->nb_library_paths); @@ -678,18 +627,6 @@ void tcc_add_pragma_libs(TCCState *s1) tcc_add_library(s1, s1->pragma_libs[i]); } -int tcc_add_symbol(TCCState *s1, const char *name, const void *val) -{ - char buf[256]; - if (s1->leading_underscore) { - buf[0] = '_'; - pstrcpy(buf + 1, sizeof(buf) - 1, name); - name = buf; - } - set_global_sym(s1, name, NULL, (addr_t)(uintptr_t)val); /* NULL: SHN_ABS */ - return 0; -} - void tcc_set_lib_path(TCCState *s, const char *path) { tcc_free(s->tcc_lib_path); diff --git a/libtcc/memory.c b/libtcc/memory.c index 722ca64c..b9904e40 100644 --- a/libtcc/memory.c +++ b/libtcc/memory.c @@ -8,6 +8,7 @@ #include #include +#include "cc/cc.h" #ifdef TCC_MEMORY_DEBUG # undef tcc_free diff --git a/libtcc/object.c b/libtcc/object.c index 9e91dd05..70854e23 100644 --- a/libtcc/object.c +++ b/libtcc/object.c @@ -1,4 +1,6 @@ -#include +#include +#include +#include #include #include #include @@ -10,4 +12,4 @@ tcc_object_type(int fd, void *h) return (0); -} \ No newline at end of file +} diff --git a/libtcc/object/coff.c b/libtcc/object/coff.c index ecbc81d0..fa4e13d8 100644 --- a/libtcc/object/coff.c +++ b/libtcc/object/coff.c @@ -1,3 +1,6 @@ +#include "utils/string.h" +#include +#include #include #ifdef HAVE_CONFIG_H # include "config.h" @@ -7,6 +10,8 @@ #include #include +#define ALIGN_UP(val, alignment) ((val + alignment - 1) & -alignment) + #define COFF_DEFAULT_ENTRYNAME "_start" void dynarray_add(void *ptab, int *nb_ptr, void *data); @@ -39,14 +44,6 @@ coff_free_section(TCCSection *s) s->data_allocated = s->data_offset = 0; } -static void -coff_new_symtab(TCCState2 *s1) -{ - TCCSymtab *symtab; - - symtab = tcc_mallocz(sizeof(TCCSymtab)); -} - void coff_new(TCCState2 *s1) { @@ -55,9 +52,12 @@ coff_new(TCCState2 *s1) s1->text_section = coff_new_section(s1, ".text", COFF_STYP_TEXT); s1->data_section = coff_new_section(s1, ".data", COFF_STYP_DATA); s1->bss_section = coff_new_section(s1, ".bss", COFF_STYP_BSS); - s1->rodata_section = coff_new_section(s1, ".rodata", COFF_STYP_DATA); + s1->rodata_section = coff_new_section(s1, ".rodata", COFF_STYP_RODATA); - coff_new_symtab(s1); + s1->symtab = tcc_mallocz(sizeof(TCCSymtab)); /* create new symtab */ + /* add dummy symbols */ + s1->symtab->nsym++; + s1->symtab->syms = tcc_mallocz(sizeof(COFFSym)); } void @@ -71,6 +71,218 @@ coff_delete(TCCState2 *s1) } dynarray_reset(&s1->sections, &s1->nb_sections); + + if (s1->symtab != NULL) + { + tcc_free(s1->symtab->strtab.tab); + tcc_free(s1->symtab->syms); + tcc_free(s1->symtab); + s1->symtab = NULL; + } +} + +void +coff_begin_file(TCCState2 *s1) +{ + TCCSection *sec; + int i; + + for (i = 1; i < s1->nb_sections; i++) + { + sec = s1->sections[i]; + sec->offset = sec->data_offset; + } +} + +void +coff_section_realloc(TCCSection *sec, size_t new_size) +{ + size_t size; + uint8_t *data; + + size = sec->data_allocated; + if (size == 0) + { + size = 1; + } + + while (size < new_size) + { + size = size * 2; + } + data = tcc_realloc(sec->data, size); + memset(data + sec->data_allocated, 0, size - sec->data_allocated); + sec->data = data; + sec->data_allocated = size; +} + +size_t +coff_section_add(TCCSection *sec, size_t size, int align) +{ + size_t offset; + size_t offset1; + + offset = ALIGN_UP(sec->data_offset, align); + offset1 = offset + size; + if (sec->flags != COFF_STYP_BSS && offset1 > sec->data_allocated) + { + coff_section_realloc(sec, offset1); + } + sec->data_offset = offset1; + if (align > sec->addralign) + { + sec->addralign = align; + } + return (offset); +} + +/* reserve at least 'size' bytes in section 'sec' from + sec->data_offset. */ +void * +coff_section_ptr_add(TCCSection *sec, size_t size) +{ + return (sec->data + coff_section_add(sec, size, 1)); +} + +static TCCSection * +coff_have_section(TCCState2 *s1, const char *name) +{ + TCCSection *sec; + int i; + + for (i = 1; i < s1->nb_sections; i++) + { + sec = s1->sections[i]; + if (strncmp(name, sec->name, 8) == 0) + { + return (sec); + } + } + return (NULL); +} + +/* return a reference to a section, and create it if it does not + exists */ +TCCSection * +coff_find_section(TCCState2 *s1, const char *name) +{ + TCCSection *sec; + + sec = coff_have_section(s1, name); + if (sec != NULL) + { + return (sec); + } + + return (coff_new_section(s1, name, COFF_STYP_TEXT)); +} + +/* + * --------------------------------------------------------------------------- + * Symbols + * --------------------------------------------------------------------------- + */ + +int +coff_add_sym(TCCState2 *s1, uint32_t value, const char *name, size_t size, + int16_t scnum, uint16_t type, int8_t sclass) +{ + size_t symidx; + size_t strtaboffset; + COFFSym *sym; + char *ptr; + + symidx = s1->symtab->nsym; + s1->symtab->nsym++; + + s1->symtab->syms = tcc_realloc(s1->symtab->syms, sizeof(COFFSym) * s1->symtab->nsym); + sym = &(s1->symtab->syms[symidx]); + if (size > 8) + { + strtaboffset = ALIGN_UP(s1->symtab->strtab.len, 1); + s1->symtab->strtab.len += strtaboffset + size + 1; + ptr = s1->symtab->strtab.tab; + s1->symtab->strtab.tab = tcc_realloc(ptr, s1->symtab->strtab.len); + ptr += strtaboffset; + memcpy(ptr, name, size + 1); + + sym->n.n.zeroes = 0x0; + sym->n.n.offset = strtaboffset; + } + else + { + memset(sym->n.name, 0, 8); + memcpy(sym->n.name, name, size); + } + + return (symidx); +} + +int +coff_find_sym(TCCState2 *s1, const char *name) +{ + size_t symidx; + size_t len; + COFFSym *sym; + const char *str; + + len = strlen(name); + + for (symidx = 1; symidx < s1->symtab->nsym; symidx++) + { + sym = &(s1->symtab->syms[symidx]); + + if ((len > 8 && sym->n.n.zeroes != 0) + || (len <= 8 && sym->n.n.zeroes == 0)) + { + continue; + } + else if (len > 8) + { + str = s1->symtab->strtab.tab + sym->n.n.offset; + if (strcmp(name, str) == 0) + { + return (symidx); + } + } + else + { + if (strncmp(name, sym->n.name, 8) == 0) + { + return (symidx); + } + } + } + + return (0); +} + +uint32_t +coff_get_sym_addr(TCCState2 *s1, const char *name, int err, int forc) +{ + COFFSym *sym; + int sym_idx; + char buf[256]; + + if (forc && s1->leading_underscore) + { + buf[0] = '_'; + pstrcpy(buf + 1, sizeof(buf) - 1, name); + name = buf; + } + + sym_idx = coff_find_sym(s1, name); + sym = &((COFFSym *)s1->symtab->syms)[sym_idx]; + if (sym_idx == 0 || sym->scnum == COFF_N_UNDEF) + { + if (err) + { + //_tcc_error_noabort("%s not defined", name); + } + return ((uint32_t)-1); + } + + return (sym->value); } int diff --git a/libtcc/option.c b/libtcc/option.c index 0dc221a7..79d2d91b 100644 --- a/libtcc/option.c +++ b/libtcc/option.c @@ -54,7 +54,6 @@ enum { OPTION_include, OPTION_nostdinc, OPTION_nostdlib, - OPTION_print_search_dirs, OPTION_w, OPTION_E, OPTION_M, @@ -100,7 +99,6 @@ static const TCCOption options[] = { {"include", OPTION_include, TCC_OPTION_HAS_ARG}, {"nostdinc", OPTION_nostdinc, 0}, {"nostdlib", OPTION_nostdlib, 0}, - {"print-search-dirs", OPTION_print_search_dirs, 0}, {"w", OPTION_w, 0}, {"E", OPTION_E, 0}, {"M", OPTION_M, 0}, @@ -141,13 +139,11 @@ static const Flag options_W[] = { static const Flag options_f[] = { {offsetof(TCCState, char_is_unsigned), 0, "unsigned-char"}, {offsetof(TCCState, char_is_unsigned), F_FD_INVERT, "signed-char"}, - {offsetof(TCCState, nocommon), F_FD_INVERT, "common"}, {offsetof(TCCState, leading_underscore), 0, "leading-underscore"}, {offsetof(TCCState, ms_extensions), 0, "ms-extensions"}, {offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers"}, {offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs"}, {offsetof(TCCState, gnu89_inline), 0, "gnu89-inline"}, - {offsetof(TCCState, unwind_tables), 0, "asynchronous-unwind-tables"}, {0, 0, NULL} }; @@ -333,25 +329,23 @@ set_linker(TCCState *s, const char *option) s->text_addr = strtoull(p, &end, 16); s->has_text_addr = 1; } else if (link_option(option, "oformat=", &p)) { - if (strstart("elf32-", &p)) { - s->output_format = TCC_OUTPUT_FORMAT_ELF; - } else if (link_arg("binary", p)) { + if (link_arg("binary", p)) + { s->output_format = TCC_OUTPUT_FORMAT_BINARY; -#ifdef TCC_TARGET_COFF - } else if (link_arg("coff", p)) { + } + else if (link_arg("coff", p)) + { s->output_format = TCC_OUTPUT_FORMAT_COFF; -#endif - } else + } + else + { goto err; + } } else if (link_option(option, "as-needed", &p)) { ignoring = 1; } else if (link_option(option, "O", &p)) { ignoring = 1; - } else if (link_option(option, "rpath=", &p)) { - copy_linker_arg(&s->rpath, p, ':'); - } else if (link_option(option, "enable-new-dtags", &p)) { - s->enable_new_dtags = 1; } else if (link_option(option, "section-alignment=", &p)) { s->section_align = strtoul(p, &end, 16); } else if (ret = link_option(option, "?whole-archive", &p), ret) { @@ -717,9 +711,6 @@ reparse: case OPTION_O: s->optimize = atoi(optarg); break; - case OPTION_print_search_dirs: - x = TCC_OPT_PRINT_DIRS; - goto extra_action; case OPTION_ar: x = TCC_OPT_ARCHIVE; extra_action: @@ -745,8 +736,6 @@ unsupported_option: return (tool); if (optind != noaction) return (0); - if (s->verbose == 2) - return (TCC_OPT_PRINT_DIRS); if (s->verbose) return (TCC_OPT_VERSION); return (TCC_OPT_HELP); diff --git a/libtcc/tccelf.c b/libtcc/tccelf.c index a4b0ff1f..35c07b59 100644 --- a/libtcc/tccelf.c +++ b/libtcc/tccelf.c @@ -28,6 +28,8 @@ #include #include +#include "cc/cc.h" + #include "utils/string.h" /* Define this to get some debug output during relocation processing. */ @@ -36,22 +38,6 @@ /********************************************************/ /* global variables */ -/* elf version information */ -struct sym_version { - char *lib; - char *version; - int out_index; - int prev_same_lib; -}; - -#define nb_sym_versions s1->nb_sym_versions -#define sym_versions s1->sym_versions -#define nb_sym_to_version s1->nb_sym_to_version -#define sym_to_version s1->sym_to_version -#define dt_verneednum s1->dt_verneednum -#define versym_section s1->versym_section -#define verneed_section s1->verneed_section - /* special flag to indicate that the section should not be linked to the other ones */ #define SHF_PRIVATE 0x80000000 /* section is dynsymtab_section */ @@ -69,8 +55,6 @@ static const char rdata[] = ".data.ro"; void tccelf_new(TCCState *s) { - TCCState *s1 = s; - /* no section zero */ dynarray_add(&s->sections, &s->nb_sections, NULL); @@ -80,22 +64,11 @@ void tccelf_new(TCCState *s) /* create ro data section (make ro after relocation done with GNU_RELRO) */ s->rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO); s->bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); - common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); - common_section->sh_num = SHN_COMMON; /* symbols are always generated for linking stage */ - symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, + s->symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, ".strtab", ".hashtab", SHF_PRIVATE); - - get_sym_attr(s, 0, 1); - -#ifdef TCC_TARGET_PE - /* to make sure that -ltcc1 -Wl,-e,_start will grab the startup code - from libtcc1.a (unless _start defined) */ - if (s->elf_entryname) - set_global_sym(s, s->elf_entryname, NULL, 0); /* SHN_UNDEF */ -#endif } void free_section(Section *s) @@ -111,16 +84,6 @@ void tccelf_delete(TCCState *s1) { int i; -#ifndef ELF_OBJ_ONLY - /* free symbol versions */ - for (i = 0; i < nb_sym_versions; i++) { - tcc_free(sym_versions[i].version); - tcc_free(sym_versions[i].lib); - } - tcc_free(sym_versions); - tcc_free(sym_to_version); -#endif - /* free all sections */ for(i = 1; i < s1->nb_sections; i++) free_section(s1->sections[i]); @@ -130,8 +93,7 @@ void tccelf_delete(TCCState *s1) free_section(s1->priv_sections[i]); dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); - tcc_free(s1->sym_attrs); - symtab_section = NULL; /* for tccrun.c:rt_printline() */ + s1->symtab_section = NULL; /* for tccrun.c:rt_printline() */ } /* save section data state */ @@ -143,7 +105,7 @@ void tccelf_begin_file(TCCState *s1) s->sh_offset = s->data_offset; } /* disable symbol hashing during compilation */ - s = s1->symtab, s->reloc = s->hash, s->hash = NULL; + s = s1->symtab_section, s->reloc = s->hash, s->hash = NULL; } static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int first_sym); @@ -152,7 +114,7 @@ static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int fi with previously existing symbols */ void tccelf_end_file(TCCState *s1) { - Section *s = s1->symtab; + Section *s = s1->symtab_section; int first_sym, nb_syms, *tr, i; first_sym = s->sh_offset / sizeof (ElfSym); @@ -303,17 +265,6 @@ void *section_ptr_add(Section *sec, addr_t size) return sec->data + offset; } -#ifndef ELF_OBJ_ONLY -/* reserve at least 'size' bytes from section start */ -static void section_reserve(Section *sec, unsigned long size) -{ - if (size > sec->data_allocated) - section_realloc(sec, size); - if (size > sec->data_offset) - sec->data_offset = size; -} -#endif - static Section *have_section(TCCState *s1, const char *name) { Section *sec; @@ -486,8 +437,8 @@ addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc) pstrcpy(buf + 1, sizeof(buf) - 1, name); name = buf; } - sym_index = find_elf_sym(s1->symtab, name); - sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index]; + sym_index = find_elf_sym(s1->symtab_section, name); + sym = &((ElfW(Sym) *)s1->symtab_section->data)[sym_index]; if (!sym_index || sym->st_shndx == SHN_UNDEF) { if (err) tcc_error_noabort("%s not defined", name); @@ -496,44 +447,6 @@ addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc) return sym->st_value; } -/* return elf symbol value */ -void *tcc_get_symbol(TCCState *s, const char *name) -{ - addr_t addr = get_sym_addr(s, name, 0, 1); - return addr == -1 ? NULL : (void*)(uintptr_t)addr; -} - -/* list elf symbol names and values */ -void list_elf_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)) -{ - ElfW(Sym) *sym; - Section *symtab; - int sym_index, end_sym; - const char *name; - unsigned char sym_vis, sym_bind; - - symtab = s->symtab; - end_sym = symtab->data_offset / sizeof (ElfSym); - for (sym_index = 0; sym_index < end_sym; ++sym_index) { - sym = &((ElfW(Sym) *)symtab->data)[sym_index]; - if (sym->st_value) { - name = (char *) symtab->link->data + sym->st_name; - sym_bind = ELFW(ST_BIND)(sym->st_info); - sym_vis = ELFW(ST_VISIBILITY)(sym->st_other); - if (sym_bind == STB_GLOBAL && sym_vis == STV_DEFAULT) - symbol_cb(ctx, name, (void*)(uintptr_t)sym->st_value); - } - } -} - -/* list elf symbol names and values */ -void tcc_list_symbols(TCCState *s, void *ctx, - void (*symbol_cb)(void *ctx, const char *name, const void *val)) -{ - list_elf_symbols(s, ctx, symbol_cb); -} - /* add an elf symbol : check if it is already defined and patch it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ int set_elf_sym(Section *s, addr_t value, unsigned long size, @@ -583,13 +496,12 @@ int set_elf_sym(Section *s, addr_t value, unsigned long size, /* keep first-found weak definition, ignore subsequents */ } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { /* ignore hidden symbols after */ - } else if ((esym->st_shndx == SHN_COMMON - || esym->st_shndx == s1->bss_section->sh_num) + } else if (esym->st_shndx == s1->bss_section->sh_num && (shndx < SHN_LORESERVE && shndx != s1->bss_section->sh_num)) { /* data symbol gets precedence over common/bss */ goto do_patch; - } else if (shndx == SHN_COMMON || shndx == s1->bss_section->sh_num) { + } else if (shndx == s1->bss_section->sh_num) { /* data symbol keeps precedence over common/bss */ } else if (s->sh_flags & SHF_DYNSYM) { /* we accept that two DLL define the same symbol */ @@ -598,10 +510,6 @@ int set_elf_sym(Section *s, addr_t value, unsigned long size, we can override. */ goto do_patch; } else { -#if 0 - printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", - sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); -#endif tcc_error_noabort("'%s' defined twice", name); } } else { @@ -659,27 +567,6 @@ void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, put_elf_reloca(symtab, s, offset, type, symbol, 0); } -struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) -{ - int n; - struct sym_attr *tab; - - if (index >= s1->nb_sym_attrs) { - if (!alloc) - return s1->sym_attrs; - /* find immediately bigger power of 2 and reallocate array */ - n = 1; - while (index >= n) - n *= 2; - tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); - s1->sym_attrs = tab; - memset(s1->sym_attrs + s1->nb_sym_attrs, 0, - (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); - s1->nb_sym_attrs = n; - } - return &s1->sym_attrs[index]; -} - static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int first_sym) { int i, type, sym_index; @@ -701,184 +588,6 @@ static void update_relocs(TCCState *s1, Section *s, int *old_to_new_syms, int fi } } -/* In an ELF file symbol table, the local symbols must appear below - the global and weak ones. Since TCC cannot sort it while generating - the code, we must do it after. All the relocation tables are also - modified to take into account the symbol table sorting */ -static void sort_syms(TCCState *s1, Section *s) -{ - int *old_to_new_syms; - ElfW(Sym) *new_syms; - int nb_syms, i; - ElfW(Sym) *p, *q; - - nb_syms = s->data_offset / sizeof(ElfW(Sym)); - new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); - old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); - - /* first pass for local symbols */ - p = (ElfW(Sym) *)s->data; - q = new_syms; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - /* save the number of local symbols in section header */ - if( s->sh_size ) /* this 'if' makes IDA happy */ - s->sh_info = q - new_syms; - - /* then second pass for non local symbols */ - p = (ElfW(Sym) *)s->data; - for(i = 0; i < nb_syms; i++) { - if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - p++; - } - - /* we copy the new symbols to the old */ - memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); - tcc_free(new_syms); - - update_relocs(s1, s, old_to_new_syms, 0); - tcc_free(old_to_new_syms); -} - -#ifndef ELF_OBJ_ONLY -/* See: https://flapenguin.me/elf-dt-gnu-hash */ -#define ELFCLASS_BITS (PTR_SIZE * 8) - -static Elf32_Word elf_gnu_hash (const unsigned char *name) -{ - Elf32_Word h = 5381; - unsigned char c; - - while ((c = *name++)) - h = h * 33 + c; - return h; -} - -static void update_gnu_hash(TCCState *s1, Section *gnu_hash) -{ - int *old_to_new_syms; - ElfW(Sym) *new_syms; - int nb_syms, i, nbuckets, bloom_size, bloom_shift; - ElfW(Sym) *p, *q; - Section *vs; - Section *dynsym = s1->dynsym; - Elf32_Word *ptr, *buckets, *chain, *hash; - unsigned int *nextbuck; - addr_t *bloom; - unsigned char *strtab; - struct { int first, last; } *buck; - - strtab = dynsym->link->data; - nb_syms = dynsym->data_offset / sizeof(ElfW(Sym)); - new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); - old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); - hash = tcc_malloc(nb_syms * sizeof(Elf32_Word)); - nextbuck = tcc_malloc(nb_syms * sizeof(int)); - - /* calculate hashes and copy undefs */ - p = (ElfW(Sym) *)dynsym->data; - q = new_syms; - for(i = 0; i < nb_syms; i++, p++) { - if (p->st_shndx == SHN_UNDEF) { - old_to_new_syms[i] = q - new_syms; - *q++ = *p; - } - else - hash[i] = elf_gnu_hash(strtab + p->st_name); - } - - ptr = (Elf32_Word *) gnu_hash->data; - nbuckets = ptr[0]; - bloom_size = ptr[2]; - bloom_shift = ptr[3]; - bloom = (addr_t *) (void *) &ptr[4]; - buckets = (Elf32_Word*) (void *) &bloom[bloom_size]; - chain = &buckets[nbuckets]; - buck = tcc_malloc(nbuckets * sizeof(*buck)); - - if (gnu_hash->data_offset != 4 * 4 + - PTR_SIZE * bloom_size + - nbuckets * 4 + - (nb_syms - (q - new_syms)) * 4) - tcc_error_noabort ("gnu_hash size incorrect"); - - /* find buckets */ - for(i = 0; i < nbuckets; i++) - buck[i].first = -1; - - p = (ElfW(Sym) *)dynsym->data; - for(i = 0; i < nb_syms; i++, p++) - if (p->st_shndx != SHN_UNDEF) { - int bucket = hash[i] % nbuckets; - - if (buck[bucket].first == -1) - buck[bucket].first = buck[bucket].last = i; - else { - nextbuck[buck[bucket].last] = i; - buck[bucket].last = i; - } - } - - /* fill buckets/chains/bloom and sort symbols */ - p = (ElfW(Sym) *)dynsym->data; - for(i = 0; i < nbuckets; i++) { - int cur = buck[i].first; - - if (cur != -1) { - buckets[i] = q - new_syms; - for (;;) { - old_to_new_syms[cur] = q - new_syms; - *q++ = p[cur]; - *chain++ = hash[cur] & ~1; - bloom[(hash[cur] / ELFCLASS_BITS) % bloom_size] |= - (addr_t)1 << (hash[cur] % ELFCLASS_BITS) | - (addr_t)1 << ((hash[cur] >> bloom_shift) % ELFCLASS_BITS); - if (cur == buck[i].last) - break; - cur = nextbuck[cur]; - } - chain[-1] |= 1; - } - } - - memcpy(dynsym->data, new_syms, nb_syms * sizeof(ElfW(Sym))); - tcc_free(new_syms); - tcc_free(hash); - tcc_free(buck); - tcc_free(nextbuck); - - update_relocs(s1, dynsym, old_to_new_syms, 0); - - /* modify the versions */ - vs = versym_section; - if (vs) { - ElfW(Half) *newver, *versym = (ElfW(Half) *)vs->data; - - if (1/*versym*/) { - newver = tcc_malloc(nb_syms * sizeof(*newver)); - for (i = 0; i < nb_syms; i++) - newver[old_to_new_syms[i]] = versym[i]; - memcpy(vs->data, newver, nb_syms * sizeof(*newver)); - tcc_free(newver); - } - } - - tcc_free(old_to_new_syms); - - /* rebuild hash */ - ptr = (Elf32_Word *) dynsym->hash->data; - rebuild_hash(dynsym, ptr[0]); -} -#endif /* ELF_OBJ_ONLY */ - /* relocate symbol table, resolve undefined symbols if do_resolve is true and output error if undefined symbol. */ void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) @@ -892,12 +601,11 @@ void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) if (sh_num == SHN_UNDEF) { if (do_resolve == 2) /* relocating dynsym */ continue; - name = (char *) s1->symtab->link->data + sym->st_name; + name = (char *) s1->symtab_section->link->data + sym->st_name; /* Use ld.so to resolve symbol for us (for tcc -run) */ if (do_resolve) { /* if dynamic symbol exist, it will be used in relocate_section */ - } else if (s1->dynsym && find_elf_sym(s1->dynsym, name)) - goto found; + } /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ if (!strcmp(name, "_fp_hw")) @@ -932,7 +640,7 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) for_each_elem(sr, 0, rel, ElfW_Rel) { ptr = s->data + rel->r_offset; sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + sym = &((ElfW(Sym) *)s1->symtab_section->data)[sym_index]; type = ELFW(R_TYPE)(rel->r_info); tgt = sym->st_value; #if SHT_RELX == SHT_RELA @@ -941,12 +649,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) addr = s->sh_addr + rel->r_offset; relocate(s1, rel, type, ptr, addr, tgt); } -#ifndef ELF_OBJ_ONLY - /* if the relocation is allocated, we change its symbol table */ - if (sr->sh_flags & SHF_ALLOC) { - sr->link = s1->dynsym; - } -#endif } /* relocate all sections */ @@ -972,236 +674,12 @@ void relocate_sections(TCCState *s1) } } - -#ifdef NEED_BUILD_GOT -static int build_got(TCCState *s1) -{ - /* if no got, then create it */ - s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - s1->got->sh_entsize = 4; - /* keep space for _DYNAMIC pointer and two dummy got entries */ - section_ptr_add(s1->got, 3 * PTR_SIZE); - return set_elf_sym(symtab_section, 0, 0, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), - 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); -} - -/* Create a GOT and (for function call) a PLT entry corresponding to a symbol - in s1->symtab. When creating the dynamic symbol table entry for the GOT - relocation, use 'size' and 'info' for the corresponding symbol metadata. - Returns the offset of the GOT or (if any) PLT entry. */ -static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, - int sym_index) -{ - int need_plt_entry; - const char *name; - ElfW(Sym) *sym; - struct sym_attr *attr; - unsigned got_offset; - char plt_name[200]; - int len; - Section *s_rel; - - need_plt_entry = (dyn_reloc_type == R_JMP_SLOT); - attr = get_sym_attr(s1, sym_index, 1); - - /* In case a function is both called and its address taken 2 GOT entries - are created, one for taking the address (GOT) and the other for the PLT - entry (PLTGOT). */ - if (need_plt_entry ? attr->plt_offset : attr->got_offset) - return attr; - - s_rel = s1->got; - if (need_plt_entry) { - if (!s1->plt) { - s1->plt = new_section(s1, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); - s1->plt->sh_entsize = 4; - } - s_rel = s1->plt; - } - - /* create the GOT entry */ - got_offset = s1->got->data_offset; - section_ptr_add(s1->got, PTR_SIZE); - - /* Create the GOT relocation that will insert the address of the object or - function of interest in the GOT entry. This is a static relocation for - memory output (dlsym will give us the address of symbols) and dynamic - relocation otherwise (executable and DLLs). The relocation should be - done lazily for GOT entry with *_JUMP_SLOT relocation type (the one - associated to a PLT entry) but is currently done at load time for an - unknown reason. */ - - sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - name = (char *) symtab_section->link->data + sym->st_name; - //printf("sym %d %s\n", need_plt_entry, name); - - if (s1->dynsym) { - if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { - /* Hack alarm. We don't want to emit dynamic symbols - and symbol based relocs for STB_LOCAL symbols, but rather - want to resolve them directly. At this point the symbol - values aren't final yet, so we must defer this. We will later - have to create a RELATIVE reloc anyway, so we misuse the - relocation slot to smuggle the symbol reference until - fill_local_got_entries. Not that the sym_index is - relative to symtab_section, not s1->dynsym! Nevertheless - we use s1->dyn_sym so that if this is the first call - that got->reloc is correctly created. Also note that - RELATIVE relocs are not normally created for the .got, - so the types serves as a marker for later (and is retained - also for the final output, which is okay because then the - got is just normal data). */ - put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE, - sym_index); - } else { - if (0 == attr->dyn_index) - attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, - sym->st_size, sym->st_info, 0, - sym->st_shndx, name); - put_elf_reloc(s1->dynsym, s_rel, got_offset, dyn_reloc_type, - attr->dyn_index); - } - } else { - put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type, - sym_index); - } - - if (need_plt_entry) { - attr->plt_offset = create_plt_entry(s1, got_offset, attr); - - /* create a symbol 'sym@plt' for the PLT jump vector */ - len = strlen(name); - if (len > sizeof plt_name - 5) - len = sizeof plt_name - 5; - memcpy(plt_name, name, len); - strcpy(plt_name + len, "@plt"); - attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name); - } else { - attr->got_offset = got_offset; - } - - return attr; -} - -/* build GOT and PLT entries */ -/* Two passes because R_JMP_SLOT should become first. Some targets - (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */ -void build_got_entries(TCCState *s1, int got_sym) -{ - Section *s; - ElfW_Rel *rel; - ElfW(Sym) *sym; - int i, type, gotplt_entry, reloc_type, sym_index; - struct sym_attr *attr; - int pass = 0; -redo: - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - type = ELFW(R_TYPE)(rel->r_info); - gotplt_entry = gotplt_entry_type(type); - if (gotplt_entry == -1) { - tcc_error_noabort ("Unknown relocation type for got: %d", type); - continue; - } - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - - if (gotplt_entry == NO_GOTPLT_ENTRY) { - continue; - } - - /* Automatically create PLT/GOT [entry] if it is an undefined - reference (resolved at runtime), or the symbol is absolute, - probably created by tcc_add_symbol, and thus on 64-bit - targets might be too far from application code. */ - if (gotplt_entry == AUTO_GOTPLT_ENTRY) { - if (sym->st_shndx == SHN_UNDEF) { - ElfW(Sym) *esym; - int dynindex; - - /* Relocations for UNDEF symbols would normally need - to be transferred into the executable or shared object. - If that were done AUTO_GOTPLT_ENTRY wouldn't exist. - But TCC doesn't do that (at least for exes), so we - need to resolve all such relocs locally. And that - means PLT slots for functions in DLLs and COPY relocs for - data symbols. COPY relocs were generated in - bind_exe_dynsyms (and the symbol adjusted to be defined), - and for functions we were generated a dynamic symbol - of function type. */ - if (s1->dynsym) { - /* dynsym isn't set for -run :-/ */ - dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; - esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; - if (dynindex - && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC - || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE - && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC))) - goto jmp_slot; - } - } else if (sym->st_shndx == SHN_ABS) { - if (sym->st_value == 0) /* from tcc_add_btstub() */ - continue; - if (PTR_SIZE != 8) - continue; - /* from tcc_add_symbol(): on 64 bit platforms these - need to go through .got */ - } else - continue; - } - - reloc_type = code_reloc(type); - if (reloc_type == -1) { - tcc_error_noabort ("Unknown relocation type: %d", type); - continue; - } - - if (reloc_type != 0) { - jmp_slot: - if (pass != 0) - continue; - reloc_type = R_JMP_SLOT; - } else { - if (pass != 1) - continue; - reloc_type = R_GLOB_DAT; - } - - if (!s1->got) - got_sym = build_got(s1); - - if (gotplt_entry == BUILD_GOT_ONLY) - continue; - - attr = put_got_entry(s1, reloc_type, sym_index); - - if (reloc_type == R_JMP_SLOT) - rel->r_info = ELFW(R_INFO)(attr->plt_sym, type); - } - } - if (++pass < 2) - goto redo; - /* .rel.plt refers to .got actually */ - if (s1->plt && s1->plt->reloc) - s1->plt->reloc->sh_info = s1->got->sh_num; - if (got_sym) /* set size */ - ((ElfW(Sym)*)symtab_section->data)[got_sym].st_size = s1->got->data_offset; -} -#endif /* def NEED_BUILD_GOT */ - int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) { int shn = sec ? sec->sh_num : offs || !name ? SHN_ABS : SHN_UNDEF; if (sec && offs == -1) offs = sec->data_offset; - return set_elf_sym(symtab_section, offs, 0, + return set_elf_sym(s1->symtab_section, offs, 0, ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); } @@ -1229,7 +707,7 @@ void add_array (TCCState *s1, const char *sec, int c) s = find_section(s1, sec); s->sh_flags = shf_RELRO; s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; - put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); + put_elf_reloc (s1->symtab_section, s, s->data_offset, R_DATA_PTR, c); section_ptr_add(s, PTR_SIZE); } @@ -1265,8 +743,7 @@ void tcc_add_runtime(TCCState *s1) if (TCC_LIBTCC1[0]) tcc_add_support(s1, TCC_LIBTCC1); - if (s1->output_type != TCC_OUTPUT_MEMORY) - tccelf_add_crtend(s1); + tccelf_add_crtend(s1); } } #endif /* ndef TCC_TARGET_PE */ @@ -1323,7 +800,7 @@ void resolve_common_syms(TCCState *s1) ElfW(Sym) *sym; /* Allocate common symbols in BSS. */ - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { + for_each_elem(s1->symtab_section, 1, sym, ElfW(Sym)) { if (sym->st_shndx == SHN_COMMON) { /* symbol alignment is in st_value for SHN_COMMONs */ sym->st_value = section_add(s1->bss_section, sym->st_size, @@ -1337,76 +814,6 @@ void resolve_common_syms(TCCState *s1) } #ifndef ELF_OBJ_ONLY -void fill_got_entry(TCCState *s1, ElfW_Rel *rel) -{ - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - - if (0 == offset) - return; - section_reserve(s1->got, offset + PTR_SIZE); -#if PTR_SIZE == 8 - write64le(s1->got->data + offset, sym->st_value); -#else - write32le(s1->got->data + offset, sym->st_value); -#endif -} - -/* Perform relocation to GOT or PLT entries */ -void fill_got(TCCState *s1) -{ - Section *s; - ElfW_Rel *rel; - int i; - - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - if (s->sh_type != SHT_RELX) - continue; - /* no need to handle got relocations */ - if (s->link != symtab_section) - continue; - for_each_elem(s, 0, rel, ElfW_Rel) { - switch (ELFW(R_TYPE) (rel->r_info)) { - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - fill_got_entry(s1, rel); - break; - } - } - } -} - -/* See put_got_entry for a description. This is the second stage - where GOT references to local defined symbols are rewritten. */ -static void fill_local_got_entries(TCCState *s1) -{ - ElfW_Rel *rel; - if (!s1->got->reloc) - return; - for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) { - if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) { - int sym_index = ELFW(R_SYM) (rel->r_info); - ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; - struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); - unsigned offset = attr->got_offset; - if (offset != rel->r_offset - s1->got->sh_addr) - tcc_error_noabort("fill_local_got_entries: huh?"); - rel->r_info = ELFW(R_INFO)(0, R_RELATIVE); -#if SHT_RELX == SHT_RELA - rel->r_addend = sym->st_value; -#else - /* All our REL architectures also happen to be 32bit LE. */ - write32le(s1->got->data + offset, sym->st_value); -#endif - } - } -} /* decide if an unallocated section should be output. */ static int set_sec_sizes(TCCState *s1) @@ -1492,8 +899,6 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) k = 0x13; } else if (s->sh_type == SHT_RELX) { k = 0x20; - if (s1->plt && s == s1->plt->reloc) - k = 0x21; } else if (s->sh_flags & SHF_EXECINSTR) { k = 0x30; /* RELRO sections --> */ @@ -1505,8 +910,6 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) k = 0x43; } else if (s->sh_type == SHT_DYNAMIC) { k = 0x46; - } else if (s == s1->got) { - k = 0x47; /* .got as RELRO needs BIND_NOW in DT_FLAGS */ } else if (s->reloc && (s->reloc->sh_flags & SHF_ALLOC) && j == 0x100) { k = 0x44; /* <-- */ @@ -1596,8 +999,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) ++phnum; if (d->dynamic) ++phnum; - if (eh_frame_hdr_section) - ++phnum; if (d->roinf) ++phnum; d->phnum = phnum; @@ -1716,8 +1117,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) fill_phdr(++ph, PT_NOTE, d->note); if (d->dynamic) fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W; - if (eh_frame_hdr_section) - fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section); if (d->roinf) fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W; if (d->interp) @@ -1733,84 +1132,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) return 0; } -/* put dynamic tag */ -static void put_dt(Section *dynamic, int dt, addr_t val) -{ - ElfW(Dyn) *dyn; - dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); - dyn->d_tag = dt; - dyn->d_un.d_val = val; -} - -/* Fill the dynamic section with tags describing the address and size of - sections */ -static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) -{ - Section *dynamic = dyninf->dynamic; - Section *s; - - /* put dynamic section entries */ - put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); - put_dt(dynamic, DT_GNU_HASH, dyninf->gnu_hash->sh_addr); - put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); - put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); - put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); - put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); -#if PTR_SIZE == 8 - put_dt(dynamic, DT_RELA, dyninf->rel_addr); - put_dt(dynamic, DT_RELASZ, dyninf->rel_size); - put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); - if (s1->plt && s1->plt->reloc) { - put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); - put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset); - put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr); - put_dt(dynamic, DT_PLTREL, DT_RELA); - } - put_dt(dynamic, DT_RELACOUNT, 0); -#else - put_dt(dynamic, DT_REL, dyninf->rel_addr); - put_dt(dynamic, DT_RELSZ, dyninf->rel_size); - put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); - if (s1->plt && s1->plt->reloc) { - put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); - put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset); - put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr); - put_dt(dynamic, DT_PLTREL, DT_REL); - } - put_dt(dynamic, DT_RELCOUNT, 0); -#endif - if (versym_section && verneed_section) { - /* The dynamic linker can not handle VERSYM without VERNEED */ - put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); - put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); - put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); - } - s = have_section(s1, ".preinit_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); - put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".init_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); - put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".fini_array"); - if (s && s->data_offset) { - put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); - put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); - } - s = have_section(s1, ".init"); - if (s && s->data_offset) { - put_dt(dynamic, DT_INIT, s->sh_addr); - } - s = have_section(s1, ".fini"); - if (s && s->data_offset) { - put_dt(dynamic, DT_FINI, s->sh_addr); - } - put_dt(dynamic, DT_NULL, 0); -} - /* Remove gaps between RELX sections. These gaps are a result of final_sections_reloc. Here some relocs are removed. The gaps are then filled with 0 in tcc_output_elf. The 0 is intepreted as @@ -1821,14 +1142,13 @@ static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf) int i; unsigned long file_offset = 0; Section *s; - Section *relocplt = s1->plt ? s1->plt->reloc : NULL; /* dynamic relocation table information, for .dynamic section */ dyninf->rel_addr = dyninf->rel_size = 0; for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; - if (s->sh_type == SHT_RELX && s != relocplt) { + if (s->sh_type == SHT_RELX) { if (dyninf->rel_size == 0) { dyninf->rel_addr = s->sh_addr; file_offset = s->sh_offset; @@ -1885,8 +1205,6 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr) return -1; } - sort_syms(s1, s1->symtab); - ehdr.e_machine = EM_386; ehdr.e_version = EV_CURRENT; ehdr.e_shoff = (sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)) + 3) & -4; @@ -2055,8 +1373,6 @@ static int elf_output_file(TCCState *s1, const char *filename) tcc_add_runtime(s1); resolve_common_syms(s1); - build_got_entries(s1, 0); - textrel = set_sec_sizes(s1); /* create and fill .shstrtab section */ @@ -2065,36 +1381,12 @@ static int elf_output_file(TCCState *s1, const char *filename) sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); /* compute section to program header mapping */ layout_sections(s1, sec_order, &dyninf); - - if (dynamic) { - /* put in GOT the dynamic section address and relocate PLT */ - write32le(s1->got->data, dynamic->sh_addr); - if (file_type == TCC_OUTPUT_EXE) - relocate_plt(s1); - /* relocate symbols in .dynsym now that final addresses are known */ - relocate_syms(s1, s1->dynsym, 2); - } - /* if building executable or DLL, then relocate each section except the GOT which is already relocated */ - relocate_syms(s1, s1->symtab, 0); + relocate_syms(s1, s1->symtab_section, 0); if (s1->nb_errors != 0) goto the_end; relocate_sections(s1); - if (dynamic) { - update_reloc_sections (s1, &dyninf); - dynamic->data_offset = dyninf.data_offset; - fill_dynamic(s1, &dyninf); - } - /* Perform relocation to GOT or PLT entries */ - if (file_type == TCC_OUTPUT_EXE) - fill_got(s1); - else if (s1->got) - fill_local_got_entries(s1); - - if (dyninf.gnu_hash) - update_gnu_hash(s1, dyninf.gnu_hash); - reorder_sections(s1, sec_order); /* Create the ELF file with name 'filename' */ @@ -2150,11 +1442,7 @@ int tcc_output_file(TCCState *s, const char *filename) { if (s->output_type == TCC_OUTPUT_OBJ) return elf_output_obj(s, filename); -#ifdef TCC_TARGET_PE - return pe_output_file(s, filename); -#else return elf_output_file(s, filename); -#endif } ssize_t full_read(int fd, void *buf, size_t count) { @@ -2255,7 +1543,7 @@ invalid: } nb_syms = sh->sh_size / sizeof(ElfW(Sym)); symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); - sm_table[i].s = symtab_section; + sm_table[i].s = s1->symtab_section; /* now load strtab */ sh = &shdr[sh->sh_link]; @@ -2299,12 +1587,6 @@ invalid: s = s1->sections[j]; if (strcmp(s->old_name, sh_name)) continue; - if (sh->sh_type != s->sh_type - && strcmp (s->old_name, ".eh_frame") - ) { - tcc_error_noabort("section type conflict: %s %02x <> %02x", s->old_name, sh->sh_type, s->sh_type); - goto the_end; - } if (!strncmp(sh_name, ".gnu.linkonce", 13)) { /* if a 'linkonce' section is already present, we do not add it again. It is a little tricky as @@ -2342,7 +1624,7 @@ invalid: /* align end of section */ /* This is needed if we compile a c file after this */ if (s == s1->text_section || s == s1->data_section || s == s1->rodata_section || - s == s1->bss_section || s == common_section) + s == s1->bss_section) s->data_offset += -s->data_offset & (s->sh_addralign - 1); next: ; } @@ -2377,7 +1659,7 @@ invalid: correct relocations */ if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { name = strtab + sym->st_name; - sym_index = find_elf_sym(symtab_section, name); + sym_index = find_elf_sym(s1->symtab_section, name); if (sym_index) old_to_new_syms[i] = sym_index; } @@ -2393,7 +1675,7 @@ invalid: } /* add symbol */ name = strtab + sym->st_name; - sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size, + sym_index = set_elf_sym(s1->symtab_section, sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx, name); old_to_new_syms[i] = sym_index; @@ -2511,7 +1793,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) do { bound = 0; for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { - Section *s = symtab_section; + Section *s = s1->symtab_section; sym_index = find_elf_sym(s, p); if (!sym_index) continue; @@ -2575,273 +1857,4 @@ int tcc_load_archive(TCCState *s1, int fd, int alacarte) /* align to even */ file_offset = (file_offset + size + 1) & ~1; } -} - -#ifndef ELF_OBJ_ONLY - -struct versym_info { - int nb_versyms; - ElfW(Verdef) *verdef; - ElfW(Verneed) *verneed; - ElfW(Half) *versym; - int nb_local_ver, *local_ver; -}; - - -#define LD_TOK_NAME 256 -#define LD_TOK_EOF (-1) - -static int ld_inp(TCCState *s1) -{ - char b; - if (s1->cc != -1) { - int c = s1->cc; - s1->cc = -1; - return c; - } - if (1 == read(s1->fd, &b, 1)) - return b; - return CH_EOF; -} - -/* return next ld script token */ -static int ld_next(TCCState *s1, char *name, int name_size) -{ - int c, d, ch; - char *q; - - redo: - ch = ld_inp(s1); - switch(ch) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - case '\n': - goto redo; - case '/': - ch = ld_inp(s1); - if (ch == '*') { /* comment */ - for (d = 0;; d = ch) { - ch = ld_inp(s1); - if (ch == CH_EOF || (ch == '/' && d == '*')) - break; - } - goto redo; - } else { - q = name; - *q++ = '/'; - goto parse_name; - } - break; - case '\\': - /* case 'a' ... 'z': */ - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - /* case 'A' ... 'z': */ - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case '.': - case '$': - case '~': - q = name; - parse_name: - for(;;) { - if (!((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || - strchr("/.-_+=$:\\,~", ch))) - break; - if ((q - name) < name_size - 1) { - *q++ = ch; - } - ch = ld_inp(s1); - } - s1->cc = ch; - *q = '\0'; - c = LD_TOK_NAME; - break; - case CH_EOF: - c = LD_TOK_EOF; - break; - default: - c = ch; - break; - } - return c; -} - -static int ld_add_file(TCCState *s1, const char filename[]) -{ - if (filename[0] == '/') { - if (CONFIG_SYSROOT[0] == '\0' - && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0) - return 0; - filename = tcc_basename(filename); - } - return -1; -} - -static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) -{ - char filename[1024], libname[1016]; - int t, group, nblibs = 0, ret = 0; - char **libs = NULL; - - group = !strcmp(cmd, "GROUP"); - if (!as_needed) - s1->new_undef_sym = 0; - t = ld_next(s1, filename, sizeof(filename)); - if (t != '(') { - ret = tcc_error_noabort("( expected"); - goto lib_parse_error; - } - t = ld_next(s1, filename, sizeof(filename)); - for(;;) { - libname[0] = '\0'; - if (t == LD_TOK_EOF) { - ret = tcc_error_noabort("unexpected end of file"); - goto lib_parse_error; - } else if (t == ')') { - break; - } else if (t == '-') { - t = ld_next(s1, filename, sizeof(filename)); - if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { - ret = tcc_error_noabort("library name expected"); - goto lib_parse_error; - } - pstrcpy(libname, sizeof libname, &filename[1]); - snprintf(filename, sizeof filename, "lib%s.a", libname); - } else if (t != LD_TOK_NAME) { - ret = tcc_error_noabort("filename expected"); - goto lib_parse_error; - } - if (!strcmp(filename, "AS_NEEDED")) { - ret = ld_add_file_list(s1, cmd, 1); - if (ret) - goto lib_parse_error; - } else { - /* TODO: Implement AS_NEEDED support. */ - /* DT_NEEDED is not used any more so ignore as_needed */ - if (1 || !as_needed) { - ret = ld_add_file(s1, filename); - if (ret) - goto lib_parse_error; - if (group) { - /* Add the filename *and* the libname to avoid future conversions */ - dynarray_add(&libs, &nblibs, tcc_strdup(filename)); - if (libname[0] != '\0') - dynarray_add(&libs, &nblibs, tcc_strdup(libname)); - } - } - } - t = ld_next(s1, filename, sizeof(filename)); - if (t == ',') { - t = ld_next(s1, filename, sizeof(filename)); - } - } - if (group && !as_needed) { - while (s1->new_undef_sym) { - int i; - s1->new_undef_sym = 0; - for (i = 0; i < nblibs; i ++) - ld_add_file(s1, libs[i]); - } - } -lib_parse_error: - dynarray_reset(&libs, &nblibs); - return ret; -} - -/* interpret a subset of GNU ldscripts to handle the dummy libc.so - files */ -int tcc_load_ldscript(TCCState *s1, int fd) -{ - char cmd[64]; - char filename[1024]; - int t, ret; - - s1->fd = fd; - s1->cc = -1; - for(;;) { - t = ld_next(s1, cmd, sizeof(cmd)); - if (t == LD_TOK_EOF) - return 0; - else if (t != LD_TOK_NAME) - return -1; - if (!strcmp(cmd, "INPUT") || - !strcmp(cmd, "GROUP")) { - ret = ld_add_file_list(s1, cmd, 0); - if (ret) - return ret; - } else if (!strcmp(cmd, "OUTPUT_FORMAT") || - !strcmp(cmd, "TARGET")) { - /* ignore some commands */ - t = ld_next(s1, cmd, sizeof(cmd)); - if (t != '(') - return tcc_error_noabort("( expected"); - for(;;) { - t = ld_next(s1, filename, sizeof(filename)); - if (t == LD_TOK_EOF) { - return tcc_error_noabort("unexpected end of file"); - } else if (t == ')') { - break; - } - } - } else { - return -1; - } - } - return 0; -} -#endif /* !ELF_OBJ_ONLY */ +} \ No newline at end of file diff --git a/tcc-doc.texi b/tcc-doc.texi index 8d172c2a..6cca4dee 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -284,7 +284,7 @@ Specify an additional static library path for the @option{-l} option. The default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}. @item -lxxx -Link your program with dynamic library libxxx.so or static library +Link your program with static library libxxx.a. The library is searched in the paths specified by the @option{-L} option and @env{LIBRARY_PATH} variable. @@ -292,30 +292,14 @@ libxxx.a. The library is searched in the paths specified by the Set the path where the tcc internal libraries (and include files) can be found (default is @file{PREFIX/lib/tcc}). -@item -shared -Generate a shared library instead of an executable. - -@item -soname name -set name for shared library to be used at runtime @item -static Generate a statically linked executable (default is a shared linked executable). -@item -rdynamic -Export global symbols to the dynamic linker. It is useful when a library -opened with @code{dlopen()} needs to access executable symbols. - @item -r Generate an object file combining all input files. -@item -Wl,-rpath=path -Put custom search path for dynamic libraries into executable. - -@item -Wl,--enable-new-dtags -When putting a custom search path for dynamic libraries into the executable, -create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH. - @item -Wl,--oformat=fmt Use @var{fmt} as output format. The supported output formats are: @table @code @@ -327,11 +311,6 @@ Binary image (only for executable output) COFF output format (only for executable output for TMS320C67xx target) @end table -@item -Wl,--export-all-symbols -@item -Wl,--export-dynamic -Export global symbols to the dynamic linker. It is useful when a library -opened with @code{dlopen()} needs to access executable symbols. - @item -Wl,-subsystem=console/gui/wince/... Set type for PE (Windows) executables. @@ -827,13 +806,9 @@ Currently, MMX opcodes are supported but not SSE ones. @cindex ELF TCC can directly output relocatable ELF files (object files), -executable ELF files and dynamic ELF libraries without relying on an +executable ELF files without relying on an external linker. -Dynamic ELF libraries can be output but the C compiler does not generate -position independent code (PIC). It means that the dynamic library -code generated by TCC cannot be factorized among processes yet. - TCC linker eliminates unreferenced object code in libraries. A single pass is done on the object and library list, so the order in which object files and libraries are specified is important (same constraint as GNU ld). No grouping @@ -841,8 +816,7 @@ options (@option{--start-group} and @option{--end-group}) are supported. @section ELF file loader -TCC can load ELF object files, archives (.a files) and dynamic -libraries (.so). +TCC can load ELF object files and archives (.a files). @section PE-i386 file generation @cindex PE-i386 diff --git a/tcc/tcc.c b/tcc/tcc.c index c60eb955..ba89a28c 100644 --- a/tcc/tcc.c +++ b/tcc/tcc.c @@ -17,8 +17,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "config.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ #include @@ -50,7 +51,7 @@ static const char help_str[] = " -E preprocess only\n" "Linker options:\n" " -Ldir add library path 'dir'\n" - " -llib link with dynamic or static library 'lib'\n" + " -llib link with static library 'lib'\n" " -r generate (relocatable) object file\n" " -Wl,-opt[=val] set linker option (see tcc -hh)\n" "Misc. options:\n" @@ -89,14 +90,11 @@ static const char help_more_str[] = " discarded-qualifiers warn when const is dropped (*)\n" "-f[no-]... flags:\n" " unsigned-char default char is unsigned\n" - " signed-char default char is signed\n" - " common use common section instead of bss\n" - " leading-underscore decorate extern symbols\n" + " signed-char default char is signed\n" " leading-underscore decorate extern symbols\n" " ms-extensions allow anonymous struct in struct\n" " dollars-in-identifiers allow '$' in C symbols\n" " reverse-funcargs evaluate function arguments right to left\n" " gnu89-inline 'extern inline' is like 'static inline'\n" - " asynchronous-unwind-tables create eh_frame section [on]\n" "-m... target specific options:\n" " ms-bitfields use MSVC bitfield layout\n" "-Wl,... linker options:\n" @@ -104,7 +102,6 @@ static const char help_more_str[] = " -[no-]whole-archive load lib(s) fully/only as needed\n" " -image-base= -Ttext= set base address of executable\n" " -section-alignment= set section alignment in executable\n" - " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n" " -oformat=[coff,binary] set executable output format\n" " -init= -fini= -Map= -as-needed -O (ignored)\n" "Predefined macros:\n" @@ -221,13 +218,6 @@ redo: return tcc_tool_ar(s, argc, argv); if (opt == TCC_OPT_VERSION) return 0; - if (opt == TCC_OPT_PRINT_DIRS) { - /* initialize search dirs */ - set_environment(s); - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - print_search_dirs(s); - return (EXIT_SUCCESS); - } if (s->nb_files == 0) { tcc_error_noabort("no input files"); @@ -279,15 +269,12 @@ redo: if (s->output_type == TCC_OUTPUT_PREPROCESS) { ; } else if (0 == ret) { - if (s->output_type == TCC_OUTPUT_MEMORY) { - } else { if (!s->outfile) s->outfile = default_outputfile(s, first_file); if (!s->just_deps) ret = tcc_output_file(s, s->outfile); if (!ret && s->gen_deps) gen_makedeps(s, s->outfile, s->deps_outfile); - } } done = 1; diff --git a/tcc/tcctools.c b/tcc/tcctools.c index 620f6e8b..bfe1dd2a 100644 --- a/tcc/tcctools.c +++ b/tcc/tcctools.c @@ -27,6 +27,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ #include @@ -361,6 +364,9 @@ const int _dowildcard = 1; /* -------------------------------------------------------------- */ /* generate xxx.d file */ +static inline int is_space(int ch) { + return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; +} static char *escape_target_dep(const char *s) { char *res = tcc_malloc(strlen(s) * 2 + 1);