diff options
Diffstat (limited to 'board/MAI/bios_emulator/scitech/src/common/peloader.c')
| -rw-r--r-- | board/MAI/bios_emulator/scitech/src/common/peloader.c | 587 | 
1 files changed, 587 insertions, 0 deletions
| diff --git a/board/MAI/bios_emulator/scitech/src/common/peloader.c b/board/MAI/bios_emulator/scitech/src/common/peloader.c new file mode 100644 index 000000000..b9bec4aeb --- /dev/null +++ b/board/MAI/bios_emulator/scitech/src/common/peloader.c @@ -0,0 +1,587 @@ +/**************************************************************************** +* +*                       SciTech MGL Graphics Library +* +*  ======================================================================== +* +*    The contents of this file are subject to the SciTech MGL Public +*    License Version 1.0 (the "License"); you may not use this file +*    except in compliance with the License. You may obtain a copy of +*    the License at http://www.scitechsoft.com/mgl-license.txt +* +*    Software distributed under the License is distributed on an +*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +*    implied. See the License for the specific language governing +*    rights and limitations under the License. +* +*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc. +* +*    The Initial Developer of the Original Code is SciTech Software, Inc. +*    All Rights Reserved. +* +*  ======================================================================== +* +* Language:     ANSI C +* Environment:  Any +* +* 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 "drvlib/peloader.h" +#include "pmapi.h" +#include "drvlib/os/os.h" +#include "drvlib/libc/init.h" +#if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED) +#define WIN32_LEAN_AND_MEAN +#define STRICT +#include <windows.h> +#endif +#include "drvlib/pe.h" + +/*--------------------------- Global variables ----------------------------*/ + +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; +    ulong   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; +} + +/**************************************************************************** +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. +{secret} +****************************************************************************/ +ulong PEAPI PE_getFileSize( +    FILE *f, +    ulong startOffset) +{ +    FILE_HDR        filehdr; +    OPTIONAL_HDR    opthdr; +    SECTION_HDR     secthdr; +    ulong           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(§hdr, 1, sizeof(secthdr), f) != sizeof(secthdr)) +            return 0xFFFFFFFF; +        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 +shared      - True to load module into shared memory + +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 * PEAPI PE_loadLibraryExt( +    FILE *f, +    ulong startOffset, +    ulong *size, +    ibool shared) +{ +    FILE_HDR        filehdr; +    OPTIONAL_HDR    opthdr; +    SECTION_HDR     secthdr; +    ulong           offset,pageOffset; +    ulong           text_off,text_addr,text_size; +    ulong           data_off,data_addr,data_size,data_end; +    ulong           export_off,export_addr,export_size,export_end; +    ulong           reloc_off,reloc_size; +    ulong           image_size; +    int             i,delta,numFixups; +    ushort          relocType,*fixup; +    PE_MODULE       *hMod = NULL; +    void            *reloc = NULL; +    BASE_RELOCATION *baseReloc; +    InitLibC_t      InitLibC; + +    /* 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_off = data_off = reloc_off = export_off = 0; +    text_addr = text_size = 0; +    data_addr = data_size = data_end = 0; +    export_addr = export_size = export_end = 0; +    reloc_size = 0; +    for (i = 0; i < filehdr.NumberOfSections; i++) { +        if (fread(§hdr, 1, sizeof(secthdr), f) != sizeof(secthdr)) +            goto Error; +        if (strcmp(secthdr.Name, ".edata") == 0 || strcmp(secthdr.Name, ".rdata") == 0) { +            /* Exports section */ +            export_off = secthdr.PointerToRawData; +            export_addr = secthdr.VirtualAddress; +            export_size = secthdr.SizeOfRawData; +            export_end = export_addr + export_size; +            } +        else if (strcmp(secthdr.Name, ".idata") == 0) { +            /* Imports section, ignore */ +            } +        else if (strcmp(secthdr.Name, ".reloc") == 0) { +            /* Relocations section */ +            reloc_off = secthdr.PointerToRawData; +            reloc_size = secthdr.SizeOfRawData; +            } +        else if (!text_off && secthdr.Characteristics & IMAGE_SCN_CNT_CODE) { +            /* Code section */ +            text_off = secthdr.PointerToRawData; +            text_addr = secthdr.VirtualAddress; +            text_size = secthdr.SizeOfRawData; +            } +        else if (!data_off && secthdr.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { +            /* Data section */ +            data_off = secthdr.PointerToRawData; +            data_addr = secthdr.VirtualAddress; +            data_size = secthdr.SizeOfRawData; +            data_end = data_addr + data_size; +            } +        } + +    /* Check to make sure that we have all the sections we need */ +    if (!text_off || !data_off || !export_off || !reloc_off) { +        result = PE_invalidDLLImage; +        goto Error; +        } + +    /* Find the size of the image to load allocate memory for it */ +    image_size = MAX(export_end,data_end) - text_addr; +    *size = sizeof(PE_MODULE) + image_size + 4096; +    if (shared) +        hMod = PM_mallocShared(*size); +    else +        hMod = PM_malloc(*size); +    reloc = PM_malloc(reloc_size); +    if (!hMod || !reloc) { +        result = PE_outOfMemory; +        goto Error; +        } + +    hMod->text = (uchar*)ROUND_4K((ulong)hMod + sizeof(PE_MODULE)); +    hMod->data = (uchar*)((ulong)hMod->text + (data_addr - text_addr)); +    hMod->export = (uchar*)((ulong)hMod->text + (export_addr - text_addr)); +    hMod->textBase = text_addr; +    hMod->dataBase = data_addr; +    hMod->exportBase = export_addr; +    hMod->exportDir = opthdr.DataDirectory[0].RelVirtualAddress - export_addr; +    hMod->shared = shared; + +    /* Now read the section images from disk */ +    result = PE_invalidDLLImage; +    fseek(f, startOffset+text_off, SEEK_SET); +    if (fread(hMod->text, 1, text_size, f) != text_size) +        goto Error; +    fseek(f, startOffset+data_off, SEEK_SET); +    if (fread(hMod->data, 1, data_size, f) != data_size) +        goto Error; +    fseek(f, startOffset+export_off, SEEK_SET); +    if (fread(hMod->export, 1, export_size, f) != export_size) +        goto Error; +    fseek(f, startOffset+reloc_off, SEEK_SET); +    if (fread(reloc, 1, reloc_size, f) != reloc_size) +        goto Error; + +    /* Now perform relocations on all sections in the image */ +    delta = (ulong)hMod->text - opthdr.ImageBase - text_addr; +    baseReloc = (BASE_RELOCATION*)reloc; +    for (;;) { +        /* Check for termination condition */ +        if (!baseReloc->PageRVA || !baseReloc->BlockSize) +            break; + +        /* Do fixups */ +        pageOffset = baseReloc->PageRVA - hMod->textBase; +        numFixups = (baseReloc->BlockSize - sizeof(BASE_RELOCATION)) / sizeof(ushort); +        fixup = (ushort*)(baseReloc + 1); +        for (i = 0; i < numFixups; i++) { +            relocType = *fixup >> 12; +            if (relocType) { +                offset = pageOffset + (*fixup & 0x0FFF); +                *(ulong*)(hMod->text + offset) += delta; +                } +            fixup++; +            } + +        /* Move to next relocation block */ +        baseReloc = (BASE_RELOCATION*)((ulong)baseReloc + baseReloc->BlockSize); +        } + +    /* Initialise the C runtime library for the loaded DLL */ +    result = PE_unableToInitLibC; +    if ((InitLibC = (InitLibC_t)PE_getProcAddress(hMod,"_InitLibC")) == NULL) +        goto Error; +    if (!InitLibC(&___imports,PM_getOSType())) +        goto Error; + +    /* Clean up, close the file and return the loaded module handle */ +    PM_free(reloc); +    result = PE_ok; +    return hMod; + +Error: +    if (shared) +        PM_freeShared(hMod); +    else +        PM_free(hMod); +    PM_free(reloc); +    return NULL; +} + +/**************************************************************************** +DESCRIPTION: +Loads a Portable Binary DLL into memory + +HEADER: +peloader.h + +PARAMETERS: +szDLLName   - Name of the PE DLL library to load +shared      - True to load module into shared memory + +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 +will only work on DLL's that do not have any imports, since we don't +resolve import dependencies in this function. + +SEE ALSO: +PE_getProcAddress, PE_freeLibrary +****************************************************************************/ +PE_MODULE * PEAPI PE_loadLibrary( +    const char *szDLLName, +    ibool shared) +{ +    PE_MODULE   *hMod; + +#if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED) +    if (!shared) { +        PM_MODULE       hInst; +        InitLibC_t      InitLibC; + +        /* For Win32 if are building checked libraries for debugging, we use +         * the real Win32 DLL functions so that we can debug the resulting DLL +         * files with the Win32 debuggers. Note that we can't do this if +         * we need to load the files into a shared memory context. +         */ +        if ((hInst = PM_loadLibrary(szDLLName)) == NULL) { +            result = PE_fileNotFound; +            return NULL; +            } + +        /* Initialise the C runtime library for the loaded DLL */ +        result = PE_unableToInitLibC; +        if ((InitLibC = (void*)PM_getProcAddress(hInst,"_InitLibC")) == NULL) +            return NULL; +        if (!InitLibC(&___imports,PM_getOSType())) +            return NULL; + +        /* Allocate the PE_MODULE structure */ +        if ((hMod = PM_malloc(sizeof(*hMod))) == NULL) +            return NULL; +        hMod->text = (void*)hInst; +        hMod->shared = -1; + +        /* DLL loaded successfully so return module handle */ +        result = PE_ok; +        return hMod; +        } +    else +#endif +        { +        FILE        *f; +        ulong       size; + +        /* Attempt to open the file on disk */ +        if (shared < 0) +            shared = 0; +        if ((f = fopen(szDLLName,"rb")) == NULL) { +            result = PE_fileNotFound; +            return NULL; +            } +        hMod = PE_loadLibraryExt(f,0,&size,shared); +        fclose(f); +        return hMod; +        } +} + +/**************************************************************************** +DESCRIPTION: +Loads a Portable Binary DLL into memory + +HEADER: +peloader.h + +PARAMETERS: +szDLLName   - Name of the PE DLL library to load +shared      - True to load module into shared memory + +RETURNS: +Handle to loaded PE DLL, or NULL on failure. + +REMARKS: +This function is the same as the regular PE_loadLibrary function, except +that it looks for the drivers in the MGL_ROOT/drivers directory or a +/drivers directory relative to the current directory. + +SEE ALSO: +PE_loadLibraryMGL, PE_getProcAddress, PE_freeLibrary +****************************************************************************/ +PE_MODULE * PEAPI PE_loadLibraryMGL( +    const char *szDLLName, +    ibool shared) +{ +#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__) +    PE_MODULE   *hMod; +#endif +    char        path[256] = ""; + +    /* We look in the 'drivers' directory, optionally under the MGL_ROOT +     * environment variable directory. +     */ +#if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__) +    if (getenv("MGL_ROOT")) { +        strcpy(path,getenv("MGL_ROOT")); +        PM_backslash(path); +        } +    strcat(path,"drivers"); +    PM_backslash(path); +    strcat(path,szDLLName); +    if ((hMod = PE_loadLibrary(path,shared)) != NULL) +        return hMod; +#endif +    strcpy(path,"drivers"); +    PM_backslash(path); +    strcat(path,szDLLName); +    return PE_loadLibrary(path,shared); +} + +/**************************************************************************** +DESCRIPTION: +Gets a function address from a Portable Binary DLL + +HEADER: +peloader.h + +PARAMETERS: +hModule     - Handle to a loaded PE DLL library +szProcName  - Name of the function to get the address of + +RETURNS: +Pointer to the function, or NULL on failure. + +REMARKS: +This function searches for the named, exported function in a loaded PE +DLL library, and returns the address of the function. If the function is +not found in the library, this function return NULL. + +SEE ALSO: +PE_loadLibrary, PE_freeLibrary +****************************************************************************/ +void * PEAPI PE_getProcAddress( +    PE_MODULE *hModule, +    const char *szProcName) +{ +#if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED) +    if (hModule->shared == -1) +        return (void*)PM_getProcAddress(hModule->text,szProcName); +    else +#endif +        { +        uint                i; +        EXPORT_DIRECTORY    *exports; +        ulong               funcOffset; +        ulong               *AddressTable; +        ulong               *NameTable; +        ushort              *OrdinalTable; +        char                *name; + +        /* Find the address of the export tables from the export section */ +        if (!hModule) +            return NULL; +        exports = (EXPORT_DIRECTORY*)(hModule->export + hModule->exportDir); +        AddressTable = (ulong*)(hModule->export + exports->AddressTableRVA - hModule->exportBase); +        NameTable = (ulong*)(hModule->export + exports->NameTableRVA - hModule->exportBase); +        OrdinalTable = (ushort*)(hModule->export + exports->OrdinalTableRVA - hModule->exportBase); + +        /* Search the export name table to find the function name */ +        for (i = 0; i < exports->NumberOfNamePointers; i++) { +            name = (char*)(hModule->export + NameTable[i] - hModule->exportBase); +            if (strcmp(name,szProcName) == 0) +                break; +            } +        if (i == exports->NumberOfNamePointers) +            return NULL; +        funcOffset = AddressTable[OrdinalTable[i]]; +        if (!funcOffset) +            return NULL; +        return (void*)(hModule->text + funcOffset - hModule->textBase); +        } +} + +/**************************************************************************** +DESCRIPTION: +Frees a loaded Portable Binary DLL + +HEADER: +peloader.h + +PARAMETERS: +hModule     - Handle to a loaded PE DLL library to free + +REMARKS: +This function frees a loaded PE DLL library from memory. + +SEE ALSO: +PE_getProcAddress, PE_loadLibrary +****************************************************************************/ +void PEAPI PE_freeLibrary( +    PE_MODULE *hModule) +{ +    TerminateLibC_t TerminateLibC; + +#if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED) +    if (hModule->shared == -1) { +        /* Run the C runtime library exit code on module unload */ +        if ((TerminateLibC = (TerminateLibC_t)PM_getProcAddress(hModule->text,"_TerminateLibC")) != NULL) +            TerminateLibC(); +        PM_freeLibrary(hModule->text); +        PM_free(hModule); +        } +    else +#endif +        { +        if (hModule) { +            /* Run the C runtime library exit code on module unload */ +            if ((TerminateLibC = (TerminateLibC_t)PE_getProcAddress(hModule,"_TerminateLibC")) != NULL) +                TerminateLibC(); +            if (hModule->shared) +                PM_freeShared(hModule); +            else +                PM_free(hModule); +            } +        } +} + +/**************************************************************************** +DESCRIPTION: +Returns the error code for the last operation + +HEADER: +peloader.h + +RETURNS: +Error code for the last operation. + +SEE ALSO: +PE_getProcAddress, PE_loadLibrary +****************************************************************************/ +int PEAPI PE_getError(void) +{ +    return result; +} + |