expld.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,081 行 · 第 1/3 页

C
1,081
字号
/****************************************************************************
*
*                            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:  Export DIP Loading/unloading of symbolic information.
*
****************************************************************************/


#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include "walloca.h"
#include "exp.h"
#include "exedos.h"
#include "exeos2.h"
#include "exeflat.h"
#include "exepe.h"
#include "exenov.h"
#include "exeelf.h"

#if defined( __WATCOMC__ ) && defined( __386__ )

/* WD looks for this symbol to determine module bitness */
int __nullarea;
#pragma aux __nullarea "*";

#endif

typedef union {
        dos_exe_header  mz;
        os2_exe_header  ne;
        os2_flat_header lx;
        pe_header       pe;
} any_header;


static struct {
    unsigned long       fpos;
    unsigned            len;
    unsigned            off;
    unsigned_8          data[256];
} Buff;

unsigned long BSeek( dig_fhandle h, unsigned long p, dig_seek w )
{
    unsigned long       bpos;
    unsigned long       npos;

    bpos = Buff.fpos - Buff.len;
    switch( w ) {
    case DIG_END:
        return( -1UL ); /* unsupported */
    case DIG_CUR:
        npos = bpos + p + Buff.off;
        break;
    case DIG_ORG:
        npos = p;
        break;
    }
    if( npos >= bpos && npos < (bpos+Buff.len) ) {
        Buff.off = npos - bpos;
        return( npos );
    }
    Buff.fpos = DCSeek( h, npos, DIG_ORG );
    Buff.off = 0;
    Buff.len = 0;
    return( Buff.fpos );
}

unsigned BRead( dig_fhandle h, void *b, unsigned s )
{
    unsigned    got;
    unsigned    want;

    if( s > sizeof( Buff.data ) ) {
        Buff.fpos = DCSeek( h, (int)Buff.fpos + (int)Buff.off - (int)Buff.len, DIG_ORG );
        Buff.len = 0;
        Buff.off = 0;
        if( Buff.fpos == -1UL ) return( 0 );
        got = DCRead( h, b, s );
        Buff.fpos += got;
        return( got );
    }
    want = s;
    got = Buff.len - Buff.off;
    if( got > want ) got = want;
    memcpy( b, &Buff.data[Buff.off], got );
    Buff.off += got;
    want -= got;
    if( want > 0 ) {
        Buff.len = DCRead( h, &Buff.data[0], sizeof( Buff.data ) );
        if( Buff.len == (unsigned)-1 ) {
            Buff.fpos = -1UL;
            Buff.off = 0;
            Buff.len = 0;
            return( (unsigned)-1 );
        }
        Buff.fpos += Buff.len;
        b = (unsigned_8 *)b + got;
        memcpy( b, &Buff.data[0], want );
        Buff.off = want;
    }
    return( s );
}

#define ROUND_UP( d, r ) (((d)+(r)-1) & ~((r)-1))

static void *HunkAlloc( imp_image_handle *ii, unsigned size )
{
    exp_hunk    *hunk;
    unsigned    alloc;

    size = ROUND_UP( size, sizeof( void * ) );
    hunk = ii->hunks;
    if( hunk == NULL || size > hunk->left ) {
        alloc = max( HUNK_SIZE, size );
        hunk = DCAlloc( (sizeof( *hunk ) - HUNK_SIZE) + alloc );
        if( hunk == NULL ) return( NULL );
        hunk->next = ii->hunks;
        ii->hunks = hunk;
        hunk->left = alloc;
    }
    hunk->left -= size;
    return( &hunk->data[ hunk->left ] );
}

static void ImpUnloadInfo( imp_image_handle *ii )
{
    exp_hunk    *curr;
    exp_hunk    *next;

    for( curr = ii->hunks; curr != NULL; curr = next ) {
        next = curr->next;
        DCFree( curr );
    }
    ii->hunks = NULL;
}

exp_block       *FindAddrBlock( imp_image_handle *ii, addr_ptr addr )
{
    exp_block   *b;

    for( b = ii->addr; b != NULL; b = b->next ) {
        if( SameAddrSpace( b->start, addr )
          && b->start.offset <= addr.offset
          && (b->start.offset+b->len) > addr.offset ) {
            return( b );
        }
    }
    return( NULL );
}

static dip_status AddName( imp_image_handle *ii, unsigned len, char *name )
{
    char        *start;
    char        *end;

    end = NULL;
    start = name;
    for( ;; ) {
        if( len == 0 ) break;
        switch( *name ) {
        case ':':
        case '\\':
        case '/':
            start = name + 1;
            end = NULL;
            break;
        case '.':
            end = name;
            break;
        }
        ++name;
        --len;
    }
    if( end == NULL ) end = name;
    ii->len = end - start;
    ii->name = HunkAlloc( ii, ii->len );
    if( ii->name == NULL ) return( DS_ERR|DS_NO_MEM );
    memcpy( ii->name, start, ii->len );
    return( DS_OK );
}

static dip_status AddBlock( imp_image_handle *ii, addr_seg seg, addr_off off,
                        unsigned_32 len, unsigned_8 code )
{
    exp_block   *new;

    new = HunkAlloc( ii, sizeof( *new ) );
    if( new == NULL ) return( DS_ERR|DS_NO_MEM );
    new->start.segment = seg;
    new->start.offset = off;
    new->len = len;
    new->code = code;
    new->next = ii->addr;
    ii->addr = new;
    return( DS_OK );
}

static dip_status AddSymbol( imp_image_handle *ii, addr_seg seg, addr_off off,
                        unsigned len, char *name )
{
    exp_sym     *new;

    new = HunkAlloc( ii, (sizeof( *new ) - 1) + len );
    if( new == NULL ) return( DS_ERR|DS_NO_MEM );
    new->addr.segment = seg;
    new->addr.offset = off;
    new->len = len;
    memcpy( new->name, name, len );
    new->next = ii->gbl;
    ii->gbl = new;
    return( DS_OK );
}

static dip_status ProcTable( dig_fhandle h, imp_image_handle *ii,
                        unsigned resident )
{
    unsigned_8  len;
    char        buff[256+sizeof(unsigned_16)];
    unsigned    first;
    unsigned    ord;
    dip_status  ds;

    first = 1;
    for( ;; ) {
        if( BRead( h, &len, sizeof( len ) ) != sizeof( len ) ) {
            return( DS_ERR|DS_FREAD_FAILED );
        }
        if( len == 0 ) break;
        if( BRead( h, buff, len + 2 ) != len + 2 ) {
            return( DS_ERR|DS_FREAD_FAILED );
        }
        ord = *(unsigned_16 *)&buff[len];
        if( resident && first ) {
            first = 0;
            ds = AddName( ii, len, buff );
            if( ds != DS_OK ) return( ds );
        } else if( ord != 0 ) {
            /* this is putting in entry number, we'll get real addr later */
            ds = AddSymbol( ii, 0, ord, len, buff );
            if( ds != DS_OK ) return( ds );
        }
    }
    return( DS_OK );
}

static dip_status TryNE( dig_fhandle h, imp_image_handle *ii,
                        any_header *head, unsigned_32 off )
{
    segment_record      seg;
    dip_status          ds;
    unsigned            ord;
    bundle_prefix       pref;
    union {
        movable_record  mov;
        fixed_record    fix;
    }                   entry;
    unsigned            i;
    exp_sym             *s;

    if( BSeek( h, off + head->ne.segment_off, DIG_ORG ) != off + head->ne.segment_off ) {
        return( DS_ERR|DS_FSEEK_FAILED );
    }
    for( i = 0; i < head->ne.segments; ++i ) {
        if( BRead( h, &seg, sizeof( seg ) ) != sizeof( seg ) ) {
            return( DS_ERR|DS_FREAD_FAILED );
        }
        ds = AddBlock( ii, i + 1, 0, seg.size == 0 ? 0x10000 : seg.size,
                        !(seg.info & SEG_DATA) );
        if( ds != DS_OK ) return( ds );
    }
    if( BSeek( h, off + head->ne.resident_off, DIG_ORG ) != off + head->ne.resident_off ) {
        return( DS_ERR|DS_FSEEK_FAILED );
    }
    ds = ProcTable( h, ii, 1 );
    if( ds != DS_OK ) return( ds );
    if( head->ne.nonres_size != 0 ) {
        if( BSeek( h, head->ne.nonres_off, DIG_ORG ) != head->ne.nonres_off ) {
            return( DS_ERR|DS_FSEEK_FAILED );
        }
        ds = ProcTable( h, ii, 0 );
        if( ds != DS_OK ) return( ds );
    }
    /* change all the symbol addresses from entry numbers to seg/offsets */
    if( BSeek( h, off + head->ne.entry_off, DIG_ORG ) != off + head->ne.entry_off ) {
        return( DS_ERR|DS_FSEEK_FAILED );
    }
    ord = 1;
    for( ;; ) {
        if( BRead( h, &pref, sizeof( pref ) ) != sizeof( pref ) ) {
            return( DS_ERR|DS_FREAD_FAILED );
        }
        if( pref.number == 0 ) break;
        if( pref.type == 0 ) {
            ord += pref.number;
        } else {
            for( i = 0; i < pref.number; ++i ) {
                if( pref.type == MOVABLE_ENTRY_PNT ) {
                    if( BRead( h, &entry.mov, sizeof( entry.mov ) ) != sizeof( entry.mov ) ) {
                        return( DS_ERR|DS_FREAD_FAILED );
                    }
                } else {
                    if( BRead( h, &entry.fix, sizeof( entry.fix ) ) != sizeof( entry.fix ) ) {
                        return( DS_ERR|DS_FREAD_FAILED );
                    }
                    entry.mov.entry = entry.fix.entry;
                    entry.mov.entrynum = pref.type;
                }
                if( entry.mov.info & ENTRY_EXPORTED ) {
                    s = ii->gbl;
                    for( ;; ) {
                        if( s == NULL ) break;
                        if( s->addr.segment == 0 && s->addr.offset == ord ) {
                            s->addr.segment = entry.mov.entrynum;
                            s->addr.offset = entry.mov.entry;
                            break;
                        }
                        s = s->next;
                    }
                }
                ++ord;
            }
        }
    }
    return( DS_OK );
}

static dip_status TryLX( dig_fhandle h, imp_image_handle *ii,
                        any_header *head, unsigned_32 off )
{
    object_record       seg;
    dip_status          ds;
    unsigned            ord;
    flat_bundle_prefix  pref;
    union {
        flat_bundle_entry32     e32;
        flat_bundle_entry16     e16;

⌨️ 快捷键说明

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