aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-12-30 07:54:48 -0800
committerH. Peter Anvin <hpa@zytor.com>2018-12-30 07:54:48 -0800
commit88477764f37a8462c7c01f2b235ef4efd08c765f (patch)
tree620ce28ac140331c6a3f6e7c4bb92400a8a080db
parent81f98fe79be23174e2d6ddd9f17a5cfb9ca71ec7 (diff)
downloadnasm-88477764f37a8462c7c01f2b235ef4efd08c765f.tar.gz
nasm-88477764f37a8462c7c01f2b235ef4efd08c765f.tar.xz
nasm-88477764f37a8462c7c01f2b235ef4efd08c765f.zip
ELF: add support for the ELF "merge" attribute
Add support for the "merge" attribute in ELF, along with the associated "strings" and size specifier attributes. Fix a few places where we used "int", but a larger type really ought to have been used. Be a bit more lax about respecifying attributes. For example, align= can be respecified; the highest resulting value is used. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--doc/changes.src3
-rw-r--r--doc/nasmdoc.src25
-rw-r--r--output/outelf.c147
-rw-r--r--output/outelf.h1
4 files changed, 142 insertions, 34 deletions
diff --git a/doc/changes.src b/doc/changes.src
index a4df0473..6fd19943 100644
--- a/doc/changes.src
+++ b/doc/changes.src
@@ -12,6 +12,9 @@ since 2007.
\b Suppress nuisance "\c{label changed during code generation}" messages
after a real error.
+\b Add support for the \c{merge} and \c{strings} attributes on ELF
+sections. See \k{elfsect}.
+
\S{cl-2.14.02} Version 2.14.02
\b Fix crash due to multiple errors or warnings during the code
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index ea6f10f2..bcfcad90 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -256,9 +256,12 @@ Object File Format
\IA{sectalign}{sectalign}
\IR{solaris x86} Solaris x86
\IA{standard section names}{standardized section names}
+\IR{strings, elf attribute} \c{strings}
\IR{symbols, exporting from dlls} symbols, exporting from DLLs
\IR{symbols, importing from dlls} symbols, importing from DLLs
\IR{test subdirectory} \c{test} subdirectory
+\IR{thread local storage in elf} thread local storage, in \c{elf}
+\IR{thread local storage in mach-o} thread local storage, in \c{macho}
\IR{tlink} \c{TLINK}
\IR{underscore, in c symbols} underscore, in C symbols
\IR{unicode} Unicode
@@ -5951,6 +5954,26 @@ contents given, such as a BSS section.
\I{section alignment, in elf}\I{alignment, in elf sections}alignment
requirements of the section.
+\b \c{ent=} or \c{entsize=} specifies the fundamental data item size
+for a section which contains either fixed-sized data structures or
+strings; this is generally used with the \c{merge} attribute (see
+below.)
+
+\b \c{byte}, \c{word}, \c{dword}, \c{qword}, \c{tword}, \c{oword},
+\c{yword}, or \c{zword} are both shorthand for \c{entsize=}, but also
+sets the default alignment.
+
+\b \i{strings, ELF attribute}\c{strings} indicate that this section
+contains exclusively null-terminated strings. By default these are
+assumed to be byte strings, but a size specifier can be used to
+override that.
+
+\b \i\c{merge} indicates that duplicate data elements in this section
+should be merged with data elements from other object files. Data
+elements can be either fixed-sized objects or null-terminatedstrings
+(with the \c{strings} attribute.) A size specifier is required unless
+\c{strings} is specified, in which case the size defaults to \c{byte}.
+
\b \i\c{tls} defines the section to be one which contains
thread local variables.
@@ -8213,7 +8236,7 @@ then the correct first instruction in the code section will not be
seen because the starting point skipped over it. This isn't really
ideal.
-To avoid this, you can specify a `\i\c{synchronisation}' point, or indeed
+To avoid this, you can specify a `\i{synchronisation}' point, or indeed
as many synchronisation points as you like (although NDISASM can
only handle 2147483647 sync points internally). The definition of a sync
point is this: NDISASM guarantees to hit sync points exactly during
diff --git a/output/outelf.c b/output/outelf.c
index de99d076..c0d19e8b 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
- *
- * Copyright 1996-2017 The NASM Authors - All Rights Reserved
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -14,7 +14,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -97,8 +97,10 @@ static int64_t elf_foffs;
static void elf_write(void);
static void elf_sect_write(struct elf_section *, const void *, size_t);
static void elf_sect_writeaddr(struct elf_section *, int64_t, size_t);
-static void elf_section_header(int, int, uint64_t, void *, bool, uint64_t, int, int,
- int, int);
+static void elf_section_header(int name, int type, uint64_t flags,
+ void *data, bool is_saa, uint64_t datalen,
+ 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 *);
@@ -211,9 +213,11 @@ const struct elf_known_section elf_known_sections[] = {
/* parse section attributes */
static void elf_section_attrib(char *name, char *attr, int pass,
uint32_t *flags_and, uint32_t *flags_or,
- uint64_t *align, int *type)
+ uint64_t *alignp, uint64_t *entsize, int *type)
{
char *opt, *val, *next;
+ uint64_t align = 0;
+ uint64_t xalign = 0;
opt = nasm_skip_spaces(attr);
if (!opt || !*opt)
@@ -225,14 +229,14 @@ static void elf_section_attrib(char *name, char *attr, int pass,
nasm_error(ERR_NONFATAL,
"section align without value specified");
} else {
- *align = atoi(val);
- if (*align == 0) {
- *align = SHA_ANY;
- } else if (!is_power2(*align)) {
+ bool err;
+ uint64_t a = readnum(val, &err);
+ if (a && !is_power2(a)) {
nasm_error(ERR_NONFATAL,
"section alignment %"PRId64" is not a power of two",
- *align);
- *align = SHA_ANY;
+ a);
+ } else if (a > align) {
+ align = a;
}
}
} else if (!nasm_stricmp(opt, "alloc")) {
@@ -250,16 +254,64 @@ static void elf_section_attrib(char *name, char *attr, int pass,
} else if (!nasm_stricmp(opt, "write")) {
*flags_and |= SHF_WRITE;
*flags_or |= SHF_WRITE;
- } else if (!nasm_stricmp(opt, "tls")) {
- *flags_and |= SHF_TLS;
- *flags_or |= SHF_TLS;
} else if (!nasm_stricmp(opt, "nowrite")) {
*flags_and |= SHF_WRITE;
*flags_or &= ~SHF_WRITE;
+ } else if (!nasm_stricmp(opt, "tls")) {
+ *flags_and |= SHF_TLS;
+ *flags_or |= SHF_TLS;
+ } else if (!nasm_stricmp(opt, "notls")) {
+ *flags_and |= SHF_TLS;
+ *flags_or &= ~SHF_TLS;
+ } else if (!nasm_stricmp(opt, "merge")) {
+ *flags_and |= SHF_MERGE;
+ *flags_or |= SHF_MERGE;
+ } else if (!nasm_stricmp(opt, "nomerge")) {
+ *flags_and |= SHF_MERGE;
+ *flags_or &= ~SHF_MERGE;
+ } else if (!nasm_stricmp(opt, "strings")) {
+ *flags_and |= SHF_STRINGS;
+ *flags_or |= SHF_STRINGS;
+ } else if (!nasm_stricmp(opt, "nostrings")) {
+ *flags_and |= SHF_STRINGS;
+ *flags_or &= ~SHF_STRINGS;
} else if (!nasm_stricmp(opt, "progbits")) {
*type = SHT_PROGBITS;
} else if (!nasm_stricmp(opt, "nobits")) {
*type = SHT_NOBITS;
+ } else if (!nasm_stricmp(opt, "ent") || !nasm_stricmp(opt,"entsize")) {
+ bool err;
+ uint64_t es;
+ if (!val) {
+ nasm_error(ERR_NONFATAL,
+ "section attribute %s without value specified", opt);
+ } else {
+ es = readnum(val, &err);
+ if (err) {
+ nasm_error(ERR_NONFATAL,
+ "invalid value %s for section attribute %s",
+ val, opt);
+ } else {
+ *entsize = es;
+ }
+ }
+ } else if (!nasm_stricmp(opt, "byte")) {
+ xalign = *entsize = 1;
+ } else if (!nasm_stricmp(opt, "word")) {
+ xalign = *entsize = 2;
+ } else if (!nasm_stricmp(opt, "dword")) {
+ xalign = *entsize = 4;
+ } else if (!nasm_stricmp(opt, "qword")) {
+ xalign = *entsize = 8;
+ } else if (!nasm_stricmp(opt, "tword")) {
+ *entsize = 10;
+ xalign = 2;
+ } else if (!nasm_stricmp(opt, "oword")) {
+ xalign = *entsize = 16;
+ } else if (!nasm_stricmp(opt, "yword")) {
+ xalign = *entsize = 32;
+ } else if (!nasm_stricmp(opt, "zword")) {
+ xalign = *entsize = 64;
} else if (pass == 1) {
nasm_error(ERR_WARNING,
"Unknown section attribute '%s' ignored on"
@@ -267,6 +319,14 @@ static void elf_section_attrib(char *name, char *attr, int pass,
}
opt = next;
}
+
+ if (!align)
+ align = xalign;
+
+ if (!align)
+ align = SHA_ANY;
+
+ *alignp = align;
}
static enum directive_result
@@ -389,7 +449,7 @@ static void add_sectname(const char *firsthalf, const char *secondhalf)
shstrtablen += len + 1;
}
-static int elf_make_section(char *name, int type, int flags, int align)
+static int elf_make_section(char *name, int type, int flags, uint64_t align)
{
struct elf_section *s;
@@ -420,7 +480,8 @@ static int32_t elf_section_names(char *name, int pass, int *bits)
{
char *p;
uint32_t flags, flags_and, flags_or;
- uint64_t align;
+ uint64_t align, entsize;
+ struct elf_section *s;
int type, i;
if (!name) {
@@ -431,10 +492,10 @@ static int32_t elf_section_names(char *name, int pass, int *bits)
p = nasm_skip_word(name);
if (*p)
*p++ = '\0';
- flags_and = flags_or = type = align = 0;
+ flags_and = flags_or = type = align = entsize = 0;
elf_section_attrib(name, p, pass, &flags_and,
- &flags_or, &align, &type);
+ &flags_or, &align, &entsize, &type);
if (!strcmp(name, ".shstrtab") ||
!strcmp(name, ".symtab") ||
@@ -461,15 +522,34 @@ static int32_t elf_section_names(char *name, int pass, int *bits)
flags = (ks->flags & ~flags_and) | flags_or;
i = elf_make_section(name, type, flags, align);
- } else if (pass == 1) {
- if ((type && sects[i]->type != type)
- || (align && sects[i]->align != align)
- || (flags_and && ((sects[i]->flags & flags_and) != flags_or)))
- nasm_error(ERR_WARNING, "incompatible section attributes ignored on"
- " redeclaration of section `%s'", name);
}
- return sects[i]->index;
+ s = sects[i];
+
+ if (pass == 1) {
+ if ((type && s->type != type)
+ || ((s->flags & flags_and) != flags_or)
+ || (entsize && s->entsize && entsize != s->entsize)) {
+ nasm_error(ERR_WARNING,
+ "incompatible section attributes ignored on"
+ " redeclaration of section `%s'", name);
+ }
+ }
+
+ if (align > s->align)
+ s->align = align;
+
+ if (entsize && !s->entsize)
+ s->entsize = entsize;
+
+ if (pass == 2 && (flags_or & SHF_MERGE) && s->entsize == 0) {
+ if (!(s->flags & SHF_STRINGS))
+ nasm_error(ERR_NONFATAL,
+ "section attribute merge specified without an entry size");
+ s->entsize = 1;
+ }
+
+ return s->index;
}
static void elf_deflabel(char *name, int32_t segment, int64_t offset,
@@ -868,7 +948,7 @@ static void elf32_out(int32_t segto, const void *data,
" segment base references");
} else {
if (wrt == NO_SEG) {
- /*
+ /*
* The if() is a hack to deal with compilers which
* don't handle switch() statements with 64-bit
* expressions.
@@ -1693,9 +1773,9 @@ static void elf_write(void)
/* The normal sections */
for (i = 0; i < nsects; i++) {
elf_section_header(p - shstrtab, sects[i]->type, sects[i]->flags,
- (sects[i]->type == SHT_PROGBITS ?
- sects[i]->data : NULL), true,
- sects[i]->len, 0, 0, sects[i]->align, 0);
+ sects[i]->data, true,
+ sects[i]->len, 0, 0,
+ sects[i]->align, sects[i]->entsize);
p += strlen(p) + 1;
}
@@ -2129,7 +2209,8 @@ static struct SAA *elf_build_reltab(uint64_t *len, struct elf_reloc *r)
static void elf_section_header(int name, int type, uint64_t flags,
void *data, bool is_saa, uint64_t datalen,
- int link, int info, int align, int eltsize)
+ int link, int info,
+ uint64_t align, uint64_t entsize)
{
union {
Elf32_Shdr shdr32;
@@ -2153,7 +2234,7 @@ static void elf_section_header(int name, int type, uint64_t flags,
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(eltsize);
+ shdr.shdr32.sh_entsize = cpu_to_le32(entsize);
} else {
nasm_assert(is_elf64());
@@ -2168,7 +2249,7 @@ static void elf_section_header(int name, int type, uint64_t flags,
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(eltsize);
+ shdr.shdr64.sh_entsize = cpu_to_le64(entsize);
}
nasm_write(&shdr, is_elf64() ? sizeof(shdr.shdr64) : sizeof(shdr.shdr32), ofile);
diff --git a/output/outelf.h b/output/outelf.h
index 8eef73ae..59d8d929 100644
--- a/output/outelf.h
+++ b/output/outelf.h
@@ -141,6 +141,7 @@ struct elf_section {
int type; /* SHT_PROGBITS or SHT_NOBITS */
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;