summaryrefslogtreecommitdiff
path: root/vere/ext/nasm/output/codeview.c
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/codeview.c
claude is gud
Diffstat (limited to 'vere/ext/nasm/output/codeview.c')
-rw-r--r--vere/ext/nasm/output/codeview.c820
1 files changed, 820 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++; */
+}