diff --git a/Makefile.in b/Makefile.in index 9894d333..56f3589f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -92,7 +92,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \ preproc-nop.$(O) \ disp8.$(O) \ iflag.$(O) \ - md5c.$(O) + md5c.$(O) output/codeview.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) \ insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) \ diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak index a4df3e30..a2bae67e 100644 --- a/Mkfiles/msvc.mak +++ b/Mkfiles/msvc.mak @@ -62,7 +62,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \ preproc-nop.$(O) \ disp8.$(O) \ iflag.$(O) \ - md5c.$(O) + md5c.$(O) output/codeview.$(O) NDISASM = ndisasm.$(O) disasm.$(O) sync.$(O) nasmlib.$(O) ver.$(O) \ insnsd.$(O) insnsb.$(O) insnsn.$(O) regs.$(O) regdis.$(O) \ diff --git a/output/codeview.c b/output/codeview.c new file mode 100644 index 00000000..4256e8dd --- /dev/null +++ b/output/codeview.c @@ -0,0 +1,720 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 1996-2010 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 +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "saa.h" +#include "output/outlib.h" +#include "output/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); + +struct dfmt df_cv8 = { + .fullname = "Codeview 8", + .shortname = "cv8", + .init = cv8_init, + .linenum = cv8_linenum, + .debug_deflabel = cv8_deflabel, + .debug_directive = null_debug_directive, + .debug_typevalue = cv8_typevalue, + .debug_output = cv8_output, + .cleanup = cv8_cleanup, +}; + +/******************************************************************************* + * dfmt callbacks + ******************************************************************************/ +struct source_file { + char *name; + 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_file; + + struct SAA *lines; + uint32_t num_lines; + + struct SAA *symbols; + struct cv8_symbol *last_sym; + unsigned num_syms[SYMTYPE_MAX]; + unsigned symbol_lengths; + unsigned total_syms; + + char *cwd; +}; +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.lines = saa_init(sizeof(struct linepair)); + cv8_state.num_lines = 0; + + cv8_state.symbols = saa_init(sizeof(struct cv8_symbol)); + cv8_state.last_sym = NULL; + + cv8_state.cwd = nasm_realpath("."); +} + +static void 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; + + if (cv8_state.source_file.name == NULL) + register_file(filename); + + s = find_section(segto); + if (s == NULL) + return; + + if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0) + return; + + li = saa_wstruct(cv8_state.lines); + li->file_offset = cv8_state.text_offset; + li->linenumber = linenumber; + + cv8_state.num_lines++; +} + +static void cv8_deflabel(char *name, int32_t segment, int64_t offset, + int is_global, char *special) +{ + int ret; + size_t len; + 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; + + /* handle local labels */ + if (name[0] == '.' && cv8_state.last_sym != NULL) { + len = strlen(cv8_state.last_sym->name) + strlen(name); + sym->name = nasm_malloc(len + 1); + ret = snprintf(sym->name, len + 1, "%s%s", + cv8_state.last_sym->name, name); + nasm_assert(ret > 0 && (size_t)ret == len); + } else { + len = strlen(name); + sym->name = nasm_malloc(len + 1); + ret = snprintf(sym->name, len + 1, "%s", name); + nasm_assert(ret > 0 && (size_t)ret == len); + } + + cv8_state.symbol_lengths += len + 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_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 coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect]; + struct coff_Section *type_sect = coff_sects[cv8_state.type_sect]; + + build_symbol_table(symbol_sect); + build_type_table(type_sect); + + if (cv8_state.source_file.name != NULL) + free(cv8_state.source_file.name); + + if (cv8_state.cwd != NULL) + free(cv8_state.cwd); + + saa_free(cv8_state.lines); + + saa_rewind(cv8_state.symbols); + while ((sym = saa_rstruct(cv8_state.symbols))) + free(sym->name); + saa_free(cv8_state.symbols); +} + +/******************************************************************************* + * 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 = fopen(filename, "r"); + 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_error(ERR_NONFATAL, "unable to hash file %s. " + "Debug information may be unavailable.\n", + filename); + } + return; +} + +static void register_file(const char *filename) +{ + cv8_state.source_file.name = nasm_realpath(filename); + memset(cv8_state.source_file.md5sum, 0, MD5_HASHBYTES); + calc_md5(filename, cv8_state.source_file.md5sum); +} + +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; + + 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 (int i = 0; i < coff_nsects; i++) { + sec = coff_sects[i]; + if (!strcmp(sym, sec->name)) { + return; + } + r->symbol += 2; + } + + saa_rewind(coff_syms); + for (uint32_t i = 0; i < coff_nsyms; i++) { + struct coff_Symbol *s = saa_rstruct(coff_syms); + r->symbol++; + if (s->strpos == -1 && s->name && !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_assert(!"relocation for unregistered symbol"); +} + +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 = 0; + size_t filename_len = strlen(cv8_state.source_file.name); + + field_length = 1 + filename_len + 1; + + section_write32(sect, 0x000000F3); + section_write32(sect, field_length); + + section_write8(sect, 0); + section_wbytes(sect, cv8_state.source_file.name, filename_len + 1); +} + +static void write_sourcefile_table(struct coff_Section *const sect) +{ + uint32_t field_length = 0; + + field_length = 4 + 2 + MD5_HASHBYTES + 2; + + section_write32(sect, 0x000000F4); + section_write32(sect, field_length); + + section_write32(sect, 1); /* offset of filename in filename str table */ + section_write16(sect, 0x0110); + section_wbytes(sect, cv8_state.source_file.md5sum, MD5_HASHBYTES); + section_write16(sect, 0); +} + +static void write_linenumber_table(struct coff_Section *const sect) +{ + int i; + uint32_t field_length = 0; + size_t field_base; + struct coff_Section *s; + struct linepair *li; + + 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 + 12 + (cv8_state.num_lines * 8); + + 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); + + /* 1 or more source mappings (we assume only 1) */ + section_write32(sect, 0); + section_write32(sect, cv8_state.num_lines); + section_write32(sect, 12 + (cv8_state.num_lines * 8)); + + /* the pairs */ + saa_rewind(cv8_state.lines); + while ((li = saa_rstruct(cv8_state.lines))) { + section_write32(sect, li->file_offset); + section_write32(sect, li->linenumber |= 0x80000000); + } +} + +static uint16_t write_symbolinfo_obj(struct coff_Section *sect, + const char sep) +{ + uint16_t obj_len; + + obj_len = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1; + + section_write16(sect, obj_len); + section_write16(sect, 0x1101); + section_write32(sect, 0); /* ASM language */ + section_wbytes(sect, cv8_state.cwd, strlen(cv8_state.cwd)); + section_write8(sect, sep); + section_wbytes(sect, coff_outfile, strlen(coff_outfile)+1); + + return obj_len; +} + +static uint16_t write_symbolinfo_properties(struct coff_Section *sect, + const char *const creator_str) +{ + uint16_t creator_len; + + creator_len = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2; + + section_write16(sect, creator_len); + section_write16(sect, 0x1116); + section_write32(sect, 3); /* language */ + if (win64) + section_write32(sect, 0x000000D0); + else if (win32) + section_write32(sect, 0x00000006); + else + nasm_assert(!"neither win32 nor win64 are set!"); + section_write32(sect, 0); /* flags*/ + section_write32(sect, 8); /* version */ + section_wbytes(sect, creator_str, strlen(creator_str)+1); + /* + * 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 uint16_t write_symbolinfo_symbols(struct coff_Section *sect) +{ + uint16_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_assert(!"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) +{ + const char sep = '\\'; + const char *creator_str = "The Netwide Assembler " NASM_VER; + + + uint16_t obj_length, creator_length, sym_length; + uint32_t field_length = 0, out_len; + + /* signature, language, workingdir / coff_outfile NULL */ + obj_length = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1; + creator_length = 2 + 4 + 4 + 4 + 4 + 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 preceeds type */ + + out_len = write_symbolinfo_obj(sect, sep); + 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) +{ + uint16_t field_len; + struct cv8_symbol *sym; + + section_write32(sect, 0x00000004); + + saa_rewind(cv8_state.symbols); + while ((sym = saa_rstruct(cv8_state.symbols))) { + if (sym->type != SYMTYPE_PROC) + continue; + + /* proc leaf */ + + field_len = 2 + 4 + 4 + 4 + 2; + section_write16(sect, field_len); + section_write16(sect, 0x1008); /* PROC type */ + + section_write32(sect, 0x00000003); /* return type */ + section_write32(sect, 0); /* calling convention (default) */ + section_write32(sect, sym->typeindex); + section_write16(sect, 0); /* # params */ + + /* arglist */ + + field_len = 2 + 4; + section_write16(sect, field_len); + section_write16(sect, 0x1201); /* ARGLIST */ + section_write32(sect, 0); /*num params */ + } +} + + diff --git a/output/outcoff.c b/output/outcoff.c index 2d55fd09..b45e4f16 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -100,47 +100,13 @@ */ /* Flag which version of COFF we are currently outputting. */ -static bool win32, win64; +bool win32, win64; static int32_t imagebase_sect; #define WRT_IMAGEBASE "..imagebase" -struct Reloc { - struct 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 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 */ -}; - -static char coff_infile[FILENAME_MAX]; - -struct Section { - struct SAA *data; - uint32_t len; - int nrelocs; - int32_t index; - struct Reloc *head, **tail; - uint32_t flags; /* section flags */ - char *name; - int32_t namepos; /* Offset of name into the strings table */ - int32_t pos, relpos; -}; +char coff_infile[FILENAME_MAX]; +char coff_outfile[FILENAME_MAX]; /* * Some common section flags by default @@ -198,11 +164,12 @@ struct Section { #define RDATA_FLAGS ((win32 | win64) ? RDATA_FLAGS_WIN : RDATA_FLAGS_DOS) #define SECT_DELTA 32 -static struct Section **sects; -static int nsects, sectlen; +struct coff_Section **coff_sects; +static int sectlen; +int coff_nsects; -static struct SAA *syms; -static uint32_t nsyms; +struct SAA *coff_syms; +uint32_t coff_nsyms; static int32_t def_seg; @@ -210,14 +177,14 @@ static int initsym; static struct RAA *bsym, *symval; -static struct SAA *strs; +struct SAA *coff_strs; static uint32_t strslen; static void coff_gen_init(void); -static void coff_sect_write(struct Section *, const uint8_t *, uint32_t); +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 Section *); +static void coff_write_relocs(struct coff_Section *); static void coff_write_symbols(void); static void coff_win32_init(void) @@ -246,46 +213,47 @@ static void coff_std_init(void) static void coff_gen_init(void) { - sects = NULL; - nsects = sectlen = 0; - syms = saa_init(sizeof(struct Symbol)); - nsyms = 0; + coff_sects = NULL; + coff_nsects = sectlen = 0; + coff_syms = saa_init(sizeof(struct coff_Symbol)); + coff_nsyms = 0; bsym = raa_init(); symval = raa_init(); - strs = saa_init(1); + coff_strs = saa_init(1); strslen = 0; def_seg = seg_alloc(); } static void coff_cleanup(int debuginfo) { - struct Reloc *r; + struct coff_Reloc *r; int i; - (void)debuginfo; + if (debuginfo && ofmt->current_dfmt->cleanup) + ofmt->current_dfmt->cleanup(); coff_write(); - for (i = 0; i < nsects; i++) { - if (sects[i]->data) - saa_free(sects[i]->data); - while (sects[i]->head) { - r = sects[i]->head; - sects[i]->head = sects[i]->head->next; + 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(sects[i]->name); - nasm_free(sects[i]); + nasm_free(coff_sects[i]->name); + nasm_free(coff_sects[i]); } - nasm_free(sects); - saa_free(syms); + nasm_free(coff_sects); + saa_free(coff_syms); raa_free(bsym); raa_free(symval); - saa_free(strs); + saa_free(coff_strs); } -static int coff_make_section(char *name, uint32_t flags) +int coff_make_section(char *name, uint32_t flags) { - struct Section *s; + struct coff_Section *s; size_t namelen; s = nasm_zalloc(sizeof(*s)); @@ -302,7 +270,7 @@ static int coff_make_section(char *name, uint32_t flags) if (namelen > 8) { if (win32 || win64) { s->namepos = strslen + 4; - saa_wbytes(strs, name, namelen + 1); + saa_wbytes(coff_strs, name, namelen + 1); strslen += namelen + 1; } else { namelen = 8; @@ -313,13 +281,13 @@ static int coff_make_section(char *name, uint32_t flags) s->name[namelen] = '\0'; s->flags = flags; - if (nsects >= sectlen) { + if (coff_nsects >= sectlen) { sectlen += SECT_DELTA; - sects = nasm_realloc(sects, sectlen * sizeof(*sects)); + coff_sects = nasm_realloc(coff_sects, sectlen * sizeof(*coff_sects)); } - sects[nsects++] = s; + coff_sects[coff_nsects++] = s; - return nsects - 1; + return coff_nsects - 1; } static inline int32_t coff_sectalign_flags(unsigned int align) @@ -418,10 +386,10 @@ static int32_t coff_section_names(char *name, int pass, int *bits) } } - for (i = 0; i < nsects; i++) - if (!strcmp(name, sects[i]->name)) + for (i = 0; i < coff_nsects; i++) + if (!strcmp(name, coff_sects[i]->name)) break; - if (i == nsects) { + if (i == coff_nsects) { if (!flags) { if (!strcmp(name, ".data")) flags = DATA_FLAGS; @@ -438,56 +406,56 @@ static int32_t coff_section_names(char *name, int pass, int *bits) } i = coff_make_section(name, flags); if (flags) - sects[i]->flags = flags; - sects[i]->flags &= align_and; - sects[i]->flags |= align_or; + coff_sects[i]->flags = flags; + coff_sects[i]->flags &= align_and; + coff_sects[i]->flags |= align_or; } else if (pass == 1) { /* Check if any flags are specified */ if (flags) { unsigned int align_flags = flags & IMAGE_SCN_ALIGN_MASK; /* Warn if non-alignment flags differ */ - if ((flags ^ sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) { + if ((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) { nasm_error(ERR_WARNING, "section attributes ignored on" " redeclaration of section `%s'", name); } /* Check if alignment might be needed */ if (align_flags > IMAGE_SCN_ALIGN_1BYTES) { - unsigned int sect_align_flags = sects[i]->flags & IMAGE_SCN_ALIGN_MASK; + unsigned int sect_align_flags = coff_sects[i]->flags & IMAGE_SCN_ALIGN_MASK; /* Compute the actual alignment */ unsigned int align = 1u << ((align_flags - IMAGE_SCN_ALIGN_1BYTES) >> 20); /* Update section header as needed */ if (align_flags > sect_align_flags) { - sects[i]->flags = (sects[i]->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags; + coff_sects[i]->flags = (coff_sects[i]->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags; } /* Check if not already aligned */ - if (sects[i]->len % align) { - unsigned int padding = (align - sects[i]->len) % align; + if (coff_sects[i]->len % align) { + unsigned int padding = (align - coff_sects[i]->len) % align; /* We need to write at most 8095 bytes */ char buffer[8095]; - if (sects[i]->flags & IMAGE_SCN_CNT_CODE) { + if (coff_sects[i]->flags & IMAGE_SCN_CNT_CODE) { /* Fill with INT 3 instructions */ memset(buffer, 0xCC, padding); } else { memset(buffer, 0x00, padding); } - saa_wbytes(sects[i]->data, buffer, padding); - sects[i]->len += padding; + saa_wbytes(coff_sects[i]->data, buffer, padding); + coff_sects[i]->len += padding; } } } } - return sects[i]->index; + return coff_sects[i]->index; } static void coff_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { int pos = strslen + 4; - struct Symbol *sym; + struct coff_Symbol *sym; if (special) nasm_error(ERR_NONFATAL, "COFF format does not support any" @@ -501,12 +469,12 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset, if (strlen(name) > 8) { size_t nlen = strlen(name)+1; - saa_wbytes(strs, name, nlen); + saa_wbytes(coff_strs, name, nlen); strslen += nlen; } else pos = -1; - sym = saa_wstruct(syms); + sym = saa_wstruct(coff_syms); sym->strpos = pos; sym->namlen = strlen(name); @@ -519,8 +487,8 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset, else { int i; sym->section = 0; - for (i = 0; i < nsects; i++) - if (segment == sects[i]->index) { + for (i = 0; i < coff_nsects; i++) + if (segment == coff_sects[i]->index) { sym->section = i + 1; break; } @@ -537,20 +505,20 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset, * to these symbol records. */ if (sym->section == 0) - bsym = raa_write(bsym, segment, nsyms); + bsym = raa_write(bsym, segment, coff_nsyms); if (segment != NO_SEG) symval = raa_write(symval, segment, sym->section ? 0 : sym->value); - nsyms++; + coff_nsyms++; } -static int32_t coff_add_reloc(struct Section *sect, int32_t segment, +static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment, int16_t type) { - struct Reloc *r; + struct coff_Reloc *r; - r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); + r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc)); sect->tail = &r->next; r->next = NULL; @@ -560,8 +528,8 @@ static int32_t coff_add_reloc(struct Section *sect, int32_t segment, } else { int i; r->symbase = REAL_SYMBOLS; - for (i = 0; i < nsects; i++) { - if (segment == sects[i]->index) { + for (i = 0; i < coff_nsects; i++) { + if (segment == coff_sects[i]->index) { r->symbol = i * 2; r->symbase = SECT_SYMBOLS; break; @@ -587,7 +555,7 @@ static void coff_out(int32_t segto, const void *data, enum out_type type, uint64_t size, int32_t segment, int32_t wrt) { - struct Section *s; + struct coff_Section *s; uint8_t mydata[8], *p; int i; @@ -607,9 +575,9 @@ static void coff_out(int32_t segto, const void *data, } s = NULL; - for (i = 0; i < nsects; i++) { - if (segto == sects[i]->index) { - s = sects[i]; + for (i = 0; i < coff_nsects; i++) { + if (segto == coff_sects[i]->index) { + s = coff_sects[i]; break; } } @@ -618,7 +586,7 @@ static void coff_out(int32_t segto, const void *data, if (segto != coff_section_names(".text", 2, &tempint)) nasm_error(ERR_PANIC, "strange segment conditions in COFF driver"); else - s = sects[nsects - 1]; + s = coff_sects[coff_nsects - 1]; } /* magically default to 'wrt ..imagebase' in .pdata and .xdata */ @@ -636,6 +604,20 @@ static void coff_out(int32_t segto, const void *data, memset(mydata, 0, sizeof(mydata)); + if (ofmt->current_dfmt && ofmt->current_dfmt->debug_output) { + struct coff_DebugInfo dinfo; + dinfo.segto = segto; + dinfo.seg = segment; + dinfo.section = s; + + if (type == OUT_ADDRESS) + dinfo.size = abs(size); + else + dinfo.size = realsize(type, size); + + ofmt->current_dfmt->debug_output(type, &dinfo); + } + if (type == OUT_RESERVE) { if (s->data) { nasm_error(ERR_WARNING, "uninitialised space declared in" @@ -717,7 +699,7 @@ static void coff_out(int32_t segto, const void *data, } } -static void coff_sect_write(struct Section *sect, +static void coff_sect_write(struct coff_Section *sect, const uint8_t *data, uint32_t len) { saa_wbytes(sect->data, data, len); @@ -738,7 +720,7 @@ typedef struct tagString { */ static STRING *Exports = NULL; -static struct Section *directive_sec; +static struct coff_Section *directive_sec; static void AddExport(char *name) { STRING *rvp = Exports, *newS; @@ -751,15 +733,15 @@ static void AddExport(char *name) if (rvp == NULL) { int i; - for (i = 0; i < nsects; i++) { - if (!strcmp(EXPORT_SECTION_NAME, sects[i]->name)) + for (i = 0; i < coff_nsects; i++) { + if (!strcmp(EXPORT_SECTION_NAME, coff_sects[i]->name)) break; } - if (i == nsects) + if (i == coff_nsects) i = coff_make_section(EXPORT_SECTION_NAME, EXPORT_SECTION_FLAGS); - directive_sec = sects[i]; + directive_sec = coff_sects[i]; Exports = newS; } else { while (rvp->next) { @@ -827,10 +809,10 @@ static int coff_directives(enum directives directive, char *value, int pass) return 0; if (sxseg == -1) { - for (i = 0; i < nsects; i++) - if (!strcmp(".sxdata",sects[i]->name)) + for (i = 0; i < coff_nsects; i++) + if (!strcmp(".sxdata",coff_sects[i]->name)) break; - if (i == nsects) + if (i == coff_nsects) sxseg = coff_make_section(".sxdata", IMAGE_SCN_LNK_INFO); else sxseg = i; @@ -841,9 +823,9 @@ static int coff_directives(enum directives directive, char *value, int pass) */ if (pass0 == 2) { uint32_t n; - saa_rewind(syms); - for (n = 0; n < nsyms; n++) { - struct Symbol *sym = saa_rstruct(syms); + saa_rewind(coff_syms); + for (n = 0; n < coff_nsyms; n++) { + struct coff_Symbol *sym = saa_rstruct(coff_syms); bool equals; /* @@ -852,7 +834,7 @@ static int coff_directives(enum directives directive, char *value, int pass) */ if (sym->strpos >=4) { char *name = nasm_malloc(sym->namlen+1); - saa_fread(strs, sym->strpos-4, name, sym->namlen); + saa_fread(coff_strs, sym->strpos-4, name, sym->namlen); name[sym->namlen] = '\0'; equals = !strcmp(value,name); nasm_free(name); @@ -867,13 +849,13 @@ static int coff_directives(enum directives directive, char *value, int pass) * .absolute and two per each section */ unsigned char value[4],*p=value; - WRITELONG(p,n + 2 + 1 + nsects*2); - coff_sect_write(sects[sxseg],value,4); + WRITELONG(p,n + 2 + 1 + coff_nsects*2); + coff_sect_write(coff_sects[sxseg],value,4); sym->type = 0x20; break; } } - if (n == nsyms) { + if (n == coff_nsyms) { nasm_error(ERR_NONFATAL, "`safeseh' directive requires valid symbol"); } @@ -886,7 +868,7 @@ static int coff_directives(enum directives directive, char *value, int pass) } /* handle relocations storm, valid for win32/64 only */ -static inline void coff_adjust_relocs(struct Section *s) +static inline void coff_adjust_relocs(struct coff_Section *s) { if (s->nrelocs < IMAGE_SCN_MAX_RELOC) return; @@ -916,13 +898,13 @@ static void coff_write(void) /* add default value for @feat.00, this allows to 'link /safeseh' */ uint32_t n; - saa_rewind(syms); - for (n = 0; n < nsyms; n++) { - struct Symbol *sym = saa_rstruct(syms); + 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 == nsyms) + if (n == coff_nsyms) coff_deflabel("@feat.00", NO_SEG, 1, 0, NULL); } @@ -931,17 +913,17 @@ static void coff_write(void) * Calculate the start of the `real' symbols at the same time. * Check for massive relocations. */ - pos = 0x14 + 0x28 * nsects; + pos = 0x14 + 0x28 * coff_nsects; initsym = 3; /* two for the file, one absolute */ - for (i = 0; i < nsects; i++) { - if (sects[i]->data) { - coff_adjust_relocs(sects[i]); - sects[i]->pos = pos; - pos += sects[i]->len; - sects[i]->relpos = pos; - pos += 10 * sects[i]->nrelocs; + for (i = 0; i < coff_nsects; 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 - sects[i]->pos = sects[i]->relpos = 0L; + coff_sects[i]->pos = coff_sects[i]->relpos = 0L; initsym += 2; /* two for each section */ } sympos = pos; @@ -954,10 +936,10 @@ static void coff_write(void) else i = IMAGE_FILE_MACHINE_I386; fwriteint16_t(i, ofile); /* machine type */ - fwriteint16_t(nsects, ofile); /* number of sections */ + fwriteint16_t(coff_nsects, ofile); /* number of sections */ fwriteint32_t(time(NULL), ofile); /* time stamp */ fwriteint32_t(sympos, ofile); - fwriteint32_t(nsyms + initsym, 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); @@ -966,20 +948,20 @@ static void coff_write(void) * Output the section headers. */ vsize = 0L; - for (i = 0; i < nsects; i++) { - coff_section_header(sects[i]->name, sects[i]->namepos, vsize, sects[i]->len, - sects[i]->pos, sects[i]->relpos, - sects[i]->nrelocs, sects[i]->flags); - vsize += sects[i]->len; + 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 < nsects; i++) - if (sects[i]->data) { - saa_fpwrite(sects[i]->data, ofile); - coff_write_relocs(sects[i]); + 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]); } /* @@ -987,7 +969,7 @@ static void coff_write(void) */ coff_write_symbols(); fwriteint32_t(strslen + 4, ofile); /* length includes length count */ - saa_fpwrite(strs, ofile); + saa_fpwrite(coff_strs, ofile); } static void coff_section_header(char *name, int32_t namepos, int32_t vsize, @@ -1047,9 +1029,9 @@ static void coff_section_header(char *name, int32_t namepos, int32_t vsize, fwriteint32_t(flags, ofile); } -static void coff_write_relocs(struct Section *s) +static void coff_write_relocs(struct coff_Section *s) { - struct Reloc *r; + struct coff_Reloc *r; /* a real number of relocations if needed */ if (s->flags & IMAGE_SCN_LNK_NRELOC_OVFL) { @@ -1106,10 +1088,10 @@ static void coff_write_symbols(void) */ memset(filename, 0, 18); /* useful zeroed buffer */ - for (i = 0; i < (uint32_t) nsects; i++) { - coff_symbol(sects[i]->name, 0L, 0L, i + 1, 0, 3, 1); - fwriteint32_t(sects[i]->len, ofile); - fwriteint16_t(sects[i]->nrelocs,ofile); + 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); nasm_write(filename, 12, ofile); } @@ -1121,9 +1103,9 @@ static void coff_write_symbols(void) /* * The real symbols. */ - saa_rewind(syms); - for (i = 0; i < nsyms; i++) { - struct Symbol *sym = saa_rstruct(syms); + 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); @@ -1132,13 +1114,13 @@ static void coff_write_symbols(void) static void coff_sectalign(int32_t seg, unsigned int value) { - struct Section *s = NULL; + struct coff_Section *s = NULL; uint32_t align; int i; - for (i = 0; i < nsects; i++) { - if (sects[i]->index == seg) { - s = sects[i]; + for (i = 0; i < coff_nsects; i++) { + if (coff_sects[i]->index == seg) { + s = coff_sects[i]; break; } } @@ -1165,12 +1147,14 @@ static void coff_std_filename(char *inname, char *outname) { strcpy(coff_infile, inname); standard_extension(inname, outname, ".o"); + strcpy(coff_outfile, outname); } static void coff_win32_filename(char *inname, char *outname) { strcpy(coff_infile, inname); standard_extension(inname, outname, ".obj"); + strcpy(coff_outfile, outname); } extern macros_t coff_stdmac[]; @@ -1206,14 +1190,18 @@ struct ofmt of_coff = { #endif +extern struct dfmt df_cv8; + #ifdef OF_WIN32 +struct dfmt *win32_debug_arr[2] = { &df_cv8, NULL }; + struct ofmt of_win32 = { "Microsoft Win32 (i386) object files", "win32", 0, - null_debug_arr, - &null_debug_form, + win32_debug_arr, + &df_cv8, coff_stdmac, coff_win32_init, coff_set_info, @@ -1231,12 +1219,14 @@ struct ofmt of_win32 = { #ifdef OF_WIN64 +struct dfmt *win64_debug_arr[2] = { &df_cv8, NULL }; + struct ofmt of_win64 = { "Microsoft Win64 (x86-64) object files", "win64", 0, - null_debug_arr, - &null_debug_form, + win64_debug_arr, + &df_cv8, coff_stdmac, coff_win64_init, coff_set_info, diff --git a/output/pecoff.h b/output/pecoff.h index 924ccd8e..8b57d6b2 100644 --- a/output/pecoff.h +++ b/output/pecoff.h @@ -474,4 +474,59 @@ #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 */ + char *name; + int32_t namepos; /* Offset of name into the strings table */ + int32_t pos, relpos; +}; + +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 */