]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/common/peloader.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / common / peloader.c
1 /****************************************************************************
2 *
3 *                       SciTech MGL Graphics Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  Any
26 *
27 * Description:  Module to implement a simple Portable Binary DLL loader
28 *               library. This library can be used to load PE DLL's under
29 *               any Intel based OS, provided the DLL's do not have any
30 *               imports in the import table.
31 *
32 *               NOTE: This loader module expects the DLL's to be built with
33 *                     Watcom C++ and may produce unexpected results with
34 *                     DLL's linked by another compiler.
35 *
36 ****************************************************************************/
37
38 #include "drvlib/peloader.h"
39 #include "pmapi.h"
40 #include "drvlib/os/os.h"
41 #include "drvlib/libc/init.h"
42 #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
43 #define WIN32_LEAN_AND_MEAN
44 #define STRICT
45 #include <windows.h>
46 #endif
47 #include "drvlib/pe.h"
48
49 /*--------------------------- Global variables ----------------------------*/
50
51 static int          result = PE_ok;
52
53 /*------------------------- Implementation --------------------------------*/
54
55 /****************************************************************************
56 PARAMETERS:
57 f           - Handle to open file to read driver from
58 startOffset - Offset to the start of the driver within the file
59
60 RETURNS:
61 Handle to loaded PE DLL, or NULL on failure.
62
63 REMARKS:
64 This function loads a Portable Binary DLL library from disk, relocates
65 the code and returns a handle to the loaded library. This function is the
66 same as the regular PE_loadLibrary except that it take a handle to an
67 open file and an offset within that file for the DLL to load.
68 ****************************************************************************/
69 static int PE_readHeader(
70     FILE *f,
71     long startOffset,
72     FILE_HDR *filehdr,
73     OPTIONAL_HDR *opthdr)
74 {
75     EXE_HDR exehdr;
76     ulong   offset,signature;
77
78     /* Read the EXE header and check for valid header signature */
79     result = PE_invalidDLLImage;
80     fseek(f, startOffset, SEEK_SET);
81     if (fread(&exehdr, 1, sizeof(exehdr), f) != sizeof(exehdr))
82         return false;
83     if (exehdr.signature != 0x5A4D)
84         return false;
85
86     /* Now seek to the start of the PE header defined at offset 0x3C
87      * in the MS-DOS EXE header, and read the signature and check it.
88      */
89     fseek(f, startOffset+0x3C, SEEK_SET);
90     if (fread(&offset, 1, sizeof(offset), f) != sizeof(offset))
91         return false;
92     fseek(f, startOffset+offset, SEEK_SET);
93     if (fread(&signature, 1, sizeof(signature), f) != sizeof(signature))
94         return false;
95     if (signature != 0x00004550)
96         return false;
97
98     /* Now read the PE file header and check that it is correct */
99     if (fread(filehdr, 1, sizeof(*filehdr), f) != sizeof(*filehdr))
100         return false;
101     if (filehdr->Machine != IMAGE_FILE_MACHINE_I386)
102         return false;
103     if (!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE))
104         return false;
105     if (!(filehdr->Characteristics & IMAGE_FILE_DLL))
106         return false;
107     if (fread(opthdr, 1, sizeof(*opthdr), f) != sizeof(*opthdr))
108         return false;
109     if (opthdr->Magic != 0x10B)
110         return false;
111
112     /* Success, so return true! */
113     return true;
114 }
115
116 /****************************************************************************
117 PARAMETERS:
118 f           - Handle to open file to read driver from
119 startOffset - Offset to the start of the driver within the file
120
121 RETURNS:
122 Size of the DLL file on disk, or -1 on error
123
124 REMARKS:
125 This function scans the headers for a Portable Binary DLL to determine the
126 length of the DLL file on disk.
127 {secret}
128 ****************************************************************************/
129 ulong PEAPI PE_getFileSize(
130     FILE *f,
131     ulong startOffset)
132 {
133     FILE_HDR        filehdr;
134     OPTIONAL_HDR    opthdr;
135     SECTION_HDR     secthdr;
136     ulong           size;
137     int             i;
138
139     /* Read the PE file headers from disk */
140     if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
141         return 0xFFFFFFFF;
142
143     /* Scan all the section headers summing up the total size */
144     size = opthdr.SizeOfHeaders;
145     for (i = 0; i < filehdr.NumberOfSections; i++) {
146         if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
147             return 0xFFFFFFFF;
148         size += secthdr.SizeOfRawData;
149         }
150     return size;
151 }
152
153 /****************************************************************************
154 DESCRIPTION:
155 Loads a Portable Binary DLL into memory from an open file
156
157 HEADER:
158 peloader.h
159
160 PARAMETERS:
161 f           - Handle to open file to read driver from
162 startOffset - Offset to the start of the driver within the file
163 size        - Place to store the size of the driver loaded
164 shared      - True to load module into shared memory
165
166 RETURNS:
167 Handle to loaded PE DLL, or NULL on failure.
168
169 REMARKS:
170 This function loads a Portable Binary DLL library from disk, relocates
171 the code and returns a handle to the loaded library. This function is the
172 same as the regular PE_loadLibrary except that it take a handle to an
173 open file and an offset within that file for the DLL to load.
174
175 SEE ALSO:
176 PE_loadLibrary, PE_getProcAddress, PE_freeLibrary
177 ****************************************************************************/
178 PE_MODULE * PEAPI PE_loadLibraryExt(
179     FILE *f,
180     ulong startOffset,
181     ulong *size,
182     ibool shared)
183 {
184     FILE_HDR        filehdr;
185     OPTIONAL_HDR    opthdr;
186     SECTION_HDR     secthdr;
187     ulong           offset,pageOffset;
188     ulong           text_off,text_addr,text_size;
189     ulong           data_off,data_addr,data_size,data_end;
190     ulong           export_off,export_addr,export_size,export_end;
191     ulong           reloc_off,reloc_size;
192     ulong           image_size;
193     int             i,delta,numFixups;
194     ushort          relocType,*fixup;
195     PE_MODULE       *hMod = NULL;
196     void            *reloc = NULL;
197     BASE_RELOCATION *baseReloc;
198     InitLibC_t      InitLibC;
199
200     /* Read the PE file headers from disk */
201     if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
202         return NULL;
203
204     /* Scan all the section headers and find the necessary sections */
205     text_off = data_off = reloc_off = export_off = 0;
206     text_addr = text_size = 0;
207     data_addr = data_size = data_end = 0;
208     export_addr = export_size = export_end = 0;
209     reloc_size = 0;
210     for (i = 0; i < filehdr.NumberOfSections; i++) {
211         if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
212             goto Error;
213         if (strcmp(secthdr.Name, ".edata") == 0 || strcmp(secthdr.Name, ".rdata") == 0) {
214             /* Exports section */
215             export_off = secthdr.PointerToRawData;
216             export_addr = secthdr.VirtualAddress;
217             export_size = secthdr.SizeOfRawData;
218             export_end = export_addr + export_size;
219             }
220         else if (strcmp(secthdr.Name, ".idata") == 0) {
221             /* Imports section, ignore */
222             }
223         else if (strcmp(secthdr.Name, ".reloc") == 0) {
224             /* Relocations section */
225             reloc_off = secthdr.PointerToRawData;
226             reloc_size = secthdr.SizeOfRawData;
227             }
228         else if (!text_off && secthdr.Characteristics & IMAGE_SCN_CNT_CODE) {
229             /* Code section */
230             text_off = secthdr.PointerToRawData;
231             text_addr = secthdr.VirtualAddress;
232             text_size = secthdr.SizeOfRawData;
233             }
234         else if (!data_off && secthdr.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
235             /* Data section */
236             data_off = secthdr.PointerToRawData;
237             data_addr = secthdr.VirtualAddress;
238             data_size = secthdr.SizeOfRawData;
239             data_end = data_addr + data_size;
240             }
241         }
242
243     /* Check to make sure that we have all the sections we need */
244     if (!text_off || !data_off || !export_off || !reloc_off) {
245         result = PE_invalidDLLImage;
246         goto Error;
247         }
248
249     /* Find the size of the image to load allocate memory for it */
250     image_size = MAX(export_end,data_end) - text_addr;
251     *size = sizeof(PE_MODULE) + image_size + 4096;
252     if (shared)
253         hMod = PM_mallocShared(*size);
254     else
255         hMod = PM_malloc(*size);
256     reloc = PM_malloc(reloc_size);
257     if (!hMod || !reloc) {
258         result = PE_outOfMemory;
259         goto Error;
260         }
261
262     hMod->text = (uchar*)ROUND_4K((ulong)hMod + sizeof(PE_MODULE));
263     hMod->data = (uchar*)((ulong)hMod->text + (data_addr - text_addr));
264     hMod->export = (uchar*)((ulong)hMod->text + (export_addr - text_addr));
265     hMod->textBase = text_addr;
266     hMod->dataBase = data_addr;
267     hMod->exportBase = export_addr;
268     hMod->exportDir = opthdr.DataDirectory[0].RelVirtualAddress - export_addr;
269     hMod->shared = shared;
270
271     /* Now read the section images from disk */
272     result = PE_invalidDLLImage;
273     fseek(f, startOffset+text_off, SEEK_SET);
274     if (fread(hMod->text, 1, text_size, f) != text_size)
275         goto Error;
276     fseek(f, startOffset+data_off, SEEK_SET);
277     if (fread(hMod->data, 1, data_size, f) != data_size)
278         goto Error;
279     fseek(f, startOffset+export_off, SEEK_SET);
280     if (fread(hMod->export, 1, export_size, f) != export_size)
281         goto Error;
282     fseek(f, startOffset+reloc_off, SEEK_SET);
283     if (fread(reloc, 1, reloc_size, f) != reloc_size)
284         goto Error;
285
286     /* Now perform relocations on all sections in the image */
287     delta = (ulong)hMod->text - opthdr.ImageBase - text_addr;
288     baseReloc = (BASE_RELOCATION*)reloc;
289     for (;;) {
290         /* Check for termination condition */
291         if (!baseReloc->PageRVA || !baseReloc->BlockSize)
292             break;
293
294         /* Do fixups */
295         pageOffset = baseReloc->PageRVA - hMod->textBase;
296         numFixups = (baseReloc->BlockSize - sizeof(BASE_RELOCATION)) / sizeof(ushort);
297         fixup = (ushort*)(baseReloc + 1);
298         for (i = 0; i < numFixups; i++) {
299             relocType = *fixup >> 12;
300             if (relocType) {
301                 offset = pageOffset + (*fixup & 0x0FFF);
302                 *(ulong*)(hMod->text + offset) += delta;
303                 }
304             fixup++;
305             }
306
307         /* Move to next relocation block */
308         baseReloc = (BASE_RELOCATION*)((ulong)baseReloc + baseReloc->BlockSize);
309         }
310
311     /* Initialise the C runtime library for the loaded DLL */
312     result = PE_unableToInitLibC;
313     if ((InitLibC = (InitLibC_t)PE_getProcAddress(hMod,"_InitLibC")) == NULL)
314         goto Error;
315     if (!InitLibC(&___imports,PM_getOSType()))
316         goto Error;
317
318     /* Clean up, close the file and return the loaded module handle */
319     PM_free(reloc);
320     result = PE_ok;
321     return hMod;
322
323 Error:
324     if (shared)
325         PM_freeShared(hMod);
326     else
327         PM_free(hMod);
328     PM_free(reloc);
329     return NULL;
330 }
331
332 /****************************************************************************
333 DESCRIPTION:
334 Loads a Portable Binary DLL into memory
335
336 HEADER:
337 peloader.h
338
339 PARAMETERS:
340 szDLLName   - Name of the PE DLL library to load
341 shared      - True to load module into shared memory
342
343 RETURNS:
344 Handle to loaded PE DLL, or NULL on failure.
345
346 REMARKS:
347 This function loads a Portable Binary DLL library from disk, relocates
348 the code and returns a handle to the loaded library. This function
349 will only work on DLL's that do not have any imports, since we don't
350 resolve import dependencies in this function.
351
352 SEE ALSO:
353 PE_getProcAddress, PE_freeLibrary
354 ****************************************************************************/
355 PE_MODULE * PEAPI PE_loadLibrary(
356     const char *szDLLName,
357     ibool shared)
358 {
359     PE_MODULE   *hMod;
360
361 #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
362     if (!shared) {
363         PM_MODULE       hInst;
364         InitLibC_t      InitLibC;
365
366         /* For Win32 if are building checked libraries for debugging, we use
367          * the real Win32 DLL functions so that we can debug the resulting DLL
368          * files with the Win32 debuggers. Note that we can't do this if
369          * we need to load the files into a shared memory context.
370          */
371         if ((hInst = PM_loadLibrary(szDLLName)) == NULL) {
372             result = PE_fileNotFound;
373             return NULL;
374             }
375
376         /* Initialise the C runtime library for the loaded DLL */
377         result = PE_unableToInitLibC;
378         if ((InitLibC = (void*)PM_getProcAddress(hInst,"_InitLibC")) == NULL)
379             return NULL;
380         if (!InitLibC(&___imports,PM_getOSType()))
381             return NULL;
382
383         /* Allocate the PE_MODULE structure */
384         if ((hMod = PM_malloc(sizeof(*hMod))) == NULL)
385             return NULL;
386         hMod->text = (void*)hInst;
387         hMod->shared = -1;
388
389         /* DLL loaded successfully so return module handle */
390         result = PE_ok;
391         return hMod;
392         }
393     else
394 #endif
395         {
396         FILE        *f;
397         ulong       size;
398
399         /* Attempt to open the file on disk */
400         if (shared < 0)
401             shared = 0;
402         if ((f = fopen(szDLLName,"rb")) == NULL) {
403             result = PE_fileNotFound;
404             return NULL;
405             }
406         hMod = PE_loadLibraryExt(f,0,&size,shared);
407         fclose(f);
408         return hMod;
409         }
410 }
411
412 /****************************************************************************
413 DESCRIPTION:
414 Loads a Portable Binary DLL into memory
415
416 HEADER:
417 peloader.h
418
419 PARAMETERS:
420 szDLLName   - Name of the PE DLL library to load
421 shared      - True to load module into shared memory
422
423 RETURNS:
424 Handle to loaded PE DLL, or NULL on failure.
425
426 REMARKS:
427 This function is the same as the regular PE_loadLibrary function, except
428 that it looks for the drivers in the MGL_ROOT/drivers directory or a
429 /drivers directory relative to the current directory.
430
431 SEE ALSO:
432 PE_loadLibraryMGL, PE_getProcAddress, PE_freeLibrary
433 ****************************************************************************/
434 PE_MODULE * PEAPI PE_loadLibraryMGL(
435     const char *szDLLName,
436     ibool shared)
437 {
438 #if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
439     PE_MODULE   *hMod;
440 #endif
441     char        path[256] = "";
442
443     /* We look in the 'drivers' directory, optionally under the MGL_ROOT
444      * environment variable directory.
445      */
446 #if !defined(__WIN32_VXD__) && !defined(__NT_DRIVER__)
447     if (getenv("MGL_ROOT")) {
448         strcpy(path,getenv("MGL_ROOT"));
449         PM_backslash(path);
450         }
451     strcat(path,"drivers");
452     PM_backslash(path);
453     strcat(path,szDLLName);
454     if ((hMod = PE_loadLibrary(path,shared)) != NULL)
455         return hMod;
456 #endif
457     strcpy(path,"drivers");
458     PM_backslash(path);
459     strcat(path,szDLLName);
460     return PE_loadLibrary(path,shared);
461 }
462
463 /****************************************************************************
464 DESCRIPTION:
465 Gets a function address from a Portable Binary DLL
466
467 HEADER:
468 peloader.h
469
470 PARAMETERS:
471 hModule     - Handle to a loaded PE DLL library
472 szProcName  - Name of the function to get the address of
473
474 RETURNS:
475 Pointer to the function, or NULL on failure.
476
477 REMARKS:
478 This function searches for the named, exported function in a loaded PE
479 DLL library, and returns the address of the function. If the function is
480 not found in the library, this function return NULL.
481
482 SEE ALSO:
483 PE_loadLibrary, PE_freeLibrary
484 ****************************************************************************/
485 void * PEAPI PE_getProcAddress(
486     PE_MODULE *hModule,
487     const char *szProcName)
488 {
489 #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
490     if (hModule->shared == -1)
491         return (void*)PM_getProcAddress(hModule->text,szProcName);
492     else
493 #endif
494         {
495         uint                i;
496         EXPORT_DIRECTORY    *exports;
497         ulong               funcOffset;
498         ulong               *AddressTable;
499         ulong               *NameTable;
500         ushort              *OrdinalTable;
501         char                *name;
502
503         /* Find the address of the export tables from the export section */
504         if (!hModule)
505             return NULL;
506         exports = (EXPORT_DIRECTORY*)(hModule->export + hModule->exportDir);
507         AddressTable = (ulong*)(hModule->export + exports->AddressTableRVA - hModule->exportBase);
508         NameTable = (ulong*)(hModule->export + exports->NameTableRVA - hModule->exportBase);
509         OrdinalTable = (ushort*)(hModule->export + exports->OrdinalTableRVA - hModule->exportBase);
510
511         /* Search the export name table to find the function name */
512         for (i = 0; i < exports->NumberOfNamePointers; i++) {
513             name = (char*)(hModule->export + NameTable[i] - hModule->exportBase);
514             if (strcmp(name,szProcName) == 0)
515                 break;
516             }
517         if (i == exports->NumberOfNamePointers)
518             return NULL;
519         funcOffset = AddressTable[OrdinalTable[i]];
520         if (!funcOffset)
521             return NULL;
522         return (void*)(hModule->text + funcOffset - hModule->textBase);
523         }
524 }
525
526 /****************************************************************************
527 DESCRIPTION:
528 Frees a loaded Portable Binary DLL
529
530 HEADER:
531 peloader.h
532
533 PARAMETERS:
534 hModule     - Handle to a loaded PE DLL library to free
535
536 REMARKS:
537 This function frees a loaded PE DLL library from memory.
538
539 SEE ALSO:
540 PE_getProcAddress, PE_loadLibrary
541 ****************************************************************************/
542 void PEAPI PE_freeLibrary(
543     PE_MODULE *hModule)
544 {
545     TerminateLibC_t TerminateLibC;
546
547 #if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
548     if (hModule->shared == -1) {
549         /* Run the C runtime library exit code on module unload */
550         if ((TerminateLibC = (TerminateLibC_t)PM_getProcAddress(hModule->text,"_TerminateLibC")) != NULL)
551             TerminateLibC();
552         PM_freeLibrary(hModule->text);
553         PM_free(hModule);
554         }
555     else
556 #endif
557         {
558         if (hModule) {
559             /* Run the C runtime library exit code on module unload */
560             if ((TerminateLibC = (TerminateLibC_t)PE_getProcAddress(hModule,"_TerminateLibC")) != NULL)
561                 TerminateLibC();
562             if (hModule->shared)
563                 PM_freeShared(hModule);
564             else
565                 PM_free(hModule);
566             }
567         }
568 }
569
570 /****************************************************************************
571 DESCRIPTION:
572 Returns the error code for the last operation
573
574 HEADER:
575 peloader.h
576
577 RETURNS:
578 Error code for the last operation.
579
580 SEE ALSO:
581 PE_getProcAddress, PE_loadLibrary
582 ****************************************************************************/
583 int PEAPI PE_getError(void)
584 {
585     return result;
586 }
587