#include <ctype.h>
#include <time.h>
#include "globals.h"
#include "memalloc.h"
#include "mangle.h"
#include "parser.h"
#include "fixup.h"
#include "segment.h"
#include "extern.h"
#include "coff.h"
#include "coffspec.h"
#include "input.h"
#include "myassert.h"
#include "omfspec.h"
#include "linnum.h"
#if COFF_SUPPORT
#define HELPSYMS 0
#define MANGLE_BYTES 8
#define STATIC_PROCS 1
#define COMPID 0
#define SIZE_CV_SEGBUF ( MAX_LINE_LEN * 2 )
struct stringitem {
struct stringitem *next;
char string[1];
};
extern void cv_write_debug_tables( struct dsym *, struct dsym *, void * );
static const char* const SymDebName[DBGS_MAX] = { ".debug$S", ".debug$T" };
static const char szdrectve[] = { ".drectve" };
static const IMAGE_SYMBOL isFeat00 = {
{"@feat.00"},
1,
IMAGE_SYM_ABSOLUTE,
IMAGE_SYM_TYPE_NULL,
IMAGE_SYM_CLASS_STATIC,
0
};
#if COMPID
static const IMAGE_SYMBOL isCompId = {
{"@comp.id"},
50727 + ( 0x7d << 16 ),
IMAGE_SYM_ABSOLUTE,
IMAGE_SYM_TYPE_NULL,
IMAGE_SYM_CLASS_STATIC,
0
};
#endif
static uint_32 Coff_AllocString( struct coffmod *cm, const char *string, int len )
{
struct stringitem *name;
uint_32 oldsize = cm->LongNames.size;
cm->LongNames.size += len + 1;
name = LclAlloc( len + sizeof( struct stringitem ) );
name->next = NULL;
strcpy( name->string, string );
if ( cm->LongNames.head ) {
cm->LongNames.tail->next = name;
cm->LongNames.tail = name;
} else {
cm->LongNames.head = cm->LongNames.tail = name;
}
return( oldsize );
}
static unsigned GetLinnumItems( struct qdesc *q )
{
unsigned i;
struct line_num_info *curr;
for ( i = 0, curr = q->head; curr; i++, curr = curr->next );
return( i );
}
static ret_code coff_write_section_table( struct module_info *modinfo, struct coffmod *cm )
{
struct dsym *curr;
struct fixup *fix;
uint_32 fileoffset;
unsigned len;
char *secname;
enum seg_type segtype;
struct IMAGE_SECTION_HEADER ish;
char buffer[MAX_ID_LEN+1];
fileoffset = sizeof( struct IMAGE_FILE_HEADER ) + modinfo->g.num_segs * sizeof( struct IMAGE_SECTION_HEADER );
cm->start_data = fileoffset;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
segtype = SEGTYPE_UNDEF;
secname = ( curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ConvertSectionName( &curr->sym, &segtype, buffer ) );
len = strlen( secname );
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
strncpy( ish.Name, secname, IMAGE_SIZEOF_SHORT_NAME );
else
sprintf( ish.Name, "/%u", Coff_AllocString( cm, secname, len ) );
ish.Misc.PhysicalAddress = 0;
ish.VirtualAddress = 0;
ish.SizeOfRawData = curr->sym.max_offset;
ish.PointerToRawData = ( ish.SizeOfRawData ? fileoffset : 0 );
ish.PointerToRelocations = 0;
ish.PointerToLinenumbers = 0;
ish.NumberOfRelocations = 0;
ish.NumberOfLinenumbers = 0;
ish.Characteristics = 0;
if ( curr->e.seginfo->info ) {
if ( curr == cm->directives )
ish.Characteristics = ( IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE );
else
ish.Characteristics = ( IMAGE_SCN_LNK_INFO | IMAGE_SCN_CNT_INITIALIZED_DATA );
} else {
if ( curr->e.seginfo->alignment != MAX_SEGALIGNMENT )
ish.Characteristics |= (uint_32)(curr->e.seginfo->alignment + 1) << 20;
if ( curr->e.seginfo->comdat_selection )
ish.Characteristics |= IMAGE_SCN_LNK_COMDAT;
if ( curr->e.seginfo->segtype == SEGTYPE_CODE ) {
ish.Characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
} else if ( curr->e.seginfo->readonly ) {
ish.Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
} else if ( curr->e.seginfo->clsym && strcmp( curr->e.seginfo->clsym->name, "CONST" ) == 0 ) {
ish.Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
} else if ( curr->e.seginfo->segtype == SEGTYPE_BSS || segtype == SEGTYPE_BSS ) {
curr->e.seginfo->segtype = SEGTYPE_BSS;
ish.Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
ish.PointerToRawData = 0;
} else if ( curr->e.seginfo->combine == COMB_STACK && curr->e.seginfo->bytes_written == 0 ) {
ish.Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
ish.SizeOfRawData = 0;
ish.PointerToRawData = 0;
} else
ish.Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
}
if ( curr->e.seginfo->characteristics ) {
ish.Characteristics &= 0x1FFFFFF;
ish.Characteristics |= (uint_32)(curr->e.seginfo->characteristics & 0xFE) << 24;
}
if ( ish.PointerToRawData )
fileoffset += ish.SizeOfRawData;
if ( curr->e.seginfo->FixupList.head ) {
for ( fix = curr->e.seginfo->FixupList.head; fix ; fix = fix->nextrlc ) {
if (fix->sym == NULL) {
if (fix->type == FIX_RELOFF32) {
uint_32* cp = (uint_32*)(curr->e.seginfo->CodeBuffer + (fix->locofs - curr->e.seginfo->start_loc));
uint_32 src = fix->locofs + fix->addbytes;
(*cp) -= src;
}
fix->type = FIX_VOID;
continue;
}
else if (fix->sym && curr->e.seginfo->Ofssize == USE64 && curr == fix->sym->segment && fix->type == FIX_RELOFF32
&& fix->sym->isdefined && !fix->sym->isfar && fix->sym->state != SYM_EXTERNAL) {
uint_32* cp = (uint_32*)(curr->e.seginfo->CodeBuffer + (fix->locofs - curr->e.seginfo->start_loc));
uint_32 src = fix->sym->offset - (fix->locofs + fix->addbytes);
(*cp) += src;
fix->type = FIX_VOID;
continue;
}
curr->e.seginfo->num_relocs++;
}
fileoffset = (fileoffset + 1) & ~1;
ish.PointerToRelocations = fileoffset;
fileoffset += curr->e.seginfo->num_relocs * sizeof( IMAGE_RELOCATION );
if ( curr->e.seginfo->num_relocs <= 0xffff ) {
ish.NumberOfRelocations = (uint_16)curr->e.seginfo->num_relocs;
} else {
ish.NumberOfRelocations = 0xffff;
ish.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL;
fileoffset += sizeof( IMAGE_RELOCATION );
}
}
if ( curr->e.seginfo->LinnumQueue && Options.debug_symbols != 4 ) {
ish.PointerToLinenumbers = fileoffset;
ish.NumberOfLinenumbers = GetLinnumItems( curr->e.seginfo->LinnumQueue );
fileoffset += ish.NumberOfLinenumbers * sizeof( IMAGE_LINENUMBER );
}
if ( fwrite( &ish, 1, sizeof( ish ), CurrFile[OBJ] ) != sizeof( ish ) )
WriteError();
}
return( NOT_ERROR );
}
static short CoffGetType( const struct asym *sym )
{
if ( sym->isproc )
return( 0x20 );
return( IMAGE_SYM_TYPE_NULL );
}
static short CoffGetClass( const struct asym *sym )
{
if ( sym->state == SYM_EXTERNAL )
if ( sym->iscomm == FALSE && sym->altname )
return( IMAGE_SYM_CLASS_WEAK_EXTERNAL );
else
return( IMAGE_SYM_CLASS_EXTERNAL );
else if ( sym->ispublic == TRUE )
return( IMAGE_SYM_CLASS_EXTERNAL );
#if HELPSYMS
else if ( sym->variable == TRUE )
return( IMAGE_SYM_CLASS_LABEL );
#endif
else if ( sym->mem_type == MT_NEAR && sym->isproc == FALSE )
return( IMAGE_SYM_CLASS_LABEL );
return( IMAGE_SYM_CLASS_STATIC );
}
static unsigned GetFileAuxEntries( uint_16 file, char * *fname )
{
const struct fname_item *curr;
unsigned len;
curr = GetFName( file );
if ( fname )
*fname = curr->fname;
len = strlen( curr->fname );
return ( len / sizeof( IMAGE_AUX_SYMBOL ) + ( len % sizeof( IMAGE_AUX_SYMBOL ) ? 1 : 0 ) );
}
static uint_32 CRC32Table[256];
static void InitCRC32( void )
{
int i,j;
uint_32 crc;
for ( i = 0; i < 256; i++ ) {
for ( j = 0, crc = i; j < 8; j++ ) {
crc = ( crc >> 1 ) ^ (0xEDB88320 * ( crc & 1 ) );
}
CRC32Table[i] = crc;
}
}
static uint_32 CRC32Comdat( uint_8 *lpBuffer, uint_32 dwBufLen, uint_32 dwCRC )
{
static bool init = FALSE;
uint_8 byt;
if ( !init ) {
init = TRUE;
InitCRC32();
}
if ( lpBuffer )
for ( ; dwBufLen; dwBufLen-- ) {
byt = *lpBuffer++;
byt = byt ^ (uint_8)dwCRC;
dwCRC = dwCRC >> 8;
dwCRC = dwCRC ^ CRC32Table[byt];
}
return( dwCRC );
}
static void coff_write_symbol(char* name, int_32 strpos, int_32 value,
int section, int type, int storageclass, int aux)
{
IMAGE_SYMBOL sym;
if (name) {
strncpy(sym.N.ShortName, name, IMAGE_SIZEOF_SHORT_NAME);
}
else {
sym.N.LongName[0] = 0;
sym.N.LongName[1] = strpos;
}
sym.Value = value;
sym.SectionNumber = section;
sym.Type = type;
sym.StorageClass = storageclass;
sym.NumberOfAuxSymbols = aux;
if (fwrite(&sym, 1, sizeof(IMAGE_SYMBOL), CurrFile[OBJ]) != sizeof(IMAGE_SYMBOL))
WriteError();
}
static void coff_write_aux(void* sym, char* name)
{
uint_32 size = sizeof(IMAGE_AUX_SYMBOL);
if (name)
strncpy(sym, name, size);
if (fwrite(sym, 1, size, CurrFile[OBJ]) != size)
WriteError();
}
static uint_32 coff_write_symbols( struct module_info *modinfo, struct coffmod *cm )
{
uint_32 cntSymbols = 0;
struct dsym *curr;
struct asym *sym;
struct qnode *q;
char *p;
unsigned len;
unsigned i;
IMAGE_AUX_SYMBOL ias;
unsigned lastfile = 0;
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
int_32 strpos = 0;
int_32 value;
int section;
int type;
int storageclass;
int aux;
int count;
#if COMPID
if (Options.debug_symbols == 4) {
coff_write_symbol("@comp.id", 0, 0x01037296,
IMAGE_SYM_ABSOLUTE, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC, 0);
cntSymbols++;
}
#endif
if ( Options.safeseh ) {
coff_write_symbol("@feat.00", 0, (Options.debug_symbols == 4) ? 16 : 1,
IMAGE_SYM_ABSOLUTE, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC, 0);
cntSymbols++;
}
if ( Options.no_file_entry == FALSE ) {
p = cm->dot_file_value;
i = strlen(p);
len = sizeof(IMAGE_AUX_SYMBOL);
aux = i / len + (i % len ? 1 : 0);
coff_write_symbol(".file", 0, Options.line_numbers ? cm->start_files : 0,
IMAGE_SYM_DEBUG, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_FILE, aux);
for (i = aux; i; i--, p += len)
coff_write_aux(&ias, p);
cntSymbols += aux + 1;
}
for( i = 1, curr = SymTables[TAB_SEG].head; curr; curr = curr->next, i++ ) {
p = (curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ConvertSectionName(&curr->sym, NULL, buffer));
len = strlen(p);
if (len > IMAGE_SIZEOF_SHORT_NAME) {
strpos = Coff_AllocString(cm, p, len);
p = NULL;
}
coff_write_symbol(p, strpos, 0, i, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC,
Options.no_section_aux_entry == FALSE ? 1 : 0);
cntSymbols++;
if ( Options.no_section_aux_entry == FALSE || curr->e.seginfo->comdat_selection ) {
memset(&ias, 0, sizeof(ias));
ias.Section.Length = curr->sym.max_offset;
ias.Section.NumberOfRelocations = ( curr->e.seginfo->num_relocs > 0xffff ? 0xffff : (uint_16)curr->e.seginfo->num_relocs );
if ( Options.line_numbers && Options.debug_symbols != 4 )
ias.Section.NumberOfLinenumbers = curr->e.seginfo->num_linnums;
else
ias.Section.NumberOfLinenumbers = 0;
if ( curr->e.seginfo->comdat_selection ) {
ias.Section.CheckSum = CRC32Comdat( curr->e.seginfo->CodeBuffer, curr->sym.max_offset, 0 );
ias.Section.Number = curr->e.seginfo->comdat_number;
ias.Section.Selection = curr->e.seginfo->comdat_selection;
}
coff_write_aux(&ias, NULL);
cntSymbols++;
}
}
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE ) {
continue;
}
p = buffer;
len = Mangle( &curr->sym, buffer );
if (curr->sym.iscomm == TRUE)
value = curr->sym.total_size;
else
value = curr->sym.offset;
if (len > IMAGE_SIZEOF_SHORT_NAME) {
p = NULL;
strpos = Coff_AllocString(cm, buffer, len);
}
coff_write_symbol(p, strpos, value, IMAGE_SYM_UNDEFINED,
CoffGetType(&curr->sym),
CoffGetClass(&curr->sym),
((curr->sym.iscomm == FALSE && curr->sym.altname) ? 1 : 0));
cntSymbols++;
if ( curr->sym.iscomm == FALSE && curr->sym.altname ) {
memset( &ias, 0, sizeof(ias) );
ias.Sym.TagIndex = curr->sym.altname->ext_idx;
ias.Sym.Misc.TotalSize = IMAGE_WEAK_EXTERN_SEARCH_LIBRARY;
coff_write_aux(&ias, NULL);
cntSymbols++;
}
}
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
sym = q->sym;
len = Mangle( sym, buffer );
if ( Options.line_numbers && Options.debug_symbols != 4 &&
sym->isproc && sym->debuginfo->file != lastfile ) {
lastfile = sym->debuginfo->file;
aux = GetFileAuxEntries(sym->debuginfo->file, &p);
coff_write_symbol(".file", 0, sym->debuginfo->next_file,
IMAGE_SYM_DEBUG, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_FILE, aux);
for (i = aux; i; i--, p += sizeof(IMAGE_AUX_SYMBOL))
coff_write_aux(&ias, p);
cntSymbols += aux + 1;
}
if ( sym->state == SYM_INTERNAL ) {
if ( sym->segment )
section = GetSegIdx( sym->segment );
else
section = (uint_16)IMAGE_SYM_ABSOLUTE;
} else
section = IMAGE_SYM_UNDEFINED;
aux = 0;
if ( Options.line_numbers && sym->isproc && Options.debug_symbols != 4 )
aux++;
p = buffer;
if (len > IMAGE_SIZEOF_SHORT_NAME) {
p = NULL;
strpos = Coff_AllocString(cm, buffer, len);
}
value = sym->offset;
coff_write_symbol(p, strpos, value, section,
CoffGetType(sym), CoffGetClass(sym), aux);
cntSymbols++;
if ( Options.line_numbers && sym->isproc && Options.debug_symbols != 4 ) {
ias.Sym.TagIndex = cntSymbols+1;
ias.Sym.Misc.TotalSize = sym->total_size;
ias.Sym.FcnAry.Function.PointerToLinenumber = sym->debuginfo->ln_fileofs;
ias.Sym.FcnAry.Function.PointerToNextFunction = sym->debuginfo->next_proc;
coff_write_aux(&ias, NULL);
type = IMAGE_SYM_TYPE_NULL;
storageclass = IMAGE_SYM_CLASS_FUNCTION;
coff_write_symbol(".bf", 0, value, section, type, storageclass, 1);
ias.Sym.TagIndex = 0;
ias.Sym.Misc.LnSz.Linenumber = sym->debuginfo->start_line;
if ( sym->debuginfo->next_proc )
ias.Sym.FcnAry.Function.PointerToNextFunction = sym->debuginfo->next_proc + 2;
else
ias.Sym.FcnAry.Function.PointerToNextFunction = 0;
coff_write_aux(&ias, NULL);
value = sym->debuginfo->line_numbers;
coff_write_symbol(".lf", 0, value, section, type, storageclass, 0);
value = sym->offset + sym->total_size;
coff_write_symbol(".ef", 0, value, section, type, storageclass, 1);
ias.Sym.TagIndex = 0;
ias.Sym.Misc.LnSz.Linenumber = sym->debuginfo->end_line;
coff_write_aux(&ias, NULL);
cntSymbols += 6;
}
}
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
struct asym * sym;
len = Mangle( &curr->sym, buffer );
p = buffer;
if (len > IMAGE_SIZEOF_SHORT_NAME) {
p = NULL;
strpos = Coff_AllocString(cm, buffer, len);
}
coff_write_symbol(p, strpos, 0, IMAGE_SYM_UNDEFINED,
IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_WEAK_EXTERNAL, 1);
cntSymbols++;
memset(&ias, 0, sizeof(ias));
sym = curr->sym.substitute;
if (sym)
ias.Sym.TagIndex = sym->ext_idx;
ias.Sym.Misc.TotalSize = IMAGE_WEAK_EXTERN_SEARCH_ALIAS;
coff_write_aux(&ias, NULL);
cntSymbols++;
}
return(cntSymbols);
}
static int GetStartLabel( char *buffer, bool msg )
{
int size = 0;
char temp[ MAX_ID_LEN + MANGLE_BYTES + 1 ];
if ( ModuleInfo.g.start_label ) {
Mangle( ModuleInfo.g.start_label, temp );
if ( Options.entry_decorated )
strcpy( buffer, temp );
else {
if ( ModuleInfo.g.start_label->langtype != LANG_C &&
ModuleInfo.g.start_label->langtype != LANG_STDCALL &&
ModuleInfo.g.start_label->langtype != LANG_SYSCALL ) {
if ( *ModuleInfo.g.start_label->name != '_' ) {
if ( msg && ( ModuleInfo.fctype != FCT_WIN64 ) )
EmitWarn( 2, LEADING_UNDERSCORE_REQUIRED_FOR_START_LABEL, ModuleInfo.g.start_label->name );
strcpy( buffer, temp );
} else {
strcpy( buffer, temp+1 );
}
} else
strcpy( buffer, temp+1 );
}
size = strlen( buffer ) + 8; }
return( size );
}
static uint_8 *coff_flushfunc( struct dsym *seg, uint_8 *curr, unsigned size, void *pv )
{
unsigned currsize = curr - seg->e.seginfo->CodeBuffer;
struct coffmod *cm;
int i;
uint_8 *p;
if ( ( currsize + size ) > SIZE_CV_SEGBUF ) {
if ( currsize ) {
p = LclAlloc( currsize + sizeof( struct qditem ) );
((struct qditem *)p)->next = NULL;
((struct qditem *)p)->size = currsize;
memcpy( p + sizeof( struct qditem ), seg->e.seginfo->CodeBuffer, currsize );
cm = pv;
i = ( seg == cm->SymDeb[DBGS_TYPES].seg ? DBGS_TYPES : DBGS_SYMBOLS );
if ( cm->SymDeb[i].q.head == NULL )
cm->SymDeb[i].q.head = cm->SymDeb[i].q.tail = p;
else {
((struct qditem *)(cm->SymDeb[i].q.tail))->next = p;
cm->SymDeb[i].q.tail = p;
}
seg->e.seginfo->current_loc = seg->e.seginfo->start_loc + currsize;
seg->e.seginfo->start_loc = seg->e.seginfo->current_loc;
}
return( seg->e.seginfo->CodeBuffer );
}
return( curr );
}
static uint_32 SetSymbolIndices( struct module_info *ModuleInfo, struct coffmod *cm )
{
struct qnode *q;
struct dsym *curr;
struct asym *sym;
uint_32 index;
uint_32 i;
struct asym *lastfproc;
unsigned lastfile = 0;
int section;
index = 0;
cm->lastproc = NULL;
cm->start_files = 0;
#if COMPID
if (Options.debug_symbols == 4)
index++;
#endif
if ( Options.safeseh )
index++;
if ( Options.no_file_entry == FALSE ) {
i = strlen( cm->dot_file_value );
index += i / sizeof( IMAGE_AUX_SYMBOL ) + 1;
if ( i % sizeof( IMAGE_AUX_SYMBOL ) )
index++;
}
cm->sectionstart = index;
index += ModuleInfo->g.num_segs;
if ( Options.no_section_aux_entry == FALSE )
index += ModuleInfo->g.num_segs;
for( curr = SymTables[TAB_EXT].head ; curr != NULL ; curr = curr->next ) {
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE )
continue;
curr->sym.ext_idx = index++;
if ( curr->sym.iscomm == FALSE && curr->sym.altname )
index++;
}
#if STATIC_PROCS
if ( Options.no_static_procs == FALSE )
for( curr = SymTables[TAB_PROC].head ; curr != NULL ; curr = curr->nextproc )
if ( curr->sym.state == SYM_INTERNAL && curr->sym.ispublic == FALSE && curr->sym.included == FALSE ) {
curr->sym.included = TRUE;
AddPublicData( &curr->sym );
}
#endif
for ( q = ModuleInfo->g.PubQueue.head; q; q = q->next ) {
sym = q->sym;
if ( Options.line_numbers && sym->isproc && Options.debug_symbols != 4 ) {
if ( sym->debuginfo->file != lastfile ) {
if ( cm->start_files == 0 )
cm->start_files = index;
else
lastfproc->debuginfo->next_file = index;
lastfproc = sym;
index += 1 + GetFileAuxEntries( sym->debuginfo->file, NULL );
lastfile = sym->debuginfo->file;
}
sym->ext_idx = index++;
index += 6;
} else
sym->ext_idx = index++;
}
return( index );
}
static void coff_write_fixup(uint_32 addr, uint_32 index, uint_16 type)
{
IMAGE_RELOCATION ir;
ir.VirtualAddress = addr;
ir.SymbolTableIndex = index;
ir.Type = type;
if (fwrite(&ir, 1, sizeof(ir), CurrFile[OBJ]) != sizeof(ir))
WriteError();
}
static void coff_write_fixups( struct dsym *section, uint_32 *poffset, uint_32 *pindex )
{
uint_32 offset = *poffset;
uint_32 index = *pindex;
struct fixup *fix;
uint_16 type;
if ( section->e.seginfo->num_relocs > 0xffff ) {
coff_write_fixup(section->e.seginfo->num_relocs + 1, 0, IMAGE_REL_I386_ABSOLUTE);
offset += sizeof(IMAGE_RELOCATION);
}
section->e.seginfo->num_relocs = 0;
for ( fix = section->e.seginfo->FixupList.head; fix ; fix = fix->nextrlc ) {
if ( section->e.seginfo->Ofssize == USE64 )
{
switch ( fix->type ) {
case FIX_VOID:
continue;
case FIX_RELOFF32:
type = IMAGE_REL_AMD64_REL32 + (fix->addbytes - 4);
break;
case FIX_OFF32:
type = IMAGE_REL_AMD64_ADDR32;
break;
case FIX_OFF32_IMGREL:
type = IMAGE_REL_AMD64_ADDR32NB;
break;
case FIX_OFF32_SECREL:
type = IMAGE_REL_AMD64_SECREL;
break;
case FIX_OFF64:
type = IMAGE_REL_AMD64_ADDR64;
break;
case FIX_SEG:
type = IMAGE_REL_AMD64_SECTION;
break;
default:
EmitErr( UNKNOWN_FIXUP_TYPE, fix->type, section->sym.name, fix->locofs );
continue;
}
}
else
switch ( fix->type ) {
case FIX_VOID:
continue;
case FIX_RELOFF16:
type = IMAGE_REL_I386_REL16;
break;
case FIX_OFF16:
type = IMAGE_REL_I386_DIR16;
break;
case FIX_RELOFF32:
type = IMAGE_REL_I386_REL32;
break;
case FIX_OFF32:
type = IMAGE_REL_I386_DIR32;
break;
case FIX_OFF32_IMGREL:
type = IMAGE_REL_I386_DIR32NB;
break;
case FIX_OFF32_SECREL:
type = IMAGE_REL_I386_SECREL;
break;
case FIX_SEG:
type = IMAGE_REL_I386_SECTION;
break;
default:
EmitErr( UNKNOWN_FIXUP_TYPE, fix->type, section->sym.name, fix->locofs );
continue;
}
if ( fix->sym->variable == TRUE ) {
#if HELPSYMS
struct asym *sym;
char buffer[12];
sprintf( buffer, "$$%06X", fix->offset );
sym = SymAlloc( buffer );
sym->state = fix->sym->state;
sym->mem_type = fix->sym->mem_type;
sym->offset = fix->offset;
sym->segment = fix->segment;
sym->variable = TRUE;
fix->sym = sym;
AddPublicData( fix->sym );
fix->sym->idx = index++;
#else
fix->sym = fix->segment_var;
#endif
} else if (( fix->sym->state == SYM_INTERNAL ) &&
fix->sym->included == FALSE &&
fix->sym->ispublic == FALSE ) {
fix->sym->included = TRUE;
AddPublicData(fix->sym);
fix->sym->ext_idx = index++;
if (Options.line_numbers && fix->sym->isproc && Options.debug_symbols != 4)
index += 6;
}
if (fix->sym && section->e.seginfo->Ofssize == USE64 && section == fix->sym->segment && fix->type == FIX_RELOFF32
&& fix->sym->isdefined && !fix->sym->isfar && fix->sym->state != SYM_EXTERNAL) {
}
else {
coff_write_fixup(fix->locofs, fix->sym->ext_idx, type);
offset += sizeof(IMAGE_RELOCATION);
section->e.seginfo->num_relocs++;
}
}
*poffset = offset;
*pindex = index;
}
static ret_code coff_write_data( struct module_info *modinfo, struct coffmod *cm )
{
struct dsym *section;
uint_32 offset = 0;
int i;
uint_32 index;
index = SetSymbolIndices( modinfo, cm );
if ( modinfo->g.SafeSEHQueue.head ) {
struct qnode *sehp;
struct qnode *sehp2;
uint_32 *pdw;
for( sehp = modinfo->g.SafeSEHQueue.head, pdw = (uint_32 *)cm->sxdata->e.seginfo->CodeBuffer; sehp ; sehp = sehp2 ) {
sehp2 = sehp->next;
*pdw++ = ((struct asym *)sehp->elmt)->ext_idx;
}
}
#if HELPSYMS==0
for( i = 0, section = SymTables[TAB_SEG].head; section ; i++, section = section->next ) {
section->sym.ext_idx = cm->sectionstart + i;
if ( Options.no_section_aux_entry == FALSE )
section->sym.ext_idx += i;
}
#endif
for( section = SymTables[TAB_SEG].head; section ; section = section->next ) {
uint_32 size;
size = section->sym.max_offset;
if ( section->e.seginfo->combine == COMB_STACK && section->e.seginfo->bytes_written == 0 )
continue;
if ( section->e.seginfo->segtype == SEGTYPE_BSS )
continue;
if ( size ) {
offset += size;
if ((offset & 1) && section->e.seginfo->FixupList.head ) {
offset++;
size++;
}
if ( section->e.seginfo->CodeBuffer == NULL ) {
fseek( CurrFile[OBJ], size, SEEK_CUR );
} else {
if ( section->e.seginfo->start_loc ) {
fseek( CurrFile[OBJ], section->e.seginfo->start_loc, SEEK_CUR );
size -= section->e.seginfo->start_loc;
}
if ( fwrite( section->e.seginfo->CodeBuffer, 1, size, CurrFile[OBJ] ) != size )
WriteError();
}
coff_write_fixups( section, &offset, &index );
}
if( Options.line_numbers && section->e.seginfo->LinnumQueue && Options.debug_symbols != 4 ) {
IMAGE_LINENUMBER il;
struct line_num_info *lni;
struct asym *last;
uint_32 line_numbers = 0;
last = NULL;
lni = (struct line_num_info *)((struct qdesc *)section->e.seginfo->LinnumQueue)->head;
for( ; lni; lni = lni->next ) {
if ( lni->number == 0 ) {
last = lni->sym;
if ( cm->lastproc )
cm->lastproc->debuginfo->next_proc = lni->sym->ext_idx;
cm->lastproc = lni->sym;
lni->sym->debuginfo->next_proc = 0;
il.Linenumber = 0;
il.Type.SymbolTableIndex = lni->sym->ext_idx;
lni->sym->debuginfo->start_line = lni->line_number;
lni->sym->debuginfo->ln_fileofs = cm->start_data + offset;
} else {
il.Linenumber = lni->number - last->debuginfo->start_line;
if ( il.Linenumber == 0 )
il.Linenumber = 0x7FFF;
il.Type.VirtualAddress = lni->offset;
}
last->debuginfo->line_numbers++;
last->debuginfo->end_line = lni->number;
if ( fwrite( &il, 1, sizeof(il), CurrFile[OBJ] ) != sizeof(il) )
WriteError();
offset += sizeof(il);
line_numbers++;
}
section->e.seginfo->num_linnums = line_numbers;
}
}
cm->size_data = offset;
return( NOT_ERROR );
}
static void coff_create_drectve( struct module_info *modinfo, struct coffmod *cm )
{
struct dsym *exp;
struct dsym *imp = NULL;
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
for( exp = SymTables[TAB_PROC].head; exp != NULL; exp = exp->nextproc ) {
if( exp->e.procinfo->isexport )
break;
}
if ( Options.write_impdef && !Options.names[OPTN_LNKDEF_FN] )
for ( imp = SymTables[TAB_EXT].head; imp; imp = imp->next )
if ( imp->sym.isproc && ( imp->sym.weak == FALSE || imp->sym.iat_used == TRUE ) )
if ( imp->sym.dll && *imp->sym.dll->name )
break;
if ( modinfo->g.start_label != NULL || modinfo->g.LibQueue.head != NULL ||
imp != NULL || exp != NULL ) {
if ( cm->directives = (struct dsym *)CreateIntSegment( szdrectve, "", MAX_SEGALIGNMENT, modinfo->Ofssize, FALSE ) ) {
struct dsym *tmp;
int size = 0;
struct qitem *q;
uint_8 *p;
cm->directives->e.seginfo->info = TRUE;
for( tmp = exp; tmp ; tmp = tmp->nextproc ) {
if( tmp->e.procinfo->isexport ) {
size += Mangle( &tmp->sym, buffer );
size += sizeof("-export:");
if ( Options.no_export_decoration == TRUE )
size += tmp->sym.name_size + 1;
}
}
for( q = modinfo->g.LibQueue.head; q ; q = q->next ) {
size += strlen( q->value ) + sizeof("-defaultlib:");
if ( *q->value != '"' && strchr( q->value, ' ') )
size += 2;
}
size += GetStartLabel( buffer, TRUE );
for( tmp = imp; tmp ; tmp = tmp->next ) {
if ( tmp->sym.isproc && ( tmp->sym.weak == FALSE || tmp->sym.iat_used == TRUE ) &&
tmp->sym.dll && *tmp->sym.dll->name ) {
size += sizeof("-import:");
size += Mangle( &tmp->sym, buffer );
size += 1 + strlen( tmp->sym.dll->name );
size += 1 + tmp->sym.name_size;
}
}
for (q = modinfo->g.LinkQueue.head; q; q = q->next) {
size += strlen(q->value) + 1;
}
cm->directives->sym.max_offset = size;
cm->directives->e.seginfo->CodeBuffer = LclAlloc( size + 1 );
p = cm->directives->e.seginfo->CodeBuffer;
for( tmp = exp; tmp ; tmp = tmp->nextproc ) {
if( tmp->e.procinfo->isexport ) {
Mangle( &tmp->sym, buffer );
if ( Options.no_export_decoration == FALSE )
p += sprintf( (char *)p, "-export:%s ", buffer );
else
p += sprintf( (char *)p, "-export:%s=%s ", tmp->sym.name, buffer );
}
}
for( q = modinfo->g.LibQueue.head; q ; q = q->next ) {
if ( *q->value != '"' && strchr( q->value, ' ' ) )
p += sprintf( (char *)p,"-defaultlib:\"%s\" ", (char *)q->value );
else
p += sprintf( (char *)p,"-defaultlib:%s ", (char *)q->value );
}
if ( modinfo->g.start_label ) {
GetStartLabel( buffer, FALSE );
p += sprintf( (char *)p, "-entry:%s ", buffer );
}
for( tmp = imp; tmp ; tmp = tmp->next ) {
if ( tmp->sym.isproc && ( tmp->sym.weak == FALSE || tmp->sym.iat_used == TRUE ) &&
tmp->sym.dll && *tmp->sym.dll->name ) {
strcpy( p, "-import:" );
p += 8;
p += Mangle( &tmp->sym, p );
*p++ = '=';
strcpy( p, tmp->sym.dll->name );
p += strlen( p );
*p++ = '.';
memcpy( p, tmp->sym.name, tmp->sym.name_size );
p += tmp->sym.name_size;
*p++ = ' ';
}
}
for (q = modinfo->g.LinkQueue.head; q; q = q->next) {
p += sprintf((char*)p, "%s ", (char*)q->value);
}
}
}
}
static ret_code coff_write_module( struct module_info *modinfo )
{
struct stringitem *pName;
struct coffmod cm;
struct IMAGE_FILE_HEADER ifh;
memset( &cm, 0, sizeof( cm ) );
cm.LongNames.size = sizeof( uint_32 );
cm.dot_file_value = CurrFName[ASM];
if ( Options.debug_symbols ) {
int i;
for ( i = 0; i < DBGS_MAX; i++ ) {
if ( NULL == ( cm.SymDeb[i].seg = (struct dsym *)CreateIntSegment( SymDebName[i], "", 0, USE32, TRUE ) ) )
break;
cm.SymDeb[i].seg->e.seginfo->characteristics = (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE) >> 24;
cm.SymDeb[i].seg->e.seginfo->CodeBuffer = CurrSource + i * SIZE_CV_SEGBUF;
cm.SymDeb[i].seg->e.seginfo->flushfunc = coff_flushfunc;
cm.SymDeb[i].q.head = NULL;
}
if ( i == DBGS_MAX ) {
cv_write_debug_tables( cm.SymDeb[DBGS_SYMBOLS].seg, cm.SymDeb[DBGS_TYPES].seg, &cm );
for ( i = 0; i < DBGS_MAX; i++ ) {
uint_8 *src;
uint_8 *dst;
if ( cm.SymDeb[i].seg->sym.max_offset ) {
if (cm.SymDeb[i].seg->sym.max_offset > SIZE_CV_SEGBUF)
cm.SymDeb[i].seg->e.seginfo->CodeBuffer = LclAlloc( cm.SymDeb[i].seg->sym.max_offset );
dst = cm.SymDeb[i].seg->e.seginfo->CodeBuffer;
for ( src = cm.SymDeb[i].q.head; src; src = ((struct qditem *)src)->next ) {
memcpy( dst, src + sizeof( struct qditem ), ((struct qditem *)src)->size );
dst += ((struct qditem *)src)->size;
}
}
}
}
}
if ( modinfo->g.SafeSEHQueue.head ) {
struct qnode *sehp;
unsigned cnt = 0;
if ( cm.sxdata = (struct dsym *)CreateIntSegment( ".sxdata", "", MAX_SEGALIGNMENT, modinfo->Ofssize, FALSE ) ) {
cm.sxdata->e.seginfo->info = TRUE;
for( sehp = modinfo->g.SafeSEHQueue.head; sehp ; sehp = sehp->next, cnt++ );
cm.sxdata->sym.max_offset = cnt*4;
cm.sxdata->e.seginfo->CodeBuffer = LclAlloc( cnt*4 );
}
}
coff_create_drectve( modinfo, &cm );
if ( modinfo->defOfssize == USE64 )
ifh.Machine = IMAGE_FILE_MACHINE_AMD64;
else
ifh.Machine = IMAGE_FILE_MACHINE_I386;
ifh.NumberOfSections = modinfo->g.num_segs;
time((time_t *)&ifh.TimeDateStamp);
ifh.SizeOfOptionalHeader = 0;
ifh.Characteristics = 0;
fseek( CurrFile[OBJ], sizeof( ifh ), SEEK_SET );
coff_write_section_table( modinfo, &cm );
coff_write_data( modinfo, &cm );
ifh.NumberOfSymbols = coff_write_symbols( modinfo, &cm );
ifh.PointerToSymbolTable = ( ifh.NumberOfSymbols ? cm.start_data + cm.size_data : 0 );
if ( fwrite( &cm.LongNames.size, 1, sizeof( cm.LongNames.size ), CurrFile[OBJ] ) != sizeof( cm.LongNames.size ) )
WriteError();
for ( pName = cm.LongNames.head; pName; pName = pName->next ) {
int i = strlen( pName->string ) + 1;
if ( fwrite( pName->string, 1, i, CurrFile[OBJ] ) != i )
WriteError();
}
fseek( CurrFile[OBJ], 0, SEEK_SET);
if ( fwrite( &ifh, 1, sizeof( ifh ), CurrFile[OBJ] ) != sizeof( ifh ) ) {
WriteError();
}
return( NOT_ERROR );
}
void coff_init( struct module_info *modinfo )
{
modinfo->g.WriteModule = coff_write_module;
return;
}
#endif