loadpe.c

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

C
1,456
字号
/****************************************************************************
*
*                            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:  Utilities for creation of PE (Win32) executable files.
*
****************************************************************************/


#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
#include "linkstd.h"
#include "exeos2.h"
#include "loados2.h"
#include "exepe.h"
#include "reloc.h"
#include "specials.h"
#include "alloc.h"
#include "pcobj.h"
#include "msg.h"
#include "wlnkmsg.h"
#include "virtmem.h"
#include "objnode.h"
#include "loadfile.h"
#include "objcalc.h"
#include "fileio.h"
#include "dbgcv.h"
#include "dbgall.h"
#include "objpass1.h"
#include "ring.h"
#include "strtab.h"
#include "carve.h"
#include "permdata.h"
#include "loadpe.h"
#include "reserr.h"
#include "wres.h"
#include "exerespe.h"
#include "param.h"
#include "pass2.h"
#include "sharedio.h"
#include "impexp.h"
#include "toc.h"
#include "objstrip.h"

#define I386_TRANSFER_OP1       0xff    /* first byte of a "JMP [FOO]" */
#define I386_TRANSFER_OP2       0x25    /* second byte of a "JMP [FOO]" */

#define MINIMUM_SEG_SHIFT       2       /* Corresponds to 2^2 == 4 bytes */
#define DEFAULT_SEG_SHIFT       9       /* Corresponds to 2^9 == 512 bytes */

#pragma pack(1);

typedef struct {
    unsigned_8  op1;
    unsigned_8  op2;
    unsigned_32 dest;
} i386_transfer;

static i386_transfer    I386Jump = { I386_TRANSFER_OP1, I386_TRANSFER_OP2, 0 };

#define I386_TRANSFER_SIZE (sizeof(i386_transfer))

#define ALPHA_TRANSFER_OP1      0x277F
#define ALPHA_TRANSFER_OP2      0xA37B
#define ALPHA_TRANSFER_OP3      0x6BFB

typedef struct {
    unsigned_16 high;
    unsigned_16 op1;
    unsigned_16 low;
    unsigned_16 op2;
    unsigned_16 zero;
    unsigned_16 op3;
} alpha_transfer;

#pragma pack();

static alpha_transfer   AlphaJump = {   0, ALPHA_TRANSFER_OP1,
                                        0, ALPHA_TRANSFER_OP2,
                                        0, ALPHA_TRANSFER_OP3 };

#define ALPHA_TRANSFER_SIZE (sizeof(alpha_transfer))

static unsigned_32 PPCJump[]= {
    0x81620000,         //   lwz        r11,[tocv]__imp_RtlMoveMemory(rtoc)
    0x818B0000,         //   lwz        r12,(r11)
    0x90410004,         //   stw        rtoc,0x4(sp)
    0x7D8903A6,         //   mtctr      r12
    0x804B0004,         //   lwz        rtoc,0x4(r11)
    0x4E800420          //   bctr
};

#define PPC_TRANSFER_SIZE (sizeof PPCJump)

#define TRANSFER_SEGNAME "TRANSFER CODE"

static module_import *  PEImpList;
static unsigned         NumMods;
static segdata *        XFerSegData;

static void             RegisterImport( dll_sym_info *sym );

static struct {
    offset      ilt_off;
    offset      eof_ilt_off;
    offset      iat_off;
    offset      mod_name_off;
    offset      hint_off;
    offset      total_size;
    segdata *   sdata;
} IData;

#define WALK_IMPORT_SYMBOLS(sym) \
    for( (sym) = HeadSym; (sym) != NULL; (sym) = (sym)->link ) \
        if( IS_SYM_IMPORTED(sym) && (sym)->p.import != NULL \
            /*&& !((sym)->info & SYM_DEAD)*/)

static offset CalcIDataSize( void )
/*******************************/
{
    struct module_import *      mod;
    struct import_name *        imp;
    unsigned_32 iatsize;
    unsigned_32 size;

    iatsize = (NumImports+NumMods) * sizeof( pe_va );
    if( (0 == iatsize) && ( LinkFlags & STRIP_CODE ) ) {
        return( 0 );
    }
    IData.ilt_off = (NumMods + 1) * sizeof( pe_import_directory );
    IData.eof_ilt_off = IData.ilt_off + iatsize;
    IData.iat_off = IData.eof_ilt_off + TocSize;
    IData.mod_name_off = IData.iat_off + iatsize;
    size = 0;
    for( mod = PEImpList; mod != NULL; mod = mod->next ) {
        size += mod->mod->len + 1;
    }
    IData.hint_off = IData.mod_name_off + size;
    size = IData.hint_off;
    for( mod = PEImpList; mod != NULL; mod = mod->next ) {
        for( imp = mod->imports; imp != NULL; imp = imp->next ) {
            if( imp->imp != NULL ) {
                size += (size & 1); /* round up */
                size += imp->imp->len +
                        (sizeof( unsigned_16 ) + sizeof( unsigned_8 ));
            }
        }
    }
    IData.total_size = size;
    return( IData.total_size );
}

extern void ResetLoadPE( void )
/*****************************/
{
    PEImpList = NULL;
    XFerSegData = NULL;
    NumMods = 0;
    NumImports = 0;
    memset(&IData, 0, sizeof IData);
}

static offset CalcIATAbsOffset( void )
/************************************/
{
    return( IDataGroup->linear + FmtData.base + IData.iat_off );
}

static void CalcImpOff( dll_sym_info *dll, unsigned *off )
/********************************************************/
{
    if( dll != NULL) { // if not end of mod marker
        dll->iatsym->addr.off = *off;
        dll->iatsym->addr.seg = 0;
    }
    *off += 4;
}

static void XFerReloc( offset off, group_entry *group, unsigned type )
/********************************************************************/
{
    reloc_item  reloc;
    size_t      size;

    size = sizeof(pe_reloc_item);
    reloc.pe = ((off + group->linear) & OSF_PAGE_MASK) | type;
    if( type == PE_FIX_HIGHADJ ) {
        size = sizeof( high_pe_reloc_item );
        reloc.hpe.low_off = AlphaJump.low;
    }
    WriteReloc( group, off, &reloc, size );
}

static int GetTransferGlueSize( int lnk_state )
/*********************************************/
{
    switch( lnk_state & HAVE_MACHTYPE_MASK ) {
    case HAVE_ALPHA_CODE:   return( ALPHA_TRANSFER_SIZE );
    case HAVE_I86_CODE:     return( I386_TRANSFER_SIZE );
    case HAVE_PPC_CODE:     return( PPC_TRANSFER_SIZE );
    default:                DbgAssert( 0 ); return( 0 );
    }
}

static void * GetTransferGlueCode( int lnk_state )
/************************************************/
{
    switch( lnk_state & HAVE_MACHTYPE_MASK ) {
    case HAVE_ALPHA_CODE:   return( &AlphaJump );
    case HAVE_I86_CODE:     return( &I386Jump );
    case HAVE_PPC_CODE:     return( &PPCJump );
    default:                DbgAssert( 0 ); return( NULL );
    }
}

extern offset FindIATSymAbsOff( symbol * sym )
/********************************************/
{
    dll_sym_info *      dll;

    dll = sym->p.import;
    DbgAssert( IS_SYM_IMPORTED(sym) && dll != NULL );
    return( dll->iatsym->addr.off );
}

extern signed_32 FindSymPosInTocv( symbol * sym )
/***********************************************/
{
    offset off = FindIATSymAbsOff(sym) - IDataGroup->linear - FmtData.base;
    off = off - TocShift - IData.eof_ilt_off;
    return( off );
}

static void GenPETransferTable( void )
/************************************/
{
    offset      off;
    offset      base;
    symbol *    sym;
    void*       data;
    size_t      datalen;
    group_entry *group;

    if( IDataGroup == NULL ) return;
    if( XFerSegData == NULL ) return;
    group = XFerSegData->u.leader->group;
    base = XFerSegData->u.leader->seg_addr.off + XFerSegData->a.delta;
    datalen = GetTransferGlueSize( LinkState );
    data = GetTransferGlueCode( LinkState );
    WALK_IMPORT_SYMBOLS(sym) {
        if( LinkState & HAVE_ALPHA_CODE ) {
            offset dest = FindIATSymAbsOff( sym );
            AlphaJump.high = dest >> 16;
            AlphaJump.low = dest;
            if( LinkState & MAKE_RELOCS ) {
                if( !(FmtData.objalign & 0xFFFF) ) {
                    XFerReloc( sym->addr.off+offsetof(alpha_transfer, high),
                               group, PE_FIX_HIGH );
                } else {
                    XFerReloc( sym->addr.off+offsetof(alpha_transfer, low),
                               group, PE_FIX_LOW );
                    XFerReloc( sym->addr.off+offsetof(alpha_transfer, high),
                                group, PE_FIX_HIGHADJ );
                }
            }
        } else if( LinkState & HAVE_I86_CODE ) {
            offset dest = FindIATSymAbsOff( sym );
            I386Jump.dest = dest;
            if( LinkState & MAKE_RELOCS ) {
                XFerReloc( sym->addr.off + offsetof(i386_transfer,dest),
                            group, PE_FIX_HIGHLOW );
            }
        } else {
            int_16 pos;
            pos = FindSymPosInTocv(sym);
            PPCJump[0] &= 0xffff0000;
            PPCJump[0] |= 0x0000ffff & pos;
        }
        off = sym->addr.off - base;
        PutInfo( XFerSegData->data + off, data, datalen );
    }
    group->size = group->totalsize;
}

static void WriteDataPages( pe_header *header, pe_object *object )
/*****************************************************************/
/* write the enumerated data pages */
{
    group_entry *group;
    char *      name;
    pe_va       linear;
    seg_leader *leader;
    unsigned_32 size_v;
    unsigned_32 size_ph;

    header->code_base = 0xFFFFFFFFUL;
    header->data_base = 0xFFFFFFFFUL;
    for( group = Groups; group != NULL; group = group->next_group) {
        if( group->totalsize == 0 ) continue;   // DANGER DANGER DANGER <--!!!
        name = group->sym->name;
        if( name == NULL || name[0] == 0 ) {
            leader = Ring2First( group->leaders );
            name = leader->segname;
            if( name == NULL ) name = "";
        }
        strncpy( object->name, name, PE_OBJ_NAME_LEN );
        size_ph = CalcGroupSize( group );
        if( group == DataGroup && FmtData.dgroupsplitseg != NULL ) {
            size_v = group->totalsize;
            if( StackSegPtr != NULL ) {
                size_v -= StackSize;
            }
        } else {
            size_v = size_ph;
        }
        linear = ROUND_UP( size_v, header->object_align );
        linear += group->linear;
        if( StartInfo.addr.seg == group->grp_addr.seg ) {
            header->entry_rva = group->linear + StartInfo.addr.off;
        }
        object->rva = group->linear;
        /*
        //  Why weren't we filling in this field? MS do!
        */
        object->virtual_size = size_v;
        object->physical_size = ROUND_UP( size_ph, header->file_align );

        object->flags = 0;
        /* segflags are in OS/2 V1.x format, we have to translate them
            into the appropriate PE bits */
        if( group->segflags & SEG_DATA ) {
            object->flags |= PE_OBJ_INIT_DATA | PE_OBJ_READABLE;
            if( !(group->segflags & SEG_READ_ONLY) ) {
                object->flags |= PE_OBJ_WRITABLE;
            }
            header->init_data_size += object->physical_size;
            if( object->rva < header->data_base ) {
                header->data_base = object->rva;
            }
        } else {

⌨️ 快捷键说明

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