home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 24 / CD_ASCQ_24_0995.iso / dos / prg / dsik205 / dsik.dat / SOURCE / PE.C < prev    next >
C/C++ Source or Header  |  1995-04-10  |  11KB  |  362 lines

  1. /****************************************************************************
  2. *
  3. *                   Digital Sound Interface Kit (DSIK)
  4. *                            Version 2.00
  5. *
  6. *                           by Carlos Hasan
  7. *
  8. * Filename:     pe.c
  9. * Version:      Revision 1.0 (EXPERIMENTAL)
  10. *
  11. * Language:     WATCOM C
  12. * Environment:  IBM PC (DOS/4GW)
  13. *
  14. * Description:  Portable Executable (PE) Dynamic Link Library loader.
  15. *
  16. * Revision History:
  17. * ----------------
  18. *
  19. * Revision 1.0  94/12/18  14:33:14  chv
  20. * Initial revision
  21. *
  22. ****************************************************************************/
  23.  
  24. #include <io.h>
  25. #include <fcntl.h>
  26. #include <malloc.h>
  27. #include <string.h>
  28. #include <stdio.h>
  29. #include "audio.h"
  30. #include "pe.h"
  31.  
  32. /*#define DEBUG*/
  33.  
  34. #ifdef DEBUG
  35. #define DBG0(fmt) printf("LOADER: "fmt)
  36. #define DBG1(fmt,a) printf("LOADER: "fmt,a)
  37. #define DBG2(fmt,a,b) printf("LOADER: "fmt,a,b)
  38. #else
  39. #define DBG0(fmt)
  40. #define DBG1(fmt,a)
  41. #define DBG2(fmt,a,b)
  42. #endif
  43.  
  44.  
  45. /****************************************************************************
  46. *
  47. * Function:     dGetLibrarySection
  48. * Parameters:   Pe      - PE library handler
  49. *               Name    - section name
  50. *
  51. * Returns:      PE section header address or NULL if error.
  52. *
  53. * Description:  This routine will search the specified section structure
  54. *               by name. It returns NULL if the section is not found.
  55. *
  56. ****************************************************************************/
  57.  
  58. static PESCN *dGetLibrarySection(HANDLE Pe, char *Name)
  59. {
  60.     int I;
  61.  
  62.     DBG1("searching section %s.\n",Name);
  63.     for (I = 0; I < Pe->Hdr.NumScns; I++)
  64.         if (!strcmp(Name,Pe->Scn[I].Name))
  65.             return &Pe->Scn[I];
  66.     return NULL;
  67. }
  68.  
  69.  
  70. /****************************************************************************
  71. *
  72. * Function:     dGetLinearAddress
  73. * Parameters:   Pe      - PE library handler
  74. *               VAddr   - virtual address
  75. *
  76. * Returns:      Linear address or NULL if address does not exist.
  77. *
  78. * Description:  This routine translates relative virtual addresses (RVA)
  79. *               to actual linear addresses. If the RVA is not found within
  80. *               the module virtual space then it returns NULL.
  81. *
  82. ****************************************************************************/
  83.  
  84. static DWORD dGetLinearAddress(HANDLE Pe, DWORD VAddr)
  85. {
  86.     PESCN *Scn;
  87.     int I;
  88.     for (I = 0, Scn = Pe->Scn; I < Pe->Hdr.NumScns; I++, Scn++)
  89.         if (VAddr >= Scn->VAddr && VAddr < (Scn->VAddr+Scn->Size))
  90.             return VAddr+Scn->PAddr-Scn->VAddr;
  91.     return 0L;
  92. }
  93.  
  94.  
  95. /****************************************************************************
  96. *
  97. * Function:     dRelocateLibrary
  98. * Parameters:   Pe      - PE library handler
  99. *
  100. * Description:  This routine performs the fixups or relocations of the
  101. *               dynamic link library. Must be called when the module
  102. *               is loaded from disk.
  103. *
  104. ****************************************************************************/
  105.  
  106. static HANDLE dRelocateLibrary(HANDLE Pe)
  107. {
  108.     PESCN *Scn;
  109.     PERLC *Rlc;
  110.     DWORD PagePtr;
  111.     WORD *TypePtr;
  112.     DWORD *TargetPtr;
  113.     int I;
  114.  
  115.     DBG0("relocating DLL library core.\n");
  116.     if (!(Scn = dGetLibrarySection(Pe,PE_RELOC))) {
  117.         DBG0("relocation section not found.\n");
  118.         return Pe;
  119.     }
  120.     Rlc = (PERLC*)Scn->PAddr;
  121.     while (Rlc->VAddr && Scn->Size) {
  122.         DBG2("vaddr: 0x%08lx  size: 0x%08lx\n",Rlc->VAddr,Rlc->Size);
  123.         Scn->Size -= Rlc->Size;
  124.         PagePtr = Rlc->VAddr;
  125.         TypePtr = Rlc->Type;
  126.         Rlc = (PERLC*)((BYTE*)Rlc+Rlc->Size);
  127.         if (!(PagePtr = dGetLinearAddress(Pe,PagePtr))) {
  128.             DBG0("relocation target page not found!\n");
  129.             continue;
  130.         }
  131.         while (TypePtr < (WORD*)Rlc) {
  132.             if (((I = *TypePtr++) & PE_R_MASK) != PE_R_HIGHLOW) {
  133.                 DBG0("ERROR: skipping relocation!\n");
  134.                 continue;
  135.             }
  136.             TargetPtr = (DWORD*)(PagePtr+(I & PE_R_OFFMASK));
  137.             *TargetPtr -= Pe->NtHdr.ImageBase;
  138.             DBG2("offset: 0x%04lx  target: 0x%08lx\n",
  139.                 (I & PE_R_OFFMASK),*TargetPtr);
  140.             if (!(*TargetPtr = dGetLinearAddress(Pe,*TargetPtr))) {
  141.                 DBG0("target address not found!\n");
  142.             }
  143.         }
  144.         DBG0("\n");
  145.     }
  146.     return Pe;
  147. }
  148.  
  149.  
  150. /****************************************************************************
  151. *
  152. * Function:     dGetProcAddress
  153. * Parameters:   Pe      - PE library handler
  154. *               Name    - procedure name
  155. *
  156. * Returns:      Procedure address or NULL if not found.
  157. *
  158. * Description:  This routine returns the address of the specified exported
  159. *               procedure name. It returns NULL if the procedure is not
  160. *               found in the export directory of the module.
  161. *
  162. ****************************************************************************/
  163.  
  164. FARPROC dGetProcAddress(HANDLE Pe, char *Name)
  165. {
  166.     PESCN *Scn;
  167.     PEEXP *Exp;
  168.     DWORD *NamePtr,*FuncPtr,ProcName,ProcAddr;
  169.     int I;
  170.  
  171.     DBG1("searching export procedure '%s'.\n",Name);
  172.     if (!(Scn = dGetLibrarySection(Pe,PE_EDATA))) {
  173.         DBG0("export section not found!\n");
  174.         return NULL;
  175.     }
  176.     Exp = (PEEXP*)Scn->PAddr;
  177.  
  178.     DBG2("DLL module '%s', %d functions.\n",
  179.         (char*)dGetLinearAddress(Pe,Exp->NamePtr), Exp->NumFuncs);
  180.  
  181.     NamePtr = (DWORD*)((BYTE*)Exp+(Exp->NameTabPtr-Scn->VAddr));
  182.     FuncPtr = (DWORD*)((BYTE*)Exp+(Exp->FuncTabPtr-Scn->VAddr));
  183.     for (I = 0; I < Exp->NumFuncs; I++) {
  184.         ProcName = *NamePtr++;
  185.         ProcAddr = *FuncPtr++;
  186.         if (!(ProcName = dGetLinearAddress(Pe,ProcName))) {
  187.             DBG0("ERROR: procedure name address not found!\n");
  188.             continue;
  189.         }
  190.         DBG2("vaddr: 0x%08lx  name: %s\n", ProcAddr, (char*)ProcName);
  191.         if (!strcmp(Name,(char*)ProcName)) {
  192.             if (!(ProcAddr = dGetLinearAddress(Pe,ProcAddr))) {
  193.                 DBG0("ERROR: entry point not found!\n");
  194.             }
  195.             return (FARPROC)ProcAddr;
  196.         }
  197.     }
  198.     DBG0("procedure not found!\n");
  199.     return NULL;
  200. }
  201.  
  202.  
  203. /****************************************************************************
  204. *
  205. * Function:     dLoadLibrary
  206. * Parameters:   Filename    - PE dynamic link library path name
  207. *
  208. * Returns:      PE dynamic link library handler or NULL if error.
  209. *
  210. * Description:  This routine load Portable Executable (PE) dynamic link
  211. *               libraries from disk. This loader is not complete and have
  212. *               not been fully tested yet.
  213. *
  214. ****************************************************************************/
  215.  
  216. HANDLE dLoadLibrary(char *Filename)
  217. {
  218.     DOSHDR DosHdr;
  219.     HANDLE Pe;
  220.     PESCN *Scn;
  221.     int Handle,I;
  222.  
  223.     DBG0("opening DLL library file.\n");
  224.     if ((Handle = open(Filename,O_RDONLY|O_BINARY)) < 0)
  225.         return NULL;
  226.     if (!(Pe = (HANDLE)calloc(1,sizeof(PEDLL)))) {
  227.         close(Handle);
  228.         return NULL;
  229.     }
  230.  
  231.     DBG0("reading MS-DOS executable header.\n");
  232.     if (read(Handle,&DosHdr,sizeof(DosHdr)) != sizeof(DosHdr)) {
  233.         dFreeLibrary(Pe);
  234.         close(Handle);
  235.         return NULL;
  236.     }
  237.     if (DosHdr.Magic != DOS_MAGIC ||
  238.             lseek(Handle,DosHdr.NewHdrPtr,SEEK_SET) < 0) {
  239.         dFreeLibrary(Pe);
  240.         close(Handle);
  241.         return NULL;
  242.     }
  243.  
  244.     DBG0("reading PE executable headers.\n");
  245.     if (read(Handle,&Pe->Hdr,sizeof(PEHDR)) != sizeof(PEHDR)) {
  246.         dFreeLibrary(Pe);
  247.         close(Handle);
  248.         return NULL;
  249.     }
  250.     if (read(Handle,&Pe->NtHdr,sizeof(PENTHDR)) != sizeof(PENTHDR)) {
  251.         dFreeLibrary(Pe);
  252.         close(Handle);
  253.         return NULL;
  254.     }
  255.     if (Pe->Hdr.Magic != PE_MAGIC || Pe->Hdr.Machine != PE_M_I386 ||
  256.             !(Pe->Hdr.Flags & PE_F_DLL) || !(Pe->Hdr.Flags & PE_F_EXEC) ||
  257.             !(Pe->Hdr.Flags & PE_F_AR32WR) ||
  258.             lseek(Handle,Pe->Hdr.NtHdrSize-sizeof(PENTHDR),SEEK_CUR) < 0) {
  259.         dFreeLibrary(Pe);
  260.         close(Handle);
  261.         return NULL;
  262.     }
  263.  
  264.     DBG0("reading PE section headers.\n");
  265.     if (!(Pe->Scn = (PESCN*)calloc(Pe->Hdr.NumScns,sizeof(PESCN)))) {
  266.         dFreeLibrary(Pe);
  267.         close(Handle);
  268.         return NULL;
  269.     }
  270.     if (read(Handle,Pe->Scn,Pe->Hdr.NumScns*sizeof(PESCN)) !=
  271.             Pe->Hdr.NumScns*sizeof(PESCN)) {
  272.         memset(Pe->Scn,0,Pe->Hdr.NumScns*sizeof(PESCN));
  273.         dFreeLibrary(Pe);
  274.         close(Handle);
  275.         return NULL;
  276.     }
  277.  
  278.     DBG0("reading PE section images.\n");
  279.     for (I = 0; I < Pe->Hdr.NumScns; I++)
  280.         Pe->Scn[I].PAddr = 0;
  281.     for (I = 0, Scn = Pe->Scn; I < Pe->Hdr.NumScns; I++, Scn++) {
  282.         DBG2("reading PE section '%s' (0x%08lx bytes)\n",
  283.             Scn->Name, Scn->Size);
  284.         if (!Scn->Size)
  285.             continue;
  286.         if (!(Scn->PAddr = (DWORD)malloc(Scn->Size))) {
  287.             dFreeLibrary(Pe);
  288.             close(Handle);
  289.             return NULL;
  290.         }
  291.         if (lseek(Handle,Scn->ScnPtr,SEEK_SET) < 0) {
  292.             dFreeLibrary(Pe);
  293.             close(Handle);
  294.             return NULL;
  295.         }
  296.         if (read(Handle,(void*)Scn->PAddr,Scn->Size) != Scn->Size) {
  297.             dFreeLibrary(Pe);
  298.             close(Handle);
  299.             return NULL;
  300.         }
  301.     }
  302.     DBG0("closing DLL library file.\n");
  303.     close(Handle);
  304.     return dRelocateLibrary(Pe);
  305. }
  306.  
  307.  
  308. /****************************************************************************
  309. *
  310. * Function:     dFreeLibrary
  311. * Parameters:   Pe      - PE library handler
  312. *
  313. * Description:  This routine releases the memory used by PE DLL modules.
  314. *
  315. ****************************************************************************/
  316.  
  317. void dFreeLibrary(HANDLE Pe)
  318. {
  319.     int I;
  320.  
  321.     DBG0("releasing DLL library from memory.\n");
  322.     if (Pe) {
  323.         if (Pe->Scn) {
  324.             for (I = 0; I < Pe->Hdr.NumScns; I++)
  325.                 if (Pe->Scn[I].PAddr) free((void*)Pe->Scn[I].PAddr);
  326.             free(Pe->Scn);
  327.         }
  328.         free(Pe);
  329.     }
  330. }
  331.  
  332.  
  333. /****************************************************************************
  334. *
  335. * Function:     dLoadDriver
  336. * Parameters:   SC      - soundcard structure
  337. *
  338. * Returns:      Audio Driver structure or NULL if error.
  339. *
  340. * Description:  Used to load dynamic link audio drivers from disk. It uses
  341. *               the Portable Executable (PE) dynamic link loader.
  342. *
  343. ****************************************************************************/
  344.  
  345. Driver *dLoadDriver(SoundCard *SC)
  346. {
  347.     HANDLE H;
  348.     FARPROC DrvProc;
  349.     Driver *DrvPtr;
  350.  
  351.     if (!(DrvPtr = dGetDriverStruc(SC->ID))) {
  352.         if (!(H = dLoadLibrary(SC->DriverName)))
  353.             return NULL;
  354.         if (!(DrvProc = dGetProcAddress(H,"DriverProc"))) {
  355.             dFreeLibrary(H);
  356.             return NULL;
  357.         }
  358.         DrvPtr = (Driver*)(*DrvProc)();
  359.     }
  360.     return DrvPtr;
  361. }
  362.