summaryrefslogtreecommitdiff
path: root/vere/ext/nasm/output
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
committerpolwex <polwex@sortug.com>2025-10-05 21:56:51 +0700
commitfcedfddf00b3f994e4f4e40332ac7fc192c63244 (patch)
tree51d38e62c7bdfcc5f9a5e9435fe820c93cfc9a3d /vere/ext/nasm/output
claude is gud
Diffstat (limited to 'vere/ext/nasm/output')
-rw-r--r--vere/ext/nasm/output/codeview.c820
-rw-r--r--vere/ext/nasm/output/dwarf.h621
-rw-r--r--vere/ext/nasm/output/elf.h557
-rw-r--r--vere/ext/nasm/output/legacy.c122
-rw-r--r--vere/ext/nasm/output/macho.h282
-rw-r--r--vere/ext/nasm/output/nulldbg.c96
-rw-r--r--vere/ext/nasm/output/nullout.c60
-rw-r--r--vere/ext/nasm/output/outaout.c923
-rw-r--r--vere/ext/nasm/output/outaout.mac37
-rw-r--r--vere/ext/nasm/output/outas86.c611
-rw-r--r--vere/ext/nasm/output/outas86.mac37
-rw-r--r--vere/ext/nasm/output/outbin.c1669
-rw-r--r--vere/ext/nasm/output/outbin.mac40
-rw-r--r--vere/ext/nasm/output/outcoff.c1436
-rw-r--r--vere/ext/nasm/output/outcoff.mac43
-rw-r--r--vere/ext/nasm/output/outdbg.c576
-rw-r--r--vere/ext/nasm/output/outdbg.mac56
-rw-r--r--vere/ext/nasm/output/outelf.c3672
-rw-r--r--vere/ext/nasm/output/outelf.h133
-rw-r--r--vere/ext/nasm/output/outelf.mac41
-rw-r--r--vere/ext/nasm/output/outform.c135
-rw-r--r--vere/ext/nasm/output/outform.h354
-rw-r--r--vere/ext/nasm/output/outieee.c1521
-rw-r--r--vere/ext/nasm/output/outlib.c324
-rw-r--r--vere/ext/nasm/output/outlib.h313
-rw-r--r--vere/ext/nasm/output/outmacho.c2411
-rw-r--r--vere/ext/nasm/output/outmacho.mac49
-rw-r--r--vere/ext/nasm/output/outobj.c2701
-rw-r--r--vere/ext/nasm/output/outobj.mac49
-rw-r--r--vere/ext/nasm/output/pecoff.h542
-rw-r--r--vere/ext/nasm/output/stabs.h150
31 files changed, 20381 insertions, 0 deletions
diff --git a/vere/ext/nasm/output/codeview.c b/vere/ext/nasm/output/codeview.c
new file mode 100644
index 0000000..d1011fc
--- /dev/null
+++ b/vere/ext/nasm/output/codeview.c
@@ -0,0 +1,820 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * codeview.c Codeview Debug Format support for COFF
+ */
+
+#include "version.h"
+#include "compiler.h"
+
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "preproc.h"
+#include "saa.h"
+#include "hashtbl.h"
+#include "outlib.h"
+#include "pecoff.h"
+#include "md5.h"
+
+static void cv8_init(void);
+static void cv8_linenum(const char *filename, int32_t linenumber,
+ int32_t segto);
+static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special);
+static void cv8_typevalue(int32_t type);
+static void cv8_output(int type, void *param);
+static void cv8_cleanup(void);
+
+const struct dfmt df_cv8 = {
+ "Codeview 8+", /* .fullname */
+ "cv8", /* .shortname */
+ cv8_init, /* .init */
+ cv8_linenum, /* .linenum */
+ cv8_deflabel, /* .debug_deflabel */
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive, /* .debug_directive */
+ cv8_typevalue, /* .debug_typevalue */
+ cv8_output, /* .debug_output */
+ cv8_cleanup, /* .cleanup */
+ NULL /* pragma list */
+};
+
+/*******************************************************************************
+ * dfmt callbacks
+ ******************************************************************************/
+struct source_file;
+
+struct source_file {
+ const char *filename;
+ char *fullname;
+ uint32_t fullnamelen;
+
+ struct source_file *next;
+
+ uint32_t filetbl_off;
+ uint32_t sourcetbl_off;
+
+ struct SAA *lines;
+ uint32_t num_lines;
+
+ unsigned char md5sum[MD5_HASHBYTES];
+};
+
+struct linepair {
+ uint32_t file_offset;
+ uint32_t linenumber;
+};
+
+enum symbol_type {
+ SYMTYPE_CODE,
+ SYMTYPE_PROC,
+ SYMTYPE_LDATA,
+ SYMTYPE_GDATA,
+
+ SYMTYPE_MAX
+};
+
+struct cv8_symbol {
+ enum symbol_type type;
+ char *name;
+
+ uint32_t secrel;
+ uint16_t section;
+ uint32_t size;
+ uint32_t typeindex;
+
+ enum symtype {
+ TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
+ TYPE_BYTE = 0x0020,
+ TYPE_WORD = 0x0021,
+ TYPE_DWORD= 0x0022,
+ TYPE_QUAD = 0x0023,
+
+ TYPE_REAL32 = 0x0040,
+ TYPE_REAL64 = 0x0041,
+ TYPE_REAL80 = 0x0042,
+ TYPE_REAL128= 0x0043,
+ TYPE_REAL256= 0x0044,
+ TYPE_REAL512= 0x0045
+ } symtype;
+};
+
+struct cv8_state {
+ int symbol_sect;
+ int type_sect;
+
+ uint32_t text_offset;
+
+ struct source_file *source_files, **source_files_tail;
+ const char *last_filename;
+ struct source_file *last_source_file;
+ struct hash_table file_hash;
+ unsigned num_files;
+ uint32_t total_filename_len;
+
+
+ unsigned total_lines;
+
+ struct SAA *symbols;
+ struct cv8_symbol *last_sym;
+ unsigned num_syms[SYMTYPE_MAX];
+ unsigned symbol_lengths;
+ unsigned total_syms;
+
+ struct {
+ char *name;
+ size_t namebytes;
+ } outfile;
+};
+struct cv8_state cv8_state;
+
+static void cv8_init(void)
+{
+ const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_DISCARDABLE |
+ IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_ALIGN_1BYTES;
+
+ cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
+ cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
+
+ cv8_state.text_offset = 0;
+
+ cv8_state.source_files = NULL;
+ cv8_state.source_files_tail = &cv8_state.source_files;
+
+ cv8_state.num_files = 0;
+ cv8_state.total_filename_len = 0;
+
+ cv8_state.total_lines = 0;
+
+ cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
+ cv8_state.last_sym = NULL;
+}
+
+static struct source_file *register_file(const char *filename);
+static struct coff_Section *find_section(int32_t segto);
+
+static void cv8_linenum(const char *filename, int32_t linenumber,
+ int32_t segto)
+{
+ struct coff_Section *s;
+ struct linepair *li;
+ struct source_file *file;
+
+ file = register_file(filename);
+
+ s = find_section(segto);
+ if (s == NULL)
+ return;
+
+ if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
+ return;
+
+ li = saa_wstruct(file->lines);
+ li->file_offset = cv8_state.text_offset;
+ li->linenumber = linenumber;
+
+ file->num_lines++;
+ cv8_state.total_lines++;
+}
+
+static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ struct cv8_symbol *sym;
+ struct coff_Section *s;
+
+ (void)special;
+
+ s = find_section(segment);
+ if (s == NULL)
+ return;
+
+ sym = saa_wstruct(cv8_state.symbols);
+
+ if (s->flags & IMAGE_SCN_MEM_EXECUTE)
+ sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
+ else
+ sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
+ cv8_state.num_syms[sym->type]++;
+ cv8_state.total_syms++;
+
+ sym->section = segment;
+ sym->secrel = offset;
+ sym->symtype = TYPE_UNREGISTERED;
+ sym->size = 0;
+ sym->typeindex = 0;
+
+ sym->name = nasm_strdup(name);
+ cv8_state.symbol_lengths += strlen(sym->name) + 1;
+
+ if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
+ cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
+ cv8_state.last_sym = sym;
+}
+
+static void cv8_typevalue(int32_t type)
+{
+ if (!cv8_state.last_sym)
+ return;
+ if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
+ return;
+
+ switch (TYM_TYPE(type)) {
+ case TY_BYTE:
+ cv8_state.last_sym->symtype = TYPE_BYTE;
+ break;
+ case TY_WORD:
+ cv8_state.last_sym->symtype = TYPE_WORD;
+ break;
+ case TY_DWORD:
+ cv8_state.last_sym->symtype = TYPE_DWORD;
+ break;
+ case TY_QWORD:
+ cv8_state.last_sym->symtype = TYPE_QUAD;
+ break;
+ case TY_FLOAT:
+ cv8_state.last_sym->symtype = TYPE_REAL32;
+ break;
+ case TY_TBYTE:
+ cv8_state.last_sym->symtype = TYPE_REAL80;
+ break;
+ case TY_OWORD:
+ cv8_state.last_sym->symtype = TYPE_REAL128;
+ break;
+ case TY_YWORD:
+ cv8_state.last_sym->symtype = TYPE_REAL256;
+ break;
+ case TY_ZWORD:
+ cv8_state.last_sym->symtype = TYPE_REAL512;
+ break;
+ case TY_UNKNOWN:
+ break;
+ case TY_LABEL:
+ break;
+ }
+}
+
+static void cv8_output(int type, void *param)
+{
+ struct coff_DebugInfo *dinfo = param;
+
+ (void)type;
+
+ if (dinfo->section && dinfo->section->name &&
+ !strncmp(dinfo->section->name, ".text", 5))
+ cv8_state.text_offset += dinfo->size;
+}
+
+static void build_symbol_table(struct coff_Section *const sect);
+static void build_type_table(struct coff_Section *const sect);
+
+static void cv8_cleanup(void)
+{
+ struct cv8_symbol *sym;
+ struct source_file *file, *ftmp;
+
+ struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
+ struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
+
+ cv8_state.outfile.name = nasm_realpath(outname);
+ cv8_state.outfile.namebytes = strlen(cv8_state.outfile.name) + 1;
+
+ build_symbol_table(symbol_sect);
+ build_type_table(type_sect);
+
+ list_for_each_safe(file, ftmp, cv8_state.source_files) {
+ nasm_free(file->fullname);
+ saa_free(file->lines);
+ nasm_free(file);
+ }
+ hash_free(&cv8_state.file_hash);
+
+ saa_rewind(cv8_state.symbols);
+ while ((sym = saa_rstruct(cv8_state.symbols)))
+ nasm_free(sym->name);
+ saa_free(cv8_state.symbols);
+
+ nasm_free(cv8_state.outfile.name);
+}
+
+/*******************************************************************************
+ * implementation
+ ******************************************************************************/
+static void calc_md5(const char *const filename,
+ unsigned char sum[MD5_HASHBYTES])
+{
+ int success = 0;
+ unsigned char *file_buf;
+ FILE *f;
+ MD5_CTX ctx;
+
+ f = pp_input_fopen(filename, NF_BINARY);
+ if (!f)
+ goto done;
+
+ file_buf = nasm_zalloc(BUFSIZ);
+
+ MD5Init(&ctx);
+ while (!feof(f)) {
+ size_t i = fread(file_buf, 1, BUFSIZ, f);
+ if (ferror(f))
+ goto done_0;
+ else if (i == 0)
+ break;
+ MD5Update(&ctx, file_buf, i);
+ }
+ MD5Final(sum, &ctx);
+
+ success = 1;
+done_0:
+ nasm_free(file_buf);
+ fclose(f);
+done:
+ if (!success) {
+ nasm_nonfatal("unable to hash file %s. "
+ "Debug information may be unavailable.",
+ filename);
+ }
+ return;
+}
+
+static struct source_file *register_file(const char *filename)
+{
+ struct source_file *file;
+ void **filep;
+ char *fullpath;
+ struct hash_insert hi;
+
+ /*
+ * The common case is that we are invoked with the same filename
+ * as we were last time. Make this a pointer comparison: this is
+ * safe because the NASM core code allocates each filename once
+ * and never frees it.
+ */
+ if (likely(cv8_state.last_filename == filename))
+ return cv8_state.last_source_file;
+
+ cv8_state.last_filename = filename;
+
+ filep = hash_find(&cv8_state.file_hash, filename, &hi);
+ if (likely(filep)) {
+ file = *filep;
+ } else {
+ /* New filename encounter */
+
+ fullpath = nasm_realpath(filename);
+
+ nasm_new(file);
+ file->filename = filename;
+ file->fullname = fullpath;
+ file->fullnamelen = strlen(fullpath);
+ file->lines = saa_init(sizeof(struct linepair));
+ *cv8_state.source_files_tail = file;
+ cv8_state.source_files_tail = &file->next;
+ calc_md5(fullpath, file->md5sum);
+
+ hash_add(&hi, filename, file);
+
+ cv8_state.num_files++;
+ cv8_state.total_filename_len += file->fullnamelen + 1;
+ }
+
+ cv8_state.last_source_file = file;
+ return file;
+}
+
+static struct coff_Section *find_section(int32_t segto)
+{
+ int i;
+
+ for (i = 0; i < coff_nsects; i++) {
+ struct coff_Section *sec;
+
+ sec = coff_sects[i];
+ if (segto == sec->index)
+ return sec;
+ }
+ return NULL;
+}
+
+static void register_reloc(struct coff_Section *const sect,
+ char *sym, uint32_t addr, uint16_t type)
+{
+ struct coff_Reloc *r;
+ struct coff_Section *sec;
+ uint32_t i;
+
+ r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
+ sect->tail = &r->next;
+ r->next = NULL;
+ sect->nrelocs++;
+
+ r->address = addr;
+ r->symbase = SECT_SYMBOLS;
+ r->type = type;
+
+ r->symbol = 0;
+ for (i = 0; i < (uint32_t)coff_nsects; i++) {
+ sec = coff_sects[i];
+ if (!strcmp(sym, sec->name)) {
+ return;
+ }
+ r->symbol += 2;
+ }
+
+ saa_rewind(coff_syms);
+ for (i = 0; i < coff_nsyms; i++) {
+ struct coff_Symbol *s = saa_rstruct(coff_syms);
+ r->symbol++;
+ if (s->strpos == -1 && !strcmp(sym, s->name)) {
+ return;
+ } else if (s->strpos != -1) {
+ int res;
+ char *symname;
+
+ symname = nasm_malloc(s->namlen + 1);
+ saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
+ symname[s->namlen] = '\0';
+ res = strcmp(sym, symname);
+ nasm_free(symname);
+ if (!res)
+ return;
+ }
+ }
+ nasm_panic("codeview: relocation for unregistered symbol: %s", sym);
+}
+
+static inline void section_write32(struct coff_Section *sect, uint32_t val)
+{
+ saa_write32(sect->data, val);
+ sect->len += 4;
+}
+
+static inline void section_write16(struct coff_Section *sect, uint16_t val)
+{
+ saa_write16(sect->data, val);
+ sect->len += 2;
+}
+
+static inline void section_write8(struct coff_Section *sect, uint8_t val)
+{
+ saa_write8(sect->data, val);
+ sect->len++;
+}
+
+static inline void section_wbytes(struct coff_Section *sect, const void *buf,
+ size_t len)
+{
+ saa_wbytes(sect->data, buf, len);
+ sect->len += len;
+}
+
+static void write_filename_table(struct coff_Section *const sect)
+{
+ uint32_t field_length;
+ uint32_t tbl_off = 1; /* offset starts at 1 to skip NULL entry */
+ struct source_file *file;
+
+ nasm_assert(cv8_state.source_files != NULL);
+ nasm_assert(cv8_state.num_files > 0);
+ nasm_assert(cv8_state.total_filename_len > 0);
+
+ field_length = 1 + cv8_state.total_filename_len;
+
+ section_write32(sect, 0x000000F3);
+ section_write32(sect, field_length);
+
+ section_write8(sect, 0);
+
+ list_for_each(file, cv8_state.source_files) {
+ section_wbytes(sect, file->fullname, file->fullnamelen + 1);
+ file->filetbl_off = tbl_off;
+ tbl_off += file->fullnamelen + 1;
+ }
+}
+
+static void write_sourcefile_table(struct coff_Section *const sect)
+{
+ const uint32_t entry_size = 4 + 2 + MD5_HASHBYTES + 2;
+
+ uint32_t field_length = 0;
+ uint32_t tbl_off = 0;
+ struct source_file *file;
+
+ field_length = entry_size * cv8_state.num_files;
+
+ section_write32(sect, 0x000000F4);
+ section_write32(sect, field_length);
+
+ list_for_each(file, cv8_state.source_files) {
+ nasm_assert(file->filetbl_off > 0);
+ section_write32(sect, file->filetbl_off);
+ section_write16(sect, 0x0110);
+ section_wbytes(sect, file->md5sum, MD5_HASHBYTES);
+ section_write16(sect, 0);
+
+ file->sourcetbl_off = tbl_off;
+ tbl_off += entry_size;
+ }
+}
+
+static void write_linenumber_table(struct coff_Section *const sect)
+{
+ const uint32_t file_field_len = 12;
+ const uint32_t line_field_len = 8;
+
+ int i;
+ uint32_t field_length = 0;
+ size_t field_base;
+ struct source_file *file;
+ struct coff_Section *s;
+
+ for (i = 0; i < coff_nsects; i++) {
+ if (!strncmp(coff_sects[i]->name, ".text", 5))
+ break;
+ }
+
+ if (i == coff_nsects)
+ return;
+ s = coff_sects[i];
+
+ field_length = 12;
+ field_length += (cv8_state.num_files * file_field_len);
+ field_length += (cv8_state.total_lines * line_field_len);
+
+ section_write32(sect, 0x000000F2);
+ section_write32(sect, field_length);
+
+ field_base = sect->len;
+ section_write32(sect, 0); /* SECREL, updated by relocation */
+ section_write16(sect, 0); /* SECTION, updated by relocation*/
+ section_write16(sect, 0); /* pad */
+ section_write32(sect, s->len);
+
+ register_reloc(sect, ".text", field_base,
+ win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
+
+ register_reloc(sect, ".text", field_base + 4,
+ win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
+
+ list_for_each(file, cv8_state.source_files) {
+ struct linepair *li;
+
+ /* source mapping */
+ section_write32(sect, file->sourcetbl_off);
+ section_write32(sect, file->num_lines);
+ section_write32(sect, file_field_len + (file->num_lines * line_field_len));
+
+ /* the pairs */
+ saa_rewind(file->lines);
+ while ((li = saa_rstruct(file->lines))) {
+ section_write32(sect, li->file_offset);
+ section_write32(sect, li->linenumber |= 0x80000000);
+ }
+ }
+}
+
+static uint32_t write_symbolinfo_obj(struct coff_Section *sect)
+{
+ uint32_t obj_len;
+
+ obj_len = 2 + 4 + cv8_state.outfile.namebytes;
+
+ section_write16(sect, obj_len);
+ section_write16(sect, 0x1101);
+ section_write32(sect, 0); /* ASM language */
+ section_wbytes(sect, cv8_state.outfile.name, cv8_state.outfile.namebytes);
+
+ return obj_len;
+}
+
+static uint32_t write_symbolinfo_properties(struct coff_Section *sect,
+ const char *const creator_str)
+{
+ /* https://github.com/Microsoft/microsoft-pdb/blob/1d60e041/include/cvinfo.h#L3313 */
+ uint32_t creator_len;
+
+ creator_len = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
+
+ /*
+ * We used to use a language ID of 3 for "MASM", since it's closest of the
+ * options available; however, BinScope from WACK (the Windows Application
+ * Certification Kit) tests for specific minimum MASM versions and trying to
+ * match an increasing sequence of random MASM version/build numbers seems
+ * like a fool's errand.
+ *
+ * Instead, use a different language ID (NASM is, after all, not MASM
+ * syntax) and just write the actual NASM version number. BinScope appears
+ * to be happy with that.
+ */
+
+ section_write16(sect, creator_len);
+ section_write16(sect, 0x1116);
+ section_write32(sect, 'N'); /* language: 'N' (0x4e) for "NASM"; flags are 0 */
+ if (win64)
+ section_write16(sect, 0x00D0); /* machine */
+ else if (win32)
+ section_write16(sect, 0x0006); /* machine */
+ else
+ nasm_panic("neither win32 nor win64 are set!");
+ section_write16(sect, 0); /* verFEMajor */
+ section_write16(sect, 0); /* verFEMinor */
+ section_write16(sect, 0); /* verFEBuild */
+
+ /* BinScope/WACK insist on version >= 8.0.50727 */
+ section_write16(sect, NASM_MAJOR_VER); /* verMajor */
+ section_write16(sect, NASM_MINOR_VER); /* verMinor */
+ section_write16(sect, NASM_SUBMINOR_VER*100 + NASM_PATCHLEVEL_VER); /* verBuild */
+
+ section_wbytes(sect, creator_str, strlen(creator_str)+1); /* verSt */
+ /*
+ * normally there would be key/value pairs here, but they aren't
+ * necessary. They are terminated by 2B
+ */
+ section_write16(sect, 0);
+
+ return creator_len;
+}
+
+static uint32_t write_symbolinfo_symbols(struct coff_Section *sect)
+{
+ uint32_t len = 0, field_len;
+ uint32_t field_base;
+ struct cv8_symbol *sym;
+
+ saa_rewind(cv8_state.symbols);
+ while ((sym = saa_rstruct(cv8_state.symbols))) {
+ switch (sym->type) {
+ case SYMTYPE_LDATA:
+ case SYMTYPE_GDATA:
+ field_len = 12 + strlen(sym->name) + 1;
+ len += field_len - 2;
+ section_write16(sect, field_len);
+ if (sym->type == SYMTYPE_LDATA)
+ section_write16(sect, 0x110C);
+ else
+ section_write16(sect, 0x110D);
+ section_write32(sect, sym->symtype);
+
+ field_base = sect->len;
+ section_write32(sect, 0); /* SECREL */
+ section_write16(sect, 0); /* SECTION */
+ break;
+ case SYMTYPE_PROC:
+ case SYMTYPE_CODE:
+ field_len = 9 + strlen(sym->name) + 1;
+ len += field_len - 2;
+ section_write16(sect, field_len);
+ section_write16(sect, 0x1105);
+
+ field_base = sect->len;
+ section_write32(sect, 0); /* SECREL */
+ section_write16(sect, 0); /* SECTION */
+ section_write8(sect, 0); /* FLAG */
+ break;
+ default:
+ nasm_panic("unknown symbol type");
+ }
+
+ section_wbytes(sect, sym->name, strlen(sym->name) + 1);
+
+ register_reloc(sect, sym->name, field_base,
+ win64 ? IMAGE_REL_AMD64_SECREL :
+ IMAGE_REL_I386_SECREL);
+ register_reloc(sect, sym->name, field_base + 4,
+ win64 ? IMAGE_REL_AMD64_SECTION :
+ IMAGE_REL_I386_SECTION);
+ }
+
+ return len;
+}
+
+static void write_symbolinfo_table(struct coff_Section *const sect)
+{
+ static const char creator_str[] = "The Netwide Assembler " NASM_VER;
+ uint32_t obj_length, creator_length, sym_length;
+ uint32_t field_length = 0, out_len;
+
+ nasm_assert(cv8_state.outfile.namebytes);
+
+ /* signature, language, outfile NULL */
+ obj_length = 2 + 4 + cv8_state.outfile.namebytes;
+ creator_length = 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str)+1 + 2;
+
+ sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
+ ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
+ ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
+ ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
+ cv8_state.symbol_lengths;
+
+ field_length = 2 + obj_length +
+ 2 + creator_length +
+ (4 * cv8_state.total_syms) + sym_length;
+
+ section_write32(sect, 0x000000F1);
+ section_write32(sect, field_length);
+
+ /* for sub fields, length proceeds type */
+
+ out_len = write_symbolinfo_obj(sect);
+ nasm_assert(out_len == obj_length);
+
+ out_len = write_symbolinfo_properties(sect, creator_str);
+ nasm_assert(out_len == creator_length);
+
+ out_len = write_symbolinfo_symbols(sect);
+ nasm_assert(out_len == sym_length);
+}
+
+static inline void align4_table(struct coff_Section *const sect)
+{
+ unsigned diff;
+ uint32_t zero = 0;
+ struct SAA *data = sect->data;
+
+ if (data->wptr % 4 == 0)
+ return;
+
+ diff = 4 - (data->wptr % 4);
+ if (diff)
+ section_wbytes(sect, &zero, diff);
+}
+
+static void build_symbol_table(struct coff_Section *const sect)
+{
+ section_write32(sect, 0x00000004);
+
+ write_filename_table(sect);
+ align4_table(sect);
+ write_sourcefile_table(sect);
+ align4_table(sect);
+ write_linenumber_table(sect);
+ align4_table(sect);
+ write_symbolinfo_table(sect);
+ align4_table(sect);
+}
+
+static void build_type_table(struct coff_Section *const sect)
+{
+ uint32_t field_len;
+ uint32_t typeindex = 0x1000;
+ uint32_t idx_arglist;
+
+ section_write32(sect, 0x00000004);
+
+ /* empty argument list type */
+ field_len = 2 + 4;
+ section_write16(sect, field_len);
+ section_write16(sect, 0x1201); /* ARGLIST */
+ section_write32(sect, 0); /* num params */
+ idx_arglist = typeindex++;
+
+ /* procedure type: void proc(void) */
+ field_len = 2 + 4 + 1 + 1 + 2 + 4;
+ section_write16(sect, field_len);
+ section_write16(sect, 0x1008); /* PROC type */
+
+ section_write32(sect, 0x00000003); /* return type VOID */
+ section_write8(sect, 0); /* calling convention (default) */
+ section_write8(sect, 0); /* function attributes */
+ section_write16(sect, 0); /* # params */
+ section_write32(sect, idx_arglist); /* argument list type */
+ /* idx_voidfunc = typeindex++; */
+}
diff --git a/vere/ext/nasm/output/dwarf.h b/vere/ext/nasm/output/dwarf.h
new file mode 100644
index 0000000..87bc0c8
--- /dev/null
+++ b/vere/ext/nasm/output/dwarf.h
@@ -0,0 +1,621 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef OUTPUT_DWARF_H
+#define OUTPUT_DWARF_H
+
+/*
+ * based on DWARF 3 standard
+ */
+
+enum dwarf_tag {
+ DW_TAG_padding = 0x00,
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_global_subroutine = 0x06,
+ DW_TAG_global_variable = 0x07,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_local_variable = 0x0c,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine = 0x14,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_parameter = 0x2f,
+ DW_TAG_template_value_parameter = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ /* DWARF 3 */
+ DW_TAG_dwarf_procedure = 0x36,
+ DW_TAG_restrict_type = 0x37,
+ DW_TAG_interface_type = 0x38,
+ DW_TAG_namespace = 0x39,
+ DW_TAG_imported_module = 0x3a,
+ DW_TAG_unspecified_type = 0x3b,
+ DW_TAG_partial_unit = 0x3c,
+ DW_TAG_imported_unit = 0x3d,
+ DW_TAG_condition = 0x3f,
+ DW_TAG_shared_type = 0x40,
+ /* DWARF 4 */
+ DW_TAG_type_unit = 0x41,
+ DW_TAG_rvalue_reference_type = 0x42,
+ DW_TAG_template_alias = 0x43,
+ /* DWARF 5 */
+ DW_TAG_atomic_type = 0x47,
+
+ DW_TAG_lo_user = 0x4080,
+ DW_TAG_hi_user = 0xffff
+};
+
+enum dwarf_child {
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01
+};
+
+enum dwarf_form {
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16,
+ /* DWARF 4 */
+ DW_FORM_sec_offset = 0x17,
+ DW_FORM_exprloc = 0x18,
+ DW_FORM_flag_present = 0x19,
+ DW_FORM_ref_sig8 = 0x20
+};
+
+enum dwarf_attribute {
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_bit_stride = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention= 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_item = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ /* DWARF 3 */
+ DW_AT_allocated = 0x4e,
+ DW_AT_associated = 0x4f,
+ DW_AT_data_location = 0x50,
+ DW_AT_byte_stride = 0x51,
+ DW_AT_entry_pc = 0x52,
+ DW_AT_use_UTF8 = 0x53,
+ DW_AT_extension = 0x54,
+ DW_AT_ranges = 0x55,
+ DW_AT_trampoline = 0x56,
+ DW_AT_call_column = 0x57,
+ DW_AT_call_file = 0x58,
+ DW_AT_call_line = 0x59,
+ DW_AT_description = 0x5a,
+ DW_AT_binary_scale = 0x5b,
+ DW_AT_decimal_scale = 0x5c,
+ DW_AT_small = 0x5d,
+ DW_AT_decimal_sign = 0x5e,
+ DW_AT_digit_count = 0x5f,
+ DW_AT_picture_string = 0x60,
+ DW_AT_mutable = 0x61,
+ DW_AT_threads_scaled = 0x62,
+ DW_AT_explicit = 0x63,
+ DW_AT_object_pointer = 0x64,
+ DW_AT_endianity = 0x65,
+ DW_AT_elemental = 0x66,
+ DW_AT_pure = 0x67,
+ DW_AT_recursive = 0x68,
+ /* DWARF 4 */
+ DW_AT_signature = 0x69,
+ DW_AT_main_subprogram = 0x6a,
+ DW_AT_data_bit_offset = 0x6b,
+ DW_AT_const_expr = 0x6c,
+ DW_AT_enum_class = 0x6d,
+ DW_AT_linkage_name = 0x6e,
+ /* DWARF 5 */
+ DW_AT_noreturn = 0x87,
+
+ DW_AT_lo_user = 0x2000,
+ DW_AT_hi_user = 0x3fff
+};
+
+enum dwarf_op {
+ DW_OP_addr = 0x03,
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08,
+ DW_OP_const1s = 0x09,
+ DW_OP_const2u = 0x0a,
+ DW_OP_const2s = 0x0b,
+ DW_OP_const4u = 0x0c,
+ DW_OP_const4s = 0x0d,
+ DW_OP_const8u = 0x0e,
+ DW_OP_const8s = 0x0f,
+ DW_OP_constu = 0x10,
+ DW_OP_consts = 0x11,
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15,
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1a,
+ DW_OP_div = 0x1b,
+ DW_OP_minus = 0x1c,
+ DW_OP_mod = 0x1d,
+ DW_OP_mul = 0x1e,
+ DW_OP_neg = 0x1f,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23,
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2f,
+ DW_OP_bra = 0x28,
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2a,
+ DW_OP_gt = 0x2b,
+ DW_OP_le = 0x2c,
+ DW_OP_lt = 0x2d,
+ DW_OP_ne = 0x2e,
+ DW_OP_lit0 = 0x30,
+ DW_OP_lit1 = 0x31,
+ DW_OP_lit2 = 0x32,
+ DW_OP_lit3 = 0x33,
+ DW_OP_lit4 = 0x34,
+ DW_OP_lit5 = 0x35,
+ DW_OP_lit6 = 0x36,
+ DW_OP_lit7 = 0x37,
+ DW_OP_lit8 = 0x38,
+ DW_OP_lit9 = 0x39,
+ DW_OP_lit10 = 0x3a,
+ DW_OP_lit11 = 0x3b,
+ DW_OP_lit12 = 0x3c,
+ DW_OP_lit13 = 0x3d,
+ DW_OP_lit14 = 0x3e,
+ DW_OP_lit15 = 0x3f,
+ DW_OP_lit16 = 0x40,
+ DW_OP_lit17 = 0x41,
+ DW_OP_lit18 = 0x42,
+ DW_OP_lit19 = 0x43,
+ DW_OP_lit20 = 0x44,
+ DW_OP_lit21 = 0x45,
+ DW_OP_lit22 = 0x46,
+ DW_OP_lit23 = 0x47,
+ DW_OP_lit24 = 0x48,
+ DW_OP_lit25 = 0x49,
+ DW_OP_lit26 = 0x4a,
+ DW_OP_lit27 = 0x4b,
+ DW_OP_lit28 = 0x4c,
+ DW_OP_lit29 = 0x4d,
+ DW_OP_lit30 = 0x4e,
+ DW_OP_lit31 = 0x4f,
+ DW_OP_reg0 = 0x50,
+ DW_OP_reg1 = 0x51,
+ DW_OP_reg2 = 0x52,
+ DW_OP_reg3 = 0x53,
+ DW_OP_reg4 = 0x54,
+ DW_OP_reg5 = 0x55,
+ DW_OP_reg6 = 0x56,
+ DW_OP_reg7 = 0x57,
+ DW_OP_reg8 = 0x58,
+ DW_OP_reg9 = 0x59,
+ DW_OP_reg10 = 0x5a,
+ DW_OP_reg11 = 0x5b,
+ DW_OP_reg12 = 0x5c,
+ DW_OP_reg13 = 0x5d,
+ DW_OP_reg14 = 0x5e,
+ DW_OP_reg15 = 0x5f,
+ DW_OP_reg16 = 0x60,
+ DW_OP_reg17 = 0x61,
+ DW_OP_reg18 = 0x62,
+ DW_OP_reg19 = 0x63,
+ DW_OP_reg20 = 0x64,
+ DW_OP_reg21 = 0x65,
+ DW_OP_reg22 = 0x66,
+ DW_OP_reg23 = 0x67,
+ DW_OP_reg24 = 0x68,
+ DW_OP_reg25 = 0x69,
+ DW_OP_reg26 = 0x6a,
+ DW_OP_reg27 = 0x6b,
+ DW_OP_reg28 = 0x6c,
+ DW_OP_reg29 = 0x6d,
+ DW_OP_reg30 = 0x6e,
+ DW_OP_reg31 = 0x6f,
+ DW_OP_breg0 = 0x70,
+ DW_OP_breg1 = 0x71,
+ DW_OP_breg2 = 0x72,
+ DW_OP_breg3 = 0x73,
+ DW_OP_breg4 = 0x74,
+ DW_OP_breg5 = 0x75,
+ DW_OP_breg6 = 0x76,
+ DW_OP_breg7 = 0x77,
+ DW_OP_breg8 = 0x78,
+ DW_OP_breg9 = 0x79,
+ DW_OP_breg10 = 0x7a,
+ DW_OP_breg11 = 0x7b,
+ DW_OP_breg12 = 0x7c,
+ DW_OP_breg13 = 0x7d,
+ DW_OP_breg14 = 0x7e,
+ DW_OP_breg15 = 0x7f,
+ DW_OP_breg16 = 0x80,
+ DW_OP_breg17 = 0x81,
+ DW_OP_breg18 = 0x82,
+ DW_OP_breg19 = 0x83,
+ DW_OP_breg20 = 0x84,
+ DW_OP_breg21 = 0x85,
+ DW_OP_breg22 = 0x86,
+ DW_OP_breg23 = 0x87,
+ DW_OP_breg24 = 0x88,
+ DW_OP_breg25 = 0x89,
+ DW_OP_breg26 = 0x8a,
+ DW_OP_breg27 = 0x8b,
+ DW_OP_breg28 = 0x8c,
+ DW_OP_breg29 = 0x8d,
+ DW_OP_breg30 = 0x8e,
+ DW_OP_breg31 = 0x8f,
+ DW_OP_regx = 0x90,
+ DW_OP_fbreg = 0x91,
+ DW_OP_bregx = 0x92,
+ DW_OP_piece = 0x93,
+ DW_OP_deref_size = 0x94,
+ DW_OP_xderef_size = 0x95,
+ DW_OP_nop = 0x96,
+ /* DWARF 3 */
+ DW_OP_push_object_address = 0x97,
+ DW_OP_call2 = 0x98,
+ DW_OP_call4 = 0x99,
+ DW_OP_call_ref = 0x9a ,
+ DW_OP_form_tls_address = 0x9b,
+ DW_OP_call_frame_cfa = 0x9c,
+ DW_OP_bit_piece = 0x9d,
+ /* DWARF 4 */
+ DW_OP_implicit_value = 0x9e,
+ DW_OP_stack_value = 0x9f,
+
+ DW_OP_lo_user = 0xe0,
+ DW_OP_hi_user = 0xff
+};
+
+enum dwarf_base_type {
+ DW_ATE_address = 0x01,
+ DW_ATE_boolean = 0x02,
+ DW_ATE_complex_float = 0x03,
+ DW_ATE_float = 0x04,
+ DW_ATE_signed = 0x05,
+ DW_ATE_signed_char = 0x06,
+ DW_ATE_unsigned = 0x07,
+ DW_ATE_unsigned_char = 0x08,
+ /* DWARF 3 */
+ DW_ATE_imaginary_float = 0x09,
+ DW_ATE_packed_decimal = 0x0a,
+ DW_ATE_numeric_string = 0x0b,
+ DW_ATE_edited = 0x0c,
+ DW_ATE_signed_fixed = 0x0d,
+ DW_ATE_unsigned_fixed = 0x0e,
+ DW_ATE_decimal_float = 0x0f,
+ /* DWARF 4 */
+ DW_ATE_UTF = 0x10,
+
+ DW_ATE_lo_user = 0x80,
+ DW_ATE_hi_user = 0xff
+};
+
+enum dwarf_decimal_sign {
+ DW_DS_unsigned = 0x01,
+ DW_DS_leading_overpunch = 0x02,
+ DW_DS_trailing_overpunch = 0x03,
+ DW_DS_leading_separate = 0x04,
+ DW_DS_trailing_separate = 0x05
+};
+
+enum dwarf_endianity {
+ DW_END_default = 0x00,
+ DW_END_big = 0x01,
+ DW_END_little = 0x02,
+
+ DW_END_lo_user = 0x40,
+ DW_END_hi_user = 0xff
+};
+
+enum dwarf_accessibility {
+ DW_ACCESS_public = 0x01,
+ DW_ACCESS_protected = 0x02,
+ DW_ACCESS_private = 0x03
+};
+
+enum dwarf_visibility {
+ DW_VIS_local = 0x01,
+ DW_VIS_exported = 0x02,
+ DW_VIS_qualified = 0x03
+};
+
+enum dwarf_virtuality {
+ DW_VIRTUALITY_none = 0x00,
+ DW_VIRTUALITY_virtual = 0x01,
+ DW_VIRTUALITY_pure_virtual = 0x02
+};
+
+enum dwarf_language {
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ DW_LANG_Java = 0x000b,
+ DW_LANG_C99 = 0x000c,
+ DW_LANG_Ada95 = 0x000d,
+ DW_LANG_Fortran95 = 0x000e,
+ DW_LANG_PLI = 0x000f,
+ DW_LANG_ObjC = 0x0010,
+ DW_LANG_ObjC_plus_plus = 0x0011,
+ DW_LANG_UPC = 0x0012,
+ DW_LANG_D = 0x0013,
+ DW_LANG_Python = 0x0014,
+ DW_LANG_OpenCL = 0x0015,
+ DW_LANG_Go = 0x0016,
+ DW_LANG_Modula3 = 0x0017,
+ DW_LANG_Haskell = 0x0018,
+ DW_LANG_C_plus_plus_03 = 0x0019,
+ DW_LANG_C_plus_plus_11 = 0x001a,
+ DW_LANG_OCaml = 0x001b,
+ DW_LANG_Rust = 0x001c,
+ DW_LANG_C11 = 0x001d,
+ DW_LANG_Swift = 0x001e,
+ DW_LANG_Julia = 0x001f,
+ DW_LANG_Dylan = 0x0020,
+ DW_LANG_C_plus_plus_14 = 0x0021,
+ DW_LANG_Fortran03 = 0x0022,
+ DW_LANG_Fortran08 = 0x0023,
+ DW_LANG_RenderScript = 0x0024,
+
+ DW_LANG_Mips_Assembler = 0x8001,
+
+ DW_LANG_lo_user = 0x8000,
+ DW_LANG_hi_user = 0xffff,
+
+ DW_LANG_Rust_old = 0x9000
+};
+
+enum dwarf_identifier_case {
+ DW_ID_case_sensitive = 0x00,
+ DW_ID_up_case = 0x01,
+ DW_ID_down_case = 0x02,
+ DW_ID_case_insensitive = 0x03
+};
+
+enum dwarf_calling_conversion {
+ DW_CC_normal = 0x01,
+ DW_CC_program = 0x02,
+ DW_CC_nocall = 0x03,
+ DW_CC_pass_by_reference = 0x4,
+ DW_CC_pass_by_value = 0x5,
+
+ DW_CC_lo_user = 0x40,
+ DW_CC_hi_user = 0xff,
+
+ DW_CC_GNU_renesas_sh = 0x40,
+ DW_CC_GNU_borland_fastcall_i386 = 0x41
+};
+
+enum dwarf_inline {
+ DW_INL_not_inlined = 0x00,
+ DW_INL_inlined = 0x01,
+ DW_INL_declared_not_inlined = 0x02,
+ DW_INL_declared_inlined = 0x03
+};
+
+enum dwarf_ordering {
+ DW_ORD_row_major = 0x00,
+ DW_ORD_col_major = 0x01
+};
+
+enum dwarf_discriminant {
+ DW_DSC_label = 0x00,
+ DW_DSC_range = 0x01
+};
+
+enum dwarf_line_number {
+ DW_LNS_extended_op = 0x00,
+ DW_LNS_copy = 0x01,
+ DW_LNS_advance_pc = 0x02,
+ DW_LNS_advance_line = 0x03,
+ DW_LNS_set_file = 0x04,
+ DW_LNS_set_column = 0x05,
+ DW_LNS_negate_stmt = 0x06,
+ DW_LNS_set_basic_block = 0x07,
+ DW_LNS_const_add_pc = 0x08,
+ DW_LNS_fixed_advance_pc = 0x09,
+ DW_LNS_set_prologue_end = 0x0a,
+ DW_LNS_set_epilogue_begin = 0x0b,
+ DW_LNS_set_isa = 0x0c
+};
+
+enum dwarf_line_number_extended {
+ DW_LNE_end_sequence = 0x01,
+ DW_LNE_set_address = 0x02,
+ DW_LNE_define_file = 0x03,
+ DW_LNE_set_discriminator= 0x04,
+ DW_LNE_lo_user = 0x80,
+ DW_LNE_hi_user = 0xff
+};
+
+enum dwarf_macinfo_type {
+ DW_MACINFO_define = 0x01,
+ DW_MACINFO_undef = 0x02,
+ DW_MACINFO_start_file = 0x03,
+ DW_MACINFO_end_file = 0x04,
+ DW_MACINFO_vendor_ext = 0xff
+};
+
+enum dwarf_call_frame {
+ DW_CFA_advance_loc = 0x01,
+ DW_CFA_offset = 0x02,
+ DW_CFA_restore = 0x03,
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01,
+ DW_CFA_advance_loc1 = 0x02,
+ DW_CFA_advance_loc2 = 0x03,
+ DW_CFA_advance_loc4 = 0x04,
+ DW_CFA_offset_extended = 0x05,
+ DW_CFA_restore_extended = 0x06,
+ DW_CFA_undefined = 0x07,
+ DW_CFA_same_value = 0x08,
+ DW_CFA_register = 0x09,
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c,
+ DW_CFA_def_cfa_register = 0x0d,
+ DW_CFA_def_cfa_offset = 0x0e,
+ /* DWARF 3 */
+ DW_CFA_def_cfa_expression = 0x0f,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_lo_user = 0x1c,
+ DW_CFA_hi_user = 0x3f
+};
+
+#endif /* OUTPUT_DWARF_H */
diff --git a/vere/ext/nasm/output/elf.h b/vere/ext/nasm/output/elf.h
new file mode 100644
index 0000000..a15688e
--- /dev/null
+++ b/vere/ext/nasm/output/elf.h
@@ -0,0 +1,557 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef OUTPUT_ELF_H
+#define OUTPUT_ELF_H
+
+/*
+ * Since NASM support both Elf32/64 file formats
+ * we need to cover all types, structures, typedefs and etc
+ */
+
+#include "compiler.h"
+
+/* Segment types */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOOS 0x60000000
+#define PT_HIOS 0x6fffffff
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_GNU_EH_FRAME 0x6474e550 /* Extension, eh? */
+
+/* ELF file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* ELF machine types */
+#define EM_NONE 0
+#define EM_M32 1
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_68K 4
+#define EM_88K 5
+#define EM_486 6 /* Not used in Linux at least */
+#define EM_860 7
+#define EM_MIPS 8 /* R3k, bigendian(?) */
+#define EM_MIPS_RS4_BE 10 /* R4k BE */
+#define EM_PARISC 15
+#define EM_SPARC32PLUS 18
+#define EM_PPC 20
+#define EM_PPC64 21
+#define EM_S390 22
+#define EM_SH 42
+#define EM_SPARCV9 43 /* v9 = SPARC64 */
+#define EM_H8_300H 47
+#define EM_H8S 48
+#define EM_IA_64 50
+#define EM_X86_64 62
+#define EM_CRIS 76
+#define EM_V850 87
+#define EM_ALPHA 0x9026 /* Interim Alpha that stuck around */
+#define EM_CYGNUS_V850 0x9080 /* Old v850 ID used by Cygnus */
+#define EM_S390_OLD 0xA390 /* Obsolete interim value for S/390 */
+
+/* Dynamic type values */
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
+
+/* Auxiliary table entries */
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17 /* frequency at which times() increments */
+/* 18..22 = ? */
+#define AT_SECURE 23 /* secure mode boolean */
+
+/* Program header permission flags */
+#define PF_X 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+
+/* Section header types */
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#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
+#define SHT_HIUSER 0xffffffff
+
+/* Section header flags */
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */
+#define SHF_GROUP (1 << 9) /* Section is member of a group */
+#define SHF_TLS (1 << 10) /* Section hold thread-local data */
+
+/* Special section numbers */
+#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 */
+
+/* Length of magic at the start of a file */
+#define EI_NIDENT 16
+
+/* Magic number constants... */
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_ABIVERSION 8
+#define EI_NINDENT 16
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+#define ELFOSABI_NONE 0
+#define ELFOSABI_LINUX 3
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding) */
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Symbol types */
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object */
+#define STT_NUM 7 /* Number of defined types */
+
+/* Symbol visibilities */
+#define STV_DEFAULT 0 /* Default symbol visibility rules */
+#define STV_INTERNAL 1 /* Processor specific hidden class */
+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
+#define STV_PROTECTED 3 /* Not preemptible, not exported */
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field */
+#define ELF32_ST_BIND(i) ((i) >> 4)
+#define ELF32_ST_MKBIND(i) ((i) << 4) /* just a helper */
+#define ELF32_ST_TYPE(i) ((i) & 0xf)
+#define ELF32_ST_INFO(b, i) (ELF32_ST_MKBIND(b) + ELF32_ST_TYPE(i))
+
+#define ELF64_ST_BIND(i) ELF32_ST_BIND(i)
+#define ELF64_ST_MKBIND(i) ELF32_ST_MKBIND(i)
+#define ELF64_ST_TYPE(i) ELF32_ST_TYPE(i)
+#define ELF64_ST_INFO(b, i) ELF32_ST_INFO(b, i)
+
+/*
+ * ELF standard typedefs (yet more proof that <stdint.h> was way overdue)
+ */
+
+typedef uint16_t Elf32_Half;
+typedef int16_t Elf32_SHalf;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Section;
+
+typedef uint16_t Elf64_Half;
+typedef int16_t Elf64_SHalf;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+typedef uint64_t Elf64_Off;
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Section;
+
+/*
+ * Dynamic header
+ */
+
+typedef struct elf32_dyn {
+ Elf32_Sword d_tag;
+ union {
+ Elf32_Sword d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct elf64_dyn {
+ Elf64_Sxword d_tag;
+ union {
+ Elf64_Xword d_val;
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Dyn;
+
+/*
+ * Relocations
+ */
+
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+#define ELF32_R_INFO(s,t) (((Elf32_Word)(s) << 8) + ELF32_R_TYPE(t))
+
+typedef struct elf32_rel {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf32_rela {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+enum reloc32_type {
+ R_386_32 = 1, /* ordinary absolute relocation */
+ R_386_PC32 = 2, /* PC-relative relocation */
+ R_386_GOT32 = 3, /* an offset into GOT */
+ R_386_PLT32 = 4, /* a PC-relative offset into PLT */
+ R_386_COPY = 5, /* ??? */
+ R_386_GLOB_DAT = 6, /* ??? */
+ R_386_JUMP_SLOT = 7, /* ??? */
+ R_386_RELATIVE = 8, /* ??? */
+ R_386_GOTOFF = 9, /* an offset from GOT base */
+ R_386_GOTPC = 10, /* a PC-relative offset _to_ GOT */
+ R_386_TLS_TPOFF = 14, /* Offset in static TLS block */
+ R_386_TLS_IE = 15, /* Address of GOT entry for static TLS block offset */
+ /* These are GNU extensions, but useful */
+ R_386_16 = 20, /* A 16-bit absolute relocation */
+ R_386_PC16 = 21, /* A 16-bit PC-relative relocation */
+ R_386_8 = 22, /* An 8-bit absolute relocation */
+ R_386_PC8 = 23, /* An 8-bit PC-relative relocation */
+ R_386_SEG16 = 45, /* A 16-bit real-mode segment */
+ R_386_SUB16 = 46, /* Subtract 16-bit value */
+ R_386_SUB32 = 47 /* Subtract 32-bit value */
+};
+
+#define ELF64_R_SYM(x) ((x) >> 32)
+#define ELF64_R_TYPE(x) ((x) & 0xffffffff)
+#define ELF64_R_INFO(s,t) (((Elf64_Xword)(s) << 32) + ELF64_R_TYPE(t))
+
+typedef struct elf64_rel {
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+} Elf64_Rel;
+
+typedef struct elf64_rela {
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+ Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+enum reloc64_type {
+ R_X86_64_NONE = 0, /* No reloc */
+ R_X86_64_64 = 1, /* Direct 64 bit */
+ R_X86_64_PC32 = 2, /* PC relative 32 bit signed */
+ R_X86_64_GOT32 = 3, /* 32 bit GOT entry */
+ R_X86_64_PLT32 = 4, /* 32 bit PLT address */
+ R_X86_64_COPY = 5, /* Copy symbol at runtime */
+ R_X86_64_GLOB_DAT = 6, /* Create GOT entry */
+ R_X86_64_JUMP_SLOT = 7, /* Create PLT entry */
+ R_X86_64_RELATIVE = 8, /* Adjust by program base */
+ R_X86_64_GOTPCREL = 9, /* 32 bit signed PC relative offset to GOT */
+ R_X86_64_32 = 10, /* Direct 32 bit zero extended */
+ R_X86_64_32S = 11, /* Direct 32 bit sign extended */
+ R_X86_64_16 = 12, /* Direct 16 bit zero extended */
+ R_X86_64_PC16 = 13, /* 16 bit sign extended pc relative */
+ R_X86_64_8 = 14, /* Direct 8 bit sign extended */
+ R_X86_64_PC8 = 15, /* 8 bit sign extended pc relative */
+ R_X86_64_DTPMOD64 = 16, /* ID of module containing symbol */
+ R_X86_64_DTPOFF64 = 17, /* Offset in module's TLS block */
+ R_X86_64_TPOFF64 = 18, /* Offset in initial TLS block */
+ R_X86_64_TLSGD = 19, /* 32 bit signed PC relative offset to two GOT entries for GD symbol */
+ R_X86_64_TLSLD = 20, /* 32 bit signed PC relative offset to two GOT entries for LD symbol */
+ R_X86_64_DTPOFF32 = 21, /* Offset in TLS block */
+ R_X86_64_GOTTPOFF = 22, /* 32 bit signed PC relative offset to GOT entry for IE symbol */
+ R_X86_64_TPOFF32 = 23, /* Offset in initial TLS block */
+ R_X86_64_PC64 = 24, /* word64 S + A - P */
+ R_X86_64_GOTOFF64 = 25, /* word64 S + A - GOT */
+ R_X86_64_GOTPC32 = 26, /* word32 GOT + A - P */
+ R_X86_64_GOT64 = 27, /* word64 G + A */
+ R_X86_64_GOTPCREL64 = 28, /* word64 G + GOT - P + A */
+ R_X86_64_GOTPC64 = 29, /* word64 GOT - P + A */
+ R_X86_64_GOTPLT64 = 30, /* word64 G + A */
+ R_X86_64_PLTOFF64 = 31, /* word64 L - GOT + A */
+ R_X86_64_SIZE32 = 32, /* word32 Z + A */
+ R_X86_64_SIZE64 = 33, /* word64 Z + A */
+ R_X86_64_GOTPC32_TLSDESC= 34, /* word32 */
+ R_X86_64_TLSDESC_CALL = 35, /* none */
+ R_X86_64_TLSDESC = 36 /* word64?2 */
+};
+
+/*
+ * Symbol
+ */
+
+typedef struct elf32_sym {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+typedef struct elf64_sym {
+ Elf64_Word st_name;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf64_Half st_shndx;
+ Elf64_Addr st_value;
+ Elf64_Xword st_size;
+} Elf64_Sym;
+
+/*
+ * Main file header
+ */
+
+typedef struct elf32_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry;
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/*
+ * Program header
+ */
+
+typedef struct elf32_phdr {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Addr p_paddr;
+ Elf64_Xword p_filesz;
+ Elf64_Xword p_memsz;
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+/*
+ * Section header
+ */
+
+typedef struct elf32_shdr {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct elf64_shdr {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Xword sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Xword sh_addralign;
+ Elf64_Xword sh_entsize;
+} Elf64_Shdr;
+
+/*
+ * Note header
+ */
+typedef struct elf32_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+typedef struct elf64_note {
+ Elf64_Word n_namesz; /* Name size */
+ Elf64_Word n_descsz; /* Content size */
+ Elf64_Word n_type; /* Content type */
+} Elf64_Nhdr;
+
+#endif /* OUTPUT_ELF_H */
diff --git a/vere/ext/nasm/output/legacy.c b/vere/ext/nasm/output/legacy.c
new file mode 100644
index 0000000..15d22e9
--- /dev/null
+++ b/vere/ext/nasm/output/legacy.c
@@ -0,0 +1,122 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2016-2022 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * output/legacy.c
+ *
+ * Mangle a struct out_data to match the rather bizarre legacy
+ * backend interface.
+ *
+ * The "data" parameter for the output function points to a "int64_t",
+ * containing the address of the target in question, unless the type is
+ * OUT_RAWDATA, in which case it points to an "uint8_t"
+ * array.
+ *
+ * Exceptions are OUT_RELxADR, which denote an x-byte relocation
+ * which will be a relative jump. For this we need to know the
+ * distance in bytes from the start of the relocated record until
+ * the end of the containing instruction. _This_ is what is stored
+ * in the size part of the parameter, in this case.
+ *
+ * Also OUT_RESERVE denotes reservation of N bytes of BSS space,
+ * and the contents of the "data" parameter is irrelevant.
+ */
+
+#include "nasm.h"
+#include "outlib.h"
+
+void nasm_do_legacy_output(const struct out_data *data)
+{
+ const void *dptr = data->data;
+ enum out_type type = data->type;
+ int32_t tsegment = data->tsegment;
+ int32_t twrt = data->twrt;
+ uint64_t size = data->size;
+
+ switch (data->type) {
+ case OUT_RELADDR:
+ switch (data->size) {
+ case 1:
+ type = OUT_REL1ADR;
+ break;
+ case 2:
+ type = OUT_REL2ADR;
+ break;
+ case 4:
+ type = OUT_REL4ADR;
+ break;
+ case 8:
+ type = OUT_REL8ADR;
+ break;
+ default:
+ panic();
+ break;
+ }
+
+ dptr = &data->toffset;
+ size = data->relbase - data->offset;
+ break;
+
+ case OUT_SEGMENT:
+ type = OUT_ADDRESS;
+ tsegment |= 1;
+ /* fall through */
+
+ case OUT_ADDRESS:
+ dptr = &data->toffset;
+ size = (data->flags & OUT_SIGNED) ? -data->size : data->size;
+ break;
+
+ case OUT_RAWDATA:
+ case OUT_RESERVE:
+ tsegment = twrt = NO_SEG;
+ break;
+
+ case OUT_ZERODATA:
+ tsegment = twrt = NO_SEG;
+ type = OUT_RAWDATA;
+ dptr = zero_buffer;
+ while (size > ZERO_BUF_SIZE) {
+ ofmt->legacy_output(data->segment, dptr, type,
+ ZERO_BUF_SIZE, tsegment, twrt);
+ size -= ZERO_BUF_SIZE;
+ }
+ break;
+
+ default:
+ panic();
+ break;
+ }
+
+ ofmt->legacy_output(data->segment, dptr, type, size, tsegment, twrt);
+}
diff --git a/vere/ext/nasm/output/macho.h b/vere/ext/nasm/output/macho.h
new file mode 100644
index 0000000..538c531
--- /dev/null
+++ b/vere/ext/nasm/output/macho.h
@@ -0,0 +1,282 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef OUTPUT_MACHO_H
+#define OUTPUT_MACHO_H
+
+#include "compiler.h"
+
+/* Magics */
+#define MH_MAGIC 0xfeedface
+#define MH_MAGIC_64 0xfeedfacf
+
+/* File types */
+#define MH_OBJECT 0x1
+
+/* CPUs */
+#define CPU_ARCH_MASK 0xff000000
+#define CPU_ARCH_ABI64 0x01000000
+#define CPU_TYPE_X86 7
+#define CPU_TYPE_I386 CPU_TYPE_X86
+#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64)
+
+#define CPU_SUBTYPE_MASK 0xff000000
+#define CPU_SUBTYPE_I386_ALL 3
+
+/* Header flags */
+#define MH_SUBSECTIONS_VIA_SYMBOLS 0x00002000
+
+/* Load commands */
+#define LC_SEGMENT 0x1
+#define LC_SEGMENT_64 0x19
+#define LC_SYMTAB 0x2
+
+/* Symbol type bits */
+#define N_STAB 0xe0
+#define N_PEXT 0x10
+#define N_TYPE 0x0e
+#define N_EXT 0x01
+
+/* To mask with N_TYPE */
+#define N_UNDF 0x00
+#define N_ABS 0x02
+#define N_INDR 0x0a
+#define N_PBUD 0x0c
+#define N_SECT 0x0e
+
+/* Section ordinals */
+#define NO_SECT 0x00
+#define MAX_SECT 0xff
+
+/* Section bits */
+#define SECTION_TYPE 0x000000ff
+#define SECTION_ATTRIBUTES 0xffffff00
+#define SECTION_ATTRIBUTES_USR 0xff000000
+#define SECTION_ATTRIBUTES_SYS 0x00ffff00
+
+#define S_REGULAR 0x00
+#define S_ZEROFILL 0x01
+#define S_CSTRING_LITERALS 0x02
+#define S_4BYTE_LITERALS 0x03
+#define S_8BYTE_LITERALS 0x04
+#define S_LITERAL_POINTERS 0x05
+#define S_NON_LAZY_SYMBOL_POINTERS 0x06
+#define S_LAZY_SYMBOL_POINTERS 0x07
+#define S_SYMBOL_STUBS 0x08
+#define S_MOD_INIT_FUNC_POINTERS 0x09
+#define S_MOD_TERM_FUNC_POINTERS 0x0a
+#define S_COALESCED 0x0b
+#define S_GB_ZEROFILL 0x0c
+#define S_INTERPOSING 0x0d
+#define S_16BYTE_LITERALS 0x0e
+#define S_DTRACE_DOF 0x0f
+#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
+#define S_THREAD_LOCAL_REGULAR 0x11
+#define S_THREAD_LOCAL_ZEROFILL 0x12
+#define S_THREAD_LOCAL_VARIABLES 0x13
+#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14
+#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15
+
+#define S_ATTR_PURE_INSTRUCTIONS 0x80000000
+#define S_ATTR_NO_TOC 0x40000000
+#define S_ATTR_STRIP_STATIC_SYMS 0x20000000
+#define S_ATTR_NO_DEAD_STRIP 0x10000000
+#define S_ATTR_LIVE_SUPPORT 0x08000000
+#define S_ATTR_SELF_MODIFYING_CODE 0x04000000
+#define S_ATTR_DEBUG 0x02000000
+
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400
+#define S_ATTR_EXT_RELOC 0x00000200
+#define S_ATTR_LOC_RELOC 0x00000100
+#define INDIRECT_SYMBOL_LOCAL 0x80000000
+#define INDIRECT_SYMBOL_ABS 0x40000000
+
+/* Relocation info type */
+#define GENERIC_RELOC_VANILLA 0
+#define GENERIC_RELOC_PAIR 1
+#define GENERIC_RELOC_SECTDIFF 2
+#define GENERIC_RELOC_PB_LA_PTR 3
+#define GENERIC_RELOC_LOCAL_SECTDIFF 4
+#define GENERIC_RELOC_TLV 5
+
+#define X86_64_RELOC_UNSIGNED 0
+#define X86_64_RELOC_SIGNED 1
+#define X86_64_RELOC_BRANCH 2
+#define X86_64_RELOC_GOT_LOAD 3
+#define X86_64_RELOC_GOT 4
+#define X86_64_RELOC_SUBTRACTOR 5
+#define X86_64_RELOC_SIGNED_1 6
+#define X86_64_RELOC_SIGNED_2 7
+#define X86_64_RELOC_SIGNED_4 8
+#define X86_64_RELOC_TLV 9
+
+/* Relocation info */
+#define R_ABS 0
+#define R_SCATTERED 0x80000000
+
+/* VM permission constants */
+#define VM_PROT_NONE 0x00
+#define VM_PROT_READ 0x01
+#define VM_PROT_WRITE 0x02
+#define VM_PROT_EXECUTE 0x04
+
+typedef struct {
+ uint32_t magic;
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ uint32_t filetype;
+ uint32_t ncmds;
+ uint32_t sizeofcmds;
+ uint32_t flags;
+} macho_header_t;
+
+typedef struct {
+ uint32_t magic;
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ uint32_t filetype;
+ uint32_t ncmds;
+ uint32_t sizeofcmds;
+ uint32_t flags;
+ uint32_t reserved;
+} macho_header_64_t;
+
+typedef struct {
+ uint32_t cmd;
+ uint32_t cmdsize;
+} macho_load_command_t;
+
+typedef struct {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char segname[16];
+ uint32_t vmaddr;
+ uint32_t vmsize;
+ uint32_t fileoff;
+ uint32_t filesize;
+ uint32_t maxprot;
+ uint32_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+} macho_segment_command_t;
+
+typedef struct {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ char segname[16];
+ uint64_t vmaddr;
+ uint64_t vmsize;
+ uint64_t fileoff;
+ uint64_t filesize;
+ uint32_t maxprot;
+ uint32_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+} macho_segment_command_64_t;
+
+typedef struct {
+ char sectname[16];
+ char segname[16];
+ uint32_t addr;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t align;
+ uint32_t reloff;
+ uint32_t nreloc;
+ uint32_t flags;
+ uint32_t reserved1;
+ uint32_t reserved2;
+} macho_section_t;
+
+typedef struct {
+ char sectname[16];
+ char segname[16];
+ uint64_t addr;
+ uint64_t size;
+ uint32_t offset;
+ uint32_t align;
+ uint32_t reloff;
+ uint32_t nreloc;
+ uint32_t flags;
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+} macho_section_64_t;
+
+typedef struct {
+ uint32_t cmd;
+ uint32_t cmdsize;
+ uint32_t symoff;
+ uint32_t nsyms;
+ uint32_t stroff;
+ uint32_t strsize;
+} macho_symtab_command_t;
+
+typedef struct {
+ int32_t r_address;
+ union {
+ struct {
+ uint32_t r_symbolnum: 24,
+ r_pcrel: 1,
+ r_length: 2,
+ r_extern: 1,
+ r_type: 4;
+ } s;
+ uint32_t r_raw;
+ } u;
+} macho_relocation_info_t;
+
+typedef struct nlist_base {
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+} macho_nlist_base_t;
+
+typedef struct nlist {
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ int16_t n_desc;
+ uint32_t n_value;
+} macho_nlist_t;
+
+typedef struct {
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+ uint64_t n_value;
+} macho_nlist_64_t;
+
+#endif /* OUTPUT_MACHO_H */
diff --git a/vere/ext/nasm/output/nulldbg.c b/vere/ext/nasm/output/nulldbg.c
new file mode 100644
index 0000000..93ec3a7
--- /dev/null
+++ b/vere/ext/nasm/output/nulldbg.c
@@ -0,0 +1,96 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2014 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outlib.h"
+
+void null_debug_init(void)
+{
+}
+
+void null_debug_linenum(const char *filename, int32_t linenumber, int32_t segto)
+{
+ (void)filename;
+ (void)linenumber;
+ (void)segto;
+}
+
+void null_debug_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ (void)name;
+ (void)segment;
+ (void)offset;
+ (void)is_global;
+ (void)special;
+}
+
+void null_debug_directive(const char *directive, const char *params)
+{
+ (void)directive;
+ (void)params;
+}
+
+void null_debug_typevalue(int32_t type)
+{
+ (void)type;
+}
+
+void null_debug_output(int type, void *param)
+{
+ (void)type;
+ (void)param;
+}
+
+void null_debug_cleanup(void)
+{
+}
+
+const struct dfmt null_debug_form = {
+ "Null",
+ "null",
+ null_debug_init,
+ null_debug_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ null_debug_typevalue,
+ null_debug_output,
+ null_debug_cleanup,
+ NULL /* pragma list */
+};
+
+const struct dfmt * const null_debug_arr[2] = { &null_debug_form, NULL };
diff --git a/vere/ext/nasm/output/nullout.c b/vere/ext/nasm/output/nullout.c
new file mode 100644
index 0000000..121fe70
--- /dev/null
+++ b/vere/ext/nasm/output/nullout.c
@@ -0,0 +1,60 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outlib.h"
+
+enum directive_result
+null_directive(enum directive directive, char *value)
+{
+ (void)directive;
+ (void)value;
+ return DIRR_UNKNOWN;
+}
+
+void null_sectalign(int32_t seg, unsigned int value)
+{
+ (void)seg;
+ (void)value;
+}
+
+void null_reset(void)
+{
+ /* Nothing to do */
+}
+
+int32_t null_segbase(int32_t segment)
+{
+ return segment;
+}
diff --git a/vere/ext/nasm/output/outaout.c b/vere/ext/nasm/output/outaout.c
new file mode 100644
index 0000000..c59c789
--- /dev/null
+++ b/vere/ext/nasm/output/outaout.c
@@ -0,0 +1,923 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2013 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outaout.c output routines for the Netwide Assembler to produce
+ * Linux a.out object files
+ */
+
+#include "compiler.h"
+
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "saa.h"
+#include "raa.h"
+#include "stdscan.h"
+#include "eval.h"
+#include "outform.h"
+#include "outlib.h"
+
+#if defined OF_AOUT || defined OF_AOUTB
+
+#define RELTYPE_ABSOLUTE 0x00
+#define RELTYPE_RELATIVE 0x01
+#define RELTYPE_GOTPC 0x01 /* no explicit GOTPC in a.out */
+#define RELTYPE_GOTOFF 0x10
+#define RELTYPE_GOT 0x10 /* distinct from GOTOFF bcos sym not sect */
+#define RELTYPE_PLT 0x21
+#define RELTYPE_SYMFLAG 0x08
+
+struct Reloc {
+ struct Reloc *next;
+ int32_t address; /* relative to _start_ of section */
+ int32_t symbol; /* symbol number or -ve section id */
+ int bytes; /* 2 or 4 */
+ int reltype; /* see above */
+};
+
+struct Symbol {
+ int32_t strpos; /* string table position of name */
+ int type; /* symbol type - see flags below */
+ int32_t value; /* address, or COMMON variable size */
+ int32_t size; /* size for data or function exports */
+ int32_t segment; /* back-reference used by gsym_reloc */
+ struct Symbol *next; /* list of globals in each section */
+ struct Symbol *nextfwd; /* list of unresolved-size symbols */
+ char *name; /* for unresolved-size symbols */
+ int32_t symnum; /* index into symbol table */
+};
+
+/*
+ * Section IDs - used in Reloc.symbol when negative, and in
+ * Symbol.type when positive.
+ */
+#define SECT_ABS 2 /* absolute value */
+#define SECT_TEXT 4 /* text section */
+#define SECT_DATA 6 /* data section */
+#define SECT_BSS 8 /* bss section */
+#define SECT_MASK 0xE /* mask out any of the above */
+
+/*
+ * More flags used in Symbol.type.
+ */
+#define SYM_GLOBAL 1 /* it's a global symbol */
+#define SYM_DATA 0x100 /* used for shared libs */
+#define SYM_FUNCTION 0x200 /* used for shared libs */
+#define SYM_WITH_SIZE 0x4000 /* not output; internal only */
+
+/*
+ * Bit more explanation of symbol types: SECT_xxx denotes a local
+ * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
+ * this module. Just SYM_GLOBAL, with zero value, denotes an
+ * external symbol referenced in this module. And just SYM_GLOBAL,
+ * but with a non-zero value, declares a C `common' variable, of
+ * size `value'.
+ */
+
+struct Section {
+ struct SAA *data;
+ uint32_t len, size, nrelocs;
+ int32_t index;
+ struct Reloc *head, **tail;
+ struct Symbol *gsyms, *asym;
+};
+
+static struct Section stext, sdata, sbss;
+
+static struct SAA *syms;
+static uint32_t nsyms;
+
+static struct RAA *bsym;
+
+static struct SAA *strs;
+static uint32_t strslen;
+
+static struct Symbol *fwds;
+
+static int bsd;
+static int is_pic;
+
+static void aout_write(void);
+static void aout_write_relocs(struct Reloc *);
+static void aout_write_syms(void);
+static void aout_sect_write(struct Section *, const uint8_t *,
+ uint32_t);
+static void aout_pad_sections(void);
+static void aout_fixup_relocs(struct Section *);
+
+/*
+ * Special section numbers which are used to define special
+ * symbols, which can be used with WRT to provide PIC relocation
+ * types.
+ */
+static int32_t aout_gotpc_sect, aout_gotoff_sect;
+static int32_t aout_got_sect, aout_plt_sect;
+static int32_t aout_sym_sect;
+
+static void aoutg_init(void)
+{
+ stext.data = saa_init(1L);
+ stext.head = NULL;
+ stext.tail = &stext.head;
+ sdata.data = saa_init(1L);
+ sdata.head = NULL;
+ sdata.tail = &sdata.head;
+ stext.len = stext.size = sdata.len = sdata.size = sbss.len = 0;
+ stext.nrelocs = sdata.nrelocs = 0;
+ stext.gsyms = sdata.gsyms = sbss.gsyms = NULL;
+ stext.index = seg_alloc();
+ sdata.index = seg_alloc();
+ sbss.index = seg_alloc();
+ stext.asym = sdata.asym = sbss.asym = NULL;
+ syms = saa_init((int32_t)sizeof(struct Symbol));
+ nsyms = 0;
+ bsym = raa_init();
+ strs = saa_init(1L);
+ strslen = 0;
+ fwds = NULL;
+}
+
+#ifdef OF_AOUT
+
+static void aout_init(void)
+{
+ bsd = false;
+ aoutg_init();
+
+ aout_gotpc_sect = aout_gotoff_sect = aout_got_sect =
+ aout_plt_sect = aout_sym_sect = NO_SEG;
+}
+
+#endif
+
+#ifdef OF_AOUTB
+
+extern const struct ofmt of_aoutb;
+
+static void aoutb_init(void)
+{
+ bsd = true;
+ aoutg_init();
+
+ is_pic = 0x00; /* may become 0x40 */
+
+ aout_gotpc_sect = seg_alloc();
+ backend_label("..gotpc", aout_gotpc_sect + 1, 0L);
+ aout_gotoff_sect = seg_alloc();
+ backend_label("..gotoff", aout_gotoff_sect + 1, 0L);
+ aout_got_sect = seg_alloc();
+ backend_label("..got", aout_got_sect + 1, 0L);
+ aout_plt_sect = seg_alloc();
+ backend_label("..plt", aout_plt_sect + 1, 0L);
+ aout_sym_sect = seg_alloc();
+ backend_label("..sym", aout_sym_sect + 1, 0L);
+}
+
+#endif
+
+static void aout_cleanup(void)
+{
+ struct Reloc *r;
+
+ aout_pad_sections();
+ aout_fixup_relocs(&stext);
+ aout_fixup_relocs(&sdata);
+ aout_write();
+ saa_free(stext.data);
+ while (stext.head) {
+ r = stext.head;
+ stext.head = stext.head->next;
+ nasm_free(r);
+ }
+ saa_free(sdata.data);
+ while (sdata.head) {
+ r = sdata.head;
+ sdata.head = sdata.head->next;
+ nasm_free(r);
+ }
+ saa_free(syms);
+ raa_free(bsym);
+ saa_free(strs);
+}
+
+static int32_t aout_section_names(char *name, int *bits)
+{
+ /*
+ * Default to 32 bits.
+ */
+ if (!name) {
+ *bits = 32;
+ return stext.index;
+ }
+
+ if (!strcmp(name, ".text"))
+ return stext.index;
+ else if (!strcmp(name, ".data"))
+ return sdata.index;
+ else if (!strcmp(name, ".bss"))
+ return sbss.index;
+ else
+ return NO_SEG;
+}
+
+static void aout_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ int pos = strslen + 4;
+ struct Symbol *sym;
+ int special_used = false;
+
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ /*
+ * This is a NASM special symbol. We never allow it into
+ * the a.out symbol table, even if it's a valid one. If it
+ * _isn't_ a valid one, we should barf immediately.
+ */
+ if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") &&
+ strcmp(name, "..got") && strcmp(name, "..plt") &&
+ strcmp(name, "..sym"))
+ nasm_nonfatal("unrecognised special symbol `%s'", name);
+ return;
+ }
+
+ if (is_global == 3) {
+ struct 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 = special;
+
+ p = nasm_skip_spaces(nasm_skip_word(p));
+ 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_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);
+
+ sym = saa_wstruct(syms);
+
+ sym->strpos = pos;
+ sym->type = is_global ? SYM_GLOBAL : 0;
+ sym->segment = segment;
+ if (segment == NO_SEG)
+ sym->type |= SECT_ABS;
+ else if (segment == stext.index) {
+ sym->type |= SECT_TEXT;
+ if (is_global) {
+ sym->next = stext.gsyms;
+ stext.gsyms = sym;
+ } else if (!stext.asym)
+ stext.asym = sym;
+ } else if (segment == sdata.index) {
+ sym->type |= SECT_DATA;
+ if (is_global) {
+ sym->next = sdata.gsyms;
+ sdata.gsyms = sym;
+ } else if (!sdata.asym)
+ sdata.asym = sym;
+ } else if (segment == sbss.index) {
+ sym->type |= SECT_BSS;
+ if (is_global) {
+ sym->next = sbss.gsyms;
+ sbss.gsyms = sym;
+ } else if (!sbss.asym)
+ sbss.asym = sym;
+ } else
+ sym->type = SYM_GLOBAL;
+ if (is_global == 2)
+ sym->value = offset;
+ else
+ sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
+
+ if (is_global && sym->type != SYM_GLOBAL) {
+ /*
+ * Global symbol exported _from_ this module. We must check
+ * the special text for type information.
+ */
+
+ if (special) {
+ int n = strcspn(special, " ");
+
+ if (!nasm_strnicmp(special, "function", n))
+ sym->type |= SYM_FUNCTION;
+ else if (!nasm_strnicmp(special, "data", n) ||
+ !nasm_strnicmp(special, "object", n))
+ sym->type |= SYM_DATA;
+ else
+ nasm_nonfatal("unrecognised symbol type `%.*s'",
+ n, special);
+ if (special[n]) {
+ struct tokenval tokval;
+ expr *e;
+ int fwd = false;
+ char *saveme = stdscan_get();
+
+ if (!bsd) {
+ nasm_nonfatal("Linux a.out does not support"
+ " symbol size information");
+ } else {
+ while (special[n] && nasm_isspace(special[n]))
+ n++;
+ /*
+ * We have a size expression; attempt to
+ * evaluate it.
+ */
+ sym->type |= SYM_WITH_SIZE;
+ 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_nonfatal("cannot use relocatable"
+ " expression as symbol size");
+ else
+ sym->size = reloc_value(e);
+ }
+ }
+ stdscan_set(saveme);
+ }
+ special_used = true;
+ }
+ }
+
+ /*
+ * define the references from external-symbol segment numbers
+ * to these symbol records.
+ */
+ if (segment != NO_SEG && segment != stext.index &&
+ segment != sdata.index && segment != sbss.index)
+ bsym = raa_write(bsym, segment, nsyms);
+ sym->symnum = nsyms;
+
+ nsyms++;
+ if (sym->type & SYM_WITH_SIZE)
+ nsyms++; /* and another for the size */
+
+ if (special && !special_used)
+ nasm_nonfatal("no special symbol features supported here");
+}
+
+static void aout_add_reloc(struct Section *sect, int32_t segment,
+ int reltype, int bytes)
+{
+ struct Reloc *r;
+
+ r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
+ sect->tail = &r->next;
+ r->next = NULL;
+
+ r->address = sect->len;
+ r->symbol = (segment == NO_SEG ? -SECT_ABS :
+ segment == stext.index ? -SECT_TEXT :
+ segment == sdata.index ? -SECT_DATA :
+ segment == sbss.index ? -SECT_BSS :
+ raa_read(bsym, segment));
+ r->reltype = reltype;
+ if (r->symbol >= 0)
+ r->reltype |= RELTYPE_SYMFLAG;
+ r->bytes = bytes;
+
+ 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.
+ *
+ * RELTYPE_GOT references require the _exact_ symbol address to be
+ * used; RELTYPE_ABSOLUTE 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 int32_t aout_add_gsym_reloc(struct Section *sect,
+ int32_t segment, int32_t offset,
+ int type, int bytes, int exact)
+{
+ struct Symbol *sym, *sm, *shead;
+ struct Reloc *r;
+
+ /*
+ * First look up the segment to find whether it's text, data,
+ * bss or an external symbol.
+ */
+ shead = NULL;
+ if (segment == stext.index)
+ shead = stext.gsyms;
+ else if (segment == sdata.index)
+ shead = sdata.gsyms;
+ else if (segment == sbss.index)
+ shead = sbss.gsyms;
+ if (!shead) {
+ if (exact && offset != 0)
+ nasm_nonfatal("unable to find a suitable global symbol"
+ " for this reference");
+ else
+ aout_add_reloc(sect, segment, type, bytes);
+ return offset;
+ }
+
+ if (exact) {
+ /*
+ * Find a symbol pointing _exactly_ at this one.
+ */
+ list_for_each(sym, shead)
+ if (sym->value == offset)
+ break;
+ } else {
+ /*
+ * Find the nearest symbol below this one.
+ */
+ sym = NULL;
+ list_for_each(sm, shead)
+ if (sm->value <= offset && (!sym || sm->value > sym->value))
+ sym = sm;
+ }
+ if (!sym && exact) {
+ nasm_nonfatal("unable to find a suitable global symbol"
+ " for this reference");
+ return 0;
+ }
+
+ r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
+ sect->tail = &r->next;
+ r->next = NULL;
+
+ r->address = sect->len;
+ r->symbol = sym->symnum;
+ r->reltype = type | RELTYPE_SYMFLAG;
+ r->bytes = bytes;
+
+ sect->nrelocs++;
+
+ return offset - sym->value;
+}
+
+/*
+ * This routine deals with ..gotoff relocations. These _must_ refer
+ * to a symbol, due to a perversity of *BSD's PIC implementation,
+ * and it must be a non-global one as well; so we store `asym', the
+ * first nonglobal symbol defined in each section, and always work
+ * from that. Relocation type is always RELTYPE_GOTOFF.
+ *
+ * Return value is the adjusted value of `addr', having become an
+ * offset from the `asym' symbol rather than the section.
+ */
+static int32_t aout_add_gotoff_reloc(struct Section *sect, int32_t segment,
+ int32_t offset, int bytes)
+{
+ struct Reloc *r;
+ struct Symbol *asym;
+
+ /*
+ * First look up the segment to find whether it's text, data,
+ * bss or an external symbol.
+ */
+ asym = NULL;
+ if (segment == stext.index)
+ asym = stext.asym;
+ else if (segment == sdata.index)
+ asym = sdata.asym;
+ else if (segment == sbss.index)
+ asym = sbss.asym;
+ if (!asym)
+ nasm_nonfatal("`..gotoff' relocations require a non-global"
+ " symbol in the section");
+
+ r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
+ sect->tail = &r->next;
+ r->next = NULL;
+
+ r->address = sect->len;
+ r->symbol = asym->symnum;
+ r->reltype = RELTYPE_GOTOFF;
+ r->bytes = bytes;
+
+ sect->nrelocs++;
+
+ return offset - asym->value;
+}
+
+static void aout_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ struct Section *s;
+ int32_t addr;
+ uint8_t mydata[4], *p;
+
+ if (segto == stext.index)
+ s = &stext;
+ else if (segto == sdata.index)
+ s = &sdata;
+ else if (segto == sbss.index)
+ s = NULL;
+ else {
+ nasm_warn(WARN_OTHER, "attempt to assemble code in"
+ " segment %d: defaulting to `.text'", segto);
+ s = &stext;
+ }
+
+ if (!s && type != OUT_RESERVE) {
+ nasm_warn(WARN_OTHER, "attempt to initialize memory in the"
+ " BSS section: ignored");
+ sbss.len += realsize(type, size);
+ return;
+ }
+
+ memset(mydata, 0, sizeof(mydata));
+
+ if (type == OUT_RESERVE) {
+ if (s) {
+ nasm_warn(WARN_ZEROING, "uninitialized space declared in"
+ " %s section: zeroing",
+ (segto == stext.index ? "code" : "data"));
+ aout_sect_write(s, NULL, size);
+ } else
+ sbss.len += size;
+ } else if (type == OUT_RAWDATA) {
+ aout_sect_write(s, data, size);
+ } else if (type == OUT_ADDRESS) {
+ int asize = abs((int)size);
+ addr = *(int64_t *)data;
+ if (segment != NO_SEG) {
+ if (segment % 2) {
+ nasm_nonfatal("a.out format does not support"
+ " segment base references");
+ } else {
+ if (wrt == NO_SEG) {
+ aout_add_reloc(s, segment, RELTYPE_ABSOLUTE, asize);
+ } else if (!bsd) {
+ nasm_nonfatal("Linux a.out format does not support"
+ " any use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ } else if (wrt == aout_gotpc_sect + 1) {
+ is_pic = 0x40;
+ aout_add_reloc(s, segment, RELTYPE_GOTPC, asize);
+ } else if (wrt == aout_gotoff_sect + 1) {
+ is_pic = 0x40;
+ addr = aout_add_gotoff_reloc(s, segment, addr, asize);
+ } else if (wrt == aout_got_sect + 1) {
+ is_pic = 0x40;
+ addr = aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT,
+ asize, true);
+ } else if (wrt == aout_sym_sect + 1) {
+ addr = aout_add_gsym_reloc(s, segment, addr,
+ RELTYPE_ABSOLUTE, asize,
+ false);
+ } else if (wrt == aout_plt_sect + 1) {
+ is_pic = 0x40;
+ nasm_nonfatal("a.out format cannot produce non-PC-"
+ "relative PLT references");
+ } else {
+ nasm_nonfatal("a.out format does not support this"
+ " use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ }
+ }
+ }
+ p = mydata;
+ if (asize == 2)
+ WRITESHORT(p, addr);
+ else
+ WRITELONG(p, addr);
+ aout_sect_write(s, mydata, asize);
+ } else if (type == OUT_REL2ADR) {
+ if (segment != NO_SEG && segment % 2) {
+ nasm_nonfatal("a.out format does not support"
+ " segment base references");
+ } else {
+ if (wrt == NO_SEG) {
+ aout_add_reloc(s, segment, RELTYPE_RELATIVE, 2);
+ } else if (!bsd) {
+ nasm_nonfatal("Linux a.out format does not support"
+ " any use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ } else if (wrt == aout_plt_sect + 1) {
+ is_pic = 0x40;
+ aout_add_reloc(s, segment, RELTYPE_PLT, 2);
+ } else if (wrt == aout_gotpc_sect + 1 ||
+ wrt == aout_gotoff_sect + 1 ||
+ wrt == aout_got_sect + 1) {
+ nasm_nonfatal("a.out format cannot produce PC-"
+ "relative GOT references");
+ } else {
+ nasm_nonfatal("a.out format does not support this"
+ " use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ }
+ }
+ p = mydata;
+ WRITESHORT(p, *(int64_t *)data - (size + s->len));
+ aout_sect_write(s, mydata, 2L);
+ } else if (type == OUT_REL4ADR) {
+ if (segment != NO_SEG && segment % 2) {
+ nasm_nonfatal("a.out format does not support"
+ " segment base references");
+ } else {
+ if (wrt == NO_SEG) {
+ aout_add_reloc(s, segment, RELTYPE_RELATIVE, 4);
+ } else if (!bsd) {
+ nasm_nonfatal("Linux a.out format does not support"
+ " any use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ } else if (wrt == aout_plt_sect + 1) {
+ is_pic = 0x40;
+ aout_add_reloc(s, segment, RELTYPE_PLT, 4);
+ } else if (wrt == aout_gotpc_sect + 1 ||
+ wrt == aout_gotoff_sect + 1 ||
+ wrt == aout_got_sect + 1) {
+ nasm_nonfatal("a.out format cannot produce PC-"
+ "relative GOT references");
+ } else {
+ nasm_nonfatal("a.out format does not support this"
+ " use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ }
+ }
+ p = mydata;
+ WRITELONG(p, *(int64_t *)data - (size + s->len));
+ aout_sect_write(s, mydata, 4L);
+ }
+}
+
+static void aout_pad_sections(void)
+{
+ static uint8_t pad[] = { 0x90, 0x90, 0x90, 0x90 };
+ /*
+ * Pad each of the text and data sections with NOPs until their
+ * length is a multiple of four. (NOP == 0x90.) Also increase
+ * the length of the BSS section similarly.
+ */
+ aout_sect_write(&stext, pad, (-(int32_t)stext.len) & 3);
+ aout_sect_write(&sdata, pad, (-(int32_t)sdata.len) & 3);
+ sbss.len = ALIGN(sbss.len, 4);
+}
+
+/*
+ * a.out files have the curious property that all references to
+ * things in the data or bss sections are done by addresses which
+ * are actually relative to the start of the _text_ section, in the
+ * _file_. (No relation to what happens after linking. No idea why
+ * this should be so. It's very strange.) So we have to go through
+ * the relocation table, _after_ the final size of each section is
+ * known, and fix up the relocations pointed to.
+ */
+static void aout_fixup_relocs(struct Section *sect)
+{
+ struct Reloc *r;
+
+ saa_rewind(sect->data);
+ list_for_each(r, sect->head) {
+ uint8_t *p, *q, blk[4];
+ int32_t l;
+
+ saa_fread(sect->data, r->address, blk, (int32_t)r->bytes);
+ p = q = blk;
+ l = *p++;
+ if (r->bytes > 1) {
+ l += ((int32_t)*p++) << 8;
+ if (r->bytes == 4) {
+ l += ((int32_t)*p++) << 16;
+ l += ((int32_t)*p++) << 24;
+ }
+ }
+ if (r->symbol == -SECT_DATA)
+ l += stext.len;
+ else if (r->symbol == -SECT_BSS)
+ l += stext.len + sdata.len;
+ if (r->bytes == 4)
+ WRITELONG(q, l);
+ else if (r->bytes == 2)
+ WRITESHORT(q, l);
+ else
+ *q++ = l & 0xFF;
+ saa_fwrite(sect->data, r->address, blk, (int32_t)r->bytes);
+ }
+}
+
+static void aout_write(void)
+{
+ /*
+ * Emit the a.out header.
+ */
+ /* OMAGIC, M_386 or MID_I386, no flags */
+ fwriteint32_t(bsd ? 0x07018600 | is_pic : 0x640107L, ofile);
+ fwriteint32_t(stext.len, ofile);
+ fwriteint32_t(sdata.len, ofile);
+ fwriteint32_t(sbss.len, ofile);
+ fwriteint32_t(nsyms * 12, ofile); /* length of symbol table */
+ fwriteint32_t(0L, ofile); /* object files have no entry point */
+ fwriteint32_t(stext.nrelocs * 8, ofile); /* size of text relocs */
+ fwriteint32_t(sdata.nrelocs * 8, ofile); /* size of data relocs */
+
+ /*
+ * Write out the code section and the data section.
+ */
+ saa_fpwrite(stext.data, ofile);
+ saa_fpwrite(sdata.data, ofile);
+
+ /*
+ * Write out the relocations.
+ */
+ aout_write_relocs(stext.head);
+ aout_write_relocs(sdata.head);
+
+ /*
+ * Write the symbol table.
+ */
+ aout_write_syms();
+
+ /*
+ * And the string table.
+ */
+ fwriteint32_t(strslen + 4, ofile); /* length includes length count */
+ saa_fpwrite(strs, ofile);
+}
+
+static void aout_write_relocs(struct Reloc *r)
+{
+ list_for_each(r, r) {
+ uint32_t word2;
+
+ fwriteint32_t(r->address, ofile);
+
+ if (r->symbol >= 0)
+ word2 = r->symbol;
+ else
+ word2 = -r->symbol;
+ word2 |= r->reltype << 24;
+ word2 |= (r->bytes == 1 ? 0 :
+ r->bytes == 2 ? 0x2000000L : 0x4000000L);
+ fwriteint32_t(word2, ofile);
+ }
+}
+
+static void aout_write_syms(void)
+{
+ uint32_t i;
+
+ saa_rewind(syms);
+ for (i = 0; i < nsyms; i++) {
+ struct Symbol *sym = saa_rstruct(syms);
+ fwriteint32_t(sym->strpos, ofile);
+ fwriteint32_t((int32_t)sym->type & ~SYM_WITH_SIZE, ofile);
+ /*
+ * Fix up the symbol value now we know the final section
+ * sizes.
+ */
+ if ((sym->type & SECT_MASK) == SECT_DATA)
+ sym->value += stext.len;
+ if ((sym->type & SECT_MASK) == SECT_BSS)
+ sym->value += stext.len + sdata.len;
+ fwriteint32_t(sym->value, ofile);
+ /*
+ * Output a size record if necessary.
+ */
+ if (sym->type & SYM_WITH_SIZE) {
+ fwriteint32_t(sym->strpos, ofile);
+ fwriteint32_t(0x0DL, ofile); /* special value: means size */
+ fwriteint32_t(sym->size, ofile);
+ i++; /* use up another of `nsyms' */
+ }
+ }
+}
+
+static void aout_sect_write(struct Section *sect,
+ const uint8_t *data, uint32_t len)
+{
+ saa_wbytes(sect->data, data, len);
+ sect->len += len;
+}
+
+extern macros_t aout_stdmac[];
+
+#endif /* OF_AOUT || OF_AOUTB */
+
+#ifdef OF_AOUT
+
+const struct ofmt of_aout = {
+ "Linux a.out",
+ "aout",
+ ".o",
+ 0,
+ 32,
+ null_debug_arr,
+ &null_debug_form,
+ aout_stdmac,
+ aout_init,
+ null_reset,
+ nasm_do_legacy_output,
+ aout_out,
+ aout_deflabel,
+ aout_section_names,
+ NULL,
+ null_sectalign,
+ null_segbase,
+ null_directive,
+ aout_cleanup,
+ NULL /* pragma list */
+};
+
+#endif
+
+#ifdef OF_AOUTB
+
+const struct ofmt of_aoutb = {
+ "NetBSD/FreeBSD a.out",
+ "aoutb",
+ ".o",
+ 0,
+ 32,
+ null_debug_arr,
+ &null_debug_form,
+ aout_stdmac,
+ aoutb_init,
+ null_reset,
+ nasm_do_legacy_output,
+ aout_out,
+ aout_deflabel,
+ aout_section_names,
+ NULL,
+ null_sectalign,
+ null_segbase,
+ null_directive,
+ aout_cleanup,
+ NULL /* pragma list */
+};
+
+#endif
diff --git a/vere/ext/nasm/output/outaout.mac b/vere/ext/nasm/output/outaout.mac
new file mode 100644
index 0000000..5b7b366
--- /dev/null
+++ b/vere/ext/nasm/output/outaout.mac
@@ -0,0 +1,37 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2009 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: aout aoutb
+%define __?SECT?__ [section .text]
+%macro __?NASM_CDecl?__ 1
+%endmacro
diff --git a/vere/ext/nasm/output/outas86.c b/vere/ext/nasm/output/outas86.c
new file mode 100644
index 0000000..54b22f8
--- /dev/null
+++ b/vere/ext/nasm/output/outas86.c
@@ -0,0 +1,611 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2017 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outas86.c output routines for the Netwide Assembler to produce
+ * Linux as86 (bin86-0.3) object files
+ */
+
+#include "compiler.h"
+
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "saa.h"
+#include "raa.h"
+#include "outform.h"
+#include "outlib.h"
+
+#ifdef OF_AS86
+
+struct Piece {
+ struct Piece *next;
+ int type; /* 0 = absolute, 1 = seg, 2 = sym */
+ int32_t offset; /* relative offset */
+ int number; /* symbol/segment number (4=bss) */
+ int32_t bytes; /* size of reloc or of absolute data */
+ bool relative; /* relative address? */
+};
+
+struct Symbol {
+ int32_t strpos; /* string table position of name */
+ int flags; /* symbol flags */
+ int segment; /* 4=bss at this point */
+ int32_t value; /* address, or COMMON variable size */
+};
+
+/*
+ * Section IDs - used in Piece.number and Symbol.segment.
+ */
+#define SECT_TEXT 0 /* text section */
+#define SECT_DATA 3 /* data section */
+#define SECT_BSS 4 /* bss section */
+
+/*
+ * Flags used in Symbol.flags.
+ */
+#define SYM_ENTRY (1<<8)
+#define SYM_EXPORT (1<<7)
+#define SYM_IMPORT (1<<6)
+#define SYM_ABSOLUTE (1<<4)
+
+struct Section {
+ struct SAA *data;
+ uint32_t datalen, size, len;
+ int32_t index;
+ struct Piece *head, *last, **tail;
+};
+
+static struct Section stext, sdata;
+static uint32_t bsslen;
+static int32_t bssindex;
+
+static struct SAA *syms;
+static uint32_t nsyms;
+
+static struct RAA *bsym;
+
+static struct SAA *strs;
+static size_t strslen;
+
+static int as86_reloc_size;
+
+static void as86_write(void);
+static void as86_write_section(struct Section *, int);
+static size_t as86_add_string(const char *name);
+static void as86_sect_write(struct Section *, const uint8_t *,
+ uint32_t);
+
+static void as86_init(void)
+{
+ stext.data = saa_init(1L);
+ stext.datalen = 0L;
+ stext.head = stext.last = NULL;
+ stext.tail = &stext.head;
+ sdata.data = saa_init(1L);
+ sdata.datalen = 0L;
+ sdata.head = sdata.last = NULL;
+ sdata.tail = &sdata.head;
+ bsslen =
+ stext.len = stext.datalen = stext.size =
+ sdata.len = sdata.datalen = sdata.size = 0;
+ stext.index = seg_alloc();
+ sdata.index = seg_alloc();
+ bssindex = seg_alloc();
+ syms = saa_init((int32_t)sizeof(struct Symbol));
+ nsyms = 0;
+ bsym = raa_init();
+ strs = saa_init(1L);
+ strslen = 0;
+
+ /* as86 module name = input file minus extension */
+ as86_add_string(filename_set_extension(inname, ""));
+}
+
+static void as86_cleanup(void)
+{
+ struct Piece *p;
+
+ as86_write();
+ saa_free(stext.data);
+ while (stext.head) {
+ p = stext.head;
+ stext.head = stext.head->next;
+ nasm_free(p);
+ }
+ saa_free(sdata.data);
+ while (sdata.head) {
+ p = sdata.head;
+ sdata.head = sdata.head->next;
+ nasm_free(p);
+ }
+ saa_free(syms);
+ raa_free(bsym);
+ saa_free(strs);
+}
+
+static int32_t as86_section_names(char *name, int *bits)
+{
+ /*
+ * Default is 16 bits.
+ */
+ if (!name) {
+ *bits = 16;
+ return stext.index;
+ }
+
+ if (!strcmp(name, ".text"))
+ return stext.index;
+ else if (!strcmp(name, ".data"))
+ return sdata.index;
+ else if (!strcmp(name, ".bss"))
+ return bssindex;
+ else
+ return NO_SEG;
+}
+
+static size_t as86_add_string(const char *name)
+{
+ size_t pos = strslen;
+ size_t length = strlen(name);
+
+ saa_wbytes(strs, name, length + 1);
+ strslen += 1 + length;
+
+ return pos;
+}
+
+static void as86_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ bool is_start = false;
+ struct Symbol *sym;
+
+ if (special)
+ nasm_nonfatal("as86 format does not support any"
+ " special symbol types");
+
+
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ if (strcmp(name, "..start")) {
+ nasm_nonfatal("unrecognised special symbol `%s'", name);
+ return;
+ } else {
+ is_start = true;
+ }
+ }
+
+ sym = saa_wstruct(syms);
+
+ sym->strpos = as86_add_string(name);
+ sym->flags = 0;
+
+ if (is_start)
+ sym->flags = SYM_ENTRY;
+
+ if (segment == NO_SEG)
+ sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
+ else if (segment == stext.index)
+ sym->segment = SECT_TEXT;
+ else if (segment == sdata.index)
+ sym->segment = SECT_DATA;
+ else if (segment == bssindex)
+ sym->segment = SECT_BSS;
+ else {
+ sym->flags |= SYM_IMPORT;
+ sym->segment = 15;
+ }
+
+ if (is_global == 2)
+ sym->segment = 3; /* already have IMPORT */
+
+ if (is_global && !(sym->flags & SYM_IMPORT))
+ sym->flags |= SYM_EXPORT;
+
+ sym->value = offset;
+
+ /*
+ * define the references from external-symbol segment numbers
+ * to these symbol records.
+ */
+ if (segment != NO_SEG && segment != stext.index &&
+ segment != sdata.index && segment != bssindex)
+ bsym = raa_write(bsym, segment, nsyms);
+
+ nsyms++;
+}
+
+static void as86_add_piece(struct Section *sect, int type, int32_t offset,
+ int32_t segment, int32_t bytes, int relative)
+{
+ struct Piece *p;
+
+ sect->len += bytes;
+
+ if (type == 0 && sect->last && sect->last->type == 0) {
+ sect->last->bytes += bytes;
+ return;
+ }
+
+ p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
+ sect->tail = &p->next;
+ p->next = NULL;
+
+ p->type = type;
+ p->offset = offset;
+ p->bytes = bytes;
+ p->relative = relative;
+
+ if (type == 1 && segment == stext.index)
+ p->number = SECT_TEXT;
+ else if (type == 1 && segment == sdata.index)
+ p->number = SECT_DATA;
+ else if (type == 1 && segment == bssindex)
+ p->number = SECT_BSS;
+ else if (type == 1)
+ p->number = raa_read(bsym, segment), p->type = 2;
+}
+
+static void as86_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ struct Section *s;
+ int32_t offset;
+ uint8_t mydata[4], *p;
+
+ if (wrt != NO_SEG) {
+ wrt = NO_SEG; /* continue to do _something_ */
+ nasm_nonfatal("WRT not supported by as86 output format");
+ }
+
+ if (segto == stext.index)
+ s = &stext;
+ else if (segto == sdata.index)
+ s = &sdata;
+ else if (segto == bssindex)
+ s = NULL;
+ else {
+ nasm_warn(WARN_OTHER, "attempt to assemble code in"
+ " segment %d: defaulting to `.text'", segto);
+ s = &stext;
+ }
+
+ if (!s && type != OUT_RESERVE) {
+ nasm_warn(WARN_OTHER, "attempt to initialize memory in the"
+ " BSS section: ignored");
+ bsslen += realsize(type, size);
+ return;
+ }
+
+ memset(mydata, 0, sizeof(mydata));
+
+ if (type == OUT_RESERVE) {
+ if (s) {
+ nasm_warn(WARN_ZEROING, "uninitialized space declared in"
+ " %s section: zeroing",
+ (segto == stext.index ? "code" : "data"));
+ as86_sect_write(s, NULL, size);
+ as86_add_piece(s, 0, 0L, 0L, size, 0);
+ } else
+ bsslen += size;
+ } else if (type == OUT_RAWDATA) {
+ as86_sect_write(s, data, size);
+ as86_add_piece(s, 0, 0L, 0L, size, 0);
+ } else if (type == OUT_ADDRESS) {
+ int asize = abs((int)size);
+ if (segment != NO_SEG) {
+ if (segment % 2) {
+ nasm_nonfatal("as86 format does not support"
+ " segment base references");
+ } else {
+ offset = *(int64_t *)data;
+ as86_add_piece(s, 1, offset, segment, asize, 0);
+ }
+ } else {
+ p = mydata;
+ WRITELONG(p, *(int64_t *)data);
+ as86_sect_write(s, data, asize);
+ as86_add_piece(s, 0, 0L, 0L, asize, 0);
+ }
+ } else if (type == OUT_REL2ADR) {
+ if (segment != NO_SEG) {
+ if (segment % 2) {
+ nasm_nonfatal("as86 format does not support"
+ " segment base references");
+ } else {
+ offset = *(int64_t *)data;
+ as86_add_piece(s, 1, offset - size + 2, segment, 2L,
+ 1);
+ }
+ }
+ } else if (type == OUT_REL4ADR) {
+ if (segment != NO_SEG) {
+ if (segment % 2) {
+ nasm_nonfatal("as86 format does not support"
+ " segment base references");
+ } else {
+ offset = *(int64_t *)data;
+ as86_add_piece(s, 1, offset - size + 4, segment, 4L,
+ 1);
+ }
+ }
+ }
+}
+
+static void as86_write(void)
+{
+ uint32_t i;
+ int32_t symlen, seglen, segsize;
+
+ /*
+ * First, go through the symbol records working out how big
+ * each will be. Also fix up BSS references at this time, and
+ * set the flags words up completely.
+ */
+ symlen = 0;
+ saa_rewind(syms);
+ for (i = 0; i < nsyms; i++) {
+ struct Symbol *sym = saa_rstruct(syms);
+ if (sym->segment == SECT_BSS)
+ sym->segment = SECT_DATA, sym->value += sdata.len;
+ sym->flags |= sym->segment;
+ if (sym->value == 0)
+ sym->flags |= 0 << 14, symlen += 4;
+ else if (sym->value >= 0 && sym->value <= 255)
+ sym->flags |= 1 << 14, symlen += 5;
+ else if (sym->value >= 0 && sym->value <= 65535L)
+ sym->flags |= 2 << 14, symlen += 6;
+ else
+ sym->flags |= 3 << 14, symlen += 8;
+ }
+
+ /*
+ * Now do the same for the segments, and get the segment size
+ * descriptor word at the same time.
+ */
+ seglen = segsize = 0;
+ if ((uint32_t)stext.len > 65535L)
+ segsize |= 0x03000000L, seglen += 4;
+ else
+ segsize |= 0x02000000L, seglen += 2;
+ if ((uint32_t)sdata.len > 65535L)
+ segsize |= 0xC0000000L, seglen += 4;
+ else
+ segsize |= 0x80000000L, seglen += 2;
+
+ /*
+ * Emit the as86 header.
+ */
+ fwriteint32_t(0x000186A3L, ofile);
+ fputc(0x2A, ofile);
+ fwriteint32_t(27 + symlen + seglen + strslen, ofile); /* header length */
+ fwriteint32_t(stext.len + sdata.len + bsslen, ofile);
+ fwriteint16_t(strslen, ofile);
+ fwriteint16_t(0, ofile); /* class = revision = 0 */
+ fwriteint32_t(0x55555555L, ofile); /* segment max sizes: always this */
+ fwriteint32_t(segsize, ofile); /* segment size descriptors */
+ if (segsize & 0x01000000L)
+ fwriteint32_t(stext.len, ofile);
+ else
+ fwriteint16_t(stext.len, ofile);
+ if (segsize & 0x40000000L)
+ fwriteint32_t(sdata.len + bsslen, ofile);
+ else
+ fwriteint16_t(sdata.len + bsslen, ofile);
+ fwriteint16_t(nsyms, ofile);
+
+ /*
+ * Write the symbol table.
+ */
+ saa_rewind(syms);
+ for (i = 0; i < nsyms; i++) {
+ struct Symbol *sym = saa_rstruct(syms);
+ fwriteint16_t(sym->strpos, ofile);
+ fwriteint16_t(sym->flags, ofile);
+ switch (sym->flags & (3 << 14)) {
+ case 0 << 14:
+ break;
+ case 1 << 14:
+ fputc(sym->value, ofile);
+ break;
+ case 2 << 14:
+ fwriteint16_t(sym->value, ofile);
+ break;
+ case 3 << 14:
+ fwriteint32_t(sym->value, ofile);
+ break;
+ }
+ }
+
+ /*
+ * Write out the string table.
+ */
+ saa_fpwrite(strs, ofile);
+
+ /*
+ * Write the program text.
+ */
+ as86_reloc_size = -1;
+ as86_write_section(&stext, SECT_TEXT);
+ as86_write_section(&sdata, SECT_DATA);
+ /*
+ * Append the BSS section to the .data section
+ */
+ if (bsslen > 65535L) {
+ fputc(0x13, ofile);
+ fwriteint32_t(bsslen, ofile);
+ } else if (bsslen > 255) {
+ fputc(0x12, ofile);
+ fwriteint16_t(bsslen, ofile);
+ } else if (bsslen) {
+ fputc(0x11, ofile);
+ fputc(bsslen, ofile);
+ }
+
+ fputc(0, ofile); /* termination */
+}
+
+static void as86_set_rsize(int size)
+{
+ if (as86_reloc_size != size) {
+ switch (as86_reloc_size = size) {
+ case 1:
+ fputc(0x01, ofile);
+ break;
+ case 2:
+ fputc(0x02, ofile);
+ break;
+ case 4:
+ fputc(0x03, ofile);
+ break;
+ default:
+ nasm_panic("bizarre relocation size %d", size);
+ break;
+ }
+ }
+}
+
+static void as86_write_section(struct Section *sect, int index)
+{
+ struct Piece *p;
+ uint32_t s;
+ int32_t length;
+
+ fputc(0x20 + index, ofile); /* select the right section */
+
+ saa_rewind(sect->data);
+
+ for (p = sect->head; p; p = p->next)
+ switch (p->type) {
+ case 0:
+ /*
+ * Absolute data. Emit it in chunks of at most 64
+ * bytes.
+ */
+ length = p->bytes;
+ do {
+ char buf[64];
+ int32_t tmplen = (length > 64 ? 64 : length);
+ fputc(0x40 | (tmplen & 0x3F), ofile);
+ saa_rnbytes(sect->data, buf, tmplen);
+ nasm_write(buf, tmplen, ofile);
+ length -= tmplen;
+ } while (length > 0);
+ break;
+ case 1:
+ /*
+ * A segment-type relocation. First fix up the BSS.
+ */
+ if (p->number == SECT_BSS)
+ p->number = SECT_DATA, p->offset += sdata.len;
+ as86_set_rsize(p->bytes);
+ fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, ofile);
+ if (as86_reloc_size == 2)
+ fwriteint16_t(p->offset, ofile);
+ else
+ fwriteint32_t(p->offset, ofile);
+ break;
+ case 2:
+ /*
+ * A symbol-type relocation.
+ */
+ as86_set_rsize(p->bytes);
+ s = p->offset;
+ if (s > 65535L)
+ s = 3;
+ else if (s > 255)
+ s = 2;
+ else if (s > 0)
+ s = 1;
+ else
+ s = 0;
+ fputc(0xC0 |
+ (p->relative ? 0x20 : 0) |
+ (p->number > 255 ? 0x04 : 0) | s, ofile);
+ if (p->number > 255)
+ fwriteint16_t(p->number, ofile);
+ else
+ fputc(p->number, ofile);
+ switch (s) {
+ case 0:
+ break;
+ case 1:
+ fputc(p->offset, ofile);
+ break;
+ case 2:
+ fwriteint16_t(p->offset, ofile);
+ break;
+ case 3:
+ fwriteint32_t(p->offset, ofile);
+ break;
+ }
+ break;
+ }
+}
+
+static void as86_sect_write(struct Section *sect,
+ const uint8_t *data, uint32_t len)
+{
+ saa_wbytes(sect->data, data, len);
+ sect->datalen += len;
+}
+
+extern macros_t as86_stdmac[];
+
+const struct ofmt of_as86 = {
+ "as86 (bin86/dev86 toolchain)",
+ "as86",
+ ".o",
+ 0,
+ 32,
+ null_debug_arr,
+ &null_debug_form,
+ as86_stdmac,
+ as86_init,
+ null_reset,
+ nasm_do_legacy_output,
+ as86_out,
+ as86_deflabel,
+ as86_section_names,
+ NULL,
+ null_sectalign,
+ null_segbase,
+ null_directive,
+ as86_cleanup,
+ NULL /* pragma list */
+};
+
+#endif /* OF_AS86 */
diff --git a/vere/ext/nasm/output/outas86.mac b/vere/ext/nasm/output/outas86.mac
new file mode 100644
index 0000000..f7c9a48
--- /dev/null
+++ b/vere/ext/nasm/output/outas86.mac
@@ -0,0 +1,37 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2009 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: as86
+%define __?SECT?__ [section .text]
+%macro __?NASM_CDecl?__ 1
+%endmacro
diff --git a/vere/ext/nasm/output/outbin.c b/vere/ext/nasm/output/outbin.c
new file mode 100644
index 0000000..1522e5c
--- /dev/null
+++ b/vere/ext/nasm/output/outbin.c
@@ -0,0 +1,1669 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2017 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outbin.c output routines for the Netwide Assembler to produce
+ * flat-form binary files
+ */
+
+/* This is the extended version of NASM's original binary output
+ * format. It is backward compatible with the original BIN format,
+ * and contains support for multiple sections and advanced section
+ * ordering.
+ *
+ * Feature summary:
+ *
+ * - Users can create an arbitrary number of sections; they are not
+ * limited to just ".text", ".data", and ".bss".
+ *
+ * - Sections can be either progbits or nobits type.
+ *
+ * - You can specify that they be aligned at a certain boundary
+ * following the previous section ("align="), or positioned at an
+ * arbitrary byte-granular location ("start=").
+ *
+ * - You can specify a "virtual" start address for a section, which
+ * will be used for the calculation for all address references
+ * with respect to that section ("vstart=").
+ *
+ * - The ORG directive, as well as the section/segment directive
+ * arguments ("align=", "start=", "vstart="), can take a critical
+ * expression as their value. For example: "align=(1 << 12)".
+ *
+ * - You can generate map files using the 'map' directive.
+ *
+ */
+
+/* Uncomment the following define if you want sections to adapt
+ * their progbits/nobits state depending on what type of
+ * instructions are issued, rather than defaulting to progbits.
+ * Note that this behavior violates the specification.
+
+#define ABIN_SMART_ADAPT
+
+*/
+
+#include "compiler.h"
+
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "saa.h"
+#include "stdscan.h"
+#include "labels.h"
+#include "eval.h"
+#include "outform.h"
+#include "outlib.h"
+
+#ifdef OF_BIN
+
+static FILE *rf = NULL;
+static void (*do_output)(void);
+
+/* Section flags keep track of which attributes the user has defined. */
+#define START_DEFINED 0x001
+#define ALIGN_DEFINED 0x002
+#define FOLLOWS_DEFINED 0x004
+#define VSTART_DEFINED 0x008
+#define VALIGN_DEFINED 0x010
+#define VFOLLOWS_DEFINED 0x020
+#define TYPE_DEFINED 0x040
+#define TYPE_PROGBITS 0x080
+#define TYPE_NOBITS 0x100
+
+/* This struct is used to keep track of symbols for map-file generation. */
+static struct bin_label {
+ char *name;
+ struct bin_label *next;
+} *no_seg_labels, **nsl_tail;
+
+static struct Section {
+ char *name;
+ struct SAA *contents;
+ int64_t length; /* section length in bytes */
+
+/* Section attributes */
+ int flags; /* see flag definitions above */
+ uint64_t align; /* section alignment */
+ uint64_t valign; /* notional section alignment */
+ uint64_t start; /* section start address */
+ uint64_t vstart; /* section virtual start address */
+ char *follows; /* the section that this one will follow */
+ char *vfollows; /* the section that this one will notionally follow */
+ int32_t start_index; /* NASM section id for non-relocated version */
+ int32_t vstart_index; /* the NASM section id */
+
+ struct bin_label *labels; /* linked-list of label handles for map output. */
+ struct bin_label **labels_end; /* Holds address of end of labels list. */
+ struct Section *prev; /* Points to previous section (implicit follows). */
+ struct Section *next; /* This links sections with a defined start address. */
+
+/* The extended bin format allows for sections to have a "virtual"
+ * start address. This is accomplished by creating two sections:
+ * one beginning at the Load Memory Address and the other beginning
+ * at the Virtual Memory Address. The LMA section is only used to
+ * define the section.<section_name>.start label, but there isn't
+ * any other good way for us to handle that label.
+ */
+
+} *sections, *last_section;
+
+static struct Reloc {
+ struct Reloc *next;
+ int32_t posn;
+ int32_t bytes;
+ int32_t secref;
+ int32_t secrel;
+ struct Section *target;
+} *relocs, **reloctail;
+
+static uint64_t origin;
+static int origin_defined;
+
+/* Stuff we need for map-file generation. */
+#define MAP_ORIGIN 1
+#define MAP_SUMMARY 2
+#define MAP_SECTIONS 4
+#define MAP_SYMBOLS 8
+static int map_control = 0;
+
+extern macros_t bin_stdmac[];
+
+static void add_reloc(struct Section *s, int32_t bytes, int32_t secref,
+ int32_t secrel)
+{
+ struct Reloc *r;
+
+ r = *reloctail = nasm_malloc(sizeof(struct Reloc));
+ reloctail = &r->next;
+ r->next = NULL;
+ r->posn = s->length;
+ r->bytes = bytes;
+ r->secref = secref;
+ r->secrel = secrel;
+ r->target = s;
+}
+
+static struct Section *find_section_by_name(const char *name)
+{
+ struct Section *s;
+
+ list_for_each(s, sections)
+ if (!strcmp(s->name, name))
+ break;
+ return s;
+}
+
+static struct Section *find_section_by_index(int32_t index)
+{
+ struct Section *s;
+
+ list_for_each(s, sections)
+ if ((index == s->vstart_index) || (index == s->start_index))
+ break;
+ return s;
+}
+
+static struct Section *create_section(char *name)
+{
+ struct Section *s = nasm_zalloc(sizeof(*s));
+
+ s->prev = last_section;
+ s->name = nasm_strdup(name);
+ s->labels_end = &(s->labels);
+ s->contents = saa_init(1L);
+
+ /* Register our sections with NASM. */
+ s->vstart_index = seg_alloc();
+ s->start_index = seg_alloc();
+
+ /* FIXME: Append to a tail, we need some helper */
+ last_section->next = s;
+ last_section = s;
+
+ return last_section;
+}
+
+static void bin_cleanup(void)
+{
+ struct Section *g, **gp;
+ struct Section *gs = NULL, **gsp;
+ struct Section *s, **sp;
+ struct Section *nobits = NULL, **nt;
+ struct Section *last_progbits;
+ struct bin_label *l;
+ struct Reloc *r;
+ uint64_t pend;
+ int h;
+
+ if (debug_level(1)) {
+ nasm_debug("bin_cleanup: Sections were initially referenced in this order:\n");
+ for (h = 0, s = sections; s; h++, s = s->next)
+ nasm_debug("%i. %s\n", h, s->name);
+ }
+
+ /* Assembly has completed, so now we need to generate the output file.
+ * Step 1: Separate progbits and nobits sections into separate lists.
+ * Step 2: Sort the progbits sections into their output order.
+ * Step 3: Compute start addresses for all progbits sections.
+ * Step 4: Compute vstart addresses for all sections.
+ * Step 5: Apply relocations.
+ * Step 6: Write the sections' data to the output file.
+ * Step 7: Generate the map file.
+ * Step 8: Release all allocated memory.
+ */
+
+ /* To do: Smart section-type adaptation could leave some empty sections
+ * without a defined type (progbits/nobits). Won't fix now since this
+ * feature will be disabled. */
+
+ /* Step 1: Split progbits and nobits sections into separate lists. */
+
+ nt = &nobits;
+ /* Move nobits sections into a separate list. Also pre-process nobits
+ * sections' attributes. */
+ for (sp = &sections->next, s = sections->next; s; s = *sp) { /* Skip progbits sections. */
+ if (s->flags & TYPE_PROGBITS) {
+ sp = &s->next;
+ continue;
+ }
+ /* Do some special pre-processing on nobits sections' attributes. */
+ if (s->flags & (START_DEFINED | ALIGN_DEFINED | FOLLOWS_DEFINED)) { /* Check for a mixture of real and virtual section attributes. */
+ if (s->flags & (VSTART_DEFINED | VALIGN_DEFINED |
+ VFOLLOWS_DEFINED))
+ nasm_fatal("cannot mix real and virtual attributes"
+ " in nobits section (%s)", s->name);
+ /* Real and virtual attributes mean the same thing for nobits sections. */
+ if (s->flags & START_DEFINED) {
+ s->vstart = s->start;
+ s->flags |= VSTART_DEFINED;
+ }
+ if (s->flags & ALIGN_DEFINED) {
+ s->valign = s->align;
+ s->flags |= VALIGN_DEFINED;
+ }
+ if (s->flags & FOLLOWS_DEFINED) {
+ s->vfollows = s->follows;
+ s->flags |= VFOLLOWS_DEFINED;
+ s->flags &= ~FOLLOWS_DEFINED;
+ }
+ }
+ /* Every section must have a start address. */
+ if (s->flags & VSTART_DEFINED) {
+ s->start = s->vstart;
+ s->flags |= START_DEFINED;
+ }
+ /* Move the section into the nobits list. */
+ *sp = s->next;
+ s->next = NULL;
+ *nt = s;
+ nt = &s->next;
+ }
+
+ /* Step 2: Sort the progbits sections into their output order. */
+
+ /* In Step 2 we move around sections in groups. A group
+ * begins with a section (group leader) that has a user-
+ * defined start address or follows section. The remainder
+ * of the group is made up of the sections that implicitly
+ * follow the group leader (i.e., they were defined after
+ * the group leader and were not given an explicit start
+ * address or follows section by the user). */
+
+ /* For anyone attempting to read this code:
+ * g (group) points to a group of sections, the first one of which has
+ * a user-defined start address or follows section.
+ * gp (g previous) holds the location of the pointer to g.
+ * gs (g scan) is a temp variable that we use to scan to the end of the group.
+ * gsp (gs previous) holds the location of the pointer to gs.
+ * nt (nobits tail) points to the nobits section-list tail.
+ */
+
+ /* Link all 'follows' groups to their proper position. To do
+ * this we need to know three things: the start of the group
+ * to relocate (g), the section it is following (s), and the
+ * end of the group we're relocating (gs). */
+ for (gp = &sections, g = sections; g; g = gs) { /* Find the next follows group that is out of place (g). */
+ if (!(g->flags & FOLLOWS_DEFINED)) {
+ while (g->next) {
+ if ((g->next->flags & FOLLOWS_DEFINED) &&
+ strcmp(g->name, g->next->follows))
+ break;
+ g = g->next;
+ }
+ if (!g->next)
+ break;
+ gp = &g->next;
+ g = g->next;
+ }
+ /* Find the section that this group follows (s). */
+ for (sp = &sections, s = sections;
+ s && strcmp(s->name, g->follows);
+ sp = &s->next, s = s->next) ;
+ if (!s)
+ nasm_fatal("section %s follows an invalid or"
+ " unknown section (%s)", g->name, g->follows);
+ if (s == g)
+ nasm_fatal("section %s is self following", s->name);
+ if (s->next && (s->next->flags & FOLLOWS_DEFINED) &&
+ !strcmp(s->name, s->next->follows))
+ nasm_fatal("sections %s and %s can't both follow"
+ " section %s", g->name, s->next->name, s->name);
+ /* Find the end of the current follows group (gs). */
+ for (gsp = &g->next, gs = g->next;
+ gs && (gs != s) && !(gs->flags & START_DEFINED);
+ gsp = &gs->next, gs = gs->next) {
+ if (gs->next && (gs->next->flags & FOLLOWS_DEFINED) &&
+ strcmp(gs->name, gs->next->follows)) {
+ gsp = &gs->next;
+ gs = gs->next;
+ break;
+ }
+ }
+ /* Re-link the group after its follows section. */
+ *gsp = s->next;
+ s->next = g;
+ *gp = gs;
+ }
+
+ /* Link all 'start' groups to their proper position. Once
+ * again we need to know g, s, and gs (see above). The main
+ * difference is we already know g since we sort by moving
+ * groups from the 'unsorted' list into a 'sorted' list (g
+ * will always be the first section in the unsorted list). */
+ for (g = sections, sections = NULL; g; g = gs) { /* Find the section that we will insert this group before (s). */
+ for (sp = &sections, s = sections; s; sp = &s->next, s = s->next)
+ if ((s->flags & START_DEFINED) && (g->start < s->start))
+ break;
+ /* Find the end of the group (gs). */
+ for (gs = g->next, gsp = &g->next;
+ gs && !(gs->flags & START_DEFINED);
+ gsp = &gs->next, gs = gs->next) ;
+ /* Re-link the group before the target section. */
+ *sp = g;
+ *gsp = s;
+ }
+
+ /* Step 3: Compute start addresses for all progbits sections. */
+
+ /* Make sure we have an origin and a start address for the first section. */
+ if (origin_defined) {
+ if (sections->flags & START_DEFINED) {
+ /* Make sure this section doesn't begin before the origin. */
+ if (sections->start < origin)
+ nasm_fatal("section %s begins"
+ " before program origin", sections->name);
+ } else if (sections->flags & ALIGN_DEFINED) {
+ sections->start = ALIGN(origin, sections->align);
+ } else {
+ sections->start = origin;
+ }
+ } else {
+ if (!(sections->flags & START_DEFINED))
+ sections->start = 0;
+ origin = sections->start;
+ }
+ sections->flags |= START_DEFINED;
+
+ /* Make sure each section has an explicit start address. If it
+ * doesn't, then compute one based its alignment and the end of
+ * the previous section. */
+ for (pend = sections->start, g = s = sections; g; g = g->next) { /* Find the next section that could cause an overlap situation
+ * (has a defined start address, and is not zero length). */
+ if (g == s)
+ for (s = g->next;
+ s && ((s->length == 0) || !(s->flags & START_DEFINED));
+ s = s->next) ;
+ /* Compute the start address of this section, if necessary. */
+ if (!(g->flags & START_DEFINED)) { /* Default to an alignment of 4 if unspecified. */
+ if (!(g->flags & ALIGN_DEFINED)) {
+ g->align = 4;
+ g->flags |= ALIGN_DEFINED;
+ }
+ /* Set the section start address. */
+ g->start = ALIGN(pend, g->align);
+ g->flags |= START_DEFINED;
+ }
+ /* Ugly special case for progbits sections' virtual attributes:
+ * If there is a defined valign, but no vstart and no vfollows, then
+ * we valign after the previous progbits section. This case doesn't
+ * really make much sense for progbits sections with a defined start
+ * address, but it is possible and we must do *something*.
+ * Not-so-ugly special case:
+ * If a progbits section has no virtual attributes, we set the
+ * vstart equal to the start address. */
+ if (!(g->flags & (VSTART_DEFINED | VFOLLOWS_DEFINED))) {
+ if (g->flags & VALIGN_DEFINED)
+ g->vstart = ALIGN(pend, g->valign);
+ else
+ g->vstart = g->start;
+ g->flags |= VSTART_DEFINED;
+ }
+ /* Ignore zero-length sections. */
+ if (g->start < pend)
+ continue;
+ /* Compute the span of this section. */
+ pend = g->start + g->length;
+ /* Check for section overlap. */
+ if (s) {
+ if (s->start < origin)
+ nasm_fatal("section %s beings before program origin",
+ s->name);
+ if (g->start > s->start)
+ nasm_fatal("sections %s ~ %s and %s overlap!",
+ gs->name, g->name, s->name);
+ if (pend > s->start)
+ nasm_fatal("sections %s and %s overlap!",
+ g->name, s->name);
+ }
+ /* Remember this section as the latest >0 length section. */
+ gs = g;
+ }
+
+ /* Step 4: Compute vstart addresses for all sections. */
+
+ /* Attach the nobits sections to the end of the progbits sections. */
+ for (s = sections; s->next; s = s->next) ;
+ s->next = nobits;
+ last_progbits = s;
+ /*
+ * Scan for sections that don't have a vstart address. If we find
+ * one we'll attempt to compute its vstart. If we can't compute
+ * the vstart, we leave it alone and come back to it in a
+ * subsequent scan. We continue scanning and re-scanning until
+ * we've gone one full cycle without computing any vstarts.
+ */
+ do { /* Do one full scan of the sections list. */
+ for (h = 0, g = sections; g; g = g->next) {
+ if (g->flags & VSTART_DEFINED)
+ continue;
+ /* Find the section that this one virtually follows. */
+ if (g->flags & VFOLLOWS_DEFINED) {
+ for (s = sections; s && strcmp(g->vfollows, s->name);
+ s = s->next) ;
+ if (!s)
+ nasm_fatal("section %s vfollows unknown section (%s)",
+ g->name, g->vfollows);
+ } else if (g->prev != NULL)
+ for (s = sections; s && (s != g->prev); s = s->next) ;
+ /* The .bss section is the only one with prev = NULL.
+ In this case we implicitly follow the last progbits
+ section. */
+ else
+ s = last_progbits;
+
+ /* If the section we're following has a vstart, we can proceed. */
+ if (s->flags & VSTART_DEFINED) { /* Default to virtual alignment of four. */
+ if (!(g->flags & VALIGN_DEFINED)) {
+ g->valign = 4;
+ g->flags |= VALIGN_DEFINED;
+ }
+ /* Compute the vstart address. */
+ g->vstart = ALIGN(s->vstart + s->length, g->valign);
+ g->flags |= VSTART_DEFINED;
+ h++;
+ /* Start and vstart mean the same thing for nobits sections. */
+ if (g->flags & TYPE_NOBITS)
+ g->start = g->vstart;
+ }
+ }
+ } while (h);
+
+ /* Now check for any circular vfollows references, which will manifest
+ * themselves as sections without a defined vstart. */
+ for (h = 0, s = sections; s; s = s->next) {
+ if (!(s->flags & VSTART_DEFINED)) { /* Non-fatal errors after assembly has completed are generally a
+ * no-no, but we'll throw a fatal one eventually so it's ok. */
+ nasm_nonfatal("cannot compute vstart for section %s", s->name);
+ h++;
+ }
+ }
+ if (h)
+ nasm_fatal("circular vfollows path detected");
+
+ if (debug_level(1)) {
+ nasm_debug("bin_cleanup: Confirm final section order for output file:\n");
+ for (h = 0, s = sections; s && (s->flags & TYPE_PROGBITS);
+ h++, s = s->next)
+ nasm_debug("%i. %s\n", h, s->name);
+ }
+
+ /* Step 5: Apply relocations. */
+
+ /* Prepare the sections for relocating. */
+ list_for_each(s, sections)
+ saa_rewind(s->contents);
+ /* Apply relocations. */
+ list_for_each(r, relocs) {
+ uint8_t *p, mydata[8];
+ int64_t l;
+ int b;
+
+ nasm_assert(r->bytes <= 8);
+
+ memset(mydata, 0, sizeof(mydata));
+
+ saa_fread(r->target->contents, r->posn, mydata, r->bytes);
+ p = mydata;
+ l = 0;
+ for (b = r->bytes - 1; b >= 0; b--)
+ l = (l << 8) + mydata[b];
+
+ s = find_section_by_index(r->secref);
+ if (s) {
+ if (r->secref == s->start_index)
+ l += s->start;
+ else
+ l += s->vstart;
+ }
+ s = find_section_by_index(r->secrel);
+ if (s) {
+ if (r->secrel == s->start_index)
+ l -= s->start;
+ else
+ l -= s->vstart;
+ }
+
+ WRITEADDR(p, l, r->bytes);
+ saa_fwrite(r->target->contents, r->posn, mydata, r->bytes);
+ }
+
+ /* Step 6: Write the section data to the output file. */
+ do_output();
+
+ /* Step 7: Generate the map file. */
+
+ if (map_control) {
+ static const char not_defined[] = "not defined";
+
+ /* Display input and output file names. */
+ fprintf(rf, "\n- NASM Map file ");
+ for (h = 63; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n",
+ inname, outname);
+
+ if (map_control & MAP_ORIGIN) { /* Display program origin. */
+ fprintf(rf, "-- Program origin ");
+ for (h = 61; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\n%08"PRIX64"\n\n", origin);
+ }
+ /* Display sections summary. */
+ if (map_control & MAP_SUMMARY) {
+ fprintf(rf, "-- Sections (summary) ");
+ for (h = 57; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\nVstart Start Stop "
+ "Length Class Name\n");
+ list_for_each(s, sections) {
+ fprintf(rf, "%16"PRIX64" %16"PRIX64" %16"PRIX64" %08"PRIX64" ",
+ s->vstart, s->start, s->start + s->length,
+ s->length);
+ if (s->flags & TYPE_PROGBITS)
+ fprintf(rf, "progbits ");
+ else
+ fprintf(rf, "nobits ");
+ fprintf(rf, "%s\n", s->name);
+ }
+ fprintf(rf, "\n");
+ }
+ /* Display detailed section information. */
+ if (map_control & MAP_SECTIONS) {
+ fprintf(rf, "-- Sections (detailed) ");
+ for (h = 56; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\n");
+ list_for_each(s, sections) {
+ fprintf(rf, "---- Section %s ", s->name);
+ if (strlen(s->name) < 65)
+ for (h = 65 - strlen(s->name); h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\nclass: ");
+ if (s->flags & TYPE_PROGBITS)
+ fprintf(rf, "progbits");
+ else
+ fprintf(rf, "nobits");
+ fprintf(rf, "\nlength: %16"PRIX64"\nstart: %16"PRIX64""
+ "\nalign: ", s->length, s->start);
+ if (s->flags & ALIGN_DEFINED)
+ fprintf(rf, "%16"PRIX64"", s->align);
+ else
+ fputs(not_defined, rf);
+ fprintf(rf, "\nfollows: ");
+ if (s->flags & FOLLOWS_DEFINED)
+ fprintf(rf, "%s", s->follows);
+ else
+ fputs(not_defined, rf);
+ fprintf(rf, "\nvstart: %16"PRIX64"\nvalign: ", s->vstart);
+ if (s->flags & VALIGN_DEFINED)
+ fprintf(rf, "%16"PRIX64"", s->valign);
+ else
+ fputs(not_defined, rf);
+ fprintf(rf, "\nvfollows: ");
+ if (s->flags & VFOLLOWS_DEFINED)
+ fprintf(rf, "%s", s->vfollows);
+ else
+ fputs(not_defined, rf);
+ fprintf(rf, "\n\n");
+ }
+ }
+ /* Display symbols information. */
+ if (map_control & MAP_SYMBOLS) {
+ int32_t segment;
+ int64_t offset;
+ enum label_type found_label;
+
+ fprintf(rf, "-- Symbols ");
+ for (h = 68; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\n");
+ if (no_seg_labels) {
+ fprintf(rf, "---- No Section ");
+ for (h = 63; h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\nValue Name\n");
+ list_for_each(l, no_seg_labels) {
+ found_label = lookup_label(l->name, &segment, &offset);
+ nasm_assert(found_label != LBL_none);
+ fprintf(rf, "%08"PRIX64" %s\n", offset, l->name);
+ }
+ fprintf(rf, "\n\n");
+ }
+ list_for_each(s, sections) {
+ if (s->labels) {
+ fprintf(rf, "---- Section %s ", s->name);
+ for (h = 65 - strlen(s->name); h; h--)
+ fputc('-', rf);
+ fprintf(rf, "\n\nReal Virtual Name\n");
+ list_for_each(l, s->labels) {
+ found_label = lookup_label(l->name, &segment, &offset);
+ nasm_assert(found_label != LBL_none);
+ fprintf(rf, "%16"PRIX64" %16"PRIX64" %s\n",
+ s->start + offset, s->vstart + offset,
+ l->name);
+ }
+ fprintf(rf, "\n");
+ }
+ }
+ }
+ }
+
+ /* Close the report file. */
+ if (map_control && (rf != stdout) && (rf != stderr))
+ fclose(rf);
+
+ /* Step 8: Release all allocated memory. */
+
+ /* Free sections, label pointer structs, etc.. */
+ while (sections) {
+ s = sections;
+ sections = s->next;
+ saa_free(s->contents);
+ nasm_free(s->name);
+ if (s->flags & FOLLOWS_DEFINED)
+ nasm_free(s->follows);
+ if (s->flags & VFOLLOWS_DEFINED)
+ nasm_free(s->vfollows);
+ while (s->labels) {
+ l = s->labels;
+ s->labels = l->next;
+ nasm_free(l);
+ }
+ nasm_free(s);
+ }
+
+ /* Free no-section labels. */
+ while (no_seg_labels) {
+ l = no_seg_labels;
+ no_seg_labels = l->next;
+ nasm_free(l);
+ }
+
+ /* Free relocation structures. */
+ while (relocs) {
+ r = relocs->next;
+ nasm_free(relocs);
+ relocs = r;
+ }
+}
+
+static void bin_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ uint8_t *p, mydata[8];
+ struct Section *s;
+
+ if (wrt != NO_SEG) {
+ wrt = NO_SEG; /* continue to do _something_ */
+ nasm_nonfatal("WRT not supported by binary output format");
+ }
+
+ /* Find the segment we are targeting. */
+ s = find_section_by_index(segto);
+ if (!s)
+ nasm_panic("code directed to nonexistent segment?");
+
+ /* "Smart" section-type adaptation code. */
+ if (!(s->flags & TYPE_DEFINED)) {
+ if (type == OUT_RESERVE)
+ s->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ else
+ s->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ }
+
+ if ((s->flags & TYPE_NOBITS) && (type != OUT_RESERVE))
+ nasm_warn(WARN_OTHER, "attempt to initialize memory in a"
+ " nobits section: ignored");
+
+ switch (type) {
+ case OUT_ADDRESS:
+ {
+ int asize = abs((int)size);
+
+ if (segment != NO_SEG && !find_section_by_index(segment)) {
+ if (segment % 2)
+ nasm_nonfatal("binary output format does not support"
+ " segment base references");
+ else
+ nasm_nonfatal("binary output format does not support"
+ " external references");
+ segment = NO_SEG;
+ }
+ if (s->flags & TYPE_PROGBITS) {
+ if (segment != NO_SEG)
+ add_reloc(s, asize, segment, -1L);
+ p = mydata;
+ WRITEADDR(p, *(int64_t *)data, asize);
+ saa_wbytes(s->contents, mydata, asize);
+ }
+
+ /*
+ * Reassign size with sign dropped, we will need it
+ * for section length calculation.
+ */
+ size = asize;
+ break;
+ }
+
+ case OUT_RAWDATA:
+ if (s->flags & TYPE_PROGBITS)
+ saa_wbytes(s->contents, data, size);
+ break;
+
+ case OUT_RESERVE:
+ if (s->flags & TYPE_PROGBITS) {
+ nasm_warn(WARN_ZEROING, "uninitialized space declared in"
+ " %s section: zeroing", s->name);
+ saa_wbytes(s->contents, NULL, size);
+ }
+ break;
+
+ case OUT_REL1ADR:
+ case OUT_REL2ADR:
+ case OUT_REL4ADR:
+ case OUT_REL8ADR:
+ {
+ int64_t addr = *(int64_t *)data - size;
+ size = realsize(type, size);
+ if (segment != NO_SEG && !find_section_by_index(segment)) {
+ if (segment % 2)
+ nasm_nonfatal("binary output format does not support"
+ " segment base references");
+ else
+ nasm_nonfatal("binary output format does not support"
+ " external references");
+ segment = NO_SEG;
+ }
+ if (s->flags & TYPE_PROGBITS) {
+ add_reloc(s, size, segment, segto);
+ p = mydata;
+ WRITEADDR(p, addr - s->length, size);
+ saa_wbytes(s->contents, mydata, size);
+ }
+ break;
+ }
+
+ default:
+ nasm_nonfatal("unsupported relocation type %d\n", type);
+ break;
+ }
+
+ s->length += size;
+}
+
+static void bin_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ (void)segment; /* Don't warn that this parameter is unused */
+ (void)offset; /* Don't warn that this parameter is unused */
+
+ if (special)
+ nasm_nonfatal("binary format does not support any"
+ " special symbol types");
+ else if (name[0] == '.' && name[1] == '.' && name[2] != '@')
+ nasm_nonfatal("unrecognised special symbol `%s'", name);
+ else if (is_global == 2)
+ nasm_nonfatal("binary output format does not support common"
+ " variables");
+ else {
+ struct Section *s;
+ struct bin_label ***ltp;
+
+ /* Remember label definition so we can look it up later when
+ * creating the map file. */
+ s = find_section_by_index(segment);
+ if (s)
+ ltp = &(s->labels_end);
+ else
+ ltp = &nsl_tail;
+ (**ltp) = nasm_malloc(sizeof(struct bin_label));
+ (**ltp)->name = name;
+ (**ltp)->next = NULL;
+ *ltp = &((**ltp)->next);
+ }
+
+}
+
+/* These constants and the following function are used
+ * by bin_secname() to parse attribute assignments. */
+
+enum { ATTRIB_START, ATTRIB_ALIGN, ATTRIB_FOLLOWS,
+ ATTRIB_VSTART, ATTRIB_VALIGN, ATTRIB_VFOLLOWS,
+ ATTRIB_NOBITS, ATTRIB_PROGBITS
+};
+
+static int bin_read_attribute(char **line, int *attribute,
+ uint64_t *value)
+{
+ expr *e;
+ int attrib_name_size;
+ struct tokenval tokval;
+ char *exp;
+
+ /* Skip whitespace. */
+ while (**line && nasm_isspace(**line))
+ (*line)++;
+ if (!**line)
+ return 0;
+
+ /* Figure out what attribute we're reading. */
+ if (!nasm_strnicmp(*line, "align=", 6)) {
+ *attribute = ATTRIB_ALIGN;
+ attrib_name_size = 6;
+ } else {
+ if (!nasm_strnicmp(*line, "start=", 6)) {
+ *attribute = ATTRIB_START;
+ attrib_name_size = 6;
+ } else if (!nasm_strnicmp(*line, "follows=", 8)) {
+ *attribute = ATTRIB_FOLLOWS;
+ *line += 8;
+ return 1;
+ } else if (!nasm_strnicmp(*line, "vstart=", 7)) {
+ *attribute = ATTRIB_VSTART;
+ attrib_name_size = 7;
+ } else if (!nasm_strnicmp(*line, "valign=", 7)) {
+ *attribute = ATTRIB_VALIGN;
+ attrib_name_size = 7;
+ } else if (!nasm_strnicmp(*line, "vfollows=", 9)) {
+ *attribute = ATTRIB_VFOLLOWS;
+ *line += 9;
+ return 1;
+ } else if (!nasm_strnicmp(*line, "nobits", 6) &&
+ (nasm_isspace((*line)[6]) || ((*line)[6] == '\0'))) {
+ *attribute = ATTRIB_NOBITS;
+ *line += 6;
+ return 1;
+ } else if (!nasm_strnicmp(*line, "progbits", 8) &&
+ (nasm_isspace((*line)[8]) || ((*line)[8] == '\0'))) {
+ *attribute = ATTRIB_PROGBITS;
+ *line += 8;
+ return 1;
+ } else
+ return 0;
+ }
+
+ /* Find the end of the expression. */
+ if ((*line)[attrib_name_size] != '(') {
+ /* Single term (no parenthesis). */
+ exp = *line += attrib_name_size;
+ while (**line && !nasm_isspace(**line))
+ (*line)++;
+ if (**line) {
+ **line = '\0';
+ (*line)++;
+ }
+ } else {
+ char c;
+ int pcount = 1;
+
+ /* Full expression (delimited by parenthesis) */
+ exp = *line += attrib_name_size + 1;
+ while (1) {
+ (*line) += strcspn(*line, "()'\"");
+ if (**line == '(') {
+ ++(*line);
+ ++pcount;
+ }
+ if (**line == ')') {
+ ++(*line);
+ --pcount;
+ if (!pcount)
+ break;
+ }
+ if ((**line == '"') || (**line == '\'')) {
+ c = **line;
+ while (**line) {
+ ++(*line);
+ if (**line == c)
+ break;
+ }
+ if (!**line) {
+ nasm_nonfatal("invalid syntax in `section' directive");
+ return -1;
+ }
+ ++(*line);
+ }
+ if (!**line) {
+ nasm_nonfatal("expecting `)'");
+ return -1;
+ }
+ }
+ *(*line - 1) = '\0'; /* Terminate the expression. */
+ }
+
+ /* Check for no value given. */
+ if (!*exp) {
+ nasm_warn(WARN_OTHER, "No value given to attribute in"
+ " `section' directive");
+ return -1;
+ }
+
+ /* Read and evaluate the expression. */
+ stdscan_reset();
+ stdscan_set(exp);
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL);
+ if (e) {
+ if (!is_really_simple(e)) {
+ nasm_nonfatal("section attribute value must be"
+ " a critical expression");
+ return -1;
+ }
+ } else {
+ nasm_nonfatal("Invalid attribute value"
+ " specified in `section' directive.");
+ return -1;
+ }
+ *value = (uint64_t)reloc_value(e);
+ return 1;
+}
+
+static void bin_sectalign(int32_t seg, unsigned int value)
+{
+ struct Section *s = find_section_by_index(seg);
+
+ if (!s || !is_power2(value))
+ return;
+
+ if (value > s->align)
+ s->align = value;
+
+ if (!(s->flags & ALIGN_DEFINED))
+ s->flags |= ALIGN_DEFINED;
+}
+
+static void bin_assign_attributes(struct Section *sec, char *astring)
+{
+ int attribute, check;
+ uint64_t value;
+ char *p;
+
+ while (1) { /* Get the next attribute. */
+ check = bin_read_attribute(&astring, &attribute, &value);
+ /* Skip bad attribute. */
+ if (check == -1)
+ continue;
+ /* Unknown section attribute, so skip it and warn the user. */
+ if (!check) {
+ if (!*astring)
+ break; /* End of line. */
+ else {
+ p = astring;
+ while (*astring && !nasm_isspace(*astring))
+ astring++;
+ if (*astring) {
+ *astring = '\0';
+ astring++;
+ }
+ nasm_warn(WARN_OTHER, "ignoring unknown section attribute: \"%s\"", p);
+ }
+ continue;
+ }
+
+ switch (attribute) { /* Handle nobits attribute. */
+ case ATTRIB_NOBITS:
+ if ((sec->flags & TYPE_DEFINED)
+ && (sec->flags & TYPE_PROGBITS))
+ nasm_nonfatal("attempt to change section type"
+ " from progbits to nobits");
+ else
+ sec->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ continue;
+
+ /* Handle progbits attribute. */
+ case ATTRIB_PROGBITS:
+ if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_NOBITS))
+ nasm_nonfatal("attempt to change section type"
+ " from nobits to progbits");
+ else
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ continue;
+
+ /* Handle align attribute. */
+ case ATTRIB_ALIGN:
+ if (!value || ((value - 1) & value)) {
+ nasm_nonfatal("argument to `align' is not a power of two");
+ } else {
+ /*
+ * Alignment is already satisfied if
+ * the previous align value is greater
+ */
+ if ((sec->flags & ALIGN_DEFINED) && (value < sec->align))
+ value = sec->align;
+
+ /* Don't allow a conflicting align value. */
+ if ((sec->flags & START_DEFINED) && (sec->start & (value - 1))) {
+ nasm_nonfatal("`align' value conflicts with section start address");
+ } else {
+ sec->align = value;
+ sec->flags |= ALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle valign attribute. */
+ case ATTRIB_VALIGN:
+ if (!value || ((value - 1) & value))
+ nasm_nonfatal("argument to `valign' is not a power of two");
+ else { /* Alignment is already satisfied if the previous
+ * align value is greater. */
+ if ((sec->flags & VALIGN_DEFINED) && (value < sec->valign))
+ value = sec->valign;
+
+ /* Don't allow a conflicting valign value. */
+ if ((sec->flags & VSTART_DEFINED)
+ && (sec->vstart & (value - 1)))
+ nasm_nonfatal("`valign' value conflicts with `vstart' address");
+ else {
+ sec->valign = value;
+ sec->flags |= VALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle start attribute. */
+ case ATTRIB_START:
+ if (sec->flags & FOLLOWS_DEFINED)
+ nasm_nonfatal("cannot combine `start' and `follows'"
+ " section attributes");
+ else if ((sec->flags & START_DEFINED) && (value != sec->start))
+ nasm_nonfatal("section start address redefined");
+ else {
+ sec->start = value;
+ sec->flags |= START_DEFINED;
+ if (sec->flags & ALIGN_DEFINED) {
+ if (sec->start & (sec->align - 1))
+ nasm_nonfatal("`start' address conflicts"
+ " with section alignment");
+ sec->flags ^= ALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle vstart attribute. */
+ case ATTRIB_VSTART:
+ if (sec->flags & VFOLLOWS_DEFINED)
+ nasm_nonfatal("cannot combine `vstart' and `vfollows'"
+ " section attributes");
+ else if ((sec->flags & VSTART_DEFINED)
+ && (value != sec->vstart))
+ nasm_nonfatal("section virtual start address"
+ " (vstart) redefined");
+ else {
+ sec->vstart = value;
+ sec->flags |= VSTART_DEFINED;
+ if (sec->flags & VALIGN_DEFINED) {
+ if (sec->vstart & (sec->valign - 1))
+ nasm_nonfatal("`vstart' address conflicts"
+ " with `valign' value");
+ sec->flags ^= VALIGN_DEFINED;
+ }
+ }
+ continue;
+
+ /* Handle follows attribute. */
+ case ATTRIB_FOLLOWS:
+ p = astring;
+ astring += strcspn(astring, " \t");
+ if (astring == p)
+ nasm_nonfatal("expecting section name for `follows'"
+ " attribute");
+ else {
+ *(astring++) = '\0';
+ if (sec->flags & START_DEFINED)
+ nasm_nonfatal("cannot combine `start' and `follows'"
+ " section attributes");
+ sec->follows = nasm_strdup(p);
+ sec->flags |= FOLLOWS_DEFINED;
+ }
+ continue;
+
+ /* Handle vfollows attribute. */
+ case ATTRIB_VFOLLOWS:
+ if (sec->flags & VSTART_DEFINED)
+ nasm_nonfatal("cannot combine `vstart' and `vfollows'"
+ " section attributes");
+ else {
+ p = astring;
+ astring += strcspn(astring, " \t");
+ if (astring == p)
+ nasm_nonfatal("expecting section name for `vfollows'"
+ " attribute");
+ else {
+ *(astring++) = '\0';
+ sec->vfollows = nasm_strdup(p);
+ sec->flags |= VFOLLOWS_DEFINED;
+ }
+ }
+ continue;
+ }
+ }
+}
+
+static void bin_define_section_labels(void)
+{
+ static int labels_defined = 0;
+ struct Section *sec;
+ char *label_name;
+ size_t base_len;
+
+ if (labels_defined)
+ return;
+ list_for_each(sec, sections) {
+ base_len = strlen(sec->name) + 8;
+ label_name = nasm_malloc(base_len + 8);
+ strcpy(label_name, "section.");
+ strcpy(label_name + 8, sec->name);
+
+ /* section.<name>.start */
+ strcpy(label_name + base_len, ".start");
+ define_label(label_name, sec->start_index, 0L, false);
+
+ /* section.<name>.vstart */
+ strcpy(label_name + base_len, ".vstart");
+ define_label(label_name, sec->vstart_index, 0L, false);
+
+ nasm_free(label_name);
+ }
+ labels_defined = 1;
+}
+
+static int32_t bin_secname(char *name, int *bits)
+{
+ char *p;
+ struct Section *sec;
+
+ /* bin_secname is called with *name = NULL at the start of each
+ * pass. Use this opportunity to establish the default section
+ * (default is BITS-16 ".text" segment).
+ */
+ if (!name) {
+ /* Reset ORG and section attributes at the start of each pass. */
+ origin_defined = 0;
+ list_for_each(sec, sections)
+ sec->flags &= ~(START_DEFINED | VSTART_DEFINED |
+ ALIGN_DEFINED | VALIGN_DEFINED);
+
+ /* Define section start and vstart labels. */
+ if (!pass_first())
+ bin_define_section_labels();
+
+ /* Establish the default (.text) section. */
+ *bits = 16;
+ sec = find_section_by_name(".text");
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ return sec->vstart_index;
+ }
+
+ /* Attempt to find the requested section. If it does not
+ * exist, create it. */
+ p = name;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ sec = find_section_by_name(name);
+ if (!sec) {
+ sec = create_section(name);
+ if (!strcmp(name, ".data"))
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+ else if (!strcmp(name, ".bss")) {
+ sec->flags |= TYPE_DEFINED | TYPE_NOBITS;
+ sec->prev = NULL;
+ }
+ }
+
+ /* Handle attribute assignments. */
+ if (!pass_first())
+ bin_assign_attributes(sec, p);
+
+#ifndef ABIN_SMART_ADAPT
+ /* The following line disables smart adaptation of
+ * PROGBITS/NOBITS section types (it forces sections to
+ * default to PROGBITS). */
+ if (!pass_first() && !(sec->flags & TYPE_DEFINED))
+ sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
+#endif
+
+ return sec->vstart_index;
+}
+
+static enum directive_result
+bin_directive(enum directive directive, char *args)
+{
+ switch (directive) {
+ case D_ORG:
+ {
+ struct tokenval tokval;
+ uint64_t value;
+ expr *e;
+
+ stdscan_reset();
+ stdscan_set(args);
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL);
+ if (e) {
+ if (!is_really_simple(e))
+ nasm_nonfatal("org value must be a critical"
+ " expression");
+ else {
+ value = reloc_value(e);
+ /* Check for ORG redefinition. */
+ if (origin_defined && (value != origin))
+ nasm_nonfatal("program origin redefined");
+ else {
+ origin = value;
+ origin_defined = 1;
+ }
+ }
+ } else
+ nasm_nonfatal("No or invalid offset specified"
+ " in ORG directive.");
+ return DIRR_OK;
+ }
+ case D_MAP:
+ {
+ /* The 'map' directive allows the user to generate section
+ * and symbol information to stdout, stderr, or to a file. */
+ char *p;
+
+ if (!pass_first())
+ return DIRR_OK;
+ args += strspn(args, " \t");
+ while (*args) {
+ p = args;
+ args += strcspn(args, " \t");
+ if (*args != '\0')
+ *(args++) = '\0';
+ if (!nasm_stricmp(p, "all"))
+ map_control |=
+ MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS | MAP_SYMBOLS;
+ else if (!nasm_stricmp(p, "brief"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY;
+ else if (!nasm_stricmp(p, "sections"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS;
+ else if (!nasm_stricmp(p, "segments"))
+ map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS;
+ else if (!nasm_stricmp(p, "symbols"))
+ map_control |= MAP_SYMBOLS;
+ else if (!rf) {
+ if (!nasm_stricmp(p, "stdout"))
+ rf = stdout;
+ else if (!nasm_stricmp(p, "stderr"))
+ rf = stderr;
+ else { /* Must be a filename. */
+ rf = nasm_open_write(p, NF_TEXT);
+ if (!rf) {
+ nasm_warn(WARN_OTHER, "unable to open map file `%s'", p);
+ map_control = 0;
+ return DIRR_OK;
+ }
+ }
+ } else
+ nasm_warn(WARN_OTHER, "map file already specified");
+ }
+ if (map_control == 0)
+ map_control |= MAP_ORIGIN | MAP_SUMMARY;
+ if (!rf)
+ rf = stdout;
+ return DIRR_OK;
+ }
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+const struct ofmt of_bin, of_ith, of_srec;
+static void binfmt_init(void);
+static void do_output_bin(void);
+static void do_output_ith(void);
+static void do_output_srec(void);
+
+static void bin_init(void)
+{
+ do_output = do_output_bin;
+ binfmt_init();
+}
+
+static void ith_init(void)
+{
+ do_output = do_output_ith;
+ binfmt_init();
+}
+
+static void srec_init(void)
+{
+ do_output = do_output_srec;
+ binfmt_init();
+}
+
+static void binfmt_init(void)
+{
+ relocs = NULL;
+ reloctail = &relocs;
+ origin_defined = 0;
+ no_seg_labels = NULL;
+ nsl_tail = &no_seg_labels;
+
+ /* Create default section (.text). */
+ sections = last_section = nasm_zalloc(sizeof(struct Section));
+ last_section->name = nasm_strdup(".text");
+ last_section->contents = saa_init(1L);
+ last_section->flags = TYPE_DEFINED | TYPE_PROGBITS;
+ last_section->labels_end = &(last_section->labels);
+ last_section->start_index = seg_alloc();
+ last_section->vstart_index = seg_alloc();
+}
+
+/* Generate binary file output */
+static void do_output_bin(void)
+{
+ struct Section *s;
+ uint64_t addr = origin;
+
+ /* Write the progbits sections to the output file. */
+ list_for_each(s, sections) {
+ /* Skip non-progbits sections */
+ if (!(s->flags & TYPE_PROGBITS))
+ continue;
+ /* Skip zero-length sections */
+ if (s->length == 0)
+ continue;
+
+ /* Pad the space between sections. */
+ nasm_assert(addr <= s->start);
+ fwritezero(s->start - addr, ofile);
+
+ /* Write the section to the output file. */
+ saa_fpwrite(s->contents, ofile);
+
+ /* Keep track of the current file position */
+ addr = s->start + s->length;
+ }
+}
+
+/* Generate Intel hex file output */
+static void write_ith_record(unsigned int len, uint16_t addr,
+ uint8_t type, void *data)
+{
+ char buf[1+2+4+2+255*2+2+2];
+ char *p = buf;
+ uint8_t csum, *dptr = data;
+ unsigned int i;
+
+ nasm_assert(len <= 255);
+
+ csum = len + addr + (addr >> 8) + type;
+ for (i = 0; i < len; i++)
+ csum += dptr[i];
+ csum = -csum;
+
+ p += sprintf(p, ":%02X%04X%02X", len, addr, type);
+ for (i = 0; i < len; i++)
+ p += sprintf(p, "%02X", dptr[i]);
+ p += sprintf(p, "%02X\n", csum);
+
+ nasm_write(buf, p-buf, ofile);
+}
+
+static void do_output_ith(void)
+{
+ uint8_t buf[32];
+ struct Section *s;
+ uint64_t addr, hiaddr, hilba;
+ uint64_t length;
+ unsigned int chunk;
+
+ /* Write the progbits sections to the output file. */
+ hilba = 0;
+ list_for_each(s, sections) {
+ /* Skip non-progbits sections */
+ if (!(s->flags & TYPE_PROGBITS))
+ continue;
+ /* Skip zero-length sections */
+ if (s->length == 0)
+ continue;
+
+ addr = s->start;
+ length = s->length;
+ saa_rewind(s->contents);
+
+ while (length) {
+ hiaddr = addr >> 16;
+ if (hiaddr != hilba) {
+ buf[0] = hiaddr >> 8;
+ buf[1] = hiaddr;
+ write_ith_record(2, 0, 4, buf);
+ hilba = hiaddr;
+ }
+
+ chunk = 32 - (addr & 31);
+ if (length < chunk)
+ chunk = length;
+
+ saa_rnbytes(s->contents, buf, chunk);
+ write_ith_record(chunk, (uint16_t)addr, 0, buf);
+
+ addr += chunk;
+ length -= chunk;
+ }
+ }
+
+ /* Write closing record */
+ write_ith_record(0, 0, 1, NULL);
+}
+
+/* Generate Motorola S-records */
+static void write_srecord(unsigned int len, unsigned int alen,
+ uint32_t addr, uint8_t type, void *data)
+{
+ char buf[2+2+8+255*2+2+2];
+ char *p = buf;
+ uint8_t csum, *dptr = data;
+ unsigned int i;
+
+ nasm_assert(len <= 255);
+
+ switch (alen) {
+ case 2:
+ addr &= 0xffff;
+ break;
+ case 3:
+ addr &= 0xffffff;
+ break;
+ case 4:
+ break;
+ default:
+ panic();
+ break;
+ }
+
+ csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
+ for (i = 0; i < len; i++)
+ csum += dptr[i];
+ csum = 0xff-csum;
+
+ p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
+ for (i = 0; i < len; i++)
+ p += sprintf(p, "%02X", dptr[i]);
+ p += sprintf(p, "%02X\n", csum);
+
+ nasm_write(buf, p-buf, ofile);
+}
+
+static void do_output_srec(void)
+{
+ uint8_t buf[32];
+ struct Section *s;
+ uint64_t addr, maxaddr;
+ uint64_t length;
+ int alen;
+ unsigned int chunk;
+ char dtype, etype;
+
+ maxaddr = 0;
+ list_for_each(s, sections) {
+ /* Skip non-progbits sections */
+ if (!(s->flags & TYPE_PROGBITS))
+ continue;
+ /* Skip zero-length sections */
+ if (s->length == 0)
+ continue;
+
+ addr = s->start + s->length - 1;
+ if (addr > maxaddr)
+ maxaddr = addr;
+ }
+
+ if (maxaddr <= 0xffff) {
+ alen = 2;
+ dtype = '1'; /* S1 = 16-bit data */
+ etype = '9'; /* S9 = 16-bit end */
+ } else if (maxaddr <= 0xffffff) {
+ alen = 3;
+ dtype = '2'; /* S2 = 24-bit data */
+ etype = '8'; /* S8 = 24-bit end */
+ } else {
+ alen = 4;
+ dtype = '3'; /* S3 = 32-bit data */
+ etype = '7'; /* S7 = 32-bit end */
+ }
+
+ /* Write head record */
+ write_srecord(0, 2, 0, '0', NULL);
+
+ /* Write the progbits sections to the output file. */
+ list_for_each(s, sections) {
+ /* Skip non-progbits sections */
+ if (!(s->flags & TYPE_PROGBITS))
+ continue;
+ /* Skip zero-length sections */
+ if (s->length == 0)
+ continue;
+
+ addr = s->start;
+ length = s->length;
+ saa_rewind(s->contents);
+
+ while (length) {
+ chunk = 32 - (addr & 31);
+ if (length < chunk)
+ chunk = length;
+
+ saa_rnbytes(s->contents, buf, chunk);
+ write_srecord(chunk, alen, (uint32_t)addr, dtype, buf);
+
+ addr += chunk;
+ length -= chunk;
+ }
+ }
+
+ /* Write closing record */
+ write_srecord(0, alen, 0, etype, NULL);
+}
+
+
+const struct ofmt of_bin = {
+ "Flat raw binary (MS-DOS, embedded, ...)",
+ "bin",
+ "",
+ 0,
+ 64,
+ null_debug_arr,
+ &null_debug_form,
+ bin_stdmac,
+ bin_init,
+ null_reset,
+ nasm_do_legacy_output,
+ bin_out,
+ bin_deflabel,
+ bin_secname,
+ NULL,
+ bin_sectalign,
+ null_segbase,
+ bin_directive,
+ bin_cleanup,
+ NULL /* pragma list */
+};
+
+const struct ofmt of_ith = {
+ "Intel Hex encoded flat binary",
+ "ith",
+ ".ith", /* really should have been ".hex"... */
+ OFMT_TEXT,
+ 64,
+ null_debug_arr,
+ &null_debug_form,
+ bin_stdmac,
+ ith_init,
+ null_reset,
+ nasm_do_legacy_output,
+ bin_out,
+ bin_deflabel,
+ bin_secname,
+ NULL,
+ bin_sectalign,
+ null_segbase,
+ bin_directive,
+ bin_cleanup,
+ NULL /* pragma list */
+};
+
+const struct ofmt of_srec = {
+ "Motorola S-records encoded flat binary",
+ "srec",
+ ".srec",
+ OFMT_TEXT,
+ 64,
+ null_debug_arr,
+ &null_debug_form,
+ bin_stdmac,
+ srec_init,
+ null_reset,
+ nasm_do_legacy_output,
+ bin_out,
+ bin_deflabel,
+ bin_secname,
+ NULL,
+ bin_sectalign,
+ null_segbase,
+ bin_directive,
+ bin_cleanup,
+ NULL /* pragma list */
+};
+
+#endif /* #ifdef OF_BIN */
diff --git a/vere/ext/nasm/output/outbin.mac b/vere/ext/nasm/output/outbin.mac
new file mode 100644
index 0000000..99c15b6
--- /dev/null
+++ b/vere/ext/nasm/output/outbin.mac
@@ -0,0 +1,40 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2009 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: bin
+%define __?SECT?__ [section .text]
+%imacro org 1+.nolist
+[org %1]
+%endmacro
+%macro __?NASM_CDecl?__ 1
+%endmacro
diff --git a/vere/ext/nasm/output/outcoff.c b/vere/ext/nasm/output/outcoff.c
new file mode 100644
index 0000000..c2b4eb6
--- /dev/null
+++ b/vere/ext/nasm/output/outcoff.c
@@ -0,0 +1,1436 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outcoff.c output routines for the Netwide Assembler to produce
+ * COFF object files (for DJGPP and Win32)
+ */
+
+#include "compiler.h"
+
+#include "nctype.h"
+#include <time.h>
+#include "ver.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "ilog2.h"
+#include "error.h"
+#include "saa.h"
+#include "raa.h"
+#include "eval.h"
+#include "outform.h"
+#include "outlib.h"
+#include "pecoff.h"
+
+#if defined(OF_COFF) || defined(OF_WIN32) || defined(OF_WIN64)
+
+/*
+ * Notes on COFF:
+ *
+ * (0) When I say `standard COFF' below, I mean `COFF as output and
+ * used by DJGPP'. I assume DJGPP gets it right.
+ *
+ * (1) Win32 appears to interpret the term `relative relocation'
+ * differently from standard COFF. Standard COFF understands a
+ * relative relocation to mean that during relocation you add the
+ * address of the symbol you're referencing, and subtract the base
+ * address of the section you're in. Win32 COFF, by contrast, seems
+ * to add the address of the symbol and then subtract the address
+ * of THE BYTE AFTER THE RELOCATED DWORD. Hence the two formats are
+ * subtly incompatible.
+ *
+ * (2) Win32 doesn't bother putting any flags in the header flags
+ * field (at offset 0x12 into the file).
+ *
+ * (3) Win32/64 uses some extra flags into the section header table:
+ * it defines flags 0x80000000 (writable), 0x40000000 (readable)
+ * and 0x20000000 (executable), and uses them in the expected
+ * combinations. It also defines 0x00100000 through 0x00f00000 for
+ * section alignments of 1 through 8192 bytes.
+ *
+ * (4) Both standard COFF and Win32 COFF seem to use the DWORD
+ * field directly after the section name in the section header
+ * table for something strange: they store what the address of the
+ * section start point _would_ be, if you laid all the sections end
+ * to end starting at zero. Dunno why. Microsoft's documentation
+ * lists this field as "Virtual Size of Section", which doesn't
+ * seem to fit at all. In fact, Win32 even includes non-linked
+ * sections such as .drectve in this calculation.
+ *
+ * Newer versions of MASM seem to have changed this to be zero, and
+ * that apparently matches the COFF spec, so go with that.
+ *
+ * (5) Standard COFF does something very strange to common
+ * variables: the relocation point for a common variable is as far
+ * _before_ the variable as its size stretches out _after_ it. So
+ * we must fix up common variable references. Win32 seems to be
+ * sensible on this one.
+ */
+
+/* Flag which version of COFF we are currently outputting. */
+bool win32, win64;
+
+static int32_t imagebase_sect;
+#define WRT_IMAGEBASE "..imagebase"
+
+/*
+ * Some common section flags by default
+ */
+#define TEXT_FLAGS_WIN \
+ (IMAGE_SCN_CNT_CODE | \
+ IMAGE_SCN_ALIGN_16BYTES | \
+ IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_MEM_READ)
+#define TEXT_FLAGS_DOS \
+ (IMAGE_SCN_CNT_CODE)
+
+#define DATA_FLAGS_WIN \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_ALIGN_4BYTES | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE)
+#define DATA_FLAGS_DOS \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA)
+
+#define BSS_FLAGS_WIN \
+ (IMAGE_SCN_CNT_UNINITIALIZED_DATA | \
+ IMAGE_SCN_ALIGN_4BYTES | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE)
+#define BSS_FLAGS_DOS \
+ (IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+
+#define RDATA_FLAGS_WIN \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_ALIGN_8BYTES | \
+ IMAGE_SCN_MEM_READ)
+
+#define RDATA_FLAGS_DOS \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA)
+
+#define PDATA_FLAGS \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_ALIGN_4BYTES | \
+ IMAGE_SCN_MEM_READ)
+
+#define XDATA_FLAGS \
+ (IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_ALIGN_8BYTES | \
+ IMAGE_SCN_MEM_READ)
+
+#define INFO_FLAGS \
+ (IMAGE_SCN_ALIGN_1BYTES | \
+ IMAGE_SCN_LNK_INFO | \
+ IMAGE_SCN_LNK_REMOVE)
+
+#define TEXT_FLAGS ((win32 | win64) ? TEXT_FLAGS_WIN : TEXT_FLAGS_DOS)
+#define DATA_FLAGS ((win32 | win64) ? DATA_FLAGS_WIN : DATA_FLAGS_DOS)
+#define BSS_FLAGS ((win32 | win64) ? BSS_FLAGS_WIN : BSS_FLAGS_DOS)
+#define RDATA_FLAGS ((win32 | win64) ? RDATA_FLAGS_WIN : RDATA_FLAGS_DOS)
+
+#define COFF_MAX_ALIGNMENT 8192
+
+#define SECT_DELTA 32
+struct coff_Section **coff_sects;
+static int sectlen;
+int coff_nsects;
+
+struct SAA *coff_syms;
+uint32_t coff_nsyms;
+
+static int32_t def_seg;
+
+static int initsym;
+
+static struct RAA *bsym, *symval;
+
+struct SAA *coff_strs;
+static uint32_t strslen;
+
+static void coff_gen_init(void);
+static void coff_sect_write(struct coff_Section *, const uint8_t *, uint32_t);
+static void coff_write(void);
+static void coff_section_header(char *, int32_t, int32_t, int32_t, int32_t, int32_t, int, int32_t);
+static void coff_write_relocs(struct coff_Section *);
+static void coff_write_symbols(void);
+static void coff_defcomdatname(char *name, int32_t segment);
+
+#define COMDAT_PLACEHOLDER_NAME ".tmpcmdt"
+
+static void coff_win32_init(void)
+{
+ win32 = true;
+ win64 = false;
+ coff_gen_init();
+}
+
+static void coff_win64_init(void)
+{
+ win32 = false;
+ win64 = true;
+ coff_gen_init();
+ imagebase_sect = seg_alloc()+1;
+ backend_label(WRT_IMAGEBASE, imagebase_sect, 0);
+}
+
+static void coff_std_init(void)
+{
+ win32 = win64 = false;
+ coff_gen_init();
+}
+
+static void coff_gen_init(void)
+{
+
+ coff_sects = NULL;
+ coff_nsects = sectlen = 0;
+ coff_syms = saa_init(sizeof(struct coff_Symbol));
+ coff_nsyms = 0;
+ bsym = raa_init();
+ symval = raa_init();
+ coff_strs = saa_init(1);
+ strslen = 0;
+ def_seg = seg_alloc();
+}
+
+static void coff_cleanup(void)
+{
+ struct coff_Reloc *r;
+ int i;
+
+ dfmt->cleanup();
+
+ coff_write();
+ for (i = 0; i < coff_nsects; i++) {
+ if (coff_sects[i]->data)
+ saa_free(coff_sects[i]->data);
+ while (coff_sects[i]->head) {
+ r = coff_sects[i]->head;
+ coff_sects[i]->head = coff_sects[i]->head->next;
+ nasm_free(r);
+ }
+ nasm_free(coff_sects[i]->name);
+ nasm_free(coff_sects[i]->comdat_name);
+ nasm_free(coff_sects[i]);
+ }
+ nasm_free(coff_sects);
+ saa_free(coff_syms);
+ raa_free(bsym);
+ raa_free(symval);
+ saa_free(coff_strs);
+}
+
+int coff_make_section(char *name, uint32_t flags)
+{
+ struct coff_Section *s;
+ size_t namelen;
+
+ s = nasm_zalloc(sizeof(*s));
+
+ if (flags != BSS_FLAGS)
+ s->data = saa_init(1);
+ s->tail = &s->head;
+ if (!strcmp(name, ".text"))
+ s->index = def_seg;
+ else
+ s->index = seg_alloc();
+ s->namepos = -1;
+ namelen = strlen(name);
+ if (namelen > 8) {
+ if (win32 || win64) {
+ s->namepos = strslen + 4;
+ saa_wbytes(coff_strs, name, namelen + 1);
+ strslen += namelen + 1;
+ } else {
+ namelen = 8;
+ }
+ }
+ s->name = nasm_malloc(namelen + 1);
+ strncpy(s->name, name, namelen);
+ s->name[namelen] = '\0';
+ s->flags = flags;
+
+ if (coff_nsects >= sectlen) {
+ sectlen += SECT_DELTA;
+ coff_sects = nasm_realloc(coff_sects, sectlen * sizeof(*coff_sects));
+ }
+ coff_sects[coff_nsects++] = s;
+
+ return coff_nsects - 1;
+}
+
+/*
+ * Update the name and flags of an existing section
+ */
+static void coff_update_section(int section, char *name, uint32_t flags)
+{
+ struct coff_Section *s = coff_sects[section];
+ size_t namelen = strlen(name);
+
+ if (namelen > 8) {
+ if (win32 || win64) {
+ s->namepos = strslen + 4;
+ saa_wbytes(coff_strs, name, namelen + 1);
+ strslen += namelen + 1;
+ } else {
+ namelen = 8;
+ }
+ }
+
+ nasm_free(s->name);
+ s->name = nasm_malloc(namelen + 1);
+ strncpy(s->name, name, namelen);
+ s->name[namelen] = '\0';
+ s->flags = flags;
+}
+
+/*
+ * Convert an alignment value to the corresponding flags.
+ * An alignment value of 0 means no flags should be set.
+ */
+static inline uint32_t coff_sectalign_flags(unsigned int align)
+{
+ return (alignlog2_32(align) + 1) << 20;
+}
+
+/*
+ * Get the default section flags (based on section name)
+ */
+static uint32_t coff_section_flags(char *name, uint32_t flags)
+{
+ if (!flags) {
+ flags = TEXT_FLAGS;
+
+ if (!strcmp(name, ".data")) {
+ flags = DATA_FLAGS;
+ } else if (!strcmp(name, ".rdata")) {
+ flags = RDATA_FLAGS;
+ } else if (!strcmp(name, ".bss")) {
+ flags = BSS_FLAGS;
+ } else if (win64) {
+ if (!strcmp(name, ".pdata"))
+ flags = PDATA_FLAGS;
+ else if (!strcmp(name, ".xdata"))
+ flags = XDATA_FLAGS;
+ }
+ }
+
+ return flags;
+}
+
+static int32_t coff_section_names(char *name, int *bits)
+{
+ char *p, *comdat_name;
+ uint32_t flags, align_flags;
+ int i, j;
+ int8_t comdat_selection;
+ int32_t comdat_associated;
+
+ /*
+ * Set default bits.
+ */
+ if (!name) {
+ if(win64)
+ *bits = 64;
+ else
+ *bits = 32;
+
+ return def_seg;
+ }
+
+ p = name;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ if (strlen(name) > 8) {
+ if (!win32 && !win64) {
+ nasm_warn(WARN_OTHER, "COFF section names limited to 8 characters: truncating");
+ name[8] = '\0';
+ }
+ }
+ flags = align_flags = comdat_selection = comdat_associated = 0;
+ comdat_name = NULL;
+
+ while (*p && nasm_isspace(*p))
+ p++;
+ while (*p) {
+ char *q = p;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ p++;
+
+ if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) {
+ flags = TEXT_FLAGS;
+ } else if (!nasm_stricmp(q, "data")) {
+ flags = DATA_FLAGS;
+ } else if (!nasm_stricmp(q, "rdata")) {
+ if (win32 | win64)
+ flags = RDATA_FLAGS;
+ else {
+ flags = DATA_FLAGS; /* gotta do something */
+ nasm_nonfatal("standard COFF does not support"
+ " read-only data sections");
+ }
+ } else if (!nasm_stricmp(q, "bss")) {
+ flags = BSS_FLAGS;
+ } else if (!nasm_stricmp(q, "info")) {
+ if (win32 | win64)
+ flags = INFO_FLAGS;
+ else {
+ flags = DATA_FLAGS; /* gotta do something */
+ nasm_nonfatal("standard COFF does not support"
+ " informational sections");
+ }
+ } else if (!nasm_strnicmp(q, "align=", 6)) {
+ if (q[6 + strspn(q + 6, "0123456789")])
+ nasm_nonfatal("argument to `align' is not numeric");
+ else {
+ unsigned int align = atoi(q + 6);
+ /* Allow align=0 meaning use default */
+ if (!align) {
+ align_flags = 0;
+ } else if (!is_power2(align)) {
+ nasm_nonfatal("argument to `align' is not a"
+ " power of two");
+ } else if (align > COFF_MAX_ALIGNMENT) {
+ nasm_nonfatal("maximum alignment in COFF is %d bytes",
+ COFF_MAX_ALIGNMENT);
+ } else {
+ align_flags = coff_sectalign_flags(align);
+ }
+ }
+ } else if (!nasm_strnicmp(q, "comdat=", 7)) {
+ /*
+ * Expected format: comdat=num:name]
+ * where
+ * num is a number: one of the IMAGE_COMDAT_SELECT_* constants
+ * name is a string: the "COMDAT name"
+ */
+ comdat_selection = strtoul(q + 7, &q, 10);
+ if (!comdat_selection)
+ nasm_nonfatal("invalid argument to `comdat'");
+ else if (*q != ':' || q[1] == '\0')
+ nasm_nonfatal("missing name in `comdat'");
+ else {
+ comdat_name = q + 1;
+ }
+ }
+ }
+
+ for (i = 0; i < coff_nsects; i++)
+ if (!strcmp(name, coff_sects[i]->name)) {
+ if (!comdat_name && !coff_sects[i]->comdat_name)
+ break;
+ else if (comdat_name && coff_sects[i]->comdat_name &&
+ !strcmp(comdat_name, coff_sects[i]->comdat_name)) {
+ /*
+ * For COMDAT, it makes sense to have multiple sections with
+ * the same name (different comdat name though)
+ */
+ if ((coff_sects[i]->comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) ||
+ (coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE)) {
+ /*
+ * Let's also allow an associative/other pair with the same name
+ */
+ break;
+ }
+ }
+ }
+ else if (comdat_name && coff_sects[i]->comdat_name &&
+ !coff_sects[i]->comdat_selection &&
+ !strcmp(comdat_name, coff_sects[i]->comdat_name) &&
+ comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * This seems to be a "placeholder section" we've created before
+ * to be the associate of a previous comdat section.
+ * We'll just update the name and flags with the real ones now.
+ */
+ flags = coff_section_flags(name, flags);
+ coff_update_section(i, name, flags | IMAGE_SCN_LNK_COMDAT);
+ coff_sects[i]->comdat_selection = comdat_selection;
+ break;
+ }
+
+ if (i == coff_nsects) {
+ flags = coff_section_flags(name, flags);
+
+ if (comdat_name) {
+ flags |= IMAGE_SCN_LNK_COMDAT;
+
+ if (comdat_selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * Find an existing section with given comdat name
+ */
+ for (j = 0; j < coff_nsects; j++)
+ if (coff_sects[j]->comdat_name &&
+ !strcmp(coff_sects[j]->comdat_name, comdat_name))
+ break;
+
+ if (j == coff_nsects) {
+ /*
+ * The associated section doesn't exist (yet)
+ * Even though the specs don't enforce a particular order,
+ * VS (2019) linker doesn't accept .obj files where the
+ * target section is a later one (than the one with sel==5)
+ *
+ * So let's insert another section now (a placeholder),
+ * hoping it will be turned into the target section later.
+ */
+ j = coff_make_section(COMDAT_PLACEHOLDER_NAME, TEXT_FLAGS);
+ coff_sects[j]->comdat_name = nasm_strdup(comdat_name);
+ }
+
+ comdat_associated = j + 1;
+ }
+ }
+
+ i = coff_make_section(name, flags);
+ coff_sects[i]->align_flags = align_flags;
+
+ if (comdat_name) {
+ coff_sects[i]->comdat_selection = comdat_selection;
+ coff_sects[i]->comdat_associated = comdat_associated;
+ coff_sects[i]->comdat_name = nasm_strdup(comdat_name);
+ }
+ } else {
+ if (flags) {
+ if (comdat_name)
+ flags |= IMAGE_SCN_LNK_COMDAT;
+
+ /* Warn if non-alignment flags differ */
+ if (((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) &&
+ coff_sects[i]->pass_last_seen == pass_count()) {
+ nasm_warn(WARN_OTHER, "section attributes changed on"
+ " redeclaration of section `%s'", name);
+ }
+ }
+
+ /*
+ * Alignment can be increased, but never decreased. However,
+ * specifying a narrower alignment is permitted and ignored.
+ */
+ if (align_flags > coff_sects[i]->align_flags) {
+ coff_sects[i]->align_flags = align_flags;
+ }
+
+ if (comdat_name) {
+ if ((coff_sects[i]->comdat_selection != comdat_selection) &&
+ coff_sects[i]->pass_last_seen == pass_count()) {
+ nasm_warn(WARN_OTHER, "comdat selection changed on"
+ " redeclaration of name `%s'", comdat_name);
+ }
+ }
+ }
+
+ coff_sects[i]->pass_last_seen = pass_count();
+ return coff_sects[i]->index;
+}
+
+static void coff_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ int pos, section;
+ struct coff_Symbol *sym;
+
+ if (special)
+ nasm_nonfatal("COFF format does not support any"
+ " special symbol types");
+
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ if (strcmp(name,WRT_IMAGEBASE))
+ nasm_nonfatal("unrecognized special symbol `%s'", name);
+ return;
+ }
+
+ if (segment == NO_SEG)
+ section = -1; /* absolute symbol */
+ else {
+ int i;
+ section = 0;
+ for (i = 0; i < coff_nsects; i++)
+ if (segment == coff_sects[i]->index) {
+ section = i + 1;
+
+ if (coff_sects[i]->comdat_name && !coff_sects[i]->comdat_symbol) {
+ /*
+ * The "comdat symbol" must be the first one in symbol table
+ * So we'll insert/define it - before defining the other one
+ */
+ coff_sects[i]->comdat_symbol = 1;
+
+ if (coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE &&
+ 0 != strcmp(coff_sects[i]->comdat_name, name)) {
+ coff_defcomdatname(coff_sects[i]->comdat_name, segment);
+ }
+ }
+ break;
+ }
+ }
+
+ pos = strslen + 4;
+ if (strlen(name) > 8) {
+ size_t nlen = strlen(name)+1;
+ saa_wbytes(coff_strs, name, nlen);
+ strslen += nlen;
+ } else
+ pos = -1;
+
+ sym = saa_wstruct(coff_syms);
+
+ sym->strpos = pos;
+ sym->namlen = strlen(name);
+ if (pos == -1)
+ strcpy(sym->name, name);
+ sym->is_global = !!is_global;
+ sym->type = 0; /* Default to T_NULL (no type) */
+ sym->section = section;
+ if (!sym->section)
+ sym->is_global = true;
+ if (is_global == 2)
+ sym->value = offset;
+ else
+ sym->value = (sym->section == 0 ? 0 : offset);
+
+ /*
+ * define the references from external-symbol segment numbers
+ * to these symbol records.
+ */
+ if (sym->section == 0)
+ bsym = raa_write(bsym, segment, coff_nsyms);
+
+ if (segment != NO_SEG)
+ symval = raa_write(symval, segment, sym->section ? 0 : sym->value);
+
+ coff_nsyms++;
+}
+
+static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment,
+ int16_t type)
+{
+ struct coff_Reloc *r;
+
+ r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
+ sect->tail = &r->next;
+ r->next = NULL;
+
+ r->address = sect->len;
+ if (segment == NO_SEG) {
+ r->symbol = 0, r->symbase = ABS_SYMBOL;
+ } else {
+ int i;
+ r->symbase = REAL_SYMBOLS;
+ for (i = 0; i < coff_nsects; i++) {
+ if (segment == coff_sects[i]->index) {
+ r->symbol = i * 2;
+ r->symbase = SECT_SYMBOLS;
+ break;
+ }
+ }
+ if (r->symbase == REAL_SYMBOLS)
+ r->symbol = raa_read(bsym, segment);
+ }
+ r->type = type;
+
+ sect->nrelocs++;
+
+ /*
+ * Return the fixup for standard COFF common variables.
+ */
+ if (r->symbase == REAL_SYMBOLS && !(win32 | win64))
+ return raa_read(symval, segment);
+
+ return 0;
+}
+
+static void coff_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ struct coff_Section *s;
+ uint8_t mydata[8], *p;
+ int i;
+
+ if (wrt != NO_SEG && !win64) {
+ wrt = NO_SEG; /* continue to do _something_ */
+ nasm_nonfatal("WRT not supported by COFF output formats");
+ }
+
+ s = NULL;
+ for (i = 0; i < coff_nsects; i++) {
+ if (segto == coff_sects[i]->index) {
+ s = coff_sects[i];
+ break;
+ }
+ }
+ if (!s) {
+ int tempint; /* ignored */
+ if (segto != coff_section_names(".text", &tempint))
+ nasm_panic("strange segment conditions in COFF driver");
+ else
+ s = coff_sects[coff_nsects - 1];
+ }
+
+ /* magically default to 'wrt ..imagebase' in .pdata and .xdata */
+ if (win64 && wrt == NO_SEG) {
+ if (!strcmp(s->name,".pdata") || !strcmp(s->name,".xdata"))
+ wrt = imagebase_sect;
+ }
+
+ if (!s->data && type != OUT_RESERVE) {
+ nasm_warn(WARN_OTHER, "attempt to initialize memory in"
+ " BSS section `%s': ignored", s->name);
+ s->len += realsize(type, size);
+ return;
+ }
+
+ memset(mydata, 0, sizeof(mydata));
+
+ if (dfmt && dfmt->debug_output) {
+ struct coff_DebugInfo dinfo;
+ dinfo.segto = segto;
+ dinfo.seg = segment;
+ dinfo.section = s;
+
+ if (type == OUT_ADDRESS)
+ dinfo.size = abs((int)size);
+ else
+ dinfo.size = realsize(type, size);
+
+ dfmt->debug_output(type, &dinfo);
+ }
+
+ if (type == OUT_RESERVE) {
+ if (s->data) {
+ nasm_warn(WARN_ZEROING, "uninitialised space declared in"
+ " non-BSS section `%s': zeroing", s->name);
+ coff_sect_write(s, NULL, size);
+ } else
+ s->len += size;
+ } else if (type == OUT_RAWDATA) {
+ coff_sect_write(s, data, size);
+ } else if (type == OUT_ADDRESS) {
+ int asize = abs((int)size);
+ if (!win64) {
+ if (asize != 4 && (segment != NO_SEG || wrt != NO_SEG)) {
+ nasm_nonfatal("COFF format does not support non-32-bit"
+ " relocations");
+ } else {
+ int32_t fix = 0;
+ if (segment != NO_SEG || wrt != NO_SEG) {
+ if (wrt != NO_SEG) {
+ nasm_nonfatal("COFF format does not support WRT types");
+ } else if (segment % 2) {
+ nasm_nonfatal("COFF format does not support"
+ " segment base references");
+ } else
+ fix = coff_add_reloc(s, segment, IMAGE_REL_I386_DIR32);
+ }
+ p = mydata;
+ WRITELONG(p, *(int64_t *)data + fix);
+ coff_sect_write(s, mydata, asize);
+ }
+ } else {
+ int32_t fix = 0;
+ p = mydata;
+ if (asize == 8) {
+ if (wrt == imagebase_sect) {
+ nasm_nonfatal("operand size mismatch: 'wrt "
+ WRT_IMAGEBASE "' is a 32-bit operand");
+ }
+ fix = coff_add_reloc(s, segment, IMAGE_REL_AMD64_ADDR64);
+ WRITEDLONG(p, *(int64_t *)data + fix);
+ coff_sect_write(s, mydata, asize);
+ } else {
+ fix = coff_add_reloc(s, segment,
+ wrt == imagebase_sect ? IMAGE_REL_AMD64_ADDR32NB:
+ IMAGE_REL_AMD64_ADDR32);
+ WRITELONG(p, *(int64_t *)data + fix);
+ coff_sect_write(s, mydata, asize);
+ }
+ }
+ } else if (type == OUT_REL2ADR) {
+ nasm_nonfatal("COFF format does not support 16-bit relocations");
+ } else if (type == OUT_REL4ADR) {
+ if (segment == segto && !(win64)) /* Acceptable for RIP-relative */
+ nasm_panic("intra-segment OUT_REL4ADR");
+ else if (segment == NO_SEG && win32)
+ nasm_nonfatal("Win32 COFF does not correctly support"
+ " relative references to absolute addresses");
+ else {
+ int32_t fix = 0;
+ if (segment != NO_SEG && segment % 2) {
+ nasm_nonfatal("COFF format does not support"
+ " segment base references");
+ } else
+ fix = coff_add_reloc(s, segment,
+ win64 ? IMAGE_REL_AMD64_REL32 : IMAGE_REL_I386_REL32);
+ p = mydata;
+ if (win32 | win64) {
+ WRITELONG(p, *(int64_t *)data + 4 - size + fix);
+ } else {
+ WRITELONG(p, *(int64_t *)data - (size + s->len) + fix);
+ }
+ coff_sect_write(s, mydata, 4L);
+ }
+
+ }
+}
+
+static void coff_sect_write(struct coff_Section *sect,
+ const uint8_t *data, uint32_t len)
+{
+ saa_wbytes(sect->data, data, len);
+ sect->len += len;
+}
+
+typedef struct tagString {
+ struct tagString *next;
+ int len;
+ char *String;
+} STRING;
+
+#define EXPORT_SECTION_NAME ".drectve"
+#define EXPORT_SECTION_FLAGS INFO_FLAGS
+/*
+ * #define EXPORT_SECTION_NAME ".text"
+ * #define EXPORT_SECTION_FLAGS TEXT_FLAGS
+ */
+
+static STRING *Exports = NULL;
+static struct coff_Section *directive_sec;
+static void AddExport(char *name)
+{
+ STRING *rvp = Exports, *newS;
+
+ newS = (STRING *) nasm_malloc(sizeof(STRING));
+ newS->len = strlen(name);
+ newS->next = NULL;
+ newS->String = (char *)nasm_malloc(newS->len + 1);
+ strcpy(newS->String, name);
+ if (rvp == NULL) {
+ int i;
+
+ for (i = 0; i < coff_nsects; i++) {
+ if (!strcmp(EXPORT_SECTION_NAME, coff_sects[i]->name))
+ break;
+ }
+
+ if (i == coff_nsects)
+ i = coff_make_section(EXPORT_SECTION_NAME, EXPORT_SECTION_FLAGS);
+
+ directive_sec = coff_sects[i];
+ Exports = newS;
+ } else {
+ while (rvp->next) {
+ if (!strcmp(rvp->String, name))
+ return;
+ rvp = rvp->next;
+ }
+ rvp->next = newS;
+ }
+}
+
+static void BuildExportTable(STRING **rvp)
+{
+ STRING *p, *t;
+
+ if (!rvp || !*rvp)
+ return;
+
+ list_for_each_safe(p, t, *rvp) {
+ coff_sect_write(directive_sec, (uint8_t *)"-export:", 8);
+ coff_sect_write(directive_sec, (uint8_t *)p->String, p->len);
+ coff_sect_write(directive_sec, (uint8_t *)" ", 1);
+ nasm_free(p->String);
+ nasm_free(p);
+ }
+
+ *rvp = NULL;
+}
+
+static void coff_defcomdatname(char *name, int32_t segment)
+{
+ coff_deflabel(name, segment, 0, 1, NULL);
+}
+
+static enum directive_result
+coff_directives(enum directive directive, char *value)
+{
+ switch (directive) {
+ case D_EXPORT:
+ {
+ char *q, *name;
+
+ /*
+ * XXX: pass_first() is really wrong here, but AddExport()
+ * needs to be modified to handle duplicate calls for the
+ * same value in order to change that. The right thing to do
+ * is probably to mark a label as an export in the label
+ * structure, in case the label doesn't actually exist.
+ */
+ if (!pass_first())
+ return DIRR_OK; /* ignore in pass two */
+ name = q = value;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+
+ if (!*name) {
+ nasm_nonfatal("`export' directive requires export name");
+ return DIRR_ERROR;
+ }
+ if (*q) {
+ nasm_nonfatal("unrecognized export qualifier `%s'", q);
+ return DIRR_ERROR;
+ }
+ AddExport(name);
+ return DIRR_OK;
+ }
+ case D_SAFESEH:
+ {
+ static int sxseg=-1;
+ int i;
+
+ if (!win32) /* Only applicable for -f win32 */
+ return 0;
+
+ if (sxseg == -1) {
+ for (i = 0; i < coff_nsects; i++)
+ if (!strcmp(".sxdata",coff_sects[i]->name))
+ break;
+ if (i == coff_nsects)
+ sxseg = coff_make_section(".sxdata", IMAGE_SCN_LNK_INFO);
+ else
+ sxseg = i;
+ }
+ /*
+ * pass_final() is the only time when the full set of symbols are
+ * guaranteed to be present as it is the final output pass.
+ */
+ if (pass_final()) {
+ uint32_t n;
+ saa_rewind(coff_syms);
+ for (n = 0; n < coff_nsyms; n++) {
+ struct coff_Symbol *sym = saa_rstruct(coff_syms);
+ bool equals;
+
+ /*
+ * sym->strpos is biased by 4, because symbol
+ * table is prefixed with table length
+ */
+ if (sym->strpos >=4) {
+ char *name = nasm_malloc(sym->namlen+1);
+ saa_fread(coff_strs, sym->strpos-4, name, sym->namlen);
+ name[sym->namlen] = '\0';
+ equals = !strcmp(value,name);
+ nasm_free(name);
+ } else {
+ equals = !strcmp(value,sym->name);
+ }
+
+ if (equals) {
+ /*
+ * this value arithmetic effectively reflects
+ * initsym in coff_write(): 2 for file, 1 for
+ * .absolute and two per each section
+ */
+ unsigned char value[4],*p=value;
+ WRITELONG(p,n + 2 + 1 + coff_nsects*2);
+ coff_sect_write(coff_sects[sxseg],value,4);
+ sym->type = 0x20;
+ break;
+ }
+ }
+ if (n == coff_nsyms) {
+ nasm_nonfatal("`safeseh' directive requires valid symbol");
+ return DIRR_ERROR;
+ }
+ }
+ return DIRR_OK;
+ }
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+/* handle relocations storm, valid for win32/64 only */
+static inline void coff_adjust_relocs(struct coff_Section *s)
+{
+ if (s->nrelocs < IMAGE_SCN_MAX_RELOC)
+ return;
+#ifdef OF_COFF
+ else
+ {
+ if (ofmt == &of_coff)
+ nasm_fatal("Too many relocations (%d) for section `%s'",
+ s->nrelocs, s->name);
+ }
+#endif
+
+ s->flags |= IMAGE_SCN_LNK_NRELOC_OVFL;
+ s->nrelocs++;
+}
+
+/*
+ * Make sure we satisfy all section alignment requirements and put the
+ * resulting alignment flags into the flags value in the header. If
+ * no user-specified alignment is given, use the default for the
+ * section type; then either way round up to alignment specified by
+ * sectalign directives.
+ */
+static inline void coff_adjust_alignment(struct coff_Section *s)
+{
+ uint32_t align_flags = s->align_flags;
+
+ if (!align_flags) {
+ /* No user-specified alignment, use default for partition type */
+ align_flags = s->flags & IMAGE_SCN_ALIGN_MASK;
+ }
+
+ if (align_flags < s->sectalign_flags)
+ align_flags = s->sectalign_flags;
+
+ s->flags = (s->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags;
+}
+
+static void coff_write(void)
+{
+ int32_t pos, sympos, vsize;
+ int i;
+
+ /* fill in the .drectve section with -export's */
+ BuildExportTable(&Exports);
+
+ if (win32) {
+ /* add default value for @feat.00, this allows to 'link /safeseh' */
+ uint32_t n;
+
+ saa_rewind(coff_syms);
+ for (n = 0; n < coff_nsyms; n++) {
+ struct coff_Symbol *sym = saa_rstruct(coff_syms);
+ if (sym->strpos == -1 && !strcmp("@feat.00",sym->name))
+ break;
+ }
+ if (n == coff_nsyms)
+ coff_deflabel("@feat.00", NO_SEG, 1, 0, NULL);
+ }
+
+ /*
+ * Check all comdat sections
+ */
+ for (i = 0; i < coff_nsects; i++)
+ if (coff_sects[i]->comdat_name) {
+ if (!coff_sects[i]->comdat_symbol &&
+ coff_sects[i]->comdat_selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ /*
+ * This section doesn't have its comdat symbol defined; do it
+ */
+ coff_defcomdatname(coff_sects[i]->comdat_name, coff_sects[i]->index);
+ }
+ if (!coff_sects[i]->comdat_selection) {
+ /*
+ * This is a placeholder section that wasn't properly defined
+ */
+ nasm_nonfatal("`comdat' associate with symbol `%s` wasn't defined",
+ coff_sects[i]->comdat_name);
+ }
+ }
+
+ /*
+ * Work out how big the file will get.
+ * Calculate the start of the `real' symbols at the same time.
+ * Check for massive relocations.
+ */
+ pos = 0x14 + 0x28 * coff_nsects;
+ initsym = 3; /* two for the file, one absolute */
+ for (i = 0; i < coff_nsects; i++) {
+ coff_adjust_alignment(coff_sects[i]);
+ if (coff_sects[i]->data) {
+ coff_adjust_relocs(coff_sects[i]);
+ coff_sects[i]->pos = pos;
+ pos += coff_sects[i]->len;
+ coff_sects[i]->relpos = pos;
+ pos += 10 * coff_sects[i]->nrelocs;
+ } else
+ coff_sects[i]->pos = coff_sects[i]->relpos = 0L;
+ initsym += 2; /* two for each section */
+ }
+ sympos = pos;
+
+ /*
+ * Output the COFF header.
+ */
+ if (win64)
+ i = IMAGE_FILE_MACHINE_AMD64;
+ else
+ i = IMAGE_FILE_MACHINE_I386;
+ fwriteint16_t(i, ofile); /* machine type */
+ fwriteint16_t(coff_nsects, ofile); /* number of sections */
+ fwriteint32_t(posix_timestamp(), ofile); /* timestamp */
+ fwriteint32_t(sympos, ofile);
+ fwriteint32_t(coff_nsyms + initsym, ofile);
+ fwriteint16_t(0, ofile); /* no optional header */
+ /* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */
+ fwriteint16_t((win32 | win64) ? 0 : 0x104, ofile);
+
+ /*
+ * Output the section headers.
+ */
+ vsize = 0L;
+ for (i = 0; i < coff_nsects; i++) {
+ coff_section_header(coff_sects[i]->name, coff_sects[i]->namepos, vsize, coff_sects[i]->len,
+ coff_sects[i]->pos, coff_sects[i]->relpos,
+ coff_sects[i]->nrelocs, coff_sects[i]->flags);
+ vsize += coff_sects[i]->len;
+ }
+
+ /*
+ * Output the sections and their relocations.
+ */
+ for (i = 0; i < coff_nsects; i++)
+ if (coff_sects[i]->data) {
+ saa_fpwrite(coff_sects[i]->data, ofile);
+ coff_write_relocs(coff_sects[i]);
+
+ if (coff_sects[i]->flags & IMAGE_SCN_LNK_COMDAT) {
+ /*
+ * Checksum the section data
+ */
+ uint32_t checksum = 0;
+ const char *data;
+ size_t len;
+
+ saa_rewind(coff_sects[i]->data);
+ while (len = coff_sects[i]->data->datalen,
+ (data = saa_rbytes(coff_sects[i]->data, &len)) != NULL)
+ checksum = crc32b(checksum, data, len);
+
+ coff_sects[i]->checksum = checksum;
+ }
+ }
+
+ /*
+ * Output the symbol and string tables.
+ */
+ coff_write_symbols();
+ fwriteint32_t(strslen + 4, ofile); /* length includes length count */
+ saa_fpwrite(coff_strs, ofile);
+}
+
+static void coff_section_header(char *name, int32_t namepos, int32_t vsize,
+ int32_t datalen, int32_t datapos,
+ int32_t relpos, int nrelocs, int32_t flags)
+{
+ char padname[8];
+
+ (void)vsize;
+
+ if (namepos == -1) {
+ strncpy(padname, name, 8);
+ nasm_write(padname, 8, ofile);
+ } else {
+ /*
+ * If name is longer than 8 bytes, write '/' followed
+ * by offset into the strings table represented as
+ * decimal number.
+ */
+ namepos = namepos % 100000000;
+ padname[0] = '/';
+ padname[1] = '0' + (namepos / 1000000);
+ namepos = namepos % 1000000;
+ padname[2] = '0' + (namepos / 100000);
+ namepos = namepos % 100000;
+ padname[3] = '0' + (namepos / 10000);
+ namepos = namepos % 10000;
+ padname[4] = '0' + (namepos / 1000);
+ namepos = namepos % 1000;
+ padname[5] = '0' + (namepos / 100);
+ namepos = namepos % 100;
+ padname[6] = '0' + (namepos / 10);
+ namepos = namepos % 10;
+ padname[7] = '0' + (namepos);
+ nasm_write(padname, 8, ofile);
+ }
+
+ fwriteint32_t(0, ofile); /* Virtual size field - set to 0 or vsize */
+ fwriteint32_t(0L, ofile); /* RVA/offset - we ignore */
+ fwriteint32_t(datalen, ofile);
+ fwriteint32_t(datapos, ofile);
+ fwriteint32_t(relpos, ofile);
+ fwriteint32_t(0L, ofile); /* no line numbers - we don't do 'em */
+
+ /*
+ * a special case -- if there are too many relocs
+ * we have to put IMAGE_SCN_MAX_RELOC here and write
+ * the real relocs number into VirtualAddress of first
+ * relocation
+ */
+ if (flags & IMAGE_SCN_LNK_NRELOC_OVFL)
+ fwriteint16_t(IMAGE_SCN_MAX_RELOC, ofile);
+ else
+ fwriteint16_t(nrelocs, ofile);
+
+ fwriteint16_t(0, ofile); /* again, no line numbers */
+ fwriteint32_t(flags, ofile);
+}
+
+static void coff_write_relocs(struct coff_Section *s)
+{
+ struct coff_Reloc *r;
+
+ /* a real number of relocations if needed */
+ if (s->flags & IMAGE_SCN_LNK_NRELOC_OVFL) {
+ fwriteint32_t(s->nrelocs, ofile);
+ fwriteint32_t(0, ofile);
+ fwriteint16_t(0, ofile);
+ }
+
+ for (r = s->head; r; r = r->next) {
+ fwriteint32_t(r->address, ofile);
+ fwriteint32_t(r->symbol + (r->symbase == REAL_SYMBOLS ? initsym :
+ r->symbase == ABS_SYMBOL ? initsym - 1 :
+ r->symbase == SECT_SYMBOLS ? 2 : 0),
+ ofile);
+ fwriteint16_t(r->type, ofile);
+ }
+}
+
+static void coff_symbol(char *name, int32_t strpos, int32_t value,
+ int section, int type, int storageclass, int aux)
+{
+ char padname[8];
+
+ if (name) {
+ strncpy(padname, name, 8);
+ nasm_write(padname, 8, ofile);
+ } else {
+ fwriteint32_t(0, ofile);
+ fwriteint32_t(strpos, ofile);
+ }
+
+ fwriteint32_t(value, ofile);
+ fwriteint16_t(section, ofile);
+ fwriteint16_t(type, ofile);
+
+ fputc(storageclass, ofile);
+ fputc(aux, ofile);
+}
+
+static void coff_write_symbols(void)
+{
+ char filename[18];
+ uint32_t i;
+
+ /*
+ * The `.file' record, and the file name auxiliary record.
+ */
+ coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1);
+ if (reproducible)
+ memset(filename, 0, 18);
+ else
+ strncpy(filename, inname, 18);
+ nasm_write(filename, 18, ofile);
+
+ /*
+ * The section records, with their auxiliaries.
+ */
+ memset(filename, 0, 18); /* useful zeroed buffer */
+
+ for (i = 0; i < (uint32_t) coff_nsects; i++) {
+ coff_symbol(coff_sects[i]->name, 0L, 0L, i + 1, 0, 3, 1);
+ fwriteint32_t(coff_sects[i]->len, ofile);
+ fwriteint16_t(coff_sects[i]->nrelocs,ofile);
+ if (coff_sects[i]->flags & IMAGE_SCN_LNK_COMDAT) {
+ fwriteint16_t(0, ofile);
+ fwriteint32_t(coff_sects[i]->checksum, ofile);
+ fwriteint16_t(coff_sects[i]->comdat_associated, ofile);
+ fputc(coff_sects[i]->comdat_selection, ofile);
+ nasm_write(filename, 3, ofile);
+ }
+ else
+ nasm_write(filename, 12, ofile);
+ }
+
+ /*
+ * The absolute symbol, for relative-to-absolute relocations.
+ */
+ coff_symbol(".absolut", 0L, 0L, -1, 0, 3, 0);
+
+ /*
+ * The real symbols.
+ */
+ saa_rewind(coff_syms);
+ for (i = 0; i < coff_nsyms; i++) {
+ struct coff_Symbol *sym = saa_rstruct(coff_syms);
+ coff_symbol(sym->strpos == -1 ? sym->name : NULL,
+ sym->strpos, sym->value, sym->section,
+ sym->type, sym->is_global ? 2 : 3, 0);
+ }
+}
+
+static void coff_sectalign(int32_t seg, unsigned int value)
+{
+ struct coff_Section *s = NULL;
+ uint32_t flags;
+ int i;
+
+ for (i = 0; i < coff_nsects; i++) {
+ if (coff_sects[i]->index == seg) {
+ s = coff_sects[i];
+ break;
+ }
+ }
+
+ if (!s || !is_power2(value))
+ return;
+
+ if (value > COFF_MAX_ALIGNMENT)
+ value = COFF_MAX_ALIGNMENT; /* Do our best... */
+
+ flags = coff_sectalign_flags(value);
+ if (flags > s->sectalign_flags)
+ s->sectalign_flags = flags;
+}
+
+extern macros_t coff_stdmac[];
+
+#endif /* defined(OF_COFF) || defined(OF_WIN32) */
+
+#ifdef OF_COFF
+
+static const struct pragma_facility coff_pragma_list[] = {
+ { "coff", NULL },
+ { NULL, NULL }
+};
+
+const struct ofmt of_coff = {
+ "COFF (i386) (DJGPP, some Unix variants)",
+ "coff",
+ ".o",
+ 0,
+ 32,
+ null_debug_arr,
+ &null_debug_form,
+ coff_stdmac,
+ coff_std_init,
+ null_reset,
+ nasm_do_legacy_output,
+ coff_out,
+ coff_deflabel,
+ coff_section_names,
+ NULL,
+ coff_sectalign,
+ null_segbase,
+ coff_directives,
+ coff_cleanup,
+ coff_pragma_list
+};
+
+#endif
+
+
+#ifdef OF_WIN32
+
+static const struct pragma_facility coff_win_pragma_list[] = {
+ { "win", NULL },
+ { "coff", NULL },
+ { NULL, NULL }
+};
+
+extern const struct dfmt df_cv8;
+static const struct dfmt * const win32_debug_arr[2] = { &df_cv8, NULL };
+
+const struct ofmt of_win32 = {
+ "Microsoft extended COFF for Win32 (i386)",
+ "win32",
+ ".obj",
+ 0,
+ 32,
+ win32_debug_arr,
+ &df_cv8,
+ coff_stdmac,
+ coff_win32_init,
+ null_reset,
+ nasm_do_legacy_output,
+ coff_out,
+ coff_deflabel,
+ coff_section_names,
+ NULL,
+ coff_sectalign,
+ null_segbase,
+ coff_directives,
+ coff_cleanup,
+ coff_win_pragma_list
+};
+
+#endif
+
+#ifdef OF_WIN64
+
+static const struct dfmt * const win64_debug_arr[2] = { &df_cv8, NULL };
+
+const struct ofmt of_win64 = {
+ "Microsoft extended COFF for Win64 (x86-64)",
+ "win64",
+ ".obj",
+ 0,
+ 64,
+ win64_debug_arr,
+ &df_cv8,
+ coff_stdmac,
+ coff_win64_init,
+ null_reset,
+ nasm_do_legacy_output,
+ coff_out,
+ coff_deflabel,
+ coff_section_names,
+ NULL,
+ coff_sectalign,
+ null_segbase,
+ coff_directives,
+ coff_cleanup,
+ coff_win_pragma_list
+};
+
+#endif
diff --git a/vere/ext/nasm/output/outcoff.mac b/vere/ext/nasm/output/outcoff.mac
new file mode 100644
index 0000000..8d338ef
--- /dev/null
+++ b/vere/ext/nasm/output/outcoff.mac
@@ -0,0 +1,43 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2009 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: coff win32 win64
+%define __?SECT?__ [section .text]
+%macro __?NASM_CDecl?__ 1
+%endmacro
+%imacro export 1+.nolist
+[export %1]
+%endmacro
+%imacro safeseh 1.nolist
+[safeseh %1]
+%endmacro
diff --git a/vere/ext/nasm/output/outdbg.c b/vere/ext/nasm/output/outdbg.c
new file mode 100644
index 0000000..e7a9a4e
--- /dev/null
+++ b/vere/ext/nasm/output/outdbg.c
@@ -0,0 +1,576 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outdbg.c output routines for the Netwide Assembler to produce
+ * a debugging trace
+ */
+
+#include "compiler.h"
+
+#include "nctype.h"
+#include <errno.h>
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outform.h"
+#include "outlib.h"
+#include "insns.h"
+#include "dbginfo.h"
+
+#ifdef OF_DBG
+
+struct Section {
+ struct Section *next;
+ int32_t number;
+ char *name;
+} *dbgsect;
+
+static unsigned long dbg_max_data_dump = 128;
+static bool section_labels = true;
+static bool subsections_via_symbols = false;
+static int32_t init_seg;
+
+const struct ofmt of_dbg;
+static void dbg_init(void)
+{
+ dbgsect = NULL;
+ fprintf(ofile, "NASM Output format debug dump\n");
+ fprintf(ofile, "input file = %s\n", inname);
+ fprintf(ofile, "output file = %s\n", outname);
+ init_seg = seg_alloc();
+}
+
+static void dbg_reset(void)
+{
+ fprintf(ofile, "*** pass reset: pass = %"PRId64" (%s)\n",
+ pass_count(), pass_type_name());
+}
+
+static void dbg_cleanup(void)
+{
+ dfmt->cleanup();
+ while (dbgsect) {
+ struct Section *tmp = dbgsect;
+ dbgsect = dbgsect->next;
+ nasm_free(tmp->name);
+ nasm_free(tmp);
+ }
+}
+
+static int32_t dbg_add_section(char *name, int *bits, const char *whatwecallit)
+{
+ int seg;
+
+ /*
+ * We must have an initial default: let's make it 16.
+ */
+ if (!name)
+ *bits = 16;
+
+ if (!name) {
+ fprintf(ofile, "section_name on init: returning %d\n", init_seg);
+ seg = init_seg;
+ } else {
+ int n = strcspn(name, " \t");
+ char *sname = nasm_strndup(name, n);
+ char *tail = nasm_skip_spaces(name+n);
+ struct Section *s;
+
+ seg = NO_SEG;
+ for (s = dbgsect; s; s = s->next)
+ if (!strcmp(s->name, sname))
+ seg = s->number;
+
+ if (seg == NO_SEG) {
+ s = nasm_malloc(sizeof(*s));
+ s->name = sname;
+ s->number = seg = seg_alloc();
+ s->next = dbgsect;
+ dbgsect = s;
+ fprintf(ofile, "%s %s (%s) pass %"PRId64" (%s) : returning %d\n",
+ whatwecallit, name, tail, pass_count(), pass_type_name(), seg);
+
+ if (section_labels)
+ backend_label(s->name, s->number + 1, 0);
+ }
+ }
+ return seg;
+}
+
+static int32_t dbg_section_names(char *name, int *bits)
+{
+ return dbg_add_section(name, bits, "section_names");
+}
+
+static int32_t dbg_herelabel(const char *name, enum label_type type,
+ int32_t oldseg, int32_t *subsection,
+ bool *copyoffset)
+{
+ int32_t newseg = oldseg;
+
+ if (subsections_via_symbols && type != LBL_LOCAL) {
+ newseg = *subsection;
+ if (newseg == NO_SEG) {
+ newseg = *subsection = seg_alloc();
+ *copyoffset = true; /* Minic MachO for now */
+ }
+ }
+ fprintf(ofile, "herelabel %s type %d (seg %08x) -> %08x\n",
+ name, type, oldseg, newseg);
+
+ return newseg;
+}
+
+static void dbg_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ fprintf(ofile, "deflabel %s := %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
+ name, segment, offset,
+ is_global == 2 ? "common" : is_global ? "global" : "local",
+ is_global, special ? ": " : "", special);
+}
+
+static const char *out_type(enum out_type type)
+{
+ static const char *out_types[] = {
+ "rawdata",
+ "reserve",
+ "zerodata",
+ "address",
+ "reladdr",
+ "segment"
+ };
+ static char invalid_buf[64];
+
+ if (type >= sizeof(out_types)/sizeof(out_types[0])) {
+ sprintf(invalid_buf, "[invalid type %d]", type);
+ return invalid_buf;
+ }
+
+ return out_types[type];
+}
+
+static const char *out_flags(enum out_flags flags)
+{
+ static const char *out_flags[] = {
+ "signed",
+ "unsigned"
+ };
+ static char flags_buf[1024];
+ unsigned long flv = flags;
+ size_t n;
+ size_t left = sizeof flags_buf - 1;
+ char *p = flags_buf;
+ unsigned int i;
+
+ for (i = 0; flv; flv >>= 1, i++) {
+ if (flv & 1) {
+ if (i < ARRAY_SIZE(out_flags))
+ n = snprintf(p, left, "%s,", out_flags[i]);
+ else
+ n = snprintf(p, left, "%u,", i);
+ if (n >= left)
+ break;
+ left -= n;
+ p += n;
+ }
+ }
+ if (p > flags_buf)
+ p--; /* Delete final comma */
+ *p = '\0';
+
+ return flags_buf;
+}
+
+static void dbg_out(const struct out_data *data)
+{
+ fprintf(ofile,
+ "out to %"PRIx32":%"PRIx64" %s(%s) bits %d insoffs %d/%d "
+ "size %"PRIu64,
+ data->segment, data->offset,
+ out_type(data->type), out_flags(data->flags),
+ data->bits, data->insoffs, data->inslen, data->size);
+ if (data->itemp) {
+ fprintf(ofile, " ins %s(%d)",
+ nasm_insn_names[data->itemp->opcode], data->itemp->operands);
+ } else {
+ fprintf(ofile, " no ins (plain data)");
+ }
+
+ if (data->type == OUT_ADDRESS || data->type == OUT_RELADDR ||
+ data->type == OUT_SEGMENT) {
+ fprintf(ofile, " target %"PRIx32":%"PRIx64,
+ data->tsegment, data->toffset);
+ if (data->twrt != NO_SEG)
+ fprintf(ofile, " wrt %"PRIx32, data->twrt);
+ }
+ if (data->type == OUT_RELADDR)
+ fprintf(ofile, " relbase %"PRIx64, data->relbase);
+
+ putc('\n', ofile);
+
+ if (data->type == OUT_RAWDATA) {
+ if ((size_t)data->size != data->size) {
+ fprintf(ofile, " data: <error: impossible size>\n");
+ } else if (!data->data) {
+ fprintf(ofile, " data: <error: null pointer>\n");
+ } else if (dbg_max_data_dump != -1UL &&
+ data->size > dbg_max_data_dump) {
+ fprintf(ofile, " data: <%"PRIu64" bytes>\n", data->size);
+ } else {
+ size_t i, j;
+ const uint8_t *bytes = data->data;
+ for (i = 0; i < data->size; i += 16) {
+ fprintf(ofile, " data:");
+ for (j = 0; j < 16; j++) {
+ if (i+j >= data->size)
+ fprintf(ofile, " ");
+ else
+ fprintf(ofile, "%c%02x",
+ (j == 8) ? '-' : ' ', bytes[i+j]);
+ }
+ fprintf(ofile," ");
+ for (j = 0; j < 16; j++) {
+ if (i+j >= data->size) {
+ putc(' ', ofile);
+ } else {
+ if (bytes[i+j] >= 32 && bytes[i+j] <= 126)
+ putc(bytes[i+j], ofile);
+ else
+ putc('.', ofile);
+ }
+ }
+ putc('\n', ofile);
+ }
+ }
+ }
+
+ /* This is probably the only place were we'll call this this way... */
+ nasm_do_legacy_output(data);
+}
+
+static void dbg_legacy_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ int32_t ldata;
+
+ if (type == OUT_ADDRESS)
+ fprintf(ofile, " legacy: out to %"PRIx32", len = %d: ",
+ segto, (int)abs((int)size));
+ else
+ fprintf(ofile, " legacy: out to %"PRIx32", len = %"PRId64" (0x%"PRIx64"): ",
+ segto, (int64_t)size, size);
+
+ switch (type) {
+ case OUT_RESERVE:
+ fprintf(ofile, "reserved.\n");
+ break;
+ case OUT_RAWDATA:
+ fprintf(ofile, "rawdata\n"); /* Already have a data dump */
+ break;
+ case OUT_ADDRESS:
+ ldata = *(int64_t *)data;
+ fprintf(ofile, "addr %08"PRIx32" (seg %08"PRIx32", wrt %08"PRIx32")\n",
+ ldata, segment, wrt);
+ break;
+ case OUT_REL1ADR:
+ fprintf(ofile, "rel1adr %02"PRIx8" (seg %08"PRIx32")\n",
+ (uint8_t)*(int64_t *)data, segment);
+ break;
+ case OUT_REL2ADR:
+ fprintf(ofile, "rel2adr %04"PRIx16" (seg %08"PRIx32")\n",
+ (uint16_t)*(int64_t *)data, segment);
+ break;
+ case OUT_REL4ADR:
+ fprintf(ofile, "rel4adr %08"PRIx32" (seg %08"PRIx32")\n",
+ (uint32_t)*(int64_t *)data,
+ segment);
+ break;
+ case OUT_REL8ADR:
+ fprintf(ofile, "rel8adr %016"PRIx64" (seg %08"PRIx32")\n",
+ (uint64_t)*(int64_t *)data, segment);
+ break;
+ default:
+ fprintf(ofile, "unknown\n");
+ break;
+ }
+}
+
+static void dbg_sectalign(int32_t seg, unsigned int value)
+{
+ fprintf(ofile, "set alignment (%d) for segment (%u)\n",
+ seg, value);
+}
+
+static enum directive_result
+dbg_directive(enum directive directive, char *value)
+{
+ switch (directive) {
+ /*
+ * The .obj GROUP directive is nontrivial to emulate in a macro.
+ * It effectively creates a "pseudo-section" containing the first
+ * space-separated argument; the rest we ignore.
+ */
+ case D_GROUP:
+ {
+ int dummy;
+ dbg_add_section(value, &dummy, "directive:group");
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ fprintf(ofile, "directive [%s] value [%s] pass %"PRId64" (%s)\n",
+ directive_dname(directive), value, pass_count(), pass_type_name());
+ return DIRR_OK;
+}
+
+static enum directive_result
+dbg_pragma(const struct pragma *pragma);
+
+static const struct pragma_facility dbg_pragma_list[] = {
+ { NULL, dbg_pragma }
+};
+
+static enum directive_result
+dbg_pragma(const struct pragma *pragma)
+{
+ fprintf(ofile, "pragma %s(%s) %s[%s] %s\n",
+ pragma->facility_name,
+ pragma->facility->name ? pragma->facility->name : "<default>",
+ pragma->opname, directive_dname(pragma->opcode),
+ pragma->tail);
+
+ if (pragma->facility == &dbg_pragma_list[0]) {
+ switch (pragma->opcode) {
+ case D_MAXDUMP:
+ if (!nasm_stricmp(pragma->tail, "unlimited")) {
+ dbg_max_data_dump = -1UL;
+ } else {
+ char *ep;
+ unsigned long arg;
+
+ errno = 0;
+ arg = strtoul(pragma->tail, &ep, 0);
+ if (errno || *nasm_skip_spaces(ep)) {
+ nasm_warn(WARN_PRAGMA_BAD | ERR_PASS2,
+ "invalid %%pragma dbg maxdump argument");
+ return DIRR_ERROR;
+ } else {
+ dbg_max_data_dump = arg;
+ }
+ }
+ break;
+ case D_NOSECLABELS:
+ section_labels = false;
+ break;
+ case D_SUBSECTIONS_VIA_SYMBOLS:
+ subsections_via_symbols = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return DIRR_OK;
+}
+
+static const char * const types[] = {
+ "unknown", "label", "byte", "word", "dword", "float", "qword", "tbyte"
+};
+static void dbgdbg_init(void)
+{
+ fprintf(ofile, "dbg init: debug information enabled\n");
+}
+static void dbgdbg_cleanup(void)
+{
+ fprintf(ofile, "dbg cleanup: called\n");
+}
+
+static void dbgdbg_linnum(const char *lnfname, int32_t lineno, int32_t segto)
+{
+ fprintf(ofile, "dbg linenum: %s(%"PRId32") segment %"PRIx32"\n",
+ lnfname, lineno, segto);
+}
+static void dbgdbg_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ fprintf(ofile, "dbg deflabel: %s = %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
+ name,
+ segment, offset,
+ is_global == 2 ? "common" : is_global ? "global" : "local",
+ is_global, special ? ": " : "", special);
+}
+
+static void dbgdbg_debug_smacros(bool define, const char *def)
+{
+ fprintf(ofile, "dbg define: %s [%s]\n",
+ define ? "define " : "undef ", def);
+}
+static void dbgdbg_debug_include(bool start, struct src_location outer,
+ struct src_location inner)
+{
+ fprintf(ofile, "dbg include: %s include: %s:%"PRId32" %s %s:%"PRId32"\n",
+ start ? "start" : "end", outer.filename, outer.lineno,
+ start ? "->" : "<-", inner.filename, inner.lineno);
+}
+
+static void dbgdbg_output(int output_type, void *param)
+{
+ (void)output_type;
+ (void)param;
+ fprintf(ofile, "dbg output: called\n");
+}
+static void dbgdbg_typevalue(int32_t type)
+{
+ fprintf(ofile, "dbg typevalue: %s(%"PRIX32")\n",
+ types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type));
+}
+
+static void
+write_macro_inv_list(const struct debug_macro_inv *inv, int level)
+{
+ int indent = (level+1) << 1;
+
+ while (inv) {
+ const struct rbtree *rb;
+
+ fprintf(ofile, "%*smacro: %s, invoked at %s:%"PRId32
+ ", %"PRIu32" ranges\n",
+ indent, "", inv->def->name, inv->where.filename,
+ inv->where.lineno, inv->naddr);
+
+ for (rb = rb_first(inv->addr.tree); rb; rb = rb_next(rb)) {
+ const struct debug_macro_addr *addr =
+ (const struct debug_macro_addr *)rb;
+ if (!addr->len) {
+ fprintf(ofile, "%*s%08"PRIx32": empty\n",
+ indent+2, "", debug_macro_seg(addr));
+ } else {
+ fprintf(ofile,
+ "%*s%08"PRIx32":[%016"PRIx64" ... %016"PRIx64"] "
+ "len %"PRIu64"\n",
+ indent+2, "",
+ debug_macro_seg(addr), addr->start,
+ addr->start + addr->len - 1, addr->len);
+ }
+ }
+
+ write_macro_inv_list(inv->down.l, level+1);
+ inv = inv->next;
+ }
+}
+
+static void dbgdbg_debug_mmacros(const struct debug_macro_info *dmi)
+{
+ const struct debug_macro_def *def;
+
+ fprintf(ofile, "dbg macros: %llu macros defined\n",
+ (unsigned long long)dmi->def.n);
+
+ fprintf(ofile, " macro definitions:\n");
+ list_for_each(def, dmi->def.l) {
+ fprintf(ofile, " macro: %s, count %llu, defined at %s:%"PRId32"\n",
+ def->name, (unsigned long long)def->ninv,
+ def->where.filename, def->where.lineno);
+ }
+
+ fprintf(ofile, " macro invocations:\n");
+ write_macro_inv_list(dmi->inv.l, 1);
+
+ fprintf(ofile, " end macro debug information\n");
+}
+
+static void dbgdbg_debug_directive(const char *id, const char *value)
+{
+ fprintf(ofile, "dbg directive: id [%s] value [%s] pass %"PRId64" (%s)\n",
+ id, value, pass_count(), pass_type_name());
+}
+
+
+static const struct pragma_facility dbgdbg_pragma_list[] = {
+ { "dbgdbg", dbg_pragma },
+ { NULL, dbg_pragma } /* Won't trigger, "debug" is a reserved ns */
+};
+
+static const struct dfmt debug_debug_form = {
+ "Trace of all info passed to debug stage",
+ "debug",
+ dbgdbg_init,
+ dbgdbg_linnum,
+ dbgdbg_deflabel,
+ dbgdbg_debug_smacros,
+ dbgdbg_debug_include,
+ dbgdbg_debug_mmacros,
+ dbgdbg_debug_directive,
+ dbgdbg_typevalue,
+ dbgdbg_output,
+ dbgdbg_cleanup,
+ dbgdbg_pragma_list
+};
+
+static const struct dfmt * const debug_debug_arr[3] = {
+ &debug_debug_form,
+ &null_debug_form,
+ NULL
+};
+
+extern macros_t dbg_stdmac[];
+
+const struct ofmt of_dbg = {
+ "Trace of all info passed to output stage",
+ "dbg",
+ ".dbg",
+ OFMT_TEXT|OFMT_KEEP_ADDR,
+ 64,
+ debug_debug_arr,
+ &debug_debug_form,
+ dbg_stdmac,
+ dbg_init,
+ dbg_reset,
+ dbg_out,
+ dbg_legacy_out,
+ dbg_deflabel,
+ dbg_section_names,
+ dbg_herelabel,
+ dbg_sectalign,
+ null_segbase,
+ dbg_directive,
+ dbg_cleanup,
+ dbg_pragma_list
+};
+
+#endif /* OF_DBG */
diff --git a/vere/ext/nasm/output/outdbg.mac b/vere/ext/nasm/output/outdbg.mac
new file mode 100644
index 0000000..44cd11c
--- /dev/null
+++ b/vere/ext/nasm/output/outdbg.mac
@@ -0,0 +1,56 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2017 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+;
+; Define a few macros which lets the dbg format process files intended
+; for the .obj and .bin formats.
+;
+OUT: dbg
+%define __?SECT?__ [section .text]
+%imacro group 1+.nolist
+[group %1]
+%endmacro
+%imacro uppercase 0+.nolist
+ %pragma dbg uppercase %1
+%endmacro
+%imacro export 1+.nolist
+ %pragma dbg export %1
+%endmacro
+%imacro import 1+.nolist
+ %pragma dbg import %1
+%endmacro
+%imacro org 1+.nolist
+ %pragma dbg org %1
+%endmacro
+%macro __?NASM_CDecl?__ 1
+%endmacro
diff --git a/vere/ext/nasm/output/outelf.c b/vere/ext/nasm/output/outelf.c
new file mode 100644
index 0000000..ad8d210
--- /dev/null
+++ b/vere/ext/nasm/output/outelf.c
@@ -0,0 +1,3672 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2022 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Common code for outelf32 and outelf64
+ */
+
+#include "compiler.h"
+
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "saa.h"
+#include "raa.h"
+#include "stdscan.h"
+#include "eval.h"
+#include "outform.h"
+#include "outlib.h"
+#include "rbtree.h"
+#include "hashtbl.h"
+#include "ver.h"
+
+#include "dwarf.h"
+#include "stabs.h"
+#include "outelf.h"
+#include "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 *symtab, *symtab_shndx;
+
+static struct SAA *strs;
+static uint32_t strslen;
+
+static struct RAA *section_by_index;
+static struct hash_table section_by_name;
+
+static struct elf_symbol *fwds;
+
+static char elf_module[FILENAME_MAX];
+static char elf_dir[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 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 size_t elf_build_symtab(void);
+static int add_sectname(const char *, const char *);
+
+/* First debugging section index */
+static int sec_debug;
+
+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 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 */
+
+/* This should match the order in elf_write() */
+enum dwarf_sect {
+ DWARF_ARANGES,
+ DWARF_RELA_ARANGES,
+ DWARF_PUBNAMES,
+ DWARF_INFO,
+ DWARF_RELA_INFO,
+ DWARF_ABBREV,
+ DWARF_LINE,
+ DWARF_RELA_LINE,
+ DWARF_FRAME,
+ DWARF_LOC,
+ DWARF_NSECT
+};
+
+struct dwarf_format {
+ uint16_t dwarf_version;
+ uint16_t sect_version[DWARF_NSECT];
+ /* ... add more here to generalize further */
+};
+const struct dwarf_format *dwfmt;
+
+static void dwarf32_init(void);
+static void dwarfx32_init(void);
+static void dwarf64_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);
+
+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 relsize; /* Size of a reltype 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);
+
+/*
+ * 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 */
+
+/* Known sections with nonstandard defaults. -n means n*pointer size. */
+struct elf_known_section {
+ const char *name; /* Name of section */
+ int type; /* Section type (SHT_) */
+ uint32_t flags; /* Section flags (SHF_) */
+ int align; /* Section alignment */
+ int entsize; /* Entry size, if applicable */
+};
+
+static const struct elf_known_section elf_known_sections[] = {
+ { ".text", SHT_PROGBITS, SHF_ALLOC|SHF_EXECINSTR, 16, 0 },
+ { ".rodata", SHT_PROGBITS, SHF_ALLOC, 4, 0 },
+ { ".lrodata", SHT_PROGBITS, SHF_ALLOC, 4, 0 },
+ { ".data", SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, 4, 0 },
+ { ".ldata", SHT_PROGBITS, SHF_ALLOC|SHF_WRITE, 4, 0 },
+ { ".bss", SHT_NOBITS, SHF_ALLOC|SHF_WRITE, 4, 0 },
+ { ".lbss", SHT_NOBITS, SHF_ALLOC|SHF_WRITE, 4, 0 },
+ { ".tdata", SHT_PROGBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4, 0 },
+ { ".tbss", SHT_NOBITS, SHF_ALLOC|SHF_WRITE|SHF_TLS, 4, 0 },
+ { ".comment", SHT_PROGBITS, 0, 1, 0 },
+ { ".preinit_array", SHT_PREINIT_ARRAY, SHF_ALLOC, -1, -1 },
+ { ".init_array", SHT_INIT_ARRAY, SHF_ALLOC, -1, -1 },
+ { ".fini_array", SHT_FINI_ARRAY, SHF_ALLOC, -1, -1 },
+ { ".note", SHT_NOTE, 0, 4, 0 },
+ { NULL /*default*/, SHT_PROGBITS, SHF_ALLOC, 1, 0 }
+};
+
+struct size_unit {
+ char name[8];
+ int bytes;
+ int align;
+};
+static const struct size_unit size_units[] =
+{
+ { "byte", 1, 1 },
+ { "word", 2, 2 },
+ { "dword", 4, 4 },
+ { "qword", 8, 8 },
+ { "tword", 10, 2 },
+ { "tbyte", 10, 2 },
+ { "oword", 16, 16 },
+ { "xword", 16, 16 },
+ { "yword", 32, 32 },
+ { "zword", 64, 64 },
+ { "pointer", -1, -1 },
+ { "", 0, 0 }
+};
+
+static inline size_t to_bytes(int val)
+{
+ return (val >= 0) ? (size_t)val : -val * efmt->word;
+}
+
+/* parse section attributes */
+static void elf_section_attrib(char *name, char *attr, uint32_t *flags_and, uint32_t *flags_or,
+ 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)
+ return;
+
+ while ((opt = nasm_opt_val(opt, &val, &next))) {
+ if (!nasm_stricmp(opt, "align")) {
+ if (!val) {
+ nasm_nonfatal("section align without value specified");
+ } else {
+ 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",
+ a);
+ } else if (a > align) {
+ align = a;
+ }
+ }
+ } else if (!nasm_stricmp(opt, "alloc")) {
+ *flags_and |= SHF_ALLOC;
+ *flags_or |= SHF_ALLOC;
+ } else if (!nasm_stricmp(opt, "noalloc")) {
+ *flags_and |= SHF_ALLOC;
+ *flags_or &= ~SHF_ALLOC;
+ } else if (!nasm_stricmp(opt, "exec")) {
+ *flags_and |= SHF_EXECINSTR;
+ *flags_or |= SHF_EXECINSTR;
+ } else if (!nasm_stricmp(opt, "noexec")) {
+ *flags_and |= SHF_EXECINSTR;
+ *flags_or &= ~SHF_EXECINSTR;
+ } else if (!nasm_stricmp(opt, "write")) {
+ *flags_and |= SHF_WRITE;
+ *flags_or |= SHF_WRITE;
+ } else if (!nasm_stricmp(opt, "nowrite") ||
+ !nasm_stricmp(opt, "readonly")) {
+ *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, "note")) {
+ *type = SHT_NOTE;
+ } else if (!nasm_stricmp(opt, "preinit_array")) {
+ *type = SHT_PREINIT_ARRAY;
+ } else if (!nasm_stricmp(opt, "init_array")) {
+ *type = SHT_INIT_ARRAY;
+ } else if (!nasm_stricmp(opt, "fini_array")) {
+ *type = SHT_FINI_ARRAY;
+ } else {
+ uint64_t mult;
+ size_t l;
+ const char *a = strchr(opt, '*');
+ bool err;
+ const struct size_unit *su;
+
+ if (a) {
+ l = a - opt - 1;
+ mult = readnum(a+1, &err);
+ } else {
+ l = strlen(opt);
+ mult = 1;
+ }
+
+ for (su = size_units; su->bytes; su++) {
+ if (!nasm_strnicmp(opt, su->name, l))
+ break;
+ }
+
+ if (su->bytes) {
+ *entsize = to_bytes(su->bytes) * mult;
+ xalign = to_bytes(su->align);
+ } else {
+ /* Unknown attribute */
+ nasm_warn(WARN_OTHER,
+ "unknown section attribute '%s' ignored on"
+ " declaration of section `%s'", opt, name);
+ }
+ }
+ opt = next;
+ }
+
+ switch (*type) {
+ case SHT_PREINIT_ARRAY:
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ if (!xalign)
+ xalign = efmt->word;
+ if (!*entsize)
+ *entsize = efmt->word;
+ break;
+ default:
+ break;
+ }
+
+ if (!align)
+ align = xalign;
+ if (!align)
+ align = SHA_ANY;
+
+ *alignp = align;
+}
+
+static enum directive_result
+elf_directive(enum directive directive, char *value)
+{
+ int64_t n;
+ bool err;
+ char *p;
+
+ switch (directive) {
+ case D_OSABI:
+ if (!pass_first()) /* XXX: Why? */
+ return DIRR_OK;
+
+ n = readnum(value, &err);
+ if (err) {
+ nasm_nonfatal("`osabi' directive requires a parameter");
+ return DIRR_ERROR;
+ }
+
+ if (n < 0 || n > 255) {
+ nasm_nonfatal("valid osabi numbers are 0 to 255");
+ return DIRR_ERROR;
+ }
+
+ elf_osabi = n;
+ elf_abiver = 0;
+
+ p = strchr(value,',');
+ if (!p)
+ return DIRR_OK;
+
+ n = readnum(p + 1, &err);
+ if (err || n < 0 || n > 255) {
+ nasm_nonfatal("invalid ABI version number (valid: 0 to 255)");
+ return DIRR_ERROR;
+ }
+
+ elf_abiver = n;
+ return DIRR_OK;
+
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+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),
+ ".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),
+ ".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),
+ ".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[] = {
+ ".shstrtab", ".strtab", ".symtab", ".symtab_shndx", NULL
+ };
+ const char * const *p;
+ const char * cur_path = nasm_realpath(inname);
+
+ strlcpy(elf_module, inname, sizeof(elf_module));
+ strlcpy(elf_dir, nasm_dirname(cur_path), sizeof(elf_dir));
+ 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("", ""); /* SHN_UNDEF */
+
+ fwds = NULL;
+
+ section_by_index = raa_init();
+
+ /*
+ * Add reserved section names to the section hash, with NULL
+ * as the data pointer
+ */
+ for (p = reserved_sections; *p; p++) {
+ struct hash_insert hi;
+ hash_find(&section_by_name, *p, &hi);
+ hash_add(&hi, *p, NULL);
+ }
+
+ /*
+ * FIXME: tlsie is Elf32 only and
+ * gottpoff is Elfx32|64 only.
+ */
+ elf_gotpc_sect = seg_alloc();
+ backend_label("..gotpc", elf_gotpc_sect + 1, 0L);
+ elf_gotoff_sect = seg_alloc();
+ backend_label("..gotoff", elf_gotoff_sect + 1, 0L);
+ elf_got_sect = seg_alloc();
+ backend_label("..got", elf_got_sect + 1, 0L);
+ elf_plt_sect = seg_alloc();
+ backend_label("..plt", elf_plt_sect + 1, 0L);
+ elf_sym_sect = seg_alloc();
+ backend_label("..sym", elf_sym_sect + 1, 0L);
+ elf_gottpoff_sect = seg_alloc();
+ backend_label("..gottpoff", elf_gottpoff_sect + 1, 0L);
+ elf_tlsie_sect = seg_alloc();
+ backend_label("..tlsie", elf_tlsie_sect + 1, 0L);
+
+ 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]->rel)
+ saa_free(sects[i]->rel);
+ while (sects[i]->head) {
+ r = sects[i]->head;
+ sects[i]->head = sects[i]->head->next;
+ nasm_free(r);
+ }
+ }
+ hash_free(&section_by_name);
+ raa_free(section_by_index);
+ nasm_free(sects);
+ saa_free(syms);
+ raa_free(bsym);
+ saa_free(strs);
+ dfmt->cleanup();
+}
+
+/*
+ * 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 l1 = strlen(firsthalf);
+ int l2 = strlen(secondhalf);
+
+ while (shstrtablen + l1 + l2 + 1 > shstrtabsize)
+ shstrtab = nasm_realloc(shstrtab, (shstrtabsize += SHSTR_DELTA));
+
+ memcpy(shstrtab + shstrtablen, firsthalf, l1);
+ shstrtablen += l1;
+ memcpy(shstrtab + shstrtablen, secondhalf, l2+1);
+ shstrtablen += l2 + 1;
+
+ return nsections++;
+}
+
+static struct elf_section *
+elf_make_section(char *name, int type, int flags, uint64_t 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();
+
+ s->name = nasm_strdup(name);
+ s->type = type;
+ s->flags = flags;
+ s->align = align;
+ s->shndx = add_sectname("", name);
+
+ if (nsects >= sectlen)
+ sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects));
+ sects[nsects++] = s;
+
+ return s;
+}
+
+static int32_t elf_section_names(char *name, int *bits)
+{
+ char *p;
+ uint32_t flags, flags_and, flags_or;
+ uint64_t align, entsize;
+ void **hp;
+ struct elf_section *s;
+ struct hash_insert hi;
+ int type;
+
+ if (!name) {
+ *bits = ofmt->maxbits;
+ return def_seg;
+ }
+
+ p = nasm_skip_word(name);
+ if (*p)
+ *p++ = '\0';
+ flags_and = flags_or = type = align = entsize = 0;
+
+ elf_section_attrib(name, p, &flags_and, &flags_or, &align, &entsize, &type);
+
+ hp = hash_find(&section_by_name, name, &hi);
+ if (hp) {
+ s = *hp;
+ if (!s) {
+ nasm_nonfatal("attempt to redefine reserved section name `%s'", name);
+ return NO_SEG;
+ }
+ } else {
+ const struct elf_known_section *ks = elf_known_sections;
+
+ while (ks->name) {
+ if (!strcmp(name, ks->name))
+ break;
+ ks++;
+ }
+
+ type = type ? type : ks->type;
+ if (!align)
+ align = to_bytes(ks->align);
+ if (!entsize)
+ entsize = to_bytes(ks->entsize);
+ flags = (ks->flags & ~flags_and) | flags_or;
+
+ s = elf_make_section(name, type, flags, align);
+ hash_add(&hi, s->name, s);
+ section_by_index = raa_write_ptr(section_by_index, s->index >> 1, s);
+ }
+
+ if ((type && s->type != type)
+ || ((s->flags & flags_and) != flags_or)
+ || (entsize && s->entsize && entsize != s->entsize)) {
+ nasm_warn(WARN_OTHER, "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 ((flags_or & SHF_MERGE) && s->entsize == 0) {
+ if (!(s->flags & SHF_STRINGS))
+ nasm_nonfatal("section attribute merge specified without an entry size or `strings'");
+ s->entsize = 1;
+ }
+
+ return s->index;
+}
+
+static inline bool sym_type_local(int type)
+{
+ return ELF32_ST_BIND(type) == STB_LOCAL;
+}
+
+static void elf_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special)
+{
+ int pos = strslen;
+ struct elf_symbol *sym;
+ const char *spcword = nasm_skip_spaces(special);
+ int bind, type; /* st_info components */
+ const struct elf_section *sec = NULL;
+
+ if (debug_level(2)) {
+ nasm_debug(" elf_deflabel: %s, seg=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n",
+ name, segment, offset, is_global, special);
+ }
+
+ 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_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_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;
+ bind = is_global ? STB_GLOBAL : STB_LOCAL;
+ type = STT_NOTYPE;
+ sym->other = STV_DEFAULT;
+ sym->size = 0;
+ if (segment == NO_SEG) {
+ sym->section = XSHN_ABS;
+ } else {
+ sym->section = XSHN_UNDEF;
+ if (segment == def_seg) {
+ /* we have to be sure at least text section is there */
+ int tempint;
+ if (segment != elf_section_names(".text", &tempint))
+ nasm_panic("strange segment conditions in ELF driver");
+ }
+ sec = raa_read_ptr(section_by_index, segment >> 1);
+ if (sec)
+ sym->section = sec->shndx;
+ }
+
+ if (is_global == 2) {
+ sym->size = offset;
+ sym->symv.key = 0;
+ 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
+ * as the alignment for the common variable.
+ *
+ * XXX: this should allow an expression.
+ */
+ if (spcword) {
+ bool err;
+ sym->symv.key = readnum(spcword, &err);
+ if (err)
+ nasm_nonfatal("alignment constraint `%s' is not a"
+ " valid number", special);
+ else if (!is_power2(sym->symv.key))
+ nasm_nonfatal("alignment constraint `%s' is not a"
+ " power of two", special);
+ spcword = nasm_skip_spaces(nasm_skip_word(spcword));
+ }
+ } else {
+ sym->symv.key = (sym->section == XSHN_UNDEF ? 0 : offset);
+ }
+
+ if (spcword && *spcword) {
+ const char *wend;
+ bool ok = true;
+
+ while (ok) {
+ size_t wlen;
+ wend = nasm_skip_word(spcword);
+ wlen = wend - spcword;
+
+ switch (wlen) {
+ case 4:
+ if (!nasm_strnicmp(spcword, "data", wlen))
+ type = STT_OBJECT;
+ else if (!nasm_strnicmp(spcword, "weak", wlen))
+ bind = STB_WEAK;
+ else
+ ok = false;
+ break;
+
+ case 6:
+ if (!nasm_strnicmp(spcword, "notype", wlen))
+ type = STT_NOTYPE;
+ else if (!nasm_strnicmp(spcword, "object", wlen))
+ type = STT_OBJECT;
+ else if (!nasm_strnicmp(spcword, "hidden", wlen))
+ sym->other = STV_HIDDEN;
+ else if (!nasm_strnicmp(spcword, "strong", wlen))
+ bind = STB_GLOBAL;
+ else
+ ok = false;
+ break;
+
+ case 7:
+ if (!nasm_strnicmp(spcword, "default", wlen))
+ sym->other = STV_DEFAULT;
+ else
+ ok = false;
+ break;
+
+ case 8:
+ if (!nasm_strnicmp(spcword, "function", wlen))
+ type = STT_FUNC;
+ else if (!nasm_stricmp(spcword, "internal"))
+ sym->other = STV_INTERNAL;
+ else
+ ok = false;
+ break;
+
+ case 9:
+ if (!nasm_strnicmp(spcword, "protected", wlen))
+ sym->other = STV_PROTECTED;
+ else
+ ok = false;
+ break;
+
+ default:
+ ok = false;
+ break;
+ }
+
+ if (ok)
+ spcword = nasm_skip_spaces(wend);
+ }
+ if (!is_global && bind != STB_LOCAL) {
+ nasm_nonfatal("weak and strong only applies to global symbols");
+ bind = STB_LOCAL;
+ }
+
+ if (spcword && *spcword) {
+ struct tokenval tokval;
+ expr *e;
+ int fwd = 0;
+ char *saveme = stdscan_get();
+
+ /*
+ * We have a size expression; attempt to
+ * evaluate it.
+ */
+ stdscan_reset();
+ stdscan_set((char *)spcword);
+ 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_nonfatal("cannot use relocatable"
+ " expression as symbol size");
+ else
+ sym->size = reloc_value(e);
+ }
+ stdscan_set(saveme);
+ }
+ }
+
+ /*
+ * If it is in a TLS segment, mark symbol accordingly.
+ */
+ if (sec && (sec->flags & SHF_TLS))
+ type = STT_TLS;
+
+ /* Note: ELF32_ST_INFO() and ELF64_ST_INFO() are identical */
+ sym->type = ELF32_ST_INFO(bind, type);
+
+ if (sym_type_local(sym->type)) {
+ nlocals++;
+ } else {
+ /*
+ * 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 == XSHN_UNDEF || sym->section == XSHN_COMMON) {
+ bsym = raa_write(bsym, segment, nglobs);
+ } 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.
+ *
+ * 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);
+
+ }
+ sym->globnum = nglobs;
+ nglobs++;
+ }
+}
+
+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) {
+ 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;
+
+ 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;
+
+ /*
+ * 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 = raa_read_ptr(section_by_index, segment >> 1);
+ if (!s) {
+ if (exact && offset)
+ nasm_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_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;
+ static struct symlininfo sinfo;
+
+ /*
+ * handle absolute-assembly (structure definitions)
+ */
+ if (segto == NO_SEG) {
+ if (type != OUT_RESERVE)
+ nasm_nonfatal("attempt to assemble code in [ABSOLUTE] space");
+ return;
+ }
+
+ s = raa_read_ptr(section_by_index, segto >> 1);
+ if (!s) {
+ int tempint; /* ignored */
+ if (segto != elf_section_names(".text", &tempint))
+ nasm_panic("strange segment conditions in ELF driver");
+ else
+ s = sects[nsects - 1];
+ }
+
+ /* again some stabs debugging stuff */
+ sinfo.offset = s->len;
+ /* Adjust to an index of the section table. */
+ sinfo.section = s->shndx - 1;
+ 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_warn(WARN_OTHER, "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_NOBITS) {
+ nasm_warn(WARN_ZEROING, "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:
+ elf_sect_write(s, data, size);
+ break;
+
+ case OUT_ADDRESS:
+ {
+ bool err = false;
+ int asize = abs((int)size);
+
+ addr = *(int64_t *)data;
+ if (segment != NO_SEG) {
+ if (segment & 1) {
+ nasm_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:
+ elf_add_reloc(s, segment, 0, R_386_8);
+ break;
+ case 2:
+ 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 */
+ err = true;
+ 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 $-$$.
+ */
+ err = asize != 4;
+ addr += s->len;
+ elf_add_reloc(s, segment, 0, R_386_GOTPC);
+ } else if (wrt == elf_gotoff_sect + 1) {
+ err = asize != 4;
+ elf_add_reloc(s, segment, 0, R_386_GOTOFF);
+ } else if (wrt == elf_tlsie_sect + 1) {
+ err = asize != 4;
+ addr = elf_add_gsym_reloc(s, segment, addr, 0,
+ R_386_TLS_IE, true);
+ } else if (wrt == elf_got_sect + 1) {
+ err = asize != 4;
+ addr = elf_add_gsym_reloc(s, segment, addr, 0,
+ R_386_GOT32, true);
+ } else if (wrt == elf_sym_sect + 1) {
+ switch (asize) {
+ case 1:
+ addr = elf_add_gsym_reloc(s, segment, addr, 0,
+ R_386_8, false);
+ break;
+ case 2:
+ 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:
+ err = true;
+ break;
+ }
+ } else if (wrt == elf_plt_sect + 1) {
+ nasm_nonfatal("ELF format cannot produce non-PC-"
+ "relative PLT references");
+ } else {
+ nasm_nonfatal("ELF format does not support this"
+ " use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ }
+ }
+ }
+
+ if (err) {
+ nasm_nonfatal("Unsupported %d-bit ELF relocation", asize << 3);
+ }
+ 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 & 1)) {
+ nasm_nonfatal("ELF format does not support"
+ " segment base references");
+ } else {
+ if (wrt == NO_SEG) {
+ elf_add_reloc(s, segment, 0, reltype);
+ } else {
+ nasm_nonfatal("Unsupported %d-bit ELF relocation", bytes << 3);
+ }
+ }
+ elf_sect_writeaddr(s, addr, bytes);
+ break;
+
+ case OUT_REL4ADR:
+ addr = *(int64_t *)data - size;
+ if (segment == segto)
+ nasm_panic("intra-segment OUT_REL4ADR");
+ if (segment != NO_SEG && (segment & 1)) {
+ nasm_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_nonfatal("ELF format cannot produce PC-"
+ "relative GOT references");
+ } else {
+ nasm_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_nonfatal("32-bit ELF format does not support 64-bit relocations");
+ addr = 0;
+ elf_sect_writeaddr(s, addr, 8);
+ break;
+
+ default:
+ panic();
+ }
+}
+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;
+ static struct symlininfo sinfo;
+
+ /*
+ * handle absolute-assembly (structure definitions)
+ */
+ if (segto == NO_SEG) {
+ if (type != OUT_RESERVE)
+ nasm_nonfatal("attempt to assemble code in [ABSOLUTE] space");
+ return;
+ }
+
+ s = raa_read_ptr(section_by_index, segto >> 1);
+ if (!s) {
+ int tempint; /* ignored */
+ if (segto != elf_section_names(".text", &tempint))
+ nasm_panic("strange segment conditions in ELF driver");
+ else
+ s = sects[nsects - 1];
+ }
+
+ /* again some stabs debugging stuff */
+ sinfo.offset = s->len;
+ /* Adjust to an index of the section table. */
+ sinfo.section = s->shndx - 1;
+ 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_warn(WARN_OTHER, "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_NOBITS) {
+ nasm_warn(WARN_ZEROING, "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("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 & 1) {
+ nasm_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("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_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_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("internal error elf64-hpa-903");
+ break;
+ }
+ } else if (wrt == elf_plt_sect + 1) {
+ nasm_nonfatal("ELF format cannot produce non-PC-"
+ "relative PLT references");
+ } else {
+ nasm_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("intra-segment OUT_REL1ADR");
+ if (segment == NO_SEG) {
+ /* Do nothing */
+ } else if (segment & 1) {
+ nasm_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_nonfatal("Unsupported %d-bit ELF relocation", bytes << 3);
+ }
+ }
+ elf_sect_writeaddr(s, addr, bytes);
+ break;
+
+ case OUT_REL4ADR:
+ addr = *(int64_t *)data - size;
+ if (segment == segto)
+ nasm_panic("intra-segment OUT_REL4ADR");
+ if (segment == NO_SEG) {
+ /* Do nothing */
+ } else if (segment & 1) {
+ nasm_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_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_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("intra-segment OUT_REL8ADR");
+ if (segment == NO_SEG) {
+ /* Do nothing */
+ } else if (segment & 1) {
+ nasm_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_nonfatal("ELF64 requires ..gotoff references to be "
+ "absolute");
+ } else if (wrt == elf_gottpoff_sect + 1) {
+ nasm_nonfatal("ELF64 requires ..gottpoff references to be "
+ "dword");
+ } else {
+ nasm_nonfatal("ELF64 format does not support this"
+ " use of WRT");
+ }
+ }
+ elf_sect_writeaddr(s, addr, 8);
+ break;
+
+ default:
+ panic();
+ }
+}
+
+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;
+ static struct symlininfo sinfo;
+
+ /*
+ * handle absolute-assembly (structure definitions)
+ */
+ if (segto == NO_SEG) {
+ if (type != OUT_RESERVE)
+ nasm_nonfatal("attempt to assemble code in [ABSOLUTE] space");
+ return;
+ }
+
+ s = raa_read_ptr(section_by_index, segto >> 1);
+ if (!s) {
+ int tempint; /* ignored */
+ if (segto != elf_section_names(".text", &tempint))
+ nasm_panic("strange segment conditions in ELF driver");
+ else
+ s = sects[nsects - 1];
+ }
+
+ /* again some stabs debugging stuff */
+ sinfo.offset = s->len;
+ /* Adjust to an index of the section table. */
+ sinfo.section = s->shndx - 1;
+ 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_warn(WARN_OTHER, "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_NOBITS) {
+ nasm_warn(WARN_ZEROING, "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("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 & 1) {
+ nasm_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("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_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_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("internal error elfx32-hpa-903");
+ break;
+ }
+ } else if (wrt == elf_plt_sect + 1) {
+ nasm_nonfatal("ELF format cannot produce non-PC-"
+ "relative PLT references");
+ } else {
+ nasm_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("intra-segment OUT_REL1ADR");
+ if (segment == NO_SEG) {
+ /* Do nothing */
+ } else if (segment & 1) {
+ nasm_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_nonfatal("unsupported %d-bit ELF relocation", bytes << 3);
+ }
+ }
+ elf_sect_writeaddr(s, addr, bytes);
+ break;
+
+ case OUT_REL4ADR:
+ addr = *(int64_t *)data - size;
+ if (segment == segto)
+ nasm_panic("intra-segment OUT_REL4ADR");
+ if (segment == NO_SEG) {
+ /* Do nothing */
+ } else if (segment & 1) {
+ nasm_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_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_nonfatal("ELFX32 format does not support this use of WRT");
+ }
+ }
+ elf_sect_writeaddr(s, addr, 4);
+ break;
+
+ case OUT_REL8ADR:
+ nasm_nonfatal("32-bit ELF format does not support 64-bit relocations");
+ addr = 0;
+ elf_sect_writeaddr(s, addr, 8);
+ break;
+
+ default:
+ panic();
+ }
+}
+
+/*
+ * 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;
+ size_t symtablocal;
+ int sec_shstrtab, sec_symtab, sec_strtab;
+ union ehdr ehdr;
+
+ /*
+ * Add any sections we don't already have:
+ * rel/rela sections for the user sections, debug sections, and
+ * the ELF special sections.
+ */
+
+ 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(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. */
+ add_sectname("", ".debug_aranges");
+ add_sectname(efmt->relpfx, ".debug_aranges");
+ add_sectname("", ".debug_pubnames");
+ add_sectname("", ".debug_info");
+ add_sectname(efmt->relpfx, ".debug_info");
+ add_sectname("", ".debug_abbrev");
+ add_sectname("", ".debug_line");
+ add_sectname(efmt->relpfx, ".debug_line");
+ add_sectname("", ".debug_frame");
+ add_sectname("", ".debug_loc");
+ }
+
+ sec_shstrtab = add_sectname("", ".shstrtab");
+ sec_symtab = add_sectname("", ".symtab");
+ sec_strtab = add_sectname("", ".strtab");
+
+ /*
+ * Build the symbol table and relocation tables.
+ */
+ symtablocal = elf_build_symtab();
+
+ /* Do we need an .symtab_shndx section? */
+ if (symtab_shndx)
+ add_sectname("", ".symtab_shndx");
+
+ 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);
+ }
+ }
+
+ /*
+ * Output the ELF header.
+ */
+ 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.
+ */
+ 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,
+ nsections > (int)SHN_LORESERVE ? nsections : 0,
+ sec_shstrtab >= (int)SHN_LORESERVE ? sec_shstrtab : 0,
+ 0, 0, 0);
+ p = shstrtab + 1;
+
+ /* The normal sections */
+ for (i = 0; i < nsects; i++) {
+ elf_section_header(p - shstrtab, sects[i]->type, sects[i]->flags,
+ sects[i]->data, true,
+ sects[i]->len, 0, 0,
+ sects[i]->align, sects[i]->entsize);
+ 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 */
+
+ /* this function call creates the stab sections in memory */
+ stabs_generate();
+
+ if (stabbuf && stabstrbuf && stabrelbuf) {
+ elf_section_header(p - shstrtab, SHT_PROGBITS, 0, stabbuf, false,
+ stablen, sec_stabstr, 0, 4, 12);
+ p += strlen(p) + 1;
+
+ elf_section_header(p - shstrtab, SHT_STRTAB, 0, stabstrbuf, false,
+ stabstrlen, 0, 0, 4, 0);
+ p += strlen(p) + 1;
+
+ /* link -> symtable info -> section to refer to */
+ elf_section_header(p - shstrtab, efmt->reltype, 0,
+ stabrelbuf, false, stabrellen,
+ sec_symtab, sec_stab,
+ efmt->word, efmt->relsize);
+ p += strlen(p) + 1;
+ }
+ } else if (dfmt_is_dwarf()) {
+ /* for dwarf debugging information, create the ten dwarf sections */
+
+ /* 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, efmt->reltype, 0, arangesrelbuf, false,
+ arangesrellen, sec_symtab,
+ sec_debug_aranges,
+ efmt->word, efmt->relsize);
+ 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, efmt->reltype, 0, inforelbuf, false,
+ inforellen, sec_symtab,
+ sec_debug_info,
+ efmt->word, efmt->relsize);
+ 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, efmt->reltype, 0, linerelbuf, false,
+ linerellen, sec_symtab,
+ sec_debug_line,
+ efmt->word, efmt->relsize);
+ 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;
+ }
+
+ /* 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->relsize);
+ p += strlen(p) + 1;
+ }
+ }
+ fwritezero(align, ofile);
+
+ /*
+ * Now output the sections.
+ */
+ elf_write_sections();
+
+ nasm_free(elf_sects);
+ saa_free(symtab);
+ if (symtab_shndx)
+ saa_free(symtab_shndx);
+}
+
+static size_t nsyms;
+
+static void elf_sym(const struct elf_symbol *sym)
+{
+ int shndx = sym->section;
+
+ /*
+ * Careful here. This relies on sym->section being signed; for
+ * special section indices 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);
+
+ efmt->elf_sym(sym);
+ nsyms++;
+}
+
+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.
+ */
+ nasm_zero(xsym);
+ elf_sym(&xsym);
+
+ /*
+ * Next, an entry for the file name.
+ */
+ 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.
+ */
+ 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);
+ while ((sym = saa_rstruct(syms))) {
+ if (!sym_type_local(sym->type))
+ continue;
+
+ elf_sym(sym);
+ }
+
+ nlocal = nsyms;
+
+ /*
+ * Now the global symbols.
+ */
+ saa_rewind(syms);
+ while ((sym = saa_rstruct(syms))) {
+ if (sym_type_local(sym->type))
+ continue;
+
+ elf_sym(sym);
+ }
+
+ return nlocal;
+}
+
+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;
+
+ 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);
+
+ /*
+ * 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;
+
+ if (sym >= GLOBAL_TEMP_BASE)
+ sym += global_offset;
+
+ 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;
+ }
+
+ return s;
+}
+
+static struct SAA *elf64_build_reltab(const struct elf_reloc *r)
+{
+ struct SAA *s;
+ int32_t global_offset;
+ Elf64_Rela rela64;
+
+ 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;
+
+ 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;
+}
+
+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)
+{
+ elf_sects[elf_nsect].data = data;
+ elf_sects[elf_nsect].len = datalen;
+ elf_sects[elf_nsect].is_saa = is_saa;
+ elf_nsect++;
+
+ 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.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);
+
+ 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.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, sizeof shdr, ofile);
+ }
+}
+
+static void elf_write_sections(void)
+{
+ int i;
+ for (i = 0; i < elf_nsect; i++)
+ if (elf_sects[i].data) {
+ int32_t len = elf_sects[i].len;
+ int32_t reallen = ALIGN(len, SEC_FILEALIGN);
+ int32_t align = reallen - len;
+ if (elf_sects[i].is_saa)
+ saa_fpwrite(elf_sects[i].data, ofile);
+ else
+ nasm_write(elf_sects[i].data, len, ofile);
+ fwritezero(align, ofile);
+ }
+}
+
+static void elf_sect_write(struct elf_section *sect, const void *data, size_t len)
+{
+ saa_wbytes(sect->data, data, len);
+ sect->len += len;
+}
+
+static void elf_sect_writeaddr(struct elf_section *sect, int64_t data, size_t len)
+{
+ saa_writeaddr(sect->data, data, len);
+ sect->len += len;
+}
+
+static void elf_sectalign(int32_t seg, unsigned int value)
+{
+ struct elf_section *s;
+
+ s = raa_read_ptr(section_by_index, seg >> 1);
+ if (!s || !is_power2(value))
+ return;
+
+ if (value > s->align)
+ s->align = value;
+}
+
+extern macros_t elf_stdmac[];
+
+/* Claim "elf" as a pragma namespace, for the future */
+static const struct pragma_facility elf_pragma_list[] =
+{
+ { "elf", NULL },
+ { NULL, NULL } /* Implements the canonical output name */
+};
+
+
+static const struct dfmt elf32_df_dwarf = {
+ "ELF32 (i386) dwarf (newer)",
+ "dwarf",
+ dwarf32_init,
+ dwarf_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ dwarf_output,
+ dwarf_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt elf32_df_stabs = {
+ "ELF32 (i386) stabs (older)",
+ "stabs",
+ null_debug_init,
+ stabs_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ stabs_output,
+ stabs_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt * const elf32_debugs_arr[3] =
+ { &elf32_df_dwarf, &elf32_df_stabs, NULL };
+
+const struct ofmt of_elf32 = {
+ "ELF32 (i386) (Linux, most Unix variants)",
+ "elf32",
+ ".o",
+ 0,
+ 32,
+ elf32_debugs_arr,
+ &elf32_df_dwarf,
+ elf_stdmac,
+ elf32_init,
+ null_reset,
+ nasm_do_legacy_output,
+ elf32_out,
+ elf_deflabel,
+ elf_section_names,
+ NULL,
+ elf_sectalign,
+ null_segbase,
+ elf_directive,
+ elf_cleanup,
+ elf_pragma_list,
+};
+
+static const struct dfmt elf64_df_dwarf = {
+ "ELF64 (x86-64) dwarf (newer)",
+ "dwarf",
+ dwarf64_init,
+ dwarf_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ dwarf_output,
+ dwarf_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt elf64_df_stabs = {
+ "ELF64 (x86-64) stabs (older)",
+ "stabs",
+ null_debug_init,
+ stabs_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ stabs_output,
+ stabs_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt * const elf64_debugs_arr[3] =
+ { &elf64_df_dwarf, &elf64_df_stabs, NULL };
+
+const struct ofmt of_elf64 = {
+ "ELF64 (x86-64) (Linux, most Unix variants)",
+ "elf64",
+ ".o",
+ 0,
+ 64,
+ elf64_debugs_arr,
+ &elf64_df_dwarf,
+ elf_stdmac,
+ elf64_init,
+ null_reset,
+ nasm_do_legacy_output,
+ elf64_out,
+ elf_deflabel,
+ elf_section_names,
+ NULL,
+ elf_sectalign,
+ null_segbase,
+ elf_directive,
+ elf_cleanup,
+ elf_pragma_list,
+};
+
+static const struct dfmt elfx32_df_dwarf = {
+ "ELFx32 (x86-64) dwarf (newer)",
+ "dwarf",
+ dwarfx32_init,
+ dwarf_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ dwarf_output,
+ dwarf_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt elfx32_df_stabs = {
+ "ELFx32 (x86-64) stabs (older)",
+ "stabs",
+ null_debug_init,
+ stabs_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ debug_typevalue,
+ stabs_output,
+ stabs_cleanup,
+ elf_pragma_list,
+};
+
+static const struct dfmt * const elfx32_debugs_arr[3] =
+ { &elfx32_df_dwarf, &elfx32_df_stabs, NULL };
+
+const struct ofmt of_elfx32 = {
+ "ELFx32 (ELF32 for x86-64) (Linux)",
+ "elfx32",
+ ".o",
+ 0,
+ 64,
+ elfx32_debugs_arr,
+ &elfx32_df_dwarf,
+ elf_stdmac,
+ elfx32_init,
+ null_reset,
+ nasm_do_legacy_output,
+ elfx32_out,
+ elf_deflabel,
+ elf_section_names,
+ NULL,
+ elf_sectalign,
+ null_segbase,
+ elf_directive,
+ elf_cleanup,
+ NULL /* pragma list */
+};
+
+static bool is_elf64(void)
+{
+ return ofmt == &of_elf64;
+}
+
+static bool is_elf32(void)
+{
+ return ofmt == &of_elf32;
+}
+
+static bool is_elfx32(void)
+{
+ return ofmt == &of_elfx32;
+}
+
+static bool dfmt_is_stabs(void)
+{
+ return dfmt == &elf32_df_stabs ||
+ dfmt == &elfx32_df_stabs ||
+ dfmt == &elf64_df_stabs;
+}
+
+static bool dfmt_is_dwarf(void)
+{
+ return dfmt == &elf32_df_dwarf ||
+ dfmt == &elfx32_df_dwarf ||
+ dfmt == &elf64_df_dwarf;
+}
+
+/* common debugging routines */
+static void debug_typevalue(int32_t type)
+{
+ int32_t stype, ssize;
+ switch (TYM_TYPE(type)) {
+ case TY_LABEL:
+ ssize = 0;
+ stype = STT_NOTYPE;
+ break;
+ case TY_BYTE:
+ ssize = 1;
+ stype = STT_OBJECT;
+ break;
+ case TY_WORD:
+ ssize = 2;
+ stype = STT_OBJECT;
+ break;
+ case TY_DWORD:
+ ssize = 4;
+ stype = STT_OBJECT;
+ break;
+ case TY_FLOAT:
+ ssize = 4;
+ stype = STT_OBJECT;
+ break;
+ case TY_QWORD:
+ ssize = 8;
+ stype = STT_OBJECT;
+ break;
+ case TY_TBYTE:
+ ssize = 10;
+ stype = STT_OBJECT;
+ break;
+ case TY_OWORD:
+ ssize = 16;
+ stype = STT_OBJECT;
+ break;
+ case TY_YWORD:
+ ssize = 32;
+ stype = STT_OBJECT;
+ break;
+ case TY_ZWORD:
+ ssize = 64;
+ stype = STT_OBJECT;
+ break;
+ case TY_COMMON:
+ ssize = 0;
+ stype = STT_COMMON;
+ break;
+ case TY_SEG:
+ ssize = 0;
+ stype = STT_SECTION;
+ break;
+ case TY_EXTERN:
+ ssize = 0;
+ stype = STT_NOTYPE;
+ break;
+ case TY_EQU:
+ ssize = 0;
+ stype = STT_NOTYPE;
+ break;
+ default:
+ ssize = 0;
+ stype = STT_NOTYPE;
+ break;
+ }
+ /* Set type and size info on most recently seen symbol if we haven't set it already.
+ But avoid setting size info on object (data) symbols in absolute sections (which
+ is primarily structs); some environments get confused with non-zero-extent absolute
+ object symbols and end up showing them in backtraces for NULL fn pointer calls. */
+ if (stype == STT_OBJECT && lastsym && !lastsym->type && lastsym->section != XSHN_ABS) {
+ lastsym->size = ssize;
+ lastsym->type = stype;
+ }
+}
+
+/* stabs debugging routines */
+
+static void stabs_linenum(const char *filename, int32_t linenumber, int32_t segto)
+{
+ (void)segto;
+ if (!stabs_filename) {
+ stabs_filename = nasm_malloc(strlen(filename) + 1);
+ strcpy(stabs_filename, filename);
+ } else {
+ if (strcmp(stabs_filename, filename)) {
+ /* yep, a memory leak...this program is one-shot anyway, so who cares...
+ in fact, this leak comes in quite handy to maintain a list of files
+ encountered so far in the symbol lines... */
+
+ /* why not nasm_free(stabs_filename); we're done with the old one */
+
+ stabs_filename = nasm_malloc(strlen(filename) + 1);
+ strcpy(stabs_filename, filename);
+ }
+ }
+ debug_immcall = 1;
+ currentline = linenumber;
+}
+
+static void stabs_output(int type, void *param)
+{
+ struct symlininfo *s;
+ struct linelist *el;
+ if (type == TY_DEBUGSYMLIN) {
+ if (debug_immcall) {
+ s = (struct symlininfo *)param;
+ if (!(sects[s->section]->flags & SHF_EXECINSTR))
+ return; /* line info is only collected for executable sections */
+ numlinestabs++;
+ el = nasm_malloc(sizeof(struct linelist));
+ el->info.offset = s->offset;
+ el->info.section = s->section;
+ el->info.name = s->name;
+ el->line = currentline;
+ el->filename = stabs_filename;
+ el->next = 0;
+ if (stabslines) {
+ stabslines->last->next = el;
+ stabslines->last = el;
+ } else {
+ stabslines = el;
+ stabslines->last = el;
+ }
+ }
+ }
+ debug_immcall = 0;
+}
+
+/* for creating the .stab , .stabstr and .rel.stab sections in memory */
+
+static void stabs_generate(void)
+{
+ int i, numfiles, strsize, numstabs = 0, currfile, mainfileindex;
+ uint8_t *sbuf, *ssbuf, *rbuf, *sptr, *rptr;
+ char **allfiles;
+ int *fileidx;
+
+ struct linelist *ptr;
+
+ ptr = stabslines;
+
+ allfiles = nasm_zalloc(numlinestabs * sizeof(char *));
+ numfiles = 0;
+ while (ptr) {
+ if (numfiles == 0) {
+ allfiles[0] = ptr->filename;
+ numfiles++;
+ } else {
+ for (i = 0; i < numfiles; i++) {
+ if (!strcmp(allfiles[i], ptr->filename))
+ break;
+ }
+ if (i >= numfiles) {
+ allfiles[i] = ptr->filename;
+ numfiles++;
+ }
+ }
+ ptr = ptr->next;
+ }
+ strsize = 1;
+ fileidx = nasm_malloc(numfiles * sizeof(int));
+ for (i = 0; i < numfiles; i++) {
+ fileidx[i] = strsize;
+ strsize += strlen(allfiles[i]) + 1;
+ }
+ currfile = mainfileindex = 0;
+ for (i = 0; i < numfiles; i++) {
+ if (!strcmp(allfiles[i], elf_module)) {
+ currfile = mainfileindex = i;
+ break;
+ }
+ }
+
+ /*
+ * worst case size of the stab buffer would be:
+ * the sourcefiles changes each line, which would mean 1 SOL, 1 SYMLIN per line
+ * plus one "ending" entry
+ */
+ sbuf = nasm_malloc((numlinestabs * 2 + 4) *
+ sizeof(struct stabentry));
+ ssbuf = nasm_malloc(strsize);
+ rbuf = nasm_malloc(numlinestabs * (is_elf64() ? 16 : 8) * (2 + 3));
+ rptr = rbuf;
+
+ for (i = 0; i < numfiles; i++)
+ strcpy((char *)ssbuf + fileidx[i], allfiles[i]);
+ ssbuf[0] = 0;
+
+ stabstrlen = strsize; /* set global variable for length of stab strings */
+
+ sptr = sbuf;
+ ptr = stabslines;
+ numstabs = 0;
+
+ if (ptr) {
+ /*
+ * this is the first stab, its strx points to the filename of the
+ * source-file, the n_desc field should be set to the number
+ * of remaining stabs
+ */
+ WRITE_STAB(sptr, fileidx[0], 0, 0, 0, stabstrlen);
+
+ /* this is the stab for the main source file */
+ WRITE_STAB(sptr, fileidx[mainfileindex], N_SO, 0, 0, 0);
+
+ /* relocation table entry */
+
+ /*
+ * Since the symbol table has two entries before
+ * the section symbols, the index in the info.section
+ * member must be adjusted by adding 2
+ */
+
+ if (is_elf32()) {
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32);
+ } else if (is_elfx32()) {
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32);
+ WRITELONG(rptr, 0);
+ } else {
+ nasm_assert(is_elf64());
+ WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4);
+ WRITELONG(rptr, R_X86_64_32);
+ WRITELONG(rptr, ptr->info.section + 2);
+ WRITEDLONG(rptr, 0);
+ }
+ numstabs++;
+ }
+
+ if (is_elf32()) {
+ while (ptr) {
+ if (strcmp(allfiles[currfile], ptr->filename)) {
+ /* oops file has changed... */
+ for (i = 0; i < numfiles; i++)
+ if (!strcmp(allfiles[i], ptr->filename))
+ break;
+ currfile = i;
+ WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0,
+ ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32);
+ }
+
+ WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_386_32);
+
+ ptr = ptr->next;
+ }
+ } else if (is_elfx32()) {
+ while (ptr) {
+ if (strcmp(allfiles[currfile], ptr->filename)) {
+ /* oops file has changed... */
+ for (i = 0; i < numfiles; i++)
+ if (!strcmp(allfiles[i], ptr->filename))
+ break;
+ currfile = i;
+ WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0,
+ ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32);
+ WRITELONG(rptr, ptr->info.offset);
+ }
+
+ WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITELONG(rptr, (sptr - sbuf) - 4);
+ WRITELONG(rptr, ((ptr->info.section + 2) << 8) | R_X86_64_32);
+ WRITELONG(rptr, ptr->info.offset);
+
+ ptr = ptr->next;
+ }
+ } else {
+ nasm_assert(is_elf64());
+ while (ptr) {
+ if (strcmp(allfiles[currfile], ptr->filename)) {
+ /* oops file has changed... */
+ for (i = 0; i < numfiles; i++)
+ if (!strcmp(allfiles[i], ptr->filename))
+ break;
+ currfile = i;
+ WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0,
+ ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4);
+ WRITELONG(rptr, R_X86_64_32);
+ WRITELONG(rptr, ptr->info.section + 2);
+ WRITEDLONG(rptr, ptr->info.offset);
+ }
+
+ WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset);
+ numstabs++;
+
+ /* relocation table entry */
+ WRITEDLONG(rptr, (int64_t)(sptr - sbuf) - 4);
+ WRITELONG(rptr, R_X86_64_32);
+ WRITELONG(rptr, ptr->info.section + 2);
+ WRITEDLONG(rptr, ptr->info.offset);
+
+ ptr = ptr->next;
+ }
+ }
+
+ /* this is an "ending" token */
+ WRITE_STAB(sptr, 0, N_SO, 0, 0, 0);
+ numstabs++;
+
+ ((struct stabentry *)sbuf)->n_desc = numstabs;
+
+ nasm_free(allfiles);
+ nasm_free(fileidx);
+
+ stablen = (sptr - sbuf);
+ stabrellen = (rptr - rbuf);
+ stabrelbuf = rbuf;
+ stabbuf = sbuf;
+ stabstrbuf = ssbuf;
+}
+
+static void stabs_cleanup(void)
+{
+ struct linelist *ptr, *del;
+ if (!stabslines)
+ return;
+
+ ptr = stabslines;
+ while (ptr) {
+ del = ptr;
+ ptr = ptr->next;
+ nasm_free(del);
+ }
+
+ nasm_free(stabbuf);
+ nasm_free(stabrelbuf);
+ nasm_free(stabstrbuf);
+}
+
+/* dwarf routines */
+
+static void dwarf_init_common(const struct dwarf_format *fmt)
+{
+ dwfmt = fmt;
+ ndebugs = 3; /* 3 debug symbols */
+}
+
+static void dwarf32_init(void)
+{
+ static const struct dwarf_format dwfmt32 = {
+ 2, /* DWARF 2 */
+ /* section version numbers: */
+ { 2, /* .debug_aranges */
+ 0, /* .rela.debug_aranges */
+ 2, /* .debug_pubnames */
+ 2, /* .debug_info */
+ 0, /* .rela.debug_info */
+ 0, /* .debug_abbrev */
+ 2, /* .debug_line */
+ 0, /* .rela.debug_line */
+ 1, /* .debug_frame */
+ 0 } /* .debug_loc */
+ };
+ dwarf_init_common(&dwfmt32);
+}
+
+static void dwarfx32_init(void)
+{
+ static const struct dwarf_format dwfmtx32 = {
+ 3, /* DWARF 3 */
+ /* section version numbers: */
+ { 2, /* .debug_aranges */
+ 0, /* .rela.debug_aranges */
+ 2, /* .debug_pubnames */
+ 3, /* .debug_info */
+ 0, /* .rela.debug_info */
+ 0, /* .debug_abbrev */
+ 3, /* .debug_line */
+ 0, /* .rela.debug_line */
+ 3, /* .debug_frame */
+ 0 } /* .debug_loc */
+ };
+ dwarf_init_common(&dwfmtx32);
+}
+
+static void dwarf64_init(void)
+{
+ static const struct dwarf_format dwfmt64 = {
+ 3, /* DWARF 3 */
+ /* section version numbers: */
+ { 2, /* .debug_aranges */
+ 0, /* .rela.debug_aranges */
+ 2, /* .debug_pubnames */
+ 3, /* .debug_info */
+ 0, /* .rela.debug_info */
+ 0, /* .debug_abbrev */
+ 3, /* .debug_line */
+ 0, /* .rela.debug_line */
+ 3, /* .debug_frame */
+ 0 } /* .debug_loc */
+ };
+ dwarf_init_common(&dwfmt64);
+}
+
+static void dwarf_linenum(const char *filename, int32_t linenumber,
+ int32_t segto)
+{
+ (void)segto;
+ dwarf_findfile(filename);
+ debug_immcall = 1;
+ currentline = linenumber;
+}
+
+/* called from elf_out with type == TY_DEBUGSYMLIN */
+static void dwarf_output(int type, void *param)
+{
+ int ln, aa, inx, maxln, soc;
+ struct symlininfo *s;
+ struct SAA *plinep;
+
+ (void)type;
+
+ s = (struct symlininfo *)param;
+
+ /* line number info is only gathered for executable sections */
+ if (!(sects[s->section]->flags & SHF_EXECINSTR))
+ return;
+
+ /* Check if section index has changed */
+ if (!(dwarf_csect && (dwarf_csect->section) == (s->section)))
+ dwarf_findsect(s->section);
+
+ /* do nothing unless line or file has changed */
+ if (!debug_immcall)
+ return;
+
+ ln = currentline - dwarf_csect->line;
+ aa = s->offset - dwarf_csect->offset;
+ inx = dwarf_clist->line;
+ plinep = dwarf_csect->psaa;
+ /* check for file change */
+ if (!(inx == dwarf_csect->file)) {
+ saa_write8(plinep,DW_LNS_set_file);
+ saa_write8(plinep,inx);
+ dwarf_csect->file = inx;
+ }
+ /* check for line change */
+ if (ln) {
+ /* test if in range of special op code */
+ maxln = line_base + line_range;
+ soc = (ln - line_base) + (line_range * aa) + opcode_base;
+ if (ln >= line_base && ln < maxln && soc < 256) {
+ saa_write8(plinep,soc);
+ } else {
+ saa_write8(plinep,DW_LNS_advance_line);
+ saa_wleb128s(plinep,ln);
+ if (aa) {
+ saa_write8(plinep,DW_LNS_advance_pc);
+ saa_wleb128u(plinep,aa);
+ }
+ saa_write8(plinep,DW_LNS_copy);
+ }
+ dwarf_csect->line = currentline;
+ dwarf_csect->offset = s->offset;
+ }
+
+ /* show change handled */
+ debug_immcall = 0;
+}
+
+
+static void dwarf_generate(void)
+{
+ uint8_t *pbuf;
+ int indx;
+ struct linelist *ftentry;
+ struct SAA *paranges, *ppubnames, *pinfo, *pabbrev, *plines, *plinep;
+ struct SAA *parangesrel, *plinesrel, *pinforel;
+ struct sectlist *psect;
+ size_t saalen, linepoff, totlen, highaddr;
+
+ if (is_elf32()) {
+ /* write epilogues for each line program range */
+ /* and build aranges section */
+ paranges = saa_init(1L);
+ parangesrel = saa_init(1L);
+ saa_write16(paranges, dwfmt->sect_version[DWARF_ARANGES]);
+ saa_write32(parangesrel, paranges->datalen+4);
+ saa_write32(parangesrel, (dwarf_infosym << 8) + R_386_32); /* reloc to info */
+ saa_write32(paranges,0); /* offset into info */
+ saa_write8(paranges,4); /* pointer size */
+ saa_write8(paranges,0); /* not segmented */
+ saa_write32(paranges,0); /* padding */
+ /* iterate though sectlist entries */
+ psect = dwarf_fsect;
+ totlen = 0;
+ highaddr = 0;
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ plinep = psect->psaa;
+ /* Line Number Program Epilogue */
+ saa_write8(plinep,2); /* std op 2 */
+ saa_write8(plinep,(sects[psect->section]->len)-psect->offset);
+ saa_write8(plinep,DW_LNS_extended_op);
+ saa_write8(plinep,1); /* operand length */
+ saa_write8(plinep,DW_LNE_end_sequence);
+ totlen += plinep->datalen;
+ /* range table relocation entry */
+ saa_write32(parangesrel, paranges->datalen + 4);
+ saa_write32(parangesrel, ((uint32_t) (psect->section + 2) << 8) + R_386_32);
+ /* range table entry */
+ saa_write32(paranges,0x0000); /* range start */
+ saa_write32(paranges,sects[psect->section]->len); /* range length */
+ highaddr += sects[psect->section]->len;
+ /* done with this entry */
+ psect = psect->next;
+ }
+ saa_write32(paranges,0); /* null address */
+ saa_write32(paranges,0); /* null length */
+ saalen = paranges->datalen;
+ arangeslen = saalen + 4;
+ arangesbuf = pbuf = nasm_malloc(arangeslen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(paranges, pbuf, saalen);
+ saa_free(paranges);
+ } else if (is_elfx32()) {
+ /* write epilogues for each line program range */
+ /* and build aranges section */
+ paranges = saa_init(1L);
+ parangesrel = saa_init(1L);
+ saa_write16(paranges, dwfmt->sect_version[DWARF_ARANGES]);
+ saa_write32(parangesrel, paranges->datalen+4);
+ saa_write32(parangesrel, (dwarf_infosym << 8) + R_X86_64_32); /* reloc to info */
+ saa_write32(parangesrel, 0);
+ saa_write32(paranges,0); /* offset into info */
+ saa_write8(paranges,4); /* pointer size */
+ saa_write8(paranges,0); /* not segmented */
+ saa_write32(paranges,0); /* padding */
+ /* iterate though sectlist entries */
+ psect = dwarf_fsect;
+ totlen = 0;
+ highaddr = 0;
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ plinep = psect->psaa;
+ /* Line Number Program Epilogue */
+ saa_write8(plinep,2); /* std op 2 */
+ saa_write8(plinep,(sects[psect->section]->len)-psect->offset);
+ saa_write8(plinep,DW_LNS_extended_op);
+ saa_write8(plinep,1); /* operand length */
+ saa_write8(plinep,DW_LNE_end_sequence);
+ totlen += plinep->datalen;
+ /* range table relocation entry */
+ saa_write32(parangesrel, paranges->datalen + 4);
+ saa_write32(parangesrel, ((uint32_t) (psect->section + 2) << 8) + R_X86_64_32);
+ saa_write32(parangesrel, (uint32_t) 0);
+ /* range table entry */
+ saa_write32(paranges,0x0000); /* range start */
+ saa_write32(paranges,sects[psect->section]->len); /* range length */
+ highaddr += sects[psect->section]->len;
+ /* done with this entry */
+ psect = psect->next;
+ }
+ saa_write32(paranges,0); /* null address */
+ saa_write32(paranges,0); /* null length */
+ saalen = paranges->datalen;
+ arangeslen = saalen + 4;
+ arangesbuf = pbuf = nasm_malloc(arangeslen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(paranges, pbuf, saalen);
+ saa_free(paranges);
+ } else {
+ nasm_assert(is_elf64());
+ /* write epilogues for each line program range */
+ /* and build aranges section */
+ paranges = saa_init(1L);
+ parangesrel = saa_init(1L);
+ saa_write16(paranges, dwfmt->sect_version[DWARF_ARANGES]);
+ saa_write64(parangesrel, paranges->datalen+4);
+ saa_write64(parangesrel, (dwarf_infosym << 32) + R_X86_64_32); /* reloc to info */
+ saa_write64(parangesrel, 0);
+ saa_write32(paranges,0); /* offset into info */
+ saa_write8(paranges,8); /* pointer size */
+ saa_write8(paranges,0); /* not segmented */
+ saa_write32(paranges,0); /* padding */
+ /* iterate though sectlist entries */
+ psect = dwarf_fsect;
+ totlen = 0;
+ highaddr = 0;
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ plinep = psect->psaa;
+ /* Line Number Program Epilogue */
+ saa_write8(plinep,2); /* std op 2 */
+ saa_write8(plinep,(sects[psect->section]->len)-psect->offset);
+ saa_write8(plinep,DW_LNS_extended_op);
+ saa_write8(plinep,1); /* operand length */
+ saa_write8(plinep,DW_LNE_end_sequence);
+ totlen += plinep->datalen;
+ /* range table relocation entry */
+ saa_write64(parangesrel, paranges->datalen + 4);
+ saa_write64(parangesrel, ((uint64_t) (psect->section + 2) << 32) + R_X86_64_64);
+ saa_write64(parangesrel, (uint64_t) 0);
+ /* range table entry */
+ saa_write64(paranges,0x0000); /* range start */
+ saa_write64(paranges,sects[psect->section]->len); /* range length */
+ highaddr += sects[psect->section]->len;
+ /* done with this entry */
+ psect = psect->next;
+ }
+ saa_write64(paranges,0); /* null address */
+ saa_write64(paranges,0); /* null length */
+ saalen = paranges->datalen;
+ arangeslen = saalen + 4;
+ arangesbuf = pbuf = nasm_malloc(arangeslen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(paranges, pbuf, saalen);
+ saa_free(paranges);
+ }
+
+ /* build rela.aranges section */
+ arangesrellen = saalen = parangesrel->datalen;
+ arangesrelbuf = pbuf = nasm_malloc(arangesrellen);
+ saa_rnbytes(parangesrel, pbuf, saalen);
+ saa_free(parangesrel);
+
+ /* build pubnames section */
+ if (0) {
+ ppubnames = saa_init(1L);
+ saa_write16(ppubnames,dwfmt->sect_version[DWARF_PUBNAMES]);
+ saa_write32(ppubnames,0); /* offset into info */
+ saa_write32(ppubnames,0); /* space used in info */
+ saa_write32(ppubnames,0); /* end of list */
+ saalen = ppubnames->datalen;
+ pubnameslen = saalen + 4;
+ pubnamesbuf = pbuf = nasm_malloc(pubnameslen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(ppubnames, pbuf, saalen);
+ saa_free(ppubnames);
+ } else {
+ /* Don't write a section without actual information */
+ pubnameslen = 0;
+ }
+
+ if (is_elf32()) {
+ /* build info section */
+ pinfo = saa_init(1L);
+ pinforel = saa_init(1L);
+ saa_write16(pinfo, dwfmt->sect_version[DWARF_INFO]);
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, (dwarf_abbrevsym << 8) + R_386_32); /* reloc to abbrev */
+ saa_write32(pinfo,0); /* offset into abbrev */
+ saa_write8(pinfo,4); /* pointer size */
+ saa_write8(pinfo,1); /* abbrviation number LEB128u */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32);
+ saa_write32(pinfo,0); /* DW_AT_low_pc */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32);
+ saa_write32(pinfo,highaddr); /* DW_AT_high_pc */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, (dwarf_linesym << 8) + R_386_32); /* reloc to line */
+ saa_write32(pinfo,0); /* DW_AT_stmt_list */
+ saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); /* DW_AT_name */
+ saa_wbytes(pinfo, elf_dir, strlen(elf_dir)+1); /* DW_AT_comp_dir */
+ saa_wbytes(pinfo, nasm_signature(), nasm_signature_len()+1);
+ saa_write16(pinfo,DW_LANG_Mips_Assembler);
+ saa_write8(pinfo,2); /* abbrviation number LEB128u */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_386_32);
+ saa_write32(pinfo,0); /* DW_AT_low_pc */
+ saa_write32(pinfo,0); /* DW_AT_frame_base */
+ saa_write8(pinfo,0); /* end of entries */
+ saalen = pinfo->datalen;
+ infolen = saalen + 4;
+ infobuf = pbuf = nasm_malloc(infolen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(pinfo, pbuf, saalen);
+ saa_free(pinfo);
+ } else if (is_elfx32()) {
+ /* build info section */
+ pinfo = saa_init(1L);
+ pinforel = saa_init(1L);
+ saa_write16(pinfo, dwfmt->sect_version[DWARF_INFO]);
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, (dwarf_abbrevsym << 8) + R_X86_64_32); /* reloc to abbrev */
+ saa_write32(pinforel, 0);
+ saa_write32(pinfo,0); /* offset into abbrev */
+ saa_write8(pinfo,4); /* pointer size */
+ saa_write8(pinfo,1); /* abbrviation number LEB128u */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32);
+ saa_write32(pinforel, 0);
+ saa_write32(pinfo,0); /* DW_AT_low_pc */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32);
+ saa_write32(pinforel, highaddr);
+ saa_write32(pinfo,0); /* DW_AT_high_pc */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, (dwarf_linesym << 8) + R_X86_64_32); /* reloc to line */
+ saa_write32(pinforel, 0);
+ saa_write32(pinfo,0); /* DW_AT_stmt_list */
+ saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); /* DW_AT_name */
+ saa_wbytes(pinfo, elf_dir, strlen(elf_dir)+1); /* DW_AT_comp_dir */
+ saa_wbytes(pinfo, nasm_signature(), nasm_signature_len()+1);
+ saa_write16(pinfo,DW_LANG_Mips_Assembler);
+ saa_write8(pinfo,2); /* abbrviation number LEB128u */
+ saa_write32(pinforel, pinfo->datalen + 4);
+ saa_write32(pinforel, ((dwarf_fsect->section + 2) << 8) + R_X86_64_32);
+ saa_write32(pinforel, 0);
+ saa_write32(pinfo,0); /* DW_AT_low_pc */
+ saa_write32(pinfo,0); /* DW_AT_frame_base */
+ saa_write8(pinfo,0); /* end of entries */
+ saalen = pinfo->datalen;
+ infolen = saalen + 4;
+ infobuf = pbuf = nasm_malloc(infolen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(pinfo, pbuf, saalen);
+ saa_free(pinfo);
+ } else {
+ nasm_assert(is_elf64());
+ /* build info section */
+ pinfo = saa_init(1L);
+ pinforel = saa_init(1L);
+ saa_write16(pinfo, dwfmt->sect_version[DWARF_INFO]);
+ saa_write64(pinforel, pinfo->datalen + 4);
+ saa_write64(pinforel, (dwarf_abbrevsym << 32) + R_X86_64_32); /* reloc to abbrev */
+ saa_write64(pinforel, 0);
+ saa_write32(pinfo,0); /* offset into abbrev */
+ saa_write8(pinfo,8); /* pointer size */
+ saa_write8(pinfo,1); /* abbrviation number LEB128u */
+ saa_write64(pinforel, pinfo->datalen + 4);
+ saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64);
+ saa_write64(pinforel, 0);
+ saa_write64(pinfo,0); /* DW_AT_low_pc */
+ saa_write64(pinforel, pinfo->datalen + 4);
+ saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64);
+ saa_write64(pinforel, highaddr);
+ saa_write64(pinfo,0); /* DW_AT_high_pc */
+ saa_write64(pinforel, pinfo->datalen + 4);
+ saa_write64(pinforel, (dwarf_linesym << 32) + R_X86_64_32); /* reloc to line */
+ saa_write64(pinforel, 0);
+ saa_write32(pinfo,0); /* DW_AT_stmt_list */
+ saa_wbytes(pinfo, elf_module, strlen(elf_module)+1); /* DW_AT_name */
+ saa_wbytes(pinfo, elf_dir, strlen(elf_dir)+1); /* DW_AT_comp_dir */
+ saa_wbytes(pinfo, nasm_signature(), nasm_signature_len()+1);
+ saa_write16(pinfo,DW_LANG_Mips_Assembler);
+ saa_write8(pinfo,2); /* abbrviation number LEB128u */
+ saa_write64(pinforel, pinfo->datalen + 4);
+ saa_write64(pinforel, ((uint64_t)(dwarf_fsect->section + 2) << 32) + R_X86_64_64);
+ saa_write64(pinforel, 0);
+ saa_write64(pinfo,0); /* DW_AT_low_pc */
+ saa_write64(pinfo,0); /* DW_AT_frame_base */
+ saa_write8(pinfo,0); /* end of entries */
+ saalen = pinfo->datalen;
+ infolen = saalen + 4;
+ infobuf = pbuf = nasm_malloc(infolen);
+ WRITELONG(pbuf,saalen); /* initial length */
+ saa_rnbytes(pinfo, pbuf, saalen);
+ saa_free(pinfo);
+ }
+
+ /* build rela.info section */
+ inforellen = saalen = pinforel->datalen;
+ inforelbuf = pbuf = nasm_malloc(inforellen);
+ saa_rnbytes(pinforel, pbuf, saalen);
+ saa_free(pinforel);
+
+ /* build abbrev section */
+ pabbrev = saa_init(1L);
+ saa_write8(pabbrev,1); /* entry number LEB128u */
+ saa_write8(pabbrev,DW_TAG_compile_unit); /* tag LEB128u */
+ saa_write8(pabbrev,1); /* has children */
+ /* the following attributes and forms are all LEB128u values */
+ saa_write8(pabbrev,DW_AT_low_pc);
+ saa_write8(pabbrev,DW_FORM_addr);
+ saa_write8(pabbrev,DW_AT_high_pc);
+ saa_write8(pabbrev,DW_FORM_addr);
+ saa_write8(pabbrev,DW_AT_stmt_list);
+ saa_write8(pabbrev,DW_FORM_data4);
+ saa_write8(pabbrev,DW_AT_name);
+ saa_write8(pabbrev,DW_FORM_string);
+ saa_write8(pabbrev,DW_AT_comp_dir);
+ saa_write8(pabbrev,DW_FORM_string);
+ saa_write8(pabbrev,DW_AT_producer);
+ saa_write8(pabbrev,DW_FORM_string);
+ saa_write8(pabbrev,DW_AT_language);
+ saa_write8(pabbrev,DW_FORM_data2);
+ saa_write16(pabbrev,0); /* end of entry */
+ /* LEB128u usage same as above */
+ saa_write8(pabbrev,2); /* entry number */
+ saa_write8(pabbrev,DW_TAG_subprogram);
+ saa_write8(pabbrev,0); /* no children */
+ saa_write8(pabbrev,DW_AT_low_pc);
+ saa_write8(pabbrev,DW_FORM_addr);
+ saa_write8(pabbrev,DW_AT_frame_base);
+ saa_write8(pabbrev,DW_FORM_data4);
+ saa_write16(pabbrev,0); /* end of entry */
+ /* Terminal zero entry */
+ saa_write8(pabbrev,0);
+ abbrevlen = saalen = pabbrev->datalen;
+ abbrevbuf = pbuf = nasm_malloc(saalen);
+ saa_rnbytes(pabbrev, pbuf, saalen);
+ saa_free(pabbrev);
+
+ /* build line section */
+ /* prolog */
+ plines = saa_init(1L);
+ saa_write8(plines,1); /* Minimum Instruction Length */
+ saa_write8(plines,1); /* Initial value of 'is_stmt' */
+ saa_write8(plines,line_base); /* Line Base */
+ saa_write8(plines,line_range); /* Line Range */
+ saa_write8(plines,opcode_base); /* Opcode Base */
+ /* standard opcode lengths (# of LEB128u operands) */
+ saa_write8(plines,0); /* Std opcode 1 length */
+ saa_write8(plines,1); /* Std opcode 2 length */
+ saa_write8(plines,1); /* Std opcode 3 length */
+ saa_write8(plines,1); /* Std opcode 4 length */
+ saa_write8(plines,1); /* Std opcode 5 length */
+ saa_write8(plines,0); /* Std opcode 6 length */
+ saa_write8(plines,0); /* Std opcode 7 length */
+ saa_write8(plines,0); /* Std opcode 8 length */
+ saa_write8(plines,1); /* Std opcode 9 length */
+ saa_write8(plines,0); /* Std opcode 10 length */
+ saa_write8(plines,0); /* Std opcode 11 length */
+ saa_write8(plines,1); /* Std opcode 12 length */
+ /* Directory Table */
+ saa_write8(plines,0); /* End of table */
+ /* File Name Table */
+ ftentry = dwarf_flist;
+ for (indx = 0; indx < dwarf_numfiles; indx++) {
+ saa_wbytes(plines, ftentry->filename, (int32_t)(strlen(ftentry->filename) + 1));
+ saa_write8(plines,0); /* directory LEB128u */
+ saa_write8(plines,0); /* time LEB128u */
+ saa_write8(plines,0); /* size LEB128u */
+ ftentry = ftentry->next;
+ }
+ saa_write8(plines,0); /* End of table */
+ linepoff = plines->datalen;
+ linelen = linepoff + totlen + 10;
+ linebuf = pbuf = nasm_malloc(linelen);
+ WRITELONG(pbuf,linelen-4); /* initial length */
+ WRITESHORT(pbuf,dwfmt->sect_version[DWARF_LINE]);
+ WRITELONG(pbuf,linepoff); /* offset to line number program */
+ /* write line header */
+ saalen = linepoff;
+ saa_rnbytes(plines, pbuf, saalen); /* read a given no. of bytes */
+ pbuf += linepoff;
+ saa_free(plines);
+ /* concatenate line program ranges */
+ linepoff += 13;
+ plinesrel = saa_init(1L);
+ psect = dwarf_fsect;
+ if (is_elf32()) {
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ saa_write32(plinesrel, linepoff);
+ saa_write32(plinesrel, ((uint32_t) (psect->section + 2) << 8) + R_386_32);
+ plinep = psect->psaa;
+ saalen = plinep->datalen;
+ saa_rnbytes(plinep, pbuf, saalen);
+ pbuf += saalen;
+ linepoff += saalen;
+ saa_free(plinep);
+ /* done with this entry */
+ psect = psect->next;
+ }
+ } else if (is_elfx32()) {
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ saa_write32(plinesrel, linepoff);
+ saa_write32(plinesrel, ((psect->section + 2) << 8) + R_X86_64_32);
+ saa_write32(plinesrel, 0);
+ plinep = psect->psaa;
+ saalen = plinep->datalen;
+ saa_rnbytes(plinep, pbuf, saalen);
+ pbuf += saalen;
+ linepoff += saalen;
+ saa_free(plinep);
+ /* done with this entry */
+ psect = psect->next;
+ }
+ } else {
+ nasm_assert(is_elf64());
+ for (indx = 0; indx < dwarf_nsections; indx++) {
+ saa_write64(plinesrel, linepoff);
+ saa_write64(plinesrel, ((uint64_t) (psect->section + 2) << 32) + R_X86_64_64);
+ saa_write64(plinesrel, (uint64_t) 0);
+ plinep = psect->psaa;
+ saalen = plinep->datalen;
+ saa_rnbytes(plinep, pbuf, saalen);
+ pbuf += saalen;
+ linepoff += saalen;
+ saa_free(plinep);
+ /* done with this entry */
+ psect = psect->next;
+ }
+ }
+
+ /* build rela.lines section */
+ linerellen =saalen = plinesrel->datalen;
+ linerelbuf = pbuf = nasm_malloc(linerellen);
+ saa_rnbytes(plinesrel, pbuf, saalen);
+ saa_free(plinesrel);
+
+ /* build .debug_frame section */
+ if (0) {
+ framelen = 4;
+ framebuf = pbuf = nasm_malloc(framelen);
+ WRITELONG(pbuf,framelen-4); /* initial length */
+ } else {
+ /* Leave .debug_frame empty if not used! */
+ framelen = 0;
+ }
+
+ /* build .debug_loc section */
+ if (0) {
+ loclen = 16;
+ locbuf = pbuf = nasm_malloc(loclen);
+ if (is_elf32() || is_elfx32()) {
+ WRITELONG(pbuf,0); /* null beginning offset */
+ WRITELONG(pbuf,0); /* null ending offset */
+ } else {
+ nasm_assert(is_elf64());
+ WRITEDLONG(pbuf,0); /* null beginning offset */
+ WRITEDLONG(pbuf,0); /* null ending offset */
+ }
+ } else {
+ /* Leave .debug_frame empty if not used! */
+ loclen = 0;
+ }
+}
+
+static void dwarf_cleanup(void)
+{
+ nasm_free(arangesbuf);
+ nasm_free(arangesrelbuf);
+ nasm_free(pubnamesbuf);
+ nasm_free(infobuf);
+ nasm_free(inforelbuf);
+ nasm_free(abbrevbuf);
+ nasm_free(linebuf);
+ nasm_free(linerelbuf);
+ nasm_free(framebuf);
+ nasm_free(locbuf);
+}
+
+static void dwarf_findfile(const char * fname)
+{
+ int finx;
+ struct linelist *match;
+
+ /* return if fname is current file name */
+ if (dwarf_clist && !(strcmp(fname, dwarf_clist->filename)))
+ return;
+
+ /* search for match */
+ match = 0;
+ if (dwarf_flist) {
+ match = dwarf_flist;
+ for (finx = 0; finx < dwarf_numfiles; finx++) {
+ if (!(strcmp(fname, match->filename))) {
+ dwarf_clist = match;
+ return;
+ }
+ match = match->next;
+ }
+ }
+
+ /* add file name to end of list */
+ dwarf_clist = nasm_malloc(sizeof(struct linelist));
+ dwarf_numfiles++;
+ dwarf_clist->line = dwarf_numfiles;
+ dwarf_clist->filename = nasm_malloc(strlen(fname) + 1);
+ strcpy(dwarf_clist->filename,fname);
+ dwarf_clist->next = 0;
+ if (!dwarf_flist) { /* if first entry */
+ dwarf_flist = dwarf_elist = dwarf_clist;
+ dwarf_clist->last = 0;
+ } else { /* chain to previous entry */
+ dwarf_elist->next = dwarf_clist;
+ dwarf_elist = dwarf_clist;
+ }
+}
+
+static void dwarf_findsect(const int index)
+{
+ int sinx;
+ struct sectlist *match;
+ struct SAA *plinep;
+
+ /* return if index is current section index */
+ if (dwarf_csect && (dwarf_csect->section == index))
+ return;
+
+ /* search for match */
+ match = 0;
+ if (dwarf_fsect) {
+ match = dwarf_fsect;
+ for (sinx = 0; sinx < dwarf_nsections; sinx++) {
+ if (match->section == index) {
+ dwarf_csect = match;
+ return;
+ }
+ match = match->next;
+ }
+ }
+
+ /* add entry to end of list */
+ dwarf_csect = nasm_malloc(sizeof(struct sectlist));
+ dwarf_nsections++;
+ dwarf_csect->psaa = plinep = saa_init(1L);
+ dwarf_csect->line = 1;
+ dwarf_csect->offset = 0;
+ dwarf_csect->file = 1;
+ dwarf_csect->section = index;
+ dwarf_csect->next = 0;
+ /* set relocatable address at start of line program */
+ saa_write8(plinep,DW_LNS_extended_op);
+ saa_write8(plinep,is_elf64() ? 9 : 5); /* operand length */
+ saa_write8(plinep,DW_LNE_set_address);
+ if (is_elf64())
+ saa_write64(plinep,0); /* Start Address */
+ else
+ saa_write32(plinep,0); /* Start Address */
+
+ if (!dwarf_fsect) { /* if first entry */
+ dwarf_fsect = dwarf_esect = dwarf_csect;
+ dwarf_csect->last = 0;
+ } else { /* chain to previous entry */
+ dwarf_esect->next = dwarf_csect;
+ dwarf_esect = dwarf_csect;
+ }
+}
+
+#endif /* defined(OF_ELF32) || defined(OF_ELF64) || defined(OF_ELFX32) */
diff --git a/vere/ext/nasm/output/outelf.h b/vere/ext/nasm/output/outelf.h
new file mode 100644
index 0000000..fcb91db
--- /dev/null
+++ b/vere/ext/nasm/output/outelf.h
@@ -0,0 +1,133 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2019 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Internal definitions common to outelf32 and outelf64
+ */
+#ifndef OUTPUT_OUTELF_H
+#define OUTPUT_OUTELF_H
+
+#include "elf.h"
+#include "rbtree.h"
+#include "saa.h"
+
+#define GLOBAL_TEMP_BASE 0x40000000 /* bigger than any sane symbol index */
+
+/* alignment of sections in file */
+#define SEC_FILEALIGN 16
+
+/* this stuff is needed for the dwarf/stabs debugging format */
+#define TY_DEBUGSYMLIN 0x40 /* internal call to debug_out */
+
+/*
+ * Debugging ELF sections (section indices starting with sec_debug)
+ */
+
+/* stabs */
+#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 {
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_other;
+ uint16_t n_desc;
+ uint32_t n_value;
+};
+
+/* dwarf */
+#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;
+
+#define WRITE_STAB(p,n_strx,n_type,n_other,n_desc,n_value) \
+ do { \
+ WRITELONG(p, n_strx); \
+ WRITECHAR(p, n_type); \
+ WRITECHAR(p, n_other); \
+ WRITESHORT(p, n_desc); \
+ WRITELONG(p, n_value); \
+ } while (0)
+
+struct elf_reloc {
+ struct elf_reloc *next;
+ int64_t address; /* relative to _start_ of section */
+ int64_t symbol; /* symbol index */
+ int64_t offset; /* symbol addend */
+ int type; /* type of relocation */
+};
+
+struct elf_symbol {
+ struct rbtree symv; /* symbol value and symbol rbtree */
+ int32_t strpos; /* string table position of name */
+ int32_t section; /* section ID of the symbol */
+ int type; /* symbol type */
+ int other; /* symbol visibility */
+ int32_t size; /* size of symbol */
+ int32_t globnum; /* symbol table offset if global */
+ struct elf_symbol *nextfwd; /* list of unresolved-size symbols */
+ char *name; /* used temporarily if in above list */
+};
+
+struct elf_section {
+ struct SAA *data;
+ uint64_t len;
+ uint64_t size;
+ uint64_t nrelocs;
+ int32_t index; /* NASM index or NO_SEG if internal */
+ int shndx; /* ELF index */
+ int type; /* SHT_* */
+ uint64_t align; /* alignment: power of two */
+ uint64_t flags; /* section flags */
+ int64_t pass_last_seen;
+ uint64_t entsize; /* entry size */
+ char *name;
+ struct SAA *rel;
+ struct elf_reloc *head;
+ struct elf_reloc **tail;
+ struct rbtree *gsyms; /* global symbols in section */
+};
+
+#endif /* OUTPUT_OUTELF_H */
diff --git a/vere/ext/nasm/output/outelf.mac b/vere/ext/nasm/output/outelf.mac
new file mode 100644
index 0000000..94babe3
--- /dev/null
+++ b/vere/ext/nasm/output/outelf.mac
@@ -0,0 +1,41 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2017 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: elf elf32 elf64
+%define __?SECT?__ [section .text]
+%macro __?NASM_CDecl?__ 1
+%define $_%1 $%1
+%endmacro
+%imacro osabi 1+.nolist
+[%? %1]
+%endmacro
diff --git a/vere/ext/nasm/output/outform.c b/vere/ext/nasm/output/outform.c
new file mode 100644
index 0000000..a2fdde8
--- /dev/null
+++ b/vere/ext/nasm/output/outform.c
@@ -0,0 +1,135 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2011 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outform.c manages a list of output formats, and associates
+ * them with their relevant drivers. Also has a
+ * routine to find the correct driver given a name
+ * for it
+ */
+
+#include "compiler.h"
+
+
+#define BUILD_DRIVERS_ARRAY
+#include "outform.h"
+#include "outlib.h"
+
+const struct ofmt *ofmt_find(const char *name,
+ const struct ofmt_alias **ofmt_alias)
+{
+ const struct ofmt * const *ofp;
+ const struct ofmt *of;
+ unsigned int i;
+
+ *ofmt_alias = NULL;
+
+ /* primary targets first */
+ for (ofp = drivers; (of = *ofp); ofp++) {
+ if (!nasm_stricmp(name, of->shortname))
+ return of;
+ }
+
+ /* lets walk thru aliases then */
+ for (i = 0; i < ARRAY_SIZE(ofmt_aliases); i++) {
+ if (ofmt_aliases[i].shortname &&
+ !nasm_stricmp(name, ofmt_aliases[i].shortname)) {
+ *ofmt_alias = &ofmt_aliases[i];
+ return ofmt_aliases[i].ofmt;
+ }
+ }
+
+ return NULL;
+}
+
+const struct dfmt *dfmt_find(const struct ofmt *ofmt, const char *name)
+{
+ const struct dfmt * const *dfp;
+ const struct dfmt *df;
+
+ for (dfp = ofmt->debug_formats; (df = *dfp); dfp++) {
+ if (!nasm_stricmp(name, df->shortname))
+ return df;
+ }
+ return NULL;
+}
+
+void ofmt_list(const struct ofmt *deffmt, FILE * fp)
+{
+ const struct ofmt * const *ofp, *of;
+ unsigned int i;
+
+ /* primary targets first */
+ for (ofp = drivers; (of = *ofp); ofp++) {
+ fprintf(fp, " %-20s %s%s\n",
+ of->shortname,
+ of->fullname,
+ of == deffmt ? " [default]" : "");
+ }
+
+ /* lets walk through aliases then */
+ for (i = 0; i < ARRAY_SIZE(ofmt_aliases); i++) {
+ if (!ofmt_aliases[i].shortname)
+ continue;
+ fprintf(fp, " %-20s Legacy alias for \"%s\"\n",
+ ofmt_aliases[i].shortname,
+ ofmt_aliases[i].ofmt->shortname);
+ }
+}
+
+void dfmt_list(FILE *fp)
+{
+ const struct ofmt * const *ofp;
+ const struct ofmt *of;
+ const struct dfmt * const *dfp;
+ const struct dfmt *df;
+ char prefixbuf[32];
+ const char *prefix;
+
+ for (ofp = drivers; (of = *ofp); ofp++) {
+ if (of->debug_formats && of->debug_formats != null_debug_arr) {
+ snprintf(prefixbuf, sizeof prefixbuf, "%s:",
+ of->shortname);
+ prefix = prefixbuf;
+
+ for (dfp = of->debug_formats; (df = *dfp); dfp++) {
+ if (df != &null_debug_form)
+ fprintf(fp, " %-10s %-9s %s%s\n",
+ prefix,
+ df->shortname, df->fullname,
+ df == of->default_dfmt ? " [default]" : "");
+ prefix = "";
+ }
+ }
+ }
+}
diff --git a/vere/ext/nasm/output/outform.h b/vere/ext/nasm/output/outform.h
new file mode 100644
index 0000000..3b84674
--- /dev/null
+++ b/vere/ext/nasm/output/outform.h
@@ -0,0 +1,354 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2022 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outform.h header file for binding output format drivers to the
+ * remainder of the code in the Netwide Assembler
+ */
+
+/*
+ * This header file allows configuration of which output formats
+ * get compiled into the NASM binary. You can configure by defining
+ * various preprocessor symbols beginning with "OF_", either on the
+ * compiler command line or at the top of this file.
+ *
+ * OF_ONLY -- only include specified object formats
+ * OF_name -- ensure that output format 'name' is included
+ * OF_NO_name -- remove output format 'name'
+ * OF_DOS -- ensure that 'obj', 'bin', 'win32' & 'win64' are included.
+ * OF_UNIX -- ensure that 'aout', 'aoutb', 'coff', 'elf32' & 'elf64' are in.
+ * OF_OTHERS -- ensure that 'bin', 'as86', 'rdf' 'macho32' & 'macho64' are in.
+ * OF_ALL -- ensure that all formats are included.
+ * note that this doesn't include 'dbg', which is
+ * only really useful if you're doing development
+ * work on NASM. Define OF_DBG if you want this.
+ *
+ * OF_DEFAULT=of_name -- ensure that 'name' is the default format.
+ *
+ * eg: -DOF_UNIX -DOF_ELF32 -DOF_DEFAULT=of_elf32 would be a suitable config
+ * for an average linux system.
+ *
+ * Default config = -DOF_ALL -DOF_DEFAULT=of_bin
+ *
+ * You probably only want to set these options while compiling 'nasm.c'. */
+
+#ifndef NASM_OUTFORM_H
+#define NASM_OUTFORM_H
+
+#include "nasm.h"
+
+/* -------------- USER MODIFIABLE PART ---------------- */
+
+/*
+ * Insert #defines here in accordance with the configuration
+ * instructions above.
+ *
+ * E.g.
+ *
+ * #define OF_ONLY
+ * #define OF_OBJ
+ * #define OF_BIN
+ *
+ * for a 16-bit DOS assembler with no extraneous formats.
+ */
+
+/* ------------ END USER MODIFIABLE PART -------------- */
+
+/* ====configurable info begins here==== */
+/* formats configurable:
+ * bin,obj,elf32,elf64,aout,aoutb,coff,win32,as86,rdf2,macho32,macho64 */
+
+/* process options... */
+
+#ifndef OF_ONLY
+#ifndef OF_ALL
+#define OF_ALL /* default is to have all formats */
+#endif
+#endif
+
+#ifdef OF_ALL /* set all formats on... */
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_ELF32
+#define OF_ELF32
+#endif
+#ifndef OF_ELFX32
+#define OF_ELFX32
+#endif
+#ifndef OF_ELF64
+#define OF_ELF64
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#ifndef OF_WIN64
+#define OF_WIN64
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_IEEE
+#define OF_IEEE
+#endif
+#ifndef OF_MACHO32
+#define OF_MACHO32
+#endif
+#ifndef OF_MACHO64
+#define OF_MACHO64
+#endif
+#ifndef OF_DBG
+#define OF_DBG
+#endif
+#endif /* OF_ALL */
+
+/* turn on groups of formats specified.... */
+#ifdef OF_DOS
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_COFF
+#define OF_COFF /* COFF is used by DJGPP */
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#ifndef OF_WIN64
+#define OF_WIN64
+#endif
+#endif
+
+#ifdef OF_UNIX
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_ELF32
+#define OF_ELF32
+#endif
+#ifndef OF_ELF64
+#define OF_ELF64
+#endif
+#ifndef OF_ELFX32
+#define OF_ELFX32
+#endif
+#endif
+
+#ifdef OF_OTHERS
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_IEEE
+#define OF_IEEE
+#endif
+#ifndef OF_MACHO32
+#define OF_MACHO32
+#endif
+#ifndef OF_MACHO64
+#define OF_MACHO64
+#endif
+#endif
+
+/* finally... override any format specifically specified to be off */
+#ifdef OF_NO_BIN
+#undef OF_BIN
+#endif
+#ifdef OF_NO_OBJ
+#undef OF_OBJ
+#endif
+#ifdef OF_NO_ELF32
+#undef OF_ELF32
+#endif
+#ifdef OF_NO_ELF64
+#undef OF_ELF64
+#endif
+#ifdef OF_NO_ELFX32
+#undef OF_ELFX32
+#endif
+#ifdef OF_NO_AOUT
+#undef OF_AOUT
+#endif
+#ifdef OF_NO_AOUTB
+#undef OF_AOUTB
+#endif
+#ifdef OF_NO_COFF
+#undef OF_COFF
+#endif
+#ifdef OF_NO_WIN32
+#undef OF_WIN32
+#endif
+#ifdef OF_NO_WIN64
+#undef OF_WIN64
+#endif
+#ifdef OF_NO_AS86
+#undef OF_AS86
+#endif
+#ifdef OF_NO_IEEE
+#undef OF_IEEE
+#endif
+#ifdef OF_NO_MACHO32
+#undef OF_MACHO32
+#endif
+#ifdef OF_NO_MACHO64
+#undef OF_MACHO64
+#endif
+#ifdef OF_NO_DBG
+#undef OF_DBG
+#endif
+
+#ifndef OF_DEFAULT
+#define OF_DEFAULT of_bin
+#endif
+
+extern const struct ofmt of_bin;
+extern const struct ofmt of_ith;
+extern const struct ofmt of_srec;
+extern const struct ofmt of_aout;
+extern const struct ofmt of_aoutb;
+extern const struct ofmt of_coff;
+extern const struct ofmt of_elf32;
+extern const struct ofmt of_elfx32;
+extern const struct ofmt of_elf64;
+extern const struct ofmt of_as86;
+extern const struct ofmt of_obj;
+extern const struct ofmt of_win32;
+extern const struct ofmt of_win64;
+extern const struct ofmt of_ieee;
+extern const struct ofmt of_macho32;
+extern const struct ofmt of_macho64;
+extern const struct ofmt of_dbg;
+
+#ifdef BUILD_DRIVERS_ARRAY /* only if included from outform.c */
+
+/*
+ * pull in the externs for the different formats, then make the
+ * drivers array based on the above defines
+ */
+
+static const struct ofmt * const drivers[] = {
+#ifdef OF_BIN
+ &of_bin,
+ &of_ith,
+ &of_srec,
+#endif
+#ifdef OF_AOUT
+ &of_aout,
+#endif
+#ifdef OF_AOUTB
+ &of_aoutb,
+#endif
+#ifdef OF_COFF
+ &of_coff,
+#endif
+#ifdef OF_ELF32
+ &of_elf32,
+#endif
+#ifdef OF_ELF64
+ &of_elf64,
+#endif
+#ifdef OF_ELFX32
+ &of_elfx32,
+#endif
+#ifdef OF_AS86
+ &of_as86,
+#endif
+#ifdef OF_OBJ
+ &of_obj,
+#endif
+#ifdef OF_WIN32
+ &of_win32,
+#endif
+#ifdef OF_WIN64
+ &of_win64,
+#endif
+#ifdef OF_IEEE
+ &of_ieee,
+#endif
+#ifdef OF_MACHO32
+ &of_macho32,
+#endif
+#ifdef OF_MACHO64
+ &of_macho64,
+#endif
+#ifdef OF_DBG
+ &of_dbg,
+#endif
+
+ NULL
+};
+
+static const struct ofmt_alias ofmt_aliases[] = {
+#ifdef OF_ELF32
+ { "elf", &of_elf32 },
+#endif
+#ifdef OF_MACHO32
+ { "macho", &of_macho32 },
+#endif
+#ifdef OF_WIN32
+ { "win", &of_win32 },
+#endif
+ { NULL, NULL }
+};
+
+#endif /* BUILD_DRIVERS_ARRAY */
+
+const struct ofmt *ofmt_find(const char *name, const struct ofmt_alias **ofmt_alias);
+const struct dfmt *dfmt_find(const struct ofmt *, const char *);
+void ofmt_list(const struct ofmt *, FILE *);
+void dfmt_list(FILE *);
+extern const struct dfmt null_debug_form;
+
+#endif /* NASM_OUTFORM_H */
diff --git a/vere/ext/nasm/output/outieee.c b/vere/ext/nasm/output/outieee.c
new file mode 100644
index 0000000..7ba9036
--- /dev/null
+++ b/vere/ext/nasm/output/outieee.c
@@ -0,0 +1,1521 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2022 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outieee.c output routines for the Netwide Assembler to produce
+ * IEEE-std object files
+ */
+
+/* notes: I have tried to make this correspond to the IEEE version
+ * of the standard, specifically the primary ASCII version. It should
+ * be trivial to create the binary version given this source (which is
+ * one of MANY things that have to be done to make this correspond to
+ * the hp-microtek version of the standard).
+ *
+ * 16-bit support is assumed to use 24-bit addresses
+ * The linker can sort out segmentation-specific stuff
+ * if it keeps track of externals
+ * in terms of being relative to section bases
+ *
+ * A non-standard variable type, the 'Yn' variable, has been introduced.
+ * Basically it is a reference to extern 'n'- denoting the low limit
+ * (L-variable) of the section that extern 'n' is defined in. Like the
+ * x variable, there may be no explicit assignment to it, it is derived
+ * from the public definition corresponding to the extern name. This
+ * is required because the one thing the mufom guys forgot to do well was
+ * take into account segmented architectures.
+ *
+ * I use comment classes for various things and these are undefined by
+ * the standard.
+ *
+ * Debug info should be considered totally non-standard (local labels are
+ * standard but linenum records are not covered by the standard.
+ * Type defs have the standard format but absolute meanings for ordinal
+ * types are not covered by the standard.)
+ *
+ * David Lindauer, LADsoft
+ */
+#include "compiler.h"
+
+#include <time.h>
+#include <ctype.h> /* For toupper() */
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "ver.h"
+
+#include "outform.h"
+#include "outlib.h"
+
+#ifdef OF_IEEE
+
+#define ARRAY_BOT 0x1
+
+static char ieee_infile[FILENAME_MAX];
+static int ieee_uppercase;
+
+static bool any_segs;
+static int arrindex;
+
+#define HUNKSIZE 1024 /* Size of the data hunk */
+#define EXT_BLKSIZ 512
+#define LDPERLINE 32 /* bytes per line in output */
+
+struct ieeeSection;
+
+struct LineNumber {
+ struct LineNumber *next;
+ struct ieeeSection *segment;
+ int32_t offset;
+ int32_t lineno;
+};
+
+static struct FileName {
+ struct FileName *next;
+ char *name;
+ int32_t index;
+} *fnhead, **fntail;
+
+static struct Array {
+ struct Array *next;
+ unsigned size;
+ int basetype;
+} *arrhead, **arrtail;
+
+static struct ieeePublic {
+ struct ieeePublic *next;
+ char *name;
+ int32_t offset;
+ int32_t segment; /* only if it's far-absolute */
+ int32_t index;
+ int type; /* for debug purposes */
+} *fpubhead, **fpubtail, *last_defined;
+
+static struct ieeeExternal {
+ struct ieeeExternal *next;
+ char *name;
+ int32_t commonsize;
+} *exthead, **exttail;
+
+static int externals;
+
+static struct ExtBack {
+ struct ExtBack *next;
+ int index[EXT_BLKSIZ];
+} *ebhead, **ebtail;
+
+/* NOTE: the first segment MUST be the lineno segment */
+static struct ieeeSection {
+ struct ieeeSection *next;
+ char *name;
+ struct ieeeObjData *data, *datacurr;
+ struct ieeeFixupp *fptr, *flptr;
+ int32_t index; /* the NASM segment id */
+ int32_t ieee_index; /* the IEEE-file segment index */
+ int32_t currentpos;
+ int32_t align; /* can be SEG_ABS + absolute addr */
+ int32_t startpos;
+ int32_t use32; /* is this segment 32-bit? */
+ int64_t pass_last_seen;
+ struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
+ enum {
+ CMB_PRIVATE = 0,
+ CMB_PUBLIC = 2,
+ CMB_COMMON = 6
+ } combine;
+} *seghead, **segtail, *ieee_seg_needs_update;
+
+struct ieeeObjData {
+ struct ieeeObjData *next;
+ uint8_t data[HUNKSIZE];
+};
+
+struct ieeeFixupp {
+ struct ieeeFixupp *next;
+ enum {
+ FT_SEG = 0,
+ FT_REL = 1,
+ FT_OFS = 2,
+ FT_EXT = 3,
+ FT_WRT = 4,
+ FT_EXTREL = 5,
+ FT_EXTWRT = 6,
+ FT_EXTSEG = 7
+ } ftype;
+ int16_t size;
+ int32_t id1;
+ int32_t id2;
+ int32_t offset;
+ int32_t addend;
+};
+
+static int32_t ieee_entry_seg, ieee_entry_ofs;
+static int checksum;
+
+extern const struct ofmt of_ieee;
+static const struct dfmt ladsoft_debug_form;
+
+static void ieee_data_new(struct ieeeSection *);
+static void ieee_write_fixup(int32_t, int32_t, struct ieeeSection *,
+ int, uint64_t, int32_t);
+static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
+static int32_t ieee_segment(char *, int *);
+static void ieee_write_file(void);
+static void ieee_write_byte(struct ieeeSection *, int);
+static void ieee_write_word(struct ieeeSection *, int);
+static void ieee_write_dword(struct ieeeSection *, int32_t);
+static void ieee_putascii(char *, ...);
+static void ieee_putcs(int);
+static int32_t ieee_putld(int32_t, int32_t, uint8_t *);
+static int32_t ieee_putlr(struct ieeeFixupp *);
+static void ieee_unqualified_name(char *, char *);
+
+/*
+ * pup init
+ */
+static void ieee_init(void)
+{
+ strlcpy(ieee_infile, inname, sizeof(ieee_infile));
+ any_segs = false;
+ fpubhead = NULL;
+ fpubtail = &fpubhead;
+ exthead = NULL;
+ exttail = &exthead;
+ externals = 1;
+ ebhead = NULL;
+ ebtail = &ebhead;
+ seghead = ieee_seg_needs_update = NULL;
+ segtail = &seghead;
+ ieee_entry_seg = NO_SEG;
+ ieee_uppercase = false;
+ checksum = 0;
+}
+
+/*
+ * Rundown
+ */
+static void ieee_cleanup(void)
+{
+ ieee_write_file();
+ dfmt->cleanup();
+ while (seghead) {
+ struct ieeeSection *segtmp = seghead;
+ seghead = seghead->next;
+ while (segtmp->pubhead) {
+ struct ieeePublic *pubtmp = segtmp->pubhead;
+ segtmp->pubhead = pubtmp->next;
+ nasm_free(pubtmp);
+ }
+ while (segtmp->fptr) {
+ struct ieeeFixupp *fixtmp = segtmp->fptr;
+ segtmp->fptr = fixtmp->next;
+ nasm_free(fixtmp);
+ }
+ while (segtmp->data) {
+ struct ieeeObjData *dattmp = segtmp->data;
+ segtmp->data = dattmp->next;
+ nasm_free(dattmp);
+ }
+ nasm_free(segtmp);
+ }
+ while (fpubhead) {
+ struct ieeePublic *pubtmp = fpubhead;
+ fpubhead = fpubhead->next;
+ nasm_free(pubtmp);
+ }
+ while (exthead) {
+ struct ieeeExternal *exttmp = exthead;
+ exthead = exthead->next;
+ nasm_free(exttmp);
+ }
+ while (ebhead) {
+ struct ExtBack *ebtmp = ebhead;
+ ebhead = ebhead->next;
+ nasm_free(ebtmp);
+ }
+}
+
+/*
+ * callback for labels
+ */
+static void ieee_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ /*
+ * We have three cases:
+ *
+ * (i) `segment' is a segment-base. If so, set the name field
+ * for the segment structure it refers to, and then
+ * return.
+ *
+ * (ii) `segment' is one of our segments, or a SEG_ABS segment.
+ * Save the label position for later output of a PUBDEF record.
+ *
+ *
+ * (iii) `segment' is not one of our segments. Save the label
+ * position for later output of an EXTDEF.
+ */
+ struct ieeeExternal *ext;
+ struct ExtBack *eb;
+ struct ieeeSection *seg;
+ int i;
+
+ if (special)
+ nasm_nonfatal("unrecognised symbol type `%s'", special);
+ /*
+ * First check for the double-period, signifying something
+ * unusual.
+ */
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ if (!strcmp(name, "..start")) {
+ ieee_entry_seg = segment;
+ ieee_entry_ofs = offset;
+ }
+ return;
+ }
+
+ /*
+ * Case (i):
+ */
+ if (ieee_seg_needs_update) {
+ ieee_seg_needs_update->name = name;
+ return;
+ }
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ /*
+ * case (ii)
+ */
+ if (segment >= SEG_ABS) {
+ /*
+ * SEG_ABS subcase of (ii).
+ */
+ if (is_global) {
+ struct ieeePublic *pub;
+
+ pub = *fpubtail = nasm_malloc(sizeof(*pub));
+ fpubtail = &pub->next;
+ pub->next = NULL;
+ pub->name = name;
+ pub->offset = offset;
+ pub->segment = segment & ~SEG_ABS;
+ }
+ return;
+ }
+
+ for (seg = seghead; seg && is_global; seg = seg->next)
+ if (seg->index == segment) {
+ struct ieeePublic *pub;
+
+ last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
+ seg->pubtail = &pub->next;
+ pub->next = NULL;
+ pub->name = name;
+ pub->offset = offset;
+ pub->index = seg->ieee_index;
+ pub->segment = -1;
+ return;
+ }
+
+ /*
+ * Case (iii).
+ */
+ if (is_global) {
+ ext = *exttail = nasm_malloc(sizeof(*ext));
+ ext->next = NULL;
+ exttail = &ext->next;
+ ext->name = name;
+ if (is_global == 2)
+ ext->commonsize = offset;
+ else
+ ext->commonsize = 0;
+ i = segment / 2;
+ eb = ebhead;
+ if (!eb) {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ while (i > EXT_BLKSIZ) {
+ if (eb && eb->next)
+ eb = eb->next;
+ else {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ i -= EXT_BLKSIZ;
+ }
+ eb->index[i] = externals++;
+ }
+
+}
+
+/*
+ * Put data out
+ */
+static void ieee_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ const uint8_t *ucdata;
+ int32_t ldata;
+ struct ieeeSection *seg;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint; /* ignored */
+ if (segto != ieee_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in IEEE driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("code directed to nonexistent segment?");
+
+ if (type == OUT_RAWDATA) {
+ ucdata = data;
+ while (size--)
+ ieee_write_byte(seg, *ucdata++);
+ } else if (type == OUT_ADDRESS || type == OUT_REL2ADR ||
+ type == OUT_REL4ADR) {
+ if (type == OUT_ADDRESS)
+ size = abs((int)size);
+ else if (segment == NO_SEG)
+ nasm_nonfatal("relative call to absolute address not"
+ " supported by IEEE format");
+ ldata = *(int64_t *)data;
+ if (type == OUT_REL2ADR)
+ ldata += (size - 2);
+ if (type == OUT_REL4ADR)
+ ldata += (size - 4);
+ ieee_write_fixup(segment, wrt, seg, size, type, ldata);
+ if (size == 2)
+ ieee_write_word(seg, ldata);
+ else
+ ieee_write_dword(seg, ldata);
+ } else if (type == OUT_RESERVE) {
+ while (size--)
+ ieee_write_byte(seg, 0);
+ }
+}
+
+static void ieee_data_new(struct ieeeSection *segto)
+{
+
+ if (!segto->data)
+ segto->data = segto->datacurr =
+ nasm_malloc(sizeof(*(segto->datacurr)));
+ else
+ segto->datacurr = segto->datacurr->next =
+ nasm_malloc(sizeof(*(segto->datacurr)));
+ segto->datacurr->next = NULL;
+}
+
+/*
+ * this routine is unalduterated bloatware. I usually don't do this
+ * but I might as well see what it is like on a harmless program.
+ * If anyone wants to optimize this is a good canditate!
+ */
+static void ieee_write_fixup(int32_t segment, int32_t wrt,
+ struct ieeeSection *segto, int size,
+ uint64_t realtype, int32_t offset)
+{
+ struct ieeeSection *target;
+ struct ieeeFixupp s;
+
+ /* Don't put a fixup for things NASM can calculate */
+ if (wrt == NO_SEG && segment == NO_SEG)
+ return;
+
+ s.ftype = -1;
+ /* if it is a WRT offset */
+ if (wrt != NO_SEG) {
+ s.ftype = FT_WRT;
+ s.addend = offset;
+ if (wrt >= SEG_ABS)
+ s.id1 = -(wrt - SEG_ABS);
+ else {
+ if (wrt % 2 && realtype != OUT_REL2ADR
+ && realtype != OUT_REL4ADR) {
+ wrt--;
+
+ for (target = seghead; target; target = target->next)
+ if (target->index == wrt)
+ break;
+ if (target) {
+ s.id1 = target->ieee_index;
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment)
+ break;
+
+ if (target)
+ s.id2 = target->ieee_index;
+ else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ s.ftype = FT_EXTWRT;
+ s.addend = 0;
+ s.id2 = eb->index[i];
+ } else
+ nasm_nonfatal("source of WRT must be an offset");
+ }
+
+ } else
+ nasm_panic("unrecognised WRT value in ieee_write_fixup");
+ } else
+ nasm_nonfatal("target of WRT must be a section");
+ }
+ s.size = size;
+ ieee_install_fixup(segto, &s);
+ return;
+ }
+ /* Pure segment fixup ? */
+ if (segment != NO_SEG) {
+ s.ftype = FT_SEG;
+ s.id1 = 0;
+ if (segment >= SEG_ABS) {
+ /* absolute far segment fixup */
+ s.id1 = -(segment - ~SEG_ABS);
+ } else if (segment % 2) {
+ /* fixup to named segment */
+ /* look it up */
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment - 1)
+ break;
+ if (target)
+ s.id1 = target->ieee_index;
+ else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ nasm_panic("Segment of a rel not supported in ieee_write_fixup");
+ } else {
+ /* If we want the segment */
+ s.ftype = FT_EXTSEG;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ }
+
+ } else
+ /* If we get here the seg value doesn't make sense */
+ nasm_panic("unrecognised segment value in ieee_write_fixup");
+ }
+
+ } else {
+ /* Assume we are offsetting directly from a section
+ * So look up the target segment
+ */
+ for (target = seghead; target; target = target->next)
+ if (target->index == segment)
+ break;
+ if (target) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ /* PC rel to a known offset */
+ s.id1 = target->ieee_index;
+ s.ftype = FT_REL;
+ s.size = size;
+ s.addend = offset;
+ } else {
+ /* We were offsetting from a seg */
+ s.id1 = target->ieee_index;
+ s.ftype = FT_OFS;
+ s.size = size;
+ s.addend = offset;
+ }
+ } else {
+ /*
+ * Now we assume the segment field is being used
+ * to hold an extern index
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ while (i > EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ /* if we have an extern decide the type and make a record
+ */
+ if (eb) {
+ if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+ s.ftype = FT_EXTREL;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ } else {
+ /* else we want the external offset */
+ s.ftype = FT_EXT;
+ s.addend = 0;
+ s.id1 = eb->index[i];
+ }
+
+ } else
+ /* If we get here the seg value doesn't make sense */
+ nasm_panic("unrecognised segment value in ieee_write_fixup");
+ }
+ }
+ if (size != 2 && s.ftype == FT_SEG)
+ nasm_nonfatal("IEEE format can only handle 2-byte"
+ " segment base references");
+ s.size = size;
+ ieee_install_fixup(segto, &s);
+ return;
+ }
+ /* should never get here */
+}
+static void ieee_install_fixup(struct ieeeSection *seg,
+ struct ieeeFixupp *fix)
+{
+ struct ieeeFixupp *f;
+ f = nasm_malloc(sizeof(struct ieeeFixupp));
+ memcpy(f, fix, sizeof(struct ieeeFixupp));
+ f->offset = seg->currentpos;
+ seg->currentpos += fix->size;
+ f->next = NULL;
+ if (seg->fptr)
+ seg->flptr = seg->flptr->next = f;
+ else
+ seg->fptr = seg->flptr = f;
+
+}
+
+/*
+ * segment registry
+ */
+static int32_t ieee_segment(char *name, int *bits)
+{
+ /*
+ * We call the label manager here to define a name for the new
+ * segment, and when our _own_ label-definition stub gets
+ * called in return, it should register the new segment name
+ * using the pointer it gets passed. That way we save memory,
+ * by sponging off the label manager.
+ */
+ if (!name) {
+ *bits = 16;
+ if (!any_segs)
+ return 0;
+ return seghead->index;
+ } else {
+ struct ieeeSection *seg;
+ int ieee_idx, attrs;
+ bool rn_error;
+ char *p;
+
+ /*
+ * Look for segment attributes.
+ */
+ attrs = 0;
+ while (*name == '.')
+ name++; /* hack, but a documented one */
+ p = name;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+ while (*p) {
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+
+ attrs++;
+ }
+
+ ieee_idx = 1;
+ for (seg = seghead; seg; seg = seg->next) {
+ ieee_idx++;
+ if (!strcmp(seg->name, name)) {
+ if (attrs > 0 && seg->pass_last_seen == pass_count())
+ nasm_warn(WARN_OTHER, "segment attributes specified on"
+ " redeclaration of segment: ignoring");
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+
+ seg->pass_last_seen = pass_count();
+ return seg->index;
+ }
+ }
+
+ *segtail = seg = nasm_malloc(sizeof(*seg));
+ seg->next = NULL;
+ segtail = &seg->next;
+ seg->index = seg_alloc();
+ seg->ieee_index = ieee_idx;
+ any_segs = true;
+ seg->name = NULL;
+ seg->currentpos = 0;
+ seg->align = 1; /* default */
+ seg->use32 = *bits == 32; /* default to user spec */
+ seg->combine = CMB_PUBLIC; /* default */
+ seg->pubhead = NULL;
+ seg->pubtail = &seg->pubhead;
+ seg->data = NULL;
+ seg->fptr = NULL;
+ seg->lochead = NULL;
+ seg->loctail = &seg->lochead;
+
+ /*
+ * Process the segment attributes.
+ */
+ p = name;
+ while (attrs--) {
+ p += strlen(p);
+ while (!*p)
+ p++;
+
+ /*
+ * `p' contains a segment attribute.
+ */
+ if (!nasm_stricmp(p, "private"))
+ seg->combine = CMB_PRIVATE;
+ else if (!nasm_stricmp(p, "public"))
+ seg->combine = CMB_PUBLIC;
+ else if (!nasm_stricmp(p, "common"))
+ seg->combine = CMB_COMMON;
+ else if (!nasm_stricmp(p, "use16"))
+ seg->use32 = false;
+ else if (!nasm_stricmp(p, "use32"))
+ seg->use32 = true;
+ else if (!nasm_strnicmp(p, "align=", 6)) {
+ seg->align = readnum(p + 6, &rn_error);
+ if (seg->align == 0)
+ seg->align = 1;
+ if (rn_error) {
+ seg->align = 1;
+ nasm_nonfatal("segment alignment should be numeric");
+ }
+ switch (seg->align) {
+ case 1: /* BYTE */
+ case 2: /* WORD */
+ case 4: /* DWORD */
+ case 16: /* PARA */
+ case 256: /* PAGE */
+ case 8:
+ case 32:
+ case 64:
+ case 128:
+ break;
+ default:
+ nasm_nonfatal("invalid alignment value %d", seg->align);
+ seg->align = 1;
+ break;
+ }
+ } else if (!nasm_strnicmp(p, "absolute=", 9)) {
+ seg->align = SEG_ABS + readnum(p + 9, &rn_error);
+ if (rn_error)
+ nasm_nonfatal("argument to `absolute' segment"
+ " attribute should be numeric");
+ }
+ }
+
+ ieee_seg_needs_update = seg;
+ if (seg->align >= SEG_ABS)
+ define_label(name, NO_SEG, seg->align - SEG_ABS, false);
+ else
+ define_label(name, seg->index + 1, 0L, false);
+ ieee_seg_needs_update = NULL;
+
+ /*
+ * In commit 98578071b9d71ecaa2344dd9c185237c1765041e
+ * we reworked labels significantly which in turn lead
+ * to the case where seg->name = NULL here and we get
+ * nil dereference in next segments definitions.
+ *
+ * Lets placate this case with explicit name setting
+ * if labels engine didn't set it yet.
+ *
+ * FIXME: Need to revisit this moment if such fix doesn't
+ * break anything but since IEEE 695 format is veeery
+ * old I don't expect there are many users left. In worst
+ * case this should only lead to a memory leak.
+ */
+ if (!seg->name)
+ seg->name = nasm_strdup(name);
+
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+ return seg->index;
+ }
+}
+
+/*
+ * directives supported
+ */
+static enum directive_result
+ieee_directive(enum directive directive, char *value)
+{
+ (void)value;
+
+ switch (directive) {
+ case D_UPPERCASE:
+ ieee_uppercase = true;
+ return DIRR_OK;
+
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+static void ieee_sectalign(int32_t seg, unsigned int value)
+{
+ struct ieeeSection *s;
+
+ list_for_each(s, seghead) {
+ if (s->index == seg)
+ break;
+ }
+
+ /*
+ * 256 is maximum there, note it may happen
+ * that align is issued on "absolute" segment
+ * it's fine since SEG_ABS > 256 and we never
+ * get escape this test
+ */
+ if (!s || !is_power2(value) || value > 256)
+ return;
+
+ if ((unsigned int)s->align < value)
+ s->align = value;
+}
+
+/*
+ * Return segment data
+ */
+static int32_t ieee_segbase(int32_t segment)
+{
+ struct ieeeSection *seg;
+
+ /*
+ * Find the segment in our list.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment - 1)
+ break;
+
+ if (!seg)
+ return segment; /* not one of ours - leave it alone */
+
+ if (seg->align >= SEG_ABS)
+ return seg->align; /* absolute segment */
+
+ return segment; /* no special treatment */
+}
+
+static void ieee_write_file(void)
+{
+ const struct tm * const thetime = &official_compile_time.local;
+ struct FileName *fn;
+ struct ieeeSection *seg;
+ struct ieeePublic *pub, *loc;
+ struct ieeeExternal *ext;
+ struct ieeeObjData *data;
+ struct ieeeFixupp *fix;
+ struct Array *arr;
+ int i;
+ const bool debuginfo = (dfmt == &ladsoft_debug_form);
+
+ /*
+ * Write the module header
+ */
+ ieee_putascii("MBFNASM,%02X%s.\n", strlen(ieee_infile), ieee_infile);
+
+ /*
+ * Write the NASM boast comment.
+ */
+ ieee_putascii("CO0,%02X%s.\n", nasm_comment_len(), nasm_comment());
+
+ /*
+ * write processor-specific information
+ */
+ ieee_putascii("AD8,4,L.\n");
+
+ /*
+ * date and time
+ */
+ ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\n",
+ 1900 + thetime->tm_year, thetime->tm_mon + 1,
+ thetime->tm_mday, thetime->tm_hour, thetime->tm_min,
+ thetime->tm_sec);
+ /*
+ * if debugging, dump file names
+ */
+ for (fn = fnhead; fn && debuginfo; fn = fn->next) {
+ ieee_putascii("C0105,%02X%s.\n", strlen(fn->name), fn->name);
+ }
+
+ ieee_putascii("CO101,07ENDHEAD.\n");
+ /*
+ * the standard doesn't specify when to put checksums,
+ * we'll just do it periodically.
+ */
+ ieee_putcs(false);
+
+ /*
+ * Write the section headers
+ */
+ seg = seghead;
+ if (!debuginfo && seg && !strcmp(seg->name, "??LINE"))
+ seg = seg->next;
+ while (seg) {
+ char buf[256];
+ char attrib;
+ switch (seg->combine) {
+ case CMB_PUBLIC:
+ default:
+ attrib = 'C';
+ break;
+ case CMB_PRIVATE:
+ attrib = 'S';
+ break;
+ case CMB_COMMON:
+ attrib = 'M';
+ break;
+ }
+ ieee_unqualified_name(buf, seg->name);
+ if (seg->align >= SEG_ABS) {
+ ieee_putascii("ST%X,A,%02X%s.\n", seg->ieee_index,
+ strlen(buf), buf);
+ ieee_putascii("ASL%X,%lX.\n", seg->ieee_index,
+ (seg->align - SEG_ABS) * 16);
+ } else {
+ ieee_putascii("ST%X,%c,%02X%s.\n", seg->ieee_index, attrib,
+ strlen(buf), buf);
+ ieee_putascii("SA%X,%lX.\n", seg->ieee_index, seg->align);
+ ieee_putascii("ASS%X,%X.\n", seg->ieee_index,
+ seg->currentpos);
+ }
+ seg = seg->next;
+ }
+ /*
+ * write the start address if there is one
+ */
+ if (ieee_entry_seg && seghead) {
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == ieee_entry_seg)
+ break;
+ if (!seg)
+ nasm_panic("Start address records are incorrect");
+ else
+ ieee_putascii("ASG,R%X,%lX,+.\n", seg->ieee_index,
+ ieee_entry_ofs);
+ }
+
+ ieee_putcs(false);
+ /*
+ * Write the publics
+ */
+ i = 1;
+ for (seg = seghead; seg; seg = seg->next) {
+ for (pub = seg->pubhead; pub; pub = pub->next) {
+ char buf[256];
+ ieee_unqualified_name(buf, pub->name);
+ ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf);
+ if (pub->segment == -1)
+ ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index,
+ pub->offset);
+ else
+ ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16,
+ pub->offset);
+ if (debuginfo) {
+ if (pub->type >= 0x100)
+ ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100);
+ else
+ ieee_putascii("ATI%X,%X.\n", i, pub->type);
+ }
+ i++;
+ }
+ }
+ pub = fpubhead;
+ i = 1;
+ while (pub) {
+ char buf[256];
+ ieee_unqualified_name(buf, pub->name);
+ ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf);
+ if (pub->segment == -1)
+ ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index,
+ pub->offset);
+ else
+ ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16,
+ pub->offset);
+ if (debuginfo) {
+ if (pub->type >= 0x100)
+ ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100);
+ else
+ ieee_putascii("ATI%X,%X.\n", i, pub->type);
+ }
+ i++;
+ pub = pub->next;
+ }
+ /*
+ * Write the externals
+ */
+ ext = exthead;
+ i = 1;
+ while (ext) {
+ char buf[256];
+ ieee_unqualified_name(buf, ext->name);
+ ieee_putascii("NX%X,%02X%s.\n", i++, strlen(buf), buf);
+ ext = ext->next;
+ }
+ ieee_putcs(false);
+
+ /*
+ * IEEE doesn't have a standard pass break record
+ * so use the ladsoft variant
+ */
+ ieee_putascii("CO100,06ENDSYM.\n");
+
+ /*
+ * now put types
+ */
+ i = ARRAY_BOT;
+ for (arr = arrhead; arr && debuginfo; arr = arr->next) {
+ ieee_putascii("TY%X,20,%X,%lX.\n", i++, arr->basetype,
+ arr->size);
+ }
+ /*
+ * now put locals
+ */
+ i = 1;
+ for (seg = seghead; seg && debuginfo; seg = seg->next) {
+ for (loc = seg->lochead; loc; loc = loc->next) {
+ char buf[256];
+ ieee_unqualified_name(buf, loc->name);
+ ieee_putascii("NN%X,%02X%s.\n", i, strlen(buf), buf);
+ if (loc->segment == -1)
+ ieee_putascii("ASN%X,R%X,%lX,+.\n", i, loc->index,
+ loc->offset);
+ else
+ ieee_putascii("ASN%X,%lX,%lX,+.\n", i, loc->segment * 16,
+ loc->offset);
+ if (debuginfo) {
+ if (loc->type >= 0x100)
+ ieee_putascii("ATN%X,T%X.\n", i, loc->type - 0x100);
+ else
+ ieee_putascii("ATN%X,%X.\n", i, loc->type);
+ }
+ i++;
+ }
+ }
+
+ /*
+ * put out section data;
+ */
+ seg = seghead;
+ if (!debuginfo && seg && !strcmp(seg->name, "??LINE"))
+ seg = seg->next;
+ while (seg) {
+ if (seg->currentpos) {
+ int32_t size, org = 0;
+ data = seg->data;
+ ieee_putascii("SB%X.\n", seg->ieee_index);
+ fix = seg->fptr;
+ while (fix) {
+ size = HUNKSIZE - (org % HUNKSIZE);
+ size =
+ size + org >
+ seg->currentpos ? seg->currentpos - org : size;
+ size = fix->offset - org > size ? size : fix->offset - org;
+ org = ieee_putld(org, org + size, data->data);
+ if (org % HUNKSIZE == 0)
+ data = data->next;
+ if (org == fix->offset) {
+ org += ieee_putlr(fix);
+ fix = fix->next;
+ }
+ }
+ while (org < seg->currentpos && data) {
+ size =
+ seg->currentpos - org >
+ HUNKSIZE ? HUNKSIZE : seg->currentpos - org;
+ org = ieee_putld(org, org + size, data->data);
+ data = data->next;
+ }
+ ieee_putcs(false);
+
+ }
+ seg = seg->next;
+ }
+ /*
+ * module end record
+ */
+ ieee_putascii("ME.\n");
+}
+
+static void ieee_write_byte(struct ieeeSection *seg, int data)
+{
+ int temp;
+ if (!(temp = seg->currentpos++ % HUNKSIZE))
+ ieee_data_new(seg);
+ seg->datacurr->data[temp] = data;
+}
+
+static void ieee_write_word(struct ieeeSection *seg, int data)
+{
+ ieee_write_byte(seg, data & 0xFF);
+ ieee_write_byte(seg, (data >> 8) & 0xFF);
+}
+
+static void ieee_write_dword(struct ieeeSection *seg, int32_t data)
+{
+ ieee_write_byte(seg, data & 0xFF);
+ ieee_write_byte(seg, (data >> 8) & 0xFF);
+ ieee_write_byte(seg, (data >> 16) & 0xFF);
+ ieee_write_byte(seg, (data >> 24) & 0xFF);
+}
+static void printf_func(1, 2) ieee_putascii(char *format, ...)
+{
+ char buffer[256];
+ size_t i, l;
+ va_list ap;
+
+ va_start(ap, format);
+ l = vsnprintf(buffer, sizeof(buffer), format, ap);
+ nasm_assert(l < sizeof(buffer));
+ for (i = 0; i < l; i++)
+ if ((uint8_t)buffer[i] > 31)
+ checksum += buffer[i];
+ va_end(ap);
+ fputs(buffer, ofile);
+}
+
+/*
+ * put out a checksum record */
+static void ieee_putcs(int toclear)
+{
+ if (toclear) {
+ ieee_putascii("CS.\n");
+ } else {
+ checksum += 'C';
+ checksum += 'S';
+ ieee_putascii("CS%02X.\n", checksum & 127);
+ }
+ checksum = 0;
+}
+
+static int32_t ieee_putld(int32_t start, int32_t end, uint8_t *buf)
+{
+ int32_t val;
+ if (start == end)
+ return (start);
+ val = start % HUNKSIZE;
+ /* fill up multiple lines */
+ while (end - start >= LDPERLINE) {
+ int i;
+ ieee_putascii("LD");
+ for (i = 0; i < LDPERLINE; i++) {
+ ieee_putascii("%02X", buf[val++]);
+ start++;
+ }
+ ieee_putascii(".\n");
+ }
+ /* if no partial lines */
+ if (start == end)
+ return (start);
+ /* make a partial line */
+ ieee_putascii("LD");
+ while (start < end) {
+ ieee_putascii("%02X", buf[val++]);
+ start++;
+ }
+ ieee_putascii(".\n");
+ return (start);
+}
+static int32_t ieee_putlr(struct ieeeFixupp *p)
+{
+/*
+ * To deal with the vagaries of segmentation the LADsoft linker
+ * defines two types of segments: absolute and virtual. Note that
+ * 'absolute' in this context is a different thing from the IEEE
+ * definition of an absolute segment type, which is also supported. If a
+ * segment is linked in virtual mode the low limit (L-var) is
+ * subtracted from each R,X, and P variable which appears in an
+ * expression, so that we can have relative offsets. Meanwhile
+ * in the ABSOLUTE mode this subtraction is not done and
+ * so we can use absolute offsets from 0. In the LADsoft linker
+ * this configuration is not done in the assemblker source but in
+ * a source the linker reads. Generally this type of thing only
+ * becomes an issue if real mode code is used. A pure 32-bit linker could
+ * get away without defining the virtual mode...
+ */
+ char buf[40];
+ int32_t size = p->size;
+ switch (p->ftype) {
+ case FT_SEG:
+ if (p->id1 < 0)
+ sprintf(buf, "%"PRIX32"", -p->id1);
+ else
+ sprintf(buf, "L%"PRIX32",10,/", p->id1);
+ break;
+ case FT_OFS:
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+", p->id1, p->addend);
+ break;
+ case FT_REL:
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,P,-,%X,-", p->id1, p->addend, p->size);
+ break;
+
+ case FT_WRT:
+ if (p->id2 < 0)
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,%"PRIX32",-", p->id2, p->addend,
+ p->id2, -p->id1 * 16);
+ else
+ sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,L%"PRIX32",-", p->id2, p->addend,
+ p->id2, p->id1);
+ break;
+ case FT_EXT:
+ sprintf(buf, "X%"PRIX32"", p->id1);
+ break;
+ case FT_EXTREL:
+ sprintf(buf, "X%"PRIX32",P,-,%"PRIX32",-", p->id1, size);
+ break;
+ case FT_EXTSEG:
+ /* We needed a non-ieee hack here.
+ * We introduce the Y variable, which is the low
+ * limit of the native segment the extern resides in
+ */
+ sprintf(buf, "Y%"PRIX32",10,/", p->id1);
+ break;
+ case FT_EXTWRT:
+ if (p->id2 < 0)
+ sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,%"PRIX32",-", p->id2, p->id2,
+ -p->id1 * 16);
+ else
+ sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,L%"PRIX32",-", p->id2, p->id2, p->id1);
+ break;
+ }
+ ieee_putascii("LR(%s,%"PRIX32").\n", buf, size);
+
+ return (size);
+}
+
+/* Dump all segment data (text and fixups )*/
+
+static void ieee_unqualified_name(char *dest, char *source)
+{
+ if (ieee_uppercase) {
+ while (*source)
+ *dest++ = toupper(*source++);
+ *dest = 0;
+ } else
+ strcpy(dest, source);
+}
+static void dbgls_init(void)
+{
+ int tempint;
+
+ fnhead = NULL;
+ fntail = &fnhead;
+ arrindex = ARRAY_BOT;
+ arrhead = NULL;
+ arrtail = &arrhead;
+ ieee_segment("??LINE", &tempint);
+ any_segs = false;
+}
+static void dbgls_cleanup(void)
+{
+ struct ieeeSection *segtmp;
+ while (fnhead) {
+ struct FileName *fntemp = fnhead;
+ fnhead = fnhead->next;
+ nasm_free(fntemp->name);
+ nasm_free(fntemp);
+ }
+ for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
+ while (segtmp->lochead) {
+ struct ieeePublic *loctmp = segtmp->lochead;
+ segtmp->lochead = loctmp->next;
+ nasm_free(loctmp->name);
+ nasm_free(loctmp);
+ }
+ }
+ while (arrhead) {
+ struct Array *arrtmp = arrhead;
+ arrhead = arrhead->next;
+ nasm_free(arrtmp);
+ }
+}
+
+/*
+ * because this routine is not bracketed in
+ * the main program, this routine will be called even if there
+ * is no request for debug info
+ * so, we have to make sure the ??LINE segment is available
+ * as the first segment when this debug format is selected
+ */
+static void dbgls_linnum(const char *lnfname, int32_t lineno, int32_t segto)
+{
+ struct FileName *fn;
+ struct ieeeSection *seg;
+ int i = 0;
+ if (segto == NO_SEG)
+ return;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint; /* ignored */
+ if (segto != ieee_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in IEEE driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("lineno directed to nonexistent segment?");
+
+ for (fn = fnhead; fn; fn = fn->next) {
+ if (!nasm_stricmp(lnfname, fn->name))
+ break;
+ i++;
+ }
+ if (!fn) {
+ fn = nasm_malloc(sizeof(*fn));
+ fn->name = nasm_malloc(strlen(lnfname) + 1);
+ fn->index = i;
+ strcpy(fn->name, lnfname);
+ fn->next = NULL;
+ *fntail = fn;
+ fntail = &fn->next;
+ }
+ ieee_write_byte(seghead, fn->index);
+ ieee_write_word(seghead, lineno);
+ ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS,
+ seg->currentpos);
+
+}
+static void dbgls_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ struct ieeeSection *seg;
+
+ /* Keep compiler from warning about special */
+ (void)special;
+
+ /*
+ * Note: ..[^@] special symbols are filtered in labels.c
+ */
+
+ /*
+ * If it's a special-retry from pass two, discard it.
+ */
+ if (is_global == 3)
+ return;
+
+ /*
+ * Case (i):
+ */
+ if (ieee_seg_needs_update)
+ return;
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ if (segment >= SEG_ABS || segment == NO_SEG) {
+ return;
+ }
+
+ /*
+ * If `any_segs' is still false, we might need to define a
+ * default segment, if they're trying to declare a label in
+ * `first_seg'. But the label should exist due to a prior
+ * call to ieee_deflabel so we can skip that.
+ */
+
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment) {
+ struct ieeePublic *loc;
+ /*
+ * Case (ii). Maybe MODPUB someday?
+ */
+ if (!is_global) {
+ last_defined = loc = nasm_malloc(sizeof(*loc));
+ *seg->loctail = loc;
+ seg->loctail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+ loc->segment = -1;
+ loc->index = seg->ieee_index;
+ }
+ }
+}
+static void dbgls_typevalue(int32_t type)
+{
+ int elem = TYM_ELEMENTS(type);
+ type = TYM_TYPE(type);
+
+ if (!last_defined)
+ return;
+
+ switch (type) {
+ case TY_BYTE:
+ last_defined->type = 1; /* uint8_t */
+ break;
+ case TY_WORD:
+ last_defined->type = 3; /* unsigned word */
+ break;
+ case TY_DWORD:
+ last_defined->type = 5; /* unsigned dword */
+ break;
+ case TY_FLOAT:
+ last_defined->type = 9; /* float */
+ break;
+ case TY_QWORD:
+ last_defined->type = 10; /* qword */
+ break;
+ case TY_TBYTE:
+ last_defined->type = 11; /* TBYTE */
+ break;
+ default:
+ last_defined->type = 0x10; /* near label */
+ break;
+ }
+
+ if (elem > 1) {
+ struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp));
+ int vtype = last_defined->type;
+ arrtmp->size = elem;
+ arrtmp->basetype = vtype;
+ arrtmp->next = NULL;
+ last_defined->type = arrindex++ + 0x100;
+ *arrtail = arrtmp;
+ arrtail = &(arrtmp->next);
+ }
+ last_defined = NULL;
+}
+static void dbgls_output(int output_type, void *param)
+{
+ (void)output_type;
+ (void)param;
+}
+static const struct dfmt ladsoft_debug_form = {
+ "LADsoft Debug Records",
+ "ladsoft",
+ dbgls_init,
+ dbgls_linnum,
+ dbgls_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ dbgls_typevalue,
+ dbgls_output,
+ dbgls_cleanup,
+ NULL /* pragma list */
+};
+static const struct dfmt * const ladsoft_debug_arr[3] = {
+ &ladsoft_debug_form,
+ &null_debug_form,
+ NULL
+};
+const struct ofmt of_ieee = {
+ "IEEE-695 (LADsoft variant) object file format",
+ "ieee",
+ ".o",
+ OFMT_TEXT,
+ 32,
+ ladsoft_debug_arr,
+ &ladsoft_debug_form,
+ NULL,
+ ieee_init,
+ null_reset,
+ nasm_do_legacy_output,
+ ieee_out,
+ ieee_deflabel,
+ ieee_segment,
+ NULL,
+ ieee_sectalign,
+ ieee_segbase,
+ ieee_directive,
+ ieee_cleanup,
+ NULL /* pragma list */
+};
+
+#endif /* OF_IEEE */
diff --git a/vere/ext/nasm/output/outlib.c b/vere/ext/nasm/output/outlib.c
new file mode 100644
index 0000000..54c8753
--- /dev/null
+++ b/vere/ext/nasm/output/outlib.c
@@ -0,0 +1,324 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outlib.c
+ *
+ * Common routines for the output backends.
+ */
+
+#include "outlib.h"
+#include "raa.h"
+
+uint64_t realsize(enum out_type type, uint64_t size)
+{
+ switch (type) {
+ case OUT_REL1ADR:
+ return 1;
+ case OUT_REL2ADR:
+ return 2;
+ case OUT_REL4ADR:
+ return 4;
+ case OUT_REL8ADR:
+ return 8;
+ default:
+ return size;
+ }
+}
+
+/* Common section/symbol handling */
+
+struct ol_sect *_ol_sect_list;
+uint64_t _ol_nsects; /* True sections, not external symbols */
+static struct ol_sect **ol_sect_tail = &_ol_sect_list;
+static struct hash_table ol_secthash;
+static struct RAA *ol_sect_index_tbl;
+
+struct ol_sym *_ol_sym_list;
+uint64_t _ol_nsyms;
+static struct ol_sym **ol_sym_tail = &_ol_sym_list;
+static struct hash_table ol_symhash;
+
+void ol_init(void)
+{
+}
+
+static void ol_free_symbols(void)
+{
+ struct ol_sym *s, *stmp;
+
+ hash_free(&ol_symhash);
+
+ list_for_each_safe(s, stmp, _ol_sym_list) {
+ nasm_free((char *)s->name);
+ nasm_free(s);
+ }
+
+ _ol_nsyms = 0;
+ _ol_sym_list = NULL;
+ ol_sym_tail = &_ol_sym_list;
+}
+
+static void ol_free_sections(void)
+{
+ struct ol_sect *s, *stmp;
+
+ hash_free(&ol_secthash);
+ raa_free(ol_sect_index_tbl);
+ ol_sect_index_tbl = NULL;
+
+ list_for_each_safe(s, stmp, _ol_sect_list) {
+ saa_free(s->data);
+ saa_free(s->reloc);
+ nasm_free((char *)s->name);
+ nasm_free(s);
+ }
+
+ _ol_nsects = 0;
+ _ol_sect_list = NULL;
+ ol_sect_tail = &_ol_sect_list;
+}
+
+void ol_cleanup(void)
+{
+ ol_free_symbols();
+ ol_free_sections();
+}
+
+/*
+ * Allocate a section index and add a section, subsection, or external
+ * symbol to the section-by-index table. If the index provided is zero,
+ * allocate a new index via seg_alloc().
+ */
+static uint32_t ol_seg_alloc(void *s, uint32_t ix)
+{
+ if (!ix)
+ ix = seg_alloc();
+ ol_sect_index_tbl = raa_write_ptr(ol_sect_index_tbl, ix >> 1, s);
+ return ix;
+}
+
+/*
+ * Find a section or create a new section structure if it does not exist
+ * and allocate it an index value via seg_alloc().
+ */
+struct ol_sect *_ol_get_sect(const char *name, size_t ssize, size_t rsize)
+{
+ struct ol_sect *s, **sp;
+ struct hash_insert hi;
+
+ sp = (struct ol_sect **)hash_find(&ol_secthash, name, &hi);
+ if (sp)
+ return *sp;
+
+ s = nasm_zalloc(ssize);
+ s->syml.tail = &s->syml.head;
+ s->name = nasm_strdup(name);
+ s->data = saa_init(1);
+ s->reloc = saa_init(rsize);
+ *ol_sect_tail = s;
+ ol_sect_tail = &s->next;
+ _ol_nsects++;
+ s->index = s->subindex = ol_seg_alloc(s, 0);
+
+ hash_add(&hi, s->name, s);
+ return s;
+}
+
+/* Find a section by name without creating one */
+struct ol_sect *_ol_sect_by_name(const char *name)
+{
+ struct ol_sect **sp;
+
+ sp = (struct ol_sect **)hash_find(&ol_secthash, name, NULL);
+ return sp ? *sp : NULL;
+}
+
+/* Find a section or external symbol by index; NULL if not valid */
+struct ol_sect *_ol_sect_by_index(int32_t index)
+{
+ uint32_t ix = index;
+
+ if (unlikely(ix >= SEG_ABS))
+ return NULL;
+
+ return raa_read_ptr(ol_sect_index_tbl, ix >> 1);
+}
+
+/*
+ * Start a new subsection for the given section. At the moment, once a
+ * subsection has been created, it is not possible to revert to an
+ * earlier subsection. ol_sect_by_index() will return the main section
+ * structure. Returns the new section index. This is used to prevent
+ * the front end from optimizing across subsection boundaries.
+ */
+int32_t _ol_new_subsection(struct ol_sect *sect)
+{
+ if (unlikely(!sect))
+ return NO_SEG;
+
+ return sect->subindex = ol_seg_alloc(sect, 0);
+}
+
+/*
+ * Insert a symbol into a list; need to use upcasting using container_of()
+ * to walk the list later.
+ */
+static void ol_add_sym_to(struct ol_symlist *syml, struct ol_symhead *head,
+ uint64_t offset)
+{
+ syml->tree.key = offset;
+ head->tree = rb_insert(head->tree, &syml->tree);
+ *head->tail = syml;
+ head->tail = &syml->next;
+ head->n++;
+}
+
+/*
+ * Create a location structure from seg:offs
+ */
+void ol_mkloc(struct ol_loc *loc, int64_t offs, int32_t seg)
+{
+ nasm_zero(*loc);
+ loc->offs = offs;
+
+ if (unlikely((uint32_t)seg >= SEG_ABS)) {
+ if (likely(seg == NO_SEG)) {
+ loc->seg.t = OS_NOSEG;
+ } else {
+ loc->seg.t = OS_ABS;
+ loc->seg.index = seg - SEG_ABS;
+ }
+ } else {
+ loc->seg.index = seg & ~1;
+ loc->seg.t = OS_SECT | (seg & 1);
+ loc->seg.s.sect = _ol_sect_by_index(loc->seg.index);
+ }
+}
+
+/*
+ * Create a new symbol. If this symbol is OS_OFFS, add it to the relevant
+ * section, too. If the symbol already exists, return NULL; this is
+ * different from ol_get_section() as a single section may be invoked
+ * many times. On the contrary, the front end will prevent a single symbol
+ * from being defined more than once.
+ *
+ * If flags has OF_GLOBAL set, add it to the global symbol hash for
+ * the containing section if applicable.
+ *
+ * If flags has OF_IMPSEC set, allocate a segment index for it via
+ * seg_alloc() unless v->index is already set, and add it to the
+ * section by index list.
+ */
+struct ol_sym *_ol_new_sym(const char *name, const struct ol_loc *v,
+ uint32_t flags, size_t size)
+{
+ struct hash_insert hi;
+ struct ol_sym *sym;
+
+ if (hash_find(&ol_symhash, name, &hi))
+ return NULL; /* Symbol already exists */
+
+ flags |= OF_SYMBOL;
+
+ sym = nasm_zalloc(size);
+ sym->name = nasm_strdup(name);
+ sym->v = *v;
+
+ if (sym->v.seg.t & OS_SECT) {
+ struct ol_sect *sect = sym->v.seg.s.sect;
+
+ if (!sect || (sect->flags & OF_SYMBOL))
+ /* Must be an external or common reference */
+ flags |= OF_IMPSEC;
+
+ if (flags & OF_IMPSEC) {
+ /* Metasection */
+ if (!sym->v.seg.s.sym) {
+ sym->v.seg.s.sym = sym;
+ sym->v.seg.index = ol_seg_alloc(sym, sym->v.seg.index);
+ }
+ } else if (sym->v.seg.t == OS_OFFS) {
+ struct ol_sect * const sect = sym->v.seg.s.sect;
+ const uint64_t offs = sym->v.offs;
+
+ ol_add_sym_to(&sym->syml, &sect->syml, offs);
+ if (flags & OF_GLOBAL)
+ ol_add_sym_to(&sym->symg, &sect->symg, offs);
+ }
+ }
+ sym->flags = flags;
+
+ *ol_sym_tail = sym;
+ ol_sym_tail = &sym->next;
+ _ol_nsyms++;
+
+ hash_add(&hi, sym->name, sym);
+ return sym;
+}
+
+/* Find a symbol in the global namespace */
+struct ol_sym *_ol_sym_by_name(const char *name)
+{
+ struct ol_sym **symp;
+
+ symp = (struct ol_sym **)hash_find(&ol_symhash, name, NULL);
+ return symp ? *symp : NULL;
+}
+
+/*
+ * Find a symbol by address in a specific section. If no symbol is defined
+ * at that exact address, return the immediately previously defined one.
+ * If global is set, then only return global symbols.
+ */
+struct ol_sym *_ol_sym_by_address(struct ol_sect *sect, int64_t addr,
+ bool global)
+{
+ struct ol_symhead *head;
+ size_t t_offs;
+ struct rbtree *t;
+
+ if (global) {
+ head = &sect->symg;
+ t_offs = offsetof(struct ol_sym, symg.tree);
+ } else {
+ head = &sect->syml;
+ t_offs = offsetof(struct ol_sym, syml.tree);
+ }
+
+ t = rb_search(head->tree, addr);
+ if (!t)
+ return NULL;
+
+ return (struct ol_sym *)((char *)t - t_offs);
+}
diff --git a/vere/ext/nasm/output/outlib.h b/vere/ext/nasm/output/outlib.h
new file mode 100644
index 0000000..7f6a789
--- /dev/null
+++ b/vere/ext/nasm/output/outlib.h
@@ -0,0 +1,313 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef NASM_OUTLIB_H
+#define NASM_OUTLIB_H
+
+#include "compiler.h"
+#include "nasm.h"
+#include "error.h"
+#include "hashtbl.h"
+#include "saa.h"
+#include "rbtree.h"
+
+uint64_t realsize(enum out_type type, uint64_t size);
+
+/* Do-nothing versions of some output routines */
+enum directive_result
+null_directive(enum directive directive, char *value);
+void null_sectalign(int32_t seg, unsigned int value);
+void null_reset(void);
+int32_t null_segbase(int32_t seg);
+
+/* Do-nothing versions of all the debug routines */
+void null_debug_init(void);
+void null_debug_linenum(const char *filename, int32_t linenumber,
+ int32_t segto);
+void null_debug_deflabel(char *name, int32_t segment, int64_t offset,
+ int is_global, char *special);
+void null_debug_directive(const char *directive, const char *params);
+void null_debug_typevalue(int32_t type);
+void null_debug_output(int type, void *param);
+void null_debug_cleanup(void);
+extern const struct dfmt * const null_debug_arr[2];
+
+/* Wrapper for unported backends */
+void nasm_do_legacy_output(const struct out_data *data);
+
+/*
+ * Common routines for tasks that really should migrate into the core.
+ * This provides a common interface for maintaining sections and symbols,
+ * and provide quick lookups as well as declared-order sequential walks.
+ *
+ * These structures are intended to be embedded at the *top* of a
+ * backend-specific structure containing additional information.
+ *
+ * The tokens O_Section, O_Symbol and O_Reloc are intended to be
+ * defined as macros by the backend before including this file!
+ */
+
+struct ol_sect;
+struct ol_sym;
+
+#ifndef O_Section
+typedef struct ol_sect O_Section;
+#endif
+#ifndef O_Symbol
+typedef struct ol_sym O_Symbol;
+#endif
+#ifndef O_Reloc
+typedef void * O_Reloc;
+#endif
+
+/* Common section structure */
+
+/*
+ * Common flags for sections and symbols; low values reserved for
+ * backend. Note that both ol_sect and ol_sym begin with a flags
+ * field, so if a section pointer points to an external symbol instead
+ * they can be trivially resolved.
+ */
+#define OF_SYMBOL 0x80000000
+#define OF_GLOBAL 0x40000000
+#define OF_IMPSEC 0x20000000
+#define OF_COMMON 0x10000000
+
+struct ol_sym;
+
+struct ol_symlist {
+ struct ol_symlist *next;
+ struct rbtree tree;
+};
+struct ol_symhead {
+ struct ol_symlist *head, **tail;
+ struct rbtree *tree;
+ uint64_t n;
+};
+
+struct ol_sect {
+ uint32_t flags; /* Section/symbol flags */
+ struct ol_sect *next; /* Next section in declared order */
+ const char *name; /* Name of section */
+ struct ol_symhead syml; /* All symbols in this section */
+ struct ol_symhead symg; /* Global symbols in this section */
+ struct SAA *data; /* Contents of section */
+ struct SAA *reloc; /* Section relocations */
+ uint32_t index; /* Primary section index */
+ uint32_t subindex; /* Current subsection index */
+};
+
+/* Segment reference */
+enum ol_seg_type {
+ OS_NOSEG = 0, /* Plain number (no segment) */
+ OS_SEGREF = 1, /* It is a segment reference */
+ OS_ABS = 1, /* Absolute segment reference */
+ OS_SECT = 2, /* It is a real section */
+ OS_OFFS = OS_SECT, /* Offset reference in section */
+ OS_SEG = OS_SECT|OS_SEGREF /* Section reference */
+};
+
+union ol_segval {
+ struct ol_sect *sect; /* Section structure */
+ struct ol_sym *sym; /* External symbol structure */
+};
+
+struct ol_seg {
+ union ol_segval s;
+ enum ol_seg_type t;
+
+ /*
+ * For a section: subsection index
+ * For a metasymbol: virtual segment index
+ * For an absolute symbol: absolute value
+ */
+ uint32_t index;
+};
+
+/* seg:offs representing the full location value and type */
+struct ol_loc {
+ int64_t offs;
+ struct ol_seg seg;
+};
+
+/* Common symbol structure */
+struct ol_sym {
+ uint32_t flags; /* Section/symbol flags */
+ uint32_t size; /* Size value (for backend) */
+ struct ol_sym *next; /* Next symbol in declared order */
+ const char *name; /* Symbol name */
+ struct ol_symlist syml; /* Section-local symbol list */
+ struct ol_symlist symg; /* Section-local global symbol list */
+ struct ol_loc p; /* Symbol position ("where") */
+ struct ol_loc v; /* Symbol value ("what") */
+};
+
+/*
+ * Operations
+ */
+void ol_init(void);
+void ol_cleanup(void);
+
+/* Convert offs:seg to a location structure */
+extern void
+ol_mkloc(struct ol_loc *loc, int64_t offs, int32_t seg);
+
+/* Get the section or external symbol from a struct ol_seg */
+static inline O_Section *seg_sect(struct ol_seg *seg)
+{
+ return (O_Section *)seg->s.sect;
+}
+static inline O_Symbol *seg_xsym(struct ol_seg *seg)
+{
+ return (O_Symbol *)seg->s.sym;
+}
+
+/*
+ * Return a pointer to the symbol structure if and only if a section is
+ * really a symbol of some kind (extern, common...)
+ */
+static inline struct ol_sym *_seg_extsym(struct ol_sect *sect)
+{
+ return (sect->flags & OF_SYMBOL) ? (struct ol_sym *)sect : NULL;
+}
+static inline O_Symbol *seg_extsym(O_Section *sect)
+{
+ return (O_Symbol *)_seg_extsym((struct ol_sect *)sect);
+}
+
+/*
+ * Find a section or create a new section structure if it does not exist
+ * and allocate it an index value via seg_alloc().
+ */
+extern struct ol_sect *
+_ol_get_sect(const char *name, size_t ssize, size_t rsize);
+static inline O_Section *ol_get_sect(const char *name)
+{
+ return (O_Section *)_ol_get_sect(name, sizeof(O_Section), sizeof(O_Reloc));
+}
+
+/* Find a section by name without creating one */
+extern struct ol_sect *_ol_sect_by_name(const char *);
+static inline O_Section *ol_sect_by_name(const char *name)
+{
+ return (O_Section *)_ol_sect_by_name(name);
+}
+
+/* Find a section or external symbol by index; NULL if not valid */
+extern struct ol_sect *_ol_sect_by_index(int32_t index);
+static inline O_Section *ol_sect_by_index(int32_t index)
+{
+ return (O_Section *)_ol_sect_by_index(index);
+}
+
+/* Global list of sections (not including external symbols) */
+extern struct ol_sect *_ol_sect_list;
+static inline O_Section *ol_sect_list(void)
+{
+ return (O_Section *)_ol_sect_list;
+}
+
+/* Count of sections (not including external symbols) */
+extern uint64_t _ol_nsects;
+static inline uint64_t ol_nsects(void)
+{
+ return _ol_nsects;
+}
+
+/*
+ * Start a new subsection for the given section. At the moment, once a
+ * subsection has been created, it is not possible to revert to an
+ * earlier subsection. ol_sect_by_index() will return the main section
+ * structure. Returns the new section index. This is used to prevent
+ * the front end from optimizing across subsection boundaries.
+ */
+extern int32_t _ol_new_subsection(struct ol_sect *sect);
+static inline int32_t ol_new_subsection(O_Section *sect)
+{
+ return _ol_new_subsection((struct ol_sect *)sect);
+}
+
+/*
+ * Create a new symbol. If this symbol is OS_OFFS, add it to the relevant
+ * section, too. If the symbol already exists, return NULL; this is
+ * different from ol_get_section() as a single section may be invoked
+ * many times. On the contrary, the front end will prevent a single symbol
+ * from being defined more than once.
+ *
+ * If flags has OF_GLOBAL set, add it to the global symbol hash for the
+ * containing section. If flags has OF_IMPSEC set, allocate a segment
+ * index for it via seg_alloc() and add it to the section by index list.
+ */
+extern struct ol_sym *_ol_new_sym(const char *name, const struct ol_loc *v,
+ uint32_t flags, size_t size);
+static inline O_Symbol *ol_new_sym(const char *name, const struct ol_loc *v,
+ uint32_t flags)
+{
+ return (O_Symbol *)_ol_new_sym(name, v, flags, sizeof(O_Symbol));
+}
+
+/* Find a symbol by name in the global namespace */
+extern struct ol_sym *_ol_sym_by_name(const char *name);
+static inline O_Symbol *ol_sym_by_name(const char *name)
+{
+ return (O_Symbol *)_ol_sym_by_name(name);
+}
+
+/*
+ * Find a symbol by address in a specific section. If no symbol is defined
+ * at that exact address, return the immediately previously defined one.
+ * If global is set, then only return global symbols.
+ */
+extern struct ol_sym *_ol_sym_by_address(struct ol_sect *sect, int64_t addr,
+ bool global);
+static inline O_Symbol *ol_sym_by_address(O_Section *sect, int64_t addr,
+ bool global)
+{
+ return (O_Symbol *)_ol_sym_by_address((struct ol_sect *)sect, addr, global);
+}
+
+/* Global list of symbols */
+extern struct ol_sym *_ol_sym_list;
+static inline O_Symbol *ol_sym_list(void)
+{
+ return (O_Symbol *)_ol_sym_list;
+}
+
+/* Global count of symbols */
+extern uint64_t _ol_nsyms;
+static inline uint64_t ol_nsyms(void)
+{
+ return _ol_nsyms;
+}
+
+#endif /* NASM_OUTLIB_H */
diff --git a/vere/ext/nasm/output/outmacho.c b/vere/ext/nasm/output/outmacho.c
new file mode 100644
index 0000000..1e776f5
--- /dev/null
+++ b/vere/ext/nasm/output/outmacho.c
@@ -0,0 +1,2411 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outmacho.c output routines for the Netwide Assembler to produce
+ * NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
+ */
+
+#include "compiler.h"
+
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "ilog2.h"
+#include "labels.h"
+#include "error.h"
+#include "saa.h"
+#include "raa.h"
+#include "rbtree.h"
+#include "hashtbl.h"
+#include "outform.h"
+#include "outlib.h"
+#include "ver.h"
+#include "dwarf.h"
+#include "macho.h"
+
+#if defined(OF_MACHO) || defined(OF_MACHO64)
+
+/* Mach-O in-file header structure sizes */
+#define MACHO_HEADER_SIZE 28
+#define MACHO_SEGCMD_SIZE 56
+#define MACHO_SECTCMD_SIZE 68
+#define MACHO_SYMCMD_SIZE 24
+#define MACHO_NLIST_SIZE 12
+#define MACHO_RELINFO_SIZE 8
+
+#define MACHO_HEADER64_SIZE 32
+#define MACHO_SEGCMD64_SIZE 72
+#define MACHO_SECTCMD64_SIZE 80
+#define MACHO_NLIST64_SIZE 16
+
+/* Mach-O relocations numbers */
+
+#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+#define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
+
+/* Our internal relocation types */
+enum reltype {
+ RL_ABS, /* Absolute relocation */
+ RL_REL, /* Relative relocation */
+ RL_TLV, /* Thread local */
+ RL_BRANCH, /* Relative direct branch */
+ RL_SUB, /* X86_64_RELOC_SUBTRACT */
+ RL_GOT, /* X86_64_RELOC_GOT */
+ RL_GOTLOAD /* X86_64_RELOC_GOT_LOAD */
+};
+#define RL_MAX_32 RL_TLV
+#define RL_MAX_64 RL_GOTLOAD
+
+struct macho_fmt {
+ uint32_t ptrsize; /* Pointer size in bytes */
+ uint32_t mh_magic; /* Which magic number to use */
+ uint32_t cpu_type; /* Which CPU type */
+ uint32_t lc_segment; /* Which segment load command */
+ uint32_t header_size; /* Header size */
+ uint32_t segcmd_size; /* Segment command size */
+ uint32_t sectcmd_size; /* Section command size */
+ uint32_t nlist_size; /* Nlist (symbol) size */
+ enum reltype maxreltype; /* Maximum entry in enum reltype permitted */
+ uint32_t reloc_abs; /* Absolute relocation type */
+ uint32_t reloc_rel; /* Relative relocation type */
+ uint32_t reloc_tlv; /* Thread local relocation type */
+ bool forcesym; /* Always use "external" (symbol-relative) relocations */
+};
+
+static struct macho_fmt fmt;
+
+static void fwriteptr(uint64_t data, FILE * fp)
+{
+ fwriteaddr(data, fmt.ptrsize, fp);
+}
+
+struct section {
+ /* nasm internal data */
+ struct section *next;
+ struct SAA *data;
+ int32_t index; /* Main section index */
+ int32_t subsection; /* Current subsection index */
+ int32_t fileindex;
+ struct reloc *relocs;
+ struct rbtree *syms[2]; /* All/global symbols symbols in section */
+ int align;
+ bool by_name; /* This section was specified by full MachO name */
+ char namestr[34]; /* segment,section as a C string */
+
+ /* data that goes into the file */
+ char sectname[16]; /* what this section is called */
+ char segname[16]; /* segment this section will be in */
+ uint64_t addr; /* in-memory address (subject to alignment) */
+ uint64_t size; /* in-memory and -file size */
+ uint64_t offset; /* in-file offset */
+ uint32_t pad; /* padding bytes before section */
+ uint32_t nreloc; /* relocation entry count */
+ uint32_t flags; /* type and attributes (masked) */
+ uint32_t extreloc; /* external relocations */
+};
+
+#define S_NASM_TYPE_MASK 0x800004ff /* we consider these bits "section type" */
+
+/* fake section for absolute symbols, *not* part of the section linked list */
+static struct section absolute_sect;
+
+struct reloc {
+ /* nasm internal data */
+ struct reloc *next;
+
+ /* data that goes into the file */
+ int32_t addr; /* op's offset in section */
+ uint32_t snum:24, /* contains symbol index if
+ ** ext otherwise in-file
+ ** section number */
+ pcrel:1, /* relative relocation */
+ length:2, /* 0=byte, 1=word, 2=int32_t, 3=int64_t */
+ ext:1, /* external symbol referenced */
+ type:4; /* reloc type */
+};
+
+struct symbol {
+ /* nasm internal data */
+ struct rbtree symv[2]; /* All/global symbol rbtrees; "key" contains the
+ symbol offset. */
+ struct symbol *next; /* next symbol in the list */
+ char *name; /* name of this symbol */
+ int32_t initial_snum; /* symbol number used above in reloc */
+ int32_t snum; /* true snum for reloc */
+
+ /* data that goes into the file */
+ uint32_t strx; /* string table index */
+ uint8_t type; /* symbol type */
+ uint8_t sect; /* NO_SECT or section number */
+ uint16_t desc; /* for stab debugging, 0 for us */
+};
+
+#define DEFAULT_SECTION_ALIGNMENT 0 /* byte (i.e. no) alignment */
+
+static struct section *sects, **sectstail, **sectstab;
+static struct symbol *syms, **symstail;
+static uint32_t nsyms;
+
+/* These variables are set by macho_layout_symbols() to organize
+ the symbol table and string table in order the dynamic linker
+ expects. They are then used in macho_write() to put out the
+ symbols and strings in that order.
+
+ The order of the symbol table is:
+ local symbols
+ defined external symbols (sorted by name)
+ undefined external symbols (sorted by name)
+
+ The order of the string table is:
+ strings for external symbols
+ strings for local symbols
+ */
+static uint32_t ilocalsym = 0;
+static uint32_t iextdefsym = 0;
+static uint32_t iundefsym = 0;
+static uint32_t nlocalsym;
+static uint32_t nextdefsym;
+static uint32_t nundefsym;
+static struct symbol **extdefsyms = NULL;
+static struct symbol **undefsyms = NULL;
+
+static struct RAA *extsyms;
+static struct SAA *strs;
+static uint32_t strslen;
+
+/* Global file information. This should be cleaned up into either
+ a structure or as function arguments. */
+static uint32_t head_ncmds = 0;
+static uint32_t head_sizeofcmds = 0;
+static uint32_t head_flags = 0;
+static uint64_t seg_filesize = 0;
+static uint64_t seg_vmsize = 0;
+static uint32_t seg_nsects = 0;
+static uint64_t rel_padcnt = 0;
+
+/*
+ * Functions for handling fixed-length zero-padded string
+ * fields, that may or may not be null-terminated.
+ */
+
+/* Copy a string into a zero-padded fixed-length field */
+#define xstrncpy(xdst, xsrc) strncpy(xdst, xsrc, sizeof(xdst))
+
+/* Compare a fixed-length field with a string */
+#define xstrncmp(xdst, xsrc) strncmp(xdst, xsrc, sizeof(xdst))
+
+#define alignint32_t(x) \
+ ALIGN(x, sizeof(int32_t)) /* align x to int32_t boundary */
+
+#define alignint64_t(x) \
+ ALIGN(x, sizeof(int64_t)) /* align x to int64_t boundary */
+
+#define alignptr(x) \
+ ALIGN(x, fmt.ptrsize) /* align x to output format width */
+
+static struct hash_table section_by_name;
+static struct RAA *section_by_index;
+
+static struct section * never_null
+find_or_add_section(const char *segname, const char *sectname)
+{
+ struct hash_insert hi;
+ void **sp;
+ struct section *s;
+ char sect[34];
+
+ snprintf(sect, sizeof sect, "%-16s,%-16s", segname, sectname);
+
+ sp = hash_find(&section_by_name, sect, &hi);
+ if (sp)
+ return (struct section *)(*sp);
+
+ s = nasm_zalloc(sizeof *s);
+ xstrncpy(s->segname, segname);
+ xstrncpy(s->sectname, sectname);
+ xstrncpy(s->namestr, sect);
+ hash_add(&hi, s->namestr, s);
+
+ s->index = s->subsection = seg_alloc();
+ section_by_index = raa_write_ptr(section_by_index, s->index >> 1, s);
+
+ return s;
+}
+
+static inline bool is_new_section(const struct section *s)
+{
+ return !s->data;
+}
+
+static struct section *get_section_by_name(const char *segname,
+ const char *sectname)
+{
+ char sect[34];
+ void **sp;
+
+ snprintf(sect, sizeof sect, "%-16s,%-16s", segname, sectname);
+
+ sp = hash_find(&section_by_name, sect, NULL);
+ return sp ? (struct section *)(*sp) : NULL;
+}
+
+static struct section *get_section_by_index(int32_t index)
+{
+ if (index < 0 || index >= SEG_ABS || (index & 1))
+ return NULL;
+
+ return raa_read_ptr(section_by_index, index >> 1);
+}
+
+struct dir_list {
+ struct dir_list *next;
+ struct dir_list *last;
+ const char *dir_name;
+ uint32_t dir;
+};
+
+struct file_list {
+ struct file_list *next;
+ struct file_list *last;
+ const char *file_name;
+ uint32_t file;
+ struct dir_list *dir;
+};
+
+struct dw_sect_list {
+ struct SAA *psaa;
+ int32_t section;
+ uint32_t line;
+ uint64_t offset;
+ uint32_t file;
+ struct dw_sect_list *next;
+ struct dw_sect_list *last;
+};
+
+struct section_info {
+ uint64_t size;
+ int32_t secto;
+};
+
+#define DW_LN_BASE (-5)
+#define DW_LN_RANGE 14
+#define DW_OPCODE_BASE 13
+#define DW_MAX_LN (DW_LN_BASE + DW_LN_RANGE)
+#define DW_MAX_SP_OPCODE 256
+
+static struct file_list *dw_head_file = 0, *dw_cur_file = 0, **dw_last_file_next = NULL;
+static struct dir_list *dw_head_dir = 0, **dw_last_dir_next = NULL;
+static struct dw_sect_list *dw_head_sect = 0, *dw_cur_sect = 0, *dw_last_sect = 0;
+static uint32_t cur_line = 0, dw_num_files = 0, dw_num_dirs = 0, dw_num_sects = 0;
+static bool dbg_immcall = false;
+static const char *module_name = NULL;
+
+/*
+ * Special section numbers which are used to define Mach-O special
+ * symbols, which can be used with WRT to provide PIC relocation
+ * types.
+ */
+static int32_t macho_tlvp_sect;
+static int32_t macho_gotpcrel_sect;
+
+static void macho_init(void)
+{
+ module_name = inname;
+ sects = NULL;
+ sectstail = &sects;
+
+ /* Fake section for absolute symbols */
+ absolute_sect.index = NO_SEG;
+
+ syms = NULL;
+ symstail = &syms;
+ nsyms = 0;
+ nlocalsym = 0;
+ nextdefsym = 0;
+ nundefsym = 0;
+
+ extsyms = raa_init();
+ strs = saa_init(1L);
+
+ section_by_index = raa_init();
+
+ /* string table starts with a zero byte so index 0 is an empty string */
+ saa_wbytes(strs, zero_buffer, 1);
+ strslen = 1;
+
+ /* add special symbol for TLVP */
+ macho_tlvp_sect = seg_alloc() + 1;
+ backend_label("..tlvp", macho_tlvp_sect, 0L);
+}
+
+static void sect_write(struct section *sect,
+ const uint8_t *data, uint32_t len)
+{
+ saa_wbytes(sect->data, data, len);
+ sect->size += len;
+}
+
+/*
+ * Find a suitable global symbol for a ..gotpcrel or ..tlvp reference
+ */
+static struct symbol *macho_find_sym(struct section *s, uint64_t offset,
+ bool global, bool exact)
+{
+ struct rbtree *srb;
+
+ srb = rb_search(s->syms[global], offset);
+
+ if (!srb || (exact && srb->key != offset)) {
+ nasm_error(ERR_NONFATAL, "unable to find a suitable%s%s symbol"
+ " for this reference",
+ global ? " global" : "",
+ s == &absolute_sect ? " absolute " : "");
+ return NULL;
+ }
+
+ return container_of(srb - global, struct symbol, symv);
+}
+
+static int64_t add_reloc(struct section *sect, int32_t section,
+ int64_t offset,
+ enum reltype reltype, int bytes)
+{
+ struct reloc *r;
+ struct section *s;
+ int32_t fi;
+ int64_t adjust;
+
+ /* Double check this is a valid relocation type for this platform */
+ nasm_assert(reltype <= fmt.maxreltype);
+
+ /* the current end of the section will be the symbol's address for
+ ** now, might have to be fixed by macho_fixup_relocs() later on. make
+ ** sure we don't make the symbol scattered by setting the highest
+ ** bit by accident */
+ r = nasm_malloc(sizeof(struct reloc));
+ r->addr = sect->size & ~R_SCATTERED;
+ r->ext = 1;
+ adjust = 0;
+
+ /* match byte count 1, 2, 4, 8 to length codes 0, 1, 2, 3 respectively */
+ r->length = ilog2_32(bytes);
+
+ /* set default relocation values */
+ r->type = fmt.reloc_abs;
+ r->pcrel = 0;
+ r->snum = R_ABS;
+
+ s = get_section_by_index(section);
+ fi = s ? s->fileindex : NO_SECT;
+
+ /* absolute relocation */
+ switch (reltype) {
+ case RL_ABS:
+ if (section == NO_SEG) {
+ /* absolute (can this even happen?) */
+ r->ext = 0;
+ } else if (fi == NO_SECT) {
+ /* external */
+ r->snum = raa_read(extsyms, section);
+ } else {
+ /* local */
+ r->ext = 0;
+ r->snum = fi;
+ }
+ break;
+
+ case RL_REL:
+ case RL_BRANCH:
+ r->type = fmt.reloc_rel;
+ r->pcrel = 1;
+ if (section == NO_SEG) {
+ /* may optionally be converted below by fmt.forcesym */
+ r->ext = 0;
+ } else if (fi == NO_SECT) {
+ /* external */
+ sect->extreloc = 1;
+ r->snum = raa_read(extsyms, section);
+ if (reltype == RL_BRANCH)
+ r->type = X86_64_RELOC_BRANCH;
+ } else {
+ /* local */
+ r->ext = 0;
+ r->snum = fi;
+ if (reltype == RL_BRANCH)
+ r->type = X86_64_RELOC_BRANCH;
+ }
+ break;
+
+ case RL_SUB: /* obsolete */
+ nasm_warn(WARN_OTHER, "relcation with subtraction"
+ "becomes to be obsolete");
+ r->ext = 0;
+ r->type = X86_64_RELOC_SUBTRACTOR;
+ break;
+
+ case RL_GOT:
+ r->type = X86_64_RELOC_GOT;
+ goto needsym;
+
+ case RL_GOTLOAD:
+ r->type = X86_64_RELOC_GOT_LOAD;
+ goto needsym;
+
+ case RL_TLV:
+ r->type = fmt.reloc_tlv;
+ goto needsym;
+
+ needsym:
+ r->pcrel = (fmt.ptrsize == 8 ? 1 : 0);
+ if (section == NO_SEG) {
+ nasm_error(ERR_NONFATAL, "Unsupported use of use of WRT");
+ goto bail;
+ } else if (fi == NO_SECT) {
+ /* external */
+ r->snum = raa_read(extsyms, section);
+ } else {
+ /* internal - GOTPCREL doesn't need to be in global */
+ struct symbol *sym = macho_find_sym(s, offset,
+ false, /* reltype != RL_TLV */
+ true);
+ if (!sym) {
+ nasm_error(ERR_NONFATAL, "Symbol for WRT not found");
+ goto bail;
+ }
+
+ adjust -= sym->symv[0].key;
+ r->snum = sym->initial_snum;
+ }
+ break;
+ }
+
+ /*
+ * For 64-bit Mach-O, force a symbol reference if at all possible
+ * Allow for r->snum == R_ABS by searching absolute_sect
+ */
+ if (!r->ext && fmt.forcesym) {
+ struct symbol *sym = macho_find_sym(s ? s : &absolute_sect,
+ offset, false, false);
+ if (sym) {
+ adjust -= sym->symv[0].key;
+ r->snum = sym->initial_snum;
+ r->ext = 1;
+ }
+ }
+
+ if (r->pcrel)
+ adjust += ((r->ext && fmt.ptrsize == 8) ? bytes : -(int64_t)sect->size);
+
+ /* NeXT as puts relocs in reversed order (address-wise) into the
+ ** files, so we do the same, doesn't seem to make much of a
+ ** difference either way */
+ r->next = sect->relocs;
+ sect->relocs = r;
+ if (r->ext)
+ sect->extreloc = 1;
+ ++sect->nreloc;
+
+ return adjust;
+
+ bail:
+ nasm_free(r);
+ return 0;
+}
+
+static void macho_output(int32_t secto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t section, int32_t wrt)
+{
+ struct section *s;
+ int64_t addr, offset;
+ uint8_t mydata[16], *p;
+ bool is_bss;
+ enum reltype reltype;
+
+ s = get_section_by_index(secto);
+ if (!s) {
+ nasm_warn(WARN_OTHER, "attempt to assemble code in"
+ " section %d: defaulting to `.text'", secto);
+ s = get_section_by_name("__TEXT", "__text");
+
+ /* should never happen */
+ if (!s)
+ nasm_panic("text section not found");
+ }
+
+ /* debug code generation only for sections tagged with
+ * instruction attribute */
+ if (s->flags & S_ATTR_SOME_INSTRUCTIONS)
+ {
+ struct section_info sinfo;
+ sinfo.size = s->size;
+ sinfo.secto = secto;
+ dfmt->debug_output(0, &sinfo);
+ }
+
+ is_bss = (s->flags & SECTION_TYPE) == S_ZEROFILL;
+
+ if (is_bss && type != OUT_RESERVE) {
+ nasm_warn(WARN_OTHER, "attempt to initialize memory in "
+ "BSS section: ignored");
+ /* FIXME */
+ nasm_warn(WARN_OTHER, "section size may be negative"
+ "with address symbols");
+ s->size += realsize(type, size);
+ return;
+ }
+
+ memset(mydata, 0, sizeof(mydata));
+
+ switch (type) {
+ case OUT_RESERVE:
+ if (!is_bss) {
+ nasm_warn(WARN_ZEROING, "uninitialized space declared in"
+ " %s,%s section: zeroing", s->segname, s->sectname);
+
+ sect_write(s, NULL, size);
+ } else
+ s->size += size;
+
+ break;
+
+ case OUT_RAWDATA:
+ sect_write(s, data, size);
+ break;
+
+ case OUT_ADDRESS:
+ {
+ int asize = abs((int)size);
+
+ addr = *(int64_t *)data;
+ if (section != NO_SEG) {
+ if (section % 2) {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " section base references");
+ } else if (wrt == NO_SEG) {
+ if (fmt.ptrsize == 8 && asize != 8) {
+ nasm_error(ERR_NONFATAL,
+ "Mach-O 64-bit format does not support"
+ " 32-bit absolute addresses");
+ } else {
+ addr += add_reloc(s, section, addr, RL_ABS, asize);
+ }
+ } else if (wrt == macho_tlvp_sect && fmt.ptrsize != 8 &&
+ asize == (int) fmt.ptrsize) {
+ addr += add_reloc(s, section, addr, RL_TLV, asize);
+ } else {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " this use of WRT");
+ }
+ }
+
+ p = mydata;
+ WRITEADDR(p, addr, asize);
+ sect_write(s, mydata, asize);
+ break;
+ }
+
+ case OUT_REL1ADR:
+ case OUT_REL2ADR:
+
+ p = mydata;
+ offset = *(int64_t *)data;
+ addr = offset - size;
+
+ if (section != NO_SEG && section % 2) {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " section base references");
+ } else if (fmt.ptrsize == 8) {
+ nasm_error(ERR_NONFATAL, "Unsupported non-32-bit"
+ " Macho-O relocation [2]");
+ } else if (wrt != NO_SEG) {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " this use of WRT");
+ wrt = NO_SEG; /* we can at least _try_ to continue */
+ } else {
+ addr += add_reloc(s, section, addr+size, RL_REL,
+ type == OUT_REL1ADR ? 1 : 2);
+ }
+
+ WRITESHORT(p, addr);
+ sect_write(s, mydata, type == OUT_REL1ADR ? 1 : 2);
+ break;
+
+ case OUT_REL4ADR:
+ case OUT_REL8ADR:
+
+ p = mydata;
+ offset = *(int64_t *)data;
+ addr = offset - size;
+ reltype = RL_REL;
+
+ if (section != NO_SEG && section % 2) {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " section base references");
+ } else if (wrt == NO_SEG) {
+ if (fmt.ptrsize == 8 &&
+ (s->flags & S_ATTR_SOME_INSTRUCTIONS)) {
+ uint8_t opcode[2];
+
+ opcode[0] = opcode[1] = 0;
+
+ /* HACK: Retrieve instruction opcode */
+ if (likely(s->data->datalen >= 2)) {
+ saa_fread(s->data, s->data->datalen-2, opcode, 2);
+ } else if (s->data->datalen == 1) {
+ saa_fread(s->data, 0, opcode+1, 1);
+ }
+
+ if ((opcode[0] != 0x0f && (opcode[1] & 0xfe) == 0xe8) ||
+ (opcode[0] == 0x0f && (opcode[1] & 0xf0) == 0x80)) {
+ /* Direct call, jmp, or jcc */
+ reltype = RL_BRANCH;
+ }
+ }
+ } else if (wrt == macho_gotpcrel_sect) {
+ reltype = RL_GOT;
+
+ if ((s->flags & S_ATTR_SOME_INSTRUCTIONS) &&
+ s->data->datalen >= 3) {
+ uint8_t gotload[3];
+
+ /* HACK: Retrieve instruction opcode */
+ saa_fread(s->data, s->data->datalen-3, gotload, 3);
+ if ((gotload[0] & 0xf8) == 0x48 &&
+ gotload[1] == 0x8b &&
+ (gotload[2] & 0307) == 0005) {
+ /* movq <reg>,[rel sym wrt ..gotpcrel] */
+ reltype = RL_GOTLOAD;
+ }
+ }
+ } else if (wrt == macho_tlvp_sect && fmt.ptrsize == 8) {
+ reltype = RL_TLV;
+ } else {
+ nasm_error(ERR_NONFATAL, "Mach-O format does not support"
+ " this use of WRT");
+ /* continue with RL_REL */
+ }
+
+ addr += add_reloc(s, section, offset, reltype,
+ type == OUT_REL4ADR ? 4 : 8);
+ WRITELONG(p, addr);
+ sect_write(s, mydata, type == OUT_REL4ADR ? 4 : 8);
+ break;
+
+ default:
+ nasm_error(ERR_NONFATAL, "Unrepresentable relocation in Mach-O");
+ break;
+ }
+}
+
+#define S_CODE (S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS)
+#define NO_TYPE S_NASM_TYPE_MASK
+
+/* Translation table from traditional Unix section names to Mach-O */
+static const struct macho_known_section {
+ const char *nasmsect;
+ const char *segname;
+ const char *sectname;
+ const uint32_t flags;
+} known_sections[] = {
+ { ".text", "__TEXT", "__text", S_CODE },
+ { ".data", "__DATA", "__data", S_REGULAR },
+ { ".rodata", "__DATA", "__const", S_REGULAR },
+ { ".bss", "__DATA", "__bss", S_ZEROFILL },
+ { ".debug_abbrev", "__DWARF", "__debug_abbrev", S_ATTR_DEBUG },
+ { ".debug_info", "__DWARF", "__debug_info", S_ATTR_DEBUG },
+ { ".debug_line", "__DWARF", "__debug_line", S_ATTR_DEBUG },
+ { ".debug_str", "__DWARF", "__debug_str", S_ATTR_DEBUG },
+};
+
+/* Section type or attribute directives */
+static const struct macho_known_section_attr {
+ const char *name;
+ uint32_t flags;
+} sect_attribs[] = {
+ { "data", S_REGULAR },
+ { "code", S_CODE },
+ { "mixed", S_REGULAR | S_ATTR_SOME_INSTRUCTIONS },
+ { "bss", S_ZEROFILL },
+ { "zerofill", S_ZEROFILL },
+ { "no_dead_strip", NO_TYPE | S_ATTR_NO_DEAD_STRIP },
+ { "live_support", NO_TYPE | S_ATTR_LIVE_SUPPORT },
+ { "strip_static_syms", NO_TYPE | S_ATTR_STRIP_STATIC_SYMS },
+ { "debug", NO_TYPE | S_ATTR_DEBUG },
+ { NULL, 0 }
+};
+
+static const struct macho_known_section *
+lookup_known_section(const char *name, bool by_sectname)
+{
+ size_t i;
+
+ if (name && name[0]) {
+ for (i = 0; i < ARRAY_SIZE(known_sections); i++) {
+ const char *p = by_sectname ?
+ known_sections[i].sectname :
+ known_sections[i].nasmsect;
+ if (!strcmp(name, p))
+ return &known_sections[i];
+ }
+ }
+
+ return NULL;
+}
+
+static int32_t macho_section(char *name, int *bits)
+{
+ const struct macho_known_section *known_section;
+ const struct macho_known_section_attr *sa;
+ char *sectionAttributes;
+ struct section *s;
+ const char *section, *segment;
+ uint32_t flags;
+ char *currentAttribute;
+ char *comma;
+
+ bool new_seg;
+
+ /* Default to the appropriate number of bits. */
+ if (!name) {
+ *bits = fmt.ptrsize << 3;
+ name = ".text";
+ sectionAttributes = NULL;
+ } else {
+ sectionAttributes = name;
+ name = nasm_strsep(&sectionAttributes, " \t");
+ }
+
+ section = segment = NULL;
+ flags = 0;
+
+ comma = strchr(name, ',');
+ if (comma) {
+ int len;
+
+ *comma = '\0';
+ segment = name;
+ section = comma+1;
+
+ len = strlen(segment);
+ if (len == 0) {
+ nasm_error(ERR_NONFATAL, "empty segment name\n");
+ } else if (len > 16) {
+ nasm_error(ERR_NONFATAL, "segment name %s too long\n", segment);
+ }
+
+ len = strlen(section);
+ if (len == 0) {
+ nasm_error(ERR_NONFATAL, "empty section name\n");
+ } else if (len > 16) {
+ nasm_error(ERR_NONFATAL, "section name %s too long\n", section);
+ }
+
+ known_section = lookup_known_section(section, true);
+ if (known_section)
+ flags = known_section->flags;
+ else
+ flags = S_REGULAR;
+ } else {
+ known_section = lookup_known_section(name, false);
+ if (!known_section) {
+ nasm_error(ERR_NONFATAL, "unknown section name %s\n", name);
+ return NO_SEG;
+ }
+
+ segment = known_section->segname;
+ section = known_section->sectname;
+ flags = known_section->flags;
+ }
+
+ /* try to find section with that name, or create it */
+ s = find_or_add_section(segment, section);
+ new_seg = is_new_section(s);
+
+ /* initialize it if it is a brand new section */
+ if (new_seg) {
+ *sectstail = s;
+ sectstail = &s->next;
+
+ s->data = saa_init(1L);
+ s->fileindex = ++seg_nsects;
+ s->align = -1;
+ s->pad = -1;
+ s->offset = -1;
+ s->by_name = false;
+
+ s->size = 0;
+ s->nreloc = 0;
+ s->flags = flags;
+ }
+
+ if (comma)
+ *comma = ','; /* Restore comma */
+
+ s->by_name = s->by_name || comma; /* Was specified by name */
+
+ flags = NO_TYPE;
+
+ while (sectionAttributes &&
+ (currentAttribute = nasm_strsep(&sectionAttributes, " \t"))) {
+ if (!*currentAttribute)
+ continue;
+
+ if (!nasm_strnicmp("align=", currentAttribute, 6)) {
+ char *end;
+ int newAlignment, value;
+
+ value = strtoul(currentAttribute + 6, (char**)&end, 0);
+ newAlignment = alignlog2_32(value);
+
+ if (0 != *end) {
+ nasm_error(ERR_NONFATAL,
+ "unknown or missing alignment value \"%s\" "
+ "specified for section \"%s\"",
+ currentAttribute + 6,
+ name);
+ } else if (0 > newAlignment) {
+ nasm_error(ERR_NONFATAL,
+ "alignment of %d (for section \"%s\") is not "
+ "a power of two",
+ value,
+ name);
+ }
+
+ if (s->align < newAlignment)
+ s->align = newAlignment;
+ } else {
+ for (sa = sect_attribs; sa->name; sa++) {
+ if (!nasm_stricmp(sa->name, currentAttribute)) {
+ if ((sa->flags & S_NASM_TYPE_MASK) != NO_TYPE) {
+ flags = (flags & ~S_NASM_TYPE_MASK)
+ | (sa->flags & S_NASM_TYPE_MASK);
+ }
+ flags |= sa->flags & ~S_NASM_TYPE_MASK;
+ break;
+ }
+ }
+
+ if (!sa->name) {
+ nasm_error(ERR_NONFATAL,
+ "unknown section attribute %s for section %s",
+ currentAttribute, name);
+ }
+ }
+ }
+
+ if ((flags & S_NASM_TYPE_MASK) != NO_TYPE) {
+ if (!new_seg && ((s->flags ^ flags) & S_NASM_TYPE_MASK)) {
+ nasm_error(ERR_NONFATAL,
+ "inconsistent section attributes for section %s\n",
+ name);
+ } else {
+ s->flags = (s->flags & ~S_NASM_TYPE_MASK) | flags;
+ }
+ } else {
+ s->flags |= flags & ~S_NASM_TYPE_MASK;
+ }
+
+ return s->subsection;
+}
+
+static int32_t macho_herelabel(const char *name, enum label_type type,
+ int32_t section, int32_t *subsection,
+ bool *copyoffset)
+{
+ struct section *s;
+ int32_t subsec;
+ (void)name;
+
+ if (!(head_flags & MH_SUBSECTIONS_VIA_SYMBOLS))
+ return section;
+
+ /* No subsection only for local labels */
+ if (type == LBL_LOCAL)
+ return section;
+
+ s = get_section_by_index(section);
+ if (!s)
+ return section;
+
+ subsec = *subsection;
+ if (subsec == NO_SEG) {
+ /* Allocate a new subsection index */
+ subsec = *subsection = seg_alloc();
+ section_by_index = raa_write_ptr(section_by_index, subsec >> 1, s);
+ }
+
+ s->subsection = subsec;
+ *copyoffset = true; /* Maintain previous offset */
+ return subsec;
+}
+
+static void macho_symdef(char *name, int32_t section, int64_t offset,
+ int is_global, char *special)
+{
+ struct symbol *sym;
+ struct section *s;
+ bool special_used = false;
+
+#if defined(DEBUG) && DEBUG>2
+ nasm_error(ERR_DEBUG,
+ " macho_symdef: %s, pass=%"PRId64" type %s, sec=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n",
+ name, pass_count(), pass_types[pass_type()],
+ section, offset, is_global, special);
+#endif
+
+ if (is_global == 3) {
+ if (special) {
+ int n = strcspn(special, " \t");
+
+ if (!nasm_strnicmp(special, "private_extern", n)) {
+ for (sym = syms; sym != NULL; sym = sym->next) {
+ if (!strcmp(name, sym->name)) {
+ if (sym->type & N_PEXT)
+ return; /* nothing to be done */
+ else
+ break;
+ }
+ }
+ }
+ }
+ nasm_error(ERR_NONFATAL, "The Mach-O format does not "
+ "(yet) support forward reference fixups.");
+ return;
+ }
+
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ /*
+ * This is a NASM special symbol. We never allow it into
+ * the Macho-O symbol table, even if it's a valid one. If it
+ * _isn't_ a valid one, we should barf immediately.
+ */
+ if (strcmp(name, "..gotpcrel") && strcmp(name, "..tlvp"))
+ nasm_error(ERR_NONFATAL, "unrecognized special symbol `%s'", name);
+ return;
+ }
+
+ sym = *symstail = nasm_zalloc(sizeof(struct symbol));
+ sym->next = NULL;
+ symstail = &sym->next;
+
+ sym->name = name;
+ sym->strx = strslen;
+ sym->type = 0;
+ sym->desc = 0;
+ sym->symv[0].key = offset;
+ sym->symv[1].key = offset;
+ sym->initial_snum = -1;
+
+ /* external and common symbols get N_EXT */
+ if (is_global != 0) {
+ sym->type |= N_EXT;
+ }
+ if (is_global == 1) {
+ /* check special to see if the global symbol shall be marked as private external: N_PEXT */
+ if (special) {
+ int n = strcspn(special, " \t");
+
+ if (!nasm_strnicmp(special, "private_extern", n))
+ sym->type |= N_PEXT;
+ else
+ nasm_error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", n, special);
+ }
+ special_used = true;
+ }
+
+ /* track the initially allocated symbol number for use in future fix-ups */
+ sym->initial_snum = nsyms;
+
+ if (section == NO_SEG) {
+ /* symbols in no section get absolute */
+ sym->type |= N_ABS;
+ sym->sect = NO_SECT;
+
+ s = &absolute_sect;
+ } else {
+ s = get_section_by_index(section);
+
+ sym->type |= N_SECT;
+
+ /* get the in-file index of the section the symbol was defined in */
+ sym->sect = s ? s->fileindex : NO_SECT;
+
+ if (!s) {
+ /* remember symbol number of references to external
+ ** symbols, this works because every external symbol gets
+ ** its own section number allocated internally by nasm and
+ ** can so be used as a key */
+ extsyms = raa_write(extsyms, section, nsyms);
+
+ switch (is_global) {
+ case 1:
+ case 2:
+ /* there isn't actually a difference between global
+ ** and common symbols, both even have their size in
+ ** sym->symv[0].key */
+ sym->type = N_EXT;
+ break;
+
+ default:
+ /* give an error on unfound section if it's not an
+ ** external or common symbol (assemble_file() does a
+ ** seg_alloc() on every call for them) */
+ nasm_panic("in-file index for section %d not found, is_global = %d", section, is_global);
+ break;
+ }
+ }
+ }
+
+ if (s) {
+ s->syms[0] = rb_insert(s->syms[0], &sym->symv[0]);
+ if (is_global)
+ s->syms[1] = rb_insert(s->syms[1], &sym->symv[1]);
+ }
+
+ ++nsyms;
+
+ if (special && !special_used)
+ nasm_error(ERR_NONFATAL, "no special symbol features supported here");
+}
+
+static void macho_sectalign(int32_t seg, unsigned int value)
+{
+ struct section *s;
+ int align;
+
+ nasm_assert(!(seg & 1));
+
+ s = get_section_by_index(seg);
+
+ if (!s || !is_power2(value))
+ return;
+
+ align = alignlog2_32(value);
+ if (s->align < align)
+ s->align = align;
+}
+
+extern macros_t macho_stdmac[];
+
+/* Comparison function for qsort symbol layout. */
+static int layout_compare (const struct symbol **s1,
+ const struct symbol **s2)
+{
+ return (strcmp ((*s1)->name, (*s2)->name));
+}
+
+/* The native assembler does a few things in a similar function
+
+ * Remove temporary labels
+ * Sort symbols according to local, external, undefined (by name)
+ * Order the string table
+
+ We do not remove temporary labels right now.
+
+ numsyms is the total number of symbols we have. strtabsize is the
+ number entries in the string table. */
+
+static void macho_layout_symbols (uint32_t *numsyms,
+ uint32_t *strtabsize)
+{
+ struct symbol *sym, **symp;
+ uint32_t i,j;
+
+ *numsyms = 0;
+ *strtabsize = sizeof (char);
+
+ symp = &syms;
+
+ while ((sym = *symp)) {
+ /* Undefined symbols are now external. */
+ if (sym->type == N_UNDF)
+ sym->type |= N_EXT;
+
+ if ((sym->type & N_EXT) == 0) {
+ sym->snum = *numsyms;
+ *numsyms = *numsyms + 1;
+ nlocalsym++;
+ }
+ else {
+ if ((sym->type & N_TYPE) != N_UNDF) {
+ nextdefsym++;
+ } else {
+ nundefsym++;
+ }
+
+ /* If we handle debug info we'll want
+ to check for it here instead of just
+ adding the symbol to the string table. */
+ sym->strx = *strtabsize;
+ saa_wbytes (strs, sym->name, (int32_t)(strlen(sym->name) + 1));
+ *strtabsize += strlen(sym->name) + 1;
+ }
+ symp = &(sym->next);
+ }
+
+ /* Next, sort the symbols. Most of this code is a direct translation from
+ the Apple cctools symbol layout. We need to keep compatibility with that. */
+ /* Set the indexes for symbol groups into the symbol table */
+ ilocalsym = 0;
+ iextdefsym = nlocalsym;
+ iundefsym = nlocalsym + nextdefsym;
+
+ /* allocate arrays for sorting externals by name */
+ extdefsyms = nasm_malloc(nextdefsym * sizeof(struct symbol *));
+ undefsyms = nasm_malloc(nundefsym * sizeof(struct symbol *));
+
+ i = 0;
+ j = 0;
+
+ symp = &syms;
+
+ while ((sym = *symp)) {
+
+ if((sym->type & N_EXT) == 0) {
+ sym->strx = *strtabsize;
+ saa_wbytes (strs, sym->name, (int32_t)(strlen (sym->name) + 1));
+ *strtabsize += strlen(sym->name) + 1;
+ }
+ else {
+ if ((sym->type & N_TYPE) != N_UNDF) {
+ extdefsyms[i++] = sym;
+ } else {
+ undefsyms[j++] = sym;
+ }
+ }
+ symp = &(sym->next);
+ }
+
+ qsort(extdefsyms, nextdefsym, sizeof(struct symbol *),
+ (int (*)(const void *, const void *))layout_compare);
+ qsort(undefsyms, nundefsym, sizeof(struct symbol *),
+ (int (*)(const void *, const void *))layout_compare);
+
+ for(i = 0; i < nextdefsym; i++) {
+ extdefsyms[i]->snum = *numsyms;
+ *numsyms += 1;
+ }
+ for(j = 0; j < nundefsym; j++) {
+ undefsyms[j]->snum = *numsyms;
+ *numsyms += 1;
+ }
+}
+
+/* Calculate some values we'll need for writing later. */
+
+static void macho_calculate_sizes (void)
+{
+ struct section *s;
+ int fi;
+
+ /* count sections and calculate in-memory and in-file offsets */
+ for (s = sects; s != NULL; s = s->next) {
+ uint64_t newaddr;
+
+ /* recalculate segment address based on alignment and vm size */
+ s->addr = seg_vmsize;
+
+ /* we need section alignment to calculate final section address */
+ if (s->align == -1)
+ s->align = DEFAULT_SECTION_ALIGNMENT;
+
+ newaddr = ALIGN(s->addr, UINT64_C(1) << s->align);
+ s->addr = newaddr;
+
+ seg_vmsize = newaddr + s->size;
+
+ /* zerofill sections aren't actually written to the file */
+ if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
+ /*
+ * LLVM/Xcode as always aligns the section data to 4
+ * bytes; there is a comment in the LLVM source code that
+ * perhaps aligning to pointer size would be better.
+ */
+ s->pad = ALIGN(seg_filesize, 4) - seg_filesize;
+ s->offset = seg_filesize + s->pad;
+ seg_filesize += s->size + s->pad;
+
+ /* filesize and vmsize needs to be aligned */
+ seg_vmsize += s->pad;
+ }
+ }
+
+ /* calculate size of all headers, load commands and sections to
+ ** get a pointer to the start of all the raw data */
+ if (seg_nsects > 0) {
+ ++head_ncmds;
+ head_sizeofcmds += fmt.segcmd_size + seg_nsects * fmt.sectcmd_size;
+ }
+
+ if (nsyms > 0) {
+ ++head_ncmds;
+ head_sizeofcmds += MACHO_SYMCMD_SIZE;
+ }
+
+ if (seg_nsects > MAX_SECT) {
+ nasm_fatal("MachO output is limited to %d sections\n",
+ MAX_SECT);
+ }
+
+ /* Create a table of sections by file index to avoid linear search */
+ sectstab = nasm_malloc((seg_nsects + 1) * sizeof(*sectstab));
+ sectstab[NO_SECT] = &absolute_sect;
+ for (s = sects, fi = 1; s != NULL; s = s->next, fi++)
+ sectstab[fi] = s;
+}
+
+/* Write out the header information for the file. */
+
+static void macho_write_header (void)
+{
+ fwriteint32_t(fmt.mh_magic, ofile); /* magic */
+ fwriteint32_t(fmt.cpu_type, ofile); /* CPU type */
+ fwriteint32_t(CPU_SUBTYPE_I386_ALL, ofile); /* CPU subtype */
+ fwriteint32_t(MH_OBJECT, ofile); /* Mach-O file type */
+ fwriteint32_t(head_ncmds, ofile); /* number of load commands */
+ fwriteint32_t(head_sizeofcmds, ofile); /* size of load commands */
+ fwriteint32_t(head_flags, ofile); /* flags, if any */
+ fwritezero(fmt.header_size - 7*4, ofile); /* reserved fields */
+}
+
+/* Write out the segment load command at offset. */
+
+static uint32_t macho_write_segment (uint64_t offset)
+{
+ uint64_t rel_base = alignptr(offset + seg_filesize);
+ uint32_t s_reloff = 0;
+ struct section *s;
+
+ fwriteint32_t(fmt.lc_segment, ofile); /* cmd == LC_SEGMENT_64 */
+
+ /* size of load command including section load commands */
+ fwriteint32_t(fmt.segcmd_size + seg_nsects * fmt.sectcmd_size,
+ ofile);
+
+ /* in an MH_OBJECT file all sections are in one unnamed (name
+ ** all zeros) segment */
+ fwritezero(16, ofile);
+ fwriteptr(0, ofile); /* in-memory offset */
+ fwriteptr(seg_vmsize, ofile); /* in-memory size */
+ fwriteptr(offset, ofile); /* in-file offset to data */
+ fwriteptr(seg_filesize, ofile); /* in-file size */
+ fwriteint32_t(VM_PROT_DEFAULT, ofile); /* maximum vm protection */
+ fwriteint32_t(VM_PROT_DEFAULT, ofile); /* initial vm protection */
+ fwriteint32_t(seg_nsects, ofile); /* number of sections */
+ fwriteint32_t(0, ofile); /* no flags */
+
+ /* emit section headers */
+ for (s = sects; s != NULL; s = s->next) {
+ if (s->nreloc) {
+ nasm_assert((s->flags & SECTION_TYPE) != S_ZEROFILL);
+ s->flags |= S_ATTR_LOC_RELOC;
+ if (s->extreloc)
+ s->flags |= S_ATTR_EXT_RELOC;
+ } else if (!xstrncmp(s->segname, "__DATA") &&
+ !xstrncmp(s->sectname, "__const") &&
+ !s->by_name &&
+ !get_section_by_name("__TEXT", "__const")) {
+ /*
+ * The MachO equivalent to .rodata can be either
+ * __DATA,__const or __TEXT,__const; the latter only if
+ * there are no relocations. However, when mixed it is
+ * better to specify the segments explicitly.
+ */
+ xstrncpy(s->segname, "__TEXT");
+ }
+
+ nasm_write(s->sectname, sizeof(s->sectname), ofile);
+ nasm_write(s->segname, sizeof(s->segname), ofile);
+ fwriteptr(s->addr, ofile);
+ fwriteptr(s->size, ofile);
+
+ /* dummy data for zerofill sections or proper values */
+ if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
+ nasm_assert(s->pad != (uint32_t)-1);
+ offset += s->pad;
+ fwriteint32_t(offset, ofile);
+ offset += s->size;
+ /* Write out section alignment, as a power of two.
+ e.g. 32-bit word alignment would be 2 (2^2 = 4). */
+ fwriteint32_t(s->align, ofile);
+ /* To be compatible with cctools as we emit
+ a zero reloff if we have no relocations. */
+ fwriteint32_t(s->nreloc ? rel_base + s_reloff : 0, ofile);
+ fwriteint32_t(s->nreloc, ofile);
+
+ s_reloff += s->nreloc * MACHO_RELINFO_SIZE;
+ } else {
+ fwriteint32_t(0, ofile);
+ fwriteint32_t(s->align, ofile);
+ fwriteint32_t(0, ofile);
+ fwriteint32_t(0, ofile);
+ }
+
+ fwriteint32_t(s->flags, ofile); /* flags */
+ fwriteint32_t(0, ofile); /* reserved */
+ fwriteptr(0, ofile); /* reserved */
+ }
+
+ rel_padcnt = rel_base - offset;
+ offset = rel_base + s_reloff;
+
+ return offset;
+}
+
+/* For a given chain of relocs r, write out the entire relocation
+ chain to the object file. */
+
+static void macho_write_relocs (struct reloc *r)
+{
+ while (r) {
+ uint32_t word2;
+
+ fwriteint32_t(r->addr, ofile); /* reloc offset */
+
+ word2 = r->snum;
+ word2 |= r->pcrel << 24;
+ word2 |= r->length << 25;
+ word2 |= r->ext << 27;
+ word2 |= r->type << 28;
+ fwriteint32_t(word2, ofile); /* reloc data */
+ r = r->next;
+ }
+}
+
+/* Write out the section data. */
+static void macho_write_section (void)
+{
+ struct section *s;
+ struct reloc *r;
+ uint8_t *p;
+ int32_t len;
+ int64_t l;
+ union offset {
+ uint64_t val;
+ uint8_t buf[8];
+ } blk;
+
+ for (s = sects; s != NULL; s = s->next) {
+ if ((s->flags & SECTION_TYPE) == S_ZEROFILL)
+ continue;
+
+ /* Like a.out Mach-O references things in the data or bss
+ * sections by addresses which are actually relative to the
+ * start of the _text_ section, in the _file_. See outaout.c
+ * for more information. */
+ saa_rewind(s->data);
+ for (r = s->relocs; r != NULL; r = r->next) {
+ len = (uint32_t)1 << r->length;
+ if (len > 4) /* Can this ever be an issue?! */
+ len = 8;
+ blk.val = 0;
+ saa_fread(s->data, r->addr, blk.buf, len);
+
+ /* get offset based on relocation type */
+#ifdef WORDS_LITTLEENDIAN
+ l = blk.val;
+#else
+ l = blk.buf[0];
+ l += ((int64_t)blk.buf[1]) << 8;
+ l += ((int64_t)blk.buf[2]) << 16;
+ l += ((int64_t)blk.buf[3]) << 24;
+ l += ((int64_t)blk.buf[4]) << 32;
+ l += ((int64_t)blk.buf[5]) << 40;
+ l += ((int64_t)blk.buf[6]) << 48;
+ l += ((int64_t)blk.buf[7]) << 56;
+#endif
+
+ /* If the relocation is internal add to the current section
+ offset. Otherwise the only value we need is the symbol
+ offset which we already have. The linker takes care
+ of the rest of the address. */
+ if (!r->ext) {
+ /* generate final address by section address and offset */
+ nasm_assert(r->snum <= seg_nsects);
+ l += sectstab[r->snum]->addr;
+ if (r->pcrel)
+ l -= s->addr;
+ } else if (r->pcrel && r->type == GENERIC_RELOC_VANILLA) {
+ l -= s->addr;
+ }
+
+ /* write new offset back */
+ p = blk.buf;
+ WRITEDLONG(p, l);
+ saa_fwrite(s->data, r->addr, blk.buf, len);
+ }
+
+ /* dump the section data to file */
+ fwritezero(s->pad, ofile);
+ saa_fpwrite(s->data, ofile);
+ }
+
+ /* pad last section up to reloc entries on pointer boundary */
+ fwritezero(rel_padcnt, ofile);
+
+ /* emit relocation entries */
+ for (s = sects; s != NULL; s = s->next)
+ macho_write_relocs (s->relocs);
+}
+
+/* Write out the symbol table. We should already have sorted this
+ before now. */
+static void macho_write_symtab (void)
+{
+ struct symbol *sym;
+ uint64_t i;
+
+ /* we don't need to pad here since MACHO_RELINFO_SIZE == 8 */
+
+ for (sym = syms; sym != NULL; sym = sym->next) {
+ if ((sym->type & N_EXT) == 0) {
+ fwriteint32_t(sym->strx, ofile); /* string table entry number */
+ nasm_write(&sym->type, 1, ofile); /* symbol type */
+ nasm_write(&sym->sect, 1, ofile); /* section */
+ fwriteint16_t(sym->desc, ofile); /* description */
+
+ /* Fix up the symbol value now that we know the final section
+ sizes. */
+ if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+ nasm_assert(sym->sect <= seg_nsects);
+ sym->symv[0].key += sectstab[sym->sect]->addr;
+ }
+
+ fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
+ }
+ }
+
+ for (i = 0; i < nextdefsym; i++) {
+ sym = extdefsyms[i];
+ fwriteint32_t(sym->strx, ofile);
+ nasm_write(&sym->type, 1, ofile); /* symbol type */
+ nasm_write(&sym->sect, 1, ofile); /* section */
+ fwriteint16_t(sym->desc, ofile); /* description */
+
+ /* Fix up the symbol value now that we know the final section
+ sizes. */
+ if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+ nasm_assert(sym->sect <= seg_nsects);
+ sym->symv[0].key += sectstab[sym->sect]->addr;
+ }
+
+ fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
+ }
+
+ for (i = 0; i < nundefsym; i++) {
+ sym = undefsyms[i];
+ fwriteint32_t(sym->strx, ofile);
+ nasm_write(&sym->type, 1, ofile); /* symbol type */
+ nasm_write(&sym->sect, 1, ofile); /* section */
+ fwriteint16_t(sym->desc, ofile); /* description */
+
+ /* Fix up the symbol value now that we know the final section
+ sizes. */
+ if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
+ nasm_assert(sym->sect <= seg_nsects);
+ sym->symv[0].key += sectstab[sym->sect]->addr;
+ }
+
+ fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
+ }
+
+}
+
+/* Fixup the snum in the relocation entries, we should be
+ doing this only for externally referenced symbols. */
+static void macho_fixup_relocs (struct reloc *r)
+{
+ struct symbol *sym;
+
+ while (r != NULL) {
+ if (r->ext) {
+ for (sym = syms; sym != NULL; sym = sym->next) {
+ if (sym->initial_snum == r->snum) {
+ r->snum = sym->snum;
+ break;
+ }
+ }
+ }
+ r = r->next;
+ }
+}
+
+/* Write out the object file. */
+
+static void macho_write (void)
+{
+ uint64_t offset = 0;
+
+ /* mach-o object file structure:
+ **
+ ** mach header
+ ** uint32_t magic
+ ** int cpu type
+ ** int cpu subtype
+ ** uint32_t mach file type
+ ** uint32_t number of load commands
+ ** uint32_t size of all load commands
+ ** (includes section struct size of segment command)
+ ** uint32_t flags
+ **
+ ** segment command
+ ** uint32_t command type == LC_SEGMENT[_64]
+ ** uint32_t size of load command
+ ** (including section load commands)
+ ** char[16] segment name
+ ** pointer in-memory offset
+ ** pointer in-memory size
+ ** pointer in-file offset to data area
+ ** pointer in-file size
+ ** (in-memory size excluding zerofill sections)
+ ** int maximum vm protection
+ ** int initial vm protection
+ ** uint32_t number of sections
+ ** uint32_t flags
+ **
+ ** section commands
+ ** char[16] section name
+ ** char[16] segment name
+ ** pointer in-memory offset
+ ** pointer in-memory size
+ ** uint32_t in-file offset
+ ** uint32_t alignment
+ ** (irrelevant in MH_OBJECT)
+ ** uint32_t in-file offset of relocation entries
+ ** uint32_t number of relocations
+ ** uint32_t flags
+ ** uint32_t reserved
+ ** uint32_t reserved
+ **
+ ** symbol table command
+ ** uint32_t command type == LC_SYMTAB
+ ** uint32_t size of load command
+ ** uint32_t symbol table offset
+ ** uint32_t number of symbol table entries
+ ** uint32_t string table offset
+ ** uint32_t string table size
+ **
+ ** raw section data
+ **
+ ** padding to pointer boundary
+ **
+ ** relocation data (struct reloc)
+ ** int32_t offset
+ ** uint data (symbolnum, pcrel, length, extern, type)
+ **
+ ** symbol table data (struct nlist)
+ ** int32_t string table entry number
+ ** uint8_t type
+ ** (extern, absolute, defined in section)
+ ** uint8_t section
+ ** (0 for global symbols, section number of definition (>= 1, <=
+ ** 254) for local symbols, size of variable for common symbols
+ ** [type == extern])
+ ** int16_t description
+ ** (for stab debugging format)
+ ** pointer value (i.e. file offset) of symbol or stab offset
+ **
+ ** string table data
+ ** list of null-terminated strings
+ */
+
+ /* Emit the Mach-O header. */
+ macho_write_header();
+
+ offset = fmt.header_size + head_sizeofcmds;
+
+ /* emit the segment load command */
+ if (seg_nsects > 0)
+ offset = macho_write_segment (offset);
+ else
+ nasm_warn(WARN_OTHER, "no sections?");
+
+ if (nsyms > 0) {
+ /* write out symbol command */
+ fwriteint32_t(LC_SYMTAB, ofile); /* cmd == LC_SYMTAB */
+ fwriteint32_t(MACHO_SYMCMD_SIZE, ofile); /* size of load command */
+ fwriteint32_t(offset, ofile); /* symbol table offset */
+ fwriteint32_t(nsyms, ofile); /* number of symbol
+ ** table entries */
+ offset += nsyms * fmt.nlist_size;
+ fwriteint32_t(offset, ofile); /* string table offset */
+ fwriteint32_t(strslen, ofile); /* string table size */
+ }
+
+ /* emit section data */
+ if (seg_nsects > 0)
+ macho_write_section ();
+
+ /* emit symbol table if we have symbols */
+ if (nsyms > 0)
+ macho_write_symtab ();
+
+ /* we don't need to pad here, we are already aligned */
+
+ /* emit string table */
+ saa_fpwrite(strs, ofile);
+}
+/* We do quite a bit here, starting with finalizing all of the data
+ for the object file, writing, and then freeing all of the data from
+ the file. */
+
+static void macho_cleanup(void)
+{
+ struct section *s;
+ struct reloc *r;
+ struct symbol *sym;
+
+ dfmt->cleanup();
+
+ /* Sort all symbols. */
+ macho_layout_symbols (&nsyms, &strslen);
+
+ /* Fixup relocation entries */
+ for (s = sects; s != NULL; s = s->next) {
+ macho_fixup_relocs (s->relocs);
+ }
+
+ /* First calculate and finalize needed values. */
+ macho_calculate_sizes();
+ macho_write();
+
+ /* free up everything */
+ while (sects->next) {
+ s = sects;
+ sects = sects->next;
+
+ saa_free(s->data);
+ while (s->relocs != NULL) {
+ r = s->relocs;
+ s->relocs = s->relocs->next;
+ nasm_free(r);
+ }
+
+ nasm_free(s);
+ }
+
+ saa_free(strs);
+
+ raa_free(extsyms);
+
+ while (syms) {
+ sym = syms;
+ syms = syms->next;
+ nasm_free (sym);
+ }
+
+ nasm_free(extdefsyms);
+ nasm_free(undefsyms);
+ nasm_free(sectstab);
+ raa_free(section_by_index);
+ hash_free(&section_by_name);
+}
+
+static bool macho_set_section_attribute_by_symbol(const char *label, uint32_t flags)
+{
+ struct section *s;
+ int32_t nasm_seg;
+ int64_t offset;
+
+ if (lookup_label(label, &nasm_seg, &offset) == LBL_none) {
+ nasm_error(ERR_NONFATAL, "unknown symbol `%s' in no_dead_strip", label);
+ return false;
+ }
+
+ s = get_section_by_index(nasm_seg);
+ if (!s) {
+ nasm_error(ERR_NONFATAL, "symbol `%s' is external or absolute", label);
+ return false;
+ }
+
+ s->flags |= flags;
+ return true;
+}
+
+/*
+ * Mark a symbol for no dead stripping
+ */
+static enum directive_result macho_no_dead_strip(const char *labels)
+{
+ char *s, *p, *ep;
+ char ec;
+ enum directive_result rv = DIRR_ERROR;
+
+ p = s = nasm_strdup(labels);
+ while (*p) {
+ ep = nasm_skip_identifier(p);
+ if (!ep) {
+ nasm_error(ERR_NONFATAL, "invalid symbol in NO_DEAD_STRIP");
+ goto err;
+ }
+ ec = *ep;
+ if (ec && ec != ',' && !nasm_isspace(ec)) {
+ nasm_error(ERR_NONFATAL, "cannot parse contents after symbol");
+ goto err;
+ }
+ *ep = '\0';
+ if (!pass_first()) {
+ if (!macho_set_section_attribute_by_symbol(p, S_ATTR_NO_DEAD_STRIP))
+ rv = DIRR_ERROR;
+ }
+ *ep = ec;
+ p = nasm_skip_spaces(ep);
+ if (*p == ',')
+ p = nasm_skip_spaces(++p);
+ }
+
+ rv = DIRR_OK;
+
+err:
+ nasm_free(s);
+ return rv;
+}
+
+/*
+ * Mach-O pragmas
+ */
+static enum directive_result
+macho_pragma(const struct pragma *pragma)
+{
+ switch (pragma->opcode) {
+ case D_SUBSECTIONS_VIA_SYMBOLS:
+ if (*pragma->tail)
+ return DIRR_BADPARAM;
+
+ if (!pass_first())
+ head_flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
+
+ /* Jmp-match optimization conflicts */
+ optimizing.flag |= OPTIM_DISABLE_JMP_MATCH;
+
+ return DIRR_OK;
+
+ case D_NO_DEAD_STRIP:
+ return macho_no_dead_strip(pragma->tail);
+
+ default:
+ return DIRR_UNKNOWN; /* Not a Mach-O directive */
+ }
+}
+
+static const struct pragma_facility macho_pragma_list[] = {
+ { "macho", macho_pragma },
+ { NULL, macho_pragma } /* Implements macho32/macho64 namespaces */
+};
+
+static void macho_dbg_generate(void)
+{
+ uint8_t *p_buf = NULL, *p_buf_base = NULL;
+ size_t saa_len = 0, high_addr = 0, total_len = 0;
+ struct section *p_section = NULL;
+ /* calculated at debug_str and referenced at debug_info */
+ uint32_t producer_str_offset = 0, module_str_offset = 0, dir_str_offset = 0;
+
+ /* debug section defines */
+ {
+ int bits = 0;
+ macho_section(".debug_abbrev", &bits);
+ macho_section(".debug_info", &bits);
+ macho_section(".debug_line", &bits);
+ macho_section(".debug_str", &bits);
+ }
+
+ /* dw section walk to find high_addr and total_len */
+ {
+ struct dw_sect_list *p_sect;
+
+ list_for_each(p_sect, dw_head_sect) {
+ uint64_t offset = get_section_by_index(p_sect->section)->size;
+ struct SAA *p_linep = p_sect->psaa;
+
+ saa_write8(p_linep, 2); /* std op 2 */
+ saa_write8(p_linep, offset - p_sect->offset);
+ saa_write8(p_linep, DW_LNS_extended_op);
+ saa_write8(p_linep, 1); /* operand length */
+ saa_write8(p_linep, DW_LNE_end_sequence);
+
+ total_len += p_linep->datalen;
+ high_addr += offset;
+ }
+ }
+
+ /* debug line */
+ {
+ struct dw_sect_list *p_sect;
+ size_t linep_off, buf_size;
+ struct SAA *p_lines = saa_init(1L);
+ struct dir_list *p_dir;
+ struct file_list *p_file;
+
+ p_section = get_section_by_name("__DWARF", "__debug_line");
+ nasm_assert(p_section != NULL);
+
+ saa_write8(p_lines, 1); /* minimum instruction length */
+ saa_write8(p_lines, 1); /* initial value of "is_stmt" */
+ saa_write8(p_lines, DW_LN_BASE); /* line base */
+ saa_write8(p_lines, DW_LN_RANGE); /* line range */
+ saa_write8(p_lines, DW_OPCODE_BASE); /* opcode base */
+ saa_write8(p_lines, 0); /* std opcode 1 length */
+ saa_write8(p_lines, 1); /* std opcode 2 length */
+ saa_write8(p_lines, 1); /* std opcode 3 length */
+ saa_write8(p_lines, 1); /* std opcode 4 length */
+ saa_write8(p_lines, 1); /* std opcode 5 length */
+ saa_write8(p_lines, 0); /* std opcode 6 length */
+ saa_write8(p_lines, 0); /* std opcode 7 length */
+ saa_write8(p_lines, 0); /* std opcode 8 length */
+ saa_write8(p_lines, 1); /* std opcode 9 length */
+ saa_write8(p_lines, 0); /* std opcode 10 length */
+ saa_write8(p_lines, 0); /* std opcode 11 length */
+ saa_write8(p_lines, 1); /* std opcode 12 length */
+ list_for_each(p_dir, dw_head_dir) {
+ saa_wcstring(p_lines, p_dir->dir_name);
+ }
+ saa_write8(p_lines, 0); /* end of table */
+
+ list_for_each(p_file, dw_head_file) {
+ saa_wcstring(p_lines, p_file->file_name);
+ saa_write8(p_lines, p_file->dir->dir); /* directory id */
+ saa_write8(p_lines, 0); /* time */
+ saa_write8(p_lines, 0); /* size */
+ }
+ saa_write8(p_lines, 0); /* end of table */
+
+ linep_off = p_lines->datalen;
+ /* 10 bytes for initial & prolong length, and dwarf version info */
+ buf_size = saa_len = linep_off + total_len + 10;
+ p_buf_base = p_buf = nasm_malloc(buf_size);
+
+ WRITELONG(p_buf, saa_len - 4); /* initial length; size excluding itself */
+ WRITESHORT(p_buf, 2); /* dwarf version */
+ WRITELONG(p_buf, linep_off); /* prolong length */
+
+ saa_rnbytes(p_lines, p_buf, linep_off);
+ p_buf += linep_off;
+ saa_free(p_lines);
+
+ list_for_each(p_sect, dw_head_sect) {
+ struct SAA *p_linep = p_sect->psaa;
+
+ saa_len = p_linep->datalen;
+ saa_rnbytes(p_linep, p_buf, saa_len);
+ p_buf += saa_len;
+
+ saa_free(p_linep);
+ }
+
+ macho_output(p_section->index, p_buf_base, OUT_RAWDATA, buf_size, NO_SEG, 0);
+
+ nasm_free(p_buf_base);
+ }
+
+ /* string section */
+ {
+ struct SAA *p_str = saa_init(1L);
+ char *cur_path = nasm_realpath(module_name);
+ char *cur_file = nasm_basename(cur_path);
+ char *cur_dir = nasm_dirname(cur_path);
+
+ p_section = get_section_by_name("__DWARF", "__debug_str");
+ nasm_assert(p_section != NULL);
+
+ producer_str_offset = 0;
+ module_str_offset = dir_str_offset = saa_wcstring(p_str, nasm_signature());
+ dir_str_offset += saa_wcstring(p_str, cur_file);
+ saa_wcstring(p_str, cur_dir);
+
+ saa_len = p_str->datalen;
+ p_buf = nasm_malloc(saa_len);
+ saa_rnbytes(p_str, p_buf, saa_len);
+ macho_output(p_section->index, p_buf, OUT_RAWDATA, saa_len, NO_SEG, 0);
+
+ nasm_free(cur_path);
+ nasm_free(cur_file);
+ nasm_free(cur_dir);
+ saa_free(p_str);
+ nasm_free(p_buf);
+ }
+
+ /* debug info */
+ {
+ struct SAA *p_info = saa_init(1L);
+
+ p_section = get_section_by_name("__DWARF", "__debug_info");
+ nasm_assert(p_section != NULL);
+
+ /* size will be overwritten once determined, so skip in p_info layout */
+ saa_write16(p_info, 2); /* dwarf version */
+ saa_write32(p_info, 0); /* offset info abbrev */
+ saa_write8(p_info, (ofmt == &of_macho64) ? 8 : 4); /* pointer size */
+
+ saa_write8(p_info, 1); /* abbrev entry number */
+
+ saa_write32(p_info, producer_str_offset); /* offset from string table for DW_AT_producer */
+ saa_write16(p_info, DW_LANG_Mips_Assembler); /* DW_AT_language */
+ saa_write32(p_info, module_str_offset); /* offset from string table for DW_AT_name */
+ saa_write32(p_info, dir_str_offset); /* offset from string table for DW_AT_comp_dir */
+ saa_write32(p_info, 0); /* DW_AT_stmt_list */
+
+ if (ofmt == &of_macho64) {
+ saa_write64(p_info, 0); /* DW_AT_low_pc */
+ saa_write64(p_info, high_addr); /* DW_AT_high_pc */
+ } else {
+ saa_write32(p_info, 0); /* DW_AT_low_pc */
+ saa_write32(p_info, high_addr); /* DW_AT_high_pc */
+ }
+
+ saa_write8(p_info, 2); /* abbrev entry number */
+
+ if (ofmt == &of_macho64) {
+ saa_write64(p_info, 0); /* DW_AT_low_pc */
+ saa_write64(p_info, 0); /* DW_AT_frame_base */
+ } else {
+ saa_write32(p_info, 0); /* DW_AT_low_pc */
+ saa_write32(p_info, 0); /* DW_AT_frame_base */
+ }
+ saa_write8(p_info, DW_END_default);
+
+ saa_len = p_info->datalen;
+ p_buf_base = p_buf = nasm_malloc(saa_len + 4); /* 4B for size info */
+
+ WRITELONG(p_buf, saa_len);
+ saa_rnbytes(p_info, p_buf, saa_len);
+ macho_output(p_section->index, p_buf_base, OUT_RAWDATA, saa_len + 4, NO_SEG, 0);
+
+ saa_free(p_info);
+ nasm_free(p_buf_base);
+ }
+
+ /* abbrev section */
+ {
+ struct SAA *p_abbrev = saa_init(1L);
+
+ p_section = get_section_by_name("__DWARF", "__debug_abbrev");
+ nasm_assert(p_section != NULL);
+
+ saa_write8(p_abbrev, 1); /* entry number */
+
+ saa_write8(p_abbrev, DW_TAG_compile_unit);
+ saa_write8(p_abbrev, DW_CHILDREN_yes);
+
+ saa_write8(p_abbrev, DW_AT_producer);
+ saa_write8(p_abbrev, DW_FORM_strp);
+
+ saa_write8(p_abbrev, DW_AT_language);
+ saa_write8(p_abbrev, DW_FORM_data2);
+
+ saa_write8(p_abbrev, DW_AT_name);
+ saa_write8(p_abbrev, DW_FORM_strp);
+
+ saa_write8(p_abbrev, DW_AT_comp_dir);
+ saa_write8(p_abbrev, DW_FORM_strp);
+
+ saa_write8(p_abbrev, DW_AT_stmt_list);
+ saa_write8(p_abbrev, DW_FORM_data4);
+
+ saa_write8(p_abbrev, DW_AT_low_pc);
+ saa_write8(p_abbrev, DW_FORM_addr);
+
+ saa_write8(p_abbrev, DW_AT_high_pc);
+ saa_write8(p_abbrev, DW_FORM_addr);
+
+ saa_write16(p_abbrev, DW_END_default);
+
+ saa_write8(p_abbrev, 2); /* entry number */
+
+ saa_write8(p_abbrev, DW_TAG_subprogram);
+ saa_write8(p_abbrev, DW_CHILDREN_no);
+
+ saa_write8(p_abbrev, DW_AT_low_pc);
+ saa_write8(p_abbrev, DW_FORM_addr);
+
+ saa_write8(p_abbrev, DW_AT_frame_base);
+ saa_write8(p_abbrev, DW_FORM_addr);
+
+ saa_write16(p_abbrev, DW_END_default);
+
+ saa_write8(p_abbrev, 0); /* Terminal zero entry */
+
+ saa_len = p_abbrev->datalen;
+
+ p_buf = nasm_malloc(saa_len);
+
+ saa_rnbytes(p_abbrev, p_buf, saa_len);
+ macho_output(p_section->index, p_buf, OUT_RAWDATA, saa_len, NO_SEG, 0);
+
+ saa_free(p_abbrev);
+ nasm_free(p_buf);
+ }
+}
+
+static void new_file_list (const char *file_name, const char *dir_name)
+{
+ struct dir_list *dir_list;
+ bool need_new_dir_list = true;
+
+ nasm_new(dw_cur_file);
+ dw_cur_file->file = ++dw_num_files;
+ dw_cur_file->file_name = file_name;
+ if(!dw_head_file) {
+ dw_head_file = dw_cur_file;
+ } else {
+ *dw_last_file_next = dw_cur_file;
+ }
+ dw_last_file_next = &(dw_cur_file->next);
+
+ if(dw_head_dir) {
+ list_for_each(dir_list, dw_head_dir) {
+ if(!(strcmp(dir_name, dir_list->dir_name))) {
+ dw_cur_file->dir = dir_list;
+ need_new_dir_list = false;
+ break;
+ }
+ }
+ }
+
+ if(need_new_dir_list)
+ {
+ nasm_new(dir_list);
+ dir_list->dir = dw_num_dirs++;
+ dir_list->dir_name = dir_name;
+ if(!dw_head_dir) {
+ dw_head_dir = dir_list;
+ } else {
+ *dw_last_dir_next = dir_list;
+ }
+ dw_last_dir_next = &(dir_list->next);
+ dw_cur_file->dir = dir_list;
+ }
+}
+
+static void macho_dbg_init(void)
+{
+}
+
+static void macho_dbg_linenum(const char *file_name, int32_t line_num, int32_t segto)
+{
+ bool need_new_list = true;
+ const char *cur_file = nasm_basename(file_name);
+ const char *cur_dir = nasm_dirname(file_name);
+ (void)segto;
+
+ if(!dw_cur_file || strcmp(cur_file, dw_cur_file->file_name) ||
+ strcmp(cur_dir, dw_cur_file->dir->dir_name)) {
+ if(dw_head_file) {
+ struct file_list *match;
+
+ list_for_each(match, dw_head_file) {
+ if(!(strcmp(cur_file, match->file_name)) &&
+ !(strcmp(cur_dir, match->dir->dir_name))) {
+ dw_cur_file = match;
+ dw_cur_file->dir = match->dir;
+ need_new_list = false;
+ break;
+ }
+ }
+ }
+
+ if (need_new_list)
+ new_file_list(cur_file, cur_dir);
+ }
+
+ if (!need_new_list) {
+ nasm_free((void *)cur_file);
+ nasm_free((void *)cur_dir);
+ }
+
+ dbg_immcall = true;
+ cur_line = line_num;
+}
+
+static void macho_dbg_output(int type, void *param)
+{
+ struct section_info *sinfo_param = (struct section_info *)param;
+ int32_t secto = sinfo_param->secto;
+ bool need_new_sect = false;
+ struct SAA *p_linep = NULL;
+ (void)type;
+
+ if(!(dw_cur_sect && (dw_cur_sect->section == secto))) {
+ need_new_sect = true;
+ if(dw_head_sect) {
+ struct dw_sect_list *match = dw_head_sect;
+ uint32_t idx = 0;
+
+ for(; idx < dw_num_sects; idx++) {
+ if(match->section == secto) {
+ dw_cur_sect = match;
+ need_new_sect = false;
+ break;
+ }
+ match = match->next;
+ }
+ }
+ }
+
+ if(need_new_sect) {
+ nasm_new(dw_cur_sect);
+ dw_num_sects ++;
+ p_linep = dw_cur_sect->psaa = saa_init(1L);
+ dw_cur_sect->line = dw_cur_sect->file = 1;
+ dw_cur_sect->offset = 0;
+ dw_cur_sect->next = NULL;
+ dw_cur_sect->section = secto;
+
+ saa_write8(p_linep, DW_LNS_extended_op);
+ saa_write8(p_linep, (ofmt == &of_macho64) ? 9 : 5);
+ saa_write8(p_linep, DW_LNE_set_address);
+ if (ofmt == &of_macho64) {
+ saa_write64(p_linep, 0);
+ } else {
+ saa_write32(p_linep, 0);
+ }
+
+ if(!dw_head_sect) {
+ dw_head_sect = dw_last_sect = dw_cur_sect;
+ } else {
+ dw_last_sect->next = dw_cur_sect;
+ dw_last_sect = dw_cur_sect;
+ }
+ }
+
+ if(dbg_immcall == true) {
+ int32_t line_delta = cur_line - dw_cur_sect->line;
+ int32_t offset_delta = sinfo_param->size - dw_cur_sect->offset;
+ uint32_t cur_file = dw_cur_file->file;
+ p_linep = dw_cur_sect->psaa;
+
+ if(cur_file != dw_cur_sect->file) {
+ saa_write8(p_linep, DW_LNS_set_file);
+ saa_write8(p_linep, cur_file);
+ dw_cur_sect->file = cur_file;
+ }
+
+ if(line_delta) {
+ int special_opcode = (line_delta - DW_LN_BASE) + (DW_LN_RANGE * offset_delta) +
+ DW_OPCODE_BASE;
+
+ if((line_delta >= DW_LN_BASE) && (line_delta < DW_MAX_LN) &&
+ (special_opcode < DW_MAX_SP_OPCODE)) {
+ saa_write8(p_linep, special_opcode);
+ } else {
+ saa_write8(p_linep, DW_LNS_advance_line);
+ saa_wleb128s(p_linep, line_delta);
+ if(offset_delta) {
+ saa_write8(p_linep, DW_LNS_advance_pc);
+ saa_wleb128u(p_linep, offset_delta);
+ }
+ saa_write8(p_linep, DW_LNS_copy);
+ }
+
+ dw_cur_sect->line = cur_line;
+ dw_cur_sect->offset = sinfo_param->size;
+ }
+
+ dbg_immcall = false;
+ }
+}
+
+static void macho_dbg_cleanup(void)
+{
+ /* dwarf sectors generation */
+ macho_dbg_generate();
+
+ {
+ struct dw_sect_list *p_sect = dw_head_sect;
+ struct file_list *p_file = dw_head_file;
+ uint32_t idx = 0;
+
+ for(; idx < dw_num_sects; idx++) {
+ struct dw_sect_list *next = p_sect->next;
+ nasm_free(p_sect);
+ p_sect = next;
+ }
+
+ for(idx = 0; idx < dw_num_files; idx++) {
+ struct file_list *next = p_file->next;
+ nasm_free(p_file);
+ p_file = next;
+ }
+ }
+}
+
+#ifdef OF_MACHO32
+static const struct macho_fmt macho32_fmt = {
+ 4,
+ MH_MAGIC,
+ CPU_TYPE_I386,
+ LC_SEGMENT,
+ MACHO_HEADER_SIZE,
+ MACHO_SEGCMD_SIZE,
+ MACHO_SECTCMD_SIZE,
+ MACHO_NLIST_SIZE,
+ RL_MAX_32,
+ GENERIC_RELOC_VANILLA,
+ GENERIC_RELOC_VANILLA,
+ GENERIC_RELOC_TLV,
+ false /* Allow segment-relative relocations */
+};
+
+static void macho32_init(void)
+{
+ fmt = macho32_fmt;
+ macho_init();
+
+ macho_gotpcrel_sect = NO_SEG;
+}
+
+static const struct dfmt macho32_df_dwarf = {
+ "Mach-O i386 dwarf for Darwin/MacOS",
+ "dwarf",
+ macho_dbg_init,
+ macho_dbg_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ null_debug_typevalue,
+ macho_dbg_output,
+ macho_dbg_cleanup,
+ NULL /*pragma list*/
+};
+
+static const struct dfmt * const macho32_df_arr[2] =
+ { &macho32_df_dwarf, NULL };
+
+const struct ofmt of_macho32 = {
+ "Mach-O i386 (Mach, including MacOS X and variants)",
+ "macho32",
+ ".o",
+ 0,
+ 32,
+ macho32_df_arr,
+ &macho32_df_dwarf,
+ macho_stdmac,
+ macho32_init,
+ null_reset,
+ nasm_do_legacy_output,
+ macho_output,
+ macho_symdef,
+ macho_section,
+ macho_herelabel,
+ macho_sectalign,
+ null_segbase,
+ null_directive,
+ macho_cleanup,
+ macho_pragma_list
+};
+#endif
+
+#ifdef OF_MACHO64
+static const struct macho_fmt macho64_fmt = {
+ 8,
+ MH_MAGIC_64,
+ CPU_TYPE_X86_64,
+ LC_SEGMENT_64,
+ MACHO_HEADER64_SIZE,
+ MACHO_SEGCMD64_SIZE,
+ MACHO_SECTCMD64_SIZE,
+ MACHO_NLIST64_SIZE,
+ RL_MAX_64,
+ X86_64_RELOC_UNSIGNED,
+ X86_64_RELOC_SIGNED,
+ X86_64_RELOC_TLV,
+ true /* Force symbol-relative relocations */
+};
+
+static void macho64_init(void)
+{
+ fmt = macho64_fmt;
+ macho_init();
+
+ /* add special symbol for ..gotpcrel */
+ macho_gotpcrel_sect = seg_alloc() + 1;
+ backend_label("..gotpcrel", macho_gotpcrel_sect, 0L);
+}
+
+static const struct dfmt macho64_df_dwarf = {
+ "Mach-O x86-64 dwarf for Darwin/MacOS",
+ "dwarf",
+ macho_dbg_init,
+ macho_dbg_linenum,
+ null_debug_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ null_debug_typevalue,
+ macho_dbg_output,
+ macho_dbg_cleanup,
+ NULL /*pragma list*/
+};
+
+static const struct dfmt * const macho64_df_arr[2] =
+ { &macho64_df_dwarf, NULL };
+
+const struct ofmt of_macho64 = {
+ "Mach-O x86-64 (Mach, including MacOS X and variants)",
+ "macho64",
+ ".o",
+ 0,
+ 64,
+ macho64_df_arr,
+ &macho64_df_dwarf,
+ macho_stdmac,
+ macho64_init,
+ null_reset,
+ nasm_do_legacy_output,
+ macho_output,
+ macho_symdef,
+ macho_section,
+ macho_herelabel,
+ macho_sectalign,
+ null_segbase,
+ null_directive,
+ macho_cleanup,
+ macho_pragma_list,
+};
+#endif
+
+#endif
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-basic-offset:4
+ * End:
+ *
+ * end of file */
diff --git a/vere/ext/nasm/output/outmacho.mac b/vere/ext/nasm/output/outmacho.mac
new file mode 100644
index 0000000..001bb3a
--- /dev/null
+++ b/vere/ext/nasm/output/outmacho.mac
@@ -0,0 +1,49 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2017 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: macho macho32 macho64
+%define __?SECT?__ [section .text]
+%macro __?NASM_CDecl?__ 1
+%endmacro
+
+; This directive sets the MH_SUBSECTIONS_VIA_SYMBOLS header flag
+%imacro subsections_via_symbols 0.nolist
+ %pragma __?OUTPUT_FORMAT?__ %?
+%endmacro
+
+%imacro no_dead_strip 1-*.nolist
+ %rep %0
+ %pragma __?OUTPUT_FORMAT?__ %? %1
+ %rotate 1
+ %endrep
+%endmacro
diff --git a/vere/ext/nasm/output/outobj.c b/vere/ext/nasm/output/outobj.c
new file mode 100644
index 0000000..281839d
--- /dev/null
+++ b/vere/ext/nasm/output/outobj.c
@@ -0,0 +1,2701 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2017 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * outobj.c output routines for the Netwide Assembler to produce
+ * .OBJ object files
+ */
+
+#include "compiler.h"
+
+#include <ctype.h> /* For toupper() */
+#include "nctype.h"
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "error.h"
+#include "stdscan.h"
+#include "eval.h"
+#include "ver.h"
+
+#include "outform.h"
+#include "outlib.h"
+
+#ifdef OF_OBJ
+
+/*
+ * outobj.c is divided into two sections. The first section is low level
+ * routines for creating obj records; It has nearly zero NASM specific
+ * code. The second section is high level routines for processing calls and
+ * data structures from the rest of NASM into obj format.
+ *
+ * It should be easy (though not zero work) to lift the first section out for
+ * use as an obj file writer for some other assembler or compiler.
+ */
+
+/*
+ * These routines are built around the ObjRecord data structure. An ObjRecord
+ * holds an object file record that may be under construction or complete.
+ *
+ * A major function of these routines is to support continuation of an obj
+ * record into the next record when the maximum record size is exceeded. The
+ * high level code does not need to worry about where the record breaks occur.
+ * It does need to do some minor extra steps to make the automatic continuation
+ * work. Those steps may be skipped for records where the high level knows no
+ * continuation could be required.
+ *
+ * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord
+ * is cleared by obj_clear.
+ *
+ * 2) The caller should fill in .type.
+ *
+ * 3) If the record is continuable and there is processing that must be done at
+ * the start of each record then the caller should fill in .ori with the
+ * address of the record initializer routine.
+ *
+ * 4) If the record is continuable and it should be saved (rather than emitted
+ * immediately) as each record is done, the caller should set .up to be a
+ * pointer to a location in which the caller keeps the master pointer to the
+ * ObjRecord. When the record is continued, the obj_bump routine will then
+ * allocate a new ObjRecord structure and update the master pointer.
+ *
+ * 5) If the .ori field was used then the caller should fill in the .parm with
+ * any data required by the initializer.
+ *
+ * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword,
+ * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of
+ * data required for this record.
+ *
+ * 7) If the record is continuable, the caller should call obj_commit at each
+ * point where breaking the record is permitted.
+ *
+ * 8) To write out the record, the caller should call obj_emit2. If the
+ * caller has called obj_commit for all data written then he can get slightly
+ * faster code by calling obj_emit instead of obj_emit2.
+ *
+ * Most of these routines return an ObjRecord pointer. This will be the input
+ * pointer most of the time and will be the new location if the ObjRecord
+ * moved as a result of the call. The caller may ignore the return value in
+ * three cases: It is a "Never Reallocates" routine; or The caller knows
+ * continuation is not possible; or The caller uses the master pointer for the
+ * next operation.
+ */
+
+#define RECORD_MAX (1024-3) /* maximal size of any record except type+reclen */
+#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */
+
+#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */
+#define FIX_16_OFFSET 0x8400
+#define FIX_16_SELECTOR 0x8800
+#define FIX_32_POINTER 0x8C00
+#define FIX_08_HIGH 0x9000
+#define FIX_32_OFFSET 0xA400
+#define FIX_48_POINTER 0xAC00
+
+enum RecordID { /* record ID codes */
+
+ THEADR = 0x80, /* module header */
+ COMENT = 0x88, /* comment record */
+
+ LINNUM = 0x94, /* line number record */
+ LNAMES = 0x96, /* list of names */
+
+ SEGDEF = 0x98, /* segment definition */
+ GRPDEF = 0x9A, /* group definition */
+ EXTDEF = 0x8C, /* external definition */
+ PUBDEF = 0x90, /* public definition */
+ COMDEF = 0xB0, /* common definition */
+
+ LEDATA = 0xA0, /* logical enumerated data */
+ FIXUPP = 0x9C, /* fixups (relocations) */
+ FIXU32 = 0x9D, /* 32-bit fixups (relocations) */
+
+ MODEND = 0x8A, /* module end */
+ MODE32 = 0x8B /* module end for 32-bit objects */
+};
+
+enum ComentID { /* ID codes for comment records */
+ dTRANSL = 0x0000, /* translator comment */
+ dOMFEXT = 0xC0A0, /* "OMF extension" */
+ dEXTENDED = 0xC0A1, /* translator-specific extensions */
+ dLINKPASS = 0x40A2, /* link pass 2 marker */
+ dTYPEDEF = 0xC0E3, /* define a type */
+ dSYM = 0xC0E6, /* symbol debug record */
+ dFILNAME = 0xC0E8, /* file name record */
+ dDEPFILE = 0xC0E9, /* dependency file */
+ dCOMPDEF = 0xC0EA /* compiler type info */
+};
+
+typedef struct ObjRecord ObjRecord;
+typedef void ORI(ObjRecord * orp);
+
+struct ObjRecord {
+ ORI *ori; /* Initialization routine */
+ int used; /* Current data size */
+ int committed; /* Data size at last boundary */
+ int x_size; /* (see obj_x) */
+ unsigned int type; /* Record type */
+ ObjRecord *child; /* Associated record below this one */
+ ObjRecord **up; /* Master pointer to this ObjRecord */
+ ObjRecord *back; /* Previous part of this record */
+ uint32_t parm[OBJ_PARMS]; /* Parameters for ori routine */
+ uint8_t buf[RECORD_MAX + 3];
+};
+
+static void obj_fwrite(ObjRecord * orp);
+static void ori_ledata(ObjRecord * orp);
+static void ori_pubdef(ObjRecord * orp);
+static void ori_null(ObjRecord * orp);
+static ObjRecord *obj_commit(ObjRecord * orp);
+
+static bool obj_uppercase; /* Flag: all names in uppercase */
+static bool obj_use32; /* Flag: at least one segment is 32-bit */
+static bool obj_nodepend; /* Flag: don't emit file dependencies */
+
+/*
+ * Clear an ObjRecord structure. (Never reallocates).
+ * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared.
+ */
+static ObjRecord *obj_clear(ObjRecord * orp)
+{
+ orp->used = 0;
+ orp->committed = 0;
+ orp->x_size = 0;
+ orp->child = NULL;
+ orp->up = NULL;
+ orp->back = NULL;
+ return (orp);
+}
+
+/*
+ * Emit an ObjRecord structure. (Never reallocates).
+ * The record is written out proceeded (recursively) by its previous part (if
+ * any) and followed (recursively) by its child (if any).
+ * The previous part and the child are freed. The main ObjRecord is cleared,
+ * not freed.
+ */
+static ObjRecord *obj_emit(ObjRecord * orp)
+{
+ if (orp->back) {
+ obj_emit(orp->back);
+ nasm_free(orp->back);
+ }
+
+ if (orp->committed)
+ obj_fwrite(orp);
+
+ if (orp->child) {
+ obj_emit(orp->child);
+ nasm_free(orp->child);
+ }
+
+ return (obj_clear(orp));
+}
+
+/*
+ * Commit and Emit a record. (Never reallocates).
+ */
+static ObjRecord *obj_emit2(ObjRecord * orp)
+{
+ obj_commit(orp);
+ return (obj_emit(orp));
+}
+
+/*
+ * Allocate and clear a new ObjRecord; Also sets .ori to ori_null
+ */
+static ObjRecord *obj_new(void)
+{
+ ObjRecord *orp;
+
+ orp = obj_clear(nasm_malloc(sizeof(ObjRecord)));
+ orp->ori = ori_null;
+ return (orp);
+}
+
+/*
+ * Advance to the next record because the existing one is full or its x_size
+ * is incompatible.
+ * Any uncommitted data is moved into the next record.
+ */
+static ObjRecord *obj_bump(ObjRecord * orp)
+{
+ ObjRecord *nxt;
+ int used = orp->used;
+ int committed = orp->committed;
+
+ if (orp->up) {
+ *orp->up = nxt = obj_new();
+ nxt->ori = orp->ori;
+ nxt->type = orp->type;
+ nxt->up = orp->up;
+ nxt->back = orp;
+ memcpy(nxt->parm, orp->parm, sizeof(orp->parm));
+ } else
+ nxt = obj_emit(orp);
+
+ used -= committed;
+ if (used) {
+ nxt->committed = 1;
+ nxt->ori(nxt);
+ nxt->committed = nxt->used;
+ memcpy(nxt->buf + nxt->committed, orp->buf + committed, used);
+ nxt->used = nxt->committed + used;
+ }
+
+ return (nxt);
+}
+
+/*
+ * Advance to the next record if necessary to allow the next field to fit.
+ */
+static ObjRecord *obj_check(ObjRecord * orp, int size)
+{
+ if (orp->used + size > RECORD_MAX)
+ orp = obj_bump(orp);
+
+ if (!orp->committed) {
+ orp->committed = 1;
+ orp->ori(orp);
+ orp->committed = orp->used;
+ }
+
+ return (orp);
+}
+
+/*
+ * All data written so far is committed to the current record (won't be moved to
+ * the next record in case of continuation).
+ */
+static ObjRecord *obj_commit(ObjRecord * orp)
+{
+ orp->committed = orp->used;
+ return (orp);
+}
+
+/*
+ * Write a byte
+ */
+static ObjRecord *obj_byte(ObjRecord * orp, uint8_t val)
+{
+ orp = obj_check(orp, 1);
+ orp->buf[orp->used] = val;
+ orp->used++;
+ return (orp);
+}
+
+/*
+ * Write a word
+ */
+static ObjRecord *obj_word(ObjRecord * orp, unsigned int val)
+{
+ orp = obj_check(orp, 2);
+ orp->buf[orp->used] = val;
+ orp->buf[orp->used + 1] = val >> 8;
+ orp->used += 2;
+ return (orp);
+}
+
+/*
+ * Write a reversed word
+ */
+static ObjRecord *obj_rword(ObjRecord * orp, unsigned int val)
+{
+ orp = obj_check(orp, 2);
+ orp->buf[orp->used] = val >> 8;
+ orp->buf[orp->used + 1] = val;
+ orp->used += 2;
+ return (orp);
+}
+
+/*
+ * Write a dword
+ */
+static ObjRecord *obj_dword(ObjRecord * orp, uint32_t val)
+{
+ orp = obj_check(orp, 4);
+ orp->buf[orp->used] = val;
+ orp->buf[orp->used + 1] = val >> 8;
+ orp->buf[orp->used + 2] = val >> 16;
+ orp->buf[orp->used + 3] = val >> 24;
+ orp->used += 4;
+ return (orp);
+}
+
+/*
+ * All fields of "size x" in one obj record must be the same size (either 16
+ * bits or 32 bits). There is a one bit flag in each record which specifies
+ * which.
+ * This routine is used to force the current record to have the desired
+ * x_size. x_size is normally automatic (using obj_x), so that this
+ * routine should be used outside obj_x, only to provide compatibility with
+ * linkers that have bugs in their processing of the size bit.
+ */
+
+static ObjRecord *obj_force(ObjRecord * orp, int x)
+{
+ if (orp->x_size == (x ^ 48))
+ orp = obj_bump(orp);
+ orp->x_size = x;
+ return (orp);
+}
+
+/*
+ * This routine writes a field of size x. The caller does not need to worry at
+ * all about whether 16-bits or 32-bits are required.
+ */
+static ObjRecord *obj_x(ObjRecord * orp, uint32_t val)
+{
+ if (orp->type & 1)
+ orp->x_size = 32;
+ if (val > 0xFFFF)
+ orp = obj_force(orp, 32);
+ if (orp->x_size == 32) {
+ ObjRecord *nxt = obj_dword(orp, val);
+ nxt->x_size = 32; /* x_size is cleared when a record overflows */
+ return nxt;
+ }
+ orp->x_size = 16;
+ return (obj_word(orp, val));
+}
+
+/*
+ * Writes an index
+ */
+static ObjRecord *obj_index(ObjRecord * orp, unsigned int val)
+{
+ if (val < 128)
+ return (obj_byte(orp, val));
+ return (obj_word(orp, (val >> 8) | (val << 8) | 0x80));
+}
+
+/*
+ * Writes a variable length value
+ */
+static ObjRecord *obj_value(ObjRecord * orp, uint32_t val)
+{
+ if (val <= 128)
+ return (obj_byte(orp, val));
+ if (val <= 0xFFFF) {
+ orp = obj_byte(orp, 129);
+ return (obj_word(orp, val));
+ }
+ if (val <= 0xFFFFFF)
+ return (obj_dword(orp, (val << 8) + 132));
+ orp = obj_byte(orp, 136);
+ return (obj_dword(orp, val));
+}
+
+/*
+ * Writes a counted string
+ */
+static ObjRecord *obj_name(ObjRecord * orp, const char *name)
+{
+ int len = strlen(name);
+ uint8_t *ptr;
+
+ if (len > UINT8_MAX) {
+ nasm_warn(WARN_OTHER, "truncating object name `%.64s...' to %u bytes",
+ name, UINT8_MAX);
+ len = UINT8_MAX;
+ }
+
+ orp = obj_check(orp, len + 1);
+ ptr = orp->buf + orp->used;
+ *ptr++ = len;
+ orp->used += len + 1;
+ if (obj_uppercase)
+ while (--len >= 0) {
+ *ptr++ = toupper(*name);
+ name++;
+ } else
+ memcpy(ptr, name, len);
+ return (orp);
+}
+
+/*
+ * Initializer for an LEDATA record.
+ * parm[0] = offset
+ * parm[1] = segment index
+ * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to
+ * represent the offset that would be required if the record were split at the
+ * last commit point.
+ * parm[2] is a copy of parm[0] as it was when the current record was initted.
+ */
+static void ori_ledata(ObjRecord * orp)
+{
+ obj_index(orp, orp->parm[1]);
+ orp->parm[2] = orp->parm[0];
+ obj_x(orp, orp->parm[0]);
+}
+
+/*
+ * Initializer for a PUBDEF record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ * parm[2] = frame (only used when both indexes are zero)
+ */
+static void ori_pubdef(ObjRecord * orp)
+{
+ obj_index(orp, orp->parm[0]);
+ obj_index(orp, orp->parm[1]);
+ if (!(orp->parm[0] | orp->parm[1]))
+ obj_word(orp, orp->parm[2]);
+}
+
+/*
+ * Initializer for a LINNUM record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ */
+static void ori_linnum(ObjRecord * orp)
+{
+ obj_index(orp, orp->parm[0]);
+ obj_index(orp, orp->parm[1]);
+}
+
+/*
+ * Initializer for a local vars record.
+ */
+static void ori_local(ObjRecord * orp)
+{
+ obj_rword(orp, dSYM);
+}
+
+/*
+ * Null initializer for records that continue without any header info
+ */
+static void ori_null(ObjRecord * orp)
+{
+ (void)orp; /* Do nothing */
+}
+
+/*
+ * This concludes the low level section of outobj.c
+ */
+
+static char obj_infile[FILENAME_MAX];
+
+static int32_t first_seg;
+static bool any_segs;
+static int passtwo;
+static int arrindex;
+
+#define GROUP_MAX 256 /* we won't _realistically_ have more
+ * than this many segs in a group */
+#define EXT_BLKSIZ 256 /* block size for externals list */
+
+struct Segment; /* need to know these structs exist */
+struct Group;
+
+struct LineNumber {
+ struct LineNumber *next;
+ struct Segment *segment;
+ int32_t offset;
+ int32_t lineno;
+};
+
+static struct FileName {
+ struct FileName *next;
+ char *name;
+ struct LineNumber *lnhead, **lntail;
+ int index;
+} *fnhead, **fntail;
+
+static struct Array {
+ struct Array *next;
+ unsigned size;
+ int basetype;
+} *arrhead, **arrtail;
+
+#define ARRAYBOT 31 /* magic number for first array index */
+
+static struct Public {
+ struct Public *next;
+ char *name;
+ int32_t offset;
+ int32_t segment; /* only if it's far-absolute */
+ int type; /* only for local debug syms */
+} *fpubhead, **fpubtail, *last_defined;
+
+static struct External {
+ struct External *next;
+ char *name;
+ int32_t commonsize;
+ int32_t commonelem; /* element size if FAR, else zero */
+ int index; /* OBJ-file external index */
+ enum {
+ DEFWRT_NONE, /* no unusual default-WRT */
+ DEFWRT_STRING, /* a string we don't yet understand */
+ DEFWRT_SEGMENT, /* a segment */
+ DEFWRT_GROUP /* a group */
+ } defwrt_type;
+ union {
+ char *string;
+ struct Segment *seg;
+ struct Group *grp;
+ } defwrt_ptr;
+ struct External *next_dws; /* next with DEFWRT_STRING */
+} *exthead, **exttail, *dws;
+
+static int externals;
+
+static struct ExtBack {
+ struct ExtBack *next;
+ struct External *exts[EXT_BLKSIZ];
+} *ebhead, **ebtail;
+
+static struct Segment {
+ struct Segment *next;
+ char *name;
+ int32_t index; /* the NASM segment id */
+ int32_t obj_index; /* the OBJ-file segment index */
+ struct Group *grp; /* the group it beint32_ts to */
+ uint32_t currentpos;
+ int32_t align; /* can be SEG_ABS + absolute addr */
+ int64_t pass_last_seen;
+ struct Public *pubhead, **pubtail, *lochead, **loctail;
+ char *segclass, *overlay; /* `class' is a C++ keyword :-) */
+ ObjRecord *orp;
+ enum {
+ CMB_PRIVATE = 0,
+ CMB_PUBLIC = 2,
+ CMB_STACK = 5,
+ CMB_COMMON = 6
+ } combine;
+ bool use32; /* is this segment 32-bit? */
+} *seghead, **segtail, *obj_seg_needs_update;
+
+static struct Group {
+ struct Group *next;
+ char *name;
+ int32_t index; /* NASM segment id */
+ int32_t obj_index; /* OBJ-file group index */
+ int32_t nentries; /* number of elements... */
+ int32_t nindices; /* ...and number of index elts... */
+ union {
+ int32_t index;
+ char *name;
+ } segs[GROUP_MAX]; /* ...in this */
+} *grphead, **grptail, *obj_grp_needs_update;
+
+static struct ImpDef {
+ struct ImpDef *next;
+ char *extname;
+ char *libname;
+ unsigned int impindex;
+ char *impname;
+} *imphead, **imptail;
+
+static struct ExpDef {
+ struct ExpDef *next;
+ char *intname;
+ char *extname;
+ unsigned int ordinal;
+ int flags;
+} *exphead, **exptail;
+
+#define EXPDEF_FLAG_ORDINAL 0x80
+#define EXPDEF_FLAG_RESIDENT 0x40
+#define EXPDEF_FLAG_NODATA 0x20
+#define EXPDEF_MASK_PARMCNT 0x1F
+
+static int32_t obj_entry_seg, obj_entry_ofs;
+
+const struct ofmt of_obj;
+static const struct dfmt borland_debug_form;
+
+/* The current segment */
+static struct Segment *current_seg;
+
+static int32_t obj_segment(char *, int *);
+static void obj_write_file(void);
+static enum directive_result obj_directive(enum directive, char *);
+
+static void obj_init(void)
+{
+ strlcpy(obj_infile, inname, sizeof(obj_infile));
+ first_seg = seg_alloc();
+ any_segs = false;
+ fpubhead = NULL;
+ fpubtail = &fpubhead;
+ exthead = NULL;
+ exttail = &exthead;
+ imphead = NULL;
+ imptail = &imphead;
+ exphead = NULL;
+ exptail = &exphead;
+ dws = NULL;
+ externals = 0;
+ ebhead = NULL;
+ ebtail = &ebhead;
+ seghead = obj_seg_needs_update = NULL;
+ segtail = &seghead;
+ grphead = obj_grp_needs_update = NULL;
+ grptail = &grphead;
+ obj_entry_seg = NO_SEG;
+ obj_uppercase = false;
+ obj_use32 = false;
+ passtwo = 0;
+ current_seg = NULL;
+}
+
+static void obj_cleanup(void)
+{
+ obj_write_file();
+ dfmt->cleanup();
+ while (seghead) {
+ struct Segment *segtmp = seghead;
+ seghead = seghead->next;
+ while (segtmp->pubhead) {
+ struct Public *pubtmp = segtmp->pubhead;
+ segtmp->pubhead = pubtmp->next;
+ nasm_free(pubtmp->name);
+ nasm_free(pubtmp);
+ }
+ nasm_free(segtmp->segclass);
+ nasm_free(segtmp->overlay);
+ nasm_free(segtmp);
+ }
+ while (fpubhead) {
+ struct Public *pubtmp = fpubhead;
+ fpubhead = fpubhead->next;
+ nasm_free(pubtmp->name);
+ nasm_free(pubtmp);
+ }
+ while (exthead) {
+ struct External *exttmp = exthead;
+ exthead = exthead->next;
+ nasm_free(exttmp);
+ }
+ while (imphead) {
+ struct ImpDef *imptmp = imphead;
+ imphead = imphead->next;
+ nasm_free(imptmp->extname);
+ nasm_free(imptmp->libname);
+ nasm_free(imptmp->impname); /* nasm_free won't mind if it's NULL */
+ nasm_free(imptmp);
+ }
+ while (exphead) {
+ struct ExpDef *exptmp = exphead;
+ exphead = exphead->next;
+ nasm_free(exptmp->extname);
+ nasm_free(exptmp->intname);
+ nasm_free(exptmp);
+ }
+ while (ebhead) {
+ struct ExtBack *ebtmp = ebhead;
+ ebhead = ebhead->next;
+ nasm_free(ebtmp);
+ }
+ while (grphead) {
+ struct Group *grptmp = grphead;
+ grphead = grphead->next;
+ nasm_free(grptmp);
+ }
+}
+
+static void obj_ext_set_defwrt(struct External *ext, char *id)
+{
+ struct Segment *seg;
+ struct Group *grp;
+
+ for (seg = seghead; seg; seg = seg->next)
+ if (!strcmp(seg->name, id)) {
+ ext->defwrt_type = DEFWRT_SEGMENT;
+ ext->defwrt_ptr.seg = seg;
+ nasm_free(id);
+ return;
+ }
+
+ for (grp = grphead; grp; grp = grp->next)
+ if (!strcmp(grp->name, id)) {
+ ext->defwrt_type = DEFWRT_GROUP;
+ ext->defwrt_ptr.grp = grp;
+ nasm_free(id);
+ return;
+ }
+
+ ext->defwrt_type = DEFWRT_STRING;
+ ext->defwrt_ptr.string = id;
+ ext->next_dws = dws;
+ dws = ext;
+}
+
+static void obj_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ /*
+ * We have three cases:
+ *
+ * (i) `segment' is a segment-base. If so, set the name field
+ * for the segment or group structure it refers to, and then
+ * return.
+ *
+ * (ii) `segment' is one of our segments, or a SEG_ABS segment.
+ * Save the label position for later output of a PUBDEF record.
+ * (Or a MODPUB, if we work out how.)
+ *
+ * (iii) `segment' is not one of our segments. Save the label
+ * position for later output of an EXTDEF, and also store a
+ * back-reference so that we can map later references to this
+ * segment number to the external index.
+ */
+ struct External *ext;
+ struct ExtBack *eb;
+ struct Segment *seg;
+ int i;
+ bool used_special = false; /* have we used the special text? */
+
+ if (debug_level(2))
+ nasm_debug(" obj_deflabel: %s, seg=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n",
+ name, segment, offset, is_global, special);
+
+ /*
+ * If it's a special-retry from pass two, discard it.
+ */
+ if (is_global == 3)
+ return;
+
+ /*
+ * First check for the double-period, signifying something
+ * unusual.
+ */
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ if (!strcmp(name, "..start")) {
+ obj_entry_seg = segment;
+ obj_entry_ofs = offset;
+ return;
+ }
+ nasm_nonfatal("unrecognised special symbol `%s'", name);
+ }
+
+ /*
+ * Case (i):
+ */
+ if (obj_seg_needs_update) {
+ obj_seg_needs_update->name = name;
+ return;
+ } else if (obj_grp_needs_update) {
+ obj_grp_needs_update->name = name;
+ return;
+ }
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ if (segment >= SEG_ABS || segment == NO_SEG) {
+ /*
+ * SEG_ABS subcase of (ii).
+ */
+ if (is_global) {
+ struct Public *pub;
+
+ pub = *fpubtail = nasm_malloc(sizeof(*pub));
+ fpubtail = &pub->next;
+ pub->next = NULL;
+ pub->name = nasm_strdup(name);
+ pub->offset = offset;
+ pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS);
+ }
+ if (special)
+ nasm_nonfatal("OBJ supports no special symbol features"
+ " for this symbol type");
+ return;
+ }
+
+ /*
+ * If `any_segs' is still false, we might need to define a
+ * default segment, if they're trying to declare a label in
+ * `first_seg'.
+ */
+ if (!any_segs && segment == first_seg) {
+ int tempint = 0;
+ if (segment != obj_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in OBJ driver");
+ }
+
+ for (seg = seghead; seg && is_global; seg = seg->next)
+ if (seg->index == segment) {
+ struct Public *loc = nasm_malloc(sizeof(*loc));
+ /*
+ * Case (ii). Maybe MODPUB someday?
+ */
+ *seg->pubtail = loc;
+ seg->pubtail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+
+ if (special)
+ nasm_nonfatal("OBJ supports no special symbol features"
+ " for this symbol type");
+ return;
+ }
+
+ /*
+ * Case (iii).
+ */
+ if (is_global) {
+ ext = *exttail = nasm_malloc(sizeof(*ext));
+ ext->next = NULL;
+ exttail = &ext->next;
+ ext->name = name;
+ /* Place by default all externs into the current segment */
+ ext->defwrt_type = DEFWRT_NONE;
+
+/* 28-Apr-2002 - John Coffman
+ The following code was introduced on 12-Aug-2000, and breaks fixups
+ on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker
+ (5.10). It was introduced after FIXUP32 was added, and may be needed
+ for 32-bit segments. The following will get 16-bit segments working
+ again, and maybe someone can correct the 'if' condition which is
+ actually needed.
+*/
+#if 0
+ if (current_seg) {
+#else
+ if (current_seg && current_seg->use32) {
+ if (current_seg->grp) {
+ ext->defwrt_type = DEFWRT_GROUP;
+ ext->defwrt_ptr.grp = current_seg->grp;
+ } else {
+ ext->defwrt_type = DEFWRT_SEGMENT;
+ ext->defwrt_ptr.seg = current_seg;
+ }
+ }
+#endif
+
+ if (is_global == 2) {
+ ext->commonsize = offset;
+ ext->commonelem = 1; /* default FAR */
+ } else
+ ext->commonsize = 0;
+ } else
+ return;
+
+ /*
+ * Now process the special text, if any, to find default-WRT
+ * specifications and common-variable element-size and near/far
+ * specifications.
+ */
+ while (special && *special) {
+ used_special = true;
+
+ /*
+ * We might have a default-WRT specification.
+ */
+ if (!nasm_strnicmp(special, "wrt", 3)) {
+ char *p;
+ int len;
+ special += 3;
+ special += strspn(special, " \t");
+ p = nasm_strndup(special, len = strcspn(special, ":"));
+ obj_ext_set_defwrt(ext, p);
+ special += len;
+ if (*special && *special != ':')
+ nasm_nonfatal("`:' expected in special symbol"
+ " text for `%s'", ext->name);
+ else if (*special == ':')
+ special++;
+ }
+
+ /*
+ * The NEAR or FAR keywords specify nearness or
+ * farness. FAR gives default element size 1.
+ */
+ if (!nasm_strnicmp(special, "far", 3)) {
+ if (ext->commonsize)
+ ext->commonelem = 1;
+ else
+ nasm_nonfatal("`%s': `far' keyword may only be applied"
+ " to common variables\n", ext->name);
+ special += 3;
+ special += strspn(special, " \t");
+ } else if (!nasm_strnicmp(special, "near", 4)) {
+ if (ext->commonsize)
+ ext->commonelem = 0;
+ else
+ nasm_nonfatal("`%s': `far' keyword may only be applied"
+ " to common variables\n", ext->name);
+ special += 4;
+ special += strspn(special, " \t");
+ }
+
+ /*
+ * If it's a common, and anything else remains on the line
+ * before a further colon, evaluate it as an expression and
+ * use that as the element size. Forward references aren't
+ * allowed.
+ */
+ if (*special == ':')
+ special++;
+ else if (*special) {
+ if (ext->commonsize) {
+ expr *e;
+ struct tokenval tokval;
+
+ stdscan_reset();
+ stdscan_set(special);
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL);
+ if (e) {
+ if (!is_simple(e))
+ nasm_nonfatal("cannot use relocatable"
+ " expression as common-variable element size");
+ else
+ ext->commonelem = reloc_value(e);
+ }
+ special = stdscan_get();
+ } else {
+ nasm_nonfatal("`%s': element-size specifications only"
+ " apply to common variables", ext->name);
+ while (*special && *special != ':')
+ special++;
+ if (*special == ':')
+ special++;
+ }
+ }
+ }
+
+ i = segment / 2;
+ eb = ebhead;
+ if (!eb) {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ while (i >= EXT_BLKSIZ) {
+ if (eb && eb->next)
+ eb = eb->next;
+ else {
+ eb = *ebtail = nasm_zalloc(sizeof(*eb));
+ eb->next = NULL;
+ ebtail = &eb->next;
+ }
+ i -= EXT_BLKSIZ;
+ }
+ eb->exts[i] = ext;
+ ext->index = ++externals;
+
+ if (special && !used_special)
+ nasm_nonfatal("OBJ supports no special symbol features"
+ " for this symbol type");
+}
+
+/* forward declaration */
+static void obj_write_fixup(ObjRecord * orp, int bytes,
+ int segrel, int32_t seg, int32_t wrt,
+ struct Segment *segto);
+
+static void obj_out(int32_t segto, const void *data,
+ enum out_type type, uint64_t size,
+ int32_t segment, int32_t wrt)
+{
+ const uint8_t *ucdata;
+ int32_t ldata;
+ struct Segment *seg;
+ ObjRecord *orp;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint = 0;
+ if (segto != obj_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in OBJ driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("code directed to nonexistent segment?");
+
+ orp = seg->orp;
+ orp->parm[0] = seg->currentpos;
+
+ switch (type) {
+ case OUT_RAWDATA:
+ ucdata = data;
+ while (size > 0) {
+ unsigned int len;
+ orp = obj_check(seg->orp, 1);
+ len = RECORD_MAX - orp->used;
+ if (len > size)
+ len = size;
+ memcpy(orp->buf + orp->used, ucdata, len);
+ orp->committed = orp->used += len;
+ orp->parm[0] = seg->currentpos += len;
+ ucdata += len;
+ size -= len;
+ }
+ break;
+
+ case OUT_ADDRESS:
+ case OUT_REL1ADR:
+ case OUT_REL2ADR:
+ case OUT_REL4ADR:
+ case OUT_REL8ADR:
+ {
+ int rsize;
+
+ if (type == OUT_ADDRESS)
+ size = abs((int)size);
+
+ if (segment == NO_SEG && type != OUT_ADDRESS)
+ nasm_nonfatal("relative call to absolute address not"
+ " supported by OBJ format");
+ if (segment >= SEG_ABS)
+ nasm_nonfatal("far-absolute relocations not supported"
+ " by OBJ format");
+
+ ldata = *(int64_t *)data;
+ if (type != OUT_ADDRESS) {
+ /*
+ * For 16-bit and 32-bit x86 code, the size and realsize() always
+ * matches as only jumps, calls and loops uses PC relative
+ * addressing and the address isn't followed by any other opcode
+ * bytes. In 64-bit mode there is RIP relative addressing which
+ * means the fixup location can be followed by an immediate value,
+ * meaning that size > realsize().
+ *
+ * When the CPU is calculating the effective address, it takes the
+ * RIP at the end of the instruction and adds the fixed up relative
+ * address value to it.
+ *
+ * The linker's point of reference is the end of the fixup location
+ * (which is the end of the instruction for Jcc, CALL, LOOP[cc]).
+ * It is calculating distance between the target symbol and the end
+ * of the fixup location, and add this to the displacement value we
+ * are calculating here and storing at the fixup location.
+ *
+ * To get the right effect, we need to _reduce_ the displacement
+ * value by the number of bytes following the fixup.
+ *
+ * Example:
+ * data at address 0x100; REL4ADR at 0x050, 4 byte immediate,
+ * end of fixup at 0x054, end of instruction at 0x058.
+ * => size = 8.
+ * => realsize() -> 4
+ * => CPU needs a value of: 0x100 - 0x058 = 0x0a8
+ * => linker/loader will add: 0x100 - 0x054 = 0x0ac
+ * => We must add an addend of -4.
+ * => realsize() - size = -4.
+ *
+ * The code used to do size - realsize() at least since v0.90,
+ * probably because it wasn't needed...
+ */
+ ldata -= size;
+ size = realsize(type, size);
+ ldata += size;
+ }
+
+ switch (size) {
+ default:
+ nasm_nonfatal("OBJ format can only handle 16- or "
+ "32-byte relocations");
+ segment = NO_SEG; /* Don't actually generate a relocation */
+ break;
+ case 2:
+ orp = obj_word(orp, ldata);
+ break;
+ case 4:
+ orp = obj_dword(orp, ldata);
+ break;
+ }
+
+ rsize = size;
+ if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
+ size == 4) {
+ /*
+ * This is a 4-byte segment-base relocation such as
+ * `MOV EAX,SEG foo'. OBJ format can't actually handle
+ * these, but if the constant term has the 16 low bits
+ * zero, we can just apply a 2-byte segment-base
+ * relocation to the low word instead.
+ */
+ rsize = 2;
+ if (ldata & 0xFFFF)
+ nasm_nonfatal("OBJ format cannot handle complex"
+ " dword-size segment base references");
+ }
+ if (segment != NO_SEG)
+ obj_write_fixup(orp, rsize,
+ (type == OUT_ADDRESS ? 0x4000 : 0),
+ segment, wrt, seg);
+ seg->currentpos += size;
+ break;
+ }
+
+ default:
+ nasm_nonfatal("Relocation type not supported by output format");
+ /* fall through */
+
+ case OUT_RESERVE:
+ if (orp->committed)
+ orp = obj_bump(orp);
+ seg->currentpos += size;
+ break;
+ }
+ obj_commit(orp);
+}
+
+static void obj_write_fixup(ObjRecord * orp, int bytes,
+ int segrel, int32_t seg, int32_t wrt,
+ struct Segment *segto)
+{
+ unsigned locat;
+ int method;
+ int base;
+ int32_t tidx, fidx;
+ struct Segment *s = NULL;
+ struct Group *g = NULL;
+ struct External *e = NULL;
+ ObjRecord *forp;
+
+ if (bytes != 2 && bytes != 4) {
+ nasm_nonfatal("`obj' output driver does not support"
+ " %d-bit relocations", bytes << 3);
+ return;
+ }
+
+ forp = orp->child;
+ if (forp == NULL) {
+ orp->child = forp = obj_new();
+ forp->up = &(orp->child);
+ /* We should choose between FIXUPP and FIXU32 record type */
+ /* If we're targeting a 32-bit segment, use a FIXU32 record */
+ if (segto->use32)
+ forp->type = FIXU32;
+ else
+ forp->type = FIXUPP;
+ }
+
+ if (seg % 2) {
+ base = true;
+ locat = FIX_16_SELECTOR;
+ seg--;
+ if (bytes != 2)
+ nasm_panic("OBJ: 4-byte segment base fixup got"
+ " through sanity check");
+ } else {
+ base = false;
+ locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET;
+ if (!segrel)
+ /*
+ * There is a bug in tlink that makes it process self relative
+ * fixups incorrectly if the x_size doesn't match the location
+ * size.
+ */
+ forp = obj_force(forp, bytes << 3);
+ }
+
+ forp = obj_rword(forp, locat | segrel | (orp->parm[0] - orp->parm[2]));
+
+ tidx = fidx = -1, method = 0; /* placate optimisers */
+
+ /*
+ * See if we can find the segment ID in our segment list. If
+ * so, we have a T4 (LSEG) target.
+ */
+ for (s = seghead; s; s = s->next)
+ if (s->index == seg)
+ break;
+ if (s)
+ method = 4, tidx = s->obj_index;
+ else {
+ for (g = grphead; g; g = g->next)
+ if (g->index == seg)
+ break;
+ if (g)
+ method = 5, tidx = g->obj_index;
+ else {
+ int32_t i = seg / 2;
+ struct ExtBack *eb = ebhead;
+ while (i >= EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ if (eb)
+ method = 6, e = eb->exts[i], tidx = e->index;
+ else
+ nasm_panic("unrecognised segment value in obj_write_fixup");
+ }
+ }
+
+ /*
+ * If no WRT given, assume the natural default, which is method
+ * F5 unless:
+ *
+ * - we are doing an OFFSET fixup for a grouped segment, in
+ * which case we require F1 (group).
+ *
+ * - we are doing an OFFSET fixup for an external with a
+ * default WRT, in which case we must honour the default WRT.
+ */
+ if (wrt == NO_SEG) {
+ if (!base && s && s->grp)
+ method |= 0x10, fidx = s->grp->obj_index;
+ else if (!base && e && e->defwrt_type != DEFWRT_NONE) {
+ if (e->defwrt_type == DEFWRT_SEGMENT)
+ method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index;
+ else if (e->defwrt_type == DEFWRT_GROUP)
+ method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index;
+ else {
+ nasm_nonfatal("default WRT specification for"
+ " external `%s' unresolved", e->name);
+ method |= 0x50, fidx = -1; /* got to do _something_ */
+ }
+ } else
+ method |= 0x50, fidx = -1;
+ } else {
+ /*
+ * See if we can find the WRT-segment ID in our segment
+ * list. If so, we have a F0 (LSEG) frame.
+ */
+ for (s = seghead; s; s = s->next)
+ if (s->index == wrt - 1)
+ break;
+ if (s)
+ method |= 0x00, fidx = s->obj_index;
+ else {
+ for (g = grphead; g; g = g->next)
+ if (g->index == wrt - 1)
+ break;
+ if (g)
+ method |= 0x10, fidx = g->obj_index;
+ else {
+ int32_t i = wrt / 2;
+ struct ExtBack *eb = ebhead;
+ while (i >= EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ if (eb)
+ method |= 0x20, fidx = eb->exts[i]->index;
+ else
+ nasm_panic("unrecognised WRT value in obj_write_fixup");
+ }
+ }
+ }
+
+ forp = obj_byte(forp, method);
+ if (fidx != -1)
+ forp = obj_index(forp, fidx);
+ forp = obj_index(forp, tidx);
+ obj_commit(forp);
+}
+
+static int32_t obj_segment(char *name, int *bits)
+{
+ /*
+ * We call the label manager here to define a name for the new
+ * segment, and when our _own_ label-definition stub gets
+ * called in return, it should register the new segment name
+ * using the pointer it gets passed. That way we save memory,
+ * by sponging off the label manager.
+ */
+ if (debug_level(3))
+ nasm_debug(" obj_segment: < %s >, *bits=%d\n", name, *bits);
+
+ if (!name) {
+ *bits = 16;
+ current_seg = NULL;
+ return first_seg;
+ } else {
+ struct Segment *seg;
+ struct Group *grp;
+ struct External **extp;
+ int obj_idx, i, attrs;
+ bool rn_error;
+ char *p;
+
+ /*
+ * Look for segment attributes.
+ */
+ attrs = 0;
+ while (*name == '.')
+ name++; /* hack, but a documented one */
+ p = name;
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+ while (*p) {
+ while (*p && !nasm_isspace(*p))
+ p++;
+ if (*p) {
+ *p++ = '\0';
+ while (*p && nasm_isspace(*p))
+ *p++ = '\0';
+ }
+
+ attrs++;
+ }
+
+ for (seg = seghead, obj_idx = 1; ; seg = seg->next, obj_idx++) {
+ if (!seg)
+ break;
+
+ if (!strcmp(seg->name, name)) {
+ if (attrs > 0 && seg->pass_last_seen == pass_count())
+ nasm_warn(WARN_OTHER, "segment attributes specified on"
+ " redeclaration of segment: ignoring");
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+ current_seg = seg;
+ seg->pass_last_seen = pass_count();
+ return seg->index;
+ }
+ }
+
+ *segtail = seg = nasm_malloc(sizeof(*seg));
+ seg->next = NULL;
+ segtail = &seg->next;
+ seg->index = (any_segs ? seg_alloc() : first_seg);
+ seg->obj_index = obj_idx;
+ seg->grp = NULL;
+ any_segs = true;
+ seg->name = nasm_strdup(name);
+ seg->currentpos = 0;
+ seg->align = 1; /* default */
+ seg->use32 = false; /* default */
+ seg->combine = CMB_PUBLIC; /* default */
+ seg->segclass = seg->overlay = NULL;
+ seg->pubhead = NULL;
+ seg->pubtail = &seg->pubhead;
+ seg->lochead = NULL;
+ seg->loctail = &seg->lochead;
+ seg->orp = obj_new();
+ seg->orp->up = &(seg->orp);
+ seg->orp->ori = ori_ledata;
+ seg->orp->type = LEDATA;
+ seg->orp->parm[1] = obj_idx;
+
+ /*
+ * Process the segment attributes.
+ */
+ p = name;
+ while (attrs--) {
+ p += strlen(p);
+ while (!*p)
+ p++;
+
+ /*
+ * `p' contains a segment attribute.
+ */
+ if (!nasm_stricmp(p, "private"))
+ seg->combine = CMB_PRIVATE;
+ else if (!nasm_stricmp(p, "public"))
+ seg->combine = CMB_PUBLIC;
+ else if (!nasm_stricmp(p, "common"))
+ seg->combine = CMB_COMMON;
+ else if (!nasm_stricmp(p, "stack"))
+ seg->combine = CMB_STACK;
+ else if (!nasm_stricmp(p, "use16"))
+ seg->use32 = false;
+ else if (!nasm_stricmp(p, "use32"))
+ seg->use32 = true;
+ else if (!nasm_stricmp(p, "flat")) {
+ /*
+ * This segment is an OS/2 FLAT segment. That means
+ * that its default group is group FLAT, even if
+ * the group FLAT does not explicitly _contain_ the
+ * segment.
+ *
+ * When we see this, we must create the group
+ * `FLAT', containing no segments, if it does not
+ * already exist; then we must set the default
+ * group of this segment to be the FLAT group.
+ */
+ struct Group *grp;
+ for (grp = grphead; grp; grp = grp->next)
+ if (!strcmp(grp->name, "FLAT"))
+ break;
+ if (!grp) {
+ obj_directive(D_GROUP, "FLAT");
+ for (grp = grphead; grp; grp = grp->next)
+ if (!strcmp(grp->name, "FLAT"))
+ break;
+ if (!grp)
+ nasm_panic("failure to define FLAT?!");
+ }
+ seg->grp = grp;
+ } else if (!nasm_strnicmp(p, "class=", 6))
+ seg->segclass = nasm_strdup(p + 6);
+ else if (!nasm_strnicmp(p, "overlay=", 8))
+ seg->overlay = nasm_strdup(p + 8);
+ else if (!nasm_strnicmp(p, "align=", 6)) {
+ seg->align = readnum(p + 6, &rn_error);
+ if (rn_error) {
+ seg->align = 1;
+ nasm_nonfatal("segment alignment should be numeric");
+ }
+ switch (seg->align) {
+ case 1: /* BYTE */
+ case 2: /* WORD */
+ case 4: /* DWORD */
+ case 16: /* PARA */
+ case 256: /* PAGE */
+ case 4096: /* PharLap extension */
+ break;
+ case 8:
+ nasm_warn(WARN_OTHER, "OBJ format does not support alignment"
+ " of 8: rounding up to 16");
+ seg->align = 16;
+ break;
+ case 32:
+ case 64:
+ case 128:
+ nasm_warn(WARN_OTHER, "OBJ format does not support alignment"
+ " of %d: rounding up to 256", seg->align);
+ seg->align = 256;
+ break;
+ case 512:
+ case 1024:
+ case 2048:
+ nasm_warn(WARN_OTHER, "OBJ format does not support alignment"
+ " of %d: rounding up to 4096", seg->align);
+ seg->align = 4096;
+ break;
+ default:
+ nasm_nonfatal("invalid alignment value %d",
+ seg->align);
+ seg->align = 1;
+ break;
+ }
+ } else if (!nasm_strnicmp(p, "absolute=", 9)) {
+ seg->align = SEG_ABS + readnum(p + 9, &rn_error);
+ if (rn_error)
+ nasm_nonfatal("argument to `absolute' segment"
+ " attribute should be numeric");
+ }
+ }
+
+ /* We need to know whenever we have at least one 32-bit segment */
+ obj_use32 |= seg->use32;
+
+ obj_seg_needs_update = seg;
+ if (seg->align >= SEG_ABS)
+ define_label(name, NO_SEG, seg->align - SEG_ABS, false);
+ else
+ define_label(name, seg->index + 1, 0L, false);
+ obj_seg_needs_update = NULL;
+
+ /*
+ * See if this segment is defined in any groups.
+ */
+ for (grp = grphead; grp; grp = grp->next) {
+ for (i = grp->nindices; i < grp->nentries; i++) {
+ if (!strcmp(grp->segs[i].name, seg->name)) {
+ nasm_free(grp->segs[i].name);
+ grp->segs[i] = grp->segs[grp->nindices];
+ grp->segs[grp->nindices++].index = seg->obj_index;
+ if (seg->grp)
+ nasm_warn(WARN_OTHER, "segment `%s' is already part of"
+ " a group: first one takes precedence",
+ seg->name);
+ else
+ seg->grp = grp;
+ }
+ }
+ }
+
+ /*
+ * Walk through the list of externals with unresolved
+ * default-WRT clauses, and resolve any that point at this
+ * segment.
+ */
+ extp = &dws;
+ while (*extp) {
+ if ((*extp)->defwrt_type == DEFWRT_STRING &&
+ !strcmp((*extp)->defwrt_ptr.string, seg->name)) {
+ nasm_free((*extp)->defwrt_ptr.string);
+ (*extp)->defwrt_type = DEFWRT_SEGMENT;
+ (*extp)->defwrt_ptr.seg = seg;
+ *extp = (*extp)->next_dws;
+ } else
+ extp = &(*extp)->next_dws;
+ }
+
+ if (seg->use32)
+ *bits = 32;
+ else
+ *bits = 16;
+ current_seg = seg;
+ return seg->index;
+ }
+}
+
+static enum directive_result
+obj_directive(enum directive directive, char *value)
+{
+ switch (directive) {
+ case D_GROUP:
+ {
+ char *p, *q, *v;
+ if (pass_first()) { /* XXX */
+ struct Group *grp;
+ struct Segment *seg;
+ struct External **extp;
+ int obj_idx;
+
+ q = value;
+ while (*q == '.')
+ q++; /* hack, but a documented one */
+ v = q;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+ /*
+ * Here we used to sanity-check the group directive to
+ * ensure nobody tried to declare a group containing no
+ * segments. However, OS/2 does this as standard
+ * practice, so the sanity check has been removed.
+ *
+ * if (!*q) {
+ * nasm_error(ERR_NONFATAL,"GROUP directive contains no segments");
+ * return DIRR_ERROR;
+ * }
+ */
+
+ obj_idx = 1;
+ for (grp = grphead; grp; grp = grp->next) {
+ obj_idx++;
+ if (!strcmp(grp->name, v)) {
+ nasm_nonfatal("group `%s' defined twice", v);
+ return DIRR_ERROR;
+ }
+ }
+
+ *grptail = grp = nasm_malloc(sizeof(*grp));
+ grp->next = NULL;
+ grptail = &grp->next;
+ grp->index = seg_alloc();
+ grp->obj_index = obj_idx;
+ grp->nindices = grp->nentries = 0;
+ grp->name = NULL;
+
+ obj_grp_needs_update = grp;
+ backend_label(v, grp->index + 1, 0L);
+ obj_grp_needs_update = NULL;
+
+ while (*q) {
+ p = q;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+ /*
+ * Now p contains a segment name. Find it.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (!strcmp(seg->name, p))
+ break;
+ if (seg) {
+ /*
+ * We have a segment index. Shift a name entry
+ * to the end of the array to make room.
+ */
+ grp->segs[grp->nentries++] = grp->segs[grp->nindices];
+ grp->segs[grp->nindices++].index = seg->obj_index;
+ if (seg->grp)
+ nasm_warn(WARN_OTHER, "segment `%s' is already part of"
+ " a group: first one takes precedence",
+ seg->name);
+ else
+ seg->grp = grp;
+ } else {
+ /*
+ * We have an as-yet undefined segment.
+ * Remember its name, for later.
+ */
+ grp->segs[grp->nentries++].name = nasm_strdup(p);
+ }
+ }
+
+ /*
+ * Walk through the list of externals with unresolved
+ * default-WRT clauses, and resolve any that point at
+ * this group.
+ */
+ extp = &dws;
+ while (*extp) {
+ if ((*extp)->defwrt_type == DEFWRT_STRING &&
+ !strcmp((*extp)->defwrt_ptr.string, grp->name)) {
+ nasm_free((*extp)->defwrt_ptr.string);
+ (*extp)->defwrt_type = DEFWRT_GROUP;
+ (*extp)->defwrt_ptr.grp = grp;
+ *extp = (*extp)->next_dws;
+ } else
+ extp = &(*extp)->next_dws;
+ }
+ }
+ return DIRR_OK;
+ }
+ case D_UPPERCASE:
+ obj_uppercase = true;
+ return DIRR_OK;
+
+ case D_IMPORT:
+ {
+ char *q, *extname, *libname, *impname;
+
+ if (!pass_first()) /* XXX */
+ return DIRR_OK;
+ extname = q = value;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+
+ libname = q;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+
+ impname = q;
+
+ if (!*extname || !*libname)
+ nasm_nonfatal("`import' directive requires symbol name"
+ " and library name");
+ else {
+ struct ImpDef *imp;
+ bool err = false;
+
+ imp = *imptail = nasm_malloc(sizeof(struct ImpDef));
+ imptail = &imp->next;
+ imp->next = NULL;
+ imp->extname = nasm_strdup(extname);
+ imp->libname = nasm_strdup(libname);
+ imp->impindex = readnum(impname, &err);
+ if (!*impname || err)
+ imp->impname = nasm_strdup(impname);
+ else
+ imp->impname = NULL;
+ }
+
+ return DIRR_OK;
+ }
+ case D_EXPORT:
+ {
+ char *q, *extname, *intname, *v;
+ struct ExpDef *export;
+ int flags = 0;
+ unsigned int ordinal = 0;
+
+ if (!pass_first())
+ return DIRR_OK; /* ignore in pass two */
+ intname = q = value;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+
+ extname = q;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+
+ if (!*intname) {
+ nasm_nonfatal("`export' directive requires export name");
+ return DIRR_OK;
+ }
+ if (!*extname) {
+ extname = intname;
+ intname = "";
+ }
+ while (*q) {
+ v = q;
+ while (*q && !nasm_isspace(*q))
+ q++;
+ if (nasm_isspace(*q)) {
+ *q++ = '\0';
+ while (*q && nasm_isspace(*q))
+ q++;
+ }
+ if (!nasm_stricmp(v, "resident"))
+ flags |= EXPDEF_FLAG_RESIDENT;
+ else if (!nasm_stricmp(v, "nodata"))
+ flags |= EXPDEF_FLAG_NODATA;
+ else if (!nasm_strnicmp(v, "parm=", 5)) {
+ bool err = false;
+ flags |= EXPDEF_MASK_PARMCNT & readnum(v + 5, &err);
+ if (err) {
+ nasm_nonfatal("value `%s' for `parm' is non-numeric", v + 5);
+ return DIRR_ERROR;
+ }
+ } else {
+ bool err = false;
+ ordinal = readnum(v, &err);
+ if (err) {
+ nasm_nonfatal("unrecognised export qualifier `%s'", v);
+ return DIRR_ERROR;
+ }
+ flags |= EXPDEF_FLAG_ORDINAL;
+ }
+ }
+
+ export = *exptail = nasm_malloc(sizeof(struct ExpDef));
+ exptail = &export->next;
+ export->next = NULL;
+ export->extname = nasm_strdup(extname);
+ export->intname = nasm_strdup(intname);
+ export->ordinal = ordinal;
+ export->flags = flags;
+
+ return DIRR_OK;
+ }
+ default:
+ return DIRR_UNKNOWN;
+ }
+}
+
+static void obj_sectalign(int32_t seg, unsigned int value)
+{
+ struct Segment *s;
+
+ list_for_each(s, seghead) {
+ if (s->index == seg)
+ break;
+ }
+
+ /*
+ * it should not be too big value
+ * and applied on non-absolute sections
+ */
+ if (!s || !is_power2(value) ||
+ value > 4096 || s->align >= SEG_ABS)
+ return;
+
+ /*
+ * FIXME: No code duplication please
+ * consider making helper for this
+ * mapping since section handler has
+ * to do the same
+ */
+ switch (value) {
+ case 8:
+ value = 16;
+ break;
+ case 32:
+ case 64:
+ case 128:
+ value = 256;
+ break;
+ case 512:
+ case 1024:
+ case 2048:
+ value = 4096;
+ break;
+ }
+
+ if (s->align < (int)value)
+ s->align = value;
+}
+
+static int32_t obj_segbase(int32_t segment)
+{
+ struct Segment *seg;
+
+ /*
+ * Find the segment in our list.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment - 1)
+ break;
+
+ if (!seg) {
+ /*
+ * Might be an external with a default WRT.
+ */
+ int32_t i = segment / 2;
+ struct ExtBack *eb = ebhead;
+ struct External *e;
+
+ while (i >= EXT_BLKSIZ) {
+ if (eb)
+ eb = eb->next;
+ else
+ break;
+ i -= EXT_BLKSIZ;
+ }
+ if (eb) {
+ e = eb->exts[i];
+ if (!e) {
+ /* Not available yet, probably a forward reference */
+ nasm_assert(!pass_final());
+ return NO_SEG;
+ }
+
+ switch (e->defwrt_type) {
+ case DEFWRT_NONE:
+ return segment; /* fine */
+ case DEFWRT_SEGMENT:
+ return e->defwrt_ptr.seg->index + 1;
+ case DEFWRT_GROUP:
+ return e->defwrt_ptr.grp->index + 1;
+ default:
+ return NO_SEG; /* can't tell what it is */
+ }
+ }
+
+ return segment; /* not one of ours - leave it alone */
+ }
+
+ if (seg->align >= SEG_ABS)
+ return seg->align; /* absolute segment */
+ if (seg->grp)
+ return seg->grp->index + 1; /* grouped segment */
+
+ return segment; /* no special treatment */
+}
+
+/* Get a file timestamp in MS-DOS format */
+static uint32_t obj_file_timestamp(const char *pathname)
+{
+ time_t t;
+ const struct tm *lt;
+
+ if (!nasm_file_time(&t, pathname))
+ return 0;
+
+ lt = localtime(&t);
+ if (!lt)
+ return 0;
+
+ if (lt->tm_year < 80 || lt->tm_year > 207)
+ return 0; /* Only years 1980-2107 representable */
+
+ return
+ ((uint32_t)lt->tm_sec >> 1) +
+ ((uint32_t)lt->tm_min << 5) +
+ ((uint32_t)lt->tm_hour << 11) +
+ ((uint32_t)lt->tm_mday << 16) +
+ (((uint32_t)lt->tm_mon + 1) << 21) +
+ (((uint32_t)lt->tm_year - 80) << 25);
+}
+
+static void obj_write_file(void)
+{
+ struct Segment *seg, *entry_seg_ptr = 0;
+ struct FileName *fn;
+ struct LineNumber *ln;
+ struct Group *grp;
+ struct Public *pub, *loc;
+ struct External *ext;
+ struct ImpDef *imp;
+ struct ExpDef *export;
+ int lname_idx;
+ ObjRecord *orp;
+ const struct strlist_entry *depfile;
+ const bool debuginfo = (dfmt == &borland_debug_form);
+
+ /*
+ * Write the THEADR module header.
+ */
+ orp = obj_new();
+ orp->type = THEADR;
+ obj_name(orp, obj_infile);
+ obj_emit2(orp);
+
+ /*
+ * Write the NASM boast comment.
+ */
+ orp->type = COMENT;
+ obj_rword(orp, dTRANSL);
+ obj_name(orp, nasm_comment());
+ obj_emit2(orp);
+
+ /*
+ * Output file dependency information
+ */
+ if (!obj_nodepend && depend_list) {
+ strlist_for_each(depfile, depend_list) {
+ uint32_t ts;
+
+ ts = obj_file_timestamp(depfile->str);
+ if (ts) {
+ orp->type = COMENT;
+ obj_rword(orp, dDEPFILE);
+ obj_dword(orp, ts);
+ obj_name(orp, depfile->str);
+ obj_emit2(orp);
+ }
+ }
+ }
+
+ orp->type = COMENT;
+ /*
+ * Write the IMPDEF records, if any.
+ */
+ for (imp = imphead; imp; imp = imp->next) {
+ obj_rword(orp, dOMFEXT);
+ obj_byte(orp, 1); /* subfunction 1: IMPDEF */
+ if (imp->impname)
+ obj_byte(orp, 0); /* import by name */
+ else
+ obj_byte(orp, 1); /* import by ordinal */
+ obj_name(orp, imp->extname);
+ obj_name(orp, imp->libname);
+ if (imp->impname)
+ obj_name(orp, imp->impname);
+ else
+ obj_word(orp, imp->impindex);
+ obj_emit2(orp);
+ }
+
+ /*
+ * Write the EXPDEF records, if any.
+ */
+ for (export = exphead; export; export = export->next) {
+ obj_rword(orp, dOMFEXT);
+ obj_byte(orp, 2); /* subfunction 2: EXPDEF */
+ obj_byte(orp, export->flags);
+ obj_name(orp, export->extname);
+ obj_name(orp, export->intname);
+ if (export->flags & EXPDEF_FLAG_ORDINAL)
+ obj_word(orp, export->ordinal);
+ obj_emit2(orp);
+ }
+
+ /* we're using extended OMF if we put in debug info */
+ if (debuginfo) {
+ orp->type = COMENT;
+ obj_rword(orp, dEXTENDED);
+ obj_emit2(orp);
+ }
+
+ /*
+ * Write the first LNAMES record, containing LNAME one, which
+ * is null. Also initialize the LNAME counter.
+ */
+ orp->type = LNAMES;
+ obj_byte(orp, 0);
+ lname_idx = 1;
+ /*
+ * Write some LNAMES for the segment names
+ */
+ for (seg = seghead; seg; seg = seg->next) {
+ orp = obj_name(orp, seg->name);
+ if (seg->segclass)
+ orp = obj_name(orp, seg->segclass);
+ if (seg->overlay)
+ orp = obj_name(orp, seg->overlay);
+ obj_commit(orp);
+ }
+ /*
+ * Write some LNAMES for the group names
+ */
+ for (grp = grphead; grp; grp = grp->next) {
+ orp = obj_name(orp, grp->name);
+ obj_commit(orp);
+ }
+ obj_emit(orp);
+
+ /*
+ * Write the SEGDEF records.
+ */
+ orp->type = SEGDEF;
+ for (seg = seghead; seg; seg = seg->next) {
+ int acbp;
+ uint32_t seglen = seg->currentpos;
+
+ acbp = (seg->combine << 2); /* C field */
+
+ if (seg->use32)
+ acbp |= 0x01; /* P bit is Use32 flag */
+ else if (seglen == 0x10000L) {
+ seglen = 0; /* This special case may be needed for old linkers */
+ acbp |= 0x02; /* B bit */
+ }
+
+ /* A field */
+ if (seg->align >= SEG_ABS)
+ /* acbp |= 0x00 */ ;
+ else if (seg->align >= 4096) {
+ if (seg->align > 4096)
+ nasm_nonfatal("segment `%s' requires more alignment"
+ " than OBJ format supports", seg->name);
+ acbp |= 0xC0; /* PharLap extension */
+ } else if (seg->align >= 256) {
+ acbp |= 0x80;
+ } else if (seg->align >= 16) {
+ acbp |= 0x60;
+ } else if (seg->align >= 4) {
+ acbp |= 0xA0;
+ } else if (seg->align >= 2) {
+ acbp |= 0x40;
+ } else
+ acbp |= 0x20;
+
+ obj_byte(orp, acbp);
+ if (seg->align & SEG_ABS) {
+ obj_x(orp, seg->align - SEG_ABS); /* Frame */
+ obj_byte(orp, 0); /* Offset */
+ }
+ obj_x(orp, seglen);
+ obj_index(orp, ++lname_idx);
+ obj_index(orp, seg->segclass ? ++lname_idx : 1);
+ obj_index(orp, seg->overlay ? ++lname_idx : 1);
+ obj_emit2(orp);
+ }
+
+ /*
+ * Write the GRPDEF records.
+ */
+ orp->type = GRPDEF;
+ for (grp = grphead; grp; grp = grp->next) {
+ int i;
+
+ if (grp->nindices != grp->nentries) {
+ for (i = grp->nindices; i < grp->nentries; i++) {
+ nasm_nonfatal("group `%s' contains undefined segment"
+ " `%s'", grp->name, grp->segs[i].name);
+ nasm_free(grp->segs[i].name);
+ grp->segs[i].name = NULL;
+ }
+ }
+ obj_index(orp, ++lname_idx);
+ for (i = 0; i < grp->nindices; i++) {
+ obj_byte(orp, 0xFF);
+ obj_index(orp, grp->segs[i].index);
+ }
+ obj_emit2(orp);
+ }
+
+ /*
+ * Write the PUBDEF records: first the ones in the segments,
+ * then the far-absolutes.
+ */
+ orp->type = PUBDEF;
+ orp->ori = ori_pubdef;
+ for (seg = seghead; seg; seg = seg->next) {
+ orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+ orp->parm[1] = seg->obj_index;
+ for (pub = seg->pubhead; pub; pub = pub->next) {
+ orp = obj_name(orp, pub->name);
+ orp = obj_x(orp, pub->offset);
+ orp = obj_byte(orp, 0); /* type index */
+ obj_commit(orp);
+ }
+ obj_emit(orp);
+ }
+ orp->parm[0] = 0;
+ orp->parm[1] = 0;
+ for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
+ if (orp->parm[2] != (uint32_t)pub->segment) {
+ obj_emit(orp);
+ orp->parm[2] = pub->segment;
+ }
+ orp = obj_name(orp, pub->name);
+ orp = obj_x(orp, pub->offset);
+ orp = obj_byte(orp, 0); /* type index */
+ obj_commit(orp);
+ }
+ obj_emit(orp);
+
+ /*
+ * Write the EXTDEF and COMDEF records, in order.
+ */
+ orp->ori = ori_null;
+ for (ext = exthead; ext; ext = ext->next) {
+ if (ext->commonsize == 0) {
+ if (orp->type != EXTDEF) {
+ obj_emit(orp);
+ orp->type = EXTDEF;
+ }
+ orp = obj_name(orp, ext->name);
+ orp = obj_index(orp, 0);
+ } else {
+ if (orp->type != COMDEF) {
+ obj_emit(orp);
+ orp->type = COMDEF;
+ }
+ orp = obj_name(orp, ext->name);
+ orp = obj_index(orp, 0);
+ if (ext->commonelem) {
+ orp = obj_byte(orp, 0x61); /* far communal */
+ orp = obj_value(orp, (ext->commonsize / ext->commonelem));
+ orp = obj_value(orp, ext->commonelem);
+ } else {
+ orp = obj_byte(orp, 0x62); /* near communal */
+ orp = obj_value(orp, ext->commonsize);
+ }
+ }
+ obj_commit(orp);
+ }
+ obj_emit(orp);
+
+ /*
+ * Write a COMENT record stating that the linker's first pass
+ * may stop processing at this point. Exception is if our
+ * MODEND record specifies a start point, in which case,
+ * according to some variants of the documentation, this COMENT
+ * should be omitted. So we'll omit it just in case.
+ * But, TASM puts it in all the time so if we are using
+ * TASM debug stuff we are putting it in
+ */
+ if (debuginfo || obj_entry_seg == NO_SEG) {
+ orp->type = COMENT;
+ obj_rword(orp, dLINKPASS);
+ obj_byte(orp, 1);
+ obj_emit2(orp);
+ }
+
+ /*
+ * 1) put out the compiler type
+ * 2) Put out the type info. The only type we are using is near label #19
+ */
+ if (debuginfo) {
+ int i;
+ struct Array *arrtmp = arrhead;
+ orp->type = COMENT;
+ obj_rword(orp, dCOMPDEF);
+ obj_byte(orp, 4);
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x18); /* type # for linking */
+ obj_word(orp, 6); /* size of type */
+ obj_byte(orp, 0x2a); /* absolute type for debugging */
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x19); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x24); /* absolute type for debugging */
+ obj_byte(orp, 0); /* near/far specifier */
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x1A); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x24); /* absolute type for debugging */
+ obj_byte(orp, 1); /* near/far specifier */
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x1b); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x23); /* absolute type for debugging */
+ obj_byte(orp, 0);
+ obj_byte(orp, 0);
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x1c); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x23); /* absolute type for debugging */
+ obj_byte(orp, 0);
+ obj_byte(orp, 4);
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x1d); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x23); /* absolute type for debugging */
+ obj_byte(orp, 0);
+ obj_byte(orp, 1);
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, 0x1e); /* type # for linking */
+ obj_word(orp, 0); /* size of type */
+ obj_byte(orp, 0x23); /* absolute type for debugging */
+ obj_byte(orp, 0);
+ obj_byte(orp, 5);
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+
+ /* put out the array types */
+ for (i = ARRAYBOT; i < arrindex; i++) {
+ obj_rword(orp, dTYPEDEF);
+ obj_word(orp, i); /* type # for linking */
+ obj_word(orp, arrtmp->size); /* size of type */
+ obj_byte(orp, 0x1A); /* absolute type for debugging (array) */
+ obj_byte(orp, arrtmp->basetype); /* base type */
+ obj_emit2(orp);
+ arrtmp = arrtmp->next;
+ }
+ }
+ /*
+ * write out line number info with a LINNUM record
+ * switch records when we switch segments, and output the
+ * file in a pseudo-TASM fashion. The record switch is naive; that
+ * is that one file may have many records for the same segment
+ * if there are lots of segment switches
+ */
+ if (fnhead && debuginfo) {
+ seg = fnhead->lnhead->segment;
+
+ for (fn = fnhead; fn; fn = fn->next) {
+ /* write out current file name */
+ orp->type = COMENT;
+ orp->ori = ori_null;
+ obj_rword(orp, dFILNAME);
+ obj_byte(orp, 0);
+ obj_name(orp, fn->name);
+ obj_dword(orp, 0);
+ obj_emit2(orp);
+
+ /* write out line numbers this file */
+
+ orp->type = LINNUM;
+ orp->ori = ori_linnum;
+ for (ln = fn->lnhead; ln; ln = ln->next) {
+ if (seg != ln->segment) {
+ /* if we get here have to flush the buffer and start
+ * a new record for a new segment
+ */
+ seg = ln->segment;
+ obj_emit(orp);
+ }
+ orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+ orp->parm[1] = seg->obj_index;
+ orp = obj_word(orp, ln->lineno);
+ orp = obj_x(orp, ln->offset);
+ obj_commit(orp);
+ }
+ obj_emit(orp);
+ }
+ }
+ /*
+ * we are going to locate the entry point segment now
+ * rather than wait until the MODEND record, because,
+ * then we can output a special symbol to tell where the
+ * entry point is.
+ *
+ */
+ if (obj_entry_seg != NO_SEG) {
+ for (seg = seghead; seg; seg = seg->next) {
+ if (seg->index == obj_entry_seg) {
+ entry_seg_ptr = seg;
+ break;
+ }
+ }
+ if (!seg)
+ nasm_nonfatal("entry point is not in this module");
+ }
+
+ /*
+ * get ready to put out symbol records
+ */
+ orp->type = COMENT;
+ orp->ori = ori_local;
+
+ /*
+ * put out a symbol for the entry point
+ * no dots in this symbol, because, borland does
+ * not (officially) support dots in label names
+ * and I don't know what various versions of TLINK will do
+ */
+ if (debuginfo && obj_entry_seg != NO_SEG) {
+ orp = obj_name(orp, "start_of_program");
+ orp = obj_word(orp, 0x19); /* type: near label */
+ orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0);
+ orp = obj_index(orp, seg->obj_index);
+ orp = obj_x(orp, obj_entry_ofs);
+ obj_commit(orp);
+ }
+
+ /*
+ * put out the local labels
+ */
+ for (seg = seghead; seg && debuginfo; seg = seg->next) {
+ /* labels this seg */
+ for (loc = seg->lochead; loc; loc = loc->next) {
+ orp = obj_name(orp, loc->name);
+ orp = obj_word(orp, loc->type);
+ orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0);
+ orp = obj_index(orp, seg->obj_index);
+ orp = obj_x(orp, loc->offset);
+ obj_commit(orp);
+ }
+ }
+ if (orp->used)
+ obj_emit(orp);
+
+ /*
+ * Write the LEDATA/FIXUPP pairs.
+ */
+ for (seg = seghead; seg; seg = seg->next) {
+ obj_emit(seg->orp);
+ nasm_free(seg->orp);
+ }
+
+ /*
+ * Write the MODEND module end marker.
+ */
+ orp->type = obj_use32 ? MODE32 : MODEND;
+ orp->ori = ori_null;
+ if (entry_seg_ptr) {
+ orp->type = entry_seg_ptr->use32 ? MODE32 : MODEND;
+ obj_byte(orp, 0xC1);
+ seg = entry_seg_ptr;
+ if (seg->grp) {
+ obj_byte(orp, 0x10);
+ obj_index(orp, seg->grp->obj_index);
+ } else {
+ /*
+ * the below changed to prevent TLINK crashing.
+ * Previous more efficient version read:
+ *
+ * obj_byte (orp, 0x50);
+ */
+ obj_byte(orp, 0x00);
+ obj_index(orp, seg->obj_index);
+ }
+ obj_index(orp, seg->obj_index);
+ obj_x(orp, obj_entry_ofs);
+ } else
+ obj_byte(orp, 0);
+ obj_emit2(orp);
+ nasm_free(orp);
+}
+
+static void obj_fwrite(ObjRecord * orp)
+{
+ unsigned int cksum, len;
+ uint8_t *ptr;
+
+ cksum = orp->type;
+ if (orp->x_size == 32)
+ cksum |= 1;
+ fputc(cksum, ofile);
+ len = orp->committed + 1;
+ cksum += (len & 0xFF) + ((len >> 8) & 0xFF);
+ fwriteint16_t(len, ofile);
+ nasm_write(orp->buf, len-1, ofile);
+ for (ptr = orp->buf; --len; ptr++)
+ cksum += *ptr;
+ fputc((-cksum) & 0xFF, ofile);
+}
+
+static enum directive_result
+obj_pragma(const struct pragma *pragma)
+{
+ switch (pragma->opcode) {
+ case D_NODEPEND:
+ obj_nodepend = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return DIRR_OK;
+}
+
+extern macros_t obj_stdmac[];
+
+static void dbgbi_init(void)
+{
+ fnhead = NULL;
+ fntail = &fnhead;
+ arrindex = ARRAYBOT;
+ arrhead = NULL;
+ arrtail = &arrhead;
+}
+static void dbgbi_cleanup(void)
+{
+ struct Segment *segtmp;
+ while (fnhead) {
+ struct FileName *fntemp = fnhead;
+ while (fnhead->lnhead) {
+ struct LineNumber *lntemp = fnhead->lnhead;
+ fnhead->lnhead = lntemp->next;
+ nasm_free(lntemp);
+ }
+ fnhead = fnhead->next;
+ nasm_free(fntemp->name);
+ nasm_free(fntemp);
+ }
+ for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
+ while (segtmp->lochead) {
+ struct Public *loctmp = segtmp->lochead;
+ segtmp->lochead = loctmp->next;
+ nasm_free(loctmp->name);
+ nasm_free(loctmp);
+ }
+ }
+ while (arrhead) {
+ struct Array *arrtmp = arrhead;
+ arrhead = arrhead->next;
+ nasm_free(arrtmp);
+ }
+}
+
+static void dbgbi_linnum(const char *lnfname, int32_t lineno, int32_t segto)
+{
+ struct FileName *fn;
+ struct LineNumber *ln;
+ struct Segment *seg;
+
+ if (segto == NO_SEG)
+ return;
+
+ /*
+ * If `any_segs' is still false, we must define a default
+ * segment.
+ */
+ if (!any_segs) {
+ int tempint = 0;
+ if (segto != obj_segment("__NASMDEFSEG", &tempint))
+ nasm_panic("strange segment conditions in OBJ driver");
+ }
+
+ /*
+ * Find the segment we are targeting.
+ */
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segto)
+ break;
+ if (!seg)
+ nasm_panic("lineno directed to nonexistent segment?");
+
+/* for (fn = fnhead; fn; fn = fnhead->next) */
+ for (fn = fnhead; fn; fn = fn->next) /* fbk - Austin Lunnen - John Fine */
+ if (!nasm_stricmp(lnfname, fn->name))
+ break;
+ if (!fn) {
+ fn = nasm_malloc(sizeof(*fn));
+ fn->name = nasm_malloc(strlen(lnfname) + 1);
+ strcpy(fn->name, lnfname);
+ fn->lnhead = NULL;
+ fn->lntail = &fn->lnhead;
+ fn->next = NULL;
+ *fntail = fn;
+ fntail = &fn->next;
+ }
+ ln = nasm_malloc(sizeof(*ln));
+ ln->segment = seg;
+ ln->offset = seg->currentpos;
+ ln->lineno = lineno;
+ ln->next = NULL;
+ *fn->lntail = ln;
+ fn->lntail = &ln->next;
+
+}
+static void dbgbi_deflabel(char *name, int32_t segment,
+ int64_t offset, int is_global, char *special)
+{
+ struct Segment *seg;
+
+ (void)special;
+
+ /*
+ * Note: ..[^@] special symbols are filtered in labels.c
+ */
+
+ /*
+ * If it's a special-retry from pass two, discard it.
+ */
+ if (is_global == 3)
+ return;
+
+ /*
+ * Case (i):
+ */
+ if (obj_seg_needs_update) {
+ return;
+ } else if (obj_grp_needs_update) {
+ return;
+ }
+ if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+ return;
+
+ if (segment >= SEG_ABS || segment == NO_SEG) {
+ return;
+ }
+
+ /*
+ * If `any_segs' is still false, we might need to define a
+ * default segment, if they're trying to declare a label in
+ * `first_seg'. But the label should exist due to a prior
+ * call to obj_deflabel so we can skip that.
+ */
+
+ for (seg = seghead; seg; seg = seg->next)
+ if (seg->index == segment) {
+ struct Public *loc = nasm_malloc(sizeof(*loc));
+ /*
+ * Case (ii). Maybe MODPUB someday?
+ */
+ last_defined = *seg->loctail = loc;
+ seg->loctail = &loc->next;
+ loc->next = NULL;
+ loc->name = nasm_strdup(name);
+ loc->offset = offset;
+ }
+}
+static void dbgbi_typevalue(int32_t type)
+{
+ int vsize;
+ int elem = TYM_ELEMENTS(type);
+ type = TYM_TYPE(type);
+
+ if (!last_defined)
+ return;
+
+ switch (type) {
+ case TY_BYTE:
+ last_defined->type = 8; /* uint8_t */
+ vsize = 1;
+ break;
+ case TY_WORD:
+ last_defined->type = 10; /* unsigned word */
+ vsize = 2;
+ break;
+ case TY_DWORD:
+ last_defined->type = 12; /* unsigned dword */
+ vsize = 4;
+ break;
+ case TY_FLOAT:
+ last_defined->type = 14; /* float */
+ vsize = 4;
+ break;
+ case TY_QWORD:
+ last_defined->type = 15; /* qword */
+ vsize = 8;
+ break;
+ case TY_TBYTE:
+ last_defined->type = 16; /* TBYTE */
+ vsize = 10;
+ break;
+ default:
+ last_defined->type = 0x19; /* label */
+ vsize = 0;
+ break;
+ }
+
+ if (elem > 1) {
+ struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp));
+ int vtype = last_defined->type;
+ arrtmp->size = vsize * elem;
+ arrtmp->basetype = vtype;
+ arrtmp->next = NULL;
+ last_defined->type = arrindex++;
+ *arrtail = arrtmp;
+ arrtail = &(arrtmp->next);
+ }
+ last_defined = NULL;
+}
+static void dbgbi_output(int output_type, void *param)
+{
+ (void)output_type;
+ (void)param;
+}
+static const struct dfmt borland_debug_form = {
+ "Borland Debug Records",
+ "borland",
+ dbgbi_init,
+ dbgbi_linnum,
+ dbgbi_deflabel,
+ NULL, /* .debug_smacros */
+ NULL, /* .debug_include */
+ NULL, /* .debug_mmacros */
+ null_debug_directive,
+ dbgbi_typevalue,
+ dbgbi_output,
+ dbgbi_cleanup,
+ NULL /* pragma list */
+};
+
+static const struct dfmt * const borland_debug_arr[3] = {
+ &borland_debug_form,
+ &null_debug_form,
+ NULL
+};
+
+static const struct pragma_facility obj_pragma_list[] = {
+ { NULL, obj_pragma }
+};
+
+const struct ofmt of_obj = {
+ "Intel/Microsoft OMF (MS-DOS, OS/2, Win16)",
+ "obj",
+ ".obj",
+ 0,
+ 32,
+ borland_debug_arr,
+ &borland_debug_form,
+ obj_stdmac,
+ obj_init,
+ null_reset,
+ nasm_do_legacy_output,
+ obj_out,
+ obj_deflabel,
+ obj_segment,
+ NULL,
+ obj_sectalign,
+ obj_segbase,
+ obj_directive,
+ obj_cleanup,
+ obj_pragma_list
+};
+#endif /* OF_OBJ */
diff --git a/vere/ext/nasm/output/outobj.mac b/vere/ext/nasm/output/outobj.mac
new file mode 100644
index 0000000..09158f2
--- /dev/null
+++ b/vere/ext/nasm/output/outobj.mac
@@ -0,0 +1,49 @@
+;; --------------------------------------------------------------------------
+;;
+;; Copyright 1996-2009 The NASM Authors - All Rights Reserved
+;; See the file AUTHORS included with the NASM distribution for
+;; the specific copyright holders.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following
+;; conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above
+;; 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
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+;; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+;; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+;; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+;; --------------------------------------------------------------------------
+
+OUT: obj
+%define __?SECT?__ [section .text]
+%imacro group 1+.nolist
+[group %1]
+%endmacro
+%imacro uppercase 0+.nolist
+[uppercase %1]
+%endmacro
+%imacro export 1+.nolist
+[export %1]
+%endmacro
+%imacro import 1+.nolist
+[import %1]
+%endmacro
+%macro __?NASM_CDecl?__ 1
+%endmacro
diff --git a/vere/ext/nasm/output/pecoff.h b/vere/ext/nasm/output/pecoff.h
new file mode 100644
index 0000000..b99bed0
--- /dev/null
+++ b/vere/ext/nasm/output/pecoff.h
@@ -0,0 +1,542 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2020 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef PECOFF_H
+#define PECOFF_H
+
+/*
+ * Microsoft Portable Executable and Common Object
+ * File Format Specification
+ *
+ * Revision 8.1 – February 15, 2008
+ */
+
+/*
+ * Machine types
+ */
+#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000
+#define IMAGE_FILE_MACHINE_AM33 0x01d3
+#define IMAGE_FILE_MACHINE_AMD64 0x8664
+#define IMAGE_FILE_MACHINE_EBC 0x0ebc
+#define IMAGE_FILE_MACHINE_M32R 0x9041
+#define IMAGE_FILE_MACHINE_ALPHA 0x0184
+#define IMAGE_FILE_MACHINE_ARM 0x01c0
+#define IMAGE_FILE_MACHINE_ALPHA64 0x0284
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_IA64 0x0200
+#define IMAGE_FILE_MACHINE_M68K 0x0268
+#define IMAGE_FILE_MACHINE_MIPS16 0x0266
+#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
+#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
+#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
+#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
+#define IMAGE_FILE_MACHINE_R3000 0x0162
+#define IMAGE_FILE_MACHINE_R4000 0x0166
+#define IMAGE_FILE_MACHINE_R10000 0x0168
+#define IMAGE_FILE_MACHINE_SH3 0x01a2
+#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
+#define IMAGE_FILE_MACHINE_SH4 0x01a6
+#define IMAGE_FILE_MACHINE_SH5 0x01a8
+#define IMAGE_FILE_MACHINE_THUMB 0x01c2
+#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
+#define IMAGE_FILE_MACHINE_MASK 0xffff
+
+/*
+ * Characteristics
+ */
+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
+#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
+#define IMAGE_FILE_32BIT_MACHINE 0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
+#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
+#define IMAGE_FILE_SYSTEM 0x1000
+#define IMAGE_FILE_DLL 0x2000
+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
+
+/*
+ * Windows subsystem
+ */
+#define IMAGE_SUBSYSTEM_UNKNOWN 0
+#define IMAGE_SUBSYSTEM_NATIVE 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define IMAGE_SUBSYSTEM_EFI_ROM 13
+#define IMAGE_SUBSYSTEM_XBOX 14
+
+/*
+ * DLL characteristics
+ */
+#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
+#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
+#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
+#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
+#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
+#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
+#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
+#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
+
+/*
+ * Section flags
+ */
+#define IMAGE_SCN_TYPE_REG 0x00000000
+#define IMAGE_SCN_TYPE_DSECT 0x00000001
+#define IMAGE_SCN_TYPE_NOLOAD 0x00000002
+#define IMAGE_SCN_TYPE_GROUP 0x00000004
+#define IMAGE_SCN_TYPE_NO_PAD 0x00000008
+#define IMAGE_SCN_TYPE_COPY 0x00000010
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+
+#define IMAGE_SCN_LNK_OTHER 0x00000100
+#define IMAGE_SCN_LNK_INFO 0x00000200
+#define IMAGE_SCN_TYPE_OVER 0x00000400
+#define IMAGE_SCN_LNK_REMOVE 0x00000800
+#define IMAGE_SCN_LNK_COMDAT 0x00001000
+
+#define IMAGE_SCN_MAX_RELOC 0xffff
+
+#define IMAGE_SCN_MEM_FARDATA 0x00008000
+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
+#define IMAGE_SCN_MEM_16BIT 0x00020000
+#define IMAGE_SCN_MEM_LOCKED 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD 0x00080000
+
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
+#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
+#define IMAGE_SCN_ALIGN_MASK 0x00f00000
+
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
+/*
+ * Relocation type x86-64
+ */
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000a
+#define IMAGE_REL_AMD64_SECREL 0x000b
+#define IMAGE_REL_AMD64_SECREL7 0x000c
+#define IMAGE_REL_AMD64_TOKEN 0x000d
+#define IMAGE_REL_AMD64_SREL32 0x000e
+#define IMAGE_REL_AMD64_PAIR 0x000f
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+/*
+ * Relocation types i386
+ */
+#define IMAGE_REL_I386_ABSOLUTE 0x0000
+#define IMAGE_REL_I386_DIR16 0x0001
+#define IMAGE_REL_I386_REL16 0x0002
+#define IMAGE_REL_I386_DIR32 0x0006
+#define IMAGE_REL_I386_DIR32NB 0x0007
+#define IMAGE_REL_I386_SEG12 0x0009
+#define IMAGE_REL_I386_SECTION 0x000a
+#define IMAGE_REL_I386_SECREL 0x000b
+#define IMAGE_REL_I386_TOKEN 0x000c
+#define IMAGE_REL_I386_SECREL7 0x000d
+#define IMAGE_REL_I386_REL32 0x0014
+
+/*
+ * Relocation types ARM
+ */
+#define IMAGE_REL_ARM_ABSOLUTE 0x0000
+#define IMAGE_REL_ARM_ADDR32 0x0001
+#define IMAGE_REL_ARM_ADDR32NB 0x0002
+#define IMAGE_REL_ARM_BRANCH24 0x0003
+#define IMAGE_REL_ARM_BRANCH11 0x0004
+#define IMAGE_REL_ARM_SECTION 0x000e
+#define IMAGE_REL_ARM_SECREL 0x000f
+
+/*
+ * Relocation types Hitachi SuperH
+ */
+#define IMAGE_REL_SH3_ABSOLUTE 0x0000
+#define IMAGE_REL_SH3_DIRECT16 0x0001
+#define IMAGE_REL_SH3_DIRECT32 0x0002
+#define IMAGE_REL_SH3_DIRECT8 0x0003
+#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004
+#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005
+#define IMAGE_REL_SH3_DIRECT4 0x0006
+#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007
+#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008
+#define IMAGE_REL_SH3_PCREL8_WORD 0x0009
+#define IMAGE_REL_SH3_PCREL8_LONG 0x000a
+#define IMAGE_REL_SH3_PCREL12_WORD 0x000b
+#define IMAGE_REL_SH3_STARTOF_SECTION 0x000c
+#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000d
+#define IMAGE_REL_SH3_SECTION 0x000e
+#define IMAGE_REL_SH3_SECREL 0x000f
+#define IMAGE_REL_SH3_DIRECT32_NB 0x0010
+#define IMAGE_REL_SH3_GPREL4_LONG 0x0011
+#define IMAGE_REL_SH3_TOKEN 0x0012
+#define IMAGE_REL_SHM_PCRELPT 0x0013
+#define IMAGE_REL_SHM_REFLO 0x0014
+#define IMAGE_REL_SHM_REFHALF 0x0015
+#define IMAGE_REL_SHM_RELLO 0x0016
+#define IMAGE_REL_SHM_RELHALF 0x0017
+#define IMAGE_REL_SHM_PAIR 0x0018
+#define IMAGE_REL_SHM_NOMODE 0x8000
+
+/*
+ * Relocation types IBM PowerPC processors
+ */
+#define IMAGE_REL_PPC_ABSOLUTE 0x0000
+#define IMAGE_REL_PPC_ADDR64 0x0001
+#define IMAGE_REL_PPC_ADDR32 0x0002
+#define IMAGE_REL_PPC_ADDR24 0x0003
+#define IMAGE_REL_PPC_ADDR16 0x0004
+#define IMAGE_REL_PPC_ADDR14 0x0005
+#define IMAGE_REL_PPC_REL24 0x0006
+#define IMAGE_REL_PPC_REL14 0x0007
+#define IMAGE_REL_PPC_ADDR32NB 0x000a
+#define IMAGE_REL_PPC_SECREL 0x000b
+#define IMAGE_REL_PPC_SECTION 0x000c
+#define IMAGE_REL_PPC_SECREL16 0x000f
+#define IMAGE_REL_PPC_REFHI 0x0010
+#define IMAGE_REL_PPC_REFLO 0x0011
+#define IMAGE_REL_PPC_PAIR 0x0012
+#define IMAGE_REL_PPC_SECRELLO 0x0013
+#define IMAGE_REL_PPC_GPREL 0x0015
+#define IMAGE_REL_PPC_TOKEN 0x0016
+
+/*
+ * Relocation types Intel Itanium processor family (IPF)
+ */
+#define IMAGE_REL_IA64_ABSOLUTE 0x0000
+#define IMAGE_REL_IA64_IMM14 0x0001
+#define IMAGE_REL_IA64_IMM22 0x0002
+#define IMAGE_REL_IA64_IMM64 0x0003
+#define IMAGE_REL_IA64_DIR32 0x0004
+#define IMAGE_REL_IA64_DIR64 0x0005
+#define IMAGE_REL_IA64_PCREL21B 0x0006
+#define IMAGE_REL_IA64_PCREL21M 0x0007
+#define IMAGE_REL_IA64_PCREL21F 0x0008
+#define IMAGE_REL_IA64_GPREL22 0x0009
+#define IMAGE_REL_IA64_LTOFF22 0x000a
+#define IMAGE_REL_IA64_SECTION 0x000b
+#define IMAGE_REL_IA64_SECREL22 0x000c
+#define IMAGE_REL_IA64_SECREL64I 0x000d
+#define IMAGE_REL_IA64_SECREL32 0x000e
+#define IMAGE_REL_IA64_DIR32NB 0x0010
+#define IMAGE_REL_IA64_SREL14 0x0011
+#define IMAGE_REL_IA64_SREL22 0x0012
+#define IMAGE_REL_IA64_SREL32 0x0013
+#define IMAGE_REL_IA64_UREL32 0x0014
+#define IMAGE_REL_IA64_PCREL60X 0x0015
+#define IMAGE_REL_IA64_PCREL 60B 0x0016
+#define IMAGE_REL_IA64_PCREL60F 0x0017
+#define IMAGE_REL_IA64_PCREL60I 0x0018
+#define IMAGE_REL_IA64_PCREL60M 0x0019
+#define IMAGE_REL_IA64_IMMGPREL64 0x001a
+#define IMAGE_REL_IA64_TOKEN 0x001b
+#define IMAGE_REL_IA64_GPREL32 0x001c
+#define IMAGE_REL_IA64_ADDEND 0x001f
+
+/*
+ * Relocation types MIPS Processors
+ */
+#define IMAGE_REL_MIPS_ABSOLUTE 0x0000
+#define IMAGE_REL_MIPS_REFHALF 0x0001
+#define IMAGE_REL_MIPS_REFWORD 0x0002
+#define IMAGE_REL_MIPS_JMPADDR 0x0003
+#define IMAGE_REL_MIPS_REFHI 0x0004
+#define IMAGE_REL_MIPS_REFLO 0x0005
+#define IMAGE_REL_MIPS_GPREL 0x0006
+#define IMAGE_REL_MIPS_LITERAL 0x0007
+#define IMAGE_REL_MIPS_SECTION 0x000a
+#define IMAGE_REL_MIPS_SECREL 0x000b
+#define IMAGE_REL_MIPS_SECRELLO 0x000c
+#define IMAGE_REL_MIPS_SECRELHI 0x000d
+#define IMAGE_REL_MIPS_JMPADDR16 0x0010
+#define IMAGE_REL_MIPS_REFWORDNB 0x0022
+#define IMAGE_REL_MIPS_PAIR 0x0025
+
+/*
+ * Relocation types Mitsubishi M32R
+ */
+#define IMAGE_REL_M32R_ABSOLUTE 0x0000
+#define IMAGE_REL_M32R_ADDR32 0x0001
+#define IMAGE_REL_M32R_ADDR32NB 0x0002
+#define IMAGE_REL_M32R_ADDR24 0x0003
+#define IMAGE_REL_M32R_GPREL16 0x0004
+#define IMAGE_REL_M32R_PCREL24 0x0005
+#define IMAGE_REL_M32R_PCREL16 0x0006
+#define IMAGE_REL_M32R_PCREL8 0x0007
+#define IMAGE_REL_M32R_REFHALF 0x0008
+#define IMAGE_REL_M32R_REFHI 0x0009
+#define IMAGE_REL_M32R_REFLO 0x000a
+#define IMAGE_REL_M32R_PAIR 0x000b
+#define IMAGE_REL_M32R_SECTION 0x000c
+#define IMAGE_REL_M32R_SECREL 0x000d
+#define IMAGE_REL_M32R_TOKEN 0x000e
+
+/*
+ * Section number values
+ */
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE -1
+#define IMAGE_SYM_DEBUG -2
+
+/*
+ * Type representation
+ */
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 1
+#define IMAGE_SYM_DTYPE_FUNCTION 2
+#define IMAGE_SYM_DTYPE_ARRAY 3
+
+/*
+ * Storage class
+ */
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION -1
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLAS S_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_SYM_CLASS_CLR_TOKEN 107
+
+/*
+ * COMDAT sections
+ */
+#define IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define IMAGE_COMDAT_SELECT_ANY 2
+#define IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+#define IMAGE_COMDAT_SELECT_LARGEST 6
+
+/*
+ * Attribute certificate table
+ */
+#define WIN_CERT_REVISION_1_0 0x0100
+#define WIN_CERT_REVISION_2_0 0x0200
+#define WIN_CERT_TYPE_X509 0x0001
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
+#define WIN_CERT_TYPE_RESERVED_1 0x0003
+#define WIN_CERT_TYPE_TS_STACK_SIGNED 0x0004
+
+/*
+ * Debug type
+ */
+#define IMAGE_DEBUG_TYPE_UNKNOWN 0
+#define IMAGE_DEBUG_TYPE_COFF 1
+#define IMAGE_DEBUG_TYPE_CODEVIEW 2
+#define IMAGE_DEBUG_TYPE_FPO 3
+#define IMAGE_DEBUG_TYPE_MISC 4
+#define IMAGE_DEBUG_TYPE_EXCEPTION 5
+#define IMAGE_DEBUG_TYPE_FIXUP 6
+#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
+#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
+#define IMAGE_DEBUG_TYP E_BORLAND 9
+#define IMAGE_DEBUG_TYPE_RESERVED10 10
+#define IMAGE_DEBUG_TYPE_CLSID 11
+
+/*
+ * Base relocation types
+ */
+#define IMAGE_REL_BASED_ABSOLUTE 0
+#define IMAGE_REL_BASED_HIGH 1
+#define IMAGE_REL_BASED_LOW 2
+#define IMAGE_REL_BASED_HIGHLOW 3
+#define IMAGE_REL_BASED_HIGHADJ 4
+#define IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
+#define IMAGE_REL_BASED_DIR64 10
+
+/*
+ * TLS callback functions
+ */
+#define DLL_PROCESS_ATTACH 1
+#define DLL_THREAD_ATTACH 2
+#define DLL_THREAD_DETACH 3
+#define DLL_PROCESS_DETACH 0
+
+/*
+ * Import Type
+ */
+#define IMPORT_CODE 0
+#define IMPORT_DATA 1
+#define IMPORT_CONST 2
+
+/*
+ * Import name type
+ */
+#define IMPORT_ORDINAL 0
+#define IMPORT_NAME 1
+#define IMPORT_NAME_NOPREFIX 2
+#define IMPORT_NAME_UNDECORATE 3
+
+struct coff_Section {
+ struct SAA *data;
+ uint32_t len;
+ int nrelocs;
+ int32_t index;
+ struct coff_Reloc *head, **tail;
+ uint32_t flags; /* section flags */
+ uint32_t align_flags; /* user-specified alignment flags */
+ uint32_t sectalign_flags; /* minimum alignment from sectalign */
+ char *name;
+ int32_t namepos; /* Offset of name into the strings table */
+ int32_t pos, relpos;
+ int64_t pass_last_seen;
+
+ /* comdat-related members */
+ char *comdat_name;
+ uint32_t checksum; /* set only for comdat sections */
+ int8_t comdat_selection;
+ int8_t comdat_symbol; /* is the "comdat name" in symbol table? */
+ int32_t comdat_associated; /* associated section for selection==5 */
+};
+
+struct coff_Reloc {
+ struct coff_Reloc *next;
+ int32_t address; /* relative to _start_ of section */
+ int32_t symbol; /* symbol number */
+ enum {
+ SECT_SYMBOLS,
+ ABS_SYMBOL,
+ REAL_SYMBOLS
+ } symbase; /* relocation for symbol number :) */
+ int16_t type;
+};
+
+struct coff_Symbol {
+ char name[9];
+ int32_t strpos; /* string table position of name */
+ int32_t value; /* address, or COMMON variable size */
+ int section; /* section number where it's defined
+ * - in COFF codes, not NASM codes */
+ bool is_global; /* is it a global symbol or not? */
+ int16_t type; /* 0 - notype, 0x20 - function */
+ int32_t namlen; /* full name length */
+};
+
+struct coff_DebugInfo {
+ int32_t segto;
+ int32_t seg;
+ uint64_t size;
+ struct coff_Section *section;
+};
+
+extern struct coff_Section **coff_sects;
+extern int coff_nsects;
+extern struct SAA *coff_syms;
+extern uint32_t coff_nsyms;
+extern struct SAA *coff_strs;
+extern bool win32, win64;
+
+extern char coff_infile[FILENAME_MAX];
+extern char coff_outfile[FILENAME_MAX];
+
+extern int coff_make_section(char *name, uint32_t flags);
+
+
+#endif /* PECOFF_H */
diff --git a/vere/ext/nasm/output/stabs.h b/vere/ext/nasm/output/stabs.h
new file mode 100644
index 0000000..dbc4986
--- /dev/null
+++ b/vere/ext/nasm/output/stabs.h
@@ -0,0 +1,150 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ * See the file AUTHORS included with the NASM distribution for
+ * the specific copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef STABS_H_
+#define STABS_H_
+
+#include "nctype.h"
+
+#include "compiler.h"
+#include "nasmlib.h"
+#include "nasm.h"
+
+/* offsets */
+enum stab_offsets {
+ STAB_strdxoff = 0,
+ STAB_typeoff = 4,
+ STAB_otheroff = 5,
+ STAB_descoff = 6,
+ STAB_valoff = 8,
+ STAB_stabsize = 12
+};
+
+/* stab/non-stab types */
+enum stab_types {
+ N_UNDF = 0x00, /* Undefined symbol */
+ N_EXT = 0x01, /* External symbol */
+ N_ABS = 0x02, /* Absolute symbol */
+ N_ABS_EXT = 0x03, /* Absolute external symbol */
+ N_TEXT = 0x04, /* Symbol in text segment */
+ N_TEXT_EXT = 0x05, /* Symbol in external text segment */
+ N_DATA = 0x06,
+ N_DATA_EXT = 0x07,
+ N_BSS = 0x08,
+ N_BSS_EXT = 0x09,
+ N_INDR = 0x0a,
+ N_FN_SEQ = 0x0c, /* N_FN from Sequent compilers */
+ N_WEAKU = 0x0d, /* Weak undefined symbol */
+ N_WEAKA = 0x0e, /* Weak absolute symbl */
+ N_WEAKT = 0x0f, /* Weak text symbol */
+ N_WEAKD = 0x10, /* Weak data symbol */
+ N_WEAKB = 0x11, /* Weak bss symbol */
+ N_COMM = 0x12, /* Common symbol */
+ N_SETA = 0x14, /* Absolute set element symbol */
+ N_SETA_EXT = 0x15,
+ N_SETT = 0x16, /* Text set element symbol */
+ N_SETT_EXT = 0x17,
+ N_SETD = 0x18, /* Data set element symbol */
+ N_SETD_EXT = 0x19,
+ N_SETB = 0x1a, /* BSS set element symbol */
+ N_SETB_EXT = 0x1b,
+ N_SETV = 0x1c, /* Pointer to set vector in data area */
+ N_SETV_EXT = 0x1d,
+ N_WARNING = 0x1e, /* Warning symbol */
+ N_FN = 0x1f, /* Filename of .o file */
+ N_GSYM = 0x20, /* Global variable */
+ N_FNAME = 0x22, /* Function name for BSD Fortran */
+ N_FUN = 0x24, /* Function name or text segment variable for C */
+ N_STSYM = 0x26, /* Data-segment variable with internal linkage */
+ N_LCSYM = 0x28, /* BSS-segment variable with internal linkage */
+ N_MAIN = 0x2a, /* Name of main routine */
+ N_ROSYM = 0x2c, /* Read-only data symbols */
+ N_BNSYM = 0x2e, /* The beginning of a relocatable function block */
+ N_PC = 0x30, /* Global symbol in Pascal */
+ N_NSYMS = 0x32, /* Number of symbols */
+ N_NOMAP = 0x34, /* No DST map for sym */
+ N_OBJ = 0x38, /* Like N_SO, but for the object file */
+ N_OPT = 0x3c, /* Options for the debugger */
+ N_RSYM = 0x40, /* Register variable */
+ N_M2C = 0x42, /* Modula-2 compilation unit */
+ N_SLINE = 0x44, /* Line number in text segment */
+ N_DSLINE = 0x46, /* Line number in data segment */
+ N_BSLINE = 0x48, /* Line number in bss segment */
+ N_BROWS = 0x48, /* Sun's source-code browser stabs */
+ N_DEFD = 0x4a, /* GNU Modula-2 definition module dependency */
+ N_FLINE = 0x4c, /* Function start/body/end line numbers */
+ N_ENSYM = 0x4e, /* This tells the end of a relocatable function */
+ N_EHDECL = 0x50, /* GNU C++ exception variable */
+ N_MOD2 = 0x50, /* Modula2 info "for imc" */
+ N_CATCH = 0x54, /* GNU C++ `catch' clause */
+ N_SSYM = 0x60, /* Structure or union element */
+ N_ENDM = 0x62, /* Last stab emitted for module */
+ N_SO = 0x64, /* ID for main source file */
+ N_OSO = 0x66, /* Apple: This is the stab that associated the .o file */
+ N_ALIAS = 0x6c, /* SunPro F77: Name of alias */
+ N_LSYM = 0x80, /* Automatic variable in the stack */
+ N_BINCL = 0x82, /* Beginning of an include file */
+ N_SOL = 0x84, /* ID for sub-source file */
+ N_PSYM = 0xa0, /* Parameter variable */
+ N_EINCL = 0xa2, /* End of an include file */
+ N_ENTRY = 0xa4, /* Alternate entry point */
+ N_LBRAC = 0xc0, /* Beginning of lexical block */
+ N_EXCL = 0xc2, /* Place holder for deleted include file */
+ N_SCOPE = 0xc4, /* Modula-2 scope information */
+ N_PATCH = 0xd0, /* Solaris2: Patch Run Time Checker */
+ N_RBRAC = 0xe0, /* End of a lexical block */
+ N_BCOMM = 0xe2, /* Begin named common block */
+ N_ECOMM = 0xe4, /* End named common block */
+ N_ECOML = 0xe8, /* Member of a common block */
+ N_WITH = 0xea, /* Solaris2: Pascal "with" statement */
+ N_NBTEXT = 0xf0,
+ N_NBDATA = 0xf2,
+ N_NBBSS = 0xf4,
+ N_NBSTS = 0xf6,
+ N_NBLCS = 0xf8,
+ N_LENG = 0xfe /* Second symbol entry whih a length-value for the preceding entry */
+};
+
+enum stab_source_file {
+ N_SO_AS = 0x01,
+ N_SO_C = 0x02,
+ N_SO_ANSI_C = 0x03,
+ N_SO_CC = 0x04,
+ N_SO_FORTRAN = 0x05,
+ N_SO_PASCAL = 0x06,
+ N_SO_FORTRAN90 = 0x07,
+ N_SO_OBJC = 0x32,
+ N_SO_OBJCPLUS = 0x33
+};
+
+#endif /* STABS_H_ */