From 8e860702e44ca1279098e0fc2142ad579774b1d2 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 28 May 2022 21:01:22 +0200 Subject: [PATCH] tccelf: sort_sections() Sort sections in separate function to allow variable calculatiion of needed program headers. Such execinstr and relro cah have their own PT_LOAD header. 315 insertions(+), 370 deletions(-) --- tccelf.c | 620 +++++++++++++++++++++++++------------------------------ tccpe.c | 65 +++--- 2 files changed, 315 insertions(+), 370 deletions(-) diff --git a/tccelf.c b/tccelf.c index ed51d68a..e6d5bc0f 100644 --- a/tccelf.c +++ b/tccelf.c @@ -47,6 +47,14 @@ struct sym_version { /* section is dynsymtab_section */ #define SHF_DYNSYM 0x40000000 +#ifdef TCC_TARGET_PE +static const int shf_RELRO = SHF_ALLOC; +static const char rdata[] = ".rdata"; +#else +static const int shf_RELRO = SHF_ALLOC | SHF_WRITE; +static const char rdata[] = ".data.ro"; +#endif + /* ------------------------------------------------------------------------- */ ST_FUNC void tccelf_new(TCCState *s) @@ -58,12 +66,8 @@ ST_FUNC void tccelf_new(TCCState *s) /* create standard sections */ text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); -#ifdef TCC_TARGET_PE - rodata_section = new_section(s, ".rdata", SHT_PROGBITS, SHF_ALLOC); -#else /* create ro data section (make ro after relocation done with GNU_RELRO) */ - rodata_section = new_section(s, ".data.ro", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); -#endif + rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO); 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; @@ -86,10 +90,8 @@ ST_FUNC void tccelf_bounds_new(TCCState *s) { TCCState *s1 = s; /* create bounds sections (make ro after relocation done with GNU_RELRO) */ - bounds_section = new_section(s, ".bounds", - SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); - lbounds_section = new_section(s, ".lbounds", - SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + bounds_section = new_section(s, ".bounds", SHT_PROGBITS, shf_RELRO); + lbounds_section = new_section(s, ".lbounds", SHT_PROGBITS, shf_RELRO); } #endif @@ -1309,10 +1311,8 @@ ST_FUNC void add_array (TCCState *s1, const char *sec, int c) { Section *s; s = find_section(s1, sec); - s->sh_flags |= SHF_WRITE; -#ifndef TCC_TARGET_PE + s->sh_flags = shf_RELRO; s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; -#endif put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); section_ptr_add(s, PTR_SIZE); } @@ -1554,9 +1554,7 @@ static void tcc_add_linker_symbols(TCCState *s1) set_global_sym(s1, "__global_pointer$", data_section, 0x800); #endif /* horrible new standard ldscript defines */ -#ifndef TCC_TARGET_PE add_init_array_defines(s1, ".preinit_array"); -#endif add_init_array_defines(s1, ".init_array"); add_init_array_defines(s1, ".fini_array"); /* add start and stop symbols for sections whose name can be @@ -1849,59 +1847,172 @@ static int set_sec_sizes(TCCState *s1) return textrel; } - -/* Info to be copied in dynamic section */ +/* various data used under elf_output_file() */ struct dyn_inf { Section *dynamic; Section *dynstr; - unsigned long data_offset; - addr_t rel_addr; - addr_t rel_size; + struct { + /* Info to be copied in dynamic section */ + unsigned long data_offset; + addr_t rel_addr; + addr_t rel_size; + }; + + ElfW(Phdr) *phdr; + int phnum; + Section *interp; + Section *note; + + /* read only segment mapping for GNU_RELRO */ + Section _roinf, *roinf; }; -/* Info for GNU_RELRO */ -struct ro_inf { - addr_t sh_offset; - addr_t sh_addr; - addr_t sh_size; -}; +/* Decide the layout of sections loaded in memory. This must be done before + program headers are filled since they contain info about the layout. + We do the following ordering: interp, symbol tables, relocations, progbits, + nobits */ +static int sort_sections(TCCState *s1, int *sec_order, Section *interp) +{ + Section *s; + int i, j, k, f, f0, n; + int nb_sections = s1->nb_sections; + int *sec_cls = sec_order + nb_sections; -static void alloc_sec_names( - TCCState *s1, int is_obj - ); + for (i = 1; i < nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_flags & SHF_ALLOC) { + j = 0x100; + if (s->sh_flags & SHF_WRITE) + j = 0x200; + if (s->sh_flags & SHF_TLS) + j += 0x200; + } else if (s->sh_name) { + j = 0x700; + } else { + j = 0x900; /* no sh_name: won't go to file */ + } + if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) { + k = 0x10; + } else if (s->sh_type == SHT_STRTAB && strcmp(s->name, ".stabstr")) { + k = 0x11; + if (i == nb_sections - 1) /* ".shstrtab" assumed to remain last */ + k = 0xff; + } else if (s->sh_type == SHT_HASH) { + k = 0x12; + } else if (s->sh_type == SHT_RELX) { + k = 0x20; + if (s1->plt && s == s1->plt->reloc) + k = 0x21; + } else if (s->sh_type == SHT_PREINIT_ARRAY) { + k = 0x41; + } else if (s->sh_type == SHT_INIT_ARRAY) { + k = 0x42; + } else if (s->sh_type == SHT_FINI_ARRAY) { + k = 0x43; +#ifdef CONFIG_TCC_BCHECK + } else if (s == bounds_section || s == lbounds_section) { + k = 0x44; +#endif + } else if (s == rodata_section || 0 == strcmp(s->name, ".data.rel.ro")) { + k = 0x45; + } 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 { + k = 0x50; + if (s->sh_type == SHT_NOTE) + k = 0x60; + if (s->sh_flags & SHF_EXECINSTR) + k = 0x70; + if (s->sh_type == SHT_NOBITS) + k = 0x80; + if (s == interp) + k = 0x00; + } + k += j; -static int layout_any_sections( - TCCState *s1, int file_offset, int *sec_order, int is_obj - ); + for (n = i; n > 1 && k < (f = sec_cls[n - 1]); --n) + sec_cls[n] = f, sec_order[n] = sec_order[n - 1]; + sec_cls[n] = k, sec_order[n] = i; + } + sec_order[0] = 0; + + /* count PT_LOAD headers needed */ + n = f0 = 0; + for (i = 1; i < nb_sections; i++) { + s = s1->sections[sec_order[i]]; + k = sec_cls[i]; + f = 0; + if (k < 0x700) { + f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS); + if ((k & 0xfff0) == 0x240) /* RELRO sections */ + f |= 1<<4; + if (f != f0) /* start new header when flags changed or relro */ + f0 = f, ++n, f |= 1<<8; + } + sec_cls[i] = f; + //printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", !!f * n, i, f, k, s->sh_type, s->sh_size, s->name); + } + return n; +} + +static ElfW(Phdr) *fill_phdr(ElfW(Phdr) *ph, int type, Section *s) +{ + if (s) { + ph->p_offset = s->sh_offset; + ph->p_vaddr = s->sh_addr; + ph->p_filesz = s->sh_size; + ph->p_align = s->sh_addralign; + } + ph->p_type = type; + ph->p_flags = PF_R; + ph->p_paddr = ph->p_vaddr; + ph->p_memsz = ph->p_filesz; + return ph; +} /* Assign sections to segments and decide how are sections laid out when loaded in memory. This function also fills corresponding program headers. */ -static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, - int phnum, int phfill, - Section *interp, - struct ro_inf *roinf, int *sec_order) +static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) { - int i, file_offset; Section *s; + addr_t addr, tmp, align, s_align, base; + ElfW(Phdr) *ph = NULL; + int i, f, n, phnum, phfill; + int file_offset; + + /* compute number of program headers */ + phnum = sort_sections(s1, sec_order, d->interp); + phfill = 0; /* set to 1 to have dll's with a PT_PHDR */ + if (d->interp) + phfill = 2; + phnum += phfill; + if (d->note) + ++phnum; + if (d->dynamic) + ++phnum; + if (d->roinf) + ++phnum; + d->phnum = phnum; + d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); file_offset = 0; if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - { - unsigned long s_align; - long long tmp; - addr_t addr; - ElfW(Phdr) *ph; - int j, k, f, file_type = s1->output_type; + s_align = ELF_PAGE_SIZE; + if (s1->section_align) + s_align = s1->section_align; - s_align = ELF_PAGE_SIZE; - if (s1->section_align) - s_align = s1->section_align; + addr = ELF_START_ADDR; + if (s1->output_type & TCC_OUTPUT_DYN) + addr = 0; - if (s1->has_text_addr) { + if (s1->has_text_addr) { + addr = s1->text_addr; + if (0) { int a_offset, p_offset; - addr = s1->text_addr; /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % ELF_PAGE_SIZE */ a_offset = (int) (addr & (s_align - 1)); @@ -1909,161 +2020,108 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, if (a_offset < p_offset) a_offset += s_align; file_offset += (a_offset - p_offset); - } else { - if (file_type & TCC_OUTPUT_DYN) - addr = 0; - else - addr = ELF_START_ADDR; - /* compute address after headers */ - addr += (file_offset & (s_align - 1)); + } + } + base = addr; + /* compute address after headers */ + addr = addr + (file_offset & (s_align - 1)); + + n = 0; + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[sec_order[i]]; + f = sec_order[i + s1->nb_sections]; + align = s->sh_addralign - 1; + + if (f == 0) { /* no alloc */ + file_offset = (file_offset + align) & ~align; + s->sh_offset = file_offset; + if (s->sh_type != SHT_NOBITS) + file_offset += s->sh_size; + continue; } - ph = &phdr[0]; - /* Leave one program headers for the program interpreter and one for - the program header table itself if needed. These are done later as - they require section layout to be done first. */ - if (interp) - ph += 2; - - /* read only segment mapping for GNU_RELRO */ - roinf->sh_offset = roinf->sh_addr = roinf->sh_size = 0; - - for(j = 0; j < phfill; j++) { - ph->p_type = j == 2 ? PT_TLS : PT_LOAD; - if (j == 0) - ph->p_flags = PF_R | PF_X; - else - ph->p_flags = PF_R | PF_W; - ph->p_align = j == 2 ? 4 : s_align; - - /* Decide the layout of sections loaded in memory. This must - be done before program headers are filled since they contain - info about the layout. We do the following ordering: interp, - symbol tables, relocations, progbits, nobits */ - /* XXX: do faster and simpler sorting */ - f = -1; - for(k = 0; k < 10; k++) { - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[i]; - /* compute if section should be included */ - if (j == 0) { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != - SHF_ALLOC) - continue; - } else if (j == 1) { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != - (SHF_ALLOC | SHF_WRITE)) - continue; - } else { - if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != - (SHF_ALLOC | SHF_WRITE | SHF_TLS)) - continue; - } - if (s == interp) { - if (k != 0) - continue; - } else if ((s->sh_type == SHT_DYNSYM || - s->sh_type == SHT_STRTAB || - s->sh_type == SHT_HASH) - && !strstr(s->name, ".stab")) { - if (k != 1) - continue; - } else if (s->sh_type == SHT_RELX) { - if (s1->plt && s == s1->plt->reloc) { - if (k != 3) - continue; - } else { - if (k != 2) - continue; - } - } else if ((s == rodata_section -#ifdef CONFIG_TCC_BCHECK - || s == bounds_section - || s == lbounds_section -#endif - ) && (s->sh_flags & SHF_WRITE)) { - if (k != 4) - continue; - /* Align next section on page size. - This is needed to remap roinf section ro. */ - f = 1; - - } else if (s->sh_type == SHT_PREINIT_ARRAY) { - if (k != 6) - continue; - } else if (s->sh_type == SHT_INIT_ARRAY) { - if (k != 7) - continue; - } else if (s->sh_type == SHT_FINI_ARRAY) { - if (k != 8) - continue; - } else if (s->sh_type == SHT_NOBITS) { - if (k != 9) - continue; - } else { - if (k != 5) - continue; - } - *sec_order++ = i; - - /* section matches: we align it and add its size */ - tmp = addr; - if (f-- == 0) - s->sh_addralign = PAGESIZE; - addr = (addr + s->sh_addralign - 1) & - ~(s->sh_addralign - 1); - file_offset += (int) ( addr - tmp ); - s->sh_offset = file_offset; - s->sh_addr = addr; - - /* update program header infos */ - if (ph->p_offset == 0) { - ph->p_offset = file_offset; - ph->p_vaddr = addr; - ph->p_paddr = ph->p_vaddr; - } - - if (k == 4) { - if (roinf->sh_size == 0) { - roinf->sh_offset = s->sh_offset; - roinf->sh_addr = s->sh_addr; - } - roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size; - } - - addr += s->sh_size; - if (s->sh_type != SHT_NOBITS) - file_offset += s->sh_size; - } + if ((f & 1<<8) && n) { + /* different rwx section flags */ + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { + /* if in the middle of a page, w e duplicate the page in + memory so that one copy is RX and the other is RW */ + if ((addr & (s_align - 1)) != 0) + addr += s_align; + } else { + align = s_align - 1; } - if (j == 0) { + } + + tmp = addr; + addr = (addr + align) & ~align; + file_offset += (int)(addr - tmp); + s->sh_offset = file_offset; + s->sh_addr = addr; + + if (f & 1<<8) { + /* set new program header */ + ph = &d->phdr[phfill + n]; + ph->p_type = PT_LOAD; + ph->p_align = s_align; + ph->p_flags = PF_R; + if (f & SHF_WRITE) + ph->p_flags |= PF_W; + if (f & SHF_EXECINSTR) + ph->p_flags |= PF_X; + if (f & SHF_TLS) { + ph->p_type = PT_TLS; + ph->p_align = 4; + } + ph->p_offset = file_offset; + ph->p_vaddr = addr; + if (n == 0) { /* Make the first PT_LOAD segment include the program headers itself (and the ELF header as well), it'll come out with same memory use but will make various tools like binutils strip work better. */ - ph->p_offset &= ~(ph->p_align - 1); - ph->p_vaddr &= ~(ph->p_align - 1); - ph->p_paddr &= ~(ph->p_align - 1); - } - ph->p_filesz = file_offset - ph->p_offset; - ph->p_memsz = addr - ph->p_vaddr; - ph++; - if (j == 0) { - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { - /* if in the middle of a page, we duplicate the page in - memory so that one copy is RX and the other is RW */ - if ((addr & (s_align - 1)) != 0) - addr += s_align; - } else { - addr = (addr + s_align - 1) & ~(s_align - 1); - file_offset = (file_offset + s_align - 1) & ~(s_align - 1); - } + ph->p_offset = 0; + ph->p_vaddr = base; } + ph->p_paddr = ph->p_vaddr; + ++n; } + + if (f & 1<<4) { + Section *roinf = &d->_roinf; + if (roinf->sh_size == 0) { + roinf->sh_offset = s->sh_offset; + roinf->sh_addr = s->sh_addr; + roinf->sh_addralign = 1; + } + roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size; + } + + addr += s->sh_size; + if (s->sh_type != SHT_NOBITS) + file_offset += s->sh_size; + + ph->p_filesz = file_offset - ph->p_offset; + ph->p_memsz = addr - ph->p_vaddr; } - /* all other sections come after */ - return layout_any_sections(s1, file_offset, sec_order, 0); + /* Fill other headers */ + if (d->note) + fill_phdr(++ph, PT_NOTE, d->note); + if (d->dynamic) + fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W; + if (d->roinf) + fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W; + if (d->interp) + fill_phdr(&d->phdr[1], PT_INTERP, d->interp); + if (phfill) { + ph = &d->phdr[0]; + ph->p_offset = sizeof(ElfW(Ehdr)); + ph->p_vaddr = base + ph->p_offset; + ph->p_filesz = phnum * sizeof(ElfW(Phdr)); + ph->p_align = 4; + fill_phdr(ph, PT_PHDR, NULL); + } + return file_offset; } /* put dynamic tag */ @@ -2075,75 +2133,6 @@ static void put_dt(Section *dynamic, int dt, addr_t val) dyn->d_un.d_val = val; } -static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, - Section *dynamic, Section *note, struct ro_inf *roinf) -{ - ElfW(Phdr) *ph; - - /* if interpreter, then add corresponding program header */ - if (interp) { - ph = &phdr[0]; - - ph->p_type = PT_PHDR; - ph->p_offset = sizeof(ElfW(Ehdr)); - ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr)); - ph->p_vaddr = interp->sh_addr - ph->p_filesz; - ph->p_paddr = ph->p_vaddr; - ph->p_flags = PF_R | PF_X; - ph->p_align = 4; /* interp->sh_addralign; */ - ph++; - - 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 (note) { - ph = &phdr[phnum - 2 - (roinf != NULL)]; - - ph->p_type = PT_NOTE; - ph->p_offset = note->sh_offset; - ph->p_vaddr = note->sh_addr; - ph->p_paddr = ph->p_vaddr; - ph->p_filesz = note->sh_size; - ph->p_memsz = note->sh_size; - ph->p_flags = PF_R; - ph->p_align = note->sh_addralign; - } - - /* if dynamic section, then add corresponding program header */ - if (dynamic) { - ph = &phdr[phnum - 1 - (roinf != NULL)]; - - 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; - } - - if (roinf) { - ph = &phdr[phnum - 1]; - - ph->p_type = PT_GNU_RELRO; - ph->p_offset = roinf->sh_offset; - ph->p_vaddr = roinf->sh_addr; - ph->p_paddr = ph->p_vaddr; - ph->p_filesz = roinf->sh_size; - ph->p_memsz = roinf->sh_size; - ph->p_flags = PF_R; - ph->p_align = 1; - } -} - /* Fill the dynamic section with tags describing the address and size of sections */ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) @@ -2245,6 +2234,7 @@ static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf) } } +static int tidy_section_headers(TCCState *s1, int *sec_order); #endif /* ndef ELF_OBJ_ONLY */ /* Create an ELF file on disk. @@ -2266,6 +2256,9 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, ehdr.e_phentsize = sizeof(ElfW(Phdr)); ehdr.e_phnum = phnum; ehdr.e_phoff = sizeof(ElfW(Ehdr)); +#ifndef ELF_OBJ_ONLY + shnum = tidy_section_headers(s1, sec_order); +#endif } /* align to 4 */ @@ -2328,8 +2321,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); sort_syms(s1, symtab_section); - for(i = 1; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; + for(i = 1; i < shnum; i++) { + s = s1->sections[sec_order ? sec_order[i] : i]; if (s->sh_type != SHT_NOBITS) { while (offset < s->sh_offset) { fputc(0, f); @@ -2348,7 +2341,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, offset++; } - for(i = 0; i < s1->nb_sections; i++) { + for(i = 0; i < shnum; i++) { sh = &shdr; memset(sh, 0, sizeof(ElfW(Shdr))); s = s1->sections[i]; @@ -2429,7 +2422,7 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, #ifndef ELF_OBJ_ONLY /* Sort section headers by assigned sh_addr, remove sections that we aren't going to output. */ -static void tidy_section_headers(TCCState *s1, int *sec_order) +static int tidy_section_headers(TCCState *s1, int *sec_order) { int i, nnew, l, *backmap; Section **snew, *s; @@ -2469,8 +2462,8 @@ static void tidy_section_headers(TCCState *s1, int *sec_order) sec_order[i] = i; tcc_free(s1->sections); s1->sections = snew; - s1->nb_sections = nnew; tcc_free(backmap); + return nnew; } #ifdef TCC_TARGET_ARM @@ -2536,34 +2529,33 @@ static void alloc_sec_names(TCCState *s1, int is_obj); /* XXX: suppress unneeded sections */ static int elf_output_file(TCCState *s1, const char *filename) { - int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order; + int i, ret, file_type, file_offset, *sec_order; struct dyn_inf dyninf = {0}; - struct ro_inf roinf; - ElfW(Phdr) *phdr; - Section *interp, *dynamic, *dynstr, *note; - struct ro_inf *roinf_use = NULL; + Section *interp, *dynstr, *dynamic; int textrel, got_sym, dt_flags_1; file_type = s1->output_type; s1->nb_errors = 0; ret = -1; - phdr = NULL; + interp = dynstr = dynamic = NULL; sec_order = NULL; - interp = dynamic = dynstr = note = NULL; + dyninf.roinf = &dyninf._roinf; #ifdef TCC_TARGET_ARM create_arm_attribute_section (s1); #endif #if TARGETOS_OpenBSD - note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); + dyninf.note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); #endif #if TARGETOS_NetBSD - note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); + dyninf.note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); #endif - { +#if TARGETOS_FreeBSD || TARGETOS_NetBSD + dyninf.roinf = NULL; +#endif /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ tcc_add_runtime(s1); resolve_common_syms(s1); @@ -2580,6 +2572,7 @@ static int elf_output_file(TCCState *s1, const char *filename) interp->sh_addralign = 1; ptr = section_ptr_add(interp, 1 + strlen(elfint)); strcpy(ptr, elfint); + dyninf.interp = interp; } /* add dynamic symbol table */ @@ -2612,7 +2605,6 @@ static int elf_output_file(TCCState *s1, const char *filename) build_got_entries(s1, 0); } version_add (s1); - } textrel = set_sec_sizes(s1); alloc_sec_names(s1, 0); @@ -2654,36 +2646,11 @@ static int elf_output_file(TCCState *s1, const char *filename) dynstr->sh_size = dynstr->data_offset; } - /* compute number of program headers */ - phfill = 2; - for (i = 1; i < s1->nb_sections; i++) - if (s1->sections[i]->sh_flags & SHF_TLS) - phfill = 3; - phnum = 3; - if (interp) - phnum += phfill; - if (note) - phnum++; -#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD - /* GNU_RELRO */ - phnum++, roinf_use = &roinf; -#endif - - /* allocate program segment headers */ - phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); - /* compute number of sections */ - shnum = s1->nb_sections; /* this array is used to reorder sections in the output file */ - sec_order = tcc_malloc(sizeof(int) * shnum); - sec_order[0] = 0; - + sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); /* compute section to program header mapping */ - file_offset = layout_sections(s1, phdr, phnum, phfill, interp, &roinf, sec_order + 1); + file_offset = layout_sections(s1, sec_order, &dyninf); - /* Fill remaining program header and finalize relocation related to dynamic - linking. */ - { - fill_unloadable_phdr(phdr, phnum, interp, dynamic, note, roinf_use); if (dynamic) { ElfW(Sym) *sym; @@ -2705,7 +2672,6 @@ static int elf_output_file(TCCState *s1, const char *filename) /* if building executable or DLL, then relocate each section except the GOT which is already relocated */ relocate_syms(s1, s1->symtab, 0); - ret = -1; if (s1->nb_errors != 0) goto the_end; relocate_sections(s1); @@ -2714,21 +2680,17 @@ static int elf_output_file(TCCState *s1, const char *filename) dynamic->data_offset = dyninf.data_offset; fill_dynamic(s1, &dyninf); } - tidy_section_headers(s1, sec_order); - /* Perform relocation to GOT or PLT entries */ if (file_type == TCC_OUTPUT_EXE && s1->static_link) fill_got(s1); else if (s1->got) fill_local_got_entries(s1); - } - /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); - s1->nb_sections = shnum; + /* Create the ELF file with name 'filename' */ + ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order); the_end: tcc_free(sec_order); - tcc_free(phdr); + tcc_free(dyninf.phdr); return ret; } #endif /* ndef ELF_OBJ_ONLY */ @@ -2751,42 +2713,24 @@ static void alloc_sec_names(TCCState *s1, int is_obj) strsec->sh_size = strsec->data_offset; } -static int layout_any_sections(TCCState *s1, int file_offset, int *sec_order, int is_obj) +/* Output an elf .o file */ +static int elf_output_obj(TCCState *s1, const char *filename) { - int i; Section *s; + int i, ret, file_offset; + s1->nb_errors = 0; + /* Allocate strings for section names */ + alloc_sec_names(s1, 1); + file_offset = sizeof (ElfW(Ehdr)); for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; - if (!is_obj && (s->sh_flags & SHF_ALLOC)) - continue; - *sec_order++ = i; - file_offset = (file_offset + s->sh_addralign - 1) & - ~(s->sh_addralign - 1); + file_offset = (file_offset + 15) & -16; s->sh_offset = file_offset; if (s->sh_type != SHT_NOBITS) file_offset += s->sh_size; } - return file_offset; -} - -/* Output an elf .o file */ -static int elf_output_obj(TCCState *s1, const char *filename) -{ - int ret, file_offset; - int *sec_order; - s1->nb_errors = 0; - - /* Allocate strings for section names */ - alloc_sec_names(s1, 1); - - /* this array is used to reorder sections in the output file */ - sec_order = tcc_malloc(sizeof(int) * s1->nb_sections); - sec_order[0] = 0; - file_offset = layout_any_sections(s1, sizeof (ElfW(Ehdr)), sec_order + 1, 1); - /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, 0, NULL, file_offset, sec_order); - tcc_free(sec_order); + ret = tcc_write_elf_file(s1, filename, 0, NULL, file_offset, NULL); return ret; } diff --git a/tccpe.c b/tccpe.c index 66773312..0efe6491 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1071,12 +1071,18 @@ static int pe_section_class(Section *s) { int type, flags; const char *name; - type = s->sh_type; flags = s->sh_flags; name = s->name; + if (0 == memcmp(name, ".stab", 5)) { + if (0 == s->s1->do_debug) + return sec_last; + return name[5] ? sec_stabstr : sec_stab; + } if (flags & SHF_ALLOC) { - if (type == SHT_PROGBITS) { + if (type == SHT_PROGBITS + || type == SHT_INIT_ARRAY + || type == SHT_FINI_ARRAY) { if (flags & SHF_EXECINSTR) return sec_text; if (flags & SHF_WRITE) @@ -1089,52 +1095,44 @@ static int pe_section_class(Section *s) return sec_pdata; return sec_rdata; } else if (type == SHT_NOBITS) { - if (flags & SHF_WRITE) - return sec_bss; + return sec_bss; } + return sec_other; } else { if (0 == strcmp(name, ".reloc")) return sec_reloc; } - if (0 == memcmp(name, ".stab", 5)) - return name[5] ? sec_stabstr : sec_stab; - if (flags & SHF_ALLOC) - return sec_other; - return -1; + return sec_last; } static int pe_assign_addresses (struct pe_info *pe) { - int i, k, o, c; + int i, k, n, c, nbs; DWORD addr; - int *section_order; + int *sec_order, *sec_cls; struct section_info *si; Section *s; TCCState *s1 = pe->s1; if (PE_DLL == pe->type) pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0); - // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); + //pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); - section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); - for (o = k = 0 ; k < sec_last; ++k) { - for (i = 1; i < s1->nb_sections; ++i) { - s = s1->sections[i]; - if (k == pe_section_class(s)) - section_order[o++] = i; - } + nbs = s1->nb_sections; + sec_order = tcc_mallocz(2 * sizeof (int) * nbs); + sec_cls = sec_order + nbs; + for (i = 1; i < nbs; ++i) { + s = s1->sections[i]; + k = pe_section_class(s); + for (n = i; n > 1 && k < (c = sec_cls[n - 1]); --n) + sec_cls[n] = c, sec_order[n] = sec_order[n - 1]; + sec_cls[n] = k, sec_order[n] = i; } - si = NULL; addr = pe->imagebase + 1; - for (i = 0; i < o; ++i) { - k = section_order[i]; - s = s1->sections[k]; - c = pe_section_class(s); - - if ((c == sec_stab || c == sec_stabstr) && 0 == s1->do_debug) - continue; + for (i = 1; (c = sec_cls[i]) < sec_last; ++i) { + s = s1->sections[sec_order[i]]; if (PE_MERGE_DATA && c == sec_bss) c = sec_data; @@ -1195,28 +1193,31 @@ add_section: } //printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name); } - tcc_free(section_order); #if 0 - for (i = 1; i < s1->nb_sections; ++i) { - Section *s = s1->sections[i]; + for (i = 1; i < nbs; ++i) { + Section *s = s1->sections[sec_order[i]]; int type = s->sh_type; int flags = s->sh_flags; printf("section %-16s %-10s %08x %04x %s,%s,%s\n", s->name, type == SHT_PROGBITS ? "progbits" : + type == SHT_INIT_ARRAY ? "initarr" : + type == SHT_FINI_ARRAY ? "finiarr" : type == SHT_NOBITS ? "nobits" : type == SHT_SYMTAB ? "symtab" : type == SHT_STRTAB ? "strtab" : type == SHT_RELX ? "rel" : "???", - s->sh_addr, - s->data_offset, + (unsigned)s->sh_addr, + (unsigned)s->data_offset, flags & SHF_ALLOC ? "alloc" : "", flags & SHF_WRITE ? "write" : "", flags & SHF_EXECINSTR ? "exec" : "" ); + fflush(stdout); } s1->verbose = 2; #endif + tcc_free(sec_order); return 0; }