jwasm/bin.c
Ilya V. Matveychikov 3b4ec5258f Fix notes produced by clang compiler
note: use '==' to turn this assignment into an equality comparison
2015-07-30 19:11:43 +03:00

1850 lines
76 KiB
C

/****************************************************************************
*
* This code is Public Domain.
*
* ========================================================================
*
* Description: Binary output routines.
* Used if -bin, -mz or -pe cmdline options were set.
*
****************************************************************************/
#include <stddef.h>
#include <ctype.h>
#include <time.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "fixup.h"
#include "omfspec.h"
#include "bin.h"
#include "listing.h"
#include "lqueue.h"
#include "myassert.h"
#if BIN_SUPPORT
#define SECTORMAP 1 /* 1=print sector map in listing file */
#if PE_SUPPORT
#include "coffspec.h"
#include "input.h"
#include "mangle.h"
#include "segment.h"
#include "equate.h"
#include "expreval.h"
#define RAWSIZE_ROUND 1 /* SectionHeader.SizeOfRawData is multiple FileAlign. Required by MS COFF spec */
#define IMGSIZE_ROUND 1 /* OptionalHeader.SizeOfImage is multiple ObjectAlign. Required by MS COFF spec */
#define IMPDIRSUF "2" /* import directory segment suffix */
#define IMPNDIRSUF "3" /* import data null directory entry segment suffix */
#define IMPILTSUF "4" /* ILT segment suffix */
#define IMPIATSUF "5" /* IAT segment suffix */
#define IMPSTRSUF "6" /* import strings segment suffix */
#endif
/* pespec.h contains MZ header declaration */
#if MZ_SUPPORT || PE_SUPPORT
#include "pespec.h"
#endif
extern void SortSegments( int );
#if MZ_SUPPORT
/* default values for OPTION MZ */
static const struct MZDATA mzdata = {0x1E, 0x10, 0, 0xFFFF };
#endif
#if SECTORMAP
/* these strings are to be moved to ltext.h */
static const char szCaption[] = { "Binary Map:" };
static const char szCaption2[] = { "Segment Pos(file) RVA Size(fil) Size(mem)" };
static const char szSep[] = { "---------------------------------------------------------------" };
static const char szHeader[] = { "<header>" };
static const char szSegLine[] = { "%-24s %8" I32_SPEC "X %8" I32_SPEC "X %9" I32_SPEC "X %9" I32_SPEC "X" };
static const char szTotal[] = { "%-42s %9" I32_SPEC "X %9" I32_SPEC "X" };
#endif
struct calc_param {
uint_8 first; /* 1=first call of CalcOffset() */
uint_8 alignment; /* current aligment */
uint_32 fileoffset; /* current file offset */
uint_32 sizehdr; /* -mz: size of MZ header, else 0 */
uint_32 entryoffset; /* -bin only: offset of first segment */
struct asym *entryseg; /* -bin only: segment of first segment */
uint_32 imagestart; /* -bin: start offset (of first segment), else 0 */
#if PE_SUPPORT
uint_32 rva; /* -pe: current RVA */
union {
uint_32 imagebase; /* -pe: image base */
#if AMD64_SUPPORT
uint_64 imagebase64; /* -pe: image base */
#endif
};
#if RAWSIZE_ROUND
uint_32 rawpagesize;
#endif
#endif
};
/* reorder segments for DOSSEG:
1. code
2. unknown
3. initialized data
4. uninitialized data
5. stack
*/
static const enum seg_type dosseg_order[] = {
SEGTYPE_CODE, SEGTYPE_UNDEF, SEGTYPE_DATA,
SEGTYPE_BSS, SEGTYPE_STACK, SEGTYPE_ABS
};
#define SIZE_DOSSEG ( sizeof( dosseg_order ) / sizeof( dosseg_order[0] ) )
#if PE_SUPPORT
static const enum seg_type flat_order[] = {
SEGTYPE_HDR, SEGTYPE_CODE, SEGTYPE_CDATA, SEGTYPE_DATA, SEGTYPE_BSS, SEGTYPE_RSRC, SEGTYPE_RELOC
};
#define SIZE_PEFLAT ( sizeof( flat_order ) / sizeof( flat_order[0] ) )
enum pe_flags_values {
PEF_MZHDR = 0x01, /* 1=create mz header */
};
#define hdrname ".hdr$"
static const char hdrattr[] = { "read public 'HDR'" };
static const char edataname[] = { ".edata" };
static const char edataattr[] = { "FLAT read public alias('.rdata') 'DATA'" };
static const char idataname[] = { ".idata$" };
//static const char idataattr[] = { "FLAT read public 'DATA'" };
static const char idataattr[] = { "FLAT read public alias('.rdata') 'DATA'" };
static const char mzcode[] = {
"db 'MZ'\0" /* e_magic */
"dw 80h, 1, 0, 4\0" /* e_cblp, e_cp, e_crlc, e_cparhdr */
"dw 0, -1, 0, 0B8h\0" /* e_minalloc, e_maxalloc, e_ss, e_sp */
"dw 0, 0, 0, 40h\0" /* e_csum, e_ip, e_cs, e_sp, e_lfarlc */
"org 40h\0" /* e_lfanew, will be set by program */
"push cs\0"
"pop ds\0"
"mov dx,@F - 40h\0"
"mov ah,9\0"
"int 21h\0"
"mov ax,4C01h\0"
"int 21h\0"
"@@:\0"
"db 'This is a PE executable',0Dh,0Ah,'$'"
};
/* default 32-bit PE header */
static const struct IMAGE_PE_HEADER32 pe32def = {
'P'+ ('E' << 8 ),
{ IMAGE_FILE_MACHINE_I386, 0, 0, 0, 0, sizeof( struct IMAGE_OPTIONAL_HEADER32 ),
IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED | IMAGE_FILE_32BIT_MACHINE
},
{ IMAGE_NT_OPTIONAL_HDR32_MAGIC,
5,1,0,0,0,0,0,0, /* linkervers maj/min, sizeof code/init/uninit, entrypoint, base code/data */
0x400000, /* image base */
0x1000, 0x200, /* SectionAlignment, FileAlignment */
4,0,0,0,4,0, /* OSversion maj/min, Imagevers maj/min, Subsystemvers maj/min */
0,0,0,0, /* Win32vers, sizeofimage, sizeofheaders, checksum */
IMAGE_SUBSYSTEM_WINDOWS_CUI,0, /* subsystem, dllcharacteristics */
0x100000,0x1000, /* sizeofstack reserve/commit */
0x100000,0x1000, /* sizeofheap reserve/commit */
0, IMAGE_NUMBEROF_DIRECTORY_ENTRIES, /* loaderflags, numberofRVAandSizes */
}
};
#if AMD64_SUPPORT
/* default 64-bit PE header */
static const struct IMAGE_PE_HEADER64 pe64def = {
'P'+ ('E' << 8 ),
{ IMAGE_FILE_MACHINE_AMD64, 0, 0, 0, 0, sizeof( struct IMAGE_OPTIONAL_HEADER64 ),
IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED | IMAGE_FILE_LARGE_ADDRESS_AWARE | IMAGE_FILE_32BIT_MACHINE
},
{ IMAGE_NT_OPTIONAL_HDR64_MAGIC,
5,1,0,0,0,0,0, /* linkervers maj/min, sizeof code/init data/uninit data, entrypoint, base code RVA */
0x400000, /* image base */
0x1000, 0x200, /* SectionAlignment, FileAlignment */
4,0,0,0,4,0, /* OSversion maj/min, Imagevers maj/min, Subsystemvers maj/min */
0,0,0,0, /* Win32vers, sizeofimage, sizeofheaders, checksum */
IMAGE_SUBSYSTEM_WINDOWS_CUI,0, /* subsystem, dllcharacteristics */
0x100000,0x1000, /* sizeofstack reserve/commit */
0x100000,0x1000, /* sizeofheap reserve/commit */
0, IMAGE_NUMBEROF_DIRECTORY_ENTRIES, /* loaderflags, numberofRVAandSizes */
}
};
#endif
#endif
#ifdef __I86__
/* "huge" fwrite() for JWasmr.exe */
uint_32 hfwrite( uint_8 huge *pBuffer, int size, uint_32 count, FILE *file )
/**************************************************************************/
{
uint_32 written;
unsigned tmpsize;
for ( written = 0; written < count; written += tmpsize ) {
if ( count > 0xFE00 )
tmpsize = 0xFE00;
else
tmpsize = count;
if ( fwrite( pBuffer, size, tmpsize, file ) != tmpsize )
WriteError();
pBuffer += tmpsize;
}
return( written );
}
#endif
/* calculate starting offset of segments and groups */
static void CalcOffset( struct dsym *curr, struct calc_param *cp )
/****************************************************************/
{
uint_32 align;
uint_32 alignbytes;
uint_32 offset;
struct dsym *grp;
if ( curr->e.seginfo->segtype == SEGTYPE_ABS ) {
curr->e.seginfo->start_offset = curr->e.seginfo->abs_frame << 4;
DebugMsg(("CalcOffset(%s): abs seg, offset=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->start_offset ));
return;
} else if ( curr->e.seginfo->info )
return;
grp = (struct dsym *)curr->e.seginfo->group;
if ( cp->alignment > curr->e.seginfo->alignment )
align = 1 << cp->alignment;
else
align = 1 << curr->e.seginfo->alignment;
//alignbytes = ((offset + (align - 1)) & (-align)) - offset;
alignbytes = ((cp->fileoffset + (align - 1)) & (-align)) - cp->fileoffset;
cp->fileoffset += alignbytes;
if ( grp == NULL ) {
offset = cp->fileoffset - cp->sizehdr; // + alignbytes;
DebugMsg(("CalcOffset(%s): fileofs=%" I32_SPEC "Xh, ofs=%" I32_SPEC "Xh\n", curr->sym.name, cp->fileoffset, offset ));
} else {
#if PE_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_PE )
offset = cp->rva;
else
#endif
if ( grp->sym.total_size == 0 ) {
grp->sym.offset = cp->fileoffset - cp->sizehdr;
offset = 0;
} else
offset = grp->sym.total_size + alignbytes;
DebugMsg(("CalcOffset(%s): fileofs=%" I32_SPEC "Xh, alignbytes=%" I32_SPEC "u, ofs=%" I32_SPEC "Xh, group=%s, grp.ofs=%" I32_SPEC "Xh\n",
curr->sym.name, cp->fileoffset, alignbytes, offset, grp->sym.name, grp->sym.offset ));
}
/* v2.04: added */
/* v2.05: this addition did mess sample Win32_5.asm, because the
* "empty" alignment sections are now added to <fileoffset>.
* todo: VA in binary map is displayed wrong.
*/
if ( cp->first == FALSE ) {
/* v2.05: do the reset more carefully.
* Do reset start_loc only if
* - segment is in a group and
* - group isn't FLAT or segment's name contains '$'
*/
if ( grp && ( grp != ModuleInfo.flat_grp ||
strchr( curr->sym.name, '$' ) ) )
curr->e.seginfo->start_loc = 0;
}
curr->e.seginfo->fileoffset = cp->fileoffset;
curr->e.seginfo->start_offset = offset;
//if ( cp->first && ModuleInfo.sub_format == SFORMAT_NONE ) {
if ( ModuleInfo.sub_format == SFORMAT_NONE ) {
cp->fileoffset += curr->sym.max_offset - curr->e.seginfo->start_loc;
if ( cp->first )
cp->imagestart = curr->e.seginfo->start_loc;
/* there's no real entry address for BIN, therefore the
start label must be at the very beginning of the file */
if ( cp->entryoffset == -1 ) {
cp->entryoffset = offset;
cp->entryseg = (struct asym *)curr;
}
} else {
/* v2.05: changed, removed */
//curr->e.seginfo->fileoffset += curr->e.seginfo->start_loc;
//fileoffset += curr->sym.max_offset;
#if PE_SUPPORT
cp->rva += curr->sym.max_offset - curr->e.seginfo->start_loc;
if ( curr->e.seginfo->segtype == SEGTYPE_BSS )
;
else
#endif
cp->fileoffset += curr->sym.max_offset - curr->e.seginfo->start_loc;
}
//offset += curr->sym.max_offset - curr->e.seginfo->start_loc;
offset += curr->sym.max_offset;
if ( grp ) {
//grp->sym.total_size = offset + curr->e.seginfo->start_loc;
grp->sym.total_size = offset;
/* v2.07: for 16-bit groups, ensure that it fits in 64 kB */
if ( grp->sym.total_size > 0x10000 && grp->sym.Ofssize == USE16 ) {
EmitWarn( 2, GROUP_EXCEEDS_64K, grp->sym.name );
}
}
#if PE_SUPPORT
DebugMsg(("CalcOffset(%s) exit: seg.fileofs=%" I32_SPEC "Xh, seg.start_offset=%" I32_SPEC "Xh, endofs=%" I32_SPEC "Xh fileofs=%" I32_SPEC "Xh rva=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->fileoffset, curr->e.seginfo->start_offset, offset, cp->fileoffset, cp->rva ));
#else
DebugMsg(("CalcOffset(%s) exit: seg.fileofs=%" I32_SPEC "Xh, seg.start_offset=%" I32_SPEC "Xh, endofs=%" I32_SPEC "Xh fileofs=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->fileoffset, curr->e.seginfo->start_offset, offset, cp->fileoffset ));
#endif
cp->first = FALSE;
return;
}
#if MZ_SUPPORT
/*
* if pDst==NULL: count the number of segment related fixups
* if pDst!=NULL: write segment related fixups
*/
static int GetSegRelocs( uint_16 *pDst )
/**************************************/
{
struct dsym *curr;
int count = 0;
uint_16 valueofs;
uint_16 valueseg;
uint_32 loc;
struct fixup *fixup;
DebugMsg(("GetSegRelocs( %p ) enter\n", pDst ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == SEGTYPE_ABS )
continue;
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
switch ( fixup->type ) {
case FIX_PTR32:
case FIX_PTR16:
case FIX_SEG:
/* ignore fixups for absolute segments */
if ( fixup->sym && fixup->sym->segment && ((struct dsym *)fixup->sym->segment)->e.seginfo->segtype == SEGTYPE_ABS )
break;
DebugMsg(("GetSegRelocs: found seg-related fixup at %s.%" I32_SPEC "X\n", curr->sym.name, fixup->locofs ));
count++;
if ( pDst ) {
/* v2.04: fixed */
loc = fixup->locofs + ( curr->e.seginfo->start_offset & 0xf );
valueseg = curr->e.seginfo->start_offset >> 4;
if ( curr->e.seginfo->group ) {
loc += curr->e.seginfo->group->offset & 0xf;
valueseg += curr->e.seginfo->group->offset >> 4;
}
if ( fixup->type == FIX_PTR16 )
loc += 2;
else if ( fixup->type == FIX_PTR32 )
loc += 4;
/* offset may be > 64 kB */
while ( loc >= 0x10000 ) {
loc -= 16;
valueseg++;
};
valueofs = loc;
DebugMsg(("GetSegRelocs: locofs=%" I32_SPEC "X fileofs=%" I32_SPEC "X segofs=%" I32_SPEC "X grpofs=%" I32_SPEC "X, fixup value: %X %X\n",
fixup->locofs, curr->e.seginfo->fileoffset, curr->e.seginfo->start_offset, curr->e.seginfo->group ? curr->e.seginfo->group->offset: 0, valueofs, valueseg ));
*pDst++ = valueofs;
*pDst++ = valueseg;
}
break;
}
}
}
DebugMsg(("GetSegRelocs()=%u\n", count ));
return( count );
}
#endif
/* get image size.
* memimage=FALSE: get size without uninitialized segments (BSS and STACK)
* memimage=TRUE: get full size
*/
static uint_32 GetImageSize( bool memimage )
/******************************************/
{
struct dsym *curr;
bool first;
uint_32 vsize = 0;
uint_32 size = 0;
for( curr = SymTables[TAB_SEG].head, first = TRUE; curr; curr = curr->next ) {
uint_32 tmp;
if ( curr->e.seginfo->segtype == SEGTYPE_ABS || curr->e.seginfo->info )
continue;
if ( memimage == FALSE ) {
if ( curr->e.seginfo->bytes_written == 0 ) {
struct dsym *dir;
for ( dir = curr->next; dir; dir = dir->next )
if ( dir->e.seginfo->bytes_written )
break;
if ( !dir )
break; /* done, skip rest of segments! */
}
}
tmp = curr->e.seginfo->fileoffset + (curr->sym.max_offset - curr->e.seginfo->start_loc );
if ( first == FALSE )
vsize += curr->e.seginfo->start_loc;
if ( memimage )
tmp += vsize;
DebugMsg(("GetImageSize(%s): fileofs=%" I32_SPEC "Xh, max_offs=%" I32_SPEC "Xh start=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->fileoffset, curr->sym.max_offset, curr->e.seginfo->start_loc ));
if ( size < tmp )
size = tmp;
first = FALSE;
}
DebugMsg(("GetImageSize(%u)=%" I32_SPEC "Xh\n", memimage, size ));
return( size );
}
/* micro-linker. resolve internal fixups.
*/
union genptr {
uint_8 *db;
uint_16 *dw;
uint_32 *dd;
#if AMD64_SUPPORT
uint_64 *dq;
#endif
};
/* handle the fixups contained in a segment */
static ret_code DoFixup( struct dsym *curr, struct calc_param *cp )
/*****************************************************************/
{
union genptr codeptr;
struct dsym *seg;
uint_32 value;
#if PE_SUPPORT && AMD64_SUPPORT
uint_64 value64;
#endif
uint_32 offset; /* v2.07 */
struct fixup *fixup;
char *tmp;
if ( curr->e.seginfo->segtype == SEGTYPE_ABS )
return( NOT_ERROR );
DebugMsg(("DoFixup(%s) enter, segment start ofs=%" I32_SPEC "Xh\n", curr->sym.name, curr->e.seginfo->start_offset ));
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
codeptr.db = curr->e.seginfo->CodeBuffer +
( fixup->locofs - curr->e.seginfo->start_loc );
//if ( fixup->sym && fixup->sym->segment ) { /* v2.08: changed */
if ( fixup->sym && ( fixup->sym->segment || fixup->sym->variable ) ) {
/* assembly time variable (also $ symbol) in reloc? */
/* v2.07: moved inside if-block, using new local var "offset" */
if ( fixup->sym->variable ) {
seg = (struct dsym *)fixup->segment_var;
offset = 0;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X, %s): variable, fixup->segment=%Xh fixup->offset=%" I32_SPEC "Xh, fixup->sym->offset=%" I32_SPEC "Xh\n",
curr->sym.name, fixup->locofs, fixup->sym->name, seg, fixup->offset, fixup->sym->offset ));
} else {
seg = (struct dsym *)fixup->sym->segment;
offset = fixup->sym->offset;
}
/* the offset result consists of
* - the symbol's offset
* - the fixup's offset (usually the displacement )
* - the segment/group offset in the image
*/
switch ( fixup->type ) {
case FIX_OFF32_IMGREL:
value = ( fixup->offset + offset + seg->e.seginfo->start_offset ) - cp->imagestart;
DebugMsg(("DoFixup(%s): IMGREL, loc=%" I32_SPEC "X value=%" I32_SPEC "X seg.start=%" I32_SPEC "X imagestart=%" I32_SPEC "X\n",
curr->sym.name, fixup->locofs, value, seg->e.seginfo->start_offset, cp->imagestart ));
break;
case FIX_OFF32_SECREL:
value = ( fixup->offset + offset ) - seg->e.seginfo->start_loc;
/* check if symbol's segment name contains a '$'.
* If yes, search the segment without suffix.
*/
if ( (tmp = strchr( seg->sym.name, '$' )) != NULL ) {
int namlen = tmp - seg->sym.name;
struct dsym *segfirst;
for( segfirst = SymTables[TAB_SEG].head; segfirst; segfirst = segfirst->next ) {
if ( segfirst->sym.name_size == namlen &&
( memcmp( segfirst->sym.name, seg->sym.name, namlen ) == 0 ) ) {
value = ( fixup->offset + offset + seg->e.seginfo->start_offset ) - segfirst->e.seginfo->start_offset;
DebugMsg(("DoFixup(%s): SECREL, primary seg=%s, start_offset=%" I32_SPEC "X\n",
curr->sym.name, segfirst->sym.name, segfirst->e.seginfo->start_offset ));
break;
}
}
}
DebugMsg(("DoFixup(%s): SECREL, loc=%" I32_SPEC "X, value=%" I32_SPEC "X\n",
curr->sym.name, fixup->locofs, value ));
break;
case FIX_RELOFF8:
case FIX_RELOFF16:
case FIX_RELOFF32:
/* v1.96: special handling for "relative" fixups */
value = seg->e.seginfo->start_offset + fixup->offset + offset;
DebugMsg(("DoFixup(%s): RELOFFx, loc=%" I32_SPEC "X, sym=%s, [start_offset=%" I32_SPEC "Xh, fixup->offset=%" I32_SPEC "Xh, fixup->sym->offset=%" I32_SPEC "Xh\n",
curr->sym.name, fixup->locofs, fixup->sym->name, seg->e.seginfo->start_offset, fixup->offset, offset ));
break;
default:
/* v2.01: don't use group if fixup explicitely refers the segment! */
//if ( seg->e.seginfo->group ) {
if ( seg->e.seginfo->group && fixup->frame_type != FRAME_SEG ) {
value = (seg->e.seginfo->group->offset & 0xF) + seg->e.seginfo->start_offset + fixup->offset + offset;
#if PE_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_PE ) {
#if AMD64_SUPPORT
if ( curr->e.seginfo->Ofssize == USE64 )
value64 = value + cp->imagebase64;
#endif
value += cp->imagebase;
}
#endif
} else
value = (seg->e.seginfo->start_offset & 0xF) + fixup->offset + offset;
DebugMsg(("DoFixup(%s): loc=%04" I32_SPEC "X, sym=%s, target->start_offset=%" I32_SPEC "Xh, fixup->offset=%" I32_SPEC "Xh, fixup->sym->offset=%" I32_SPEC "Xh\n",
curr->sym.name, fixup->locofs, fixup->sym->name, seg->e.seginfo->start_offset, fixup->offset, offset ));
break;
}
} else {
/* v2.10: member segment_var is for assembly-time variables only */
//seg = (struct dsym *)fixup->segment_var;
seg = NULL;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X, %s): target segment=0, fixup->offset=%" I32_SPEC "Xh, fixup->sym->offset=%" I32_SPEC "Xh\n",
curr->sym.name, fixup->locofs, fixup->sym ? fixup->sym->name : "", fixup->offset ? offset : 0 ));
value = 0;
}
switch ( fixup->type ) {
case FIX_RELOFF8:
//*codeptr.db += (value - fixup->locofs + 1) & 0xff;
/* changed in v1.95 */
*codeptr.db += (value - (fixup->locofs + curr->e.seginfo->start_offset) - 1) & 0xff;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_RELOFF8, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.db ));
break;
case FIX_RELOFF16:
//*codeptr.dw += (value - fixup->locofs + 2) & 0xffff;
/* changed in v1.95 */
*codeptr.dw += (value - (fixup->locofs + curr->e.seginfo->start_offset) - 2) & 0xffff;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_RELOFF16, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dw ));
break;
case FIX_RELOFF32:
#if AMD64_SUPPORT
/* adjust the location for EIP-related offsets if USE64 */
if ( curr->e.seginfo->Ofssize == USE64 ) {
fixup->locofs += fixup->addbytes - 4;
}
#endif
//*codeptr.dd += (value - fixup->locofs + 4);
/* changed in v1.95 */
*codeptr.dd += (value - (fixup->locofs + curr->e.seginfo->start_offset) - 4);
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_RELOFF32, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dd ));
break;
case FIX_OFF8:
*codeptr.db = value & 0xff;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF8, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.db ));
break;
case FIX_OFF16:
*codeptr.dw = value & 0xffff;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF16, value=%" I32_SPEC "Xh, target=%p *target=%Xh\n", curr->sym.name, fixup->locofs, value, codeptr, *codeptr.dw ));
break;
case FIX_OFF32:
*codeptr.dd = value;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF32, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dd ));
break;
case FIX_OFF32_IMGREL:
*codeptr.dd = value;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF32_IMGREL, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dd ));
break;
case FIX_OFF32_SECREL:
*codeptr.dd = value;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF32_SECREL, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dd ));
break;
#if AMD64_SUPPORT
case FIX_OFF64:
#if PE_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_PE && curr->e.seginfo->Ofssize == USE64 )
*codeptr.dq = value64;
else
#endif
*codeptr.dq = value;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_OFF64, value=%" I32_SPEC "Xh, *target=%" I64_SPEC "Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.dq ));
break;
#endif
case FIX_HIBYTE:
*codeptr.db = (value >> 8) & 0xff;
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_HIBYTE, value=%" I32_SPEC "Xh, *target=%Xh\n", curr->sym.name, fixup->locofs, value, *codeptr.db ));
break;
case FIX_SEG:
/* absolute segments are ok */
if ( fixup->sym &&
fixup->sym->state == SYM_SEG &&
((struct dsym *)fixup->sym)->e.seginfo->segtype == SEGTYPE_ABS ) {
*codeptr.dw = ((struct dsym *)fixup->sym)->e.seginfo->abs_frame;
break;
}
#if MZ_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_MZ ) {
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_SEG frame=%u, ", curr->sym.name, fixup->locofs, fixup->frame_type ));
if ( fixup->sym->state == SYM_GRP ) {
seg = (struct dsym *)fixup->sym;
*codeptr.dw = seg->sym.offset >> 4;
DebugMsg(("GROUP symbol, offset=%" I32_SPEC "Xh codeptr=%p\n", seg->sym.offset, codeptr ));
} else if ( fixup->sym->state == SYM_SEG ) {
/* v2.04: added */
seg = (struct dsym *)fixup->sym;
*codeptr.dw = ( seg->e.seginfo->start_offset + ( seg->e.seginfo->group ? seg->e.seginfo->group->offset : 0 ) ) >> 4;
DebugMsg(("SEGMENT symbol, start_offset=%" I32_SPEC "Xh\n", seg->e.seginfo->start_offset ));
//} else if ( seg->e.seginfo->group ) {
} else if ( fixup->frame_type == FRAME_GRP ) {
/* v2.04: changed */
//*codeptr.dw = (seg->e.seginfo->start_offset + seg->e.seginfo->group->offset) >> 4;
*codeptr.dw = seg->e.seginfo->group->offset >> 4;
DebugMsg(("group.offset=%" I32_SPEC "Xh\n", seg->e.seginfo->group->offset ));
} else {
*codeptr.dw = seg->e.seginfo->start_offset >> 4;
DebugMsg(("segment.offset=%" I32_SPEC "Xh\n", seg->e.seginfo->start_offset ));
}
break;
}
#endif
case FIX_PTR16:
#if 1
/* v2.10: absolute segments are ok */
if ( seg && seg->e.seginfo->segtype == SEGTYPE_ABS ) {
*codeptr.dw = value & 0xffff;
codeptr.dw++;
*codeptr.dw = seg->e.seginfo->abs_frame;
break;
}
#endif
#if MZ_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_MZ ) {
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_PTR16, seg->start=%Xh\n", curr->sym.name, fixup->locofs, seg->e.seginfo->start_offset ));
*codeptr.dw = value & 0xffff;
codeptr.dw++;
//if ( seg->e.seginfo->group ) { /* v2.04: changed */
if ( fixup->frame_type == FRAME_GRP ) {
/* v2.04: changed */
//*codeptr.dw = (seg->e.seginfo->start_offset + seg->e.seginfo->group->offset) >> 4;
*codeptr.dw = seg->e.seginfo->group->offset >> 4;
} else {
/* v2.05: changed */
//*codeptr.dw = seg->e.seginfo->start_offset >> 4;
*codeptr.dw = ( seg->e.seginfo->start_offset + ( seg->e.seginfo->group ? seg->e.seginfo->group->offset : 0 ) ) >> 4;
}
break;
}
#endif
case FIX_PTR32:
#if 1
/* v2.10: absolute segments are ok */
if ( seg && seg->e.seginfo->segtype == SEGTYPE_ABS ) {
*codeptr.dd = value;
codeptr.dd++;
*codeptr.dw = seg->e.seginfo->abs_frame;
break;
}
#endif
#if MZ_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_MZ ) {
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): FIX_PTR32\n", curr->sym.name, fixup->locofs ));
*codeptr.dd = value;
codeptr.dd++;
//if (seg->e.seginfo->group ) { /* v2.04: changed */
if ( fixup->frame_type == FRAME_GRP ) {
/* v2.04: changed */
//*codeptr.dw = (seg->e.seginfo->start_offset + seg->e.seginfo->group->offset) >> 4;
*codeptr.dw = seg->e.seginfo->group->offset >> 4;
} else {
/* v2.05: changed */
//*codeptr.dw = seg->e.seginfo->start_offset >> 4;
*codeptr.dw = ( seg->e.seginfo->start_offset + ( seg->e.seginfo->group ? seg->e.seginfo->group->offset : 0 ) ) >> 4;
}
break;
}
#endif
default:
DebugMsg(("DoFixup(%s, %04" I32_SPEC "X): invalid fixup %u\n", curr->sym.name, fixup->locofs, fixup->type ));
EmitErr( INVALID_FIXUP_TYPE, ModuleInfo.fmtopt->formatname, fixup->type, curr->sym.name, fixup->locofs );
//return( ERROR );
}
}
return( NOT_ERROR );
}
#if PE_SUPPORT
static void pe_create_MZ_header( struct module_info *modinfo )
/************************************************************/
{
const char *p;
struct asym *sym;
DebugMsg(("pe_create_MZ_header enter\n" ));
if ( Parse_Pass == PASS_1 && SymSearch( hdrname "1" ) == NULL )
modinfo->g.pe_flags |= PEF_MZHDR;
if ( modinfo->g.pe_flags & PEF_MZHDR ) {
DebugMsg(("pe_create_MZ_header: generate code\n" ));
AddLineQueueX("%r DOTNAME", T_OPTION );
AddLineQueueX("%s1 %r USE16 %r %s", hdrname, T_SEGMENT, T_WORD, hdrattr );
for( p = mzcode; p < mzcode + sizeof( mzcode ); p += strlen( p ) + 1 )
AddLineQueue( p );
AddLineQueueX("%s1 %r", hdrname, T_ENDS );
RunLineQueue();
if ( ( sym = SymSearch( hdrname "1" ) ) && sym->state == SYM_SEG )
(( struct dsym *)sym)->e.seginfo->segtype = SEGTYPE_HDR;
}
}
/* get/set value of @pe_file_flags variable */
static void set_file_flags( struct asym *sym, struct expr *opnd )
/***************************************************************/
{
struct dsym *pehdr;
struct IMAGE_PE_HEADER32 *pe;
pehdr = ( struct dsym *)SymSearch( hdrname "2" );
if ( !pehdr )
return;
pe = (struct IMAGE_PE_HEADER32 *)pehdr->e.seginfo->CodeBuffer;
if ( opnd ) /* set the value? */
pe->FileHeader.Characteristics = opnd->value;
sym->value = pe->FileHeader.Characteristics;
DebugMsg(("set_file_flags(%s, %X): value=%X\n", sym->name, opnd, sym->value ));
}
void pe_create_PE_header( void )
/******************************/
{
struct asym *sym;
struct dsym *pehdr;
int size;
void *p;
DebugMsg(("pe_create_PE_header enter\n" ));
if ( Parse_Pass == PASS_1 ) {
if ( ModuleInfo.model != MODEL_FLAT ) {
EmitError( MODEL_MUST_BE_FLAT );
}
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 ) {
size = sizeof( struct IMAGE_PE_HEADER64 );
p = (void *)&pe64def;
} else {
#endif
size = sizeof( struct IMAGE_PE_HEADER32 );
p = (void *)&pe32def;
#if AMD64_SUPPORT
}
#endif
pehdr = ( struct dsym *)SymSearch( hdrname "2" );
if ( pehdr == NULL ) {
pehdr = (struct dsym *)CreateIntSegment( hdrname "2", "HDR", 2, ModuleInfo.defOfssize, TRUE );
pehdr->e.seginfo->group = &ModuleInfo.flat_grp->sym;
pehdr->e.seginfo->combine = COMB_ADDOFF; /* PUBLIC */
pehdr->e.seginfo->characteristics = (IMAGE_SCN_MEM_READ >> 24);
pehdr->e.seginfo->readonly = 1;
pehdr->e.seginfo->bytes_written = size; /* ensure that ORG won't set start_loc (assemble.c, SetCurrOffset) */
pehdr->sym.max_offset = size;
} else {
if ( pehdr->sym.max_offset < size )
pehdr->sym.max_offset = size;
pehdr->e.seginfo->internal = TRUE;
pehdr->e.seginfo->start_loc = 0;
}
pehdr->e.seginfo->segtype = SEGTYPE_HDR;
pehdr->e.seginfo->CodeBuffer = LclAlloc( size );
memcpy( pehdr->e.seginfo->CodeBuffer, p, size );
#if 0 //def __UNIX__
time((int_32 *)(pehdr->e.seginfo->CodeBuffer+offsetof( struct IMAGE_PE_HEADER32, FileHeader.TimeDateStamp )));
#else
time((time_t *)(pehdr->e.seginfo->CodeBuffer+offsetof( struct IMAGE_PE_HEADER32, FileHeader.TimeDateStamp )));
#endif
sym = CreateVariable( "@pe_file_flags", ((struct IMAGE_PE_HEADER32 *)p)->FileHeader.Characteristics );
if ( sym ) {
DebugMsg(("pe_create_PE_header: CreateVariable(@pe_file_flags)=%X [value=%X]\n", sym, sym ? sym->value : 0 ));
sym->predefined = TRUE;
sym->sfunc_ptr = (internal_func)&set_file_flags;
}
}
}
#define CHAR_READONLY ( IMAGE_SCN_MEM_READ >> 24 )
static void pe_create_section_table( void )
/*****************************************/
{
int i;
struct dsym *objtab;
struct dsym *curr;
int bCreated = FALSE;
int objs;
DebugMsg(("pe_create_section table enter\n" ));
if ( Parse_Pass == PASS_1 ) {
objtab = ( struct dsym *)SymSearch( hdrname "3" );
if ( !objtab ) {
bCreated = TRUE;
objtab = (struct dsym *)CreateIntSegment( hdrname "3", "HDR", 2, ModuleInfo.defOfssize, TRUE );
objtab->e.seginfo->group = &ModuleInfo.flat_grp->sym;
objtab->e.seginfo->combine = COMB_ADDOFF; /* PUBLIC */
}
objtab->e.seginfo->segtype = SEGTYPE_HDR;
if ( !bCreated )
return;
/* before objects can be counted, the segment types
* SEGTYPE_CDATA ( for readonly segments ) &
* SEGTYPE_RSRC ( for resource segments )
* SEGTYPE_RELOC ( for relocations )
* must be set - also, init lname_idx field
*/
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
curr->e.seginfo->lname_idx = SEGTYPE_ERROR; /* use the highest index possible */
if ( curr->e.seginfo->segtype == SEGTYPE_DATA ) {
if ( curr->e.seginfo->readonly || curr->e.seginfo->characteristics == CHAR_READONLY )
curr->e.seginfo->segtype = SEGTYPE_CDATA;
else if ( curr->e.seginfo->clsym && strcmp( curr->e.seginfo->clsym->name, "CONST" ) == 0 )
curr->e.seginfo->segtype = SEGTYPE_CDATA;
} else if ( curr->e.seginfo->segtype == SEGTYPE_UNDEF ) {
if ( ( memcmp( curr->sym.name, ".rsrc", 5 ) == 0 ) &&
( *(curr->sym.name+5) == NULLC || *(curr->sym.name+5) == '$' ) )
curr->e.seginfo->segtype = SEGTYPE_RSRC;
else if ( strcmp( curr->sym.name, ".reloc" ) == 0 )
curr->e.seginfo->segtype = SEGTYPE_RELOC;
}
}
/* count objects ( without header types ) */
for ( i = 1, objs = 0; i < SIZE_PEFLAT; i++ ) {
DebugMsg(("pe_create_section_table: searching type %u\n", flat_order[i] ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
DebugMsg(("pe_create_section_table: section %s, type=%u, size=%X\n", curr->sym.name, curr->e.seginfo->segtype, curr->sym.max_offset ));
if ( curr->e.seginfo->segtype != flat_order[i] )
continue;
if ( curr->sym.max_offset ) {
DebugMsg(("pe_create_section_table: %s, type=%u is object %u\n", curr->sym.name, curr->e.seginfo->segtype, objs ));
objs++;
break;
}
}
}
if ( objs ) {
DebugMsg(("pe_create_section_table: items in object table: %u\n", objs ));
objtab->sym.max_offset = sizeof(struct IMAGE_SECTION_HEADER) * objs;
/* alloc space for 1 more section (.reloc) */
objtab->e.seginfo->CodeBuffer = LclAlloc( objtab->sym.max_offset + sizeof(struct IMAGE_SECTION_HEADER) );
}
}
}
/*
struct IMAGE_EXPORT_DIRECTORY {
uint_32 Characteristics;
uint_32 TimeDateStamp;
uint_16 MajorVersion;
uint_16 MinorVersion;
uint_32 Name; // RVA name of dll
uint_32 Base; // ordinal base
uint_32 NumberOfFunctions;
uint_32 NumberOfNames;
uint_32 AddressOfFunctions; // RVA of function table (array of RVAs)
uint_32 AddressOfNames; // RVA of function names (array of RVAs)
uint_32 AddressOfNameOrdinals; // RVA (array of shorts)
};
*/
struct expitem {
char *name;
unsigned idx;
};
static int compare_exp( const void *p1, const void *p2 )
/*******************************************************/
{
return( strcmp( ((struct expitem *)p1)->name, ((struct expitem *)p2)->name ) );
}
static void pe_emit_export_data( void )
/*************************************/
{
struct dsym *curr;
int_32 timedate;
int cnt;
int i;
char *name;
char *fname;
struct expitem *pitems;
struct expitem *pexp;
DebugMsg(("pe_emit_export_data enter\n" ));
for( curr = SymTables[TAB_PROC].head, cnt = 0; curr; curr = curr->nextproc ) {
if( curr->e.procinfo->isexport )
cnt++;
}
if ( cnt ) {
name = ModuleInfo.name;
AddLineQueueX( "%r DOTNAME", T_OPTION );
/* create .edata segment */
AddLineQueueX( "%s %r %r %s", edataname, T_SEGMENT, T_DWORD, edataattr );
#if 0 //def __UNIX__
time( &timedate );
#else
time( (time_t *)&timedate );
#endif
/* create export directory: Characteristics, Timedate, MajMin, Name, Base, ... */
AddLineQueueX( "DD 0, 0%xh, 0, %r @%s_name, %u, %u, %u, %r @%s_func, %r @%s_names, %r @%s_nameord",
timedate, T_IMAGEREL, name, 1, cnt, cnt, T_IMAGEREL, name, T_IMAGEREL, name, T_IMAGEREL, name );
/* the name pointer table must be in ascending order!
* so we have to fill an array of exports and sort it.
*/
pitems = (struct expitem *)myalloca( cnt * sizeof( struct expitem ) );
for( curr = SymTables[TAB_PROC].head, pexp = pitems, i = 0; curr; curr = curr->nextproc ) {
if( curr->e.procinfo->isexport ) {
pexp->name = curr->sym.name;
pexp->idx = i++;
pexp++;
}
}
qsort( pitems, cnt, sizeof( struct expitem ), compare_exp );
/* emit export address table.
* would be possible to just use the array of sorted names,
* but we want to emit the EAT being sorted by address.
*/
AddLineQueueX( "@%s_func %r DWORD", name, T_LABEL );
for( curr = SymTables[TAB_PROC].head; curr; curr = curr->nextproc ) {
if( curr->e.procinfo->isexport )
AddLineQueueX( "DD %r %s", T_IMAGEREL, curr->sym.name );
}
/* emit the name pointer table */
AddLineQueueX( "@%s_names %r DWORD", name, T_LABEL );
for ( i = 0; i < cnt; i++ )
AddLineQueueX( "DD %r @%s", T_IMAGEREL, (pitems+i)->name );
/* ordinal table. each ordinal is an index into the export address table */
AddLineQueueX( "@%s_nameord %r WORD", name, T_LABEL );
for( i = 0; i < cnt; i++ ) {
AddLineQueueX( "DW %u", (pitems+i)->idx );
}
/* v2.10: name+ext of dll */
//AddLineQueueX( "@%s_name DB '%s',0", name, name );
for ( fname = CurrFName[OBJ] + strlen( CurrFName[OBJ] ); fname > CurrFName[OBJ]; fname-- )
if ( *fname == '/' || *fname == '\\' || *fname == ':' )
break;
AddLineQueueX( "@%s_name DB '%s',0", name, fname );
for( curr = SymTables[TAB_PROC].head; curr; curr = curr->nextproc ) {
if( curr->e.procinfo->isexport ) {
Mangle( &curr->sym, StringBufferEnd );
AddLineQueueX( "@%s DB '%s',0", curr->sym.name, Options.no_export_decoration ? curr->sym.name : StringBufferEnd );
}
}
/* exit .edata segment */
AddLineQueueX( "%s %r", edataname, T_ENDS );
RunLineQueue();
}
}
/* write import data.
* convention:
* .idata$2: import directory
* .idata$3: final import directory NULL entry
* .idata$4: ILT entry
* .idata$5: IAT entry
* .idata$6: strings
*/
static void pe_emit_import_data( void )
/*************************************/
{
struct dll_desc *p;
int type = 0;
#if AMD64_SUPPORT
int ptrtype = ( ModuleInfo.defOfssize == USE64 ? T_QWORD : T_DWORD );
char *align = ( ModuleInfo.defOfssize == USE64 ? "ALIGN(8)" : "ALIGN(4)" );
#else
int ptrtype = T_DWORD;
char *align = "DWORD";
#endif
DebugMsg(("pe_emit_import_data enter\n" ));
for ( p = ModuleInfo.g.DllQueue; p; p = p->next ) {
if ( p->cnt ) {
struct dsym *curr;
char *pdot;
if ( !type ) {
type = 1;
AddLineQueueX( "@LPPROC %r %r %r", T_TYPEDEF, T_PTR, T_PROC );
AddLineQueueX( "%r DOTNAME", T_OPTION );
}
/* avoid . in IDs */
if ( (pdot = strchr( p->name, '.')) != NULL )
*pdot = '_';
/* import directory entry */
AddLineQueueX( "%s" IMPDIRSUF " %r %r %s", idataname, T_SEGMENT, T_DWORD, idataattr );
AddLineQueueX( "DD %r @%s_ilt, 0, 0, %r @%s_name, %r @%s_iat", T_IMAGEREL, p->name, T_IMAGEREL, p->name, T_IMAGEREL, p->name );
AddLineQueueX( "%s" IMPDIRSUF " %r", idataname, T_ENDS );
/* emit ILT */
AddLineQueueX( "%s" IMPILTSUF " %r %s %s", idataname, T_SEGMENT, align, idataattr );
AddLineQueueX( "@%s_ilt label %r", p->name, ptrtype );
for ( curr = SymTables[TAB_EXT].head; curr != NULL ; curr = curr->next ) {
if ( curr->sym.iat_used && curr->sym.dll == p ) {
AddLineQueueX( "@LPPROC %r @%s_name", T_IMAGEREL, curr->sym.name );
}
}
/* ILT termination entry */
AddLineQueueX( "@LPPROC 0" );
AddLineQueueX( "%s" IMPILTSUF " %r", idataname, T_ENDS );
/* emit IAT */
AddLineQueueX( "%s" IMPIATSUF " %r %s %s", idataname, T_SEGMENT, align, idataattr );
AddLineQueueX( "@%s_iat label %r", p->name, ptrtype );
for ( curr = SymTables[TAB_EXT].head; curr != NULL ; curr = curr->next ) {
if ( curr->sym.iat_used && curr->sym.dll == p ) {
Mangle( &curr->sym, StringBufferEnd );
AddLineQueueX( "%s%s @LPPROC %r @%s_name", ModuleInfo.g.imp_prefix, StringBufferEnd, T_IMAGEREL, curr->sym.name );
}
}
/* IAT termination entry */
AddLineQueueX( "@LPPROC 0" );
AddLineQueueX( "%s" IMPIATSUF " %r", idataname, T_ENDS );
/* emit name table */
AddLineQueueX( "%s" IMPSTRSUF " %r %r %s", idataname, T_SEGMENT, T_WORD, idataattr );
for ( curr = SymTables[TAB_EXT].head; curr != NULL ; curr = curr->next ) {
if ( curr->sym.iat_used && curr->sym.dll == p ) {
AddLineQueueX( "@%s_name dw 0", curr->sym.name );
AddLineQueueX( "db '%s',0", curr->sym.name );
AddLineQueue( "even" );
}
}
/* dll name table entry */
if ( pdot ) {
*pdot = NULLC;
AddLineQueueX( "@%s_%s_name db '%s.%s',0", p->name, pdot+1, p->name, pdot+1 );
*pdot = '.'; /* restore '.' in dll name */
} else
AddLineQueueX( "@%s_name db '%s',0", p->name, p->name );
AddLineQueue( "even" );
AddLineQueueX( "%s" IMPSTRSUF " %r", idataname, T_ENDS );
}
}
if ( is_linequeue_populated() ) {
/* import directory NULL entry */
AddLineQueueX( "%s" IMPNDIRSUF " %r %r %s", idataname, T_SEGMENT, T_DWORD, idataattr );
AddLineQueueX( "DD 0, 0, 0, 0, 0" );
AddLineQueueX( "%s" IMPNDIRSUF " %r", idataname, T_ENDS );
RunLineQueue();
}
}
static int get_bit( int value )
/*****************************/
{
int rc = -1;
while( value ) {
value = (value >> 1);
rc++;
}
return( rc );
}
static uint_32 pe_get_characteristics( struct dsym *seg )
/*******************************************************/
{
uint_32 result = 0;
//if ( seg->e.seginfo->alignment != MAX_SEGALIGNMENT ) /* ABS not possible */
// result |= (uint_32)(seg->e.seginfo->alignment + 1) << 20;
if ( seg->e.seginfo->segtype == SEGTYPE_CODE ) {
result |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
} else if ( seg->e.seginfo->segtype == SEGTYPE_BSS ) {
result |= IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
/* ish.SizeOfRawData = 0; */
//ish.PointerToRawData = 0;
} else if ( seg->e.seginfo->combine == COMB_STACK && seg->e.seginfo->bytes_written == 0 ) {
result |= IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
//ish.SizeOfRawData = 0;
//ish.PointerToRawData = 0;
} else if ( seg->e.seginfo->readonly ) {
result |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
} else if ( seg->e.seginfo->clsym && strcmp( seg->e.seginfo->clsym->name, "CONST" ) == 0 ) {
result |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
} else
result |= IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
/* manual characteristics set? */
if ( seg->e.seginfo->characteristics ) {
result &= 0x1FFFFFF; /* clear the IMAGE_SCN_MEM flags */
result |= (uint_32)(seg->e.seginfo->characteristics & 0xFE) << 24;
}
return( result );
}
/* set base relocations */
static void pe_set_base_relocs( struct dsym *reloc )
/**************************************************/
{
int cnt1 = 0;
int cnt2 = 0;
int ftype;
uint_32 currpage = -1;
uint_32 currloc;
struct dsym *curr;
struct fixup *fixup;
struct IMAGE_BASE_RELOCATION *baserel;
uint_16 *prel;
for ( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == SEGTYPE_HDR )
continue;
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
switch ( fixup->type ) {
case FIX_OFF16:
case FIX_OFF32:
#if AMD64_SUPPORT
case FIX_OFF64:
#endif
currloc = curr->e.seginfo->start_offset + ( fixup->locofs & 0xFFFFF000 );
if ( currloc != currpage ) {
currpage = currloc;
cnt2++;
if ( cnt1 & 1 )
cnt1++;
}
cnt1++;
break;
//case FIX_RELOFF08: /* needs no base reloc */
//case FIX_RELOFF16: /* needs no base reloc */
//case FIX_RELOFF32: /* needs no base reloc */
//case FIX_OFF08: /* needs no base reloc */
//case FIX_OFF32_IMGREL: /* needs no base reloc */
//case FIX_OFF32_SECREL: /* needs no base reloc */
//case FIX_SEG: /* segmented fixups have caused an error already */
//case FIX_PTR16: /* segmented fixups have caused an error already */
//case FIX_PTR32: /* segmented fixups have caused an error already */
//case FIX_HIBYTE: /* is an error */
default:
break;
}
}
}
reloc->sym.max_offset = cnt2 * sizeof( struct IMAGE_BASE_RELOCATION ) + cnt1 * sizeof( uint_16 );
reloc->e.seginfo->CodeBuffer = LclAlloc( reloc->sym.max_offset );
baserel = (struct IMAGE_BASE_RELOCATION *)reloc->e.seginfo->CodeBuffer;
prel = (uint_16 *)((uint_8 *)baserel + sizeof ( struct IMAGE_BASE_RELOCATION ));
baserel->VirtualAddress = -1;
for ( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == SEGTYPE_HDR )
continue;
for ( fixup = curr->e.seginfo->FixupList.head; fixup; fixup = fixup->nextrlc ) {
switch ( fixup->type ) {
case FIX_OFF16: ftype = IMAGE_REL_BASED_LOW; break;
case FIX_OFF32: ftype = IMAGE_REL_BASED_HIGHLOW; break;
#if AMD64_SUPPORT
case FIX_OFF64: ftype = IMAGE_REL_BASED_DIR64; break;
#endif
default: ftype = 0;
}
if ( ftype ) {
currloc = curr->e.seginfo->start_offset + ( fixup->locofs & 0xFFFFF000 );
if ( currloc != baserel->VirtualAddress ) {
if ( baserel->VirtualAddress != -1 ) {
/* address of relocation header must be DWORD aligned */
if ( baserel->SizeOfBlock & 2 ) {
*prel++ = 0;
baserel->SizeOfBlock += sizeof( uint_16 );
}
baserel = (struct IMAGE_BASE_RELOCATION *)prel;
prel += 4; /* 4*2 = sizeof( struct IMAGE_BASE_RELOCATION ) */
}
baserel->VirtualAddress = currloc;
baserel->SizeOfBlock = sizeof( struct IMAGE_BASE_RELOCATION );
}
*prel++ = ( fixup->locofs & 0xfff ) | ( ftype << 12 );
baserel->SizeOfBlock += sizeof( uint_16 );
}
}
}
}
#if AMD64_SUPPORT
#define GHF( x ) ( ( ModuleInfo.defOfssize == USE64 ) ? ph64->x : ph32->x )
#else
#define GHF( x ) ph32->x
#endif
/*
* set values in PE header
* including data directories:
* special section names:
* .edata - IMAGE_DIRECTORY_ENTRY_EXPORT
* .idata - IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT
* .rsrc - IMAGE_DIRECTORY_ENTRY_RESOURCE
* .pdata - IMAGE_DIRECTORY_ENTRY_EXCEPTION (64-bit only)
* .reloc - IMAGE_DIRECTORY_ENTRY_BASERELOC
* .tls - IMAGE_DIRECTORY_ENTRY_TLS
*/
static void pe_set_values( struct calc_param *cp )
/************************************************/
{
int i;
int falign;
int malign;
uint_16 ff;
uint_32 codebase = 0;
uint_32 database = 0;
uint_32 codesize = 0;
uint_32 datasize = 0;
uint_32 sizehdr = 0;
uint_32 sizeimg = 0;
struct dsym *curr;
struct dsym *mzhdr;
struct dsym *pehdr;
struct dsym *objtab;
struct dsym *reloc = NULL;
struct IMAGE_PE_HEADER32 *ph32;
#if AMD64_SUPPORT
struct IMAGE_PE_HEADER64 *ph64;
#endif
struct IMAGE_FILE_HEADER *fh;
struct IMAGE_SECTION_HEADER *section;
struct IMAGE_DATA_DIRECTORY *datadir;
char *secname;
char buffer[MAX_ID_LEN+1];
mzhdr = ( struct dsym *)SymSearch( hdrname "1" );
pehdr = ( struct dsym *)SymSearch( hdrname "2" );
objtab = ( struct dsym *)SymSearch( hdrname "3" );
/* make sure all header objects are in FLAT group */
mzhdr->e.seginfo->group = &ModuleInfo.flat_grp->sym;
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 ) {
ph64 = ( struct IMAGE_PE_HEADER64 *)pehdr->e.seginfo->CodeBuffer;
ff = ph64->FileHeader.Characteristics;
} else {
#endif
ph32 = ( struct IMAGE_PE_HEADER32 *)pehdr->e.seginfo->CodeBuffer;
ff = ph32->FileHeader.Characteristics;
#if AMD64_SUPPORT
}
#endif
if ( !( ff & IMAGE_FILE_RELOCS_STRIPPED ) ) {
DebugMsg(("pe_set_values: .reloc section required\n" ));
reloc = (struct dsym *)CreateIntSegment( ".reloc", "RELOC", 2, ModuleInfo.defOfssize, TRUE );
if ( reloc ) {
reloc->e.seginfo->group = &ModuleInfo.flat_grp->sym;
reloc->e.seginfo->combine = COMB_ADDOFF; /* PUBLIC */
reloc->e.seginfo->segtype = SEGTYPE_RELOC;
reloc->e.seginfo->characteristics = ((IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ) >> 24 );
/* make sure the section isn't empty ( true size will be calculated later ) */
reloc->sym.max_offset = sizeof( struct IMAGE_BASE_RELOCATION );
reloc->e.seginfo->bytes_written = reloc->sym.max_offset;
/* clear the additionally allocated entry in object table */
memset( objtab->e.seginfo->CodeBuffer + objtab->sym.max_offset, 0, sizeof( struct IMAGE_SECTION_HEADER ) );
objtab->sym.max_offset += sizeof( struct IMAGE_SECTION_HEADER );
}
}
/* sort: header, executable, readable, read-write segments, resources, relocs */
for ( i = 0; i < SIZE_PEFLAT; i++ ) {
DebugMsg(("pe_set_values: searching segment types %Xh\n", flat_order[i] ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == flat_order[i] ) {
curr->e.seginfo->lname_idx = i;
}
}
}
SortSegments( 2 );
falign = get_bit( GHF( OptionalHeader.FileAlignment ) );
malign = GHF( OptionalHeader.SectionAlignment );
/* assign RVAs to sections */
for ( curr = SymTables[TAB_SEG].head, i = -1; curr; curr = curr->next ) {
if ( curr->e.seginfo->lname_idx == SEGTYPE_ERROR || curr->e.seginfo->lname_idx != i ) {
i = curr->e.seginfo->lname_idx;
cp->alignment = falign;
cp->rva = (cp->rva + (malign - 1)) & (~(malign-1));
} else {
uint_32 align = 1 << curr->e.seginfo->alignment;
cp->alignment = 0;
cp->rva = (cp->rva + (align - 1)) & (~(align-1));
}
CalcOffset( curr, cp );
DebugMsg(("pe_set_values: section %s, start ofs=%" I32_SPEC "Xh, size=%" I32_SPEC "Xh, file ofs=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->start_offset, curr->sym.max_offset - curr->e.seginfo->start_loc, curr->e.seginfo->fileoffset ));
}
if ( reloc ) {
pe_set_base_relocs( reloc );
cp->rva = reloc->e.seginfo->start_offset + reloc->sym.max_offset;
}
sizeimg = cp->rva;
/* set e_lfanew of dosstub to start of PE header */
if ( mzhdr->sym.max_offset >= 0x40 )
((struct IMAGE_DOS_HEADER *)mzhdr->e.seginfo->CodeBuffer)->e_lfanew = pehdr->e.seginfo->fileoffset;
/* set number of sections in PE file header (doesn't matter if it's 32- or 64-bit) */
fh = &((struct IMAGE_PE_HEADER32 *)pehdr->e.seginfo->CodeBuffer)->FileHeader;
fh->NumberOfSections = objtab->sym.max_offset / sizeof( struct IMAGE_SECTION_HEADER );
#if RAWSIZE_ROUND
cp->rawpagesize = ( ModuleInfo.defOfssize == USE64 ? ph64->OptionalHeader.FileAlignment : ph32->OptionalHeader.FileAlignment );
#endif
/* fill object table values */
section = (struct IMAGE_SECTION_HEADER *)objtab->e.seginfo->CodeBuffer;
for( curr = SymTables[TAB_SEG].head, i = -1; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == SEGTYPE_HDR )
continue;
if ( curr->sym.max_offset == 0 ) /* ignore empty sections */
continue;
if ( curr->e.seginfo->lname_idx != i ) {
i = curr->e.seginfo->lname_idx;
secname = ( curr->e.seginfo->aliasname ? curr->e.seginfo->aliasname : ConvertSectionName( &curr->sym, NULL, buffer ) );
strncpy( section->Name, secname, sizeof ( section->Name ) );
if ( curr->e.seginfo->segtype != SEGTYPE_BSS )
section->PointerToRawData = curr->e.seginfo->fileoffset;
section->VirtualAddress = curr->e.seginfo->start_offset;
/* file offset of first section in object table defines SizeOfHeader */
if ( sizehdr == 0 )
sizehdr = curr->e.seginfo->fileoffset;
}
section->Characteristics |= pe_get_characteristics( curr );
if ( curr->e.seginfo->segtype != SEGTYPE_BSS ) {
section->SizeOfRawData += curr->sym.max_offset;
}
/* v2.10: this calculation is not correct */
//section->Misc.VirtualSize += curr->sym.max_offset;
section->Misc.VirtualSize = curr->sym.max_offset + ( curr->e.seginfo->start_offset - section->VirtualAddress );
if ( curr->next == NULL || curr->next->e.seginfo->lname_idx != i ) {
#if RAWSIZE_ROUND /* AntiVir TR/Crypt.XPACK Gen */
section->SizeOfRawData += cp->rawpagesize - 1;
section->SizeOfRawData &= ~(cp->rawpagesize - 1);
#endif
if ( section->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
if ( codebase == 0 )
codebase = section->VirtualAddress;
codesize += section->SizeOfRawData;
}
if ( section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA ) {
if ( database == 0 )
database = section->VirtualAddress;
datasize += section->SizeOfRawData;
}
}
if ( curr->next && curr->next->e.seginfo->lname_idx != i ) {
DebugMsg(("pe_set_values: object %.8s, VA=%" I32_SPEC "X size=%" I32_SPEC "X phys ofs/size=%" I32_SPEC "Xh/%" I32_SPEC "Xh\n",
section->Name, section->VirtualAddress, section->Misc.VirtualSize, section->PointerToRawData, section->SizeOfRawData ));
section++;
}
}
if ( ModuleInfo.g.start_label ) {
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 )
ph64->OptionalHeader.AddressOfEntryPoint = ((struct dsym *)ModuleInfo.g.start_label->segment)->e.seginfo->start_offset + ModuleInfo.g.start_label->offset;
else
#endif
ph32->OptionalHeader.AddressOfEntryPoint = ((struct dsym *)ModuleInfo.g.start_label->segment)->e.seginfo->start_offset + ModuleInfo.g.start_label->offset;
} else {
DebugMsg(("pe_set_values: warning: not start label found\n" ));
EmitWarn( 2, NO_START_LABEL );
}
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 ) {
#if IMGSIZE_ROUND
/* round up the SizeOfImage field to page boundary */
sizeimg = ( sizeimg + ph64->OptionalHeader.SectionAlignment - 1 ) & ~(ph64->OptionalHeader.SectionAlignment - 1);
#endif
ph64->OptionalHeader.SizeOfCode = codesize;
ph64->OptionalHeader.BaseOfCode = codebase;
ph64->OptionalHeader.SizeOfImage = sizeimg;
ph64->OptionalHeader.SizeOfHeaders = sizehdr;
datadir = &ph64->OptionalHeader.DataDirectory[0];
} else {
#endif
#if IMGSIZE_ROUND
/* round up the SizeOfImage field to page boundary */
sizeimg = ( sizeimg + ph32->OptionalHeader.SectionAlignment - 1 ) & ~(ph32->OptionalHeader.SectionAlignment - 1);
#endif
ph32->OptionalHeader.SizeOfCode = codesize;
ph32->OptionalHeader.SizeOfInitializedData = datasize;
ph32->OptionalHeader.BaseOfCode = codebase;
ph32->OptionalHeader.BaseOfData = database;
ph32->OptionalHeader.SizeOfImage = sizeimg;
ph32->OptionalHeader.SizeOfHeaders = sizehdr;
datadir = &ph32->OptionalHeader.DataDirectory[0];
#if AMD64_SUPPORT
}
#endif
/* set export directory data dir value */
if ( (curr = (struct dsym *)SymSearch( edataname )) != NULL ) {
datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = curr->sym.max_offset;
}
/* set import directory and IAT data dir value */
if ( (curr = (struct dsym *)SymSearch( ".idata$" IMPDIRSUF )) != NULL ) {
struct dsym *idata_null;
struct dsym *idata_iat;
uint_32 size;
idata_null = (struct dsym *)SymSearch( ".idata$" IMPNDIRSUF ); /* final NULL import directory entry */
idata_iat = (struct dsym *)SymSearch( ".idata$" IMPIATSUF ); /* IAT entries */
size = idata_null->e.seginfo->start_offset + idata_null->sym.max_offset - curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = size;
datadir[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = idata_iat->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_IAT].Size = idata_iat->sym.max_offset;
}
/* set resource directory data dir value */
if ( (curr = (struct dsym *)SymSearch(".rsrc")) != NULL ) {
datadir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = curr->sym.max_offset;
}
/* set relocation data dir value */
if ( (curr = (struct dsym *)SymSearch(".reloc")) != NULL ) {
datadir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = curr->sym.max_offset;
}
/* fixme: TLS entry is not written because there exists a segment .tls, but
* because a _tls_used symbol is found ( type: IMAGE_THREAD_DIRECTORY )
*/
if ( (curr = (struct dsym *)SymSearch(".tls")) != NULL ) {
datadir[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_TLS].Size = curr->sym.max_offset;
}
#if AMD64_SUPPORT
if ( ModuleInfo.defOfssize == USE64 ) {
if ( (curr = (struct dsym *)SymSearch( ".pdata" )) != NULL ) {
datadir[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = curr->sym.max_offset;
}
cp->imagebase64 = GHF( OptionalHeader.ImageBase );
} else
#endif
cp->imagebase = GHF( OptionalHeader.ImageBase );
/* remove .hdr$1 from FLAT group again */
//mzhdr->e.seginfo->group = NULL;
}
/* v2.11: this function is called when the END directive has been found.
* Previously the code was run inside EndDirective() directly.
*/
static ret_code pe_enddirhook( struct module_info *modinfo )
/**********************************************************/
{
pe_create_MZ_header( modinfo );
//pe_create_PE_header(); /* the PE header is created when the .MODEL directive is found */
pe_emit_export_data();
if ( modinfo->g.DllQueue )
pe_emit_import_data();
pe_create_section_table();
return( NOT_ERROR );
}
#endif
/* write section contents
* this is done after the last step only!
*/
static ret_code bin_write_module( struct module_info *modinfo )
/*************************************************************/
{
struct dsym *curr;
uint_32 size;
uint_32 sizetotal;
//const enum seg_type *segtype;
int i;
int first;
uint_32 sizeheap;
#if MZ_SUPPORT
struct IMAGE_DOS_HEADER *pMZ;
uint_16 reloccnt;
uint_32 sizemem;
struct dsym *stack = NULL;
uint_8 *hdrbuf;
#endif
struct calc_param cp = { TRUE, 0 };
DebugMsg(("bin_write_module: enter\n" ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
/* reset the offset fields of segments */
/* it was used to store the size in there */
curr->e.seginfo->start_offset = 0;
/* set STACK segment type */
if ( curr->e.seginfo->combine == COMB_STACK )
curr->e.seginfo->segtype = SEGTYPE_STACK;
}
/* calculate size of header */
switch( modinfo->sub_format ) {
#if MZ_SUPPORT
case SFORMAT_MZ:
reloccnt = GetSegRelocs( NULL );
cp.sizehdr = (reloccnt * 4 + modinfo->mz_data.ofs_fixups + (modinfo->mz_data.alignment - 1)) & ~(modinfo->mz_data.alignment-1);
DebugMsg(("bin_write_module: MZ format, fixups=%u, sizehdr=%" I32_SPEC "X\n", reloccnt, cp.sizehdr ));
break;
#endif
default:
cp.sizehdr = 0;
}
cp.fileoffset = cp.sizehdr;
if ( cp.sizehdr ) {
hdrbuf = LclAlloc( cp.sizehdr );
memset( hdrbuf, 0, cp.sizehdr );
}
cp.entryoffset = -1;
/* set starting offsets for all sections */
#if PE_SUPPORT
cp.rva = 0;
if ( modinfo->sub_format == SFORMAT_PE ) {
if ( ModuleInfo.model == MODEL_NONE ) {
return( EmitErr( MODEL_IS_NOT_DECLARED ) );
}
pe_set_values( &cp );
} else
#endif
if ( modinfo->segorder == SEGORDER_DOSSEG ) {
DebugMsg(("bin_write_module: .DOSSEG active\n" ));
/* for .DOSSEG, regroup segments (CODE, UNDEF, DATA, BSS) */
for ( i = 0 ; i < SIZE_DOSSEG; i++ ) {
DebugMsg(("bin_write_module: searching segment types %Xh\n", dosseg_order[i] ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype != dosseg_order[i] )
continue;
CalcOffset( curr, &cp );
DebugMsg(("bin_write_module: section %s, start ofs=%" I32_SPEC "Xh, size=%" I32_SPEC "Xh, file ofs=%" I32_SPEC "Xh\n",
curr->sym.name, curr->e.seginfo->start_offset, curr->sym.max_offset - curr->e.seginfo->start_loc, curr->e.seginfo->fileoffset ));
}
}
SortSegments( 0 );
} else { /* segment order .SEQ (default) and .ALPHA */
if ( modinfo->segorder == SEGORDER_ALPHA ) {
DebugMsg(("bin_write_module: .ALPHA active\n" ));
SortSegments( 1 );
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
/* ignore absolute segments */
CalcOffset( curr, &cp );
DebugMsg(("bin_write_module(%s): start ofs=%" I32_SPEC "Xh, size=%" I32_SPEC "Xh, file ofs=%" I32_SPEC "Xh, grp=%s\n",
curr->sym.name, curr->e.seginfo->start_offset, curr->sym.max_offset - curr->e.seginfo->start_loc, curr->e.seginfo->fileoffset, (curr->e.seginfo->group ? curr->e.seginfo->group->name : "NULL" )));
}
}
DebugMsg(("bin_write_module: all CalcOffset() done\n" ));
/* handle relocs */
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
/* v2.04: scan ALL fixups! */
//if ( DoFixup( curr ) == ERROR )
// return( ERROR );
DoFixup( curr, &cp );
#if MZ_SUPPORT
if ( stack == NULL &&
curr->e.seginfo->combine == COMB_STACK )
stack = curr;
#endif
}
/* v2.04: return if any errors occured during fixup handling */
if ( modinfo->g.error_count )
return( ERROR );
/* for plain binaries make sure the start label is at
* the beginning of the first segment */
if ( modinfo->sub_format == SFORMAT_NONE ) {
if ( modinfo->g.start_label ) {
if ( cp.entryoffset == -1 || cp.entryseg != modinfo->g.start_label->segment ) {
return( EmitError( START_LABEL_INVALID ) );
}
}
}
sizetotal = GetImageSize( FALSE );
/* for MZ|PE format, initialize the header */
switch ( modinfo->sub_format ) {
#if MZ_SUPPORT
case SFORMAT_MZ:
/* set fields in MZ header */
pMZ = (struct IMAGE_DOS_HEADER *)hdrbuf;
pMZ->e_magic = 'M' + ('Z' << 8);
pMZ->e_cblp = sizetotal % 512; /* bytes last page */
pMZ->e_cp = sizetotal / 512 + (sizetotal % 512 ? 1 : 0); /* pages */
pMZ->e_crlc = reloccnt;
pMZ->e_cparhdr = cp.sizehdr >> 4; /* size header in paras */
sizeheap = GetImageSize( TRUE ) - sizetotal;
DebugMsg(( "bin_write_module: MZ, sizetotal=%" I32_SPEC "Xh sizeheap=%" I32_SPEC "Xh\n", sizetotal, sizeheap ));
pMZ->e_minalloc = sizeheap / 16 + ((sizeheap % 16) ? 1 : 0); /* heap min */
if ( pMZ->e_minalloc < modinfo->mz_data.heapmin )
pMZ->e_minalloc = modinfo->mz_data.heapmin;
pMZ->e_maxalloc = modinfo->mz_data.heapmax; /* heap max */
if ( pMZ->e_maxalloc < pMZ->e_minalloc )
pMZ->e_maxalloc = pMZ->e_minalloc;
/* set stack if there's one defined */
if ( stack ) {
uint_32 addr = stack->e.seginfo->start_offset;
if ( stack->e.seginfo->group )
addr += stack->e.seginfo->group->offset;
DebugMsg(("bin_write_module: MZ, stack=%" I32_SPEC "Xh ofs=%" I32_SPEC "Xh\n", addr, stack->sym.max_offset ));
pMZ->e_ss = (addr >> 4) + ((addr & 0xF) ? 1 : 0); /* SS */
/* v2.11: changed sym.offset to sym.max_offset */
pMZ->e_sp = stack->sym.max_offset; /* SP */
} else {
EmitWarn( 2, NO_STACK );
}
pMZ->e_csum = 0; /* checksum */
/* set entry CS:IP if defined */
if ( modinfo->g.start_label ) {
uint_32 addr;
curr = (struct dsym *)modinfo->g.start_label->segment;
DebugMsg(("bin_write_module, start_label: offs=%" I32_SPEC "Xh, seg.offs=%" I32_SPEC "Xh, group.offs=%" I32_SPEC "Xh\n",
modinfo->g.start_label->offset, curr->e.seginfo->start_offset, curr->e.seginfo->group ? curr->e.seginfo->group->offset : 0 ));
if ( curr->e.seginfo->group ) {
addr = curr->e.seginfo->group->offset;
pMZ->e_ip = (addr & 0xF ) + curr->e.seginfo->start_offset + modinfo->g.start_label->offset; /* IP */
pMZ->e_cs = addr >> 4; /* CS */
} else {
addr = curr->e.seginfo->start_offset;
pMZ->e_ip = (addr & 0xF ) + modinfo->g.start_label->offset; /* IP */
pMZ->e_cs = addr >> 4; /* CS */
}
} else {
DebugMsg(("bin_write_module, ModuleInfo->start_label=%p\n", modinfo->g.start_label ));
EmitWarn( 2, NO_START_LABEL );
}
pMZ->e_lfarlc = modinfo->mz_data.ofs_fixups;
DebugMsg(("bin_write_module: MZ, mzdata ofs_fixups=%Xh, alignment=%Xh\n", modinfo->mz_data.ofs_fixups, modinfo->mz_data.alignment ));
GetSegRelocs( (uint_16 *)( hdrbuf + pMZ->e_lfarlc ) );
break;
#endif
}
#if SECTORMAP
if( CurrFile[LST] ) {
/* go to EOF */
fseek( CurrFile[LST], 0, SEEK_END );
LstNL();
LstNL();
LstPrintf( szCaption );
LstNL();
LstNL();
LstPrintf( szCaption2 );
LstNL();
LstPrintf( szSep );
LstNL();
}
#endif
if ( cp.sizehdr ) {
if ( fwrite( hdrbuf, 1, cp.sizehdr, CurrFile[OBJ] ) != cp.sizehdr )
WriteError();
#if SECTORMAP
LstPrintf( szSegLine, szHeader, 0, 0, cp.sizehdr, 0 );
LstNL();
#endif
LclFree( hdrbuf );
}
#ifdef DEBUG_OUT
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
DebugMsg(("bin_write_module(%s): type=%u written=%" I32_SPEC "X max=%" I32_SPEC "X start=%" I32_SPEC "X fileofs=%" I32_SPEC "X\n",
curr->sym.name, curr->e.seginfo->segtype,
curr->e.seginfo->bytes_written,
curr->sym.max_offset,
curr->e.seginfo->start_loc,
curr->e.seginfo->fileoffset ));
}
#endif
/* write sections */
for( curr = SymTables[TAB_SEG].head, first = TRUE; curr; curr = curr->next ) {
if ( curr->e.seginfo->segtype == SEGTYPE_ABS ) {
DebugMsg(("bin_write_module(%s): ABS segment not written\n", curr->sym.name ));
continue;
}
#if PE_SUPPORT
if ( ModuleInfo.sub_format == SFORMAT_PE &&
( curr->e.seginfo->segtype == SEGTYPE_BSS || curr->e.seginfo->info ) )
size = 0;
else
#endif
/* v2.05: changed */
size = curr->sym.max_offset - curr->e.seginfo->start_loc;
//size = sizemem;
sizemem = first ? size : curr->sym.max_offset;
/* if no bytes have been written to the segment, check if there's
* any further segments with bytes set. If no, skip write! */
if ( curr->e.seginfo->bytes_written == 0 ) {
struct dsym *dir;
for ( dir = curr->next; dir; dir = dir->next )
if ( dir->e.seginfo->bytes_written )
break;
if ( !dir ) {
DebugMsg(("bin_write_module(%s): segment not written, size=% " I32_SPEC "Xh sizemem=%" I32_SPEC "X\n",
curr->sym.name, size, sizemem ));
size = 0;
}
}
#if SECTORMAP
/* v2.05: changed
* print name, fileoffset, objoffset, filesize, memsize
*/
//LstPrintf( szSegLine, curr->sym.name, curr->e.seginfo->fileoffset, curr->e.seginfo->start_offset + curr->e.seginfo->start_loc, size, sizemem );
LstPrintf( szSegLine, curr->sym.name, curr->e.seginfo->fileoffset, first ? curr->e.seginfo->start_offset + curr->e.seginfo->start_loc : curr->e.seginfo->start_offset, size, sizemem );
LstNL();
#endif
if ( size != 0 && curr->e.seginfo->CodeBuffer ) {
DebugMsg(("bin_write_module(%s): write %" I32_SPEC "Xh bytes at offset %" I32_SPEC "Xh, initialized bytes=%" I32_SPEC "u, buffer=%p\n",
curr->sym.name, size, curr->e.seginfo->fileoffset, curr->e.seginfo->bytes_written, curr->e.seginfo->CodeBuffer ));
fseek( CurrFile[OBJ], curr->e.seginfo->fileoffset, SEEK_SET );
#ifdef __I86__
if ( hfwrite( curr->e.seginfo->CodeBuffer, 1, size, CurrFile[OBJ] ) != size )
WriteError();
#else
if ( fwrite( curr->e.seginfo->CodeBuffer, 1, size, CurrFile[OBJ] ) != size )
WriteError();
#endif
}
#ifdef DEBUG_OUT
else DebugMsg(("bin_write_module(%s): nothing written\n", curr->sym.name ));
#endif
first = FALSE;
}
#if PE_SUPPORT && RAWSIZE_ROUND
if ( modinfo->sub_format == SFORMAT_PE ) {
size = ftell( CurrFile[OBJ] );
if ( size & ( cp.rawpagesize - 1 ) ) {
char *tmp;
size = cp.rawpagesize - ( size & ( cp.rawpagesize - 1 ) );
tmp = myalloca( size );
memset( tmp, 0, size );
fwrite( tmp, 1, size, CurrFile[OBJ] );
}
}
#endif
#if SECTORMAP
LstPrintf( szSep );
LstNL();
#if MZ_SUPPORT
if ( modinfo->sub_format == SFORMAT_MZ )
sizeheap += sizetotal - cp.sizehdr;
else
#endif
#if PE_SUPPORT
if ( modinfo->sub_format == SFORMAT_PE )
sizeheap = cp.rva;
else
#endif
sizeheap = GetImageSize( TRUE );
LstPrintf( szTotal, " ", sizetotal, sizeheap );
LstNL();
#endif
DebugMsg(("bin_write_module: exit\n"));
return( NOT_ERROR );
}
#endif
static ret_code bin_check_external( struct module_info *modinfo )
/***************************************************************/
{
struct dsym *curr;
for ( curr = SymTables[TAB_EXT].head; curr != NULL ; curr = curr->next )
if( curr->sym.weak == FALSE || curr->sym.used == TRUE ) {
DebugMsg(("CheckExternal: error, %s weak=%u\n", curr->sym.name, curr->sym.weak ));
return( EmitErr( FORMAT_DOESNT_SUPPORT_EXTERNALS, curr->sym.name ) );
}
return( NOT_ERROR );
}
void bin_init( struct module_info *modinfo )
/******************************************/
{
modinfo->g.WriteModule = bin_write_module;
modinfo->g.Pass1Checks = bin_check_external;
switch ( modinfo->sub_format ) {
#if MZ_SUPPORT
case SFORMAT_MZ:
memcpy( &modinfo->mz_data, &mzdata, sizeof( struct MZDATA ) );
break;
#endif
#if PE_SUPPORT
case SFORMAT_PE:
modinfo->g.EndDirHook = pe_enddirhook; /* v2.11 */
break;
#endif
}
return;
}