mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-22 01:04:39 +00:00
1850 lines
76 KiB
C
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;
|
|
}
|