aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2019-02-26 00:02:35 -0800
committerH. Peter Anvin <hpa@zytor.com>2019-02-26 00:02:35 -0800
commitb2004511dddeefd7c0866a33ceaa5fa1a6ee0510 (patch)
treebe9d710d81f6c985541f79a44919d8830bb04eab
parent437e0ffa01505d173a8b9cfe2decf74f2e9795a5 (diff)
downloadnasm-b2004511dddeefd7c0866a33ceaa5fa1a6ee0510.tar.gz
nasm-b2004511dddeefd7c0866a33ceaa5fa1a6ee0510.tar.xz
nasm-b2004511dddeefd7c0866a33ceaa5fa1a6ee0510.zip
ELF: handle more than 32,633 sections
Dead code elimination in ELF uses separate ELF sections for every functions or data items that may be garbage collected. This can end up being more than 32,633 sections which, when the ELF internal and relocation sections are added in, can exceed the legacy ELF maximum of 65,279 sections. Newer versions of the ELF specification has added support for much larger number of sections by putting a place holder value (usually SHN_XINDEX == 0xffff, but 0 in some cases) into fields where the section index is a 16-bit value, and storing the full value in a diffent place: the program header uses entries in section header 0, the symbol table uses an auxiliary segment with the additional indicies; the section header did not need it as the sh_link field is already 32 (or 64) bits long. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-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"