Changes to the module loader to handle specific errors from modules
[tpg/acess2.git] / Kernel / bin / pe.c
1 /*\r
2  * Acess v1\r
3  * Portable Executable Loader\r
4  */\r
5 #define DEBUG   1\r
6 #include <acess.h>\r
7 #include <binary.h>\r
8 #include <modules.h>\r
9 #include "pe.h"\r
10 \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
17 \r
18 // === GLOBALS ===\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
22         NULL,\r
23         ('M'|('Z'<<8)), 0xFFFF, // 'MZ'\r
24         "PE/DOS",\r
25         PE_Load, PE_Relocate, PE_GetSymbol\r
26         };\r
27 \r
28 // === CODE ===\r
29 int PE_Install(char **Arguments)\r
30 {\r
31         Binary_RegisterType(&gPE_Loader);\r
32         return MODULE_ERR_OK;\r
33 }\r
34 \r
35 /**\r
36  * \brief Loads a PE Binary\r
37  */\r
38 tBinary *PE_Load(int FP)\r
39 {\r
40          int    count, i, j, k;\r
41          int    iPageCount;\r
42         tBinary *ret;\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
47         Uint    iFlags, iVA;\r
48         \r
49         ENTER("xFP", FP);\r
50         \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
54                 LEAVE('n');\r
55                 return NULL;\r
56         }\r
57         \r
58         // - Read PE Header\r
59         VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);\r
60         if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {\r
61                 ret = MZ_Open(FP);\r
62                 LEAVE('p', ret);\r
63                 return ret;\r
64         }\r
65         VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);\r
66         \r
67         // - Check PE Signature and pass on to the MZ Loader if invalid\r
68         if( peHeaders.Signature != (('P')|('E'<<8)) ) {\r
69                 ret = MZ_Open(FP);\r
70                 LEAVE('p', ret);\r
71                 return ret;\r
72         }\r
73         \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
77         if(!peSections)\r
78         {\r
79                 Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);\r
80                 LEAVE('n');\r
81                 return NULL;\r
82         }\r
83         VFS_Read(FP, count, peSections);\r
84         \r
85         // Count Pages\r
86         iPageCount = 1; // 1st page is headers\r
87         for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
88         {\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
92                 \r
93                 // Moar pages\r
94                 iPageCount += (peSections[i].VirtualSize + 0xFFF) >> 12;\r
95         }\r
96         \r
97         LOG("%i Pages", iPageCount);\r
98         \r
99         // Initialise Executable Information\r
100         ret = malloc(sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount);\r
101         \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
106         \r
107         LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);\r
108         \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
113         \r
114         // Parse Sections\r
115         j = 1;  // Page Index\r
116         for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )\r
117         {\r
118                 iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;\r
119                 \r
120                 // Skip non-loadable sections\r
121                 if(iVA == 0)    continue;\r
122                 \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
126                 \r
127                 // Create Flags\r
128                 iFlags = 0;\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
133                 \r
134                 // Create Page Listing\r
135                 count = (peSections[i].RawSize + 0xFFF) >> 12;\r
136                 for(k=0;k<count;k++)\r
137                 {\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
142                         else\r
143                                 ret->Pages[j+k].Size = 4096;\r
144                         ret->Pages[j+k].Flags = iFlags;\r
145                 }\r
146                 count = (peSections[i].VirtualSize + 0xFFF) >> 12;\r
147                 for(;k<count;k++)\r
148                 {\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
153                         else\r
154                                 ret->Pages[j+k].Size = 4096;\r
155                         ret->Pages[j+k].Flags = iFlags;\r
156                 }\r
157                 j += count;\r
158                 \r
159                 LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",\r
160                         i, namebuf, \r
161                         iVA,\r
162                         peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,\r
163                         peSections[i].Flags\r
164                         );\r
165                 \r
166         }\r
167         // Free Executable Memory\r
168         free(peSections);\r
169         \r
170         LEAVE('p', ret);\r
171         return ret;\r
172 }\r
173 \r
174 /**\r
175  */\r
176 tBinary *MZ_Open(int FP)\r
177 {\r
178         ENTER("xFP", FP);\r
179         UNIMPLEMENTED();\r
180         LEAVE('n');\r
181         return NULL;\r
182 }\r
183 \r
184 int PE_Relocate(void *Base)\r
185 {\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
191          int    i;\r
192         Uint    iBase = (Uint)Base;\r
193         #if 0\r
194         void    *hLibrary;\r
195         char    *libPath;\r
196         #endif\r
197         \r
198         ENTER("pBase", Base);\r
199         dosHdr = 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
203         \r
204         directory = (void*)(peSections[0].RVA + iBase);\r
205         \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
209         {\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
214                 #if 0\r
215                 libPath = FindLibrary(impDir[i].DLLName);\r
216                 if(libPath == NULL)\r
217                 {\r
218                         Warning("PE_Relocate - Unable to find library '%s'");\r
219                         LEAVE('i', -1);\r
220                         return -1;\r
221                 }\r
222                 LOG("DLL Path = '%s'", libPath);\r
223                 hLibrary = DynLib_Load(libPath, 0);\r
224                 #endif\r
225         }\r
226         \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
229         \r
230         LEAVE('i', 0);\r
231         return 0;\r
232 }\r
233 \r
234 int PE_GetSymbol(void *Base, char *Name, Uint *Ret)\r
235 {\r
236         return 0;\r
237 }\r

UCC git Repository :: git.ucc.asn.au