From: nasm-bot f. C. G. <gor...@gm...> - 2016-04-24 18:00:52
|
Commit-ID: 4670887c4db772d2d44889fbc4509b3fb65b311f Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=4670887c4db772d2d44889fbc4509b3fb65b311f Author: Cyrill Gorcunov <gor...@gm...> AuthorDate: Sun, 10 Apr 2016 17:37:11 +0300 Committer: Cyrill Gorcunov <gor...@gm...> CommitDate: Sun, 24 Apr 2016 20:02:41 +0300 out: Elf -- Merge Elf32, Elfx32 and Elf64 into single file There is a bunch of common code here so merge them all into one file. Unmergable parts are wrapped with is_elf() helpers. Signed-off-by: Cyrill Gorcunov <gor...@gm...> --- Makefile.in | 19 +- Mkfiles/msvc.mak | 16 +- Mkfiles/netware.mak | 16 +- Mkfiles/openwcom.mak | 19 +- Mkfiles/owlinux.mak | 16 +- output/outelf.c | 3154 +++++++++++++++++++++++++++++++++++++++++++++++++- output/outelf32.c | 2066 --------------------------------- output/outelf64.c | 2141 ---------------------------------- output/outelfx32.c | 2100 --------------------------------- 9 files changed, 3163 insertions(+), 6384 deletions(-) diff --git a/Makefile.in b/Makefile.in index 06face8..feff0c6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,8 +87,7 @@ NASM = nasm.$(O) \ output/outform.$(O) output/outlib.$(O) output/nulldbg.$(O) \ output/nullout.$(O) \ output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) \ - output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \ - output/outelfx32.$(O) \ + output/outelf.$(O) \ output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \ output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \ output/codeview.$(O) \ @@ -412,21 +411,7 @@ output/outcoff.$(O): output/outcoff.c compiler.h config.h directiv.h eval.h \ output/outdbg.$(O): output/outdbg.c compiler.h config.h directiv.h insnsi.h \ nasm.h nasmint.h nasmlib.h opflags.h output/outform.h pptok.h preproc.h \ regs.h tables.h -output/outelf.$(O): output/outelf.c compiler.h config.h directiv.h insnsi.h \ - nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ - output/outelf.h output/outform.h pptok.h preproc.h rbtree.h regs.h saa.h \ - tables.h -output/outelf32.$(O): output/outelf32.c compiler.h config.h directiv.h \ - eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h \ - output/elf.h output/outelf.h output/outform.h output/outlib.h \ - output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h \ - tables.h ver.h -output/outelf64.$(O): output/outelf64.c compiler.h config.h directiv.h \ - eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h \ - output/elf.h output/outelf.h output/outform.h output/outlib.h \ - output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h \ - tables.h ver.h -output/outelfx32.$(O): output/outelfx32.c compiler.h config.h directiv.h \ +output/outelf.$(O): output/outelf.c compiler.h config.h directiv.h \ eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h \ output/elf.h output/outelf.h output/outform.h output/outlib.h \ output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h \ diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak index ecd6c4b..52a0d59 100644 --- a/Mkfiles/msvc.mak +++ b/Mkfiles/msvc.mak @@ -57,8 +57,7 @@ NASM = nasm.$(O) \ output/outform.$(O) output/outlib.$(O) output/nulldbg.$(O) \ output/nullout.$(O) \ output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) \ - output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \ - output/outelfx32.$(O) \ + output/outelf.$(O) \ output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \ output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \ output/codeview.$(O) \ @@ -325,18 +324,7 @@ output/outcoff.$(O): output/outcoff.c compiler.h directiv.h eval.h insnsi.h \ output/outdbg.$(O): output/outdbg.c compiler.h directiv.h insnsi.h nasm.h \ nasmint.h nasmlib.h opflags.h output/outform.h pptok.h preproc.h regs.h \ tables.h -output/outelf.$(O): output/outelf.c compiler.h directiv.h insnsi.h nasm.h \ - nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h output/outelf.h \ - output/outform.h pptok.h preproc.h rbtree.h regs.h saa.h tables.h -output/outelf32.$(O): output/outelf32.c compiler.h directiv.h eval.h \ - insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ - output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ - preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h -output/outelf64.$(O): output/outelf64.c compiler.h directiv.h eval.h \ - insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ - output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ - preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h -output/outelfx32.$(O): output/outelfx32.c compiler.h directiv.h eval.h \ +output/outelf.$(O): output/outelf.c compiler.h directiv.h eval.h \ insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h diff --git a/Mkfiles/netware.mak b/Mkfiles/netware.mak index 45728a2..7cf5cc3 100644 --- a/Mkfiles/netware.mak +++ b/Mkfiles/netware.mak @@ -38,8 +38,7 @@ NASM = nasm.o \ outform.o outlib.o nulldbg.o \ nullout.o \ outbin.o outaout.o outcoff.o \ - outelf.o outelf32.o outelf64.o \ - outelfx32.o \ + outelf.o \ outobj.o outas86.o outrdf2.o \ outdbg.o outieee.o outmacho.o \ codeview.o \ @@ -209,21 +208,10 @@ outcoff.o: outcoff.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \ raa.h regs.h saa.h tables.h outdbg.o: outdbg.c compiler.h config.h directiv.h insnsi.h nasm.h nasmint.h \ nasmlib.h opflags.h outform.h pptok.h preproc.h regs.h tables.h -outelf.o: outelf.c compiler.h config.h directiv.h insnsi.h nasm.h nasmint.h \ - nasmlib.h opflags.h dwarf.h elf.h outelf.h outform.h pptok.h preproc.h \ - rbtree.h regs.h saa.h tables.h -outelf32.o: outelf32.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \ +outelf.o: outelf.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \ nasmint.h nasmlib.h opflags.h dwarf.h elf.h outelf.h outform.h outlib.h \ stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h \ ver.h -outelf64.o: outelf64.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \ - nasmint.h nasmlib.h opflags.h dwarf.h elf.h outelf.h outform.h outlib.h \ - stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h \ - ver.h -outelfx32.o: outelfx32.c compiler.h config.h directiv.h eval.h insnsi.h \ - nasm.h nasmint.h nasmlib.h opflags.h dwarf.h elf.h outelf.h outform.h \ - outlib.h stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h \ - tables.h ver.h outform.o: outform.c compiler.h config.h directiv.h insnsi.h nasm.h \ nasmint.h nasmlib.h opflags.h outform.h pptok.h preproc.h regs.h tables.h outieee.o: outieee.c compiler.h config.h directiv.h insnsi.h nasm.h \ diff --git a/Mkfiles/openwcom.mak b/Mkfiles/openwcom.mak index 4382536..9eda33e 100644 --- a/Mkfiles/openwcom.mak +++ b/Mkfiles/openwcom.mak @@ -54,8 +54,7 @@ NASM = nasm.$(O) & output/outform.$(O) output/outlib.$(O) output/nulldbg.$(O) & output/nullout.$(O) & output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) & - output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) & - output/outelfx32.$(O) & + output/outelf.$(O) & output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) & output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) & output/codeview.$(O) & @@ -353,21 +352,7 @@ output/outcoff.$(O): output/outcoff.c compiler.h config.h directiv.h eval.h & output/outdbg.$(O): output/outdbg.c compiler.h config.h directiv.h insnsi.h & nasm.h nasmint.h nasmlib.h opflags.h output/outform.h pptok.h preproc.h & regs.h tables.h -output/outelf.$(O): output/outelf.c compiler.h config.h directiv.h insnsi.h & - nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h & - output/outelf.h output/outform.h pptok.h preproc.h rbtree.h regs.h saa.h & - tables.h -output/outelf32.$(O): output/outelf32.c compiler.h config.h directiv.h & - eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h & - output/elf.h output/outelf.h output/outform.h output/outlib.h & - output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h & - tables.h ver.h -output/outelf64.$(O): output/outelf64.c compiler.h config.h directiv.h & - eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h & - output/elf.h output/outelf.h output/outform.h output/outlib.h & - output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h & - tables.h ver.h -output/outelfx32.$(O): output/outelfx32.c compiler.h config.h directiv.h & +output/outelf.$(O): output/outelf.c compiler.h config.h directiv.h & eval.h insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h & output/elf.h output/outelf.h output/outform.h output/outlib.h & output/stabs.h pptok.h preproc.h raa.h rbtree.h regs.h saa.h stdscan.h & diff --git a/Mkfiles/owlinux.mak b/Mkfiles/owlinux.mak index 3949481..312812e 100644 --- a/Mkfiles/owlinux.mak +++ b/Mkfiles/owlinux.mak @@ -65,8 +65,7 @@ NASM = nasm.$(O) \ output/outform.$(O) output/outlib.$(O) output/nulldbg.$(O) \ output/nullout.$(O) \ output/outbin.$(O) output/outaout.$(O) output/outcoff.$(O) \ - output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \ - output/outelfx32.$(O) \ + output/outelf.$(O) \ output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \ output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \ output/codeview.$(O) \ @@ -317,18 +316,7 @@ output/outcoff.$(O): output/outcoff.c compiler.h directiv.h eval.h insnsi.h \ output/outdbg.$(O): output/outdbg.c compiler.h directiv.h insnsi.h nasm.h \ nasmint.h nasmlib.h opflags.h output/outform.h pptok.h preproc.h regs.h \ tables.h -output/outelf.$(O): output/outelf.c compiler.h directiv.h insnsi.h nasm.h \ - nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h output/outelf.h \ - output/outform.h pptok.h preproc.h rbtree.h regs.h saa.h tables.h -output/outelf32.$(O): output/outelf32.c compiler.h directiv.h eval.h \ - insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ - output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ - preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h -output/outelf64.$(O): output/outelf64.c compiler.h directiv.h eval.h \ - insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ - output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ - preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h -output/outelfx32.$(O): output/outelfx32.c compiler.h directiv.h eval.h \ +output/outelf.$(O): output/outelf.c compiler.h directiv.h eval.h \ insnsi.h nasm.h nasmint.h nasmlib.h opflags.h output/dwarf.h output/elf.h \ output/outelf.h output/outform.h output/outlib.h output/stabs.h pptok.h \ preproc.h raa.h rbtree.h regs.h saa.h stdscan.h tables.h ver.h diff --git a/output/outelf.c b/output/outelf.c index 59c4f50..72eb7ea 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -41,14 +41,154 @@ #include <stdlib.h> #include "nasm.h" +#include "nasmlib.h" +#include "saa.h" +#include "raa.h" +#include "stdscan.h" +#include "eval.h" #include "output/outform.h" +#include "output/outlib.h" +#include "rbtree.h" +#include "ver.h" #include "output/dwarf.h" -#include "output/elf.h" +#include "output/stabs.h" #include "output/outelf.h" +#include "output/elf.h" #if defined(OF_ELF32) || defined(OF_ELF64) || defined(OF_ELFX32) +#define SECT_DELTA 32 +static struct elf_section **sects; +static int nsects, sectlen; + +#define SHSTR_DELTA 256 +static char *shstrtab; +static int shstrtablen, shstrtabsize; + +static struct SAA *syms; +static uint32_t nlocals, nglobs, ndebugs; /* Symbol counts */ + +static int32_t def_seg; + +static struct RAA *bsym; + +static struct SAA *strs; +static uint32_t strslen; + +static struct elf_symbol *fwds; + +static char elf_module[FILENAME_MAX]; + +extern const struct ofmt of_elf32; +extern const struct ofmt of_elf64; +extern const struct ofmt of_elfx32; + +static struct ELF_SECTDATA { + void *data; + int64_t len; + bool is_saa; +} *elf_sects; + +static int elf_nsect, nsections; +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_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(char *, char *); + +struct erel { + int offset; + int info; +}; + +struct symlininfo { + int offset; + int section; /* index into sects[] */ + int segto; /* internal section number */ + char *name; /* shallow-copied pointer of section name */ +}; + +struct linelist { + struct linelist *next; + struct linelist *last; + struct symlininfo info; + char *filename; + int line; +}; + +struct sectlist { + struct SAA *psaa; + int section; + int line; + int offset; + int file; + struct sectlist *next; + struct sectlist *last; +}; + +/* common debug variables */ +static int currentline = 1; +static int debug_immcall = 0; + +/* stabs debug variables */ +static struct linelist *stabslines = 0; +static int numlinestabs = 0; +static char *stabs_filename = 0; +static uint8_t *stabbuf = 0, *stabstrbuf = 0, *stabrelbuf = 0; +static int stablen, stabstrlen, stabrellen; + +/* dwarf debug variables */ +static struct linelist *dwarf_flist = 0, *dwarf_clist = 0, *dwarf_elist = 0; +static struct sectlist *dwarf_fsect = 0, *dwarf_csect = 0, *dwarf_esect = 0; +static int dwarf_numfiles = 0, dwarf_nsections; +static uint8_t *arangesbuf = 0, *arangesrelbuf = 0, *pubnamesbuf = 0, *infobuf = 0, *inforelbuf = 0, + *abbrevbuf = 0, *linebuf = 0, *linerelbuf = 0, *framebuf = 0, *locbuf = 0; +static int8_t line_base = -5, line_range = 14, opcode_base = 13; +static int arangeslen, arangesrellen, pubnameslen, infolen, inforellen, + abbrevlen, linelen, linerellen, framelen, loclen; +static int64_t dwarf_infosym, dwarf_abbrevsym, dwarf_linesym; + +static const struct dfmt df_dwarf; +static const struct dfmt df_stabs; +static struct elf_symbol *lastsym; + +/* common debugging routines */ +static void debug_typevalue(int32_t); + +/* stabs debugging routines */ +static void stabs_linenum(const char *filename, int32_t linenumber, int32_t); +static void stabs_output(int, void *); +static void stabs_generate(void); +static void stabs_cleanup(void); + +/* dwarf debugging routines */ +static void dwarf_init(void); +static void dwarf_linenum(const char *filename, int32_t linenumber, int32_t); +static void dwarf_output(int, void *); +static void dwarf_generate(void); +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); + +/* + * Special NASM section numbers which are used to define ELF special + * symbols. + */ +static int32_t elf_gotpc_sect, elf_gotoff_sect; +static int32_t elf_got_sect, elf_plt_sect; +static int32_t elf_sym_sect, elf_gottpoff_sect, elf_tlsie_sect; + uint8_t elf_osabi = 0; /* Default OSABI = 0 (System V or Linux) */ uint8_t elf_abiver = 0; /* Current ABI version */ @@ -170,4 +310,3016 @@ int elf_directive(enum directives directive, char *value, int pass) } } +static void elf_init(void) +{ + sects = NULL; + nsects = sectlen = 0; + syms = saa_init((int32_t)sizeof(struct elf_symbol)); + nlocals = nglobs = ndebugs = 0; + bsym = raa_init(); + strs = saa_init(1L); + saa_wbytes(strs, "\0", 1L); + saa_wbytes(strs, elf_module, strlen(elf_module)+1); + strslen = 2 + strlen(elf_module); + shstrtab = NULL; + shstrtablen = shstrtabsize = 0;; + add_sectname("", ""); + + fwds = NULL; + + /* + * FIXME: tlsie is Elf32 only and + * gottpoff is Elfx32|64 only. + */ + + elf_gotpc_sect = seg_alloc(); + define_label("..gotpc", elf_gotpc_sect + 1, 0L, NULL, false, false); + elf_gotoff_sect = seg_alloc(); + define_label("..gotoff", elf_gotoff_sect + 1, 0L, NULL, false, false); + elf_got_sect = seg_alloc(); + define_label("..got", elf_got_sect + 1, 0L, NULL, false, false); + elf_plt_sect = seg_alloc(); + define_label("..plt", elf_plt_sect + 1, 0L, NULL, false, false); + elf_sym_sect = seg_alloc(); + define_label("..sym", elf_sym_sect + 1, 0L, NULL, false, false); + elf_gottpoff_sect = seg_alloc(); + define_label("..gottpoff", elf_gottpoff_sect + 1, 0L, NULL, false, false); + elf_tlsie_sect = seg_alloc(); + define_label("..tlsie", elf_tlsie_sect + 1, 0L, NULL, false, false); + + def_seg = seg_alloc(); +} + +static void elf_cleanup(void) +{ + struct elf_reloc *r; + int i; + + elf_write(); + for (i = 0; i < nsects; i++) { + if (sects[i]->type != SHT_NOBITS) + saa_free(sects[i]->data); + if (sects[i]->head) + saa_free(sects[i]->rel); + while (sects[i]->head) { + r = sects[i]->head; + sects[i]->head = sects[i]->head->next; + nasm_free(r); + } + } + nasm_free(sects); + saa_free(syms); + raa_free(bsym); + saa_free(strs); + dfmt->cleanup(); +} + +/* add entry to the elf .shstrtab section */ +static void add_sectname(char *firsthalf, char *secondhalf) +{ + int len = strlen(firsthalf) + strlen(secondhalf); + while (shstrtablen + len + 1 > shstrtabsize) + shstrtab = nasm_realloc(shstrtab, (shstrtabsize += SHSTR_DELTA)); + strcpy(shstrtab + shstrtablen, firsthalf); + strcat(shstrtab + shstrtablen, secondhalf); + shstrtablen += len + 1; +} + +static int elf_make_section(char *name, int type, int flags, int align) +{ + struct elf_section *s; + + s = nasm_zalloc(sizeof(*s)); + + if (type != SHT_NOBITS) + s->data = saa_init(1L); + s->tail = &s->head; + if (!strcmp(name, ".text")) + 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; + + if (nsects >= sectlen) + sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects)); + sects[nsects++] = s; + + return nsects - 1; +} + +static int32_t elf_section_names(char *name, int pass, int *bits) +{ + char *p; + uint32_t flags, flags_and, flags_or; + uint64_t align; + int type, i; + + if (!name) { + *bits = ofmt->maxbits; + return def_seg; + } + + p = nasm_skip_word(name); + if (*p) + *p++ = '\0'; + flags_and = flags_or = type = align = 0; + + elf_section_attrib(name, p, pass, &flags_and, + &flags_or, &align, &type); + + if (!strcmp(name, ".shstrtab") || + !strcmp(name, ".symtab") || + !strcmp(name, ".strtab")) { + nasm_error(ERR_NONFATAL, "attempt to redefine reserved section" + "name `%s'", name); + return NO_SEG; + } + + for (i = 0; i < nsects; i++) + if (!strcmp(name, sects[i]->name)) + break; + if (i == nsects) { + const struct elf_known_section *ks = elf_known_sections; + + while (ks->name) { + if (!strcmp(name, ks->name)) + break; + ks++; + } + + type = type ? type : ks->type; + align = align ? align : ks->align; + 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; +} + +static void elf_deflabel(char *name, int32_t segment, int64_t offset, + int is_global, char *special) +{ + int pos = strslen; + struct elf_symbol *sym; + bool special_used = false; + +#if defined(DEBUG) && DEBUG>2 + nasm_error(ERR_DEBUG, + " elf_deflabel: %s, seg=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n", + name, segment, offset, is_global, special); +#endif + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + /* + * This is a NASM special symbol. We never allow it into + * the ELF symbol table, even if it's a valid one. If it + * _isn't_ a valid one, we should barf immediately. + * + * FIXME: tlsie is Elf32 only, and gottpoff is Elfx32|64 only. + */ + if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && + strcmp(name, "..got") && strcmp(name, "..plt") && + strcmp(name, "..sym") && strcmp(name, "..gottpoff") && + strcmp(name, "..tlsie")) + nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + if (is_global == 3) { + struct elf_symbol **s; + /* + * Fix up a forward-reference symbol size from the first + * pass. + */ + for (s = &fwds; *s; s = &(*s)->nextfwd) + if (!strcmp((*s)->name, name)) { + struct tokenval tokval; + expr *e; + char *p = nasm_skip_spaces(nasm_skip_word(special)); + + stdscan_reset(); + stdscan_set(p); + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL); + if (e) { + if (!is_simple(e)) + nasm_error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + (*s)->size = reloc_value(e); + } + + /* + * Remove it from the list of unresolved sizes. + */ + nasm_free((*s)->name); + *s = (*s)->nextfwd; + return; + } + return; /* it wasn't an important one */ + } + + saa_wbytes(strs, name, (int32_t)(1 + strlen(name))); + strslen += 1 + strlen(name); + + lastsym = sym = saa_wstruct(syms); + + memset(&sym->symv, 0, sizeof(struct rbtree)); + + sym->strpos = pos; + sym->type = is_global ? SYM_GLOBAL : SYM_LOCAL; + sym->other = STV_DEFAULT; + sym->size = 0; + if (segment == NO_SEG) + sym->section = SHN_ABS; + else { + int i; + sym->section = SHN_UNDEF; + if (segment == def_seg) { + /* we have to be sure at least text section is there */ + int tempint; + if (segment != elf_section_names(".text", 2, &tempint)) + nasm_panic(0, "strange segment conditions in ELF driver"); + } + for (i = 0; i < nsects; i++) { + if (segment == sects[i]->index) { + sym->section = i + 1; + break; + } + } + } + + if (is_global == 2) { + sym->size = offset; + sym->symv.key = 0; + sym->section = SHN_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 + * as the alignment for the common variable. + */ + if (special) { + bool err; + sym->symv.key = readnum(special, &err); + if (err) + nasm_error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " valid number", special); + else if ((sym->symv.key | (sym->symv.key - 1)) != 2 * sym->symv.key - 1) + nasm_error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " power of two", special); + } + special_used = true; + } else + sym->symv.key = (sym->section == SHN_UNDEF ? 0 : offset); + + if (sym->type == SYM_GLOBAL) { + /* + * If sym->section == SHN_ABS, then the first line of the + * else section would cause a core dump, because its a reference + * beyond the end of the section array. + * This behaviour is exhibited by this code: + * GLOBAL crash_nasm + * crash_nasm equ 0 + * 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) { + bsym = raa_write(bsym, segment, nglobs); + } else if (sym->section != SHN_ABS) { + /* + * This is a global symbol; so we must add it to the rbtree + * of global symbols in its section. + * + * In addition, we check the special text for symbol + * type and size information. + */ + sects[sym->section-1]->gsyms = + rb_insert(sects[sym->section-1]->gsyms, &sym->symv); + + if (special) { + int n = strcspn(special, " \t"); + + if (!nasm_strnicmp(special, "function", n)) + sym->type |= STT_FUNC; + else if (!nasm_strnicmp(special, "data", n) || + !nasm_strnicmp(special, "object", n)) + sym->type |= STT_OBJECT; + else if (!nasm_strnicmp(special, "notype", n)) + sym->type |= STT_NOTYPE; + else + nasm_error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", + n, special); + special += n; + + special = nasm_skip_spaces(special); + if (*special) { + n = strcspn(special, " \t"); + if (!nasm_strnicmp(special, "default", n)) + sym->other = STV_DEFAULT; + else if (!nasm_strnicmp(special, "internal", n)) + sym->other = STV_INTERNAL; + else if (!nasm_strnicmp(special, "hidden", n)) + sym->other = STV_HIDDEN; + else if (!nasm_strnicmp(special, "protected", n)) + sym->other = STV_PROTECTED; + else + n = 0; + special += n; + } + + if (*special) { + struct tokenval tokval; + expr *e; + int fwd = 0; + char *saveme = stdscan_get(); + + while (special[n] && nasm_isspace(special[n])) + n++; + /* + * We have a size expression; attempt to + * evaluate it. + */ + stdscan_reset(); + stdscan_set(special + n); + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, &fwd, 0, NULL); + if (fwd) { + sym->nextfwd = fwds; + fwds = sym; + sym->name = nasm_strdup(name); + } else if (e) { + if (!is_simple(e)) + nasm_error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + sym->size = reloc_value(e); + } + stdscan_set(saveme); + } + special_used = true; + } + /* + * If TLS segment, mark symbol accordingly. + */ + if (sects[sym->section - 1]->flags & SHF_TLS) { + sym->type &= 0xf0; + sym->type |= STT_TLS; + } + } + sym->globnum = nglobs; + nglobs++; + } else + nlocals++; + + if (special && !special_used) + nasm_error(ERR_NONFATAL, "no special symbol features supported here"); +} + +static void elf_add_reloc(struct elf_section *sect, int32_t segment, + int64_t offset, int type) +{ + struct elf_reloc *r; + + r = *sect->tail = nasm_zalloc(sizeof(struct elf_reloc)); + sect->tail = &r->next; + + r->address = sect->len; + 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) + r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); + } + r->type = type; + + sect->nrelocs++; +} + +/* + * This routine deals with ..got and ..sym relocations: the more + * complicated kinds. In shared-library writing, some relocations + * with respect to global symbols must refer to the precise symbol + * rather than referring to an offset from the base of the section + * _containing_ the symbol. Such relocations call to this routine, + * which searches the symbol list for the symbol in question. + * + * R_386_GOT32 | R_X86_64_GOT32 references require the _exact_ symbol address to be + * used; R_386_32 | R_X86_64_32 references can be at an offset from the symbol. + * The boolean argument `exact' tells us this. + * + * Return value is the adjusted value of `addr', having become an + * offset from the symbol rather than the section. Should always be + * zero when returning from an exact call. + * + * Limitation: if you define two symbols at the same place, + * confusion will occur. + * + * Inefficiency: we search, currently, using a linked list which + * isn't even necessarily sorted. + */ +static int64_t elf_add_gsym_reloc(struct elf_section *sect, + int32_t segment, uint64_t offset, + int64_t pcrel, int type, bool exact) +{ + struct elf_reloc *r; + struct elf_section *s; + struct elf_symbol *sym; + struct rbtree *srb; + int i; + + /* + * First look up the segment/offset pair and find a global + * symbol corresponding to it. If it's not one of our segments, + * then it must be an external symbol, in which case we're fine + * 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; + } + + if (!s) { + if (exact && offset) + nasm_error(ERR_NONFATAL, "invalid access to an external symbol"); + else + elf_add_reloc(sect, segment, offset - pcrel, type); + return 0; + } + + srb = rb_search(s->gsyms, offset); + if (!srb || (exact && srb->key != offset)) { + nasm_error(ERR_NONFATAL, "unable to find a suitable global symbol" + " for this reference"); + return 0; + } + sym = container_of(srb, struct elf_symbol, symv); + + r = *sect->tail = nasm_malloc(sizeof(struct elf_reloc)); + sect->tail = &r->next; + + r->next = NULL; + r->address = sect->len; + r->offset = offset - pcrel - sym->symv.key; + r->symbol = GLOBAL_TEMP_BASE + sym->globnum; + r->type = type; + + sect->nrelocs++; + return r->offset; +} + +static void elf32_out(int32_t segto, const void *data, + enum out_type type, uint64_t size, + int32_t segment, int32_t wrt) +{ + struct elf_section *s; + int64_t addr; + int reltype, bytes; + int i; + static struct symlininfo sinfo; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if (type != OUT_RESERVE) + nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + s = NULL; + for (i = 0; i < nsects; i++) + if (segto == sects[i]->index) { + s = sects[i]; + break; + } + if (!s) { + int tempint; /* ignored */ + if (segto != elf_section_names(".text", 2, &tempint)) + nasm_panic(0, "strange segment conditions in ELF driver"); + else { + s = sects[nsects - 1]; + i = nsects - 1; + } + } + + /* again some stabs debugging stuff */ + sinfo.offset = s->len; + sinfo.section = i; + sinfo.segto = segto; + sinfo.name = s->name; + dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); + /* end of debugging stuff */ + + if (s->type == SHT_NOBITS && type != OUT_RESERVE) { + nasm_error(ERR_WARNING, "attempt to initialize memory in" + " BSS section `%s': ignored", s->name); + s->len += realsize(type, size); + return; + } + + switch (type) { + case OUT_RESERVE: + if (s->type == SHT_PROGBITS) { + nasm_error(ERR_WARNING, "uninitialized space declared in" + " non-BSS section `%s': zeroing", s->name); + elf_sect_write(s, NULL, size); + } else + s->len += size; + break; + + case OUT_RAWDATA: + if (segment != NO_SEG) + nasm_panic(0, "OUT_RAWDATA with other than NO_SEG"); + elf_sect_write(s, data, size); + break; + + case OUT_ADDRESS: + { + bool gnu16 = false; + int asize = abs((int)size); + + addr = *(int64_t *)data; + if (segment != NO_SEG) { + if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " 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. + */ + switch (asize) { + case 1: + gnu16 = true; + elf_add_reloc(s, segment, 0, R_386_8); + break; + case 2: + gnu16 = true; + elf_add_reloc(s, segment, 0, R_386_16); + break; + case 4: + elf_add_reloc(s, segment, 0, R_386_32); + break; + default: /* Error issued further down */ + break; + } + } else if (wrt == elf_gotpc_sect + 1) { + /* + * The user will supply GOT relative to $$. ELF + * will let us have GOT relative to $. So we + * need to fix up the data item by $-$$. + */ + addr += s->len; + elf_add_reloc(s, segment, 0, R_386_GOTPC); + } else if (wrt == elf_gotoff_sect + 1) { + elf_add_reloc(s, segment, 0, R_386_GOTOFF); + } else if (wrt == elf_tlsie_sect + 1) { + addr = elf_add_gsym_reloc(s, segment, addr, 0, + R_386_TLS_IE, true); + } else if (wrt == elf_got_sect + 1) { + addr = elf_add_gsym_reloc(s, segment, addr, 0, + R_386_GOT32, true); + } else if (wrt == elf_sym_sect + 1) { + switch (asize) { + case 1: + gnu16 = true; + addr = elf_add_gsym_reloc(s, segment, addr, 0, + R_386_8, false); + break; + case 2: + gnu16 = true; + addr = elf_add_gsym_reloc(s, segment, addr, 0, + R_386_16, false); + break; + case 4: + addr = elf_add_gsym_reloc(s, segment, addr, 0, + R_386_32, false); + break; + default: + break; + } + } else if (wrt == elf_plt_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" + "relative PLT references"); + } else { + nasm_error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + } + + if (gnu16) { + nasm_error(ERR_WARNING | ERR_WARN_GNUELF, + "8- or 16-bit relocations in ELF32 is a GNU extension"); + } else if (asize != 4 && segment != NO_SEG) { + nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); + } + elf_sect_writeaddr(s, addr, asize); + break; + } + + case OUT_REL1ADR: + reltype = R_386_PC8; + bytes = 1; + goto rel12adr; + case OUT_REL2ADR: + reltype = R_386_PC16; + bytes = 2; + goto rel12adr; + +rel12adr: + addr = *(int64_t *)data - size; + nasm_assert(segment != segto); + if (segment != NO_SEG && segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + nasm_error(ERR_WARNING | ERR_WARN_GNUELF, + "8- or 16-bit relocations in ELF is a GNU extension"); + elf_add_reloc(s, segment, 0, reltype); + } else { + nasm_error(ERR_NONFATAL, + "Unsupported non-32-bit ELF relocation"); + } + } + elf_sect_writeaddr(s, addr, bytes); + break; + + case OUT_REL4ADR: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, 0, R_386_PC32); + } else if (wrt == elf_plt_sect + 1) { + elf_add_reloc(s, segment, 0, R_386_PLT32); + } else if (wrt == elf_gotpc_sect + 1 || + wrt == elf_gotoff_sect + 1 || + wrt == elf_got_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF format cannot produce PC-" + "relative GOT references"); + } else { + nasm_error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + elf_sect_writeaddr(s, addr, 4); + break; + + case OUT_REL8ADR: + nasm_error(ERR_NONFATAL, "32-bit ELF format does not support 64-bit relocations"); + addr = 0; + elf_sect_writeaddr(s, addr, 8); + break; + } +} +static void elf64_out(int32_t segto, const void *data, + enum out_type type, uint64_t size, + int32_t segment, int32_t wrt) +{ + struct elf_section *s; + int64_t addr; + int reltype, bytes; + int i; + static struct symlininfo sinfo; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if (type != OUT_RESERVE) + nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + s = NULL; + for (i = 0; i < nsects; i++) + if (segto == sects[i]->index) { + s = sects[i]; + break; + } + if (!s) { + int tempint; /* ignored */ + if (segto != elf_section_names(".text", 2, &tempint)) + nasm_panic(0, "strange segment conditions in ELF driver"); + else { + s = sects[nsects - 1]; + i = nsects - 1; + } + } + + /* again some stabs debugging stuff */ + sinfo.offset = s->len; + sinfo.section = i; + sinfo.segto = segto; + sinfo.name = s->name; + dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); + /* end of debugging stuff */ + + if (s->type == SHT_NOBITS && type != OUT_RESERVE) { + nasm_error(ERR_WARNING, "attempt to initialize memory in" + " BSS section `%s': ignored", s->name); + s->len += realsize(type, size); + return; + } + + switch (type) { + case OUT_RESERVE: + if (s->type == SHT_PROGBITS) { + nasm_error(ERR_WARNING, "uninitialized space declared in" + " non-BSS section `%s': zeroing", s->name); + elf_sect_write(s, NULL, size); + } else + s->len += size; + break; + + case OUT_RAWDATA: + if (segment != NO_SEG) + nasm_panic(0, "OUT_RAWDATA with other than NO_SEG"); + elf_sect_write(s, data, size); + break; + + case OUT_ADDRESS: + { + int isize = (int)size; + int asize = abs((int)size); + + addr = *(int64_t *)data; + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + switch (isize) { + case 1: + case -1: + elf_add_reloc(s, segment, addr, R_X86_64_8); + break; + case 2: + case -2: + elf_add_reloc(s, segment, addr, R_X86_64_16); + break; + case 4: + elf_add_reloc(s, segment, addr, R_X86_64_32); + break; + case -4: + elf_add_reloc(s, segment, addr, R_X86_64_32S); + break; + case 8: + case -8: + elf_add_reloc(s, segment, addr, R_X86_64_64); + break; + default: + nasm_panic(0, "internal error elf64-hpa-871"); + break; + } + addr = 0; + } else if (wrt == elf_gotpc_sect + 1) { + /* + * The user will supply GOT relative to $$. ELF + * will let us have GOT relative to $. So we + * need to fix up the data item by $-$$. + */ + addr += s->len; + elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32); + addr = 0; + } else if (wrt == elf_gotoff_sect + 1) { + if (asize != 8) { + nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff " + "references to be qword"); + } else { + elf_add_reloc(s, segment, addr, R_X86_64_GOTOFF64); + addr = 0; + } + } else if (wrt == elf_got_sect + 1) { + switch (asize) { + case 4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_GOT32, true); + addr = 0; + break; + case 8: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_GOT64, true); + addr = 0; + break; + default: + nasm_error(ERR_NONFATAL, "invalid ..got reference"); + break; + } + } else if (wrt == elf_sym_sect + 1) { + switch (isize) { + case 1: + case -1: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_8, false); + addr = 0; + break; + case 2: + case -2: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_16, false); + addr = 0; + break; + case 4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32, false); + addr = 0; + break; + case -4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32S, false); + addr = 0; + break; + case 8: + case -8: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_64, false); + addr = 0; + break; + default: + nasm_panic(0, "internal error elf64-hpa-903"); + break; + } + } else if (wrt == elf_plt_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" + "relative PLT references"); + } else { + nasm_error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + } + } + elf_sect_writeaddr(s, addr, asize); + break; + } + + case OUT_REL1ADR: + reltype = R_X86_64_PC8; + bytes = 1; + goto rel12adr; + + case OUT_REL2ADR: + reltype = R_X86_64_PC16; + bytes = 2; + goto rel12adr; + +rel12adr: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL1ADR"); + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, addr, reltype); + addr = 0; + } else { + nasm_error(ERR_NONFATAL, + "Unsupported non-32-bit ELF relocation"); + } + } + elf_sect_writeaddr(s, addr, bytes); + break; + + case OUT_REL4ADR: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL4ADR"); + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF64 format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, addr, R_X86_64_PC32); + addr = 0; + } else if (wrt == elf_plt_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_PLT32, true); + addr = 0; + } else if (wrt == elf_gotpc_sect + 1 || + wrt == elf_got_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_GOTPCREL, true); + addr = 0; + } else if (wrt == elf_gotoff_sect + 1 || + wrt == elf_got_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be " + "qword absolute"); + } else if (wrt == elf_gottpoff_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_GOTTPOFF, true); + addr = 0; + } else { + nasm_error(ERR_NONFATAL, "ELF64 format does not support this" + " use of WRT"); + } + } + elf_sect_writeaddr(s, addr, 4); + break; + + case OUT_REL8ADR: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL8ADR"); + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF64 format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, addr, R_X86_64_PC64); + addr = 0; + } else if (wrt == elf_gotpc_sect + 1 || + wrt == elf_got_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_GOTPCREL64, true); + addr = 0; + } else if (wrt == elf_gotoff_sect + 1 || + wrt == elf_got_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be " + "absolute"); + } else if (wrt == elf_gottpoff_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF64 requires ..gottpoff references to be " + "dword"); + } else { + nasm_error(ERR_NONFATAL, "ELF64 format does not support this" + " use of WRT"); + } + } + elf_sect_writeaddr(s, addr, 8); + break; + } +} + +static void elfx32_out(int32_t segto, const void *data, + enum out_type type, uint64_t size, + int32_t segment, int32_t wrt) +{ + struct elf_section *s; + int64_t addr; + int reltype, bytes; + int i; + static struct symlininfo sinfo; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if (type != OUT_RESERVE) + nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + s = NULL; + for (i = 0; i < nsects; i++) + if (segto == sects[i]->index) { + s = sects[i]; + break; + } + if (!s) { + int tempint; /* ignored */ + if (segto != elf_section_names(".text", 2, &tempint)) + nasm_panic(0, "strange segment conditions in ELF driver"); + else { + s = sects[nsects - 1]; + i = nsects - 1; + } + } + + /* again some stabs debugging stuff */ + sinfo.offset = s->len; + sinfo.section = i; + sinfo.segto = segto; + sinfo.name = s->name; + dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo); + /* end of debugging stuff */ + + if (s->type == SHT_NOBITS && type != OUT_RESERVE) { + nasm_error(ERR_WARNING, "attempt to initialize memory in" + " BSS section `%s': ignored", s->name); + s->len += realsize(type, size); + return; + } + + switch (type) { + case OUT_RESERVE: + if (s->type == SHT_PROGBITS) { + nasm_error(ERR_WARNING, "uninitialized space declared in" + " non-BSS section `%s': zeroing", s->name); + elf_sect_write(s, NULL, size); + } else + s->len += size; + break; + + case OUT_RAWDATA: + if (segment != NO_SEG) + nasm_panic(0, "OUT_RAWDATA with other than NO_SEG"); + elf_sect_write(s, data, size); + break; + + case OUT_ADDRESS: + { + int isize = (int)size; + int asize = abs((int)size); + + addr = *(int64_t *)data; + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + switch (isize) { + case 1: + case -1: + elf_add_reloc(s, segment, addr, R_X86_64_8); + break; + case 2: + case -2: + elf_add_reloc(s, segment, addr, R_X86_64_16); + break; + case 4: + elf_add_reloc(s, segment, addr, R_X86_64_32); + break; + case -4: + elf_add_reloc(s, segment, addr, R_X86_64_32S); + break; + case 8: + case -8: + elf_add_reloc(s, segment, addr, R_X86_64_64); + break; + default: + nasm_panic(0, "internal error elfx32-hpa-871"); + break; + } + addr = 0; + } else if (wrt == elf_gotpc_sect + 1) { + /* + * The user will supply GOT relative to $$. ELF + * will let us have GOT relative to $. So we + * need to fix up the data item by $-$$. + */ + addr += s->len; + elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32); + addr = 0; + } else if (wrt == elf_gotoff_sect + 1) { + nasm_error(ERR_NONFATAL, "ELFX32 doesn't support " + "R_X86_64_GOTOFF64"); + } else if (wrt == elf_got_sect + 1) { + switch (asize) { + case 4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_GOT32, true); + addr = 0; + break; + default: + nasm_error(ERR_NONFATAL, "invalid ..got reference"); + break; + } + } else if (wrt == elf_sym_sect + 1) { + switch (isize) { + case 1: + case -1: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_8, false); + addr = 0; + break; + case 2: + case -2: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_16, false); + addr = 0; + break; + case 4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32, false); + addr = 0; + break; + case -4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32S, false); + addr = 0; + break; + case 8: + case -8: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_64, false); + addr = 0; + break; + default: + nasm_panic(0, "internal error elfx32-hpa-903"); + break; + } + } else if (wrt == elf_plt_sect + 1) { + nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" + "relative PLT references"); + } else { + nasm_error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + } + } + elf_sect_writeaddr(s, addr, asize); + break; + } + + case OUT_REL1ADR: + reltype = R_X86_64_PC8; + bytes = 1; + goto rel12adr; + + case OUT_REL2ADR: + reltype = R_X86_64_PC16; + bytes = 2; + goto rel12adr; + +rel12adr: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL1ADR"); + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, addr, reltype); + addr = 0; + } else { + nasm_error(ERR_NONFATAL, + "Unsupported non-32-bit ELF relocation"); + } + } + elf_sect_writeaddr(s, addr, bytes); + break; + + case OUT_REL4ADR: + addr = *(int64_t *)data - size; + if (segment == segto) + nasm_panic(0, "intra-segment OUT_REL4ADR"); + if (segment == NO_SEG) { + /* Do nothing */ + } else if (segment % 2) { + nasm_error(ERR_NONFATAL, "ELFX32 format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, addr, R_X86_64_PC32); + addr = 0; + } else if (wrt == elf_plt_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_PLT32, true); + addr = 0; + } else if (wrt == elf_gotpc_sect + 1 || + wrt == elf_got_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_GOTPCREL, true); + addr = 0; + } else if (wrt == elf_gotoff_sect + 1 || + wrt == elf_got_sect + 1) { + nasm_error(ERR_NONFATAL, "invalid ..gotoff reference"); + } else if (wrt == elf_gottpoff_sect + 1) { + elf_add_gsym_reloc(s, segment, addr+size, size, + R_X86_64_GOTTPOFF, true); + addr = 0; + } else { + nasm_error(ERR_NONFATAL, "ELFX32 format does not support this" + " use of WRT"); + } + } + elf_sect_writeaddr(s, addr, 4); + break; + + case OUT_REL8ADR: + nasm_error(ERR_NONFATAL, "32-bit ELF format does not support 64-bit relocations"); + addr = 0; + elf_sect_writeaddr(s, addr, 8); + break; + } +} + +static void elf_write(void) +{ + int align; + char *p; + int i; + + struct SAA *symtab; + int32_t symtablen, symtablocal; + + /* + * 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. + */ + nsections = sec_numspecial + 1; + if (dfmt == &df_stabs) + nsections += 3; + else if (dfmt == &df_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); + } + } + + if (dfmt == &df_stabs) { + /* in case the debug information is wanted, just add these three sections... */ + add_sectname("", ".stab"); + add_sectname("", ".stabstr"); + add_sectname(".rel", ".stab"); + } else if (dfm... [truncated message content] |