symomf.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 479 行

C
479
字号
/****************************************************************************
*
*                            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:  Librarian OMF symbol processing.
*
****************************************************************************/


#include <wlib.h>

static unsigned short CurrSegRef = 0;
static char                     Rec32Bit;

struct lname {
    struct lname        *next;
    char                local;
    char                len;
    char                name[1];
};

typedef struct COMMON_BLK {
    struct COMMON_BLK       *next;
    unsigned short          segindex;
}   common_blk;


typedef enum {
    S_COMDEF,
    S_COMDAT,
    S_PUBDEF
} sym_type;

static void procsegdef (void);
static void getpubdef (void);
static void GetComent (sym_file *sfile);
static void getcomdef (void);
static void getcomdat (void);
static void getlname (int local);
static void FreeCommonBlk (void);
static void FreeLNames (void);
static int IsCommonRef (void);

static struct lname     *LName_Head;
static struct lname     **LName_Owner;
static char             Typ;
static unsigned short   Len, MaxLen;
static char *           CurrRec;
static char *           RecPtr;
static common_blk *     CurrCommonBlk;
static unsigned short   SegDefCount;
static bool             EasyOMF;
static char             NameBuff[257];

static bool GetLen( libfile io )
{
    char        ch1, ch2;

    if( LibRead( io, &ch1, sizeof( ch1 ) ) != sizeof( ch1 ) ) return( FALSE );
    if( LibRead( io, &ch2, sizeof( ch2 ) ) != sizeof( ch1 ) ) return( FALSE );
    Len = ( ( unsigned ) ch2 << 8 ) + ch1;
    return( TRUE );
}

bool GetRec( libfile io )
/***********************/
{
    if( LibRead( io, &Typ, sizeof( Typ ) ) != sizeof( Typ ) ) return( FALSE );
    if( !GetLen( io ) ) return( FALSE );
    if( Len > MaxLen ) {
        MemFree( CurrRec );
        CurrRec = MemAlloc( Len );
        MaxLen = Len;
    }
    if( LibRead( io, CurrRec, Len ) != Len ) return( FALSE );
    RecPtr = CurrRec;
    /* check to see if this is an Easy OMF-386 object file */
    /* Only need to check the first comment record */
    if( ( Typ & ~1 ) == CMD_COMENT  &&  Len == 8  &&
        memcmp( CurrRec, "\x80\xAA" "80386", 7 ) == 0 ) {
        EasyOMF = TRUE;
    }
    return( TRUE );
}


void OMFWalkSymList( obj_file *ofile, sym_file *sfile, void (*rtn)(char*name,symbol_strength,unsigned char) )
{
    EasyOMF = FALSE;
    SegDefCount = 0;    // just for FORTRAN 77 common block
    CurrSegRef = 0;
    LName_Head = NULL;
    LName_Owner = &LName_Head;

    do {
        if( !GetRec( ofile->hdl ) ) {
            FatalError( ERR_BAD_OBJECT, ofile->hdl->name );
        }

        if( Typ & 1 ) {
            Rec32Bit = TRUE;
        } else {
            Rec32Bit = EasyOMF;
        }

        if (sfile)
        {
            switch (Typ)
            {
                case CMD_SEGDEF:
                case CMD_SEGD32:
                    procsegdef();
                    break;
                case CMD_PUBDEF:
                case CMD_PUBD32:
                    getpubdef();
                    break;
                case CMD_COMENT:
                    GetComent( sfile );
                    break;
                case CMD_COMDEF:
                    getcomdef();
                    break;
                case CMD_COMDAT:
                case CMD_COMD32:
                    getcomdat();
                    break;
                case CMD_LNAMES:
                    getlname( FALSE );
                    break;
                case CMD_LLNAME:
                    getlname( TRUE );
                    break;
            } /* switch */
        } /* if */
    } while( Typ != CMD_MODEND && Typ != CMD_MODE32 );

    if (sfile)
    {
        FreeCommonBlk();
        FreeLNames();
        MemFree( CurrRec );
        CurrRec = NULL;
        Len = MaxLen = 0;
        sfile->arch.size = LibTell( ofile->hdl ) - sfile->inlib_offset;
    }
}


void OMFLibWalk( libfile io, char *name, void (*rtn)( arch_header *arch, libfile io ) )
{
    long                pagelen, offset, end_offset;
    arch_header         arch;
    char                buff[MAX_IMPORT_STRING];
    int                 len;

    if( LibRead( io, &Typ, sizeof( Typ ) ) != sizeof( Typ ) ) return; // nyi - FALSE?
    if( !GetLen( io ) ) return;
    pagelen = Len + sizeof( Typ ) + sizeof( Len );
    if( Options.page_size == 0 ) {
        Options.page_size = pagelen;
    }
    LibSeek( io, Len, SEEK_CUR );
    NewArchHeader( &arch, name );
    CurrRec = NULL;
    for( ;; ) {
        offset = LibTell( io );
        if( !GetRec( io ) ) break;
        if( Typ != CMD_THEADR ) break;
        len = *RecPtr++;
        memcpy( buff, RecPtr, len );
        buff[len] = '\0';
        arch.name = buff;
        LibSeek( io, offset, SEEK_SET );
        rtn( &arch, io );
        end_offset = LibTell( io );
        if( end_offset == offset ) {
            do {
                if( LibRead( io, &Typ, sizeof( Typ ) ) != sizeof( Typ ) ) {
                    FatalError( ERR_BAD_OBJECT, io->name );
                }
                if( LibRead( io, &Len, sizeof( Len ) ) != sizeof( Len ) ) {
                    FatalError( ERR_BAD_OBJECT, io->name );
                }
                LibSeek( io, Len, SEEK_CUR );
            } while( Typ != CMD_MODEND && Typ != CMD_MODE32 );
        }
        offset = pagelen - end_offset % pagelen;
        if( offset == pagelen ) offset = 0;
        LibSeek( io, offset, SEEK_CUR );
        if( LibRead( io, &Typ, sizeof( Typ ) ) != sizeof( Typ ) ) break;
        if( Typ == LIB_TRAILER_REC ) break;
        LibSeek( io, -1, SEEK_CUR );
    }
    MemFree( CurrRec );
    Len = MaxLen = 0;
    CurrRec = NULL;
}



static void AddOMFSymbol( sym_type type )
{
    if( type == S_COMDEF || type == S_COMDAT || IsCommonRef() ) {
        AddSym( NameBuff, SYM_WEAK, 0 );
    } else {
        AddSym( NameBuff, SYM_STRONG, 0 );
    }
}

static unsigned short GetIndex( void )
/************************************/
{
    unsigned short index;

    index = *RecPtr++;
    if( index > 0x7F ) {
        index &= 0x7f;
        index = (index << 8) | *RecPtr++;
    }
    return( index );
}


static void GetOffset( void )
/***************************/
{
    RecPtr += 2;
    if( Rec32Bit ) { /* if 386, must skip over 4 bytes */
        RecPtr += 2;
    }
}

/*
 * throw away a group and segment number and possibly frame number
 */
static void GetIdx( void )
/************************/
{
    register unsigned short         grp;

    grp = GetIndex();
    CurrSegRef = GetIndex();
    if( ( grp == 0 ) && ( CurrSegRef == 0 ) ) {
        RecPtr += 2;                    /* skip over frame number */
    }
}

static int IsCommonRef( void )      /* dedicated routine for FORTRAN 77 common block */
/****************************/
{
    common_blk * tmpblk = CurrCommonBlk;

    while( tmpblk != NULL  &&  tmpblk->segindex <= CurrSegRef ) {
        if( tmpblk->segindex == CurrSegRef ) {
            return( TRUE );
        }
        tmpblk = tmpblk->next;
    }
    return( FALSE );
}

static void FreeCommonBlk( void )   /* dedicated routine for FORTRAN 77 common block */
/*******************************/
{
    common_blk *    tmpblk;

    while( CurrCommonBlk != NULL ) {
        tmpblk = CurrCommonBlk->next;
        MemFree( CurrCommonBlk );
        CurrCommonBlk = tmpblk;
    }
}

static void procsegdef( void )      /* dedicated routine for FORTRAN 77 common block */
/****************************/
{
    common_blk   *      cmn;
    common_blk  **      owner;

    uint_8  tmpbyte = ( *RecPtr & 0x1f ) >> 2; /* get "COMBINE" bits */

    SegDefCount++;
    if( tmpbyte == 6 ) {    /* COMBINE == COMMON, record it */

        owner = &CurrCommonBlk;

        for( ;; ) {
            cmn = *owner;
            if( cmn == NULL ) break;
            owner = &cmn->next;
        }
        cmn = MemAlloc( sizeof( common_blk ) );
        cmn->segindex = SegDefCount;
        cmn->next = NULL;
        *owner = cmn;
    }
}


/*
 * from infl, get a intel name: length and name
 */
void GetName( void )
{
    int        num_char;

    num_char = (int)*RecPtr++;
    memcpy( NameBuff, RecPtr, num_char );
    RecPtr += num_char;
    NameBuff[ num_char ] = '\0';
}
/*
 * loop over the publics in the record
 */
static void getpubdef( void )
{
    GetIdx();
    while( (int)( RecPtr - CurrRec ) < ( Len - 1 ) ) {
        GetName();
        GetOffset();
        GetIndex();
        AddOMFSymbol( S_PUBDEF );
    }
}

/*
 * get the public definition out of the coment record
 */

static void GetComent( sym_file *sfile )
{
    RecPtr++;   // skip attribute byte of comment rec
    switch( *RecPtr++ ){
    case CMT_DLL_ENTRY:
        if( *RecPtr++ == DLL_IMPDEF ){
            RecPtr++;       // skip the ordinal flag
            GetName();
            AddOMFSymbol( S_PUBDEF );
        }
        break;
    case CMT_LINKER_DIRECTIVE:
        if( *RecPtr++ == LDIR_OBJ_TIMESTAMP ) {
            sfile->arch.date = *(unsigned_32 *)RecPtr;
        }
        break;
    }
}

static void GetComLen( void )
{
    switch( *RecPtr++ ) {
    case COMDEF_LEAF_4:
        RecPtr += 4;
        break;
    case COMDEF_LEAF_3:
        RecPtr += 3;
        break;
    case COMDEF_LEAF_2:
        RecPtr += 2;
        break;
    default:
        break;
    }
}

/*
 * process a COMDEF record
 */
static void getcomdef( void )
{
    while( (int)( RecPtr - CurrRec ) < ( Len - 1 ) ) {
        GetName();
        AddOMFSymbol( S_COMDEF );
        GetIndex();
        switch( *RecPtr++ ) {
        case COMDEF_FAR:
            GetComLen();
            /* fall through */
        case COMDEF_NEAR:
            GetComLen();
            break;
        }
    }
}

/*
 * process a COMDAT record
 */
static void getcomdat( void )
{
    unsigned            alloc;
    unsigned            idx;
    struct lname                *ln;

    if( *RecPtr & (COMDAT_CONTINUE|COMDAT_LOCAL) ) return;
    RecPtr++;
    alloc = *RecPtr++ & COMDAT_ALLOC_MASK;
    RecPtr++;
    GetOffset();
    GetIndex();
    if( alloc == COMDAT_EXPLICIT ) {
        GetIdx();
    }
    idx = GetIndex() - 1;
    for( ln = LName_Head; idx != 0; --idx, ln = ln->next ) {
        /* nothing to do */
    }
    if( ln->local ) return;
    memcpy( NameBuff, ln->name, ln->len );
    NameBuff[ (int)ln->len ] = '\0';
    AddOMFSymbol( S_COMDAT );
}

static void     getlname( int local )
{
    unsigned    len;
    struct lname        *ln;

    while( (int)( RecPtr - CurrRec ) < ( Len - 1 ) ) {
        len = *RecPtr++;
        ln = MemAlloc( (sizeof( struct lname ) - 1) + len );
        ln->local = local;
        ln->len = len;
        memcpy( ln->name, RecPtr, len );
        ln->next = NULL;
        *LName_Owner = ln;
        LName_Owner = &ln->next;
        RecPtr += len;
    }
}

static void FreeLNames( void )
{
    struct lname        *next;

    while( LName_Head != NULL ) {
        next = LName_Head->next;
        MemFree( LName_Head );
        LName_Head = next;
    }
}


/*
 * Skip to the end of the current object -- used in the code to delete
 * omf objects.
 */
void OMFSkipThisObject(arch_header *arch, libfile io)
{
    obj_file *file;

    file = OpenLibFile(arch->name, io);
    OMFWalkSymList(file, NULL, NULL);
    CloseLibFile(file);
} /* OMFSkipThisObject() */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?