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