peloader.c

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

C
615
字号
/****************************************************************************
*
*                            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:  Module to implement a simple Portable Binary DLL loader
*               library. This library can be used to load PE DLL's under
*               any Intel based OS, provided the DLL's do not have any
*               imports in the import table.
*
*               NOTE: This loader module expects the DLL's to be built with
*                     Watcom C++ and may produce unexpected results with
*                     DLL's linked by another compiler.
*
****************************************************************************/

#include "peloader.h"
#include "pe.h"
#include <stdlib.h>
#include <sys/mman.h>
#include "dbgmod.h"

/*--------------------------- Global variables ----------------------------*/

#define true    1
#define false   0

static int          result = PE_ok;

/*------------------------- Implementation --------------------------------*/

/****************************************************************************
PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file

RETURNS:
Handle to loaded PE DLL, or NULL on failure.

REMARKS:
This function loads a Portable Binary DLL library from disk, relocates
the code and returns a handle to the loaded library. This function is the
same as the regular PE_loadLibrary except that it take a handle to an
open file and an offset within that file for the DLL to load.
****************************************************************************/
static int PE_readHeader(
    FILE *f,
    long startOffset,
    FILE_HDR *filehdr,
    OPTIONAL_HDR *opthdr)
{
    EXE_HDR exehdr;
    u_long  offset,signature;

    /* Read the EXE header and check for valid header signature */
    result = PE_invalidDLLImage;
    fseek(f, startOffset, SEEK_SET);
    if (fread(&exehdr, 1, sizeof(exehdr), f) != sizeof(exehdr))
        return false;
    if (exehdr.signature != 0x5A4D)
        return false;

    /* Now seek to the start of the PE header defined at offset 0x3C
     * in the MS-DOS EXE header, and read the signature and check it.
     */
    fseek(f, startOffset+0x3C, SEEK_SET);
    if (fread(&offset, 1, sizeof(offset), f) != sizeof(offset))
        return false;
    fseek(f, startOffset+offset, SEEK_SET);
    if (fread(&signature, 1, sizeof(signature), f) != sizeof(signature))
        return false;
    if (signature != 0x00004550)
        return false;

    /* Now read the PE file header and check that it is correct */
    if (fread(filehdr, 1, sizeof(*filehdr), f) != sizeof(*filehdr))
        return false;
    if (filehdr->Machine != IMAGE_FILE_MACHINE_I386)
        return false;
    if (!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE))
        return false;
    if (!(filehdr->Characteristics & IMAGE_FILE_DLL))
        return false;
    if (fread(opthdr, 1, sizeof(*opthdr), f) != sizeof(*opthdr))
        return false;
    if (opthdr->Magic != 0x10B)
        return false;

    /* Success, so return true! */
    return true;
}

/****************************************************************************
DESCRIPTION:
Find the actual size of a PE file image

HEADER:
peloader.h

PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file

RETURNS:
Size of the DLL file on disk, or -1 on error

REMARKS:
This function scans the headers for a Portable Binary DLL to determine the
length of the DLL file on disk.
****************************************************************************/
u_long PE_getFileSize(
    FILE *f,
    u_long startOffset)
{
    FILE_HDR        filehdr;
    OPTIONAL_HDR    opthdr;
    SECTION_HDR     secthdr;
    u_long          size;
    int             i;

    /* Read the PE file headers from disk */
    if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
        return 0xFFFFFFFF;

    /* Scan all the section headers summing up the total size */
    size = opthdr.SizeOfHeaders;
    for (i = 0; i < filehdr.NumberOfSections; i++) {
        if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
            return 0xFFFFFFFF;
        if (!(secthdr.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
            size += secthdr.SizeOfRawData;
        }
    return size;
}

/****************************************************************************
DESCRIPTION:
Loads a Portable Binary DLL into memory from an open file

HEADER:
peloader.h

PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file
size        - Place to store the size of the driver loaded

RETURNS:
Handle to loaded PE DLL, or NULL on failure.

REMARKS:
This function loads a Portable Binary DLL library from disk, relocates
the code and returns a handle to the loaded library. This function is the
same as the regular PE_loadLibrary except that it take a handle to an
open file and an offset within that file for the DLL to load.

SEE ALSO:
PE_loadLibrary, PE_getProcAddress, PE_freeLibrary
****************************************************************************/
PE_MODULE * PE_loadLibraryExt(
    FILE *f,
    u_long startOffset,
    u_long *size)
{
    FILE_HDR        filehdr;
    OPTIONAL_HDR    opthdr;
    SECTION_HDR     secthdr;
    u_long          offset,pageOffset;
    u_long          text_raw_off,text_base,text_size,text_end;
    u_long          data_raw_off,data_base,data_size,data_virt_size,data_end;
    u_long          bss_raw_off,bss_base,bss_size,bss_end;
    u_long          import_raw_off,import_base,import_size,import_end;
    u_long          export_raw_off,export_base,export_size,export_end;
    u_long          reloc_raw_off,reloc_base= 0,reloc_size;
    u_long          image_base = 0,image_size,image_end;
    u_char          *image_ptr;
    int             i,delta,numFixups;
    u_short         relocType,*fixup;
    PE_MODULE       *hMod = NULL;
    void            *reloc = NULL;
    BASE_RELOCATION *baseReloc;

    /* Read the PE file headers from disk */
    if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
        return NULL;

    /* Scan all the section headers and find the necessary sections */
    text_raw_off = text_base = text_size = text_end = 0;
    data_raw_off = data_base = data_size = data_virt_size = data_end = 0;
    bss_raw_off = bss_base = bss_size = bss_end = 0;
    import_raw_off = import_base = import_size = import_end = 0;
    export_raw_off = export_base = export_size = export_end = 0;
    reloc_raw_off = reloc_size = 0;
    for (i = 0; i < filehdr.NumberOfSections; i++) {
        if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
            goto Error;
        if (i == 0)
            image_base = secthdr.VirtualAddress;
        if (strcmp(secthdr.Name, ".edata") == 0 || strcmp(secthdr.Name, ".rdata") == 0) {
            /* Exports section */
            export_raw_off = secthdr.PointerToRawData;
            export_base = secthdr.VirtualAddress;
            export_size = secthdr.SizeOfRawData;
            export_end = export_base + export_size;
            }
        else if (strcmp(secthdr.Name, ".idata") == 0) {
            /* Imports section */
            import_raw_off = secthdr.PointerToRawData;
            import_base = secthdr.VirtualAddress;
            import_size = secthdr.SizeOfRawData;
            import_end = import_base + import_size;
            }
        else if (strcmp(secthdr.Name, ".reloc") == 0) {
            /* Relocations section */
            reloc_raw_off = secthdr.PointerToRawData;
            reloc_base = secthdr.VirtualAddress;
            reloc_size = secthdr.SizeOfRawData;
            }
        else if (!text_raw_off && secthdr.Characteristics & IMAGE_SCN_CNT_CODE) {
            /* Code section */
            text_raw_off = secthdr.PointerToRawData;
            text_base = secthdr.VirtualAddress;
            text_size = secthdr.SizeOfRawData;
            text_end = text_base + text_size;
            }
        else if (!data_raw_off && secthdr.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
            /* Data section */
            data_raw_off = secthdr.PointerToRawData;
            data_base = secthdr.VirtualAddress;
            data_size = secthdr.SizeOfRawData;
            data_virt_size = secthdr.VirtualSize;
            data_end = data_base + data_size;
            }
        else if (!bss_raw_off && secthdr.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
            /* BSS data section */
            bss_raw_off = secthdr.PointerToRawData;
            bss_base = secthdr.VirtualAddress;
            bss_size = secthdr.SizeOfRawData;
            bss_end = bss_base + bss_size;
            }
        }

    /* Check to make sure that we have all the sections we need */
    if (!text_raw_off || !data_raw_off || !export_raw_off || !reloc_raw_off) {
        result = PE_invalidDLLImage;
        goto Error;
        }

    /* Make sure the .reloc section is after everything else we load! */
    image_end = max(max(max(max(bss_end,data_end),text_end),import_end),export_end);
    if (reloc_base <= image_end) {
        result = PE_unknownImageFormat;
        goto Error;
        }

    /* Find the size of the image sections to load and allocate memory for
     * them. We only load section data up to the .reloc section, and then
     * ignore everything else after that (eventually we might need to handle
     * the .rsrc section separately).
     */
    image_size = image_end - image_base;
    *size = sizeof(PE_MODULE) + image_size + 4096;
    hMod = malloc(*size);
    reloc = malloc(reloc_size);
    if (!hMod || !reloc) {
        result = PE_outOfMemory;
        goto Error;
        }

    /* Setup all the pointers into our loaded executeable image */
    image_ptr = (u_char*)ROUND_4K((u_long)hMod + sizeof(PE_MODULE));
    hMod->pbase = image_ptr;
    hMod->ptext = image_ptr + (text_base - image_base);
    hMod->pdata = image_ptr + (data_base - image_base);
    if (bss_base)
        hMod->pbss = image_ptr + (bss_base - image_base);
    else
        hMod->pbss = NULL;
    if (import_base)
        hMod->pimport = image_ptr + (import_base - image_base);
    else
        hMod->pimport = NULL;
    hMod->pexport = image_ptr + (export_base - image_base);
    hMod->textBase = text_base;
    hMod->dataBase = data_base;
    hMod->bssBase = bss_base;
    hMod->importBase = import_base;

⌨️ 快捷键说明

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