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 + -
显示快捷键?