From 3cd4a7c4f98bcc195fd158a27fd987e00644d808 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Jul 2002 23:00:39 +0000 Subject: [PATCH] better elf output - fixed float relocation data --- tcc.c | 608 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 503 insertions(+), 105 deletions(-) diff --git a/tcc.c b/tcc.c index ab29cb13..3a9a7ccd 100644 --- a/tcc.c +++ b/tcc.c @@ -74,7 +74,8 @@ #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 /* must be a power of two */ +#define ELF_SYM_HASH_SIZE 2048 +#define ELF_DYNSYM_HASH_SIZE 32 /* token symbol management */ typedef struct TokenSym { @@ -125,21 +126,26 @@ typedef struct SymStack { } SymStack; /* section definition */ +/* XXX: use directly ELF structure for parameters ? */ +/* special flag to indicate that the section should not be linked to + the other ones */ +#define SHF_PRIVATE 0x80000000 + typedef struct Section { unsigned char *data; /* section data */ unsigned char *data_ptr; /* current data pointer */ + int sh_name; /* elf section name (only used during output) */ int sh_num; /* elf section number */ int sh_type; /* elf section type */ int sh_flags; /* elf section flags */ -/* special flag to indicate that the section should not be linked to - the other ones */ -#define SHF_PRIVATE 0x80000000 + int sh_info; /* elf section info */ + int sh_addralign; /* elf section alignment */ int sh_entsize; /* elf entry size */ - unsigned long addr; /* address at which the section is relocated */ + 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 */ struct Section *link; /* link to another section */ struct Section *reloc; /* corresponding section for relocation, if any */ - struct Section *reloc_sec;/* relocation: pointer to corresponding - data section */ struct Section *hash; /* hash table for symbols */ struct Section *next; char name[64]; /* section name */ @@ -223,7 +229,7 @@ Section *cur_text_section; /* current section where function code is Section *bounds_section; /* contains global data bound description */ Section *lbounds_section; /* contains local data bound description */ /* symbol sections */ -Section *symtab_section, *strtab_section, *hashtab_section; +Section *symtab_section, *strtab_section; /* debug sections */ Section *stab_section, *stabstr_section; @@ -272,6 +278,9 @@ int gnu_ext = 1; /* use Tiny C extensions */ int tcc_ext = 1; +/* if true, static linking is performed */ +int static_link = 0; + struct TCCState { int dummy; }; @@ -570,7 +579,7 @@ static int put_elf_str(Section *s, const char *sym); static int put_elf_sym(Section *s, unsigned long value, unsigned long size, int info, int other, int shndx, const char *name); -static void put_elf_reloc(Section *s, unsigned long offset, +static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); static void put_stabs(const char *str, int type, int other, int desc, int value); static void put_stabn(int type, int other, int desc, int value); @@ -766,6 +775,21 @@ Section *new_section(const char *name, int sh_type, int sh_flags) pstrcpy(sec->name, sizeof(sec->name), name); sec->sh_type = sh_type; sec->sh_flags = sh_flags; + switch(sh_type) { + case SHT_HASH: + case SHT_REL: + case SHT_DYNSYM: + case SHT_SYMTAB: + case SHT_DYNAMIC: + sec->sh_addralign = 4; + break; + case SHT_STRTAB: + sec->sh_addralign = 1; + break; + default: + sec->sh_addralign = 32; /* default conservative alignment */ + break; + } #ifdef WIN32 /* XXX: currently, a single malloc */ data = malloc(SECTION_VSIZE); @@ -827,7 +851,7 @@ void greloc(Section *s, Sym *sym, unsigned long offset, int type) if (!sym->c) put_extern_sym(sym, NULL, 0); /* now we can add ELF relocation info */ - put_elf_reloc(s, offset, type, sym->c); + put_elf_reloc(symtab_section, s, offset, type, sym->c); } static inline int isid(int c) @@ -1006,6 +1030,10 @@ char *get_tok_str(int v, CValue *cv) return buf; } else if (v < tok_ident) { return table_ident[v - TOK_IDENT]->str; + } else if (v >= SYM_FIRST_ANOM) { + /* special name for anonymous symbol */ + sprintf(buf, "L.%u", v - SYM_FIRST_ANOM); + return buf; } else { /* should never happen */ return NULL; @@ -2720,19 +2748,29 @@ int gv(int rc) } else { if (is_float(vtop->t) && (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + int v; + Sym *sym; + + /* 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_offset = (int)data_section->data_ptr; + data_offset = data_section->data_ptr - data_section->data; data_offset = (data_offset + align - 1) & -align; /* XXX: not portable yet */ size = size >> 2; for(i=0;ic.tab[i]; - vtop->r |= VT_LVAL; - vtop->c.ul = data_offset; + ((int *)(data_section->data + data_offset))[i] = vtop->c.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_offset); + + vtop->r |= VT_LVAL | VT_SYM; + vtop->c.sym = sym; data_offset += size << 2; - data_section->data_ptr = (unsigned char *)data_offset; + data_section->data_ptr = data_section->data + data_offset; } #ifdef CONFIG_TCC_BCHECK if (vtop->r & VT_MUSTBOUND) @@ -6128,6 +6166,12 @@ int tcc_compile(TCCState *s) put_stabs(file->filename, N_SO, 0, 0, (unsigned long)text_section->data_ptr); } + /* an elf symbol of type STT_FILE must be put so that STB_LOCAL + symbols can be safely used */ + put_elf_sym(symtab_section, 0, 0, + ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, + SHN_ABS, file->filename); + /* define common 'char *' type because it is often used internally for arrays and struct dereference */ char_pointer_type = mk_pointer(VT_BYTE); @@ -6350,7 +6394,6 @@ void put_extern_sym(Sym *sym, Section *section, unsigned long value) sym_bind = STB_GLOBAL; /* if the symbol is global, then we look if it is already defined */ - /* NOTE: name can be NULL if anonymous symbol */ name = get_tok_str(sym->v, NULL); if (sym_bind == STB_GLOBAL) { sym->c = find_elf_sym(symtab_section, name); @@ -6378,7 +6421,7 @@ void put_extern_sym(Sym *sym, Section *section, unsigned long value) } /* put relocation */ -static void put_elf_reloc(Section *s, unsigned long offset, +static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol) { char buf[256]; @@ -6389,10 +6432,10 @@ static void put_elf_reloc(Section *s, unsigned long offset, if (!sr) { /* if no relocation section, create it */ snprintf(buf, sizeof(buf), ".rel%s", s->name); - sr = new_section(buf, SHT_REL, 0); + sr = new_section(buf, SHT_REL, s->sh_flags); sr->sh_entsize = sizeof(Elf32_Rel); - sr->link = symtab_section; - sr->reloc_sec = s; + sr->link = symtab; + sr->sh_info = s->sh_num; s->reloc = sr; } rel = (Elf32_Rel *)sr->data_ptr; @@ -6440,19 +6483,205 @@ static void put_stabd(int type, int other, int desc) put_stabs(NULL, type, other, desc, 0); } +/* 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_symbols(Section *s) +{ + int *old_to_new_syms; + Elf32_Sym *new_syms; + int nb_syms, i; + Elf32_Sym *p, *q; + Elf32_Rel *rel; + Section *sr; + int type, sym_index; + + nb_syms = (s->data_ptr - s->data) / sizeof(Elf32_Sym); + new_syms = malloc(nb_syms * sizeof(Elf32_Sym)); + if (!new_syms) + error("memory full"); + old_to_new_syms = malloc(nb_syms * sizeof(int)); + if (!old_to_new_syms) + error("memory full"); + /* first pass for local symbols */ + p = (Elf32_Sym *)s->data; + q = new_syms; + for(i = 0; i < nb_syms; i++) { + if (ELF32_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 */ + s->sh_info = q - new_syms; + + /* then second pass for non local symbols */ + p = (Elf32_Sym *)s->data; + for(i = 0; i < nb_syms; i++) { + if (ELF32_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(Elf32_Sym)); + free(new_syms); + + /* now we modify all the relocations */ + for(sr = first_section; sr != NULL; sr = sr->next) { + if (sr->sh_type == SHT_REL && sr->link == s) { + for(rel = (Elf32_Rel *)sr->data; + rel < (Elf32_Rel *)sr->data_ptr; + rel++) { + sym_index = ELF32_R_SYM(rel->r_info); + type = ELF32_R_TYPE(rel->r_info); + sym_index = old_to_new_syms[sym_index]; + rel->r_info = ELF32_R_INFO(sym_index, type); + } + } + } + + free(old_to_new_syms); +} + +static Section *new_section_hash(const char *name, int sh_flags, + int nb_buckets, Section *symtab) +{ + Section *hash; + hash = new_section(name, SHT_HASH, sh_flags); + ((int *)hash->data)[0] = nb_buckets; + ((int *)hash->data)[1] = 1; + hash->sh_entsize = sizeof(int); + hash->data_ptr += (2 + nb_buckets + 1) * sizeof(int); + symtab->hash = hash; + hash->link = symtab; + return hash; +} + +/* put dynamic tag */ +static void put_dt(Section *dynamic, int dt, unsigned long val) +{ + Elf32_Dyn *dyn; + dyn = (Elf32_Dyn *)dynamic->data_ptr; + dyn->d_tag = dt; + dyn->d_un.d_val = val; + dynamic->data_ptr += sizeof(Elf32_Dyn); +} + +/* add dynamic sections so that the executable is dynamically linked */ +static char elf_interp[] = "/lib/ld-linux.so.2"; + +#define ELF_START_ADDR 0x08048000 +#define ELF_PAGE_SIZE 0x1000 + +/* XXX: suppress that */ +static void put32(unsigned char *p, unsigned int val) +{ + p[0] = val; + p[1] = val >> 8; + p[2] = val >> 16; + p[3] = val >> 24; +} + /* output an ELF file (currently, only for testing) */ -/* XXX: generate dynamic reloc info + DLL tables */ /* XXX: generate startup code */ -/* XXX: better program header generation */ /* XXX: handle realloc'ed sections (instead of mmaping them) */ -int tcc_output_file(TCCState *s, const char *filename, int file_type) +int tcc_output_file(TCCState *s1, const char *filename, int file_type) { Elf32_Ehdr ehdr; FILE *f; - int shnum, i, phnum, file_offset, offset, size, j; - Section *sec, *strsec; - Elf32_Shdr *shdr, *sh; + int fd, mode; + int *section_order; + int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index; + unsigned long addr; + Section *strsec, *s; + Elf32_Shdr shdr, *sh; Elf32_Phdr *phdr, *ph; + Section *interp, *plt, *got, *dynamic, *dynsym, *dynstr, *hash; + unsigned char *saved_dynamic_data_ptr; + Elf32_Sym *sym; + int type; + + interp = NULL; + dynamic = NULL; + plt = NULL; /* avoid warning */ + got = NULL; /* avoid warning */ + dynsym = NULL; /* avoid warning */ + hash = NULL; /* avoid warning */ + dynstr = NULL; /* avoid warning */ + saved_dynamic_data_ptr = NULL; /* avoid warning */ + + if (file_type != TCC_FILE_OBJ && !static_link) { + const char *name; + int nb_plt_entries; + + if (file_type == TCC_FILE_EXE) { + /* add interpreter section only if executable */ + interp = new_section(".interp", SHT_PROGBITS, SHF_ALLOC); + interp->sh_addralign = 1; + strcpy(interp->data_ptr, elf_interp); + interp->data_ptr += sizeof(elf_interp); + } + + /* 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); + + /* add dynamic section */ + dynamic = new_section(".dynamic", SHT_DYNAMIC, + SHF_ALLOC | SHF_WRITE); + dynamic->link = dynstr; + dynamic->sh_entsize = sizeof(Elf32_Dyn); + + /* add PLT and GOT */ + plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); + plt->sh_entsize = 4; + got = new_section(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + got->sh_entsize = 4; + + /* add undefined symbols in dynamic symbol table */ + nb_plt_entries = 0; + for(sym = (Elf32_Sym *)symtab_section->data + 1; + sym < (Elf32_Sym *)symtab_section->data_ptr; + sym++) { + if (sym->st_shndx == SHN_UNDEF) { + name = symtab_section->link->data + sym->st_name; + type = ELF32_ST_TYPE(sym->st_info); + put_elf_sym(dynsym, 0, 0, + sym->st_info, 0, SHN_UNDEF, name); + if (type == STT_FUNC) { + nb_plt_entries++; + /* prepare space for relocation */ + put_elf_reloc(dynsym, got, 0, 0, 0); + } + } + } + + /* update PLT/GOT sizes so that we can allocate their space */ + plt->data_ptr += 16 * (nb_plt_entries + 1); + got->data_ptr += 4 * (nb_plt_entries + 3); + + put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, "libc.so.6")); + /* XXX: add other libs */ + + /* add necessary space for other entries */ + saved_dynamic_data_ptr = dynamic->data_ptr; + dynamic->data_ptr += 8 * 9; + } + + sort_symbols(symtab_section); memset(&ehdr, 0, sizeof(ehdr)); @@ -6460,20 +6689,39 @@ int tcc_output_file(TCCState *s, const char *filename, int file_type) strsec = new_section(".shstrtab", SHT_STRTAB, 0); put_elf_str(strsec, ""); - /* count number of sections and compute number of program segments */ - shnum = 1; /* section index zero is reserved */ - phnum = 0; - for(sec = first_section; sec != NULL; sec = sec->next) { - shnum++; - if ((sec->sh_flags & SHF_ALLOC) && - file_type != TCC_FILE_OBJ) - phnum++; - } - /* allocate section headers */ - shdr = malloc(shnum * sizeof(Elf32_Shdr)); - if (!shdr) + /* compute number of sections */ + shnum = nb_sections; + + /* this array is used to reorder sections in the output file */ + section_order = malloc(sizeof(int) * shnum); + if (!section_order) error("memory full"); - memset(shdr, 0, shnum * sizeof(Elf32_Shdr)); + section_order[0] = 0; + sh_order_index = 1; + + /* compute number of program headers */ + switch(file_type) { + default: + case TCC_FILE_OBJ: + phnum = 0; + break; + case TCC_FILE_EXE: + if (!static_link) + phnum = 4; + else + phnum = 2; + break; + case TCC_FILE_DLL: + phnum = 3; + break; + } + + /* allocate strings for section names */ + for(i = 1; i < nb_sections; i++) { + s = sections[i]; + s->sh_name = put_elf_str(strsec, s->name); + s->sh_size = s->data_ptr - s->data; + } /* allocate program segment headers */ phdr = malloc(phnum * sizeof(Elf32_Phdr)); @@ -6481,56 +6729,186 @@ int tcc_output_file(TCCState *s, const char *filename, int file_type) error("memory full"); memset(phdr, 0, phnum * sizeof(Elf32_Phdr)); - /* XXX: find correct load order */ file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); - for(sec = first_section, i = 1; sec != NULL; sec = sec->next, i++) { - sh = &shdr[i]; - sh->sh_name = put_elf_str(strsec, sec->name); - sh->sh_type = sec->sh_type; - sh->sh_flags = sec->sh_flags; - sh->sh_entsize = sec->sh_entsize; - if (sec->link) - sh->sh_link = sec->link->sh_num; - if (sec->reloc_sec) - sh->sh_info = sec->reloc_sec->sh_num; - if (sh->sh_type == SHT_STRTAB) { - sh->sh_addralign = 1; - } else if (sh->sh_type == SHT_SYMTAB || - (sh->sh_flags & SHF_ALLOC) == 0) { - sh->sh_addralign = 4; - } else { - sh->sh_addr = (Elf32_Word)sec->data; - sh->sh_addralign = 4096; - } - sh->sh_size = (Elf32_Word)sec->data_ptr - (Elf32_Word)sec->data; - /* align to section start */ - file_offset = (file_offset + sh->sh_addralign - 1) & - ~(sh->sh_addralign - 1); - sh->sh_offset = file_offset; - file_offset += sh->sh_size; - } - /* build program headers (simplistic - not fully correct) */ if (phnum > 0) { - j = 0; - for(i=1;ish_type == SHT_PROGBITS && - (sh->sh_flags & SHF_ALLOC) != 0) { - ph = &phdr[j++]; - ph->p_type = PT_LOAD; - ph->p_offset = sh->sh_offset; - ph->p_vaddr = sh->sh_addr; - ph->p_paddr = ph->p_vaddr; - ph->p_filesz = sh->sh_size; - ph->p_memsz = sh->sh_size; - ph->p_flags = PF_R; - if (sh->sh_flags & SHF_WRITE) - ph->p_flags |= PF_W; - if (sh->sh_flags & SHF_EXECINSTR) - ph->p_flags |= PF_X; - ph->p_align = sh->sh_addralign; + /* compute section to program header mapping */ + if (file_type == TCC_FILE_DLL) + addr = 0; + else + addr = ELF_START_ADDR; + + /* compute address after headers */ + addr += (file_offset & (ELF_PAGE_SIZE - 1)); + + /* leave one program header for the program interpreter */ + ph = &phdr[0]; + if (interp) + ph++; + + for(j = 0; j < 2; j++) { + ph->p_type = PT_LOAD; + if (j == 0) + ph->p_flags = PF_R | PF_X; + else + ph->p_flags = PF_R | PF_W; + ph->p_align = ELF_PAGE_SIZE; + + for(i = 1; i < nb_sections; i++) { + s = sections[i]; + /* compute if section should be included */ + if (j == 0) { + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + SHF_ALLOC) + continue; + } else { + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != + (SHF_ALLOC | SHF_WRITE)) + continue; + } + section_order[sh_order_index++] = i; + + /* section matches: we align it and add its size */ + tmp = file_offset; + file_offset = (file_offset + s->sh_addralign - 1) & + ~(s->sh_addralign - 1); + s->sh_offset = file_offset; + addr += file_offset - tmp; + s->sh_addr = addr; + + if (ph->p_offset == 0) { + ph->p_offset = file_offset; + ph->p_vaddr = addr; + ph->p_paddr = ph->p_vaddr; + } + addr += s->sh_size; + file_offset += s->sh_size; } + ph->p_filesz = file_offset - ph->p_offset; + ph->p_memsz = addr - ph->p_vaddr; + ph++; + } + + /* if interpreter, then add corresponing program header */ + if (interp) { + ph = &phdr[0]; + + ph->p_type = PT_INTERP; + ph->p_offset = interp->sh_offset; + ph->p_vaddr = interp->sh_addr; + ph->p_paddr = ph->p_vaddr; + ph->p_filesz = interp->sh_size; + ph->p_memsz = interp->sh_size; + ph->p_flags = PF_R; + ph->p_align = interp->sh_addralign; } + + /* if dynamic section, then add corresponing program header */ + if (dynamic) { + int sym_index, plt_offset; + unsigned char *p; + + ph = &phdr[phnum - 1]; + + ph->p_type = PT_DYNAMIC; + ph->p_offset = dynamic->sh_offset; + ph->p_vaddr = dynamic->sh_addr; + ph->p_paddr = ph->p_vaddr; + ph->p_filesz = dynamic->sh_size; + ph->p_memsz = dynamic->sh_size; + ph->p_flags = PF_R | PF_W; + ph->p_align = dynamic->sh_addralign; + + /* now all the sections are mapped, so we can compute all + PLT/GOT stuff */ + + /* first three got entries */ + got->data_ptr = got->data; + plt->data_ptr = plt->data; + if (got->reloc) + got->reloc->data_ptr = got->reloc->data; + + put32(got->data_ptr, dynamic->sh_addr); + got->data_ptr += 4; + put32(got->data_ptr, 0); + got->data_ptr += 4; + put32(got->data_ptr, 0); + got->data_ptr += 4; + + /* first plt entry */ + p = plt->data_ptr; + p[0] = 0xff; /* pushl got + 4 */ + p[1] = 0x35; + put32(p + 2, got->sh_addr + 4); + p[6] = 0xff; /* jmp *(got + 8) */ + p[7] = 0x25; + put32(p + 8, got->sh_addr + 8); + plt->data_ptr += 16; + + /* add undefined symbols in dynamic symbol table. also update + PLT and GOT if needed */ + plt_offset = 0; + sym_index = 1; + for(sym = (Elf32_Sym *)dynsym->data + 1; + sym < (Elf32_Sym *)dynsym->data_ptr; + sym++) { + type = ELF32_ST_TYPE(sym->st_info); + if (type == STT_FUNC) { + /* one more entry in PLT */ + p = plt->data_ptr; + p[0] = 0xff; /* jmp *(got + x) */ + p[1] = 0x25; + put32(p + 2, got->sh_addr + got->data_ptr - got->data); + p[6] = 0x68; /* push $xxx */ + put32(p + 7, plt_offset); + p[11] = 0xe9; /* jmp plt_start */ + put32(p + 12, -(plt->data_ptr + 16 - plt->data)); + + /* patch symbol value to point to plt */ + sym->st_value = plt->sh_addr + p - plt->data; + + plt_offset += 8; + plt->data_ptr += 16; + + /* corresponding got entry */ + put_elf_reloc(dynsym, got, + got->sh_addr + got->data_ptr - got->data, + R_386_JMP_SLOT, + sym_index); + put32(got->data_ptr, 0); + got->data_ptr += 4; + } + sym_index++; + } + /* put dynamic section entries */ + + dynamic->data_ptr = saved_dynamic_data_ptr; + put_dt(dynamic, DT_HASH, 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_ptr - dynstr->data); + put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); + put_dt(dynamic, DT_REL, got->reloc->sh_addr); + put_dt(dynamic, DT_RELSZ, got->reloc->data_ptr - got->reloc->data); + put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); + put_dt(dynamic, DT_NULL, 0); + } + + ehdr.e_phentsize = sizeof(Elf32_Phdr); + ehdr.e_phnum = phnum; + ehdr.e_phoff = sizeof(Elf32_Ehdr); + } + + /* all other sections come after */ + for(i = 1; i < nb_sections; i++) { + s = sections[i]; + if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) + continue; + section_order[sh_order_index++] = i; + + file_offset = (file_offset + s->sh_addralign - 1) & + ~(s->sh_addralign - 1); + s->sh_offset = file_offset; + file_offset += s->sh_size; } /* align to 4 */ @@ -6559,40 +6937,63 @@ int tcc_output_file(TCCState *s, const char *filename, int file_type) ehdr.e_machine = EM_386; ehdr.e_version = EV_CURRENT; ehdr.e_entry = 0; /* XXX: patch it */ - ehdr.e_phoff = sizeof(Elf32_Ehdr); ehdr.e_shoff = file_offset; ehdr.e_ehsize = sizeof(Elf32_Ehdr); - ehdr.e_phentsize = sizeof(Elf32_Phdr); - ehdr.e_phnum = phnum; ehdr.e_shentsize = sizeof(Elf32_Shdr); ehdr.e_shnum = shnum; ehdr.e_shstrndx = shnum - 1; /* write elf file */ - f = fopen(filename, "w"); - if (!f) + if (file_type == TCC_FILE_OBJ) + mode = 0666; + else + mode = 0777; + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd < 0) error("could not write '%s'", filename); + + f = fdopen(fd, "w"); fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f); fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f); offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); - for(sec = first_section, i = 1; sec != NULL; sec = sec->next, i++) { - sh = &shdr[i]; - while (offset < sh->sh_offset) { + for(i=1;ish_offset) { fputc(0, f); offset++; } - size = sec->data_ptr - sec->data; - fwrite(sec->data, 1, size, f); + size = s->data_ptr - s->data; + fwrite(s->data, 1, size, f); offset += size; } while (offset < ehdr.e_shoff) { fputc(0, f); offset++; } - fwrite(shdr, 1, shnum * sizeof(Elf32_Shdr), f); + + /* output sections */ + for(i=0;ish_name = s->sh_name; + sh->sh_type = s->sh_type; + sh->sh_flags = s->sh_flags; + sh->sh_entsize = s->sh_entsize; + sh->sh_info = s->sh_info; + if (s->link) + sh->sh_link = s->link->sh_num; + sh->sh_addralign = s->sh_addralign; + sh->sh_addr = s->sh_addr; + sh->sh_offset = s->sh_offset; + sh->sh_size = s->sh_size; + } + fwrite(sh, 1, sizeof(Elf32_Shdr), f); + } fclose(f); - free(shdr); + free(section_order); free(phdr); return 0; } @@ -6784,7 +7185,7 @@ static unsigned long get_sym_val(int sym_index) sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; val = sym->st_value; if (sym->st_shndx != SHN_ABS) - val += sections[sym->st_shndx]->addr; + val += sections[sym->st_shndx]->sh_addr; return val; } @@ -6806,7 +7207,7 @@ static void relocate_section(Section *s) ptr = s->data + rel->r_offset; val = get_sym_val(ELF32_R_SYM(rel->r_info)); type = ELF32_R_TYPE(rel->r_info); - greloc_patch(ptr, s->addr + rel->r_offset, val, type); + greloc_patch(ptr, s->sh_addr + rel->r_offset, val, type); } } @@ -6818,7 +7219,7 @@ static void relocate_program(void) /* compute relocation address : section are relocated in place */ for(s = first_section; s != NULL; s = s->next) { if (s->sh_type == SHT_PROGBITS) - s->addr = (unsigned long)s->data; + s->sh_addr = (unsigned long)s->data; } /* relocate each section */ @@ -6926,11 +7327,8 @@ TCCState *tcc_new(void) put_elf_sym(symtab_section, 0, 0, 0, 0, 0, NULL); /* private hash table for extern symbols */ - hashtab_section = new_section(".hashtab", SHT_HASH, SHF_PRIVATE); - ((int *)hashtab_section->data)[0] = ELF_SYM_HASH_SIZE; - ((int *)hashtab_section->data)[1] = 1; - hashtab_section->data_ptr += (2 + ELF_SYM_HASH_SIZE + 1) * 4; - symtab_section->hash = hashtab_section; + new_section_hash(".hashtab", SHF_PRIVATE, + ELF_SYM_HASH_SIZE, symtab_section); return s; } -- 2.11.4.GIT