#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
#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
#define IMGSIZE_ROUND 1
#define IMPDIRSUF "2"
#define IMPNDIRSUF "3"
#define IMPILTSUF "4"
#define IMPIATSUF "5"
#define IMPSTRSUF "6"
#endif
#if MZ_SUPPORT || PE_SUPPORT
#include "pespec.h"
#endif
#include "orgfixup.h"
extern void SortSegments( int );
#if MZ_SUPPORT
static const struct MZDATA mzdata = {0x1E, 0x10, 0, 0xFFFF };
#endif
#if SECTORMAP
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;
uint_8 alignment;
uint_32 fileoffset;
uint_32 sizehdr;
uint_32 entryoffset;
struct asym *entryseg;
uint_32 imagestart;
#if PE_SUPPORT
uint_32 rva;
union {
uint_32 imagebase;
#if AMD64_SUPPORT
uint_64 imagebase64;
#endif
};
#if RAWSIZE_ROUND
uint_32 rawpagesize;
#endif
#endif
};
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,
};
#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 alias('.rdata') 'DATA'" };
static const char mzcode[] = {
"db 'MZ'\0"
"dw 80h, 1, 0, 4\0"
"dw 0, -1, 0, 0B8h\0"
"dw 0, 0, 0, 40h\0"
"org 40h\0"
"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,'$'"
};
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,
0x400000,
0x1000, 0x200,
4,0,0,0,4,0,
0,0,0,0,
IMAGE_SUBSYSTEM_WINDOWS_CUI,0,
0x100000,0x1000,
0x100000,0x1000,
0, IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
}
};
#if AMD64_SUPPORT
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,
0x400000,
0x1000, 0x200,
4,0,0,0,4,0,
0,0,0,0,
IMAGE_SUBSYSTEM_WINDOWS_CUI,0,
0x100000,0x1000,
0x100000,0x1000,
0, IMAGE_NUMBEROF_DIRECTORY_ENTRIES,
}
};
#endif
#endif
#ifdef __I86__
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
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 = ((cp->fileoffset + (align - 1)) & (-align)) - cp->fileoffset;
cp->fileoffset += alignbytes;
if ( grp == NULL ) {
offset = cp->fileoffset - cp->sizehdr;
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 || ModuleInfo.sub_format == SFORMAT_64BIT )
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 ));
}
if ( cp->first == FALSE ) {
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 ( 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;
if ( cp->entryoffset == -1 ) {
cp->entryoffset = offset;
cp->entryseg = (struct asym *)curr;
}
} else {
#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;
if ( grp ) {
grp->sym.total_size = offset;
if ( grp->sym.total_size > 0x10000 && grp->sym.Ofssize == USE16 ) {
EmitWarn( 2, GROUP_EXCEEDS_64K, grp->sym.name );
}
}
cp->first = FALSE;
return;
}
#if MZ_SUPPORT
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:
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 ) {
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;
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
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;
}
}
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 );
}
union genptr {
uint_8 *db;
uint_16 *dw;
uint_32 *dd;
#if AMD64_SUPPORT
uint_64 *dq;
#endif
};
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;
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 || fixup->sym->variable ) ) {
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;
}
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;
if ( tmp = strchr( seg->sym.name, '$' ) ) {
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:
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:
if ( seg && 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 || ModuleInfo.sub_format == SFORMAT_64BIT ) {
#if AMD64_SUPPORT
if ( curr->e.seginfo->Ofssize == USE64 )
value64 = value + cp->imagebase64;
#endif
value += cp->imagebase;
}
#endif
}
else if (ModuleInfo.sub_format == SFORMAT_64BIT && Options.output_format == OFORMAT_BIN && curr != seg)
{
value = offset + cp->imagebase;
value64 = offset + cp->imagebase64;
}
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 {
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 + 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 + 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
if ( curr->e.seginfo->Ofssize == USE64 ) {
fixup->locofs += fixup->addbytes - 4;
}
#endif
*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:
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 ) {
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 ( fixup->frame_type == FRAME_GRP ) {
*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
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 ( fixup->frame_type == FRAME_GRP ) {
*codeptr.dw = seg->e.seginfo->group->offset >> 4;
} else {
*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
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 ( fixup->frame_type == FRAME_GRP ) {
*codeptr.dw = seg->e.seginfo->group->offset >> 4;
} else {
*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( 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;
}
}
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 )
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;
pehdr->e.seginfo->characteristics = (IMAGE_SCN_MEM_READ >> 24);
pehdr->e.seginfo->readonly = 1;
pehdr->e.seginfo->bytes_written = size;
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#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;
}
objtab->e.seginfo->segtype = SEGTYPE_HDR;
if ( !bCreated )
return;
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
curr->e.seginfo->lname_idx = SEGTYPE_ERROR;
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;
}
}
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;
objtab->e.seginfo->CodeBuffer = LclAlloc( objtab->sym.max_offset + sizeof(struct IMAGE_SECTION_HEADER) );
}
}
}
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 );
AddLineQueueX( "%s %r %r %s", edataname, T_SEGMENT, T_DWORD, edataattr );
#if 0#else
time( (time_t *)&timedate );
#endif
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 );
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 );
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 );
}
AddLineQueueX( "@%s_names %r DWORD", name, T_LABEL );
for ( i = 0; i < cnt; i++ )
AddLineQueueX( "DD %r @%s", T_IMAGEREL, (pitems+i)->name );
AddLineQueueX( "@%s_nameord %r WORD", name, T_LABEL );
for( i = 0; i < cnt; i++ ) {
AddLineQueueX( "DW %u", (pitems+i)->idx );
}
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 );
}
}
AddLineQueueX( "%s %r", edataname, T_ENDS );
RunLineQueue();
}
}
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 );
}
if ( pdot = strchr( p->name, '.') )
*pdot = '_';
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 );
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 );
}
}
AddLineQueueX( "@LPPROC 0" );
AddLineQueueX( "%s" IMPILTSUF " %r", idataname, T_ENDS );
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 );
}
}
AddLineQueueX( "@LPPROC 0" );
AddLineQueueX( "%s" IMPIATSUF " %r", idataname, T_ENDS );
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" );
}
}
if ( pdot ) {
*pdot = NULLC;
AddLineQueueX( "@%s_%s_name db '%s.%s',0", p->name, pdot+1, p->name, pdot+1 );
*pdot = '.';
} else
AddLineQueueX( "@%s_name db '%s',0", p->name, p->name );
AddLineQueue( "even" );
AddLineQueueX( "%s" IMPSTRSUF " %r", idataname, T_ENDS );
}
}
if ( is_linequeue_populated() ) {
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->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;
} 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;
} 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;
if ( seg->e.seginfo->characteristics ) {
result &= 0x1FFFFFF;
result |= (uint_32)(seg->e.seginfo->characteristics & 0xFE) << 24;
}
return( result );
}
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;
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 ) {
if ( baserel->SizeOfBlock & 2 ) {
*prel++ = 0;
baserel->SizeOfBlock += sizeof( uint_16 );
}
baserel = (struct IMAGE_BASE_RELOCATION *)prel;
prel += 4;
}
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
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" );
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;
reloc->e.seginfo->segtype = SEGTYPE_RELOC;
reloc->e.seginfo->characteristics = ((IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ) >> 24 );
reloc->sym.max_offset = sizeof( struct IMAGE_BASE_RELOCATION );
reloc->e.seginfo->bytes_written = reloc->sym.max_offset;
memset( objtab->e.seginfo->CodeBuffer + objtab->sym.max_offset, 0, sizeof( struct IMAGE_SECTION_HEADER ) );
objtab->sym.max_offset += sizeof( struct IMAGE_SECTION_HEADER );
}
}
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 );
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;
if ( mzhdr->sym.max_offset >= 0x40 )
((struct IMAGE_DOS_HEADER *)mzhdr->e.seginfo->CodeBuffer)->e_lfanew = pehdr->e.seginfo->fileoffset;
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
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 )
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;
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;
}
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
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
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
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
if ( curr = (struct dsym *)SymSearch( edataname ) ) {
datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = curr->sym.max_offset;
}
if ( curr = (struct dsym *)SymSearch( ".idata$" IMPDIRSUF ) ) {
struct dsym *idata_null;
struct dsym *idata_iat;
uint_32 size;
idata_null = (struct dsym *)SymSearch( ".idata$" IMPNDIRSUF );
idata_iat = (struct dsym *)SymSearch( ".idata$" IMPIATSUF );
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;
}
if ( curr = (struct dsym *)SymSearch(".rsrc") ) {
datadir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = curr->sym.max_offset;
}
if ( curr = (struct dsym *)SymSearch(".reloc") ) {
datadir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = curr->e.seginfo->start_offset;
datadir[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = curr->sym.max_offset;
}
if ( curr = (struct dsym *)SymSearch(".tls") ) {
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" ) ) {
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 );
}
static ret_code pe_enddirhook( struct module_info *modinfo )
{
pe_create_MZ_header( modinfo );
pe_emit_export_data();
if ( modinfo->g.DllQueue )
pe_emit_import_data();
pe_create_section_table();
return( NOT_ERROR );
}
#endif
static ret_code bin_write_module( struct module_info *modinfo )
{
struct dsym *curr;
uint_32 size;
uint_32 sizetotal;
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 };
uint_32 origsize;
uint_32 writesize;
uint_8 *codeptr;
DebugMsg(("bin_write_module: enter\n" ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
curr->e.seginfo->start_offset = 0;
if ( curr->e.seginfo->combine == COMB_STACK )
curr->e.seginfo->segtype = SEGTYPE_STACK;
}
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;
#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 ( 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 {
if ( modinfo->segorder == SEGORDER_ALPHA ) {
DebugMsg(("bin_write_module: .ALPHA active\n" ));
SortSegments( 1 );
}
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
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" ));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
DoFixup( curr, &cp );
#if MZ_SUPPORT
if ( stack == NULL &&
curr->e.seginfo->combine == COMB_STACK )
stack = curr;
#endif
}
if ( modinfo->g.error_count )
return( ERROR );
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 );
switch ( modinfo->sub_format ) {
#if MZ_SUPPORT
case SFORMAT_MZ:
pMZ = (struct IMAGE_DOS_HEADER *)hdrbuf;
pMZ->e_magic = 'M' + ('Z' << 8);
pMZ->e_cblp = sizetotal % 512;
pMZ->e_cp = sizetotal / 512 + (sizetotal % 512 ? 1 : 0);
pMZ->e_crlc = reloccnt;
pMZ->e_cparhdr = cp.sizehdr >> 4;
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);
if ( pMZ->e_minalloc < modinfo->mz_data.heapmin )
pMZ->e_minalloc = modinfo->mz_data.heapmin;
pMZ->e_maxalloc = modinfo->mz_data.heapmax;
if ( pMZ->e_maxalloc < pMZ->e_minalloc )
pMZ->e_maxalloc = pMZ->e_minalloc;
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);
pMZ->e_sp = stack->sym.max_offset;
} else {
EmitWarn( 2, NO_STACK );
}
pMZ->e_csum = 0;
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;
pMZ->e_cs = addr >> 4;
} else {
addr = curr->e.seginfo->start_offset;
pMZ->e_ip = (addr & 0xF ) + modinfo->g.start_label->offset;
pMZ->e_cs = addr >> 4;
}
} 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] ) {
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
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 || ModuleInfo.sub_format == SFORMAT_64BIT ) &&
( curr->e.seginfo->segtype == SEGTYPE_BSS || curr->e.seginfo->info ) )
size = 0;
else
#endif
size = curr->sym.max_offset - curr->e.seginfo->start_loc;
sizemem = first ? size : curr->sym.max_offset;
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
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 (ModuleInfo.flat)
{
origsize = size;
codeptr = curr->e.seginfo->CodeBuffer;
while (codeptr < (curr->e.seginfo->CodeBuffer+size))
{
if (!InOrgRange(codeptr - curr->e.seginfo->CodeBuffer))
{
writesize = fwrite(codeptr, 1, 1, CurrFile[OBJ]);
if (writesize != 1)
WriteError();
}
codeptr++;
}
}
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 || ModuleInfo.sub_format == SFORMAT_64BIT ) {
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 || ModuleInfo.sub_format == SFORMAT_64BIT )
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;
break;
#endif
}
return;
}