3 * Portable Executable Loader
\r
11 // === PROTOTYPES ===
\r
12 int PE_Install(char **Arguments);
\r
13 tBinary *PE_Load(int fp);
\r
14 tBinary *MZ_Open(int fp);
\r
15 int PE_Relocate(void *Base);
\r
16 int PE_GetSymbol(void *Base, char *Name, Uint *Ret);
\r
19 MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL);
\r
20 char *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so";
\r
21 tBinaryType gPE_Loader = {
\r
23 ('M'|('Z'<<8)), 0xFFFF, // 'MZ'
\r
25 PE_Load, PE_Relocate, PE_GetSymbol
\r
29 int PE_Install(char **Arguments)
\r
31 Binary_RegisterType(&gPE_Loader);
\r
32 return MODULE_ERR_OK;
\r
36 * \brief Loads a PE Binary
\r
38 tBinary *PE_Load(int FP)
\r
43 tPE_DOS_HEADER dosHdr;
\r
44 tPE_IMAGE_HEADERS peHeaders;
\r
45 tPE_SECTION_HEADER *peSections;
\r
46 char namebuf[9] = {0};
\r
51 // Read DOS header and check
\r
52 VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr);
\r
53 if( dosHdr.Ident != ('M'|('Z'<<8)) ) {
\r
59 VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);
\r
60 if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {
\r
65 VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);
\r
67 // - Check PE Signature and pass on to the MZ Loader if invalid
\r
68 if( peHeaders.Signature != (('P')|('E'<<8)) ) {
\r
74 // Read Sections (Uses `count` as a temp variable)
\r
75 count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount;
\r
76 peSections = malloc( count );
\r
79 Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);
\r
83 VFS_Read(FP, count, peSections);
\r
86 iPageCount = 1; // 1st page is headers
\r
87 for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )
\r
89 // Check if the section is loadable
\r
90 // (VA is zero in non-loadable sections)
\r
91 if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0) continue;
\r
94 iPageCount += (peSections[i].VirtualSize + 0xFFF) >> 12;
\r
97 LOG("%i Pages", iPageCount);
\r
99 // Initialise Executable Information
\r
100 ret = malloc(sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount);
\r
102 ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase;
\r
103 ret->Base = peHeaders.OptHeader.ImageBase;
\r
104 ret->Interpreter = gsPE_DefaultInterpreter;
\r
105 ret->NumPages = iPageCount;
\r
107 LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);
\r
109 ret->Pages[0].Virtual = peHeaders.OptHeader.ImageBase;
\r
110 ret->Pages[0].Physical = 0;
\r
111 ret->Pages[0].Size = 4096;
\r
112 ret->Pages[0].Flags = 0;
\r
115 j = 1; // Page Index
\r
116 for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )
\r
118 iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;
\r
120 // Skip non-loadable sections
\r
121 if(iVA == 0) continue;
\r
123 // Create Name Buffer
\r
124 memcpy(namebuf, peSections[i].Name, 8);
\r
125 LOG("Section %i '%s', iVA = %p", i, namebuf, iVA);
\r
129 if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE)
\r
130 iFlags |= BIN_PAGEFLAG_EXEC;
\r
131 if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) )
\r
132 iFlags |= BIN_PAGEFLAG_RO;
\r
134 // Create Page Listing
\r
135 count = (peSections[i].RawSize + 0xFFF) >> 12;
\r
136 for(k=0;k<count;k++)
\r
138 ret->Pages[j+k].Virtual = iVA + (k<<12);
\r
139 ret->Pages[j+k].Physical = peSections[i].RawOffs + (k<<12); // Store the offset in the physical address
\r
140 if(k == count-1 && (peSections[i].RawSize & 0xFFF))
\r
141 ret->Pages[j+k].Size = peSections[i].RawSize & 0xFFF; // Byte count in page
\r
143 ret->Pages[j+k].Size = 4096;
\r
144 ret->Pages[j+k].Flags = iFlags;
\r
146 count = (peSections[i].VirtualSize + 0xFFF) >> 12;
\r
149 ret->Pages[j+k].Virtual = iVA + (k<<12);
\r
150 ret->Pages[j+k].Physical = -1; // -1 = Fill with zeros
\r
151 if(k == count-1 && (peSections[i].VirtualSize & 0xFFF))
\r
152 ret->Pages[j+k].Size = peSections[i].VirtualSize & 0xFFF; // Byte count in page
\r
154 ret->Pages[j+k].Size = 4096;
\r
155 ret->Pages[j+k].Flags = iFlags;
\r
159 LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",
\r
162 peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,
\r
163 peSections[i].Flags
\r
167 // Free Executable Memory
\r
176 tBinary *MZ_Open(int FP)
\r
184 int PE_Relocate(void *Base)
\r
186 tPE_DOS_HEADER *dosHdr;
\r
187 tPE_IMAGE_HEADERS *peHeaders;
\r
188 tPE_SECTION_HEADER *peSections;
\r
189 tPE_DATA_DIR *directory;
\r
190 tPE_IMPORT_DIR *impDir;
\r
192 Uint iBase = (Uint)Base;
\r
198 ENTER("pBase", Base);
\r
200 peHeaders = (void*)( iBase + dosHdr->PeHdrOffs );
\r
201 LOG("Prefered Base %p", peHeaders->OptHeader.ImageBase);
\r
202 peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) );
\r
204 directory = (void*)(peSections[0].RVA + iBase);
\r
206 // === Load Import Tables
\r
207 impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase );
\r
208 for( i = 0; impDir[i].DLLName != NULL; i++ )
\r
210 impDir[i].DLLName += iBase;
\r
211 impDir[i].ImportLookupTable += iBase/4;
\r
212 impDir[i].ImportAddressTable += iBase/4;
\r
213 LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName);
\r
215 libPath = FindLibrary(impDir[i].DLLName);
\r
216 if(libPath == NULL)
\r
218 Warning("PE_Relocate - Unable to find library '%s'");
\r
222 LOG("DLL Path = '%s'", libPath);
\r
223 hLibrary = DynLib_Load(libPath, 0);
\r
227 for(i=0;i<PE_DIR_LAST;i++)
\r
228 LOG("directory[%i] = {RVA=0x%x,Size=0x%x}", i, directory[i].RVA, directory[i].Size);
\r
234 int PE_GetSymbol(void *Base, char *Name, Uint *Ret)
\r