summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/changes.src2
-rw-r--r--output/elf.h19
-rw-r--r--output/outelf.c1038
-rw-r--r--output/outelf.h43
-rw-r--r--test/fewsecs.asm2
-rw-r--r--test/manysecs.asm13
-rw-r--r--test/moresecs.asm3
-rw-r--r--test/mostsecs.asm3
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(&sects[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"