pcorec.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 899 行 · 第 1/2 页
C
899 行
/****************************************************************************
*
* 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: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <string.h>
#include "disasm.h"
#include "wdismsg.h"
#include "hashtabl.h"
#define IMPORT_LOOKUP_TABLE_SIZE 127
#define EXPORT_LOOKUP_TABLE_SIZE 29
static uint_32 DataOffset;
/*
* Static function prototypes
*/
static void ThreadFix( uint_16 );
static void FixupFix( uint_16 );
static fixup *FixField( char, int, char );
static code_block *IteratedData( void );
static void DecodeLIData( code_block * );
static void Add2List( handle **, handle * );
static segment *FindComdat( unsigned lname )
{
segment *seg;
seg = Mod->segments;
while( seg->class != TYPE_COMDAT || seg->id != lname ) {
seg = seg->next_segment;
}
return( seg );
}
void GrpDef()
/************/
{
group *grp;
char grp_type;
segment *seg;
handle *hndl;
grp = NewGroup();
PutTab( ++GrpIndex, GrpTab, grp );
grp->id = GrpIndex;
grp->name = GetTab( GetIndex(), NameTab, FALSE );
while( EndOfRecord == FALSE ) {
grp_type = GetByte();
if( grp_type == GRP_SEGIDX ) {
seg = GetTab( GetIndex(), SegTab, TRUE );
seg->grouped = grp;
} else {
Error( ERR_UNIMPLE_GROUP, TRUE );
}
hndl = NewHandle( seg );
Add2List( &grp->list, hndl );
}
}
void PubDef( bool public )
/*************************/
{
uint_16 grp_id;
uint_16 seg_id;
char *name;
uint_32 addr;
export_sym *exp;
grp_id = GetIndex();
seg_id = GetIndex();
if( grp_id == 0 && seg_id == 0 ) {
SkipPcoRec(); /* absolute PUBDEF */
return;
}
Segment = GetTab( seg_id, SegTab, TRUE );
while( EndOfRecord == FALSE ) {
name = GetName( MAX_NAME_LEN );
if( IsPharLap || Is32Record ) {
addr = GetLong();
} else {
addr = GetWord();
}
GetIndex();
exp = AddLabel( addr, name, Segment, public, FALSE );
if( Options & FORM_ASSEMBLER ) {
import_sym *imp;
hash_data *ptr;
if( !Segment->exp_lookup ) {
Segment->exp_lookup = HashTableCreate( EXPORT_LOOKUP_TABLE_SIZE, HASH_STRING,
(hash_table_comparison_func)stricmp );
if( !Segment->exp_lookup ) {
SysError( ERR_OUT_OF_MEM, FALSE );
}
}
if( !HashTableInsert( Segment->exp_lookup, (hash_value)name, (hash_data)exp ) ) {
SysError( ERR_OUT_OF_MEM, FALSE );
}
ptr = HashTableQuery( Mod->imp_lookup, (hash_value)name );
if( ptr ) {
imp = (import_sym *)*ptr;
imp->exported = TRUE;
imp->u.also_exp = exp;
}
}
}
}
static void DoExtDef( char *name, unsigned type, bool public )
/*************************************************************/
{
import_sym *imp;
segment *save_seg;
imp = AllocMem( sizeof( import_sym ) );
PutTab( ++ExtIndex, ExtTab, imp );
imp->class = TYPE_IMPORT;
imp->name = name;
imp->type_id = type;
imp->next_imp = Mod->imports;
imp->far_common = FALSE;
imp->exported = FALSE;
imp->public = public;
Mod->imports = imp;
if( Options & FORM_ASSEMBLER ) {
if( !HashTableInsert( Mod->imp_lookup, (hash_value)name, (hash_data)imp ) ) {
SysError( ERR_OUT_OF_MEM, FALSE );
}
save_seg = Segment;
Segment = Mod->segments;
while( Segment ) {
if( Segment->exp_lookup != NULL ) {
hash_data *ptr;
ptr = HashTableQuery( Segment->exp_lookup, (hash_value)imp->name );
if( ptr ) {
imp->exported = TRUE;
imp->u.also_exp = (export_sym *)*ptr;
}
}
Segment = Segment->next_segment;
}
Segment = save_seg;
}
}
void ExtDef( bool public )
/************************/
{
char *name;
unsigned type;
while( EndOfRecord == FALSE ) {
name = GetName( MAX_NAME_LEN );
type = GetIndex();
DoExtDef( name, type, public );
}
}
void CExtDef()
/************/
{
char *name;
unsigned type;
while( EndOfRecord == FALSE ) {
name = GetTab( GetIndex(), NameTab, FALSE );
name = NameAlloc( name, strlen( name ) );
type = GetIndex();
DoExtDef( name, type, TRUE );
}
}
void ComDef( bool public )
/*************************/
{
import_sym *imp;
char data_seg_type;
while( EndOfRecord == FALSE ) {
imp = AllocMem( sizeof( import_sym ) );
PutTab( ++ExtIndex, ExtTab, imp );
imp->class = TYPE_COMDEF;
imp->name = GetName( MAX_NAME_LEN );
imp->public = public;
GetIndex();
data_seg_type = GetByte();
imp->u.size = GetVarSize();
if( data_seg_type == COMDEF_FAR ) { /* FAR */
imp->u.size *= GetVarSize();
imp->far_common = TRUE;
} else {
imp->far_common = FALSE;
}
imp->next_imp = Mod->imports;
Mod->imports = imp;
if( ( Options & FORM_ASSEMBLER ) &&
!HashTableInsert( Mod->imp_lookup, (hash_value)imp->name, (hash_data)imp ) ) {
SysError( ERR_OUT_OF_MEM, FALSE );
}
}
}
static void DoLinNum( segment *seg )
/***********************************/
{
line_num *line;
line_num *new_line;
line_num **owner;
unsigned num;
uint_32 addr;
owner = (line_num **)Mod->src_rover;
if( owner == NULL ) owner = &Mod->src;
while( EndOfRecord == FALSE ) {
num = GetWord();
if( IsPharLap || Is32Record ) {
addr = GetLong();
} else {
addr = GetWord();
}
if( num <= 0x7fff ) {
line = *owner;
if( line == NULL || line->seg != seg || line->address > addr ) {
owner = &Mod->src;
}
for( ;; ) {
line = *owner;
if( line == NULL ) break;
if( line->seg == seg ) {
if( line->address > addr ) break;
} else {
if( line->num > num ) break;
}
owner = &line->next_num;
}
new_line = AllocMem( sizeof( line_num ) );
new_line->num = num;
new_line->address = addr;
new_line->seg = seg;
new_line->next_num = line;
*owner = new_line;
}
}
Mod->src_rover = (line_num *)owner;
}
void LinNum()
/***********/
{
uint_16 grp_id;
uint_16 seg_id;
grp_id = GetIndex();
seg_id = GetIndex();
if( grp_id == 0 && seg_id == 0 ) {
GetWord();
}
DoLinNum( GetTab( seg_id, SegTab, TRUE ) );
}
void LinSym()
/***********/
{
GetByte(); /* skip flag byte */
DoLinNum( FindComdat( GetIndex() ) );
}
void FixUpp()
/************/
{
uint_16 info;
while( EndOfRecord == FALSE ) {
info = GetByte();
if( info & FIXUPP_FIXUP ) {
FixupFix( info );
} else {
ThreadFix( info );
}
}
}
static void ThreadFix( uint_16 trd_dat )
/****************************************/
{
char method;
char D;
char thred;
thread *trd;
D = ( trd_dat & 0x40 ) >> 4;
thred = ( trd_dat & 0x03 ) | D;
method = ( trd_dat & 0x1c ) >> 2;
trd = GetTab( thred, ThrdTab, FALSE );
if( D == 0 ) {
method &= 3;
}
FindTarget( method, trd );
}
static void FixupFix( uint_16 locat )
/*************************************/
{
fixup *fix;
char M;
char LOC;
M = ( locat & 0x40 ) << 1;
/* we take 4-bits as if every record is a Microsoft Fixup rec */
LOC = ( locat >> 2 ) & 0x0f;
if( IsPharLap && LOC > LOC_BASE_OFFSET_32 ) {
Error( ERR_INV_FIXUP_LOC, FALSE );
return;
}
DataOffset = ( ( locat & 3 ) << 8 ) | GetByte();
fix = FixField( LOC, 1, M );
AddFix( Segment, fix );
}
static fixup *FixField( char LOC, int is_valid_loc, char M )
/************************************************************/
/*
is_valid_loc == 1 is used to parse a FIXUP
is_valid_loc == 0 is used to parse fields such as the MODEND start
address field.
M is 0 for self-relative, 1 for seg-relative
*/
{
fixup *fix;
char fix_dat;
thread *trd;
char F;
char P;
char T;
char TARGT;
char FRAME;
if( ! IsPharLap && is_valid_loc ) {
/* we want PharLap OMF fixup LOC's... so we'll just translate here */
switch( LOC ) {
case LOC_MS_LINK_OFFSET: LOC = LOC_OFFSET; break;
case LOC_MS_OFFSET_32: /* fall through */
case LOC_MS_LINK_OFFSET_32: LOC = LOC_OFFSET_32; break;
case LOC_MS_BASE_OFFSET_32: LOC = LOC_BASE_OFFSET_32; break;
}
}
fix_dat = GetByte();
fix = NewFixup( LOC | M );
FRAME = ( fix_dat & 0x70 ) >> 4;
F = fix_dat & 0x80;
if( F ) {
trd = GetTab( FRAME | 4, ThrdTab, TRUE );
fix->frame = trd->datum;
fix->seg_address = trd->address;
} else {
FindTarget( FRAME, (thread *) &fix->frame );
}
TARGT = fix_dat & 0x03;
T = fix_dat & 0x08;
if( T ) {
trd = GetTab( TARGT, ThrdTab, TRUE );
fix->target = trd->datum;
fix->imp_address = trd->address;
} else {
FindTarget( TARGT, (thread *) &fix->target );
}
P = fix_dat & 0x04;
if( P == 0 ) {
if( IsPharLap || Is32Record ) {
fix->imp_address += GetLong();
} else {
fix->imp_address += GetWord();
}
}
if( is_valid_loc ) {
switch( LOC ) {
case LOC_OFFSET_LO:
fix->imp_address += Addr( DataOffset ) & 0xff;
break;
case LOC_OFFSET:
fix->imp_address += Addr( DataOffset );
break;
case LOC_BASE:
fix->seg_address += Addr( DataOffset );
break;
case LOC_BASE_OFFSET:
fix->imp_address += Addr( DataOffset );
fix->seg_address += Addr( DataOffset + 2 );
break;
case LOC_OFFSET_32:
fix->imp_address += Addr32( DataOffset );
break;
case LOC_OFFSET_HI:
fix->imp_address += Addr( DataOffset ) >> 8;
break;
case LOC_BASE_OFFSET_32:
fix->imp_address += Addr32( DataOffset );
fix->seg_address += Addr( DataOffset + 4 );
break;
}
fix->address = DataOffset + Offset;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?