objpass1.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,236 行 · 第 1/3 页
C
1,236 行
/****************************************************************************
*
* 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: Pass 1 of Open Watcom linker.
*
****************************************************************************/
#include <string.h>
#include <stdlib.h>
#include "linkstd.h"
#include "msg.h"
#include "alloc.h"
#include "wlnkmsg.h"
#include "specials.h"
#include "objnode.h"
#include "objcalc.h"
#include "dbgall.h"
#include "overlays.h"
#include "mapio.h"
#include "cmdline.h"
#include "objstrip.h"
#include "cmdnov.h"
#include "cmdelf.h"
#include "impexp.h"
#include "ring.h"
#include "strtab.h"
#include "carve.h"
#include "permdata.h"
#include "virtmem.h"
#include "obj2supp.h"
#include "objpass2.h"
#include "objpass1.h"
#define MAX_SEGMENT 0x10000
static seg_leader * LastCodeSeg; // last code segment in current module
static void MakeNewLeader( segdata *sdata, class_entry *class, unsigned_16 info);
static void FindALeader( segdata *sdata, class_entry *class, unsigned_16 info );
static void DoAllocateSegment( segdata *sdata, char *clname );
void ResetObjPass1( void )
/************************/
{
ObjFormat = 0;
}
extern void P1Start( void )
/*************************/
{
LastCodeSeg = NULL;
}
static void DoSavedImport( symbol *sym )
/**************************************/
{
dll_sym_info * dll;
length_name modname;
length_name extname;
if( FmtData.type & (MK_OS2 | MK_PE) ) {
dll = sym->p.import;
sym->p.import = NULL;
sym->info &= ~SYM_DEFINED;
modname.name = dll->m.modname;
modname.len = strlen( modname.name );
if( dll->isordinal ) {
MSImportKeyword( sym, &modname, NULL, dll->u.ordinal );
} else {
extname.name = dll->u.entname;
extname.len = strlen( extname.name );
MSImportKeyword( sym, &modname, &extname, NOT_IMP_BY_ORDINAL );
}
FreeImport( dll );
}
}
static void DoSavedExport( symbol *sym )
/**************************************/
{
entry_export * exp;
if( FmtData.type & (MK_OS2 | MK_PE | MK_WIN_VXD) ) {
exp = sym->e.export;
exp->sym = sym;
exp->impname = NULL;
AddToExportList( exp );
} else {
AddNameTable( sym->name, strlen(sym->name), TRUE,
&FmtData.u.nov.exp.export );
}
}
static bool StoreCDatData( void *_piece, void *_loc )
/***************************************************/
{
comdat_piece *piece = _piece;
virt_mem *loc = _loc;
PutInfo( *loc, piece->data, piece->length );
*loc += piece->length;
return FALSE;
}
extern void StoreInfoData( comdat_info *info )
/********************************************/
{
virt_mem temp;
info->sdata->data = AllocStg( info->sdata->length );
temp = info->sdata->data;
RingLookup( info->pieces, StoreCDatData, &temp );
}
static bool CheckVMemPieceDiff( void *_piece, void *_loc )
/********************************************************/
{
comdat_piece *piece = _piece;
virt_mem *loc = _loc;
bool retval;
retval = !CompareInfo( *loc, piece->data, piece->length );
*loc += piece->length;
return retval;
}
static bool CheckMemPieceDiff( void *_piece, void *_loc )
/*******************************************************/
{
comdat_piece *piece = _piece;
char **loc = _loc;
bool retval;
retval = memcmp( *loc, piece->data, piece->length ) != 0;
*loc += piece->length;
return retval;
}
static bool CheckSameData( symbol *sym, comdat_info *info )
/*********************************************************/
{
virt_mem temp;
char * data;
comdat_piece * piece;
temp = sym->p.seg->data;
if( sym->mod->modinfo & MOD_DONE_PASS_1 ) {
piece = RingLookup( info->pieces, CheckVMemPieceDiff, &temp );
} else {
data = GetSegContents( sym->p.seg, temp );
piece = RingLookup( info->pieces, CheckMemPieceDiff, &data );
}
if( piece == NULL ) { // found a match
info->sym->u.datasym = sym;
return TRUE;
}
return FALSE;
}
static bool CheckAltSym( void *_sym, void *_info )
/************************************************/
{
comdat_info *info = _info;
symbol *sym = _sym;
if( sym != info->sym && IS_SYM_COMDAT(sym) && sym->info & SYM_HAS_DATA ) {
return CheckSameData( sym, info );
}
return FALSE;
}
extern void InfoCDatAltDef( comdat_info *info )
/*********************************************/
{
symbol * mainsym;
mainsym = info->sym;
info->sym = AddAltDef( mainsym, SYM_COMDAT );
info->sym->p.seg = info->sdata;
info->sym->info |= info->flags & SYM_CDAT_SEL_MASK;
if( !CheckSameData( mainsym, info ) ) {
mainsym = RingLookup( mainsym->u.altdefs, CheckAltSym, info );
if( mainsym == NULL ) {
StoreInfoData( info );
info->sym->info |= SYM_HAS_DATA;
}
}
}
static void AddCDatAltDef( segdata *sdata, symbol *sym, char *data,
sym_info flags )
/*****************************************************************/
{
comdat_info info;
comdat_piece piece;
if( LinkFlags & INC_LINK_FLAG ) {
info.sdata = sdata;
info.sym = sym;
info.flags = flags;
info.pieces = NULL;
piece.data = data;
piece.length = sdata->length;
piece.free_data = FALSE;
RingAppend( &info.pieces, &piece );
InfoCDatAltDef( &info );
}
}
static void DoIncSymbol( void *_sym )
/***********************************/
{
symbol * sym = _sym;
symbol * mainsym;
void * data;
sym_flags flags;
if( sym->info & SYM_IS_ALTDEF ) {
flags = ST_CREATE | ST_REFERENCE;
if( sym->info & SYM_STATIC ) {
flags |= ST_STATIC;
}
mainsym = SymOp( flags, sym->name, strlen(sym->name) );
if( IS_SYM_NICOMDEF(sym) ) {
MakeCommunalSym( mainsym, sym->p.cdefsize,
(sym->info & SYM_FAR_COMMUNAL) != 0,
IS_SYM_COMM32(sym) );
} else if( IS_SYM_COMDAT(sym) ) {
if( sym->info & SYM_HAS_DATA ) {
data = GetAltdefContents( sym->p.seg );
} else {
data = GetSegContents( sym->p.seg, sym->p.seg->data );
}
sym->p.seg->isdead = FALSE;
DefineComdat( sym->p.seg, mainsym, sym->addr.off,
sym->info & SYM_CDAT_SEL_MASK, data );
} else if( !(mainsym->info & SYM_DEFINED) ) {
DoSavedImport( sym ); // FIXME can lose defs here.
}
CarveFree( CarveSymbol, sym );
} else {
if( !IS_SYM_COMDAT(sym) ) {
Ring2Append( &CurrMod->publist, sym );
}
if( sym->info & SYM_DEAD ) return;
if( IS_SYM_IMPORTED(sym) ) {
DoSavedImport( sym );
} else if( IS_SYM_COMDAT(sym) ) {
DefineComdat( sym->p.seg, sym, sym->addr.off,
sym->info & SYM_CDAT_SEL_MASK,
GetSegContents(sym->p.seg, sym->p.seg->data) );
}
if( sym->info & SYM_EXPORTED ) {
DoSavedExport( sym );
}
}
}
extern unsigned long IncPass1( void )
/***********************************/
{
segdata * seglist;
segdata * seg;
symbol * publist;
virt_mem dataoff;
unsigned relocs;
seglist = CurrMod->segs;
CurrMod->segs = NULL;
CurrMod->lines = NULL;
for(;;) {
seg = Ring2Pop( &seglist );
if( seg == NULL ) break;
dataoff = seg->data;
DoAllocateSegment( seg, seg->o.clname );
seg->o.mod = CurrMod;
if( !seg->isuninit && !seg->isdead && !seg->iscdat ) {
PutInfo( seg->data, GetSegContents(seg, dataoff), seg->length );
seg->u.leader->info |= SEG_LXDATA_SEEN;
}
}
publist = CurrMod->publist;
CurrMod->publist = NULL;
Ring2Walk( publist, DoIncSymbol );
relocs = CurrMod->relocs;
PermStartMod( CurrMod ); // destroys currmod->relocs
IterateModRelocs( relocs, CurrMod->sizerelocs, IncSaveRelocs );
return 0;
}
static class_entry * FindNamedClass( char *name )
/***********************************************/
// NYI: this doesn't take into account 16 & 32 bit classes with the same name.
{
class_entry * class;
for( class = Root->classlist; class != NULL; class = class->next_class ) {
if( stricmp( class->name, name ) == 0 ) return class;
}
return NULL;
}
static bool CmpSegName( void *leader, void *name )
/************************************************/
{
return stricmp( ((seg_leader *)leader)->segname, name ) == 0;
}
static bool DefIncGroup( void *_def, void *_grouptab )
/****************************************************/
{
incgroupdef * def = _def;
group_entry *** grouptab = _grouptab;
group_entry * group;
unsigned index;
char ** currname;
class_entry * class;
seg_leader * leader;
group = GetGroup( def->names[0] );
currname = &def->names[1];
for( index = 0; index < def->numsegs; index++ ) {
class = FindNamedClass( *currname );
currname++;
if( class != NULL ) {
leader = RingLookup( class->segs, CmpSegName, *currname );
if( leader != NULL ) {
AddToGroup( group, leader );
}
}
currname++;
}
**grouptab = group;
(*grouptab)++;
return FALSE;
}
extern void DoIncGroupDefs( void )
/********************************/
{
unsigned numgroups;
group_entry ** grouptab;
numgroups = RingCount( IncGroupDefs );
_ChkAlloc( IncGroups, sizeof(group_entry *) * numgroups );
grouptab = IncGroups;
RingLookup( IncGroupDefs, DefIncGroup, &grouptab );
RingFree( &IncGroupDefs );
IncGroupDefs = NULL;
}
extern void Set32BitMode( void )
/******************************/
// make sure that the executable format is a 386 format.
{
LinkState |= FMT_SEEN_32_BIT;
if( !HintFormat( MK_ALLOW_32 ) ) {
if( !(ObjFormat & FMT_TOLD_XXBIT) ) {
ObjFormat |= FMT_TOLD_XXBIT;
LnkMsg( WRN+MSG_FOUND_XXBIT_OBJ, "sd",
CurrMod->f.source->file->name, 32 );
}
}
}
extern void Set16BitMode( void )
/******************************/
{
if( !HintFormat( MK_ALLOW_16 ) ) {
if( !(ObjFormat & FMT_TOLD_XXBIT) ) {
ObjFormat |= FMT_TOLD_XXBIT;
LnkMsg( WRN+MSG_FOUND_XXBIT_OBJ, "sd",
CurrMod->f.source->file->name, 16 );
}
}
}
extern void AllocateSegment( segnode *newseg, char *clname )
/**********************************************************/
// allocate a new segment (or new piece of a segment)
{
DoAllocateSegment( newseg->entry, clname );
newseg->info = newseg->entry->u.leader->info;
}
static void DoAllocateSegment( segdata *sdata, char *clname )
/***********************************************************/
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?