#include <limits.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "segment.h"
#include "mangle.h"
#include "extern.h"
#include "fixup.h"
#include "omf.h"
#include "omfint.h"
#include "omfspec.h"
#include "fastpass.h"
#include "myassert.h"
#include "tokenize.h"
#include "input.h"
#include "linnum.h"
#define TRUNCATE 1
#define MULTIHDR 1
#define WRITEIMPDEF 0
#define MANGLE_BYTES 8
#define MAX_ID_LEN_OMF 247
#define MAX_LNAME_SIZE 1024
#define MAX_EXT_LENGTH 1020
#define MAX_PUB_LENGTH 1024
#if TRUNCATE
#if defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
#include <unistd.h>
#else
#include <io.h>
#endif
#endif
#if defined(__UNIX__) || defined(__CYGWIN__)
#define _stat stat
#endif
#define TruncRec(objr) (void)( (objr)->length = (objr)->curoff )
enum {
TIME_SEC_B = 0,
TIME_SEC_F = 0x001f,
TIME_MIN_B = 5,
TIME_MIN_F = 0x07e0,
TIME_HOUR_B = 11,
TIME_HOUR_F = 0xf800
};
enum {
DATE_DAY_B = 0,
DATE_DAY_F = 0x001f,
DATE_MON_B = 5,
DATE_MON_F = 0x01e0,
DATE_YEAR_B = 9,
DATE_YEAR_F = 0xfe00
};
union DOS_DATETIME {
struct {
unsigned short time;
unsigned short date;
} dos;
time_t timet;
};
extern void cv_write_debug_tables( struct dsym *, struct dsym *, void * );
extern void SortSegments( int );
extern struct qdesc LinnumQueue;
extern const char szNull[];
int_32 LastCodeBufSize;
static uint_32 seg_pos;
static uint_32 public_pos;
static uint_32 end_of_header;
static int startitem;
static int startext;
#if MULTIHDR
static unsigned ln_srcfile;
#endif
static uint_8 ln_is32;
static uint_16 ln_size;
enum dbgseg_index {
DBGS_SYMBOLS,
DBGS_TYPES,
DBGS_MAX
};
struct dbg_section {
const char *name;
const char *cname;
};
static const struct dbg_section SymDebParm[DBGS_MAX] = {
{ "$$SYMBOLS", "DEBSYM" },
{ "$$TYPES", "DEBTYP" },
};
static struct dsym *SymDebSeg[DBGS_MAX];
static void omf_InitRec( struct omf_rec *obj, uint_8 command )
{
obj->length = 0;
obj->curoff = 0;
obj->data = NULL;
obj->command = command;
obj->is_32 = 0;
DebugMsg1(("omf_InitRec(%p, %X)\n", obj, command ));
return;
}
static time_t timet2dostime( time_t x )
{
struct tm * ltime;
union DOS_DATETIME dt;
ltime = localtime( &x );
dt.dos.date = (( ltime->tm_year - 80 ) << DATE_YEAR_B )
| (( ltime->tm_mon + 1 ) << DATE_MON_B )
| (( ltime->tm_mday ) << DATE_DAY_B );
dt.dos.time = (( ltime->tm_hour ) << TIME_HOUR_B )
| (( ltime->tm_min ) << TIME_MIN_B )
| (( ltime->tm_sec / 2 ) << TIME_SEC_B );
return( dt.timet );
}
static void Put8( struct omf_rec *objr, uint_8 value )
{
myassert( objr != NULL && objr->data != NULL );
objr->data[ objr->curoff++ ] = value;
}
static void Put16( struct omf_rec *objr, uint_16 value )
{
myassert( objr != NULL && objr->data != NULL );
WriteU16( objr->data + objr->curoff, value );
objr->curoff += sizeof( uint_16 );
}
static void Put32( struct omf_rec *objr, uint_32 value )
{
myassert( objr != NULL && objr->data != NULL );
WriteU32( objr->data + objr->curoff, value );
objr->curoff += sizeof( uint_32 );
}
#if 0#endif
static void PutIndex( struct omf_rec *objr, unsigned idx )
{
myassert( objr != NULL && objr->data != NULL && idx <= 0x7FFF );
if( idx > 0x7f ) {
objr->data[objr->curoff++] = ( idx >> 8 ) | 0x80;
}
objr->data[objr->curoff++] = idx & 0xff;
}
static void PutData( struct omf_rec *objr, const uint_8 *data, size_t len )
{
myassert( objr != NULL && objr->data != NULL );
memcpy( objr->data + objr->curoff, data, len );
objr->curoff += len;
}
static void PutName( struct omf_rec *objr, const char *name, size_t len )
{
myassert( objr != NULL && objr->data != NULL );
#if MAX_ID_LEN > MAX_ID_LEN_OMF
if ( len > MAX_ID_LEN_OMF ) {
EmitWarn( 1, IDENTIFIER_TOO_LONG );
len = MAX_ID_LEN_OMF;
}
#endif
objr->data[objr->curoff++] = len;
PutData( objr, (uint_8 *)name, len );
}
static void AttachData( struct omf_rec *objr, uint_8 *data, size_t len )
{
myassert( objr->data == NULL );
objr->data = data;
objr->length = len;
}
#if 0#endif
unsigned omf_GetGrpIdx( struct asym *sym )
{
return( sym ? ((struct dsym *)sym)->e.grpinfo->grp_idx : 0 );
}
void omf_OutSelect( bool is_data )
{
struct omf_rec obj;
uint_32 currofs;
int sel_idx;
static uint_32 sel_start;
unsigned char buffer[12];
if( is_data ) {
if( CurrSeg->e.seginfo->data_in_code ||
( CurrSeg->e.seginfo->segtype != SEGTYPE_CODE ) )
return;
sel_start = GetCurrOffset();
CurrSeg->e.seginfo->data_in_code = TRUE;
DebugMsg(("omf_OutSelect: data in code segment (%s), starting at %" I32_SPEC "X\n", CurrSeg->sym.name, sel_start ));
} else if ( CurrSeg->e.seginfo->data_in_code ) {
CurrSeg->e.seginfo->data_in_code = FALSE;
if( write_to_file == TRUE ) {
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_DISASM_DIRECTIVE;
sel_idx = GetSegIdx( &CurrSeg->sym );
AttachData( &obj, buffer, 11 );
currofs = GetCurrOffset();
DebugMsg(("omf_OutSelect: writing coment record about data in code: start=%" I32_SPEC "X curofs=%" I32_SPEC "X\n", sel_start, currofs ));
if( ( sel_start > 0xffffUL ) || ( currofs > 0xffffUL ) ) {
Put8( &obj, DDIR_SCAN_TABLE_32 );
PutIndex( &obj, sel_idx );
Put32( &obj, sel_start );
Put32( &obj, currofs );
} else {
Put8( &obj, DDIR_SCAN_TABLE );
PutIndex( &obj, sel_idx );
Put16( &obj, sel_start );
Put16( &obj, currofs );
}
TruncRec( &obj );
omf_write_record( &obj );
}
}
}
static void omf_write_linnum( uint_8 is32 )
{
unsigned ofssize = ( is32 ? sizeof( uint_32) : sizeof( uint_16 ) );
unsigned size;
uint_8 *data;
struct line_num_info *node;
struct line_num_info *next;
struct omf_rec obj;
for( node = LinnumQueue.head, data = StringBufferEnd; node; node = next ) {
next = node->next;
*(uint_16 *)data = node->number;
data += sizeof( uint_16 );
*(uint_32 *)data = node->offset;
data += ofssize;
LclFree( node );
}
LinnumQueue.head = NULL;
size = (char *)data - StringBufferEnd;
if( size ) {
omf_InitRec( &obj, CMD_LINNUM );
obj.is_32 = is32;
AttachData( &obj, StringBufferEnd, size );
obj.d.linnum.base.grp_idx = omf_GetGrpIdx( GetGroup( &CurrSeg->sym ) );
obj.d.linnum.base.seg_idx = CurrSeg->e.seginfo->seg_idx;
obj.d.linnum.base.frame = 0;
omf_write_record( &obj );
}
return;
}
static void omf_write_fixupp( struct dsym *seg, char is32 )
{
uint_8 *data;
unsigned size;
struct fixup *fix;
enum fixup_types type = ( is32 ? FIX_GEN_MS386 : FIX_GEN_INTEL );
struct omf_rec obj;
fix = seg->e.seginfo->FixupList.head;
while ( fix ) {
for( data = StringBufferEnd, size = 0; fix; fix = fix->nextrlc ) {
switch( fix->type ) {
case FIX_RELOFF32:
case FIX_OFF32:
case FIX_PTR32:
if ( !is32 ) continue;
break;
default:
if ( is32 ) continue;
break;
}
if ( size > 1020 - FIX_GEN_MAX )
break;
data += OmfFixGenFix( fix, seg->e.seginfo->start_loc, data, type );
size = (char *)data - StringBufferEnd;
}
if ( size ) {
omf_InitRec( &obj, CMD_FIXUPP );
obj.is_32 = is32;
AttachData( &obj, StringBufferEnd, size );
omf_write_record( &obj );
}
}
}
static uint_8 get_omfalign( uint_8 alignment );
static void omf_write_ledata( struct dsym *seg )
{
struct omf_rec obj;
int_32 size;
size = seg->e.seginfo->current_loc - seg->e.seginfo->start_loc;
DebugMsg1(( "omf_write_ledata enter, buffer=%p start ofs=%" I32_SPEC "X, size=%" I32_SPEC "X\n",
seg->e.seginfo->CodeBuffer, seg->e.seginfo->start_loc, size ));
if( size > 0 && write_to_file == TRUE ) {
LastCodeBufSize = size;
#if COMDATSUPP
if ( seg->e.seginfo->comdat_selection ) {
if ( seg->sym.used ) {
omf_InitRec( &obj, CMD_CEXTDEF );
AttachData( &obj, StringBufferEnd, 2 * sizeof( uint_16 ) );
PutIndex( &obj, seg->e.seginfo->comdat_idx );
PutIndex( &obj, 0 );
TruncRec( &obj );
omf_write_record( &obj );
if ( seg->e.seginfo->seg_idx == 0 )
seg->e.seginfo->seg_idx = startext++;
}
omf_InitRec( &obj, CMD_COMDAT );
AttachData( &obj, seg->e.seginfo->CodeBuffer, size );
if( seg->e.seginfo->start_loc > 0xffffUL )
obj.is_32 = 1;
obj.d.comdat.flags = 0;
if ( seg->e.seginfo->segtype == SEGTYPE_CODE ) {
obj.d.comdat.attributes = ( ModuleInfo.model == MODEL_FLAT ? COMDAT_CODE32 : COMDAT_FAR_CODE );
} else {
obj.d.comdat.attributes = ( ModuleInfo.model == MODEL_FLAT ? COMDAT_DATA32 : COMDAT_FAR_DATA );
}
obj.d.comdat.align = get_omfalign( seg->e.seginfo->alignment );
obj.d.comdat.offset = seg->e.seginfo->start_loc;
obj.d.comdat.type_idx = 0;
obj.d.comdat.public_lname_idx = seg->e.seginfo->comdat_idx;
} else {
#endif
omf_InitRec( &obj, CMD_LEDATA );
AttachData( &obj, seg->e.seginfo->CodeBuffer, size );
obj.d.ledata.idx = seg->e.seginfo->seg_idx;
obj.d.ledata.offset = seg->e.seginfo->start_loc;
if( obj.d.ledata.offset > 0xffffUL )
obj.is_32 = 1;
#if COMDATSUPP
}
#endif
omf_write_record( &obj );
if( seg->e.seginfo->FixupList.head != NULL ) {
#if FASTMEM==0
struct fixup *fix;
struct fixup *next;
#endif
omf_write_fixupp( seg, 0 );
omf_write_fixupp( seg, 1 );
#if FASTMEM==0
for( fix = seg->e.seginfo->FixupList.head; fix; ) {
next = fix->nextrlc;
LclFree( fix );
fix = next;
}
#endif
seg->e.seginfo->FixupList.head = seg->e.seginfo->FixupList.tail = NULL;
}
}
seg->e.seginfo->start_loc = seg->e.seginfo->current_loc;
}
void omf_FlushCurrSeg( void )
{
DebugMsg1(( "omf_FlushCurrSeg() enter, CurrSeg=%s, currsrc=%u\n", CurrSeg ? CurrSeg->sym.name : "NULL", get_curr_srcfile() ));
omf_write_ledata( CurrSeg );
if( Options.line_numbers ) {
omf_write_linnum( ln_is32 );
ln_size = 0;
}
return;
}
static void omf_write_theadr( const char *name )
{
struct omf_rec obj;
unsigned len;
DebugMsg1(("omf_write_theadr(%s) enter\n", name));
omf_InitRec( &obj, CMD_THEADR );
len = strlen( name );
AttachData( &obj, StringBufferEnd, len + 1 );
PutName( &obj, name, len );
omf_write_record( &obj );
DebugMsg1(("omf_write_theadr() exit\n"));
}
void omf_check_flush( const struct line_num_info *curr )
{
uint_8 is_32;
uint_16 size;
#if MULTIHDR
if ( curr->srcfile != ln_srcfile ) {
if ( LinnumQueue.head )
omf_FlushCurrSeg();
omf_write_theadr( GetFName( curr->srcfile )->fname );
ln_srcfile = curr->srcfile;
return;
}
#endif
is_32 = ( curr->offset > 0xffff ? TRUE : FALSE );
if ( ln_is32 != is_32 ) {
if ( LinnumQueue.head )
omf_FlushCurrSeg();
ln_is32 = is_32;
return;
}
size = sizeof( uint_16 ) + ( is_32 ? sizeof( uint_32 ) : sizeof( uint_16 ) );
if ( ln_size + size > 1024 - 8 ) {
if ( LinnumQueue.head )
omf_FlushCurrSeg();
}
ln_size += size;
return;
};
static void omf_end_of_pass1( void )
{
struct omf_rec obj;
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = 0x00;
obj.d.coment.cmt_class = CMT_MS_END_PASS_1;
AttachData( &obj, (uint_8 *)"\x001", 1 );
omf_write_record( &obj );
}
void omf_set_filepos( void )
{
DebugMsg1(( "omf_set_filepos: reset file pos to %X\n", end_of_header ));
#if MULTIHDR
#endif
fseek( CurrFile[OBJ], end_of_header, SEEK_SET );
}
static void omf_write_dosseg( void )
{
struct omf_rec obj;
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_DOSSEG;
AttachData( &obj, (uint_8 *)"", 0 );
omf_write_record( &obj );
}
static void omf_write_lib( void )
{
struct omf_rec obj;
struct qitem *curr;
struct qitem *next;
char *name;
DebugMsg1(("omf_write_lib() enter\n"));
for( curr = ModuleInfo.g.LibQueue.head; curr; curr = next ) {
next = curr->next;
name = curr->value;
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_DEFAULT_LIBRARY;
AttachData( &obj, (uint_8 *)name, strlen( name ) );
omf_write_record( &obj );
}
DebugMsg1(("omf_write_lib() exit\n"));
}
#if DLLIMPORT && WRITEIMPDEF
void omf_write_import( void )
{
struct dsym *imp;
int len;
struct omf_rec obj;
uint_8 *data;
if ( (!Options.write_impdef) || Options.names[OPTN_LNKDEF_FN] )
return;
for ( imp = SymTables[TAB_EXT].head; imp; imp = imp->next ) {
if ( imp->sym.isproc && ( imp->sym.weak == FALSE || imp->sym.iat_used == TRUE ) ) {
if ( imp->sym.dll && *imp->sym.dll->name ) {
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = 0x00;
obj.d.coment.cmt_class = CMT_OMF_EXT;
data = StringBufferEnd;
len = Mangle( &imp->sym, data+3 );
AttachData( &obj, data, len + strlen( imp->sym.dll->name ) + 5 );
Put8( &obj, CMT_EXT_IMPDEF );
Put8( &obj, 0 );
Put8( &obj, len );
obj.curoff += len;
PutName( &obj, imp->sym.dll->name, strlen( imp->sym.dll->name ) );
Put8( &obj, 0 );
omf_write_record( &obj );
}
}
}
}
#endif
static void omf_write_export( void )
{
uint_8 parmcnt;
struct dsym *dir;
struct dsym *parm;
struct omf_rec obj;
int len;
uint_8 *data;
#if DLLIMPORT && WRITEIMPDEF
omf_write_import();
#endif
for( dir = SymTables[TAB_PROC].head; dir != NULL; dir = dir->nextproc ) {
if( dir->e.procinfo->isexport ) {
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = 0x00;
obj.d.coment.cmt_class = CMT_OMF_EXT;
data = StringBufferEnd;
if ( Options.no_export_decoration == FALSE )
len = Mangle( &dir->sym, data+3 );
else {
strcpy( data+3, dir->sym.name );
len = dir->sym.name_size;
}
if ( ModuleInfo.convert_uppercase )
_strupr( data+3 );
#if MAX_ID_LEN > 255
if ( len > 255 )
len = 255;
#endif
AttachData( &obj, data, len + 4 );
Put8( &obj, CMT_EXT_EXPDEF );
for ( parm = dir->e.procinfo->paralist, parmcnt = 0; parm; parm = parm->nextparam, parmcnt++ );
parmcnt &= 0x1F;
Put8( &obj, parmcnt );
Put8( &obj, len );
obj.curoff += len;
Put8( &obj, 0 );
omf_write_record( &obj );
}
}
}
static void omf_write_grpdef( void )
{
struct dsym *curr;
struct dsym *segminfo;
struct seg_item *seg;
struct omf_rec grp;
DebugMsg1(("omf_write_grpdef enter\n"));
for( curr = SymTables[TAB_GRP].head; curr; curr = curr->next ) {
omf_InitRec( &grp, CMD_GRPDEF );
grp.d.grpdef.idx = curr->e.grpinfo->grp_idx;
AttachData( &grp, StringBufferEnd, 2 + 3 * curr->e.grpinfo->numseg );
PutIndex( &grp, curr->e.grpinfo->lname_idx );
for( seg = curr->e.grpinfo->seglist; seg; seg = seg->next ) {
segminfo = (struct dsym *)(seg->seg);
Put8( &grp, GRP_SEGIDX );
PutIndex( &grp, segminfo->e.seginfo->seg_idx );
if ( grp.curoff > OBJ_BUFFER_SIZE - 10 ) {
EmitWarn( 2, GROUP_DEFINITION_TOO_LARGE, curr->sym.name );
break;
}
}
TruncRec( &grp );
omf_write_record( &grp );
}
DebugMsg1(("omf_write_grpdef exit\n"));
}
static uint_8 get_omfalign( uint_8 alignment )
{
switch ( alignment ) {
case 1: return( SEGDEF_ALIGN_WORD );
case 2: return( SEGDEF_ALIGN_DWORD );
case 4: return( SEGDEF_ALIGN_PARA );
case 8: return( SEGDEF_ALIGN_PAGE );
#if PAGE4K
case 12:
if ( Parse_Pass == PASS_1 )
EmitWarn( 2, NO_4KPAGE_ALIGNED_SEGMENTS_IN_MS386 );
return( SEGDEF_ALIGN_4KPAGE );
#endif
case MAX_SEGALIGNMENT: return( SEGDEF_ALIGN_ABS );
}
myassert( alignment == 0 );
return( SEGDEF_ALIGN_BYTE );
}
static void omf_write_segdef( void )
{
struct dsym *curr;
struct omf_rec obj;
DebugMsg1(("omf_write_segdef enter\n"));
for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) {
#if COMDATSUPP
if ( curr->e.seginfo->comdat_selection )
continue;
#endif
omf_InitRec( &obj, CMD_SEGDEF );
if ( curr->e.seginfo->Ofssize > USE16 ) {
obj.is_32 = ( ( curr->e.seginfo->force32 || ( curr->sym.max_offset >= 0x10000 ) ) ? 1 : 0 );
} else {
obj.is_32 = 0;
}
obj.d.segdef.idx = curr->e.seginfo->seg_idx;
obj.d.segdef.use_32 = ( curr->e.seginfo->Ofssize > USE16 ? 1 : 0 );
obj.d.segdef.align = get_omfalign( curr->e.seginfo->alignment );
obj.d.segdef.combine = curr->e.seginfo->combine;
obj.d.segdef.abs.frame = curr->e.seginfo->abs_frame;
obj.d.segdef.abs.offset = curr->e.seginfo->abs_offset;
obj.d.segdef.seg_length = curr->sym.max_offset;
obj.d.segdef.seg_lname_idx = curr->e.seginfo->lname_idx;
obj.d.segdef.class_lname_idx = ( curr->e.seginfo->clsym ? curr->e.seginfo->clsym->class_lname_idx : 1 );
obj.d.segdef.ovl_lname_idx = 1;
omf_write_record( &obj );
DebugMsg1(("omf_write_segdef(%s): len=%" I32_SPEC "X use32=%u align=%u comb=%u seg_lname=%u class_lname=%u ovl_lname=%u\n",
curr->sym.name,
obj.d.segdef.seg_length,
obj.d.segdef.use_32,
obj.d.segdef.align,
obj.d.segdef.combine,
obj.d.segdef.seg_lname_idx,
obj.d.segdef.class_lname_idx,
obj.d.segdef.ovl_lname_idx
));
if( curr->e.seginfo->segtype == SEGTYPE_CODE && Options.no_opt_farcall == FALSE ) {
uint_8 buffer[4];
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_LINKER_DIRECTIVE;
AttachData( &obj, buffer, 3 );
Put8( &obj, LDIR_OPT_FAR_CALLS );
PutIndex( &obj, curr->e.seginfo->seg_idx );
TruncRec( &obj );
omf_write_record( &obj );
}
}
DebugMsg1(("omf_write_segdef exit\n"));
}
static void omf_write_lnames( void )
{
int size;
int items;
unsigned char *p;
struct qnode *curr;
struct asym *sym;
struct omf_rec obj;
unsigned char buffer[MAX_LNAME_SIZE];
DebugMsg1(("omf_write_lnames() enter\n"));
p = buffer;
*p++ = NULLC;
items = 1;
startitem = 1;
for ( curr = ModuleInfo.g.LnameQueue.head; ; curr = curr->next ) {
sym = ( curr ? (struct asym *)(curr->elmt) : NULL );
size = p - buffer;
if ( sym == NULL || ( ( size + sym->name_size + 4 ) > MAX_LNAME_SIZE )) {
if( size ) {
omf_InitRec( &obj, CMD_LNAMES );
obj.d.lnames.first_idx = startitem;
obj.d.lnames.num_names = items;
AttachData( &obj, buffer, size );
omf_write_record( &obj );
startitem = items;
}
if ( sym == NULL )
break;
p = buffer;
}
*p++ = (char)sym->name_size;
memcpy( p, sym->name, sym->name_size + 1 );
if ( ModuleInfo.case_sensitive == FALSE )
_strupr( p );
DebugMsg1(("omf_write_lnames: %u=%s\n", items, p ));
p += sym->name_size;
items++;
switch ( sym->state ) {
case SYM_SEG: ((struct dsym *)sym)->e.seginfo->lname_idx = items; break;
case SYM_GRP: ((struct dsym *)sym)->e.grpinfo->lname_idx = items; break;
default: sym->class_lname_idx = items; break;
}
};
DebugMsg1(("omf_write_lnames() exit, items=%u\n", items ));
}
struct readext {
struct dsym *p;
uint_16 index;
uint_8 method;
};
static struct asym *GetExt( struct readext *r )
{
struct asym *sym;
if ( r->method == 0 ) {
for ( ; r->p; ) {
sym = (struct asym *)r->p;
r->p = r->p->next;
if ( sym->iscomm == TRUE )
continue;
if ( sym->altname && sym->altname->included == FALSE ) {
myassert( r->index );
sym->altname->ext_idx2 = r->index++;
sym->altname->included = TRUE;
return( sym->altname );
}
}
r->method++;
r->p = SymTables[TAB_EXT].head;
}
for ( ; r->p; ) {
sym = (struct asym *)r->p;
r->p = r->p->next;
if ( sym->iscomm == TRUE || sym->weak == TRUE )
continue;
myassert( r->index );
sym->ext_idx1 = r->index++;
return( sym );
}
return( NULL );
}
static uint_16 omf_write_extdef( void )
{
struct omf_rec obj;
struct asym *sym;
struct dsym *symext;
unsigned rec_size;
unsigned len;
struct readext r;
char data[MAX_EXT_LENGTH];
unsigned char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
DebugMsg1(("omf_write_extdef enter\n"));
r.p = SymTables[TAB_EXT].head;
r.index = 1;
r.method = 0;
obj.d.extdef.first_idx = 0;
sym = GetExt( &r );
while ( sym ) {
for ( rec_size = 0, obj.d.extdef.num_names = 0; sym; sym = GetExt( &r ) ) {
DebugMsg1(("omf_write_extdef: %s\n", sym->name));
len = Mangle( sym, buffer );
#if MAX_ID_LEN > 255
if ( len > 255 )
len = 255;
#endif
if ( ModuleInfo.convert_uppercase )
_strupr( buffer );
if( rec_size + len + 2 >= MAX_EXT_LENGTH ) {
break;
}
obj.d.extdef.num_names++;
data[rec_size++] = (char)len;
memcpy( data + rec_size, buffer, len );
rec_size += len;
data[rec_size++] = 0;
}
if ( rec_size ) {
DebugMsg1(("omf_write_extdef: write record, names=%u, size=%u, MAX=%u\n", obj.d.extdef.num_names, rec_size, MAX_EXT_LENGTH ));
omf_InitRec( &obj, CMD_EXTDEF );
AttachData( &obj, (uint_8 *)data, rec_size );
omf_write_record( &obj );
obj.d.extdef.first_idx += obj.d.extdef.num_names;
}
}
for ( symext = SymTables[TAB_EXT].head; symext; symext = symext->next ) {
if ( symext->sym.iscomm == FALSE && symext->sym.altname ) {
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_WKEXT;
AttachData( &obj, buffer, 4 );
PutIndex( &obj, symext->sym.ext_idx1 );
PutIndex( &obj, symext->sym.altname->ext_idx2 );
TruncRec( &obj );
omf_write_record( &obj );
}
}
for ( symext = SymTables[TAB_EXT].head; symext; symext = symext->next ) {
if ( symext->sym.iscomm == FALSE && symext->sym.altname && symext->sym.altname->state != SYM_EXTERNAL )
symext->sym.altname->ext_idx = 0;
}
DebugMsg1(("omf_write_extdef exit, index=%u\n", r.index ));
return( r.index );
}
#define THREE_BYTE_MAX ( (1UL << 24) - 1 )
static int get_size_of_comdef_number( uint_32 value )
{
if( value < 128 ) {
return( 1 );
} else if( value <= USHRT_MAX ) {
return( 3 );
} else if( value <= THREE_BYTE_MAX ) {
return( 4 );
} else {
return( 5 );
}
}
static unsigned put_comdef_number( uint_8 *buffer, uint_32 value )
{
unsigned i;
unsigned symsize;
symsize = get_size_of_comdef_number( value );
switch( symsize ) {
case 1: *buffer = value; break;
case 3: *buffer++ = COMDEF_LEAF_2; break;
case 4: *buffer++ = COMDEF_LEAF_3; break;
case 5: *buffer++ = COMDEF_LEAF_4; break;
}
for( i = 1; i < symsize; i++ ) {
*buffer++ = value % ( UCHAR_MAX + 1 );
value >>= 8;
}
return( symsize );
}
static uint_16 omf_write_comdef( uint_16 index )
{
struct omf_rec obj;
struct dsym *curr;
unsigned num;
unsigned recsize;
unsigned numsize;
unsigned symsize;
uint_32 varsize;
unsigned start = 0;
char buffer[MAX_ID_LEN + MANGLE_BYTES + 1];
char data[MAX_EXT_LENGTH];
char number[16];
DebugMsg1(("omf_write_comdef enter\n"));
curr = SymTables[TAB_EXT].head;
while ( curr ) {
for( num = 0, recsize = 0; curr != NULL ; curr = curr->next ) {
if ( curr->sym.iscomm == FALSE )
continue;
symsize = Mangle( &curr->sym, buffer );
#if MAX_ID_LEN > 255
if ( symsize > 255 )
symsize = 255;
#endif
if ( ModuleInfo.convert_uppercase )
_strupr( buffer );
varsize = SizeFromMemtype( curr->sym.mem_type, ModuleInfo.Ofssize, curr->sym.type );
myassert( index );
curr->sym.ext_idx = index++;
DebugMsg1(("omf_write_comdef: %s, size=%u, sym.total_size=%u, sym.total_length=%u, sym.isfar=%u\n",
curr->sym.name, varsize, curr->sym.total_size, curr->sym.total_length, curr->sym.isfar ));
if ( varsize == 0 )
varsize = curr->sym.total_size / curr->sym.total_length;
numsize = 1;
if ( curr->sym.isfar == TRUE ) {
number[0] = COMDEF_FAR;
numsize += put_comdef_number( &number[1], curr->sym.total_length );
numsize += put_comdef_number( &number[numsize], varsize );
DebugMsg(("omf_write_comdef: numsize=%u, length=%u, varsize=%u\n",
numsize, curr->sym.total_length, varsize ));
} else {
number[0] = COMDEF_NEAR;
numsize += put_comdef_number( &number[1], curr->sym.total_length * varsize );
DebugMsg1(("omf_write_comdef: numsize=%u, value=%u\n",
numsize, curr->sym.total_length * varsize ));
}
if ( ( recsize + symsize + numsize + 2 ) > MAX_EXT_LENGTH )
break;
data[recsize++] = (char)symsize;
memcpy( data + recsize, buffer, symsize );
recsize += symsize;
data[recsize++] = 0;
memcpy( data + recsize, number, numsize );
recsize += numsize;
num++;
}
if( num > 0 ) {
omf_InitRec( &obj, CMD_COMDEF );
obj.d.comdef.first_idx = start;
AttachData( &obj, (uint_8 *)data, recsize );
obj.d.comdef.num_names = num;
omf_write_record( &obj );
start += num;
}
}
DebugMsg1(("omf_write_comdef exit\n"));
return( index );
}
static time_t GetFileTimeStamp( const char *filename )
{
struct _stat statbuf;
if( _stat( filename, &statbuf ) != 0 ) {
DebugMsg(("GetFileTimeStamp(%s): _stat() did return 0\n", filename ));
return( 0 );
}
return( statbuf.st_mtime );
}
static ret_code omf_write_autodep( void )
{
struct omf_rec obj;
struct fname_item *curr;
char *p = StringBufferEnd;
unsigned int len;
unsigned idx;
DebugMsg(("omf_write_autodep() enter\n"));
for( idx = 0, curr = ModuleInfo.g.FNames; idx < ModuleInfo.g.cnt_fnames; idx++, curr++ ) {
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_DEPENDENCY;
len = strlen( curr->fname );
#if MAX_STRING_LEN > 255
if ( len > 255 )
len = 255;
#endif
*((time_t *)p) = timet2dostime( GetFileTimeStamp( curr->fname ) );
*(p + 4) = (unsigned char)len;
memcpy( p + 5, curr->fname, len );
AttachData( &obj, (uint_8 *)p, len + 5 );
DebugMsg(("omf_write_autodep(): write record: file=%s, time=%X\n", curr->fname, *((time_t *)p) ));
omf_write_record( &obj );
}
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = CMT_TNP;
obj.d.coment.cmt_class = CMT_DEPENDENCY;
AttachData( &obj, (uint_8 *)"", 0 );
omf_write_record( &obj );
DebugMsg(("omf_write_autodep() exit\n"));
return( NOT_ERROR );
}
static void omf_write_alias( void )
{
struct omf_rec obj;
char *p;
uint_8 len1;
uint_8 len2;
struct dsym *curr;
char tmp[MAX_ID_LEN + MANGLE_BYTES + 1];
unsigned char buff[2*MAX_ID_LEN_OMF + 2];
for( curr = SymTables[TAB_ALIAS].head; curr; curr = curr->next ) {
len1 = Mangle( &curr->sym, tmp );
#if MAX_ID_LEN > MAX_ID_LEN_OMF
if ( len1 > MAX_ID_LEN_OMF )
len1 = MAX_ID_LEN_OMF;
#endif
p = buff;
*p++ = len1;
memcpy( p, tmp, len1 );
p += len1;
len2 = Mangle( curr->sym.substitute, tmp );
#if MAX_ID_LEN > MAX_ID_LEN_OMF
if ( len2 > MAX_ID_LEN_OMF )
len2 = MAX_ID_LEN_OMF;
#endif
*p++ = len2;
memcpy( p, tmp, len2 );
omf_InitRec( &obj, CMD_ALIAS );
AttachData( &obj, buff, len1 + len2 + 2 );
omf_write_record( &obj );
}
}
static ret_code omf_write_pubdef( void )
{
struct qnode *q;
DebugMsg1(("omf_write_pub enter\n"));
q = ModuleInfo.g.PubQueue.head;
while ( q ) {
struct asym *curr_seg;
uint_8 *data;
unsigned size;
uint_8 curr32;
uint_8 is32;
for ( size = 0, data = StringBufferEnd; q; q = q->next ) {
unsigned recsize;
unsigned len;
struct asym *sym;
sym = q->sym;
#if COMDATSUPP
if ( sym->segment && ((struct dsym *)sym->segment)->e.seginfo->comdat_selection ) {
struct dsym *seg = (struct dsym *)sym->segment;
if ( seg->e.seginfo->comdat_idx == 0 ) {
struct omf_rec obj;
seg->e.seginfo->comdat_idx = ++startitem;
seg->sym.used = sym->used;
omf_InitRec( &obj, CMD_LNAMES );
len = Mangle( sym, StringBufferEnd + 1 );
*StringBufferEnd = len;
if ( ModuleInfo.case_sensitive == FALSE )
_strupr( StringBufferEnd + 1 );
AttachData( &obj, StringBufferEnd, len + 1 );
omf_write_record( &obj );
} else if ( Parse_Pass == PASS_1 ) {
}
continue;
}
#endif
#if 1
is32 = ( sym->offset > 0xffffUL ? 1 : 0 );
#else#endif
recsize = size + sym->name_size + MANGLE_BYTES + 4+4+1+1+( is32 ? 4 : 2 );
if( size && ( sym->segment != curr_seg || is32 != curr32 || recsize > MAX_PUB_LENGTH ) )
break;
len = Mangle( sym, data + 1 );
#if MAX_ID_LEN > MAX_ID_LEN_OMF
if ( len > 255 )
len = 255;
#endif
if ( ModuleInfo.convert_uppercase )
_strupr( data + 1 );
curr_seg = sym->segment;
curr32 = is32;
*data = len;
data += len + 1;
if ( curr32 ) {
*(uint_32 *)data = sym->offset;
data += sizeof( uint_32 );
} else {
*(uint_16 *)data = sym->offset;
data += sizeof( uint_16 );
}
*data++ = 0;
size = (char *)data - StringBufferEnd;
}
if ( size ) {
struct omf_rec obj;
omf_InitRec( &obj, CMD_PUBDEF );
AttachData( &obj, StringBufferEnd, size );
obj.is_32 = curr32;
if( curr_seg == NULL ) {
obj.d.pubdef.base.grp_idx = 0;
obj.d.pubdef.base.seg_idx = 0;
} else {
obj.d.pubdef.base.seg_idx = GetSegIdx( curr_seg );
obj.d.pubdef.base.grp_idx = omf_GetGrpIdx( GetGroup( curr_seg ) );
}
obj.d.pubdef.base.frame = 0;
omf_write_record( &obj );
}
}
DebugMsg1(("omf_write_pub exit\n"));
return( NOT_ERROR );
}
static void omf_write_modend( struct fixup *fixup, uint_32 displ )
{
struct omf_rec obj;
uint_8 buffer[FIX_GEN_MODEND_MAX];
DebugMsg(("omf_write_modend( fixup=%p, displ=%" I32_SPEC "X)\n", fixup, displ ));
omf_InitRec( &obj, CMD_MODEND );
if( fixup == NULL ) {
obj.d.modend.main_module = FALSE;
obj.d.modend.start_addrs = FALSE;
} else {
obj.d.modend.start_addrs = TRUE;
obj.d.modend.main_module = TRUE;
obj.is_32 = ( GetSymOfssize( fixup->sym ) > USE16 ? 1 : 0 );
AttachData( &obj, buffer, 0 );
obj.length = OmfFixGenFixModend( fixup, buffer, displ, obj.is_32 ? FIX_GEN_MS386 : FIX_GEN_INTEL );
}
omf_write_record( &obj );
}
static uint_8 *omf_cv_flushfunc( struct dsym *seg, uint_8 *curr, unsigned size, void *pv )
{
uint_8 *buffer = seg->e.seginfo->CodeBuffer;
if ( ( curr - buffer ) && ( ( curr - buffer ) + size ) > ( 1024 - 8 ) ) {
seg->e.seginfo->current_loc = seg->e.seginfo->start_loc + ( curr - buffer );
omf_write_ledata( seg );
return( buffer );
}
return( curr );
}
static void omf_write_header_dbgcv( void )
{
int i;
struct omf_rec obj;
omf_InitRec( &obj, CMD_COMENT );
obj.d.coment.attr = 0x00;
obj.d.coment.cmt_class = CMT_MS_OMF;
AttachData( &obj, "\001CV", 3 );
omf_write_record( &obj );
for ( i = 0; i < DBGS_MAX; i++ ) {
if ( SymDebSeg[i] = (struct dsym *)CreateIntSegment( SymDebParm[i].name, SymDebParm[i].cname, 0, USE32, TRUE ) ) {
SymDebSeg[i]->e.seginfo->force32 = TRUE;
SymDebSeg[i]->e.seginfo->flushfunc = omf_cv_flushfunc;
}
}
return;
}
static void omf_write_debug_tables( void )
{
if ( SymDebSeg[DBGS_SYMBOLS] && SymDebSeg[DBGS_TYPES] ) {
SymDebSeg[DBGS_SYMBOLS]->e.seginfo->CodeBuffer = CurrSource;
SymDebSeg[DBGS_TYPES]->e.seginfo->CodeBuffer = CurrSource + 1024;
cv_write_debug_tables( SymDebSeg[DBGS_SYMBOLS], SymDebSeg[DBGS_TYPES], NULL );
}
}
static ret_code omf_write_module( struct module_info *modinfo )
{
#if TRUNCATE
int fh;
uint_32 size;
#endif
if ( Options.debug_symbols )
omf_write_debug_tables();
omf_write_modend( modinfo->g.start_fixup, modinfo->g.start_displ );
#if FASTMEM==0
LclFree( modinfo->g.start_fixup );
#endif
#if TRUNCATE
size = ftell( CurrFile[OBJ] );
#if defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
fh = fileno( CurrFile[OBJ] );
if ( ftruncate( fh, size ) );
#elif defined(__BORLANDC__)
fh = _fileno( CurrFile[OBJ] );
chsize( fh, size );
#else
fh = _fileno( CurrFile[OBJ] );
_chsize( fh, size );
#endif
#endif
fseek( CurrFile[OBJ] , seg_pos, SEEK_SET );
omf_write_segdef();
fseek( CurrFile[OBJ], public_pos, SEEK_SET);
omf_write_pubdef();
return( NOT_ERROR );
}
static ret_code omf_write_header_initial( struct module_info *modinfo )
{
uint_16 ext_idx;
if ( write_to_file == FALSE )
return( NOT_ERROR );
omf_write_theadr( CurrFName[ASM] );
if ( Options.debug_symbols )
omf_write_header_dbgcv();
if( Options.line_numbers )
omf_write_autodep();
if( ModuleInfo.segorder == SEGORDER_DOSSEG )
omf_write_dosseg();
else if( ModuleInfo.segorder == SEGORDER_ALPHA )
SortSegments( 1 );
omf_write_lib();
omf_write_lnames();
seg_pos = ftell( CurrFile[OBJ] );
omf_write_segdef();
omf_write_grpdef();
ext_idx = omf_write_extdef();
startext = omf_write_comdef( ext_idx );
omf_write_alias();
public_pos = ftell( CurrFile[OBJ] );
omf_write_pubdef();
omf_write_export();
if ( !ModuleInfo.g.start_fixup )
omf_end_of_pass1();
end_of_header = ftell( CurrFile[OBJ] );
return( NOT_ERROR );
}
void omf_init( struct module_info *modinfo )
{
DebugMsg(("omf_init enter\n"));
modinfo->g.WriteModule = omf_write_module;
modinfo->g.Pass1Checks = omf_write_header_initial;
SymDebSeg[DBGS_SYMBOLS] = NULL;
SymDebSeg[DBGS_TYPES] = NULL;
#if MULTIHDR
ln_srcfile = modinfo->srcfile;
#endif
ln_size = 0;
return;
}