mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-19 18:00:23 +08:00
coff: Add support for the Codeview 8 debug format
Codeview is a debug format for win32/win64 PE/COFF files. It adds two sections, .debug$S (symbols) and .debug$T (types), to the generated object file. These sections are then used by the linker to generate a PDB file which can be used by various debuggers (WinDbg, Visual Studio, etc). Signed-off-by: Jim Kukunas <james.t.kukunas@linux.intel.com> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
This commit is contained in:
parent
ba754eec03
commit
3115e789d6
@ -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) \
|
||||
|
@ -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) \
|
||||
|
720
output/codeview.c
Normal file
720
output/codeview.c
Normal file
@ -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 <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
310
output/outcoff.c
310
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,
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user