From 7ac43f6d19f9c54f449dee4319b8ebf8b2a4871f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 27 Jul 2002 23:08:04 +0000 Subject: [PATCH] better DLL generation - added size to all ELF symbols - dynamic hash table size --- tcc.c | 480 ++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 305 insertions(+), 175 deletions(-) diff --git a/tcc.c b/tcc.c index 2e4f0490..9155f234 100644 --- a/tcc.c +++ b/tcc.c @@ -76,8 +76,6 @@ #define TOK_HASH_SIZE 2048 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ #define SYM_HASH_SIZE 1031 -#define ELF_SYM_HASH_SIZE 2048 -#define ELF_DYNSYM_HASH_SIZE 32 /* token symbol management */ typedef struct TokenSym { @@ -147,6 +145,7 @@ typedef struct Section { unsigned long sh_size; /* section size (only used during output) */ unsigned long sh_addr; /* address at which the section is relocated */ unsigned long sh_offset; /* address at which the section is relocated */ + int nb_hashed_syms; /* used to resize the hash table */ struct Section *link; /* link to another section */ struct Section *reloc; /* corresponding section for relocation, if any */ struct Section *hash; /* hash table for symbols */ @@ -238,7 +237,7 @@ Section *lbounds_section; /* contains local data bound description */ /* symbol sections */ Section *symtab_section, *strtab_section; /* temporary dynamic symbol sections (for dll loading) */ -Section *dynsymtab_section, *dynstrtab_section; +Section *dynsymtab_section; /* exported dynamic symbol section */ Section *dynsym; /* got handling */ @@ -246,7 +245,8 @@ Section *got; unsigned long *got_offsets; int nb_got_offsets; int nb_plt_entries; - +/* give the correspondance from symtab indexes to dynsym indexes */ +int *symtab_to_dynsym; /* array of all loaded dlls (including those referenced by loaded dlls) */ @@ -596,8 +596,9 @@ static Sym *get_sym_ref(int t, Section *sec, /* section generation */ static void *section_ptr(Section *sec, unsigned long size); static void *section_ptr_add(Section *sec, unsigned long size); -void put_extern_sym(Sym *sym, Section *section, unsigned long value); -void greloc(Section *s, Sym *sym, unsigned long addr, int type); +static void put_extern_sym(Sym *sym, Section *section, + unsigned long value, unsigned long size); +static void greloc(Section *s, Sym *sym, unsigned long addr, int type); static int put_elf_str(Section *s, const char *sym); static int put_elf_sym(Section *s, unsigned long value, unsigned long size, @@ -822,10 +823,10 @@ Section *find_section(const char *name) } /* add a new relocation entry to symbol 'sym' in section 's' */ -void greloc(Section *s, Sym *sym, unsigned long offset, int type) +static void greloc(Section *s, Sym *sym, unsigned long offset, int type) { if (!sym->c) - put_extern_sym(sym, NULL, 0); + put_extern_sym(sym, NULL, 0, 0); /* now we can add ELF relocation info */ put_elf_reloc(symtab_section, s, offset, type, sym->c); } @@ -2536,17 +2537,16 @@ static Sym *get_sym_ref(int t, Section *sec, v = anon_sym++; sym = sym_push1(&global_stack, v, t | VT_STATIC, 0); sym->r = VT_CONST | VT_SYM; - put_extern_sym(sym, sec, offset); + put_extern_sym(sym, sec, offset, size); return sym; } /* push a reference to a section offset by adding a dummy symbol */ -/* XXX: add size */ -void vpush_ref(int t, Section *sec, unsigned long offset) +void vpush_ref(int t, Section *sec, unsigned long offset, unsigned long size) { CValue cval; - cval.sym = get_sym_ref(t, sec, offset, 0); + cval.sym = get_sym_ref(t, sec, offset, size); vsetc(t, VT_CONST | VT_SYM, &cval); } @@ -2760,30 +2760,24 @@ int gv(int rc) } else { if (is_float(vtop->t) && (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - int v; Sym *sym; int *ptr; - + unsigned long offset; + /* XXX: unify with initializers handling ? */ /* CPUs usually cannot use float constants, so we store them generically in data segment */ size = type_size(vtop->t, &align); - data_section->data_offset = (data_section->data_offset + - align - 1) & -align; + offset = (data_section->data_offset + align - 1) & -align; + data_section->data_offset = offset; /* XXX: not portable yet */ - ptr = section_ptr(data_section, size); + ptr = section_ptr_add(data_section, size); size = size >> 2; for(i=0;ic.tab[i]; - - v = anon_sym++; - sym = sym_push1(&global_stack, v, vtop->t | VT_STATIC, 0); - sym->r = VT_CONST | VT_SYM; - put_extern_sym(sym, data_section, data_section->data_offset); - + sym = get_sym_ref(vtop->t, data_section, offset, size << 2); vtop->r |= VT_LVAL | VT_SYM; vtop->c.sym = sym; - data_section->data_offset += size << 2; } #ifdef CONFIG_TCC_BCHECK if (vtop->r & VT_MUSTBOUND) @@ -4706,7 +4700,7 @@ void unary(void) t = VT_ARRAY | mk_pointer(VT_BYTE); s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT)); s->c = len; - vpush_ref(t, data_section, data_section->data_offset); + vpush_ref(t, data_section, data_section->data_offset, len); ptr = section_ptr_add(data_section, len); memcpy(ptr, funcname, len); next(); @@ -4724,9 +4718,9 @@ void unary(void) /* we must declare it as an array first to use initializer parser */ t = VT_ARRAY | mk_pointer(t); decl_initializer(t, data_section, data_offset, 1, 0); - data_offset += type_size(t, &align); - /* XXX: is it correct to put it exactly as an array ? */ - vpush_ref(t, data_section, fc); + size = type_size(t, &align); + data_offset += size; + vpush_ref(t, data_section, fc, size); data_section->data_offset = data_offset; } else { t = tok; @@ -5900,12 +5894,12 @@ void decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init, do_def: sym = sym_push(v, t, r | VT_SYM, 0); } - put_extern_sym(sym, sec, addr); + put_extern_sym(sym, sec, addr, size); } else { CValue cval; /* push global reference */ - sym = get_sym_ref(t, sec, addr, 0); + sym = get_sym_ref(t, sec, addr, size); cval.sym = sym; vsetc(t, VT_CONST | VT_SYM, &cval); } @@ -5942,7 +5936,6 @@ void put_func_debug(Sym *sym) funcname, sym->t & VT_STATIC ? 'f' : 'F'); put_stabs_r(buf, N_FUN, 0, file->line_num, 0, cur_text_section, sym->c); - func_ind = ind; last_ind = 0; last_line_num = 0; } @@ -6100,7 +6093,9 @@ void decl(int l) /* put function symbol */ sym = sym_push1(&global_stack, v, t, 0); } - put_extern_sym(sym, cur_text_section, ind); + /* NOTE: we patch the symbol size later */ + put_extern_sym(sym, cur_text_section, ind, 0); + func_ind = ind; sym->r = VT_SYM | VT_CONST; /* put debug symbol */ if (do_debug) @@ -6121,6 +6116,9 @@ void decl(int l) sym_pop(&label_stack, NULL); /* reset label stack */ sym_pop(&local_stack, NULL); /* reset local stack */ /* end of function */ + /* patch symbol size */ + ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = + ind - func_ind; if (do_debug) { put_stabn(N_FUN, 0, 0, ind - func_ind); } @@ -6322,6 +6320,40 @@ static unsigned long elf_hash(const unsigned char *name) return h; } +/* rebuild hash table of section s */ +/* NOTE: we do factorize the hash table code to go faster */ +static void rebuild_hash(Section *s, unsigned int nb_buckets) +{ + Elf32_Sym *sym; + int *ptr, *hash, nb_syms, sym_index, h; + char *strtab; + + strtab = s->link->data; + nb_syms = s->data_offset / sizeof(Elf32_Sym); + + s->hash->data_offset = 0; + ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); + ptr[0] = nb_buckets; + ptr[1] = nb_syms; + ptr += 2; + hash = ptr; + memset(hash, 0, (nb_buckets + 1) * sizeof(int)); + ptr += nb_buckets + 1; + + sym = (Elf32_Sym *)s->data + 1; + for(sym_index = 1; sym_index < nb_syms; sym_index++) { + if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { + h = elf_hash(strtab + sym->st_name) % nb_buckets; + *ptr = hash[h]; + hash[h] = sym_index; + } else { + *ptr = 0; + } + ptr++; + sym++; + } +} + /* return the symbol number */ static int put_elf_sym(Section *s, unsigned long value, unsigned long size, @@ -6347,20 +6379,26 @@ static int put_elf_sym(Section *s, sym_index = sym - (Elf32_Sym *)s->data; hs = s->hash; if (hs) { - int *ptr; + int *ptr, *base; ptr = section_ptr_add(hs, sizeof(int)); + base = (int *)hs->data; /* only add global or weak symbols */ if (ELF32_ST_BIND(info) != STB_LOCAL) { /* add another hashing entry */ - nbuckets = ((int *)hs->data)[0]; + nbuckets = base[0]; h = elf_hash(name) % nbuckets; - *ptr = ((int *)hs->data)[2 + h]; - ((int *)hs->data)[2 + h] = sym_index; + *ptr = base[2 + h]; + base[2 + h] = sym_index; + base[1]++; + /* we resize the hash table */ + hs->nb_hashed_syms++; + if (hs->nb_hashed_syms > 2 * nbuckets) { + rebuild_hash(s, 2 * nbuckets); + } } else { *ptr = 0; + base[1]++; } - /* but still add room for all symbols */ - ((int *)hs->data)[1]++; } return sym_index; } @@ -6457,7 +6495,8 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size, /* update sym->c so that it points to an external symbol in section 'section' with value 'value' */ -void put_extern_sym(Sym *sym, Section *section, unsigned long value) +static void put_extern_sym(Sym *sym, Section *section, + unsigned long value, unsigned long size) { int sym_type, sym_bind, sh_num, info; Elf32_Sym *esym; @@ -6502,10 +6541,11 @@ void put_extern_sym(Sym *sym, Section *section, unsigned long value) } #endif info = ELF32_ST_INFO(sym_bind, sym_type); - sym->c = add_elf_sym(symtab_section, value, 0, info, sh_num, name); + sym->c = add_elf_sym(symtab_section, value, size, info, sh_num, name); } else { esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; esym->st_value = value; + esym->st_size = size; esym->st_shndx = sh_num; } } @@ -6728,50 +6768,20 @@ static void relocate_syms(int do_resolve) } } -/* elf relocation, CPU dependant */ -static void elf_reloc(unsigned char *ptr, - unsigned long addr, unsigned long val, int type, - int sym_index) -{ - switch(type) { - case R_386_32: - *(int *)ptr += val; - break; - case R_386_PLT32: - case R_386_PC32: - *(int *)ptr += val - addr; - break; - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - *(int *)ptr = val; - break; - case R_386_GOTPC: - *(int *)ptr += got->sh_addr - addr; - break; - case R_386_GOTOFF: - *(int *)ptr += val - got->sh_addr; - break; - case R_386_GOT32: - /* we load the got offset */ - *(int *)ptr += got_offsets[sym_index]; - break; - } -} - - -/* relocate a given section */ -static void relocate_section(Section *s) +/* relocate a given section (CPU dependant) */ +static void relocate_section(TCCState *s1, Section *s) { Section *sr; - Elf32_Rel *rel, *rel_end; + Elf32_Rel *rel, *rel_end, *qrel; Elf32_Sym *sym; - int type, sym_index; + int type, sym_index, esym_index; unsigned char *ptr; - unsigned long val; + unsigned long val, addr; sr = s->reloc; rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); - for(rel = (Elf32_Rel *)sr->data; + qrel = (Elf32_Rel *)sr->data; + for(rel = qrel; rel < rel_end; rel++) { ptr = s->data + rel->r_offset; @@ -6780,8 +6790,60 @@ static void relocate_section(Section *s) sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; val = sym->st_value; type = ELF32_R_TYPE(rel->r_info); - elf_reloc(ptr, s->sh_addr + rel->r_offset, val, type, sym_index); + addr = s->sh_addr + rel->r_offset; + + /* CPU specific */ + switch(type) { + case R_386_32: + if (s1->output_type == TCC_OUTPUT_DLL) { + esym_index = symtab_to_dynsym[sym_index]; + qrel->r_offset = rel->r_offset; + if (esym_index) { + qrel->r_info = ELF32_R_INFO(esym_index, R_386_32); + qrel++; + break; + } else { + qrel->r_info = ELF32_R_INFO(0, R_386_RELATIVE); + qrel++; + } + } + *(int *)ptr += val; + break; + case R_386_PC32: + if (s1->output_type == TCC_OUTPUT_DLL) { + /* DLL relocation */ + esym_index = symtab_to_dynsym[sym_index]; + if (esym_index) { + qrel->r_offset = rel->r_offset; + qrel->r_info = ELF32_R_INFO(esym_index, R_386_PC32); + qrel++; + break; + } + } + *(int *)ptr += val - addr; + break; + case R_386_PLT32: + *(int *)ptr += val - addr; + break; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + *(int *)ptr = val; + break; + case R_386_GOTPC: + *(int *)ptr += got->sh_addr - addr; + break; + case R_386_GOTOFF: + *(int *)ptr += val - got->sh_addr; + break; + case R_386_GOT32: + /* we load the got offset */ + *(int *)ptr += got_offsets[sym_index]; + break; + } } + /* if the relocation is allocated, we change its symbol table */ + if (sr->sh_flags & SHF_ALLOC) + sr->link = dynsym; } /* relocate relocation table in 'sr' */ @@ -6799,6 +6861,39 @@ static void relocate_rel(Section *sr) } } +/* count the number of dynamic relocations so that we can reserve + their space */ +static int prepare_dynamic_rel(Section *sr) +{ + Elf32_Rel *rel, *rel_end; + int sym_index, esym_index, type, count; + + count = 0; + rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); + for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++) { + sym_index = ELF32_R_SYM(rel->r_info); + type = ELF32_R_TYPE(rel->r_info); + switch(type) { + case R_386_32: + count++; + break; + case R_386_PC32: + esym_index = symtab_to_dynsym[sym_index]; + if (esym_index) + count++; + break; + default: + break; + } + } + if (count) { + /* allocate the section */ + sr->sh_flags |= SHF_ALLOC; + sr->sh_size = count * sizeof(Elf32_Rel); + } + return count; +} + static void put_got_offset(int index, unsigned long val) { int n; @@ -6934,18 +7029,32 @@ static void build_got_entries(void) } } -static Section *new_section_hash(const char *name, int sh_flags, - int nb_buckets, Section *symtab) +static Section *new_symtab(const char *symtab_name, int sh_type, int sh_flags, + const char *strtab_name, + const char *hash_name, int hash_sh_flags) { - Section *hash; - hash = new_section(name, SHT_HASH, sh_flags); - ((int *)hash->data)[0] = nb_buckets; - ((int *)hash->data)[1] = 1; + Section *symtab, *strtab, *hash; + int *ptr, nb_buckets; + + symtab = new_section(symtab_name, sh_type, sh_flags); + symtab->sh_entsize = sizeof(Elf32_Sym); + strtab = new_section(strtab_name, SHT_STRTAB, sh_flags); + put_elf_str(strtab, ""); + symtab->link = strtab; + put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); + + nb_buckets = 1; + + hash = new_section(hash_name, SHT_HASH, hash_sh_flags); hash->sh_entsize = sizeof(int); - section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); symtab->hash = hash; hash->link = symtab; - return hash; + + ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); + ptr[0] = nb_buckets; + ptr[1] = 1; + memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); + return symtab; } /* put dynamic tag */ @@ -7055,7 +7164,7 @@ int tcc_output_file(TCCState *s1, const char *filename) Section *strsec, *s; Elf32_Shdr shdr, *sh; Elf32_Phdr *phdr, *ph; - Section *interp, *plt, *dynamic, *dynstr, *hash; + Section *interp, *plt, *dynamic, *dynstr; unsigned long saved_dynamic_data_offset; Elf32_Sym *sym; int type, file_type; @@ -7072,7 +7181,6 @@ int tcc_output_file(TCCState *s1, const char *filename) got = NULL; nb_plt_entries = 0; plt = NULL; /* avoid warning */ - hash = NULL; /* avoid warning */ dynstr = NULL; /* avoid warning */ saved_dynamic_data_offset = 0; /* avoid warning */ @@ -7095,17 +7203,11 @@ int tcc_output_file(TCCState *s1, const char *filename) } /* add dynamic symbol table */ - dynsym = new_section(".dynsym", SHT_DYNSYM, SHF_ALLOC); - dynsym->sh_entsize = sizeof(Elf32_Sym); - dynstr = new_section(".dynstr", SHT_STRTAB, SHF_ALLOC); - put_elf_str(dynstr, ""); - dynsym->link = dynstr; - put_elf_sym(dynsym, 0, 0, 0, 0, 0, NULL); - - /* hash table */ - hash = new_section_hash(".hash", SHF_ALLOC, - ELF_DYNSYM_HASH_SIZE, dynsym); - + dynsym = new_symtab(".dynsym", SHT_DYNSYM, SHF_ALLOC, + ".dynstr", + ".hash", SHF_ALLOC); + dynstr = dynsym->link; + /* add dynamic section */ dynamic = new_section(".dynamic", SHT_DYNAMIC, SHF_ALLOC | SHF_WRITE); @@ -7116,72 +7218,98 @@ int tcc_output_file(TCCState *s1, const char *filename) plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); plt->sh_entsize = 4; + build_got(); + /* scan for undefined symbols and see if they are in the dynamic symbols. If a symbol STT_FUNC is found, then we add it in the PLT. If a symbol STT_OBJECT is found, we add it in the .bss section with a suitable relocation */ sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); - for(sym = (Elf32_Sym *)symtab_section->data + 1; - sym < sym_end; - sym++) { - if (sym->st_shndx == SHN_UNDEF) { - name = symtab_section->link->data + sym->st_name; - sym_index = find_elf_sym(dynsymtab_section, name); - if (sym_index) { - esym = &((Elf32_Sym *)dynsymtab_section->data)[sym_index]; - type = ELF32_ST_TYPE(esym->st_info); - if (type == STT_FUNC) { - put_got_entry(R_386_JMP_SLOT, esym->st_size, - esym->st_info, - sym - (Elf32_Sym *)symtab_section->data); - } else if (type == STT_OBJECT) { - unsigned long offset; - offset = bss_section->data_offset; - /* XXX: which alignment ? */ - offset = (offset + 8 - 1) & -8; - index = put_elf_sym(dynsym, offset, esym->st_size, - esym->st_info, 0, - bss_section->sh_num, name); - put_elf_reloc(dynsym, bss_section, - offset, R_386_COPY, index); - offset += esym->st_size; - bss_section->data_offset = offset; - } - } else { - /* STB_WEAK undefined symbols are accepted */ - /* XXX: _fp_hw seems to be part of the ABI, so we ignore - it */ - if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || - !strcmp(name, "_fp_hw")) { + if (file_type == TCC_OUTPUT_EXE) { + for(sym = (Elf32_Sym *)symtab_section->data + 1; + sym < sym_end; + sym++) { + if (sym->st_shndx == SHN_UNDEF) { + name = symtab_section->link->data + sym->st_name; + sym_index = find_elf_sym(dynsymtab_section, name); + if (sym_index) { + esym = &((Elf32_Sym *)dynsymtab_section->data)[sym_index]; + type = ELF32_ST_TYPE(esym->st_info); + if (type == STT_FUNC) { + put_got_entry(R_386_JMP_SLOT, esym->st_size, + esym->st_info, + sym - (Elf32_Sym *)symtab_section->data); + } else if (type == STT_OBJECT) { + unsigned long offset; + offset = bss_section->data_offset; + /* XXX: which alignment ? */ + offset = (offset + 8 - 1) & -8; + index = put_elf_sym(dynsym, offset, esym->st_size, + esym->st_info, 0, + bss_section->sh_num, name); + put_elf_reloc(dynsym, bss_section, + offset, R_386_COPY, index); + offset += esym->st_size; + bss_section->data_offset = offset; + } } else { - error("undefined symbol '%s'", name); + /* STB_WEAK undefined symbols are accepted */ + /* XXX: _fp_hw seems to be part of the ABI, so we ignore + it */ + if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || + !strcmp(name, "_fp_hw")) { + } else { + error("undefined symbol '%s'", name); + } } } } - } - /* now look at unresolved dynamic symbols and export - corresponding symbol */ - sym_end = (Elf32_Sym *)(dynsymtab_section->data + - dynsymtab_section->data_offset); - for(sym = (Elf32_Sym *)dynsymtab_section->data + 1; - sym < sym_end; - sym++) { - if (sym->st_shndx == SHN_UNDEF) { - name = dynsymtab_section->link->data + sym->st_name; - sym_index = find_elf_sym(symtab_section, name); - if (sym_index) { - } else { - if (ELF32_ST_BIND(sym->st_info) == STB_WEAK) { - /* weak symbols can stay undefined */ + /* now look at unresolved dynamic symbols and export + corresponding symbol */ + sym_end = (Elf32_Sym *)(dynsymtab_section->data + + dynsymtab_section->data_offset); + for(esym = (Elf32_Sym *)dynsymtab_section->data + 1; + esym < sym_end; + esym++) { + if (esym->st_shndx == SHN_UNDEF) { + name = dynsymtab_section->link->data + esym->st_name; + sym_index = find_elf_sym(symtab_section, name); + if (sym_index) { + sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; + put_elf_sym(dynsym, sym->st_value, sym->st_size, + sym->st_info, 0, + sym->st_shndx, name); } else { - warning("undefined dynamic symbol '%s'", name); + if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { + /* weak symbols can stay undefined */ + } else { + warning("undefined dynamic symbol '%s'", name); + } } } } + } else { + int nb_syms; + /* shared library case : we simply export all the global symbols */ + nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); + symtab_to_dynsym = malloc(sizeof(int) * nb_syms); + memset(symtab_to_dynsym, 0, sizeof(int) * nb_syms); + for(sym = (Elf32_Sym *)symtab_section->data + 1; + sym < sym_end; + sym++) { + if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { + name = symtab_section->link->data + sym->st_name; + index = put_elf_sym(dynsym, sym->st_value, sym->st_size, + sym->st_info, 0, + sym->st_shndx, name); + symtab_to_dynsym[sym - (Elf32_Sym *)symtab_section->data] = + index; + } + } } - + build_got_entries(); /* update PLT/GOT sizes so that we can allocate their space */ @@ -7193,6 +7321,10 @@ int tcc_output_file(TCCState *s1, const char *filename) if (dllref->level == 0) put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); } + /* XXX: currently, since we do not handle PIC code, we + must relocate the readonly segments */ + if (file_type == TCC_OUTPUT_DLL) + put_dt(dynamic, DT_TEXTREL, 0); /* add necessary space for other entries */ saved_dynamic_data_offset = dynamic->data_offset; @@ -7243,11 +7375,17 @@ int tcc_output_file(TCCState *s1, const char *filename) for(i = 1; i < nb_sections; i++) { s = sections[i]; s->sh_name = put_elf_str(strsec, s->name); - /* we output all sections if debug or object file */ - if (do_debug || + /* when generating a DLL, we include relocations but we may + patch them */ + if (file_type == TCC_OUTPUT_DLL && + s->sh_type == SHT_REL && + !(s->sh_flags & SHF_ALLOC)) { + prepare_dynamic_rel(s); + } else if (do_debug || file_type == TCC_OUTPUT_OBJ || (s->sh_flags & SHF_ALLOC) || i == (nb_sections - 1)) { + /* we output all sections if debug or object file */ s->sh_size = s->data_offset; } } @@ -7430,7 +7568,7 @@ int tcc_output_file(TCCState *s1, const char *filename) /* put dynamic section entries */ dynamic->data_offset = saved_dynamic_data_offset; - put_dt(dynamic, DT_HASH, hash->sh_addr); + put_dt(dynamic, DT_HASH, dynsym->hash->sh_addr); put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); put_dt(dynamic, DT_SYMTAB, dynsym->sh_addr); put_dt(dynamic, DT_STRSZ, dynstr->data_offset); @@ -7470,7 +7608,7 @@ int tcc_output_file(TCCState *s1, const char *filename) for(i = 1; i < nb_sections; i++) { s = sections[i]; if (s->reloc && s != got) - relocate_section(s); + relocate_section(s1, s); } /* relocate relocation entries if the relocation tables are @@ -7484,7 +7622,10 @@ int tcc_output_file(TCCState *s1, const char *filename) } /* get entry point address */ - ehdr.e_entry = get_elf_sym_val("_start"); + if (file_type == TCC_OUTPUT_EXE) + ehdr.e_entry = get_elf_sym_val("_start"); + else + ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ } sort_syms(symtab_section); @@ -8208,7 +8349,7 @@ int tcc_run(TCCState *s1, int argc, char **argv) for(i = 1; i < nb_sections; i++) { s = sections[i]; if (s->reloc) - relocate_section(s); + relocate_section(s1, s); } prog_main = (void *)get_elf_sym_val("main"); @@ -8288,24 +8429,15 @@ TCCState *tcc_new(void) bss_section = new_section(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); /* symbols are always generated for linking stage */ - symtab_section = new_section(".symtab", SHT_SYMTAB, 0); - symtab_section->sh_entsize = sizeof(Elf32_Sym); - strtab_section = new_section(".strtab", SHT_STRTAB, 0); - put_elf_str(strtab_section, ""); - symtab_section->link = strtab_section; - put_elf_sym(symtab_section, 0, 0, 0, 0, 0, NULL); - new_section_hash(".hashtab", SHF_PRIVATE, - ELF_SYM_HASH_SIZE, symtab_section); + symtab_section = new_symtab(".symtab", SHT_SYMTAB, 0, + ".strtab", + ".hashtab", SHF_PRIVATE); + strtab_section = symtab_section->link; /* private symbol table for dynamic symbols */ - dynsymtab_section = new_section(".dynsymtab", SHT_SYMTAB, SHF_PRIVATE); - dynsymtab_section->sh_entsize = sizeof(Elf32_Sym); - dynstrtab_section = new_section(".dynstrtab", SHT_STRTAB, SHF_PRIVATE); - put_elf_str(dynstrtab_section, ""); - dynsymtab_section->link = dynstrtab_section; - put_elf_sym(dynsymtab_section, 0, 0, 0, 0, 0, NULL); - new_section_hash(".dynhashtab", SHF_PRIVATE, - ELF_SYM_HASH_SIZE, dynsymtab_section); + dynsymtab_section = new_symtab(".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, + ".dynstrtab", + ".dynhashtab", SHF_PRIVATE); return s; } @@ -8504,7 +8636,7 @@ int tcc_set_output_type(TCCState *s, int output_type) void help(void) { - printf("tcc version 0.9.8 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n" + printf("tcc version 0.9.9 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n" "usage: tcc [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" " [-g] [-b] [-Ldir] [-llib] [-shared] [-static]\n" " [--] infile1 [infile2... --] [infile_args...]\n" @@ -8528,7 +8660,7 @@ void help(void) "Linker options:\n" " -Ldir add library path 'dir'\n" " -llib link with dynamic library 'lib'\n" - " -shared generate a shared library (NOT WORKING YET)\n" + " -shared generate a shared library\n" " -static static linking\n" ); } @@ -8619,8 +8751,6 @@ int main(int argc, char **argv) output_type = TCC_OUTPUT_EXE; /* warning if not supported features */ - if (output_type == TCC_OUTPUT_DLL) - warning("dll output is currently not supported"); #ifdef CONFIG_TCC_BCHECK if (do_bounds_check && output_type != TCC_OUTPUT_MEMORY) warning("bounds checking is currently only supported for in-memory execution"); -- 2.11.4.GIT