diff options
-rw-r--r-- | doc/changes.src | 2 | ||||
-rw-r--r-- | output/elf.h | 19 | ||||
-rw-r--r-- | output/outelf.c | 1038 | ||||
-rw-r--r-- | output/outelf.h | 43 | ||||
-rw-r--r-- | test/fewsecs.asm | 2 | ||||
-rw-r--r-- | test/manysecs.asm | 13 | ||||
-rw-r--r-- | test/moresecs.asm | 3 | ||||
-rw-r--r-- | test/mostsecs.asm | 3 |
8 files changed, 570 insertions, 553 deletions
diff --git a/doc/changes.src b/doc/changes.src index 6fd19943..1e67bec5 100644 --- a/doc/changes.src +++ b/doc/changes.src @@ -15,6 +15,8 @@ after a real error. \b Add support for the \c{merge} and \c{strings} attributes on ELF sections. See \k{elfsect}. +\b Handle more than 32,633 sections in ELF. + \S{cl-2.14.02} Version 2.14.02 \b Fix crash due to multiple errors or warnings during the code diff --git a/output/elf.h b/output/elf.h index 32f5b47a..72b43073 100644 --- a/output/elf.h +++ b/output/elf.h @@ -160,7 +160,11 @@ #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 -#define SHT_NUM 12 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 @@ -179,14 +183,25 @@ #define SHF_TLS (1 << 10) /* Section hold thread-local data. */ /* Special section numbers */ -#define SHN_UNDEF 0 +#define SHN_UNDEF 0x0000 #define SHN_LORESERVE 0xff00 #define SHN_LOPROC 0xff00 #define SHN_HIPROC 0xff1f #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff #define SHN_HIRESERVE 0xffff +/* Same, but signed/sign-extended */ +#define XSHN_UNDEF ((int16_t)SHN_UNDEF) +#define XSHN_LORESERVE ((int16_t)SHN_LORESERVE) +#define XSHN_LOPROC ((int16_t)SHN_LOPROC) +#define XSHN_HIPROC ((int16_t)SHN_HIPROC) +#define XSHN_ABS ((int16_t)SHN_ABS) +#define XSHN_COMMON ((int16_t)SHN_COMMON) +#define XSHN_XINDEX ((int16_t)SHN_XINDEX) +#define XSHN_HIRESERVE ((int16_t)SHN_HIRESERVE) + /* Section align flag */ #define SHA_ANY 1 /* No alignment constraint */ diff --git a/output/outelf.c b/output/outelf.c index bd5a3e6d..4db7fbde 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -75,6 +75,8 @@ static int32_t def_seg; static struct RAA *bsym; +static struct SAA *symtab, *symtab_shndx; + static struct SAA *strs; static uint32_t strslen; @@ -106,9 +108,11 @@ static void elf_section_header(int name, int type, uint64_t flags, int link, int info, uint64_t align, uint64_t entsize); static void elf_write_sections(void); -static struct SAA *elf_build_symtab(int32_t *, int32_t *); -static struct SAA *elf_build_reltab(uint64_t *, struct elf_reloc *); -static void add_sectname(const char *, const char *); +static size_t elf_build_symtab(void); +static int add_sectname(const char *, const char *); + +/* First debugging section index */ +static int sec_debug; struct erel { int offset; @@ -182,9 +186,33 @@ static void dwarf_cleanup(void); static void dwarf_findfile(const char *); static void dwarf_findsect(const int); -static bool is_elf64(void); -static bool is_elf32(void); -static bool is_elfx32(void); +struct elf_format_info { + size_t word; /* Word size (4 or 8) */ + size_t ehdr_size; /* Size of the ELF header */ + size_t shdr_size; /* Size of a section header */ + size_t sym_size; /* Size of a symbol */ + size_t rel_size; /* Size of a reltype relocation */ + size_t rela_size; /* Size of a RELA relocation */ + char relpfx[8]; /* Relocation section prefix */ + uint32_t reltype; /* Relocation section type */ + uint16_t e_machine; /* Header e_machine field */ + uint8_t ei_class; /* ELFCLASS32 or ELFCLASS64 */ + bool elf64; /* 64-bit ELF */ + + /* Write a symbol */ + void (*elf_sym)(const struct elf_symbol *); + + /* Build a relocation table */ + struct SAA *(*elf_build_reltab)(const struct elf_reloc *); +}; +static const struct elf_format_info *efmt; + +static void elf32_sym(const struct elf_symbol *sym); +static void elf64_sym(const struct elf_symbol *sym); + +static struct SAA *elf32_build_reltab(const struct elf_reloc *r); +static struct SAA *elfx32_build_reltab(const struct elf_reloc *r); +static struct SAA *elf64_build_reltab(const struct elf_reloc *r); static bool dfmt_is_stabs(void); static bool dfmt_is_dwarf(void); @@ -377,6 +405,74 @@ elf_directive(enum directive directive, char *value, int pass) } } +static void elf_init(void); + +static void elf32_init(void) +{ + static const struct elf_format_info ef_elf32 = { + 4, + sizeof(Elf32_Ehdr), + sizeof(Elf32_Shdr), + sizeof(Elf32_Sym), + sizeof(Elf32_Rel), + sizeof(Elf32_Rela), + ".rel", + SHT_REL, + EM_386, + ELFCLASS32, + false, + + elf32_sym, + elf32_build_reltab + }; + efmt = &ef_elf32; + elf_init(); +} + +static void elfx32_init(void) +{ + static const struct elf_format_info ef_elfx32 = { + 4, + sizeof(Elf32_Ehdr), + sizeof(Elf32_Shdr), + sizeof(Elf32_Sym), + sizeof(Elf32_Rela), + sizeof(Elf32_Rela), + ".rela", + SHT_RELA, + EM_X86_64, + ELFCLASS32, + false, + + elf32_sym, + elfx32_build_reltab + }; + efmt = &ef_elfx32; + elf_init(); +} + +static void elf64_init(void) +{ + static const struct elf_format_info ef_elf64 = { + 8, + sizeof(Elf64_Ehdr), + sizeof(Elf64_Shdr), + sizeof(Elf64_Sym), + sizeof(Elf64_Rela), + sizeof(Elf64_Rela), + ".rela", + SHT_RELA, + EM_X86_64, + ELFCLASS64, + true, + + elf64_sym, + elf64_build_reltab + }; + efmt = &ef_elf64; + elf_init(); +} + static void elf_init(void) { static const char * const reserved_sections[] = { @@ -396,7 +492,7 @@ static void elf_init(void) strslen = 2 + strlen(elf_module); shstrtab = NULL; shstrtablen = shstrtabsize = 0;; - add_sectname("", ""); + add_sectname("", ""); /* SHN_UNDEF */ fwds = NULL; @@ -444,7 +540,7 @@ static void elf_cleanup(void) for (i = 0; i < nsects; i++) { if (sects[i]->type != SHT_NOBITS) saa_free(sects[i]->data); - if (sects[i]->head) + if (sects[i]->rel) saa_free(sects[i]->rel); while (sects[i]->head) { r = sects[i]->head; @@ -461,15 +557,27 @@ static void elf_cleanup(void) dfmt->cleanup(); } -/* add entry to the elf .shstrtab section */ -static void add_sectname(const char *firsthalf, const char *secondhalf) +/* + * Add entry to the elf .shstrtab section and increment nsections. + * Returns the section index for this new section. + * + * IMPORTANT: this needs to match the order the section headers are + * emitted. + */ +static int add_sectname(const char *firsthalf, const char *secondhalf) { - int len = strlen(firsthalf) + strlen(secondhalf); - while (shstrtablen + len + 1 > shstrtabsize) + int l1 = strlen(firsthalf); + int l2 = strlen(secondhalf); + + while (shstrtablen + l1 + l2 + 1 > shstrtabsize) shstrtab = nasm_realloc(shstrtab, (shstrtabsize += SHSTR_DELTA)); - strcpy(shstrtab + shstrtablen, firsthalf); - strcat(shstrtab + shstrtablen, secondhalf); - shstrtablen += len + 1; + + memcpy(shstrtab + shstrtablen, firsthalf, l1); + shstrtablen += l1; + memcpy(shstrtab + shstrtablen, secondhalf, l2+1); + shstrtablen += l2 + 1; + + return nsections++; } static struct elf_section * @@ -486,13 +594,12 @@ elf_make_section(char *name, int type, int flags, uint64_t align) s->index = def_seg; else s->index = seg_alloc(); - add_sectname("", name); s->name = nasm_strdup(name); s->type = type; s->flags = flags; s->align = align; - s->shndx = nsects + 1; + s->shndx = add_sectname("", name); if (nsects >= sectlen) sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects)); @@ -650,10 +757,10 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset, sym->other = STV_DEFAULT; sym->size = 0; if (segment == NO_SEG) - sym->section = SHN_ABS; + sym->section = XSHN_ABS; else { const struct elf_section *s; - sym->section = SHN_UNDEF; + sym->section = XSHN_UNDEF; if (segment == def_seg) { /* we have to be sure at least text section is there */ int tempint; @@ -668,7 +775,7 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset, if (is_global == 2) { sym->size = offset; sym->symv.key = 0; - sym->section = SHN_COMMON; + sym->section = XSHN_COMMON; /* * We have a common variable. Check the special text to see * if it's a valid number and power of two; if so, store it @@ -686,7 +793,7 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset, } special_used = true; } else - sym->symv.key = (sym->section == SHN_UNDEF ? 0 : offset); + sym->symv.key = (sym->section == XSHN_UNDEF ? 0 : offset); if (sym->type == SYM_GLOBAL) { /* @@ -699,9 +806,9 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset, * To avoid such a crash, such requests are silently discarded. * This may not be the best solution. */ - if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) { + if (sym->section == XSHN_UNDEF || sym->section == XSHN_COMMON) { bsym = raa_write(bsym, segment, nglobs); - } else if (sym->section != SHN_ABS) { + } else if (sym->section != XSHN_ABS) { /* * This is a global symbol; so we must add it to the rbtree * of global symbols in its section. @@ -803,11 +910,11 @@ static void elf_add_reloc(struct elf_section *sect, int32_t segment, r->offset = offset; if (segment != NO_SEG) { - int i; - for (i = 0; i < nsects; i++) - if (segment == sects[i]->index) - r->symbol = i + 2; - if (!r->symbol) + const struct elf_section *s; + s = raa_read_ptr(section_by_index, segment >> 1); + if (s) + r->symbol = s->shndx + 1; + else r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); } r->type = type; @@ -845,7 +952,6 @@ static int64_t elf_add_gsym_reloc(struct elf_section *sect, struct elf_section *s; struct elf_symbol *sym; struct rbtree *srb; - int i; /* * First look up the segment/offset pair and find a global @@ -854,13 +960,7 @@ static int64_t elf_add_gsym_reloc(struct elf_section *sect, * doing a normal elf_add_reloc after first sanity-checking * that the offset from the symbol is zero. */ - s = NULL; - for (i = 0; i < nsects; i++) - if (segment == sects[i]->index) { - s = sects[i]; - break; - } - + s = raa_read_ptr(section_by_index, segment >> 1); if (!s) { if (exact && offset) nasm_error(ERR_NONFATAL, "invalid access to an external symbol"); @@ -897,7 +997,6 @@ static void elf32_out(int32_t segto, const void *data, struct elf_section *s; int64_t addr; int reltype, bytes; - int i; static struct symlininfo sinfo; /* @@ -910,25 +1009,18 @@ static void elf32_out(int32_t segto, const void *data, return; } - s = NULL; - for (i = 0; i < nsects; i++) - if (segto == sects[i]->index) { - s = sects[i]; - break; - } + s = raa_read_ptr(section_by_index, segto >> 1); if (!s) { int tempint; /* ignored */ if (segto != elf_section_names(".text", 2, &tempint)) nasm_panic(0, "strange segment conditions in ELF driver"); - else { + else s = sects[nsects - 1]; - i = nsects - 1; - } } /* again some stabs debugging stuff */ sinfo.offset = s->len; - sinfo.section = i; + sinfo.section = s->shndx; sinfo.segto = segto; sinfo.name = s->name; dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); @@ -1116,7 +1208,6 @@ static void elf64_out(int32_t segto, const void *data, struct elf_section *s; int64_t addr; int reltype, bytes; - int i; static struct symlininfo sinfo; /* @@ -1129,25 +1220,18 @@ static void elf64_out(int32_t segto, const void *data, return; } - s = NULL; - for (i = 0; i < nsects; i++) - if (segto == sects[i]->index) { - s = sects[i]; - break; - } + s = raa_read_ptr(section_by_index, segto >> 1); if (!s) { int tempint; /* ignored */ if (segto != elf_section_names(".text", 2, &tempint)) nasm_panic(0, "strange segment conditions in ELF driver"); - else { + else s = sects[nsects - 1]; - i = nsects - 1; - } } /* again some stabs debugging stuff */ sinfo.offset = s->len; - sinfo.section = i; + sinfo.section = s->shndx; sinfo.segto = segto; sinfo.name = s->name; dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); @@ -1406,7 +1490,6 @@ static void elfx32_out(int32_t segto, const void *data, struct elf_section *s; int64_t addr; int reltype, bytes; - int i; static struct symlininfo sinfo; /* @@ -1419,25 +1502,18 @@ static void elfx32_out(int32_t segto, const void *data, return; } - s = NULL; - for (i = 0; i < nsects; i++) - if (segto == sects[i]->index) { - s = sects[i]; - break; - } + s = raa_read_ptr(section_by_index, segto >> 1); if (!s) { int tempint; /* ignored */ if (segto != elf_section_names(".text", 2, &tempint)) nasm_panic(0, "strange segment conditions in ELF driver"); - else { + else s = sects[nsects - 1]; - i = nsects - 1; - } } /* again some stabs debugging stuff */ sinfo.offset = s->len; - sinfo.section = i; + sinfo.section = s->shndx; sinfo.segto = segto; sinfo.name = s->name; dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); @@ -1651,51 +1727,53 @@ rel12adr: } } +/* + * Section index/count with a specified overflow value (usually SHN_INDEX, + * but 0 for e_shnum. + */ +static inline uint16_t elf_shndx(int section, uint16_t overflow) +{ + return cpu_to_le16(section < (int)SHN_LORESERVE ? section : overflow); +} + +struct ehdr_common { + uint8_t e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; +}; + +union ehdr { + Elf32_Ehdr ehdr32; + Elf64_Ehdr ehdr64; + struct ehdr_common com; +}; + static void elf_write(void) { int align; char *p; int i; - - struct SAA *symtab; - int32_t symtablen, symtablocal; + size_t symtablocal; + int sec_shstrtab, sec_symtab, sec_strtab; + union ehdr ehdr; /* - * Work out how many sections we will have. We have SHN_UNDEF, - * then the flexible user sections, then the fixed sections - * `.shstrtab', `.symtab' and `.strtab', then optionally - * relocation sections for the user sections. + * Add any sections we don't already have: + * rel/rela sections for the user sections, debug sections, and + * the ELF special sections. */ - nsections = sec_numspecial + 1; - if (dfmt_is_stabs()) - nsections += 3; - else if (dfmt_is_dwarf()) - nsections += 10; - - add_sectname("", ".shstrtab"); - add_sectname("", ".symtab"); - add_sectname("", ".strtab"); - for (i = 0; i < nsects; i++) { - nsections++; /* for the section itself */ - if (sects[i]->head) { - nsections++; /* for its relocations */ - add_sectname(is_elf32() ? ".rel" : ".rela", sects[i]->name); - } - } + sec_debug = nsections; if (dfmt_is_stabs()) { /* in case the debug information is wanted, just add these three sections... */ add_sectname("", ".stab"); add_sectname("", ".stabstr"); - add_sectname(is_elf32() ? ".rel" : ".rela", ".stab"); + add_sectname(efmt->relpfx, ".stab"); } else if (dfmt_is_dwarf()) { /* the dwarf debug standard specifies the following ten sections, not all of which are currently implemented, although all of them are defined. */ -#define debug_aranges (int64_t) (nsections-10) -#define debug_info (int64_t) (nsections-7) -#define debug_abbrev (int64_t) (nsections-5) -#define debug_line (int64_t) (nsections-4) add_sectname("", ".debug_aranges"); add_sectname(".rela", ".debug_aranges"); add_sectname("", ".debug_pubnames"); @@ -1708,87 +1786,72 @@ static void elf_write(void) add_sectname("", ".debug_loc"); } + sec_shstrtab = add_sectname("", ".shstrtab"); + sec_symtab = add_sectname("", ".symtab"); + sec_strtab = add_sectname("", ".strtab"); + /* - * Output the ELF header. + * Build the symbol table and relocation tables. */ - if (is_elf32() || is_elfx32()) { - Elf32_Ehdr ehdr; - - nasm_zero(ehdr.e_ident); - memcpy(ehdr.e_ident, ELFMAG, SELFMAG); - ehdr.e_ident[EI_CLASS] = ELFCLASS32; - ehdr.e_ident[EI_DATA] = ELFDATA2LSB; - ehdr.e_ident[EI_VERSION] = EV_CURRENT; - ehdr.e_ident[EI_OSABI] = elf_osabi; - ehdr.e_ident[EI_ABIVERSION] = elf_abiver; - - ehdr.e_type = cpu_to_le16(ET_REL); - ehdr.e_machine = cpu_to_le16(is_elf32() ? EM_386 : EM_X86_64); - ehdr.e_version = cpu_to_le16(EV_CURRENT); - ehdr.e_entry = 0; - ehdr.e_phoff = 0; - ehdr.e_shoff = sizeof(Elf64_Ehdr); - ehdr.e_flags = 0; - ehdr.e_ehsize = cpu_to_le16(sizeof(Elf32_Ehdr)); - ehdr.e_phentsize = 0; - ehdr.e_phnum = 0; - ehdr.e_shentsize = cpu_to_le16(sizeof(Elf32_Shdr)); - ehdr.e_shnum = cpu_to_le16(nsections); - ehdr.e_shstrndx = cpu_to_le16(sec_shstrtab); - - nasm_write(&ehdr, sizeof(ehdr), ofile); - fwritezero(sizeof(Elf64_Ehdr) - sizeof(Elf32_Ehdr), ofile); - } else { - Elf64_Ehdr ehdr; + symtablocal = elf_build_symtab(); - nasm_assert(is_elf64()); + /* Do we need an .symtab_shndx section? */ + if (symtab_shndx) + add_sectname("", ".symtab_shndx"); - nasm_zero(ehdr.e_ident); - memcpy(ehdr.e_ident, ELFMAG, SELFMAG); - ehdr.e_ident[EI_CLASS] = ELFCLASS64; - ehdr.e_ident[EI_DATA] = ELFDATA2LSB; - ehdr.e_ident[EI_VERSION] = EV_CURRENT; - ehdr.e_ident[EI_OSABI] = elf_osabi; - ehdr.e_ident[EI_ABIVERSION] = elf_abiver; - - ehdr.e_type = cpu_to_le16(ET_REL); - ehdr.e_machine = cpu_to_le16(EM_X86_64); - ehdr.e_version = cpu_to_le16(EV_CURRENT); - ehdr.e_entry = 0; - ehdr.e_phoff = 0; - ehdr.e_shoff = sizeof(Elf64_Ehdr); - ehdr.e_flags = 0; - ehdr.e_ehsize = cpu_to_le16(sizeof(Elf64_Ehdr)); - ehdr.e_phentsize = 0; - ehdr.e_phnum = 0; - ehdr.e_shentsize = cpu_to_le16(sizeof(Elf64_Shdr)); - ehdr.e_shnum = cpu_to_le16(nsections); - ehdr.e_shstrndx = cpu_to_le16(sec_shstrtab); - - nasm_write(&ehdr, sizeof(ehdr), ofile); + for (i = 0; i < nsects; i++) { + if (sects[i]->head) { + add_sectname(efmt->relpfx, sects[i]->name); + sects[i]->rel = efmt->elf_build_reltab(sects[i]->head); + } } /* - * Build the symbol table and relocation tables. + * Output the ELF header. */ - symtab = elf_build_symtab(&symtablen, &symtablocal); - for (i = 0; i < nsects; i++) - if (sects[i]->head) - sects[i]->rel = elf_build_reltab(§s[i]->rellen, - sects[i]->head); + nasm_zero(ehdr); + + /* These fields are in the same place for 32 and 64 bits */ + memcpy(&ehdr.com.e_ident[EI_MAG0], ELFMAG, SELFMAG); + ehdr.com.e_ident[EI_CLASS] = efmt->ei_class; + ehdr.com.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.com.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.com.e_ident[EI_OSABI] = elf_osabi; + ehdr.com.e_ident[EI_ABIVERSION] = elf_abiver; + ehdr.com.e_type = cpu_to_le16(ET_REL); + ehdr.com.e_machine = cpu_to_le16(efmt->e_machine); + ehdr.com.e_version = cpu_to_le16(EV_CURRENT); + + if (!efmt->elf64) { + ehdr.ehdr32.e_shoff = cpu_to_le32(sizeof ehdr); + ehdr.ehdr32.e_ehsize = cpu_to_le16(sizeof(Elf32_Ehdr)); + ehdr.ehdr32.e_shentsize = cpu_to_le16(sizeof(Elf32_Shdr)); + ehdr.ehdr32.e_shnum = elf_shndx(nsections, 0); + ehdr.ehdr32.e_shstrndx = elf_shndx(sec_shstrtab, SHN_XINDEX); + } else { + ehdr.ehdr64.e_shoff = cpu_to_le64(sizeof ehdr); + ehdr.ehdr64.e_ehsize = cpu_to_le16(sizeof(Elf64_Ehdr)); + ehdr.ehdr64.e_shentsize = cpu_to_le16(sizeof(Elf64_Shdr)); + ehdr.ehdr64.e_shnum = elf_shndx(nsections, 0); + ehdr.ehdr64.e_shstrndx = elf_shndx(sec_shstrtab, SHN_XINDEX); + } + + nasm_write(&ehdr, sizeof(ehdr), ofile); + elf_foffs = sizeof ehdr + efmt->shdr_size * nsections; /* * Now output the section header table. */ - - elf_foffs = sizeof(Elf64_Ehdr) + (is_elf64() ? sizeof(Elf64_Shdr): sizeof(Elf32_Shdr)) * nsections; align = ALIGN(elf_foffs, SEC_FILEALIGN) - elf_foffs; elf_foffs += align; elf_nsect = 0; elf_sects = nasm_malloc(sizeof(*elf_sects) * nsections); /* SHN_UNDEF */ - elf_section_header(0, SHT_NULL, 0, NULL, false, 0, SHN_UNDEF, 0, 0, 0); + elf_section_header(0, SHT_NULL, 0, NULL, false, + nsections > (int)SHN_LORESERVE ? nsections : 0, + sec_shstrtab >= (int)SHN_LORESERVE ? sec_shstrtab : 0, + 0, 0, 0); p = shstrtab + 1; /* The normal sections */ @@ -1800,53 +1863,7 @@ static void elf_write(void) p += strlen(p) + 1; } - /* .shstrtab */ - elf_section_header(p - shstrtab, SHT_STRTAB, 0, shstrtab, false, - shstrtablen, 0, 0, 1, 0); - p += strlen(p) + 1; - - /* .symtab */ - if (is_elf64()) - elf_section_header(p - shstrtab, SHT_SYMTAB, 0, symtab, true, - symtablen, sec_strtab, symtablocal, 8, 24); - else - elf_section_header(p - shstrtab, SHT_SYMTAB, 0, symtab, true, - symtablen, sec_strtab, symtablocal, 4, 16); - p += strlen(p) + 1; - - /* .strtab */ - elf_section_header(p - shstrtab, SHT_STRTAB, 0, strs, true, - strslen, 0, 0, 1, 0); - p += strlen(p) + 1; - - /* The relocation sections */ - if (is_elf32()) { - for (i = 0; i < nsects; i++) { - if (sects[i]->head) { - elf_section_header(p - shstrtab, SHT_REL, 0, sects[i]->rel, true, - sects[i]->rellen, sec_symtab, i + 1, 4, 8); - p += strlen(p) + 1; - } - } - } else if (is_elfx32()) { - for (i = 0; i < nsects; i++) { - if (sects[i]->head) { - elf_section_header(p - shstrtab, SHT_RELA, 0, sects[i]->rel, true, - sects[i]->rellen, sec_symtab, i + 1, 4, 12); - p += strlen(p) + 1; - } - } - } else { - nasm_assert(is_elf64()); - for (i = 0; i < nsects; i++) { - if (sects[i]->head) { - elf_section_header(p - shstrtab, SHT_RELA, 0, sects[i]->rel, true, - sects[i]->rellen, sec_symtab, i + 1, 8, 24); - p += strlen(p) + 1; - } - } - } - + /* The debugging sections */ if (dfmt_is_stabs()) { /* for debugging information, create the last three sections which are the .stab , .stabstr and .rel.stab sections respectively */ @@ -1856,7 +1873,7 @@ static void elf_write(void) if (stabbuf && stabstrbuf && stabrelbuf) { elf_section_header(p - shstrtab, SHT_PROGBITS, 0, stabbuf, false, - stablen, sec_stabstr, 0, 4, 12); + stablen, sec_stabstr, 0, 4, 12); p += strlen(p) + 1; elf_section_header(p - shstrtab, SHT_STRTAB, 0, stabstrbuf, false, @@ -1864,67 +1881,99 @@ static void elf_write(void) p += strlen(p) + 1; /* link -> symtable info -> section to refer to */ - if (is_elf32()) { - elf_section_header(p - shstrtab, SHT_REL, 0, stabrelbuf, false, - stabrellen, sec_symtab, sec_stab, 4, 8); - } else { - elf_section_header(p - shstrtab, SHT_RELA, 0, stabrelbuf, false, - stabrellen, sec_symtab, sec_stab, 4, is_elf64() ? 24 : 12); - } + elf_section_header(p - shstrtab, efmt->reltype, 0, + stabrelbuf, false, stabrellen, + sec_symtab, sec_stab, + efmt->word, efmt->rel_size); p += strlen(p) + 1; } } else if (dfmt_is_dwarf()) { - /* for dwarf debugging information, create the ten dwarf sections */ + /* for dwarf debugging information, create the ten dwarf sections */ - /* this function call creates the dwarf sections in memory */ - if (dwarf_fsect) - dwarf_generate(); + /* this function call creates the dwarf sections in memory */ + if (dwarf_fsect) + dwarf_generate(); - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, arangesbuf, false, - arangeslen, 0, 0, 1, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, arangesbuf, false, + arangeslen, 0, 0, 1, 0); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_RELA, 0, arangesrelbuf, false, - arangesrellen, sec_symtab, - is_elf64() ? debug_aranges : sec_debug_aranges, - 1, is_elf64() ? 24 : 12); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_RELA, 0, arangesrelbuf, false, + arangesrellen, sec_symtab, + sec_debug_aranges, + efmt->word, efmt->rela_size); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, pubnamesbuf, - false, pubnameslen, 0, 0, 1, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, pubnamesbuf, + false, pubnameslen, 0, 0, 1, 0); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, infobuf, false, - infolen, 0, 0, 1, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, infobuf, false, + infolen, 0, 0, 1, 0); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_RELA, 0, inforelbuf, false, - inforellen, sec_symtab, - is_elf64() ? debug_info : sec_debug_info, - 1, is_elf64() ? 24 : 12); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_RELA, 0, inforelbuf, false, + inforellen, sec_symtab, + sec_debug_info, + efmt->word, efmt->rela_size); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, abbrevbuf, false, - abbrevlen, 0, 0, 1, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, abbrevbuf, false, + abbrevlen, 0, 0, 1, 0); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, linebuf, false, - linelen, 0, 0, 1, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, linebuf, false, + linelen, 0, 0, 1, 0); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_RELA, 0, linerelbuf, false, - linerellen, sec_symtab, - is_elf64() ? debug_line : sec_debug_line, - 1, is_elf64() ? 24 : 12); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_RELA, 0, linerelbuf, false, + linerellen, sec_symtab, + sec_debug_line, + efmt->word, efmt->rela_size); + p += strlen(p) + 1; - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, framebuf, false, - framelen, 0, 0, 8, 0); - p += strlen(p) + 1; + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, framebuf, false, + framelen, 0, 0, 8, 0); + p += strlen(p) + 1; + + elf_section_header(p - shstrtab, SHT_PROGBITS, 0, locbuf, false, + loclen, 0, 0, 1, 0); + p += strlen(p) + 1; + } + + /* .shstrtab */ + elf_section_header(p - shstrtab, SHT_STRTAB, 0, shstrtab, false, + shstrtablen, 0, 0, 1, 0); + p += strlen(p) + 1; + + /* .symtab */ + elf_section_header(p - shstrtab, SHT_SYMTAB, 0, symtab, true, + symtab->datalen, sec_strtab, symtablocal, + efmt->word, efmt->sym_size); + p += strlen(p) + 1; + + /* .strtab */ + elf_section_header(p - shstrtab, SHT_STRTAB, 0, strs, true, + strslen, 0, 0, 1, 0); + p += strlen(p) + 1 +; + /* .symtab_shndx */ + if (symtab_shndx) { + elf_section_header(p - shstrtab, SHT_SYMTAB_SHNDX, 0, + symtab_shndx, true, symtab_shndx->datalen, + sec_symtab, 0, 1, 0); + p += strlen(p) + 1; + } - elf_section_header(p - shstrtab, SHT_PROGBITS, 0, locbuf, false, - loclen, 0, 0, 1, 0); + /* The relocation sections */ + for (i = 0; i < nsects; i++) { + if (sects[i]->rel) { + elf_section_header(p - shstrtab, efmt->reltype, 0, + sects[i]->rel, true, sects[i]->rel->datalen, + sec_symtab, sects[i]->shndx, + efmt->word, efmt->rel_size); p += strlen(p) + 1; + } } fwritezero(align, ofile); @@ -1935,241 +1984,189 @@ static void elf_write(void) nasm_free(elf_sects); saa_free(symtab); + if (symtab_shndx) + saa_free(symtab_shndx); } -static struct SAA *elf_build_symtab(int32_t *len, int32_t *local) +static size_t nsyms; + +static void elf_sym(const struct elf_symbol *sym) { - struct SAA *s = saa_init(1L); - struct elf_symbol *sym; - int i; + int shndx = sym->section; + + /* + * Careful here. This relies on sym->section being signed; for + * special section indicies this value needs to be cast to + * (int16_t) so that it sign-extends, however, here SHN_LORESERVE + * is used as an unsigned constant. + */ + if (shndx >= (int)SHN_LORESERVE) { + if (unlikely(!symtab_shndx)) { + /* Create symtab_shndx and fill previous entries with zero */ + symtab_shndx = saa_init(1); + saa_wbytes(symtab_shndx, NULL, nsyms << 2); + } + } else { + shndx = 0; /* Section index table always write zero */ + } + + if (symtab_shndx) + saa_write32(symtab_shndx, shndx); - size_t usize = is_elf64() ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); - union { - Elf32_Sym sym32; - Elf64_Sym sym64; - } u; + efmt->elf_sym(sym); + nsyms++; +} - *len = *local = 0; +static void elf32_sym(const struct elf_symbol *sym) +{ + Elf32_Sym sym32; + + sym32.st_name = cpu_to_le32(sym->strpos); + sym32.st_value = cpu_to_le32(sym->symv.key); + sym32.st_size = cpu_to_le32(sym->size); + sym32.st_info = sym->type; + sym32.st_other = sym->other; + sym32.st_shndx = elf_shndx(sym->section, SHN_XINDEX); + saa_wbytes(symtab, &sym32, sizeof sym32); +} + +static void elf64_sym(const struct elf_symbol *sym) +{ + Elf64_Sym sym64; + + sym64.st_name = cpu_to_le32(sym->strpos); + sym64.st_value = cpu_to_le64(sym->symv.key); + sym64.st_size = cpu_to_le64(sym->size); + sym64.st_info = sym->type; + sym64.st_other = sym->other; + sym64.st_shndx = elf_shndx(sym->section, SHN_XINDEX); + saa_wbytes(symtab, &sym64, sizeof sym64); +} + +static size_t elf_build_symtab(void) +{ + struct elf_symbol *sym, xsym; + size_t nlocal; + int i; + + symtab = saa_init(1); + symtab_shndx = NULL; /* * Zero symbol first as required by spec. */ - saa_wbytes(s, NULL, usize); - *len += usize; - (*local)++; + nasm_zero(xsym); + elf_sym(&xsym); /* * Next, an entry for the file name. */ - if (is_elf64()) { - u.sym64.st_name = cpu_to_le32(1); - u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_FILE); - u.sym64.st_other = 0; - u.sym64.st_shndx = cpu_to_le16(SHN_ABS); - u.sym64.st_value = 0; - u.sym64.st_size = 0; - } else { - u.sym32.st_name = cpu_to_le32(1); - u.sym32.st_value = 0; - u.sym32.st_size = 0; - u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_FILE); - u.sym32.st_other = 0; - u.sym32.st_shndx = cpu_to_le16(SHN_ABS); - } - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - + nasm_zero(xsym); + xsym.strpos = 1; + xsym.type = ELF32_ST_INFO(STB_LOCAL, STT_FILE); + xsym.section = XSHN_ABS; + elf_sym(&xsym); /* * Now some standard symbols defining the segments, for relocation * purposes. */ - if (is_elf64()) { - u.sym64.st_name = 0; - u.sym64.st_other = 0; - u.sym64.st_value = 0; - u.sym64.st_size = 0; - for (i = 1; i <= nsects; i++) { - u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym64.st_shndx = cpu_to_le16(i); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } - } else { - u.sym32.st_name = 0; - u.sym32.st_value = 0; - u.sym32.st_size = 0; - u.sym32.st_other = 0; - for (i = 1; i <= nsects; i++) { - u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym32.st_shndx = cpu_to_le16(i); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } + nasm_zero(xsym); + for (i = 1; i <= nsects; i++) { + xsym.type = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); + xsym.section = i; + elf_sym(&xsym); + } + + /* + * dwarf needs symbols for debug sections + * which are relocation targets. + */ + if (dfmt_is_dwarf()) { + dwarf_infosym = nsyms; + xsym.section = sec_debug_info; + elf_sym(&xsym); + + dwarf_abbrevsym = nsyms; + xsym.section = sec_debug_abbrev; + elf_sym(&xsym); + + dwarf_linesym = nsyms; + xsym.section = sec_debug_line; + elf_sym(&xsym); } /* * Now the other local symbols. */ saa_rewind(syms); - if (is_elf64()) { - while ((sym = saa_rstruct(syms))) { - if (sym->type & SYM_GLOBAL) - continue; - u.sym64.st_name = cpu_to_le32(sym->strpos); - u.sym64.st_info = sym->type; - u.sym64.st_other = sym->other; - u.sym64.st_shndx = cpu_to_le16(sym->section); - u.sym64.st_value = cpu_to_le64(sym->symv.key); - u.sym64.st_size = cpu_to_le64(sym->size); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } - /* - * dwarf needs symbols for debug sections - * which are relocation targets. - */ - if (dfmt_is_dwarf()) { - dwarf_infosym = *local; - u.sym64.st_name = 0; - u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym64.st_other = 0; - u.sym64.st_shndx = cpu_to_le16(debug_info); - u.sym64.st_value = 0; - u.sym64.st_size = 0; - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - dwarf_abbrevsym = *local; - u.sym64.st_name = 0; - u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym64.st_other = 0; - u.sym64.st_shndx = cpu_to_le16(debug_abbrev); - u.sym64.st_value = 0; - u.sym64.st_size = 0; - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - dwarf_linesym = *local; - u.sym64.st_name = 0; - u.sym64.st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym64.st_other = 0; - u.sym64.st_shndx = cpu_to_le16(debug_line); - u.sym64.st_value = 0; - u.sym64.st_size = 0; - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } - } else { - while ((sym = saa_rstruct(syms))) { - if (sym->type & SYM_GLOBAL) - continue; - u.sym32.st_name = cpu_to_le32(sym->strpos); - u.sym32.st_value = cpu_to_le32(sym->symv.key); - u.sym32.st_size = cpu_to_le32(sym->size); - u.sym32.st_info = sym->type; - u.sym32.st_other = sym->other; - u.sym32.st_shndx = cpu_to_le16(sym->section); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } - /* - * dwarf needs symbols for debug sections - * which are relocation targets. - */ - if (dfmt_is_dwarf()) { - dwarf_infosym = *local; - u.sym32.st_name = 0; - u.sym32.st_value = 0; - u.sym32.st_size = 0; - u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym32.st_other = 0; - u.sym32.st_shndx = cpu_to_le16(sec_debug_info); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - dwarf_abbrevsym = *local; - u.sym32.st_name = 0; - u.sym32.st_value = 0; - u.sym32.st_size = 0; - u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym32.st_other = 0; - u.sym32.st_shndx = cpu_to_le16(sec_debug_abbrev); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - dwarf_linesym = *local; - u.sym32.st_name = 0; - u.sym32.st_value = 0; - u.sym32.st_size = 0; - u.sym32.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION); - u.sym32.st_other = 0; - u.sym32.st_shndx = cpu_to_le16(sec_debug_line); - saa_wbytes(s, &u, usize); - *len += usize; - (*local)++; - } + while ((sym = saa_rstruct(syms))) { + if (sym->type & SYM_GLOBAL) + continue; + + elf_sym(sym); } + nlocal = nsyms; + /* * Now the global symbols. */ saa_rewind(syms); - if (is_elf64()) { - while ((sym = saa_rstruct(syms))) { - if (!(sym->type & SYM_GLOBAL)) - continue; - u.sym64.st_name = cpu_to_le32(sym->strpos); - u.sym64.st_info = sym->type; - u.sym64.st_other = sym->other; - u.sym64.st_shndx = cpu_to_le16(sym->section); - u.sym64.st_value = cpu_to_le64(sym->symv.key); - u.sym64.st_size = cpu_to_le64(sym->size); - saa_wbytes(s, &u, usize); - *len += usize; - } - } else { - while ((sym = saa_rstruct(syms))) { - if (!(sym->type & SYM_GLOBAL)) - continue; - u.sym32.st_name = cpu_to_le32(sym->strpos); - u.sym32.st_value = cpu_to_le32(sym->symv.key); - u.sym32.st_size = cpu_to_le32(sym->size); - u.sym32.st_info = sym->type; - u.sym32.st_other = sym->other; - u.sym32.st_shndx = cpu_to_le16(sym->section); - saa_wbytes(s, &u, usize); - *len += usize; - } + while ((sym = saa_rstruct(syms))) { + if (!(sym->type & SYM_GLOBAL)) + continue; + + elf_sym(sym); } - return s; + return nlocal; } -static struct SAA *elf_build_reltab(uint64_t *len, struct elf_reloc *r) +static struct SAA *elf32_build_reltab(const struct elf_reloc *r) { struct SAA *s; int32_t global_offset; + Elf32_Rel rel32; + + if (!r) + return NULL; + + s = saa_init(1L); + + /* + * How to onvert from a global placeholder to a real symbol index; + * the +2 refers to the two special entries, the null entry and + * the filename entry. + */ + global_offset = -GLOBAL_TEMP_BASE + nsects + nlocals + ndebugs + 2; + + while (r) { + int32_t sym = r->symbol; - size_t usize = is_elf64() ? sizeof(Elf64_Rela) : - (is_elfx32() ? sizeof(Elf32_Rela) : sizeof(Elf32_Rel)); - union { - Elf32_Rel rel32; - Elf32_Rela rela32; - Elf64_Rela rela64; - } u; + if (sym >= GLOBAL_TEMP_BASE) + sym += global_offset; + + rel32.r_offset = cpu_to_le32(r->address); + rel32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); + saa_wbytes(s, &rel32, sizeof rel32); + + r = r->next; + } + + return s; +} + +static struct SAA *elfx32_build_reltab(const struct elf_reloc *r) +{ + struct SAA *s; + int32_t global_offset; + Elf32_Rela rela32; if (!r) return NULL; s = saa_init(1L); - *len = 0; /* * How to onvert from a global placeholder to a real symbol index; @@ -2178,51 +2175,53 @@ static struct SAA *elf_build_reltab(uint64_t *len, struct elf_reloc *r) */ global_offset = -GLOBAL_TEMP_BASE + nsects + nlocals + ndebugs + 2; - if (is_elf32()) { - while (r) { - int32_t sym = r->symbol; + while (r) { + int32_t sym = r->symbol; - if (sym >= GLOBAL_TEMP_BASE) - sym += global_offset; + if (sym >= GLOBAL_TEMP_BASE) + sym += global_offset; - u.rel32.r_offset = cpu_to_le32(r->address); - u.rel32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); - saa_wbytes(s, &u, usize); - *len += usize; + rela32.r_offset = cpu_to_le32(r->address); + rela32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); + rela32.r_addend = cpu_to_le32(r->offset); + saa_wbytes(s, &rela32, sizeof rela32); - r = r->next; - } - } else if (is_elfx32()) { - while (r) { - int32_t sym = r->symbol; + r = r->next; + } + + return s; +} - if (sym >= GLOBAL_TEMP_BASE) - sym += global_offset; +static struct SAA *elf64_build_reltab(const struct elf_reloc *r) +{ + struct SAA *s; + int32_t global_offset; + Elf64_Rela rela64; - u.rela32.r_offset = cpu_to_le32(r->address); - u.rela32.r_info = cpu_to_le32(ELF32_R_INFO(sym, r->type)); - u.rela32.r_addend = cpu_to_le32(r->offset); - saa_wbytes(s, &u, usize); - *len += usize; + if (!r) + return NULL; - r = r->next; - } - } else { - nasm_assert(is_elf64()); - while (r) { - int32_t sym = r->symbol; + s = saa_init(1L); - if (sym >= GLOBAL_TEMP_BASE) - sym += global_offset; + /* + * How to onvert from a global placeholder to a real symbol index; + * the +2 refers to the two special entries, the null entry and + * the filename entry. + */ + global_offset = -GLOBAL_TEMP_BASE + nsects + nlocals + ndebugs + 2; - u.rela64.r_offset = cpu_to_le64(r->address); - u.rela64.r_info = cpu_to_le64(ELF64_R_INFO(sym, r->type)); - u.rela64.r_addend = cpu_to_le64(r->offset); - saa_wbytes(s, &u, usize); - *len += usize; + while (r) { + int32_t sym = r->symbol; - r = r->next; - } + if (sym >= GLOBAL_TEMP_BASE) + sym += global_offset; + + rela64.r_offset = cpu_to_le64(r->address); + rela64.r_info = cpu_to_le64(ELF64_R_INFO(sym, r->type)); + rela64.r_addend = cpu_to_le64(r->offset); + saa_wbytes(s, &rela64, sizeof rela64); + + r = r->next; } return s; @@ -2233,47 +2232,46 @@ static void elf_section_header(int name, int type, uint64_t flags, int link, int info, uint64_t align, uint64_t entsize) { - union { - Elf32_Shdr shdr32; - Elf64_Shdr shdr64; - } shdr; - elf_sects[elf_nsect].data = data; elf_sects[elf_nsect].len = datalen; elf_sects[elf_nsect].is_saa = is_saa; elf_nsect++; - if (is_elf32() || is_elfx32()) { - shdr.shdr32.sh_name = cpu_to_le32(name); - shdr.shdr32.sh_type = cpu_to_le32(type); - shdr.shdr32.sh_flags = cpu_to_le32(flags); - shdr.shdr32.sh_addr = 0; - shdr.shdr32.sh_offset = cpu_to_le32(type == SHT_NULL ? 0 : elf_foffs); - shdr.shdr32.sh_size = cpu_to_le32(datalen); + if (!efmt->elf64) { + Elf32_Shdr shdr; + + shdr.sh_name = cpu_to_le32(name); + shdr.sh_type = cpu_to_le32(type); + shdr.sh_flags = cpu_to_le32(flags); + shdr.sh_addr = 0; + shdr.sh_offset = cpu_to_le32(type == SHT_NULL ? 0 : elf_foffs); + shdr.sh_size = cpu_to_le32(datalen); if (data) elf_foffs += ALIGN(datalen, SEC_FILEALIGN); - shdr.shdr32.sh_link = cpu_to_le32(link); - shdr.shdr32.sh_info = cpu_to_le32(info); - shdr.shdr32.sh_addralign = cpu_to_le32(align); - shdr.shdr32.sh_entsize = cpu_to_le32(entsize); - } else { - nasm_assert(is_elf64()); + shdr.sh_link = cpu_to_le32(link); + shdr.sh_info = cpu_to_le32(info); + shdr.sh_addralign = cpu_to_le32(align); + shdr.sh_entsize = cpu_to_le32(entsize); - shdr.shdr64.sh_name = cpu_to_le32(name); - shdr.shdr64.sh_type = cpu_to_le32(type); - shdr.shdr64.sh_flags = cpu_to_le64(flags); - shdr.shdr64.sh_addr = 0; - shdr.shdr64.sh_offset = cpu_to_le64(type == SHT_NULL ? 0 : elf_foffs); - shdr.shdr64.sh_size = cpu_to_le32(datalen); + nasm_write(&shdr, sizeof shdr, ofile); + } else { + Elf64_Shdr shdr; + + shdr.sh_name = cpu_to_le32(name); + shdr.sh_type = cpu_to_le32(type); + shdr.sh_flags = cpu_to_le64(flags); + shdr.sh_addr = 0; + shdr.sh_offset = cpu_to_le64(type == SHT_NULL ? 0 : elf_foffs); + shdr.sh_size = cpu_to_le64(datalen); if (data) elf_foffs += ALIGN(datalen, SEC_FILEALIGN); - shdr.shdr64.sh_link = cpu_to_le32(link); - shdr.shdr64.sh_info = cpu_to_le32(info); - shdr.shdr64.sh_addralign = cpu_to_le64(align); - shdr.shdr64.sh_entsize = cpu_to_le64(entsize); - } + shdr.sh_link = cpu_to_le32(link); + shdr.sh_info = cpu_to_le32(info); + shdr.sh_addralign = cpu_to_le64(align); + shdr.sh_entsize = cpu_to_le64(entsize); - nasm_write(&shdr, is_elf64() ? sizeof(shdr.shdr64) : sizeof(shdr.shdr32), ofile); + nasm_write(&shdr, sizeof shdr, ofile); + } } static void elf_write_sections(void) @@ -2306,15 +2304,9 @@ static void elf_sect_writeaddr(struct elf_section *sect, int64_t data, size_t le static void elf_sectalign(int32_t seg, unsigned int value) { - struct elf_section *s = NULL; - int i; + struct elf_section *s; - for (i = 0; i < nsects; i++) { - if (sects[i]->index == seg) { - s = sects[i]; - break; - } - } + s = raa_read_ptr(section_by_index, seg >> 1); if (!s || !is_power2(value)) return; @@ -2375,7 +2367,7 @@ const struct ofmt of_elf32 = { elf32_debugs_arr, &elf32_df_stabs, elf_stdmac, - elf_init, + elf32_init, null_reset, nasm_do_legacy_output, elf32_out, @@ -2427,7 +2419,7 @@ const struct ofmt of_elf64 = { elf64_debugs_arr, &elf64_df_stabs, elf_stdmac, - elf_init, + elf64_init, null_reset, nasm_do_legacy_output, elf64_out, @@ -2479,7 +2471,7 @@ const struct ofmt of_elfx32 = { elfx32_debugs_arr, &elfx32_df_stabs, elf_stdmac, - elf_init, + elfx32_init, null_reset, nasm_do_legacy_output, elfx32_out, diff --git a/output/outelf.h b/output/outelf.h index 3c4a40c0..d499117c 100644 --- a/output/outelf.h +++ b/output/outelf.h @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2019 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -63,21 +63,13 @@ struct elf_known_section { extern const struct elf_known_section elf_known_sections[]; /* - * Special ELF sections (after the real sections but before debugging ones) - */ -#define sec_shstrtab (nsects + 1) -#define sec_symtab (nsects + 2) -#define sec_strtab (nsects + 3) -#define sec_numspecial 3 - -/* - * Debugging ELF sections (last in the file) + * Debugging ELF sections (section indicies starting with sec_debug) */ /* stabs */ -#define sec_stab (nsections-3) -#define sec_stabstr (nsections-2) -#define sec_rel_stab (nsections-1) +#define sec_stab (sec_debug + 0) +#define sec_stabstr (sec_debug + 1) +#define sec_rel_stab (sec_debug + 2) /* stabs symbol table format */ struct stabentry { @@ -89,16 +81,16 @@ struct stabentry { }; /* dwarf */ -#define sec_debug_aranges (nsections-10) -#define sec_rela_debug_aranges (nsections-9) -#define sec_debug_pubnames (nsections-8) -#define sec_debug_info (nsections-7) -#define sec_rela_debug_info (nsections-6) -#define sec_debug_abbrev (nsections-5) -#define sec_debug_line (nsections-4) -#define sec_rela_debug_line (nsections-3) -#define sec_debug_frame (nsections-2) -#define sec_debug_loc (nsections-1) +#define sec_debug_aranges (sec_debug + 0) +#define sec_rela_debug_aranges (sec_debug + 1) +#define sec_debug_pubnames (sec_debug + 2) +#define sec_debug_info (sec_debug + 3) +#define sec_rela_debug_info (sec_debug + 4) +#define sec_debug_abbrev (sec_debug + 5) +#define sec_debug_line (sec_debug + 6) +#define sec_rela_debug_line (sec_debug + 7) +#define sec_debug_frame (sec_debug + 8) +#define sec_debug_loc (sec_debug + 9) extern uint8_t elf_osabi; extern uint8_t elf_abiver; @@ -137,15 +129,14 @@ struct elf_section { uint64_t len; uint64_t size; uint64_t nrelocs; - int32_t index; /* NASM index */ + int32_t index; /* NASM index or NO_SEG if internal */ int shndx; /* ELF index */ - int type; /* SHT_PROGBITS or SHT_NOBITS */ + int type; /* SHT_* */ uint64_t align; /* alignment: power of two */ uint64_t flags; /* section flags */ uint64_t entsize; /* entry size */ char *name; struct SAA *rel; - uint64_t rellen; struct elf_reloc *head; struct elf_reloc **tail; struct rbtree *gsyms; /* global symbols in section */ diff --git a/test/fewsecs.asm b/test/fewsecs.asm new file mode 100644 index 00000000..85731acf --- /dev/null +++ b/test/fewsecs.asm @@ -0,0 +1,2 @@ +%assign NSECS 64 +%include "manysecs.asm" diff --git a/test/manysecs.asm b/test/manysecs.asm index c65c6091..49799453 100644 --- a/test/manysecs.asm +++ b/test/manysecs.asm @@ -1,6 +1,15 @@ +%ifndef NSECS + %assign NSECS 16384 +%endif + +%assign NSECS ((NSECS+3) & ~3) + %assign n 0 -%rep 10000 +%rep NSECS + %assign gcom (n & ~3) + 2 section .text %+ n progbits exec +start_ %+ n: nop -%assign n n+1 + jmp start_ %+ gcom + %assign n n+1 %endrep diff --git a/test/moresecs.asm b/test/moresecs.asm new file mode 100644 index 00000000..78d9887b --- /dev/null +++ b/test/moresecs.asm @@ -0,0 +1,3 @@ +; Less than 65,279 data sections, but more total sections +%assign NSECS 37600 +%include "manysecs.asm" diff --git a/test/mostsecs.asm b/test/mostsecs.asm new file mode 100644 index 00000000..0b91816a --- /dev/null +++ b/test/mostsecs.asm @@ -0,0 +1,3 @@ +; More than 65,279 data sections +%assign NSECS 131072 +%include "manysecs.asm" |