jwasm/omfint.c
2014-06-18 19:16:56 +04:00

529 lines
17 KiB
C

/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: OMF low-level output routines.
*
****************************************************************************/
#include <stddef.h>
#include "globals.h"
#include "omfint.h"
#include "omfspec.h"
#include "myassert.h"
#ifdef __I86__
#define FFQUAL __near
#else
#define FFQUAL
#endif
#pragma pack( push, 1 )
/* fields cmd, reclen and buffer must be consecutive */
struct outbuff {
unsigned in_buf; /* number of bytes in buffer */
uint_8 cmd; /* record cmd */
uint_16 reclen; /* record length */
uint_8 buffer[OBJ_BUFFER_SIZE];
};
#pragma pack( pop )
static void safeWrite( FILE *file, const uint_8 *buf, unsigned len )
/******************************************************************/
{
if( fwrite( buf, 1, len, file ) != len )
WriteError();
}
#if 0
/* this function was needed to reposition to the record's
* length field for update. Now always the full record is
* kept in the buffer until WEndRec().
*/
static void safeSeek( FILE *file, int_32 offset, int mode )
/*********************************************************/
{
if( fseek( file, offset, mode ) != 0 )
SeekError();
}
#endif
/* start a buffered OMF record output */
static void WBegRec( struct outbuff *out, uint_8 command )
/********************************************************/
{
out->in_buf = 0;
out->cmd = command;
}
/* WEndRec() finish a buffered record.
* - calculate checksum
* - store checksum behind buffer contents
* - writes the contents of the buffer(cmd, length, contents, checksum)
*/
static void WEndRec( struct outbuff *out )
/****************************************/
{
uint_8 checksum;
uint_8 *p;
uint_8 *end;
/**/myassert( out && out->cmd );
out->reclen = out->in_buf + 1; /* add 1 for checksum byte */
checksum = out->cmd + ( out->reclen & 0xff ) + (( out->reclen ) >> 8);
for( p = out->buffer, end = p + out->in_buf; p < end; ) {
checksum += *p++;
}
checksum = - checksum;
*p = checksum; /* store chksum in buffer */
/* write buffer + 4 extra bytes (1 cmd, 2 length, 1 chksum) */
safeWrite( CurrFile[OBJ], &out->cmd, out->in_buf + 4 );
#if 0 //def DEBUG_OUT
p = &out->cmd;
DebugMsg1(("WEndRec: %X %X %X %X\n", *p, *(p+1), *(p+2), *(p+3) ));
//printf( "WEndRec: %X %X %X %X (ofs cmd=%u ofs reclen=%u)\n", *p, *(p+1), *(p+2), *(p+3), offsetof( struct outbuff, cmd ), offsetof( struct outbuff, reclen ) );
#endif
}
/* write a byte to the current record */
static void PutByte( struct outbuff *out, uint_8 value )
/******************************************************/
{
out->buffer[ out->in_buf++ ] = value;
}
/* write an index - 1|2 byte(s) - to the current record */
static void PutIndex( struct outbuff *out, uint_16 index )
/********************************************************/
{
if( index > 0x7f ) {
PutByte( out, 0x80 | ( index >> 8 ) );
}
PutByte( out, index & 0xff );
}
/* write a word to the current record */
static void PutWord( struct outbuff *out, uint_16 value )
/*******************************************************/
{
WriteU16( out->buffer + out->in_buf, value );
out->in_buf += sizeof( uint_16 );
}
/* write a dword to the current record */
static void PutDword( struct outbuff *out, uint_32 value )
/********************************************************/
{
WriteU32( out->buffer + out->in_buf, value );
out->in_buf += sizeof( uint_32 );
}
/* write a byte sequence to the current record */
static void PutMem( struct outbuff *out, const uint_8 *buf, unsigned length )
/***************************************************************************/
{
/* ensure that there is enough free space in the buffer,
* and also 1 byte left for the chksum!
*/
if( length <= OBJ_BUFFER_SIZE - 1 - out->in_buf ) {
memcpy( &out->buffer[ out->in_buf ], buf, length );
out->in_buf += length;
} else {
/* this "shouldn't happen". */
DebugMsg(("PutMem: buffer overflow error [length=%u, free=%u]\n", length, OBJ_BUFFER_SIZE - 1 - out->in_buf ));
Fatal( INTERNAL_ERROR, __FILE__, __LINE__ );
}
}
/*--------------------------------------------------------*/
/* For 16-bit records which are the same under Intel and MS OMFs */
static int FFQUAL writeMisc( struct outbuff *out, const struct omf_rec *objr )
/****************************************************************************/
{
/**/myassert( objr->data != NULL );
WBegRec( out, objr->command );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
/* For 32-bit records which are the same under Intel and MS OMFs */
static int FFQUAL writeMisc32( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->data != NULL );
WBegRec( out, objr->command | objr->is_32 );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
static int FFQUAL writeComent( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->data != NULL );
WBegRec( out, CMD_COMENT );
PutByte( out, objr->d.coment.attr );
PutByte( out, objr->d.coment.cmt_class );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
static int FFQUAL writeSegdef( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
int is32;
uint_8 acbp;
uint_8 align;
/**/myassert( objr->command == CMD_SEGDEF );
//is32 = objr->d.segdef.use_32;
is32 = objr->is_32;
WBegRec( out, CMD_SEGDEF + is32 );
/* ACBP: bits=AAACCCBP
* AAA=alignment
* CCC=combination
* B=big
* P=32bit
*/
acbp = ( objr->d.segdef.combine << 2 ) | objr->d.segdef.use_32;
align = objr->d.segdef.align;
#if 1
acbp |= align << 5;
#else
switch( align ) {
case SEGDEF_ALIGN_ABS: acbp |= ALIGN_ABS << 5; break;
case SEGDEF_ALIGN_BYTE: acbp |= ALIGN_BYTE << 5; break;
case SEGDEF_ALIGN_WORD: acbp |= ALIGN_WORD << 5; break;
case SEGDEF_ALIGN_PARA: acbp |= ALIGN_PARA << 5; break;
case SEGDEF_ALIGN_PAGE: acbp |= ALIGN_PAGE << 5; break;
case SEGDEF_ALIGN_DWORD: acbp |= ALIGN_DWORD << 5; break;
#if PAGE4K
case SEGDEF_ALIGN_4KPAGE: acbp |= ALIGN_4KPAGE << 5; break;
#endif
default: /**/myassert( 0 );
}
#endif
/* set BIG bit. should also be done for 32-bit segments
* if their size is exactly 4 GB. Currently JWasm won't
* support segments with size 4 GB.
*/
if( is32 == 0 && objr->d.segdef.seg_length == 0x10000 ) {
acbp |= 0x02;
}
/* the segdef record is small (16bit: size 6 - 9 ):
* - byte acbp
* - word (32bit:dword) length
* - index seg name
* - index class name
* - index ovl name
* ABS segdefs are 3 bytes longer
*/
PutByte( out, acbp );
if( align == SEGDEF_ALIGN_ABS ) {
/* absolut segment has frame=word and offset=byte
* it isn't fixupp physical reference
* and doesn't depend on segment size (16/32bit)
*/
PutWord( out, objr->d.segdef.abs.frame );
PutByte( out, objr->d.segdef.abs.offset );
}
if( is32 ) {
PutDword( out, objr->d.segdef.seg_length );
} else {
PutWord( out, objr->d.segdef.seg_length );
}
PutIndex( out, objr->d.segdef.seg_lname_idx );
PutIndex( out, objr->d.segdef.class_lname_idx );
PutIndex( out, objr->d.segdef.ovl_lname_idx );
//if( objr->d.segdef.access_valid ) {
// EmitError( ACCESS_CLASSES_NOT_SUPPORTED );
//}
WEndRec( out );
return( 0 );
}
/*
* Write LEDATA or LIDATA record.
* the overhead is:
* - 1 byte cmd
* - 2 byte len
* - 1/2 bytes segment index
* - 2/4 bytes starting offset
* - 1 byte chksum
* so the data size "should" not exceed 1024-10 = 1014
*
* For LIDATA, the structure is equal.
* The structure of the data block differs, however:
* - 2/4: repeat count
* - 2: block count
* - content
*/
static int FFQUAL writeLedata( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_LEDATA || objr->command == CMD_LIDATA );
WBegRec( out, objr->command + objr->is_32 );
PutIndex( out, objr->d.ledata.idx );
if( objr->is_32 ) {
PutDword( out, objr->d.ledata.offset );
} else {
PutWord( out, objr->d.ledata.offset );
}
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
static int FFQUAL writeTheadr( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_THEADR );
return( writeMisc( out, objr ) );
}
static int FFQUAL writeModend( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
int is32;
//uint_8 is_log;
uint_8 mtype;
/**/myassert( objr->command == CMD_MODEND );
is32 = ( ( objr->is_32 && objr->d.modend.start_addrs ) ? TRUE : FALSE );
WBegRec( out, CMD_MODEND + is32 );
/* first byte is Module Type:
* bit 7: 1=main program module
* bit 6: 1=contains start address
* bit 5: Segment bit ( according to OMF, this bit should be 1 )
* bit 1-4: must be 0
* bit 0: start address contains relocatable address ( according to OMF, this bit should be 1 )
* Masm does set bit 0, but does not set bit 5!
*/
mtype = objr->d.modend.main_module ? 0x80 : 0;
if( objr->d.modend.start_addrs ) {
//is_log = objr->d.modend.is_logical;
//mtype |= 0x40 | is_log;
mtype |= 0x41;
PutByte( out, mtype );
PutMem( out, objr->data, objr->length );
} else
PutByte( out, mtype );
WEndRec( out );
return( 0 );
}
/* write public base field of COMDAT, PUBDEF or LINNUM records */
static void PutBase( struct outbuff *out, const struct base_info *base )
/**********************************************************************/
{
PutIndex( out, base->grp_idx );
PutIndex( out, base->seg_idx );
if( base->grp_idx == 0 && base->seg_idx == 0 ) {
PutWord( out, base->frame );
}
}
static int FFQUAL writePubdef( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_PUBDEF || objr->command == CMD_LPUBDEF );
WBegRec( out, objr->command + objr->is_32 );
PutBase( out, &objr->d.pubdef.base );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
static int FFQUAL writeLinnum( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_LINNUM );
WBegRec( out, CMD_LINNUM + objr->is_32 );
PutBase( out, &objr->d.linnum.base );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
#if COMDATSUPP
/* COMDATs are initialized communal data records.
* This isn't used yet for OMF.
*/
static int FFQUAL writeComdat( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_COMDAT );
/* write CMD_COMDAT/CMD_COMD32 */
WBegRec( out, objr->command + objr->is_32 );
PutByte( out, objr->d.comdat.flags );
PutByte( out, objr->d.comdat.attributes );
PutByte( out, objr->d.comdat.align );
if( objr->is_32 ) {
PutDword( out, objr->d.comdat.offset );
} else {
PutWord( out, objr->d.comdat.offset );
}
PutIndex( out, objr->d.comdat.type_idx );
if( ( objr->d.comdat.attributes & COMDAT_ALLOC_MASK ) == COMDAT_EXPLICIT ) {
PutBase( out, &objr->d.comdat.base );
}
PutIndex( out, objr->d.comdat.public_lname_idx );
/* record is already in ms omf format */
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
/* LINSYM record types are only used in conjunction with COMDAT. */
static int FFQUAL writeLinsym( struct outbuff *out, const struct omf_rec *objr )
/******************************************************************************/
{
/**/myassert( objr->command == CMD_LINSYM );
WBegRec( out, CMD_LINSYM + objr->is_32 );
PutByte( out, objr->d.linsym.flags );
PutIndex( out, objr->d.linsym.public_lname_idx );
PutMem( out, objr->data, objr->length );
WEndRec( out );
return( 0 );
}
#endif
static int FFQUAL writeUnexp( struct outbuff *out, const struct omf_rec *objr )
/*****************************************************************************/
{
DebugMsg(("unexpected OMF record type 0x%02X\n", objr->command ));
Fatal( INTERNAL_ERROR, __FILE__, __LINE__ );
/* this is never reached, since Fatal() won't return */
return( 0 );
}
typedef int FFQUAL (*pobj_filter)( struct outbuff *, const struct omf_rec * );
static const pobj_filter myFuncs[] = {
writeUnexp,
writeMisc,
writeMisc32,
writeSegdef,
writeLedata,
writeComent,
writeTheadr,
writeModend,
writePubdef,
writeLinnum,
#if COMDATSUPP
writeComdat,
writeLinsym
#endif
};
enum omffiltfuncs {
OFF_UNEXP,
OFF_MISC,
OFF_MISC32,
OFF_SEGDEF,
OFF_LEDATA,
OFF_COMENT,
OFF_THEADR,
OFF_MODEND,
OFF_PUBDEF,
OFF_LINNUM,
#if COMDATSUPP
OFF_COMDAT,
OFF_LINSYM
#endif
};
static const uint_8 func_index[] = {
OFF_THEADR, 0, 0, 0, /* 80 THEADR, LHEADR, PEDATA, PIDATA */
OFF_COMENT, OFF_MODEND, OFF_MISC, 0, /* 88 COMENT, MODEND, EXTDEF, TYPDEF */
OFF_PUBDEF, 0, OFF_LINNUM, OFF_MISC, /* 90 PUBDEF, LOCSYM, LINNUM, LNAMES */
OFF_SEGDEF, OFF_MISC, OFF_MISC32, 0, /* 98 SEGDEF, GRPDEF, FIXUP, ??? */
OFF_LEDATA, OFF_LEDATA, 0, 0, /* A0 LEDATA, LIDATA, LIBHED, LIBNAM */
0, 0, 0, 0, /* A8 LIBLOC, LIBDIC, ???, ??? */
OFF_MISC, OFF_MISC32, OFF_MISC, OFF_PUBDEF,/* B0 COMDEF, BAKPAT, LEXTDEF,LPUBDEF*/
OFF_MISC, 0, OFF_MISC, 0, /* B8 LCOMDEF,???, CEXTDEF,??? */
#if COMDATSUPP
0, OFF_COMDAT, OFF_LINSYM, OFF_MISC, /* C0 ???, COMDAT, LINSYM, ALIAS */
#else
0, 0, 0, OFF_MISC, /* C0 ???, COMDAT, LINSYM, ALIAS */
#endif
OFF_MISC32, OFF_MISC /* C8 NBKPAT, LLNAMES */
};
#define JUMP_INDEX(cmd) ( ( ( cmd ) - CMD_MIN_CMD ) >> 1 )
/* call a function - bit 0 of command is always 0 */
void omf_write_record( const struct omf_rec *objr )
/*************************************************/
{
struct outbuff out;
/**/myassert( objr != NULL && objr->command >= CMD_MIN_CMD && objr->command <= CMD_MAX_CMD + 1 );
DebugMsg1(("omf_write_record( cmd=%X data=%p length=%u )\n", objr->command, objr->data, objr->length ));
myFuncs[ func_index[JUMP_INDEX(objr->command) ] ] ( &out, objr );
}