mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 08:44:38 +00:00
1501 lines
60 KiB
C
1501 lines
60 KiB
C
/****************************************************************************
|
|
*
|
|
* This code is Public Domain.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description: COFF output routines
|
|
*
|
|
****************************************************************************/
|
|
|
|
#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 /* use helper symbols for assembly time symbol refs */
|
|
#define MANGLE_BYTES 8 /* extra size required for name decoration */
|
|
/* v2.04: to make JWasm always add static (=private) procs to the symbol table
|
|
* set STATIC_PROCS to 1. Normally those procs are only added if line
|
|
* number/symbolic debugging information is generated.
|
|
*/
|
|
#define STATIC_PROCS 1 /* v2.10: changed to 1, because Masm 6-10 DOES add static procs */
|
|
#define COMPID 0 /* 1=add comp.id absolute symbol */
|
|
/* size of codeview temp segment buffer; prior to v2.12 it was 1024 - but this may be
|
|
* insufficient if MAX_ID_LEN has been enlarged.
|
|
*/
|
|
#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 * );
|
|
|
|
enum dbgseg_index {
|
|
DBGS_SYMBOLS,
|
|
DBGS_TYPES,
|
|
DBGS_MAX
|
|
};
|
|
|
|
struct dbg_section {
|
|
//const char *name;
|
|
struct dsym *seg;
|
|
struct qdesc q;
|
|
};
|
|
|
|
/* -Zi option section info */
|
|
static const char * const SymDebName[DBGS_MAX] = { ".debug$S", ".debug$T" };
|
|
|
|
/* v2.12: all coff global variables replaced by struct coffmod */
|
|
struct coffmod {
|
|
struct dsym *directives; /* .drectve section, contains linker directives */
|
|
struct dsym *sxdata; /* section for safe exception handler data */
|
|
struct asym *lastproc; /* used if -Zd is set */
|
|
char *dot_file_value;/* value of .file symbol (isn't written by Masm v8+) */
|
|
uint_32 start_data; /* file position of start section data */
|
|
uint_32 size_data; /* total of section contents (incl relocs + linnums) */
|
|
uint_32 start_files; /* symbol table index of first .file entry used by line number info */
|
|
uint_32 sectionstart; /* symbol table index of first section */
|
|
struct dbg_section SymDeb[DBGS_MAX]; /* codeview debug sections */
|
|
struct {
|
|
struct stringitem *head;
|
|
struct stringitem *tail;
|
|
uint_32 size;
|
|
} LongNames;
|
|
#ifdef DEBUG_OUT
|
|
uint_32 start_symtab; /* calculated start of symbol table when section table is written */
|
|
#endif
|
|
};
|
|
|
|
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"},
|
|
//8803 + ( 0x2a << 16 ), /* value of Masm v6.15.8803 */
|
|
//9466 + ( 0x40 << 16 ), /* value of Masm v7.00.9466 */
|
|
50727 + ( 0x7d << 16 ), /* value of Masm v8.00.50727.104 */
|
|
//30729 + ( 0x95 << 16 ), /* value of Masm v9.00.30729.01 */
|
|
//30319 + ( 0x9e << 16 ), /* value of Masm v10.00.30319.01 */
|
|
IMAGE_SYM_ABSOLUTE,
|
|
IMAGE_SYM_TYPE_NULL,
|
|
IMAGE_SYM_CLASS_STATIC,
|
|
0 /* # of aux symbols */
|
|
};
|
|
#endif
|
|
|
|
/* alloc a string which will be stored in the COFF string table */
|
|
|
|
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 );
|
|
}
|
|
|
|
/* return number of line number items */
|
|
|
|
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 );
|
|
}
|
|
|
|
/* write COFF section table */
|
|
|
|
static ret_code coff_write_section_table( struct module_info *modinfo, struct coffmod *cm )
|
|
/*****************************************************************************************/
|
|
{
|
|
struct dsym *curr;
|
|
struct fixup *fix;
|
|
uint_32 fileoffset; /* calculated file offset for section data, relocs and linenumber info */
|
|
unsigned len;
|
|
char *secname;
|
|
//struct omf_rec *objr;
|
|
//char *p;
|
|
//uint size_relocs = 0;
|
|
enum seg_type segtype;
|
|
struct IMAGE_SECTION_HEADER ish;
|
|
char buffer[MAX_ID_LEN+1];
|
|
|
|
DebugMsg(("coff_write_section_table: enter, sections=%u\n", modinfo->g.num_segs ));
|
|
|
|
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 ) {
|
|
|
|
/* v2.04: can't happen */
|
|
//if( curr->sym.state != SYM_SEG ) {
|
|
// EmitErr( SEGMENT_NOT_DEFINED, curr->sym.name );
|
|
// continue;
|
|
//}
|
|
segtype = SEGTYPE_UNDEF;
|
|
/* v2.07: prefer ALIAS name if defined. */
|
|
secname = ( curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ConvertSectionName( &curr->sym, &segtype, buffer ) );
|
|
len = strlen( secname );
|
|
/* if section name is longer than 8 chars, a '/' is stored,
|
|
followed by a number in ascii which is the offset for the string table
|
|
*/
|
|
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
|
|
strncpy( ish.Name, secname, IMAGE_SIZEOF_SHORT_NAME );
|
|
else
|
|
sprintf( ish.Name, "/%u", Coff_AllocString( cm, secname, len ) );
|
|
|
|
/* v2.04: what is the old line supposed to do? */
|
|
//ish.Misc.PhysicalAddress = fileoffset - (size_relocs + sizeof(struct IMAGE_FILE_HEADER) + ModuleInfo->g.num_segs * sizeof(struct IMAGE_SECTION_HEADER));
|
|
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;
|
|
|
|
/* set field Characteristics; optionally reset PointerToRawData/SizeOfRawData */
|
|
if ( curr->e.seginfo->info ) {
|
|
/* v2.09: set "remove" flag for .drectve section, as it was done in v2.06 and earlier */
|
|
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 ) /* ABS not possible */
|
|
ish.Characteristics |= (uint_32)(curr->e.seginfo->alignment + 1) << 20;
|
|
#if COMDATSUPP
|
|
if ( curr->e.seginfo->comdat_selection )
|
|
ish.Characteristics |= IMAGE_SCN_LNK_COMDAT;
|
|
#endif
|
|
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 ) {
|
|
/* v2.12: if segtype is bss, ensure that seginfo->segtype is also bss; else
|
|
* the segment might be written in coff_write_data().
|
|
*/
|
|
curr->e.seginfo->segtype = SEGTYPE_BSS;
|
|
ish.Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
|
|
/* ish.SizeOfRawData = 0; */
|
|
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;
|
|
}
|
|
|
|
/* manual characteristics set? */
|
|
if ( curr->e.seginfo->characteristics ) {
|
|
ish.Characteristics &= 0x1FFFFFF; /* clear the IMAGE_SCN_MEM flags */
|
|
ish.Characteristics |= (uint_32)(curr->e.seginfo->characteristics & 0xFE) << 24;
|
|
/* the INFO bit (bit 0) needs special handling! */
|
|
//if ( curr->e.seginfo->characteristics & 1 )
|
|
// ish.Characteristics |= IMAGE_SCN_LNK_INFO;
|
|
}
|
|
|
|
if ( ish.PointerToRawData )
|
|
fileoffset += ish.SizeOfRawData;
|
|
|
|
/* set fields PointerToRelocations/NumberOfRelocations; update 'fileoffset'.
|
|
* v2.10: don't use the 16-bit NumberOfRelocations member to count relocs!
|
|
* if the true number of relocs doesn't fit in 16-bits, set the appropriate
|
|
* flag in the section header!
|
|
*/
|
|
if ( curr->e.seginfo->FixupList.head ) {
|
|
for ( fix = curr->e.seginfo->FixupList.head; fix ; fix = fix->nextrlc ) {
|
|
//printf("segment %s, reloc.sym=%s\n", curr->sym.name, fix->sym ? fix->sym : "NULL" );
|
|
if ( fix->sym == NULL ) {
|
|
#if AMD64_SUPPORT
|
|
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;
|
|
}
|
|
#endif
|
|
fix->type = FIX_VOID;
|
|
continue;
|
|
}
|
|
curr->e.seginfo->num_relocs++;
|
|
}
|
|
fileoffset = (fileoffset + 1) & ~1;
|
|
ish.PointerToRelocations = fileoffset;
|
|
/* v2.10: handle the "relocs overflow"-case */
|
|
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 {
|
|
DebugMsg(( "coff_write_section_table(%s): %" I32_SPEC "u fixups (more than 0xffff!)!\n", curr->sym.name, curr->e.seginfo->num_relocs ));
|
|
ish.NumberOfRelocations = 0xffff;
|
|
ish.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL;
|
|
/* add 1 relocation - the true number of relocations is stored in the first relocation item */
|
|
fileoffset += sizeof( IMAGE_RELOCATION );
|
|
}
|
|
//printf( "segment %s has %u relocs\n", curr->sym.name, curr->e.seginfo->num_relocs );
|
|
}
|
|
|
|
/* set fields PointerToLinenumbers/NumberOfLinenumbers; update 'fileoffset' */
|
|
|
|
if ( curr->e.seginfo->LinnumQueue ) {
|
|
ish.PointerToLinenumbers = fileoffset;
|
|
ish.NumberOfLinenumbers = GetLinnumItems( curr->e.seginfo->LinnumQueue );
|
|
fileoffset += ish.NumberOfLinenumbers * sizeof( IMAGE_LINENUMBER );
|
|
}
|
|
|
|
DebugMsg(( "coff_write_section_table(%s): name=%.8s Fixups=%u, Linnums=%u\n", curr->sym.name, ish.Name, ish.NumberOfRelocations, ish.NumberOfLinenumbers ));
|
|
if ( fwrite( &ish, 1, sizeof( ish ), CurrFile[OBJ] ) != sizeof( ish ) )
|
|
WriteError();
|
|
}
|
|
#ifdef DEBUG_OUT
|
|
cm->start_symtab = fileoffset;
|
|
#endif
|
|
DebugMsg(("coff_write_section_table: exit\n"));
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
|
|
/*
|
|
* get value for field 'type' ( IMAGE_SYM_TYPE_x ) in symbol table.
|
|
* MS tools use only 0x0 or 0x20.
|
|
*/
|
|
static short CoffGetType( const struct asym *sym )
|
|
/************************************************/
|
|
{
|
|
if ( sym->isproc )
|
|
return( 0x20 );
|
|
|
|
#if 0
|
|
switch (sym->mem_type) {
|
|
case MT_BYTE:
|
|
case MT_SBYTE:
|
|
return( IMAGE_SYM_TYPE_BYTE );
|
|
case MT_WORD:
|
|
case MT_SWORD:
|
|
return( IMAGE_SYM_TYPE_WORD );
|
|
case MT_DWORD:
|
|
case MT_SDWORD:
|
|
return( IMAGE_SYM_TYPE_DWORD );
|
|
}
|
|
#endif
|
|
return( IMAGE_SYM_TYPE_NULL );
|
|
}
|
|
|
|
/*
|
|
* get value for field 'class' ( IMAGE_SYM_CLASS_x ) in symbol table.
|
|
*/
|
|
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 ) /* assembly time variable in fixup */
|
|
return( IMAGE_SYM_CLASS_LABEL );
|
|
#endif
|
|
/* v2.09: don't declare private procs as label */
|
|
//else if ( sym->mem_type == MT_NEAR )/* added v2.0 */
|
|
else if ( sym->mem_type == MT_NEAR && sym->isproc == FALSE )
|
|
return( IMAGE_SYM_CLASS_LABEL );
|
|
|
|
return( IMAGE_SYM_CLASS_STATIC );
|
|
}
|
|
|
|
/* calc number of entries in symbol table for a file entry */
|
|
|
|
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 );
|
|
/**/myassert( len ); /* name length must be > 0 */
|
|
return ( len / sizeof( IMAGE_AUX_SYMBOL ) + ( len % sizeof( IMAGE_AUX_SYMBOL ) ? 1 : 0 ) );
|
|
}
|
|
|
|
#if COMDATSUPP
|
|
|
|
/* v2.10: COMDAT CRC calculation ( suggestion by drizz, slightly modified ) */
|
|
|
|
static uint_32 CRC32Table[256]; /* table is initialized if needed */
|
|
|
|
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 ) /* v2.11: lpBuffer may be NULL ( uninitialized data segs ) */
|
|
for ( ; dwBufLen; dwBufLen-- ) {
|
|
byt = *lpBuffer++;
|
|
byt = byt ^ (uint_8)dwCRC;
|
|
dwCRC = dwCRC >> 8;
|
|
dwCRC = dwCRC ^ CRC32Table[byt];
|
|
}
|
|
return( dwCRC );
|
|
}
|
|
#endif
|
|
|
|
/* write COFF symbol table
|
|
* contents of the table
|
|
* - @@feat.00 if .SAFESEH was set
|
|
* - file (+ 1-n aux)
|
|
* - 2 entries per section
|
|
* - externals, communals and publics
|
|
* - entries for relocations (internal)
|
|
* - aliases (weak externals)
|
|
*/
|
|
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_SYMBOL is;
|
|
IMAGE_AUX_SYMBOL ias;
|
|
unsigned lastfile = 0;
|
|
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
|
|
|
|
DebugMsg(("coff_write_symbols: enter\n"));
|
|
|
|
#if COMPID
|
|
/* write "@comp.id" entry */
|
|
if ( fwrite( &isCompId, 1, sizeof(IMAGE_SYMBOL), CurrFile[OBJ] ) != sizeof(IMAGE_SYMBOL) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
#endif
|
|
/* "@feat.00" entry (for SafeSEH) */
|
|
if ( Options.safeseh ) {
|
|
if ( fwrite( &isFeat00, 1, sizeof(IMAGE_SYMBOL), CurrFile[OBJ] ) != sizeof(IMAGE_SYMBOL) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
}
|
|
|
|
/* .file item (optionally disabled by -zlf) */
|
|
|
|
if ( Options.no_file_entry == FALSE ) {
|
|
strncpy( is.N.ShortName, ".file", IMAGE_SIZEOF_SHORT_NAME );
|
|
is.Value = ( Options.line_numbers ? cm->start_files : 0 ); /* index of next .file entry */
|
|
is.SectionNumber = (uint_16)IMAGE_SYM_DEBUG;
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.StorageClass = IMAGE_SYM_CLASS_FILE;
|
|
|
|
p = cm->dot_file_value;
|
|
i = strlen( p );
|
|
is.NumberOfAuxSymbols = i / sizeof(IMAGE_AUX_SYMBOL) + (i % sizeof(IMAGE_AUX_SYMBOL) ? 1 : 0);
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
|
|
for ( i = is.NumberOfAuxSymbols;i;i--, p += sizeof(IMAGE_AUX_SYMBOL) ) {
|
|
strncpy( ias.File.Name, p, sizeof(IMAGE_AUX_SYMBOL) );
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
}
|
|
cntSymbols += is.NumberOfAuxSymbols + 1;
|
|
}
|
|
|
|
/* next are section entries */
|
|
|
|
for( i = 1, curr = SymTables[TAB_SEG].head; curr; curr = curr->next, i++ ) {
|
|
/* v2.07: prefer ALIAS name if defined */
|
|
p = ( curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ConvertSectionName( &curr->sym, NULL, buffer ) );
|
|
len = strlen( p );
|
|
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
|
|
strncpy( is.N.ShortName, p, IMAGE_SIZEOF_SHORT_NAME );
|
|
else {
|
|
is.N.Name.Short = 0;
|
|
is.N.Name.Long = Coff_AllocString( cm, p, len );
|
|
}
|
|
is.Value = 0;
|
|
is.SectionNumber = i;
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
is.NumberOfAuxSymbols = 0;
|
|
if ( Options.no_section_aux_entry == FALSE )
|
|
is.NumberOfAuxSymbols = 1;
|
|
|
|
DebugMsg(("coff_write_symbols(%u, SECT): %s, type=%x, stgcls=%x\n", cntSymbols, curr->sym.name, is.Type, is.StorageClass ));
|
|
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
|
|
/* write the auxiliary symbol record for sections.
|
|
* may be suppressed with option -zls.
|
|
*/
|
|
if ( Options.no_section_aux_entry == FALSE
|
|
#if COMDATSUPP
|
|
|| curr->e.seginfo->comdat_selection
|
|
#endif
|
|
) {
|
|
ias.Section.Length = curr->sym.max_offset;
|
|
/* v2.10: check for overflow */
|
|
//ias.Section.NumberOfRelocations = curr->e.seginfo->num_relocs;
|
|
ias.Section.NumberOfRelocations = ( curr->e.seginfo->num_relocs > 0xffff ? 0xffff : (uint_16)curr->e.seginfo->num_relocs );
|
|
if ( Options.line_numbers )
|
|
ias.Section.NumberOfLinenumbers = curr->e.seginfo->num_linnums;
|
|
else
|
|
ias.Section.NumberOfLinenumbers = 0;
|
|
/* CheckSum, Number and Selection are for COMDAT sections only */
|
|
#if COMDATSUPP
|
|
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;
|
|
} else {
|
|
#endif
|
|
ias.Section.CheckSum = 0;
|
|
ias.Section.Number = 0;
|
|
ias.Section.Selection = 0;
|
|
#if COMDATSUPP
|
|
};
|
|
#endif
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
DebugMsg(("coff_write_symbols(%u, SECT): %s, AUX, relocs=%u, linnums=%u\n", cntSymbols, curr->sym.name, ias.Section.NumberOfRelocations, ias.Section.NumberOfLinenumbers ));
|
|
cntSymbols++;
|
|
}
|
|
}
|
|
|
|
/* third are externals + communals ( + protos [since v2.01] ) */
|
|
|
|
for( curr = SymTables[TAB_EXT].head ; curr != NULL ;curr = curr->next ) {
|
|
/* skip "weak" (=unused) externdefs */
|
|
if ( curr->sym.iscomm == FALSE && curr->sym.weak == TRUE ) {
|
|
DebugMsg(("coff_write_symbols(EXT+COMM): %s skipped, used=%u, comm=%u, weak=%u\n", curr->sym.name, curr->sym.used, curr->sym.iscomm, curr->sym.weak ));
|
|
continue;
|
|
}
|
|
len = Mangle( &curr->sym, buffer );
|
|
|
|
is.Type = CoffGetType(&curr->sym);
|
|
is.StorageClass = CoffGetClass(&curr->sym);
|
|
|
|
DebugMsg(("coff_write_symbols(%u, EXT+COMM): %s, type=%x, stgcls=%x\n", cntSymbols, curr->sym.name, is.Type, is.StorageClass ));
|
|
|
|
/* for COMMUNALs, store their size in the Value field */
|
|
if (curr->sym.iscomm == TRUE)
|
|
is.Value = curr->sym.total_size;
|
|
else
|
|
is.Value = curr->sym.offset; /* is always 0 */
|
|
is.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
is.NumberOfAuxSymbols = (( curr->sym.iscomm == FALSE && curr->sym.altname ) ? 1 : 0 );
|
|
|
|
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
|
|
strncpy( is.N.ShortName, buffer, IMAGE_SIZEOF_SHORT_NAME );
|
|
else {
|
|
is.N.Name.Short = 0;
|
|
is.N.Name.Long = Coff_AllocString( cm, buffer, len );
|
|
}
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
|
|
/* for weak externals, write the auxiliary record */
|
|
if ( curr->sym.iscomm == FALSE && curr->sym.altname ) {
|
|
memset( &ias, 0, sizeof(ias) );
|
|
ias.Sym.TagIndex = curr->sym.altname->ext_idx;
|
|
/* v2.10: weak externals defined via "extern sym (altsym) ..."
|
|
* are to have characteristics IMAGE_WEAK_EXTERN_SEARCH_LIBRARY.
|
|
*/
|
|
//ias.Sym.Misc.TotalSize = IMAGE_WEAK_EXTERN_SEARCH_ALIAS;
|
|
ias.Sym.Misc.TotalSize = IMAGE_WEAK_EXTERN_SEARCH_LIBRARY;
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
}
|
|
}
|
|
|
|
/* publics and internal symbols. The internal symbols have
|
|
* been written to the "public" queue inside coff_write_data().
|
|
*/
|
|
for ( q = ModuleInfo.g.PubQueue.head; q; q = q->next ) {
|
|
sym = q->sym;
|
|
len = Mangle( sym, buffer );
|
|
#ifdef DEBUG_OUT
|
|
if ( sym->state == SYM_INTERNAL && sym->isproc == TRUE && Options.line_numbers )
|
|
DebugMsg(("coff_write_symbols(%u): %s, file=%u\n", cntSymbols, sym->name, sym->debuginfo->file ));
|
|
#endif
|
|
if ( Options.line_numbers &&
|
|
sym->isproc &&
|
|
sym->debuginfo->file != lastfile ) {
|
|
lastfile = sym->debuginfo->file;
|
|
strncpy( is.N.ShortName, ".file", IMAGE_SIZEOF_SHORT_NAME );
|
|
is.SectionNumber = (uint_16)IMAGE_SYM_DEBUG;
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.StorageClass = IMAGE_SYM_CLASS_FILE;
|
|
is.NumberOfAuxSymbols = GetFileAuxEntries( sym->debuginfo->file, &p );
|
|
is.Value = sym->debuginfo->next_file;
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
|
|
for ( i = is.NumberOfAuxSymbols; i; i--, p += sizeof(IMAGE_AUX_SYMBOL) ) {
|
|
strncpy( ias.File.Name, p, sizeof(IMAGE_AUX_SYMBOL) );
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
}
|
|
cntSymbols += is.NumberOfAuxSymbols + 1;
|
|
}
|
|
is.Type = CoffGetType( sym );
|
|
is.StorageClass = CoffGetClass( sym );
|
|
is.Value = sym->offset;
|
|
#if 1 /* v2.07: changed - to make MT_ABS obsolete */
|
|
if ( sym->state == SYM_INTERNAL ) {
|
|
if ( sym->segment )
|
|
is.SectionNumber = GetSegIdx( sym->segment );
|
|
else
|
|
is.SectionNumber = (uint_16)IMAGE_SYM_ABSOLUTE;
|
|
} else
|
|
is.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
#else
|
|
if ( sym->state == SYM_EXTERNAL )
|
|
is.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
else if ( sym->mem_type == MT_ABS )
|
|
is.SectionNumber = IMAGE_SYM_ABSOLUTE;
|
|
else if ( sym->segment )
|
|
is.SectionNumber = GetSegIdx( sym->segment );
|
|
else
|
|
is.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
#endif
|
|
is.NumberOfAuxSymbols = 0;
|
|
if ( Options.line_numbers && sym->isproc )
|
|
is.NumberOfAuxSymbols++;
|
|
|
|
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
|
|
strncpy( is.N.ShortName, buffer, IMAGE_SIZEOF_SHORT_NAME );
|
|
else {
|
|
is.N.Name.Short = 0;
|
|
is.N.Name.Long = Coff_AllocString( cm, buffer, len );
|
|
}
|
|
|
|
DebugMsg(("coff_write_symbols(%u, PUB+INT): %s, ofs=%X, type=%X, stgcls=%X\n", cntSymbols, buffer, is.Value, is.Type, is.StorageClass ));
|
|
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
if ( Options.line_numbers && sym->isproc ) {
|
|
/* write:
|
|
* 1. the aux for the proc
|
|
* 2+3. a .bf record with 1 aux
|
|
* 4. a .lf record with 0 aux
|
|
* 5+6. a .ef record with 1 aux
|
|
*/
|
|
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;
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
|
|
strncpy( is.N.ShortName, ".bf", IMAGE_SIZEOF_SHORT_NAME );
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.NumberOfAuxSymbols = 1;
|
|
is.StorageClass = IMAGE_SYM_CLASS_FUNCTION;
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
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;
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
|
|
strncpy( is.N.ShortName, ".lf", IMAGE_SIZEOF_SHORT_NAME );
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.NumberOfAuxSymbols = 0;
|
|
is.StorageClass = IMAGE_SYM_CLASS_FUNCTION;
|
|
is.Value = sym->debuginfo->line_numbers;
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
|
|
strncpy( is.N.ShortName, ".ef", IMAGE_SIZEOF_SHORT_NAME );
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.NumberOfAuxSymbols = 1;
|
|
is.StorageClass = IMAGE_SYM_CLASS_FUNCTION;
|
|
is.Value = sym->offset + sym->total_size;
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
ias.Sym.TagIndex = 0;
|
|
ias.Sym.Misc.LnSz.Linenumber = sym->debuginfo->end_line;
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
|
|
cntSymbols += 6;
|
|
}
|
|
}
|
|
|
|
/* aliases. A weak external entry with 1 aux entry is created.
|
|
*/
|
|
for( curr = SymTables[TAB_ALIAS].head ; curr != NULL ;curr = curr->next ) {
|
|
struct asym * sym;
|
|
|
|
len = Mangle( &curr->sym, buffer );
|
|
|
|
if ( len <= IMAGE_SIZEOF_SHORT_NAME )
|
|
strncpy( is.N.ShortName, buffer, IMAGE_SIZEOF_SHORT_NAME );
|
|
else {
|
|
is.N.Name.Short = 0;
|
|
is.N.Name.Long = Coff_AllocString( cm, buffer, len );
|
|
}
|
|
|
|
is.Value = 0;
|
|
is.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
is.Type = IMAGE_SYM_TYPE_NULL;
|
|
is.StorageClass = IMAGE_SYM_CLASS_WEAK_EXTERNAL;
|
|
is.NumberOfAuxSymbols = 1;
|
|
|
|
DebugMsg(("coff_write_symbols(%u, ALIAS): symbol %s, ofs=%X\n", cntSymbols, buffer, is.Value ));
|
|
|
|
if ( fwrite( &is, 1, sizeof(is), CurrFile[OBJ] ) != sizeof(is) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
|
|
memset( &ias, 0, sizeof(ias) );
|
|
|
|
/* v2.04b: adjusted to new field <substitute> */
|
|
//sym = SymSearch( curr->sym.string_ptr );
|
|
sym = curr->sym.substitute;
|
|
if (sym)
|
|
ias.Sym.TagIndex = sym->ext_idx;
|
|
|
|
ias.Sym.Misc.TotalSize = IMAGE_WEAK_EXTERN_SEARCH_ALIAS;
|
|
if ( fwrite( &ias, 1, sizeof(ias), CurrFile[OBJ] ) != sizeof(ias) )
|
|
WriteError();
|
|
cntSymbols++;
|
|
|
|
}
|
|
|
|
DebugMsg(("coff_write_symbols: exit cntSymbols=%u\n", 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; // 8 == size of " -entry:"
|
|
}
|
|
return( size );
|
|
}
|
|
|
|
/* callback to flush contents of codeview symbolic debug info sections */
|
|
|
|
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 );
|
|
}
|
|
|
|
/* calc the current number of entries in the symbol table
|
|
* so we know the index if a new entry has to be added
|
|
* called by coff_write_data()
|
|
*/
|
|
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;
|
|
|
|
index = 0;
|
|
cm->lastproc = NULL;
|
|
cm->start_files = 0; /* v2.11: added */
|
|
|
|
#if COMPID
|
|
index++;
|
|
#endif
|
|
/* add absolute symbol @@feat.00 if -SAFESEH is set */
|
|
if ( Options.safeseh )
|
|
index++;
|
|
|
|
/* count AUX entries for .file. Depends on sizeof filename */
|
|
|
|
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++;
|
|
}
|
|
|
|
/* add entries for sections */
|
|
|
|
cm->sectionstart = index;
|
|
index += ModuleInfo->g.num_segs;
|
|
if ( Options.no_section_aux_entry == FALSE )
|
|
index += ModuleInfo->g.num_segs;
|
|
|
|
/* count externals and protos */
|
|
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++;
|
|
/* weak externals need an additional aux entry */
|
|
if ( curr->sym.iscomm == FALSE && curr->sym.altname )
|
|
index++;
|
|
}
|
|
|
|
#if STATIC_PROCS
|
|
/* v2.04: count private procedures (will become static symbols) */
|
|
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
|
|
/* count items in public queue */
|
|
for ( q = ModuleInfo->g.PubQueue.head; q; q = q->next ) {
|
|
sym = q->sym;
|
|
/* if line numbers are on, co, add 6 entries for procs */
|
|
if ( Options.line_numbers && sym->isproc ) {
|
|
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 );
|
|
}
|
|
|
|
/* write fixups for a section. */
|
|
|
|
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;
|
|
IMAGE_RELOCATION ir;
|
|
|
|
/* v2.10: handle the reloc-overflow-case */
|
|
if ( section->e.seginfo->num_relocs > 0xffff ) {
|
|
DebugMsg(("coff_write_fixups(%s): enter, num_relocs=%" I32_SPEC "u\n", section->sym.name, section->e.seginfo->num_relocs ));
|
|
ir.VirtualAddress = section->e.seginfo->num_relocs + 1;
|
|
ir.SymbolTableIndex = 0;
|
|
ir.Type = IMAGE_REL_I386_ABSOLUTE; /* doesn't matter if 32- or 64-bit */
|
|
if ( fwrite( &ir, 1, sizeof(ir), CurrFile[OBJ] ) != sizeof(ir) )
|
|
WriteError();
|
|
offset += sizeof( ir );
|
|
}
|
|
/* reset counter */
|
|
section->e.seginfo->num_relocs = 0;
|
|
|
|
for ( fix = section->e.seginfo->FixupList.head; fix ; fix = fix->nextrlc ) {
|
|
#if AMD64_SUPPORT
|
|
if ( section->e.seginfo->Ofssize == USE64 ) {
|
|
switch ( fix->type ) {
|
|
case FIX_VOID:
|
|
continue;
|
|
case FIX_RELOFF32: /* 32bit offset */
|
|
/* translated to IMAGE_REL_AMD64_REL32_[1|2|3|4|5] */
|
|
ir.Type = IMAGE_REL_AMD64_REL32 + (fix->addbytes - 4);
|
|
break;
|
|
case FIX_OFF32: /* 32bit offset */
|
|
ir.Type = IMAGE_REL_AMD64_ADDR32;
|
|
break;
|
|
#if IMAGERELSUPP
|
|
case FIX_OFF32_IMGREL:
|
|
ir.Type = IMAGE_REL_AMD64_ADDR32NB;
|
|
break;
|
|
#endif
|
|
#if SECTIONRELSUPP
|
|
case FIX_OFF32_SECREL:
|
|
ir.Type = IMAGE_REL_AMD64_SECREL;
|
|
break;
|
|
#endif
|
|
case FIX_OFF64: /* 64bit offset */
|
|
ir.Type = IMAGE_REL_AMD64_ADDR64;
|
|
break;
|
|
case FIX_SEG: /* segment fixup */
|
|
ir.Type = IMAGE_REL_AMD64_SECTION; /* ??? */
|
|
break;
|
|
#if 0 /* not supported by COFF64! shouldn't reach this point */
|
|
case FIX_RELOFF8:
|
|
case FIX_RELOFF16:
|
|
case FIX_OFF8:
|
|
case FIX_OFF16:
|
|
case FIX_HIBYTE:
|
|
case FIX_PTR16: /* 16bit far pointer */
|
|
case FIX_PTR32: /* 32bit far pointer */
|
|
#endif
|
|
default:
|
|
DebugMsg(("coff_write_fixups(%s, %Xh): reloc loc=%X type=%u idx=%u sym=%s\n",
|
|
section->sym.name, offset, fix->locofs, fix->type, fix->sym->ext_idx, fix->sym->name));
|
|
EmitErr( UNKNOWN_FIXUP_TYPE, fix->type, section->sym.name, fix->locofs );
|
|
continue; /* v2.03: skip this fixup */
|
|
//break;
|
|
}
|
|
} else
|
|
#endif
|
|
switch ( fix->type ) {
|
|
case FIX_VOID:
|
|
continue;
|
|
case FIX_RELOFF16: /* 16bit offset */
|
|
ir.Type = IMAGE_REL_I386_REL16;
|
|
break;
|
|
case FIX_OFF16: /* 16bit offset */
|
|
ir.Type = IMAGE_REL_I386_DIR16;
|
|
break;
|
|
case FIX_RELOFF32: /* 32bit offset */
|
|
ir.Type = IMAGE_REL_I386_REL32;
|
|
break;
|
|
case FIX_OFF32: /* 32bit offset */
|
|
ir.Type = IMAGE_REL_I386_DIR32;
|
|
break;
|
|
#if IMAGERELSUPP
|
|
case FIX_OFF32_IMGREL:
|
|
ir.Type = IMAGE_REL_I386_DIR32NB;
|
|
break;
|
|
#endif
|
|
#if SECTIONRELSUPP
|
|
case FIX_OFF32_SECREL:
|
|
ir.Type = IMAGE_REL_I386_SECREL;
|
|
break;
|
|
#endif
|
|
case FIX_SEG: /* segment fixup */
|
|
ir.Type = IMAGE_REL_I386_SECTION; /* ??? */
|
|
break;
|
|
#if 0
|
|
case FIX_OFF8:
|
|
case FIX_RELOFF8:
|
|
case FIX_HIBYTE:
|
|
case FIX_PTR16: /* 16bit far pointer */
|
|
case FIX_PTR32: /* 32bit far pointer */
|
|
#endif
|
|
default:
|
|
DebugMsg(("coff_write_fixups(%s, %Xh): reloc loc=%X type=%u idx=%u sym=%s\n",
|
|
section->sym.name, offset, fix->locofs, fix->type, fix->sym->ext_idx, fix->sym->name));
|
|
EmitErr( UNKNOWN_FIXUP_TYPE, fix->type, section->sym.name, fix->locofs );
|
|
continue; /* v2.03: skip this fixup */
|
|
//break;
|
|
}
|
|
/* if it's not EXTERNAL/PUBLIC, add symbol */
|
|
/* if it's an assembly time variable, create helper symbol */
|
|
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; /* storage class LABEL */
|
|
fix->sym = sym;
|
|
AddPublicData( fix->sym );
|
|
fix->sym->idx = index++;
|
|
#else
|
|
/* just use the segment entry. This approach requires
|
|
* that the offset is stored inline at the reloc location
|
|
* (patch in fixup.c)
|
|
*/
|
|
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 );
|
|
DebugMsg(("coff_write_fixups(%s, %Xh): %s added to symbol table, idx=%u\n",
|
|
section->sym.name, offset, fix->sym->name, index ));
|
|
fix->sym->ext_idx = index++;
|
|
if ( Options.line_numbers && fix->sym->isproc )
|
|
index += 6;
|
|
}
|
|
ir.VirtualAddress = fix->locofs;
|
|
ir.SymbolTableIndex = fix->sym->ext_idx;
|
|
if ( fwrite( &ir, 1, sizeof(ir), CurrFile[OBJ] ) != sizeof(ir) )
|
|
WriteError();
|
|
DebugMsg(("coff_write_fixups(%s, %Xh): reloc loc=%X type=%u idx=%u sym=%s\n",
|
|
section->sym.name, offset, ir.VirtualAddress, ir.Type, ir.SymbolTableIndex, fix->sym->name));
|
|
offset += sizeof( ir );
|
|
section->e.seginfo->num_relocs++;
|
|
} /* end for */
|
|
DebugMsg(("coff_write_fixups(%s): exit, num_relocs=%" I32_SPEC "u\n", section->sym.name, section->e.seginfo->num_relocs ));
|
|
*poffset = offset;
|
|
*pindex = index;
|
|
}
|
|
|
|
/* write section data */
|
|
|
|
static ret_code coff_write_data( struct module_info *modinfo, struct coffmod *cm )
|
|
/********************************************************************************/
|
|
{
|
|
struct dsym *section;
|
|
uint_32 offset = 0; /* offset within section contents */
|
|
int i;
|
|
uint_32 index;
|
|
|
|
DebugMsg(("coff_write_data(%s): enter\n", modinfo->name ));
|
|
|
|
/* v2.11: removed. max_offset has been set already */
|
|
//if ( directives )
|
|
// directives->sym.max_offset = size_drectve;
|
|
|
|
/* calc the current index for the COFF symbol table */
|
|
index = SetSymbolIndices( modinfo, cm );
|
|
|
|
/* fill the SafeSEH array */
|
|
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;
|
|
DebugMsg(("coff_write_data: .sxdata value=%08Xh\n", ((struct asym *)sehp->elmt)->ext_idx));
|
|
*pdw++ = ((struct asym *)sehp->elmt)->ext_idx;
|
|
LclFree( sehp );
|
|
}
|
|
}
|
|
|
|
#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
|
|
|
|
/* now scan the section's relocations. If a relocation refers to
|
|
a symbol which is not public/external, it must be added to the
|
|
symbol table. If the symbol is an assembly time variable, a helper
|
|
symbol - name is $$<offset:6> is to be added.
|
|
*/
|
|
|
|
for( section = SymTables[TAB_SEG].head; section ; section = section->next ) {
|
|
uint_32 size;
|
|
size = section->sym.max_offset;
|
|
#ifdef DEBUG_OUT
|
|
if ( section->e.seginfo->CodeBuffer )
|
|
DebugMsg(("coff_write_data(%s, %Xh): size=%X, written=%X, content=[%02X %02X ...]\n",
|
|
section->sym.name, offset, size - section->e.seginfo->start_loc, section->e.seginfo->bytes_written, *(section->e.seginfo->CodeBuffer), *(section->e.seginfo->CodeBuffer+1)));
|
|
else
|
|
DebugMsg(("coff_write_data(%s, %Xh): size=%X, buffer=NULL\n",
|
|
section->sym.name, offset, size - section->e.seginfo->start_loc ));
|
|
#endif
|
|
|
|
/* don't write section data for bss and uninitialized stack segments */
|
|
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 there was an ORG, the buffer content will
|
|
* start with the ORG address. The bytes from
|
|
* 0 - ORG must be written by moving the file pointer!
|
|
*/
|
|
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 );
|
|
} /* end if (size) */
|
|
|
|
/* v2.07: the following block has beem moved outside of "if(size)" block,
|
|
* because it may happen that a segment has size 0 and still debug info.
|
|
* In any case it's important to initialize section->e.seginfo->num_linnums
|
|
*/
|
|
/* write line number data. The peculiarity of COFF (compared to OMF) is
|
|
* that line numbers are always relative to a function start.
|
|
*
|
|
* an item with line number 0 has a special meaning - it contains a reference
|
|
* ( a symbol table index ) to the function whose line numbers are to follow.
|
|
* this item is to be followed by an item with line number 32767, which then
|
|
* tells the function's start offset ( undocumented! ).
|
|
*
|
|
*/
|
|
if( Options.line_numbers && section->e.seginfo->LinnumQueue ) {
|
|
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;
|
|
DebugMsg(("coff_write_data(%s): writing linnum data\n", section->sym.name ));
|
|
for( ; lni; lni = lni->next ) {
|
|
DebugMsg(("coff_write_data(%s, %Xh): linnum, #=%u, %s=%X, sym=%s\n",
|
|
section->sym.name, offset, lni->number, lni->number ? "ofs" : "idx", lni->offset, lni->number ? "NULL" : lni->sym->name ));
|
|
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;
|
|
#ifdef DEBUG_OUT
|
|
/* if symbol table index is 0, then the proc wasn't added
|
|
* to the "publics" queue in AddLinnumDataRef().
|
|
*/
|
|
if ( lni->sym->ext_idx == 0 ) {
|
|
DebugMsg(("coff_write_data(%s, %Xh): error, %s has symbol table index 0\n",
|
|
section->sym.name, offset, lni->sym->name ));
|
|
}
|
|
#endif
|
|
il.Type.SymbolTableIndex = lni->sym->ext_idx;
|
|
lni->sym->debuginfo->start_line = lni->line_number;
|
|
//((struct dsym *)lni->sym)->e.procinfo->file = lni->file;
|
|
lni->sym->debuginfo->ln_fileofs = cm->start_data + offset;
|
|
DebugMsg(("coff_write_data(%s, %Xh): proc %s start_line=%u\n",
|
|
section->sym.name, offset, lni->sym->name, lni->sym->debuginfo->start_line ));
|
|
} else {
|
|
/**/myassert( last != NULL );
|
|
il.Linenumber = lni->number - last->debuginfo->start_line;
|
|
/* if current line number - start line number is 0,
|
|
* generate a "32767" line number item.
|
|
*/
|
|
if ( il.Linenumber == 0 )
|
|
il.Linenumber = 0x7FFF;
|
|
il.Type.VirtualAddress = lni->offset;
|
|
}
|
|
/* v2.11: last is always != NULL */
|
|
//if ( last ) {
|
|
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++;
|
|
} /* end for */
|
|
section->e.seginfo->num_linnums = line_numbers;
|
|
} /* end if (Options.line_numbers...) */
|
|
} /* end for */
|
|
|
|
cm->size_data = offset;
|
|
|
|
DebugMsg(("coff_write_data: exit, size of sections=%Xh\n", cm->size_data ));
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* check if a .drectve section has to be created.
|
|
* if yes, create it and set its contents.
|
|
*/
|
|
|
|
static void coff_create_drectve( struct module_info *modinfo, struct coffmod *cm )
|
|
/********************************************************************************/
|
|
{
|
|
struct dsym *exp;
|
|
#if DLLIMPORT
|
|
struct dsym *imp = NULL;
|
|
#endif
|
|
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
|
|
|
|
/* does a proc exist with the EXPORT attribute? */
|
|
for( exp = SymTables[TAB_PROC].head; exp != NULL; exp = exp->nextproc ) {
|
|
if( exp->e.procinfo->isexport )
|
|
break;
|
|
}
|
|
#if DLLIMPORT
|
|
/* check if an impdef record is there */
|
|
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;
|
|
#endif
|
|
/* add a .drectve section if
|
|
- a start_label is defined and/or
|
|
- a library is included and/or
|
|
- a proc is exported and/or
|
|
- impdefs are to be written (-Zd)
|
|
*/
|
|
if ( modinfo->g.start_label != NULL ||
|
|
modinfo->g.LibQueue.head != NULL ||
|
|
#if DLLIMPORT
|
|
imp != NULL ||
|
|
#endif
|
|
exp != NULL ) {
|
|
if ( (cm->directives = (struct dsym *)CreateIntSegment( szdrectve, "", MAX_SEGALIGNMENT, modinfo->Ofssize, FALSE )) != NULL ) {
|
|
struct dsym *tmp;
|
|
int size = 0;
|
|
struct qitem *q;
|
|
uint_8 *p;
|
|
cm->directives->e.seginfo->info = TRUE;
|
|
DebugMsg(("coff_create_drectve: %s section added\n", szdrectve));
|
|
|
|
/* calc the size for this segment */
|
|
/* 1. exports */
|
|
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;
|
|
}
|
|
}
|
|
/* 2. defaultlibs */
|
|
for( q = modinfo->g.LibQueue.head; q ; q = q->next ) {
|
|
size += strlen( q->value ) + sizeof("-defaultlib:");
|
|
/* if the name isn't enclosed in double quotes and contains
|
|
a space, add 2 bytes to enclose it */
|
|
if ( *q->value != '"' && strchr( q->value, ' ') )
|
|
size += 2;
|
|
}
|
|
/* 3. start label */
|
|
size += GetStartLabel( buffer, TRUE );
|
|
#if DLLIMPORT
|
|
/* 4. impdefs */
|
|
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 ) {
|
|
/* format is:
|
|
* "-import:<mangled_name>=<module_name>.<unmangled_name>" or
|
|
* "-import:<mangled_name>=<module_name>"
|
|
*/
|
|
size += sizeof("-import:");
|
|
size += Mangle( &tmp->sym, buffer );
|
|
size += 1 + strlen( tmp->sym.dll->name );
|
|
size += 1 + tmp->sym.name_size;
|
|
}
|
|
}
|
|
#endif
|
|
cm->directives->sym.max_offset = size;
|
|
/* v2.09: allocate 1 byte more, because sprintf() is used, which
|
|
* adds a NULLC.
|
|
*/
|
|
//directives->e.seginfo->CodeBuffer = LclAlloc( size );
|
|
cm->directives->e.seginfo->CodeBuffer = LclAlloc( size + 1 );
|
|
p = cm->directives->e.seginfo->CodeBuffer;
|
|
|
|
/* copy the data */
|
|
|
|
/* 1. exports */
|
|
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 );
|
|
}
|
|
}
|
|
/* 2. libraries */
|
|
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 );
|
|
}
|
|
/* 3. entry */
|
|
if ( modinfo->g.start_label ) {
|
|
GetStartLabel( buffer, FALSE );
|
|
p += sprintf( (char *)p, "-entry:%s ", buffer );
|
|
}
|
|
#if DLLIMPORT
|
|
/* 4. impdefs */
|
|
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++ = ' ';
|
|
}
|
|
}
|
|
#endif
|
|
/**/myassert( size == p - cm->directives->e.seginfo->CodeBuffer );
|
|
//size_drectve = p - directives->e.seginfo->CodeBuffer; /* v2.11:removed */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Write current object module in COFF format.
|
|
* This function is called AFTER all assembly passes have been done.
|
|
*/
|
|
|
|
static ret_code coff_write_module( struct module_info *modinfo )
|
|
/**************************************************************/
|
|
{
|
|
struct stringitem *pName;
|
|
struct coffmod cm;
|
|
struct IMAGE_FILE_HEADER ifh;
|
|
|
|
DebugMsg(("coff_write_module: enter, sections=%u\n", modinfo->g.num_segs ));
|
|
|
|
memset( &cm, 0, sizeof( cm ) );
|
|
//directives = NULL;
|
|
//LongNames.head = NULL;
|
|
cm.LongNames.size = sizeof( uint_32 );
|
|
|
|
/* get value for .file symbol */
|
|
cm.dot_file_value = CurrFName[ASM];
|
|
#if 0 /* v2.09: always add the name in CurrFName[ASM] */
|
|
cm.dot_file_value += strlen( dot_file_value );
|
|
while ( cm.dot_file_value > CurrFName[ASM] &&
|
|
*(cm.dot_file_value-1) != '/' &&
|
|
*(cm.dot_file_value-1) != '\\') cm.dot_file_value--;
|
|
#endif
|
|
|
|
/* it might be necessary to add "internal" sections:
|
|
* - .debug$S and .debug$T sections if -Zi was set
|
|
* - .sxdata section if .SAFESEH was used
|
|
* - .drectve section if start label, exports or includelibs are used
|
|
*/
|
|
|
|
/* if -Zi is set, add .debug$S and .debug$T sections */
|
|
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;
|
|
DebugMsg(("coff_write_module: %s section added\n", SymDebName[i] ));
|
|
cm.SymDeb[i].seg->e.seginfo->characteristics = (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE) >> 24;
|
|
/* use the source line buffer as code buffer. It isn't needed anymore */
|
|
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 );
|
|
/* the contents have been written in queues. now
|
|
* copy all queue items in ONE buffer.
|
|
*/
|
|
for ( i = 0; i < DBGS_MAX; i++ ) {
|
|
uint_8 *src;
|
|
uint_8 *dst;
|
|
if ( cm.SymDeb[i].seg->sym.max_offset ) {
|
|
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;
|
|
/* fixme: free the queue items if FASTMEM==0 */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if safeSEH procs are defined, add a .sxdata section */
|
|
if ( modinfo->g.SafeSEHQueue.head ) {
|
|
struct qnode *sehp;
|
|
unsigned cnt = 0;
|
|
if ( (cm.sxdata = (struct dsym *)CreateIntSegment( ".sxdata", "", MAX_SEGALIGNMENT, modinfo->Ofssize, FALSE )) != NULL ) {
|
|
cm.sxdata->e.seginfo->info = TRUE;
|
|
/* calc the size for this segment */
|
|
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 );
|
|
DebugMsg(("coff_write_module: .sxdata section added, size=%u\n", cnt*4));
|
|
}
|
|
}
|
|
|
|
/* create .drectve section if necessary */
|
|
coff_create_drectve( modinfo, &cm );
|
|
|
|
/* v2.11: removed, max_offset has been set already */
|
|
//if ( directives )
|
|
// directives->sym.max_offset = size_drectve;
|
|
|
|
#if AMD64_SUPPORT
|
|
if ( modinfo->defOfssize == USE64 )
|
|
ifh.Machine = IMAGE_FILE_MACHINE_AMD64;
|
|
else
|
|
#endif
|
|
ifh.Machine = IMAGE_FILE_MACHINE_I386;
|
|
ifh.NumberOfSections = modinfo->g.num_segs;
|
|
#if 0 //def __UNIX__
|
|
time((int_32 *)&ifh.TimeDateStamp);
|
|
#else
|
|
time((time_t *)&ifh.TimeDateStamp);
|
|
#endif
|
|
ifh.SizeOfOptionalHeader = 0;
|
|
ifh.Characteristics = 0;
|
|
|
|
/* position behind coff file header */
|
|
fseek( CurrFile[OBJ], sizeof( ifh ), SEEK_SET );
|
|
|
|
coff_write_section_table( modinfo, &cm );
|
|
coff_write_data( modinfo, &cm );
|
|
/* v2.12: check that calculated sizes are identical to those that have been written */
|
|
/**/myassert( cm.start_symtab == ( cm.start_data + cm.size_data ) );
|
|
|
|
ifh.NumberOfSymbols = coff_write_symbols( modinfo, &cm );
|
|
ifh.PointerToSymbolTable = ( ifh.NumberOfSymbols ? cm.start_data + cm.size_data : 0 );
|
|
|
|
/* the string table is ALWAYS written, even if no strings are defined */
|
|
DebugMsg(("coff_write_module: string_table size=%u\n", cm.LongNames.size ));
|
|
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();
|
|
}
|
|
#if FASTMEM==0
|
|
for ( ; cm.LongNames.head; ) {
|
|
pName = cm.LongNames.head;
|
|
cm.LongNames.head = cm.LongNames.head->next;
|
|
LclFree( pName );
|
|
}
|
|
#endif
|
|
/* finally write the COFF file header */
|
|
fseek( CurrFile[OBJ], 0, SEEK_SET);
|
|
if ( fwrite( &ifh, 1, sizeof( ifh ), CurrFile[OBJ] ) != sizeof( ifh ) ) {
|
|
DebugMsg(("coff_write_module: error writing file header\n"));
|
|
WriteError();
|
|
}
|
|
|
|
DebugMsg(("coff_write_module: exit\n"));
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
void coff_init( struct module_info *modinfo )
|
|
/*******************************************/
|
|
{
|
|
modinfo->g.WriteModule = coff_write_module;
|
|
return;
|
|
}
|
|
#endif
|