source: trunk/kLdr/kLdrModLX.c@ 2887

Last change on this file since 2887 was 2887, checked in by bird, 19 years ago

Bugfixing.

  • Property svn:keywords set to Id
File size: 64.0 KB
RevLine 
[2826]1/* $Id: kLdrModLX.c 2887 2006-11-18 15:37:00Z bird $ */
[2821]2/** @file
3 *
[2879]4 * kLdr - The Module Interpreter for the Linear eXecutable (LX) Format.
[2821]5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
[2827]27
[2879]28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModLX.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODLX_STRICT
41 * Define KLDRMODLX_STRICT to enabled strict checks in KLDRMODLX. */
42#define KLDRMODLX_STRICT 1
43
44/** @def KLDRMODLX_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODLX_STRICT
48# define KLDRMODLX_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODLX_ASSERT(expr) do {} while (0)
51#endif
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/**
58 * Instance data for the LX module interpreter.
59 */
60typedef struct KLDRMODLX
61{
62 /** Pointer to the module. (Follows the section table.) */
63 PKLDRMOD pMod;
64 /** Pointer to the user mapping. */
65 const void *pvMapping;
66 /** The size of the mapped LX image. */
67 size_t cbMapped;
68 /** Reserved flags. */
69 uint32_t f32Reserved;
70
71 /** The offset of the LX header. */
72 off_t offHdr;
73 /** Copy of the LX header. */
74 struct e32_exe Hdr;
75
76 /** Pointer to the loader section.
77 * Allocated together with this strcture. */
78 const uint8_t *pbLoaderSection;
79 /** Pointer to the last byte in the loader section. */
80 const uint8_t *pbLoaderSectionLast;
81 /** Pointer to the object table in the loader section. */
82 const struct o32_obj *paObjs;
83 /** Pointer to the object page map table in the loader section. */
84 const struct o32_map *paPageMappings;
85 /** Pointer to the resource table in the loader section. */
86 const struct rsrc32 *paRsrcs;
87 /** Pointer to the resident name table in the loader section. */
88 const uint8_t *pbResNameTab;
89 /** Pointer to the entry table in the loader section. */
90 const uint8_t *pbEntryTab;
91
92 /** Pointer to the non-resident name table. */
93 uint8_t *pbNonResNameTab;
94 /** Pointer to the last byte in the non-resident name table. */
95 const uint8_t *pbNonResNameTabLast;
96
97 /** Pointer to the fixup section. */
98 uint8_t *pbFixupSection;
99 /** Pointer to the last byte in the fixup section. */
100 const uint8_t *pbFixupSectionLast;
101 /** Pointer to the fixup page table within pvFixupSection. */
102 const uint32_t *paoffPageFixups;
103 /** Pointer to the fixup record table within pvFixupSection. */
104 const uint8_t *pbFixupRecs;
105 /** Pointer to the import module name table within pvFixupSection. */
106 const uint8_t *pbImportMods;
107 /** Pointer to the import module name table within pvFixupSection. */
108 const uint8_t *pbImportProcs;
109} KLDRMODLX, *PKLDRMODLX;
110
111
112/*******************************************************************************
113* Internal Functions *
114*******************************************************************************/
115static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits);
116static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
118static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX);
[2882]119static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal);
120static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pszSymbol, uint32_t *piSymbol);
121static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
122 char *pchSymbol, size_t cchSymbol);
[2879]123static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits);
[2880]124static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
125static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc);
126static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb);
[2879]127static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect);
128static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle);
[2882]129static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
130 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
131static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX);
[2879]132static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
133
134
135/**
136 * Create a loader module instance interpreting the executable image found
137 * in the specified file provider instance.
138 *
139 * @returns 0 on success and *ppMod pointing to a module instance.
140 * On failure, a non-zero OS specific error code is returned.
141 * @param pOps Pointer to the registered method table.
142 * @param pRdr The file provider instance to use.
143 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
144 * @param ppMod Where to store the module instance pointer.
145 */
146static int kldrModLXCreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
147{
148 PKLDRMODLX pModLX;
149 int rc;
150
151 /*
152 * Create the instance data and do a minimal header validation.
153 */
154 rc = kldrModLXDoCreate(pRdr, offNewHdr, &pModLX);
155 if (!rc)
156 {
157 pModLX->pMod->pOps = pOps;
158 pModLX->pMod->u32Magic = KLDRMOD_MAGIC;
159 *ppMod = pModLX->pMod;
160 return 0;
161 }
162 kldrHlpFree(pModLX);
163 return rc;
164}
165
166
167/**
168 * Separate function for reading creating the LX module instance to
169 * simplify cleanup on failure.
170 */
171static int kldrModLXDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODLX *ppModLX)
172{
173 struct e32_exe Hdr;
174 PKLDRMODLX pModLX;
175 PKLDRMOD pMod;
176 size_t cb;
177 size_t cchFilename;
178 uint32_t off, offEnd;
179 uint32_t i;
180 int rc;
181 *ppModLX = NULL;
182
183 /*
184 * Read the signature and file header.
185 */
186 rc = kLdrRdrRead(pRdr, &Hdr, sizeof(Hdr), offNewHdr > 0 ? offNewHdr : 0);
187 if (rc)
188 return rc;
[2886]189 if ( Hdr.e32_magic[0] != E32MAGIC1
190 || Hdr.e32_magic[1] != E32MAGIC2)
[2879]191 return KLDR_ERR_UNKNOWN_FORMAT;
192
193 /* We're not interested in anything but x86 images. */
194 if ( Hdr.e32_level != E32LEVEL
195 || Hdr.e32_border != E32LEBO
196 || Hdr.e32_worder != E32LEWO
197 || Hdr.e32_cpu < E32CPU286
198 || Hdr.e32_cpu > E32CPU486
199 || Hdr.e32_pagesize != OBJPAGELEN
200 )
201 return KLDR_ERR_LX_BAD_HEADER;
202
203 /* Some rough sanity checks. */
204 offEnd = kLdrRdrSize(pRdr) >= (off_t)~(uint32_t)16 ? ~(uint32_t)16 : (uint32_t)kLdrRdrSize(pRdr);
205 if ( Hdr.e32_itermap > offEnd
206 || Hdr.e32_datapage > offEnd
207 || Hdr.e32_nrestab > offEnd
208 || Hdr.e32_nrestab + Hdr.e32_cbnrestab > offEnd
209 || Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr)
210 || Hdr.e32_fixupsize > offEnd - offNewHdr - sizeof(Hdr)
211 || Hdr.e32_fixupsize + Hdr.e32_ldrsize > offEnd - offNewHdr - sizeof(Hdr))
212 return KLDR_ERR_LX_BAD_HEADER;
213
214 /* Verify the loader section. */
215 offEnd = Hdr.e32_objtab + Hdr.e32_ldrsize;
216 if (Hdr.e32_objtab < sizeof(Hdr))
217 return KLDR_ERR_LX_BAD_LOADER_SECTION;
218 off = Hdr.e32_objtab + sizeof(struct o32_obj) * Hdr.e32_objcnt;
219 if (off > offEnd)
220 return KLDR_ERR_LX_BAD_LOADER_SECTION;
221 if ( Hdr.e32_objmap
222 && (Hdr.e32_objmap < off || Hdr.e32_objmap > offEnd))
223 return KLDR_ERR_LX_BAD_LOADER_SECTION;
224 if ( Hdr.e32_rsrccnt
225 && ( Hdr.e32_rsrctab < off
226 || Hdr.e32_rsrctab > offEnd
227 || Hdr.e32_rsrctab + sizeof(struct rsrc32) * Hdr.e32_rsrccnt > offEnd))
228 return KLDR_ERR_LX_BAD_LOADER_SECTION;
229 if ( Hdr.e32_restab
230 && (Hdr.e32_restab < off || Hdr.e32_restab > offEnd - 2))
231 return KLDR_ERR_LX_BAD_LOADER_SECTION;
232 if ( Hdr.e32_enttab
233 && (Hdr.e32_enttab < off || Hdr.e32_enttab > offEnd - 2))
234 return KLDR_ERR_LX_BAD_LOADER_SECTION;
235 if ( Hdr.e32_dircnt
236 && (Hdr.e32_dirtab < off || Hdr.e32_dirtab > offEnd))
237 return KLDR_ERR_LX_BAD_LOADER_SECTION;
238
239 /* Verify the fixup section. */
240 off = offEnd;
241 offEnd = off + Hdr.e32_fixupsize;
242 if ( Hdr.e32_fpagetab
243 && (Hdr.e32_fpagetab < off || Hdr.e32_fpagetab > offEnd))
244 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
245 if ( Hdr.e32_frectab
246 && (Hdr.e32_frectab < off || Hdr.e32_frectab > offEnd))
247 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
248 if ( Hdr.e32_impmod
249 && (Hdr.e32_impmod < off || Hdr.e32_impmod > offEnd || Hdr.e32_impmod + Hdr.e32_impmodcnt > offEnd))
250 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
251 if ( Hdr.e32_impproc
252 && (Hdr.e32_impproc < off || Hdr.e32_impproc > offEnd))
253 return KLDR_ERR_LX_BAD_FIXUP_SECTION;
254
255 /*
256 * Calc the instance size, allocate and initialize it.
257 */
258 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
259 cb = KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8)
260 + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMOD, aSegments[Hdr.e32_objcnt + 1]), 8)
[2883]261 + KLDR_ALIGN_Z(cchFilename + 1, 8)
[2879]262 + Hdr.e32_ldrsize;
263 pModLX = (PKLDRMODLX)kldrHlpAlloc(cb);
264 if (!pModLX)
265 return KLDR_ERR_NO_MEMORY;
266 *ppModLX = pModLX;
267
268 /* KLDRMOD */
269 pMod = (PKLDRMOD)((uint8_t *)pModLX + KLDR_ALIGN_Z(sizeof(KLDRMODLX), 8));
270 pMod->pvData = pModLX;
271 pMod->pRdr = pRdr;
272 pMod->pOps = NULL; /* set upon success. */
273 pMod->cSegments = Hdr.e32_objcnt;
274 pMod->cchFilename = cchFilename;
275 pMod->pszFilename = (char *)KLDR_ALIGN_P(&pMod->aSegments[pMod->cSegments], 8);
276 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
277 pMod->pszName = NULL; /* finalized further down */
278 pMod->cchName = 0;
279 switch (Hdr.e32_cpu)
280 {
281 case E32CPU286:
282 pMod->enmCpu = KLDRCPU_I80286;
283 pMod->enmArch = KLDRARCH_X86_16;
284 break;
285 case E32CPU386:
286 pMod->enmCpu = KLDRCPU_I386;
287 pMod->enmArch = KLDRARCH_X86_32;
288 break;
289 case E32CPU486:
290 pMod->enmCpu = KLDRCPU_I486;
291 pMod->enmArch = KLDRARCH_X86_32;
292 break;
293 }
294 pMod->enmEndian = KLDRENDIAN_LITTLE;
295 pMod->enmFmt = KLDRFMT_LX;
296 switch (Hdr.e32_mflags & E32MODMASK)
297 {
298 case E32MODEXE:
299 pMod->enmType = !(Hdr.e32_mflags & E32NOINTFIX)
300 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
301 : KLDRTYPE_EXECUTABLE_FIXED;
302 break;
303
304 case E32MODDLL:
305 case E32PROTDLL:
306 case E32MODPROTDLL:
307 pMod->enmType = !(Hdr.e32_mflags & E32SYSDLL)
308 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
309 : KLDRTYPE_SHARED_LIBRARY_FIXED;
310 break;
311
312 case E32MODPDEV:
313 case E32MODVDEV:
314 pMod->enmType = KLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
315 break;
316 }
317 pMod->u32Magic = 0; /* set upon success. */
318
319 /* KLDRMODLX */
320 pModLX->pMod = pMod;
321 pModLX->pvMapping = 0;
322 pModLX->cbMapped = Hdr.e32_mpages * Hdr.e32_pagesize;
323 pModLX->f32Reserved = 0;
324
325 pModLX->offHdr = offNewHdr >= 0 ? offNewHdr : 0;
326 pModLX->Hdr = Hdr;
327
328 pModLX->pbLoaderSection = KLDR_ALIGN_P(pMod->pszFilename + pMod->cchFilename + 1, 16);
329 pModLX->pbLoaderSectionLast = pModLX->pbLoaderSection + pModLX->Hdr.e32_ldrsize;
330 pModLX->paObjs = NULL;
331 pModLX->paPageMappings = NULL;
332 pModLX->paRsrcs = NULL;
333 pModLX->pbResNameTab = NULL;
334 pModLX->pbEntryTab = NULL;
335
336 pModLX->pbNonResNameTab = NULL;
337 pModLX->pbNonResNameTabLast = NULL;
338
339 pModLX->pbFixupSection = NULL;
340 pModLX->pbFixupSectionLast = NULL;
341 pModLX->paoffPageFixups = NULL;
342 pModLX->pbFixupRecs = NULL;
343 pModLX->pbImportMods = NULL;
344 pModLX->pbImportProcs = NULL;
345
346 /*
347 * Read the loader data.
348 */
349 rc = kLdrRdrRead(pRdr, (void *)pModLX->pbLoaderSection, pModLX->Hdr.e32_ldrsize, pModLX->Hdr.e32_objtab + pModLX->offHdr);
350 if (rc)
351 return rc;
352 if (pModLX->Hdr.e32_objcnt)
353 pModLX->paObjs = (const struct o32_obj *)pModLX->pbLoaderSection;
354 if (pModLX->Hdr.e32_objmap)
355 pModLX->paPageMappings = (const struct o32_map *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_objmap - pModLX->Hdr.e32_objtab);
356 if (pModLX->Hdr.e32_rsrccnt)
357 pModLX->paRsrcs = (const struct rsrc32 *)(pModLX->pbLoaderSection + pModLX->Hdr.e32_rsrctab - pModLX->Hdr.e32_objtab);
358 if (pModLX->Hdr.e32_restab)
359 pModLX->pbResNameTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_restab - pModLX->Hdr.e32_objtab;
360 if (pModLX->Hdr.e32_enttab)
361 pModLX->pbEntryTab = pModLX->pbLoaderSection + pModLX->Hdr.e32_enttab - pModLX->Hdr.e32_objtab;
362
363 /*
364 * Get the soname from the resident name table.
[2882]365 * Very convenient that it's the 0 ordinal, because then we get a
366 * free string terminator.
367 * (The table entry consists of a pascal string followed by a 16-bit ordinal.)
[2879]368 */
[2883]369 pMod->pszName = (const char *)kldrModLXDoNameTableLookupByOrdinal(pModLX->pbResNameTab,
370 pModLX->pbLoaderSectionLast - pModLX->pbResNameTab + 1,
371 0);
[2882]372 if (!pMod->pszName)
373 return KLDR_ERR_LX_NO_SONAME;
374 pMod->cchName = *(const uint8_t *)pMod->pszName++;
375 if (pMod->cchName != kLdrHlpStrLen(pMod->pszName))
376 return KLDR_ERR_LX_BAD_SONAME;
[2879]377
378 /*
379 * Quick validation of the object table.
380 */
381 cb = 0;
382 for (i = 0; i < pMod->cSegments; i++)
383 {
384 if (pModLX->paObjs[i].o32_base & (OBJPAGELEN - 1))
385 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
386 if (pModLX->paObjs[i].o32_base + pModLX->paObjs[i].o32_size <= pModLX->paObjs[i].o32_base)
387 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
[2887]388 if (pModLX->paObjs[i].o32_mapsize > (pModLX->paObjs[i].o32_size + (OBJPAGELEN - 1)))
[2879]389 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
390 if ( pModLX->paObjs[i].o32_mapsize
391 && ( (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap] > pModLX->pbLoaderSectionLast
392 || (uint8_t *)&pModLX->paPageMappings[pModLX->paObjs[i].o32_pagemap + pModLX->paObjs[i].o32_mapsize]
393 > pModLX->pbLoaderSectionLast))
394 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
395 if (i > 0)
396 {
397 if (pModLX->paObjs[i].o32_base <= pModLX->paObjs[i - 1].o32_base)
398 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
399 if (pModLX->paObjs[i].o32_base < pModLX->paObjs[i - 1].o32_base + pModLX->paObjs[i - 1].o32_mapsize)
400 return KLDR_ERR_LX_BAD_OBJECT_TABLE;
401 }
402 }
403 pModLX->cbMapped = pMod->cSegments
404 ? pModLX->paObjs[pMod->cSegments - 1].o32_base + pModLX->paObjs[pMod->cSegments - 1].o32_size
405 - pModLX->paObjs[pMod->cSegments - 1].o32_size
406 : 0;
407
408 /*
409 * Setup the KLDRMOD segment array.
410 */
411 for (i = 0; i < pMod->cSegments; i++)
412 {
413 /* unused */
414 pMod->aSegments[i].pvUser = NULL;
415 pMod->aSegments[i].MapAddress = 0;
416 pMod->aSegments[i].pchName = NULL;
417 pMod->aSegments[i].cchName = 0;
418 pMod->aSegments[i].offFile = -1;
419 pMod->aSegments[i].cbFile = 0;
420
421 /* size and addresses */
422 pMod->aSegments[i].Alignment = OBJPAGELEN;
423 pMod->aSegments[i].cb = pModLX->paObjs[i].o32_size;
424 pMod->aSegments[i].LinkAddress = pModLX->paObjs[i].o32_base;
425 pMod->aSegments[i].RVA = pModLX->paObjs[i].o32_base - pModLX->paObjs[0].o32_base;
426 pMod->aSegments[i].cbMapped = KLDR_ALIGN_Z(pModLX->paObjs[i].o32_size, 16);
427 if (i + 1 < pMod->cSegments)
428 pMod->aSegments[i].cbMapped = pModLX->paObjs[i + 1].o32_base - pModLX->paObjs[i].o32_base;
429
430 /* protection */
431 switch ( pModLX->paObjs[i].o32_flags
432 & (OBJSHARED | OBJREAD | OBJWRITE | OBJEXEC))
433 {
434 case 0:
435 case OBJSHARED:
436 pMod->aSegments[i].enmProt = KLDRPROT_NOACCESS;
437 break;
438 case OBJREAD:
439 case OBJREAD | OBJSHARED:
440 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
441 break;
442 case OBJWRITE:
443 case OBJWRITE | OBJREAD:
444 pMod->aSegments[i].enmProt = KLDRPROT_WRITECOPY;
445 break;
446 case OBJWRITE | OBJSHARED:
447 case OBJWRITE | OBJSHARED | OBJREAD:
448 pMod->aSegments[i].enmProt = KLDRPROT_READWRITE;
449 break;
450 case OBJEXEC:
451 case OBJEXEC | OBJSHARED:
452 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE;
453 break;
454 case OBJEXEC | OBJREAD:
455 case OBJEXEC | OBJREAD | OBJSHARED:
456 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READ;
457 break;
458 case OBJEXEC | OBJWRITE:
459 case OBJEXEC | OBJWRITE | OBJREAD:
460 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
461 break;
462 case OBJEXEC | OBJWRITE | OBJSHARED:
463 case OBJEXEC | OBJWRITE | OBJSHARED | OBJREAD:
464 pMod->aSegments[i].enmProt = KLDRPROT_EXECUTE_READWRITE;
465 break;
466 }
467 if ((pModLX->paObjs[i].o32_flags & (OBJREAD | OBJWRITE | OBJEXEC | OBJRSRC)) == OBJRSRC)
468 pMod->aSegments[i].enmProt = KLDRPROT_READONLY;
[2883]469 /*pMod->aSegments[i].f16bit = !(pModLX->paObjs[i].o32_flags & OBJBIGDEF)
470 pMod->aSegments[i].fIOPL = !(pModLX->paObjs[i].o32_flags & OBJIOPL)
471 pMod->aSegments[i].fConforming = !(pModLX->paObjs[i].o32_flags & OBJCONFORM) */
[2879]472 }
473
474 /*
475 * We're done.
476 */
477 *ppModLX = pModLX;
478 return 0;
479}
480
481
482/** @copydoc KLDRMODOPS::pfnDestroy */
483static int kldrModLXDestroy(PKLDRMOD pMod)
484{
485 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
486 int rc = 0;
487 KLDRMODLX_ASSERT(pModLX->pvMapping);
488
489 if (pMod->pRdr)
490 {
491 rc = kLdrRdrClose(pMod->pRdr);
492 pMod->pRdr = NULL;
493 }
494 if (pModLX->pbNonResNameTab)
495 {
496 kldrHlpFree(pModLX->pbNonResNameTab);
497 pModLX->pbNonResNameTab = NULL;
498 }
499 if (pModLX->pbFixupSection)
500 {
501 kldrHlpFree(pModLX->pbFixupSection);
502 pModLX->pbFixupSection = NULL;
503 }
504 pMod->u32Magic = 0;
505 pMod->pOps = NULL;
506 kldrHlpFree(pModLX);
507 return rc;
508}
509
510
511/**
512 * Resolved base address aliases.
513 *
514 * @param pModLX The interpreter module instance
515 * @param pBaseAddress The base address, IN & OUT.
516 */
517static void kldrModLXResolveBaseAddress(PKLDRMODLX pModLX, PKLDRADDR pBaseAddress)
518{
519 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
520 *pBaseAddress = pModLX->pMod->aSegments[0].MapAddress;
521 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
522 *pBaseAddress = pModLX->pMod->aSegments[0].LinkAddress;
523}
524
525
526/** @copydoc kLdrModQuerySymbol */
527static int kldrModLXQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
528 const char *pszSymbol, PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser,
529 PKLDRADDR puValue, uint32_t *pfKind)
530{
[2882]531 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
532 uint32_t iOrdinal;
533 int rc;
534 const struct b32_bundle *pBundle;
[2879]535
536
[2882]537 /*
538 * Give up at once if there is no entry table.
539 */
540 if (!pModLX->Hdr.e32_enttab)
541 return KLDR_ERR_SYMBOL_NOT_FOUND;
542
543 /*
544 * Translate the symbol name into an ordinal.
545 */
546 if (pszSymbol)
547 {
548 rc = kldrModLXDoNameLookup(pModLX, pszSymbol, &iSymbol);
549 if (rc)
550 return rc;
551 }
552
553 /*
554 * Iterate the entry table.
555 * (The entry table is made up of bundles of similar exports.)
556 */
557 iOrdinal = 0;
558 pBundle = (const struct b32_bundle *)pModLX->pbEntryTab;
559 while (!pBundle->b32_cnt && iOrdinal <= iSymbol)
560 {
561 static const size_t s_cbEntry[] = { 0, 3, 5, 5, 7 };
562
563 /*
564 * Check for a hit first.
565 */
566 iOrdinal += pBundle->b32_cnt;
567 if (iSymbol < iOrdinal)
568 {
569 uint32_t offObject;
570 const struct e32_entry *pEntry = (const struct e32_entry *)((uintptr_t)(pBundle + 1)
571 + iSymbol - (iOrdinal - pBundle->b32_cnt));
572
573 /*
574 * Calculate the return address.
575 */
576 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
577 switch (pBundle->b32_type)
578 {
579 /* empty bundles are place holders unused ordinal ranges. */
580 case EMPTY:
581 return KLDR_ERR_SYMBOL_NOT_FOUND;
582
583 /* e32_flags + a 16-bit offset. */
584 case ENTRY16:
585 offObject = pEntry->e32_variant.e32_offset.offset16;
586 if (pfKind)
587 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_NO_TYPE;
588 break;
589
590 /* e32_flags + a 16-bit offset + a 16-bit callgate selector. */
591 case GATE16:
592 offObject = pEntry->e32_variant.e32_callgate.offset;
593 if (pfKind)
594 *pfKind = KLDRSYMKIND_16BIT | KLDRSYMKIND_CODE;
595 break;
596
597 /* e32_flags + a 32-bit offset. */
598 case ENTRY32:
599 offObject = pEntry->e32_variant.e32_offset.offset32;
600 if (pfKind)
601 *pfKind = KLDRSYMKIND_32BIT;
602 break;
603
604 /* e32_flags + 16-bit import module ordinal + a 32-bit procname or ordinal. */
605 case ENTRYFWD:
606 return kldrModLXDoForwarderQuery(pModLX, pEntry, pfnGetForwarder, pvUser, puValue, pfKind);
607
608 default:
609 /* anyone actually using TYPEINFO will end up here. */
610 KLDRMODLX_ASSERT(!"Bad bundle type");
611 break;
612 }
613
614 /*
615 * Validate the object number and calc the return address.
616 */
617 if ( pBundle->b32_obj <= 0
618 || pBundle->b32_obj > pMod->cSegments)
619 return KLDR_ERR_LX_BAD_BUNDLE;
620 if (puValue)
621 *puValue = BaseAddress
622 + offObject
623 + pMod->aSegments[pBundle->b32_obj - 1].RVA;
624 return 0;
625 }
626
627 /*
628 * Skip the bundle.
629 */
630 if (pBundle->b32_type > ENTRYFWD)
631 {
632 KLDRMODLX_ASSERT(!"Bad type"); /** @todo figure out TYPEINFO. */
633 return KLDR_ERR_LX_BAD_BUNDLE;
634 }
635 if (pBundle->b32_type == 0)
636 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + 2);
637 else
638 pBundle = (const struct b32_bundle *)((const uint8_t *)pBundle + s_cbEntry[pBundle->b32_type] * pBundle->b32_cnt);
639 }
640
641 return KLDR_ERR_SYMBOL_NOT_FOUND;
642}
643
644
645/**
646 * Do name lookup.
647 *
648 * @returns See kLdrModQuerySymbol.
649 * @param pModLX The module to lookup the symbol in.
650 * @param pszSymbol The symbol to lookup.
651 * @param piSymbol Where to store the symbol ordinal.
652 */
653static int kldrModLXDoNameLookup(PKLDRMODLX pModLX, const char *pszSymbol, uint32_t *piSymbol)
654{
655
656 /*
657 * First do a hash table lookup.
658 */
659
660
661
662 /*
663
664 */
665
[2879]666 return -1;
667}
668
669
[2882]670/**
671 * Hash a symbol using the algorithm from sdbm.
672 *
673 * The following was is the documenation of the orignal sdbm functions:
674 *
675 * This algorithm was created for sdbm (a public-domain reimplementation of
676 * ndbm) database library. it was found to do well in scrambling bits,
677 * causing better distribution of the keys and fewer splits. it also happens
678 * to be a good general hashing function with good distribution. the actual
679 * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
680 * is the faster version used in gawk. [there is even a faster, duff-device
681 * version] the magic constant 65599 was picked out of thin air while
682 * experimenting with different constants, and turns out to be a prime.
683 * this is one of the algorithms used in berkeley db (see sleepycat) and
684 * elsewhere.
685 */
686static uint32_t kldrModLXDoHash(const char *pchSymbol, uint8_t cchSymbol)
687{
688 uint32_t hash = 0;
689 int ch;
690
691 while ( cchSymbol-- > 0
692 && (ch = *(unsigned const char *)pchSymbol++))
693 hash = ch + (hash << 6) + (hash << 16) - hash;
694
695 return hash;
696}
697
698
699/**
700 * Lookup a name table entry by name.
701 *
702 * @returns Pointer to the name table entry if found.
703 * @returns NULL if not found.
704 * @param pbNameTable Pointer to the name table that should be searched.
705 * @param cbNameTable The size of the name table.
706 * @param pchSymbol The name of the symbol we're looking for.
707 * @param cchSymbol The length of the symbol name.
708 */
709static const uint8_t *kldrModLXDoNameTableLookupByName(const uint8_t *pbNameTable, int32_t cbNameTable,
710 char *pchSymbol, size_t cchSymbol)
711{
712 /*
713 * Determin the namelength up front so we can skip anything which doesn't matches the length.
714 */
715 uint8_t cbSymbol8Bit = (uint8_t)cchSymbol;
716 if (cbSymbol8Bit != cchSymbol)
717 return NULL; /* too long. */
718
719 /*
720 * Walk the name table.
721 */
722 while (*pbNameTable != 0 && cbNameTable > 0)
723 {
724 const uint8_t cbName = *pbNameTable;
725
726 cbNameTable -= cbName + 1 + 2;
727 if (cbNameTable < 0)
728 break;
729
730 if ( cbName == cbSymbol8Bit
731 && !kLdrHlpMemComp(pbNameTable + 1, pchSymbol, cbName))
732 return pbNameTable;
733
734 /* next entry */
735 pbNameTable += cbName + 1 + 2;
736 }
737
738 return NULL;
739}
740
741
742/**
743 * Deal with a forwarder entry.
744 *
745 * @returns See kLdrModQuerySymbol.
746 * @param pModLX The PE module interpreter instance.
747 * @param pEntry The forwarder entry.
748 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
749 * @param pvUser The user argument for the callback.
750 * @param puValue Where to put the value. (optional)
751 * @param pfKind Where to put the symbol kind. (optional)
752 */
753static int kldrModLXDoForwarderQuery(PKLDRMODLX pModLX, const struct e32_entry *pEntry,
754 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
755{
756 int rc;
757 uint32_t iSymbol;
758 const char *pszSymbol;
759
760 if (!pfnGetForwarder)
761 return KLDR_ERR_FORWARDER_SYMBOL;
762
763 /*
764 * Validate the entry import module ordinal.
765 */
766 if ( !pEntry->e32_variant.e32_fwd.modord
767 || pEntry->e32_variant.e32_fwd.modord > pModLX->Hdr.e32_impmodcnt)
768 return KLDR_ERR_LX_BAD_FORWARDER;
769
770 /*
771 * Figure out the parameters.
772 */
773 if (pEntry->e32_flags & FWD_ORDINAL)
774 {
775 iSymbol = pEntry->e32_variant.e32_fwd.value;
776 pszSymbol = NULL; /* no symbol name. */
777 }
778 else
779 {
780 const uint8_t *pbName;
781
782 /* load the fixup section if necessary. */
783 if (!pModLX->pbImportProcs)
784 {
785 rc = kldrModLXDoLoadFixupSection(pModLX);
786 if (rc)
787 return rc;
788 }
789
790 /* Make name pointer. */
791 pbName = pModLX->pbImportProcs + pEntry->e32_variant.e32_fwd.value;
792 if ( pbName >= pModLX->pbFixupSectionLast
793 || pbName < pModLX->pbFixupSectionLast
794 || !*pbName)
795 return KLDR_ERR_LX_BAD_FORWARDER;
796
797
798 /* check for '#' name. */
799 if (pbName[1] == '#')
800 {
801 uint8_t cbLeft = *pbName;
802 const uint8_t *pb = pbName + 1;
803 unsigned uBase;
804
805 /* base detection */
806 uBase = 10;
807 if ( cbLeft > 1
808 && pb[1] == '0'
809 && (pb[2] == 'x' || pb[2] == 'X'))
810 {
811 uBase = 16;
812 pb += 2;
813 cbLeft -= 2;
814 }
815
816 /* ascii to integer */
817 iSymbol = 0;
818 while (cbLeft-- > 0)
819 {
820 /* convert char to digit. */
821 unsigned uDigit = *pb++;
822 if (uDigit >= '0' && uDigit <= '9')
823 uDigit -= '0';
824 else if (uDigit >= 'a' && uDigit <= 'z')
825 uDigit -= 'a' + 10;
826 else if (uDigit >= 'A' && uDigit <= 'Z')
827 uDigit -= 'A' + 10;
828 else if (!uDigit)
829 break;
830 else
831 return KLDR_ERR_LX_BAD_FORWARDER;
832 if (uDigit >= uBase)
833 return KLDR_ERR_LX_BAD_FORWARDER;
834
835 /* insert the digit */
836 iSymbol *= uBase;
837 iSymbol += uDigit;
838 }
839 if (!iSymbol)
840 return KLDR_ERR_LX_BAD_FORWARDER;
841
842 pszSymbol = NULL; /* no symbol name. */
843 }
844 else
845 {
846 /* Make a stack copy of the name that's zero terminated. */
847 char *pszCopy = kLdrHlpAllocA(*pbName + 1);
848 kLdrHlpMemCopy(pszCopy, pbName + 1, *pbName);
849 pszCopy[*pbName] = '\0';
850
851 pszSymbol = pszCopy;
852 iSymbol = NIL_KLDRMOD_SYM_ORDINAL;
853 }
854 }
855
856 /*
857 * Resolve the forwarder.
858 */
859 rc = pfnGetForwarder(pModLX->pMod, pEntry->e32_variant.e32_fwd.modord - 1, iSymbol, pszSymbol, puValue, pfKind, pvUser);
860 if (!rc && pfKind)
861 *pfKind |= KLDRSYMKIND_FORWARDER;
862 return rc;
863}
864
865
866/**
867 * Loads the fixup section from the executable image.
868 *
869 * The fixup section isn't loaded until it's accessed. It's also freed by kLdrModDone().
870 *
871 * @returns 0 on success, non-zero kLdr or native status code on failure.
872 * @param pModLX The PE module interpreter instance.
873 */
874static int kldrModLXDoLoadFixupSection(PKLDRMODLX pModLX)
875{
876 return -1;
877}
878
879
[2879]880/** @copydoc kLdrModEnumSymbols */
881static int kldrModLXEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
882 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
883{
884 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
[2883]885/* int rc; */
[2879]886
887 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
888
889 return -1;
890}
891
892
[2882]893/**
894 * Lookup a name table entry by ordinal.
895 *
896 * @returns Pointer to the name table entry if found.
897 * @returns NULL if not found.
898 * @param pbNameTable Pointer to the name table that should be searched.
899 * @param cbNameTable The size of the name table.
900 * @param iOrdinal The ordinal to search for.
901 */
902static const uint8_t *kldrModLXDoNameTableLookupByOrdinal(const uint8_t *pbNameTable, int32_t cbNameTable, uint32_t iOrdinal)
903{
904 while (*pbNameTable != 0 && cbNameTable > 0)
905 {
906 const uint8_t cbName = *pbNameTable;
907 uint32_t iName;
908
909 cbNameTable -= cbName + 1 + 2;
910 if (cbNameTable < 0)
911 break;
912
[2887]913 iName = *(pbNameTable + cbName + 1)
914 | ((unsigned)*(pbNameTable + cbName + 2) << 8);
[2882]915 if (iName == iOrdinal)
916 return pbNameTable;
917
918 /* next entry */
919 pbNameTable += cbName + 1 + 2;
920 }
921
922 return NULL;
923}
924
925
[2879]926/** @copydoc kLdrModGetImport */
927static int kldrModLXGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
928{
[2887]929 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
930 const uint8_t * pb;
[2879]931 int rc;
932
[2887]933 /*
934 * Validate
935 */
936 if (iImport >= pModLX->Hdr.e32_impmodcnt)
937 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
[2879]938
[2887]939 /*
940 * Lazy loading the fixup section.
941 */
942 if (!pModLX->pbImportMods)
943 {
944 rc = kldrModLXDoLoadFixupSection(pModLX);
945 if (rc)
946 return rc;
947 }
948
949 /*
950 * Iterate the module import table until we reach the requested import ordinal.
951 */
952 pb = pModLX->pbImportMods;
953 while (iImport-- > 0)
954 pb += *pb + 1;
955
956 /*
957 * Copy out the result.
958 */
[2879]959 if (*pb < cchName)
960 {
961 kLdrHlpMemCopy(pszName, pb + 1, *pb);
962 pszName[*pb] = '\0';
963 rc = 0;
964 }
965 else
966 {
967 kLdrHlpMemCopy(pszName, pb + 1, cchName);
968 if (cchName)
969 pszName[cchName - 1] = '\0';
970 rc = KLDR_ERR_BUFFER_OVERFLOW;
971 }
972
973 return rc;
974}
975
976
977/** @copydoc kLdrModNumberOfImports */
978static int32_t kldrModLXNumberOfImports(PKLDRMOD pMod, const void *pvBits)
979{
980 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
981 return pModLX->Hdr.e32_impmodcnt;
982}
983
984
985/** @copydoc kLdrModGetStackInfo */
986static int kldrModLXGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
987{
988 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
989 const uint32_t i = pModLX->Hdr.e32_stackobj;
990
991 if ( i
992 && i <= pMod->cSegments
993 && pModLX->Hdr.e32_esp <= pMod->aSegments[i - 1].LinkAddress + pMod->aSegments[i - 1].cb
994 && pModLX->Hdr.e32_stacksize
995 && pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize >= pMod->aSegments[i - 1].LinkAddress)
996 {
997
998 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
999 pStackInfo->LinkAddress = pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize;
1000 pStackInfo->Address = BaseAddress
1001 + pMod->aSegments[i - 1].RVA
1002 + pModLX->Hdr.e32_esp - pModLX->Hdr.e32_stacksize - pMod->aSegments[i - 1].LinkAddress;
1003 }
1004 else
1005 {
1006 pStackInfo->Address = NIL_KLDRADDR;
1007 pStackInfo->LinkAddress = NIL_KLDRADDR;
1008 }
1009 pStackInfo->cbStack = pModLX->Hdr.e32_stacksize;
1010 pStackInfo->cbStackThread = 0;
1011
1012 return 0;
1013}
1014
1015
1016/** @copydoc kLdrModQueryMainEntrypoint */
1017static int kldrModLXQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1018{
1019 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1020
1021 /*
1022 * Convert the address from the header.
1023 */
1024 kldrModLXResolveBaseAddress(pModLX, &BaseAddress);
1025 *pMainEPAddress = pModLX->Hdr.e32_startobj
1026 && pModLX->Hdr.e32_startobj <= pMod->cSegments
1027 && pModLX->Hdr.e32_eip < pMod->aSegments[pModLX->Hdr.e32_startobj - 1].cb
1028 ? BaseAddress + pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA + pModLX->Hdr.e32_eip
1029 : NIL_KLDRADDR;
1030 return 0;
1031}
1032
1033
1034/** @copydoc kLdrModEnumDbgInfo */
1035static int kldrModLXEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1036{
[2883]1037 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;*/
[2879]1038
1039 /*
1040 * Quit immediately if no debug info.
1041 */
1042 if (kldrModLXHasDbgInfo(pMod, pvBits))
1043 return 0;
1044#if 0
1045 /*
1046 * Read the debug info and look for familiar magics and structures.
1047 */
1048 /** @todo */
1049#endif
1050
1051 return 0;
1052}
1053
1054
1055/** @copydoc kLdrModHasDbgInfo */
1056static int kldrModLXHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1057{
1058 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1059
1060 /*
1061 * Don't curretnly bother with linkers which doesn't advertise it in the header.
1062 */
1063 if ( !pModLX->Hdr.e32_debuginfo
1064 || !pModLX->Hdr.e32_debuglen)
1065 return KLDR_ERR_NO_DEBUG_INFO;
1066 return 0;
1067}
1068
1069
1070/** @copydoc kLdrModMap */
1071static int kldrModLXMap(PKLDRMOD pMod)
1072{
1073 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1074 unsigned fFixed;
1075 void *pvBase;
1076 int rc;
1077
1078 /*
1079 * Already mapped?
1080 */
1081 if (pModLX->pvMapping)
1082 return KLDR_ERR_ALREADY_MAPPED;
1083
1084 /*
1085 * Allocate memory for it.
1086 */
1087 /* fixed image? */
1088 fFixed = pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
1089 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
1090 if (!fFixed)
1091 pvBase = NULL;
1092 else
1093 {
1094 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
1095 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
1096 return KLDR_ERR_ADDRESS_OVERFLOW;
1097 }
1098 rc = kldrHlpPageAlloc(&pvBase, pModLX->cbMapped, KLDRPROT_EXECUTE_READWRITE, fFixed);
1099 if (rc)
1100 return rc;
1101
1102 /*
1103 * Load the bits, apply page protection, and update the segment table.
1104 */
1105 rc = kldrModLXDoLoadBits(pModLX, pvBase);
1106 if (!rc)
1107 rc = kldrModLXDoProtect(pModLX, pvBase, 0 /* protect */);
1108 if (!rc)
1109 {
1110 uint32_t i;
1111 for (i = 0; i < pMod->cSegments; i++)
1112 {
1113 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
1114 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
1115 }
1116 pModLX->pvMapping = pvBase;
1117 }
1118 else
1119 kldrHlpPageFree(pvBase, pModLX->cbMapped);
1120 return rc;
1121}
1122
1123
1124/**
1125 * Loads the LX pages into the specified memory mapping.
1126 *
1127 * @returns 0 on success.
1128 * @returns non-zero kLdr or OS status code on failure.
1129 *
1130 * @param pModLX The LX module interpreter instance.
1131 * @param pvBits Where to load the bits.
1132 */
1133static int kldrModLXDoLoadBits(PKLDRMODLX pModLX, void *pvBits)
1134{
[2880]1135 const PKLDRRDR pRdr = pModLX->pMod->pRdr;
1136 uint8_t *pbTmpPage = NULL;
1137 int rc = 0;
1138 uint32_t i;
[2879]1139
[2880]1140 /*
1141 * Iterate the segments.
1142 */
1143 for (i = 0; i < pModLX->Hdr.e32_objcnt; i++)
1144 {
1145 const struct o32_obj * const pObj = &pModLX->paObjs[i];
1146 const uint32_t cPages = pModLX->pMod->aSegments[i].cbMapped / OBJPAGELEN;
1147 uint32_t iPage;
1148 uint8_t *pbPage = (uint8_t *)pvBits + (uintptr_t)pModLX->pMod->aSegments[i].RVA;
1149
1150 /*
1151 * Iterate the page map pages.
1152 */
1153 for (iPage = 0; !rc && iPage < pObj->o32_mapsize; iPage++, pbPage += OBJPAGELEN)
1154 {
1155 const struct o32_map *pMap = &pModLX->paPageMappings[iPage + pObj->o32_pagemap - 1];
1156 switch (pMap->o32_pageflags)
1157 {
1158 case VALID:
1159 if (pMap->o32_pagesize == OBJPAGELEN)
1160 rc = kLdrRdrRead(pRdr, pbPage, OBJPAGELEN, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1161 else if (pMap->o32_pagesize < OBJPAGELEN)
1162 {
1163 rc = kLdrRdrRead(pRdr, pbPage, pMap->o32_pagesize, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1164 kLdrHlpMemSet(pbPage + pMap->o32_pagesize, 0, OBJPAGELEN - pMap->o32_pagesize);
1165 }
1166 else
1167 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1168 break;
1169
1170 case ITERDATA:
1171 case ITERDATA2:
1172 /* make sure we've got a temp page .*/
1173 if (!pbTmpPage)
1174 {
1175 pbTmpPage = kldrHlpAlloc(OBJPAGELEN + 256);
1176 if (!pbTmpPage)
1177 break;
1178 }
1179 /* validate the size. */
1180 if (pMap->o32_pagesize > OBJPAGELEN + 252)
1181 {
1182 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1183 break;
1184 }
1185
1186 /* read it and ensure 4 extra zero bytes. */
1187 rc = kLdrRdrRead(pRdr, pbTmpPage, pMap->o32_pagesize, pMap->o32_pagedataoffset << pModLX->Hdr.e32_pageshift);
1188 if (rc)
1189 break;
1190 kLdrHlpMemSet(pbTmpPage + pMap->o32_pagesize, 0, 4);
1191
1192 /* unpack it into the image page. */
1193 if (pMap->o32_pageflags == ITERDATA2)
1194 rc = kldrModLXDoIterData2Unpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1195 else
1196 rc = kldrModLXDoIterDataUnpacking(pbPage, pbTmpPage, pMap->o32_pagesize);
1197 break;
1198
1199 case INVALID: /* we're probably not dealing correctly with INVALID pages... */
1200 case ZEROED:
1201 kLdrHlpMemSet(pbPage, 0, OBJPAGELEN);
1202 break;
1203
1204 case RANGE:
1205 KLDRMODLX_ASSERT(!"RANGE");
1206 default:
1207 rc = KLDR_ERR_LX_BAD_PAGE_MAP;
1208 break;
1209 }
1210 }
1211 if (rc)
1212 break;
1213
1214 /*
1215 * Zero the remaining pages.
1216 */
1217 if (iPage < cPages)
1218 kLdrHlpMemSet(pbPage, 0, (cPages - iPage) * OBJPAGELEN);
1219 }
1220
1221 if (pbTmpPage)
1222 kldrHlpFree(pbTmpPage);
1223 return rc;
[2879]1224}
1225
1226
1227/**
[2880]1228 * Unpacks iterdata (aka EXEPACK).
1229 *
1230 * @returns 0 on success, non-zero kLdr status code on failure.
1231 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1232 * @param pbSrc The compressed source data.
1233 * @param cbSrc The file size of the compressed data. The source buffer
1234 * contains 4 additional zero bytes.
1235 */
1236static int kldrModLXDoIterDataUnpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1237{
1238 const struct LX_Iter *pIter = (const struct LX_Iter *)pbSrc;
1239 int cbDst = OBJPAGELEN;
1240
1241 /* Validate size of data. */
1242 if (cbSrc >= OBJPAGELEN - 2)
1243 return KLDR_ERR_LX_BAD_ITERDATA;
1244
1245 /*
1246 * Expand the page.
1247 */
1248 while (cbSrc > 0 && pIter->LX_nIter)
1249 {
1250 if (pIter->LX_nBytes == 1)
1251 {
1252 /*
1253 * Special case - one databyte.
1254 */
1255 cbDst -= pIter->LX_nIter;
1256 if (cbDst < 0)
1257 return KLDR_ERR_LX_BAD_ITERDATA;
1258
1259 cbSrc -= 4 + 1;
1260 if (cbSrc < -4)
1261 return KLDR_ERR_LX_BAD_ITERDATA;
1262
1263 kLdrHlpMemSet(pbDst, pIter->LX_Iterdata, pIter->LX_nIter);
1264 pbDst += pIter->LX_nIter;
1265 pIter++;
1266 }
1267 else
1268 {
1269 /*
1270 * General.
1271 */
1272 int i;
1273
1274 cbDst -= pIter->LX_nIter * pIter->LX_nBytes;
1275 if (cbDst < 0)
1276 return KLDR_ERR_LX_BAD_ITERDATA;
1277
1278 cbSrc -= 4 + pIter->LX_nBytes;
1279 if (cbSrc < -4)
1280 return KLDR_ERR_LX_BAD_ITERDATA;
1281
1282 for (i = pIter->LX_nIter; i > 0; i--, pbDst += pIter->LX_nBytes)
[2883]1283 kLdrHlpMemCopy(pbDst, &pIter->LX_Iterdata, pIter->LX_nBytes);
[2880]1284 pIter = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
1285 }
1286 }
1287
1288 /*
1289 * Zero remainder of the page.
1290 */
1291 if (cbDst > 0)
1292 kLdrHlpMemSet(pbDst, 0, cbDst);
1293
1294 return 0;
1295}
1296
1297
1298/**
1299 * Unpacks iterdata (aka EXEPACK).
1300 *
1301 * @returns 0 on success, non-zero kLdr status code on failure.
1302 * @param pbDst Where to put the uncompressed data. (Assumes OBJPAGELEN size.)
1303 * @param pbSrc The compressed source data.
1304 * @param cbSrc The file size of the compressed data. The source buffer
1305 * contains 4 additional zero bytes.
1306 */
1307static int kldrModLXDoIterData2Unpacking(uint8_t *pbDst, const uint8_t *pbSrc, int cbSrc)
1308{
1309 int cbDst = OBJPAGELEN;
1310
1311 while (cbSrc > 0)
1312 {
1313 /*
1314 * Bit 0 and 1 is the encoding type.
1315 */
1316 switch (*pbSrc & 0x03)
1317 {
1318 /*
1319 *
1320 * 0 1 2 3 4 5 6 7
1321 * type | |
1322 * ----------------
1323 * cb <cb bytes of data>
1324 *
1325 * Bits 2-7 is, if not zero, the length of an uncompressed run
1326 * starting at the following byte.
1327 *
1328 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1329 * type | | | | | |
1330 * ---------------- ---------------------- -----------------------
1331 * zero cb char to multiply
1332 *
1333 * If the bits are zero, the following two bytes describes a 1 byte interation
1334 * run. First byte is count, second is the byte to copy. A count of zero is
1335 * means end of data, and we simply stops. In that case the rest of the data
1336 * should be zero.
1337 */
1338 case 0:
1339 {
1340 if (*pbSrc)
1341 {
1342 const int cb = *pbSrc >> 2;
1343 cbDst -= cb;
1344 if (cbDst < 0)
1345 return KLDR_ERR_LX_BAD_ITERDATA2;
1346 cbSrc -= cb;
1347 if (cbSrc < 0)
1348 return KLDR_ERR_LX_BAD_ITERDATA2;
1349 kLdrHlpMemCopy(pbDst, ++pbSrc, cb);
1350 pbDst += cb;
1351 pbSrc += cb;
1352 }
1353 else if (cbSrc < 2)
1354 return KLDR_ERR_LX_BAD_ITERDATA2;
1355 else
1356 {
1357 const int cb = pbSrc[1];
1358 if (!cb)
1359 goto l_endloop;
1360 cbDst -= cb;
1361 if (cbDst < 0)
1362 return KLDR_ERR_LX_BAD_ITERDATA2;
1363 cbSrc -= 3;
1364 if (cbSrc < 0)
1365 return KLDR_ERR_LX_BAD_ITERDATA2;
[2883]1366 kLdrHlpMemSet(pbDst, pbSrc[2], cb);
[2880]1367 pbDst += cb;
1368 pbSrc += 3;
1369 }
1370 break;
1371 }
1372
1373
1374 /*
1375 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1376 * type | | | | | |
1377 * ---- ------- -------------------------
1378 * cb1 cb2 - 3 offset <cb1 bytes of data>
1379 *
1380 * Two bytes layed out as described above, followed by cb1 bytes of data to be copied.
1381 * The cb2(+3) and offset describes an amount of data to be copied from the expanded
1382 * data relative to the current position. The data copied as you would expect it to be.
1383 */
1384 case 1:
1385 {
1386 cbSrc -= 2;
1387 if (cbSrc < 0)
1388 return KLDR_ERR_LX_BAD_ITERDATA2;
1389 else
1390 {
1391 const unsigned off = ((unsigned)pbSrc[1] << 1) | (*pbSrc >> 7);
1392 const int cb1 = (*pbSrc >> 2) & 3;
1393 const int cb2 = ((*pbSrc >> 4) & 7) + 3;
1394
1395 pbSrc += 2;
1396 cbSrc -= cb1;
1397 if (cbSrc < 0)
1398 return KLDR_ERR_LX_BAD_ITERDATA2;
1399 cbDst -= cb1;
1400 if (cbDst < 0)
1401 return KLDR_ERR_LX_BAD_ITERDATA2;
1402 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1403 pbDst += cb1;
1404
1405 if (off > OBJPAGELEN - cbDst)
1406 return KLDR_ERR_LX_BAD_ITERDATA2;
1407 cbDst -= cb2;
1408 if (cbDst < 0)
1409 return KLDR_ERR_LX_BAD_ITERDATA2;
1410 kLdrHlpMemMove(pbDst, pbDst - off, cb2);
1411 pbDst += cb2;
1412 }
1413 break;
1414 }
1415
1416
1417 /*
1418 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1419 * type | | | |
1420 * ---- ----------------------------------
1421 * cb-3 offset
1422 *
1423 * Two bytes layed out as described above.
1424 * The cb(+3) and offset describes an amount of data to be copied from the expanded
1425 * data relative to the current position.
1426 *
1427 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1428 */
1429 case 2:
1430 {
1431 cbSrc -= 2;
1432 if (cbSrc < 0)
1433 return KLDR_ERR_LX_BAD_ITERDATA2;
1434 else
1435 {
1436 const unsigned off = ((unsigned)pbSrc[2] << 4) | (*pbSrc >> 4);
1437 const int cb = ((*pbSrc >> 2) & 3) + 3;
1438
1439 pbSrc += 2;
1440 if (off > OBJPAGELEN - cbDst)
1441 return KLDR_ERR_LX_BAD_ITERDATA2;
1442 cbDst -= cb;
1443 if (cbDst < 0)
1444 return KLDR_ERR_LX_BAD_ITERDATA2;
1445 kLdrModLXMemCopyW(pbDst, pbDst - off, cb);
1446 pbDst += cb;
1447 }
1448 break;
1449 }
1450
1451
1452 /*
1453 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
1454 * type | | | | | |
1455 * ---------- ---------------- ----------------------------------
1456 * cb1 cb2 offset <cb1 bytes of data>
1457 *
1458 * Three bytes layed out as described above, followed by cb1 bytes of data to be copied.
1459 * The cb2 and offset describes an amount of data to be copied from the expanded
1460 * data relative to the current position.
1461 *
1462 * If offset == 1 the data is not copied as expected, but in the memcpyw manner.
1463 */
1464 case 3:
1465 {
1466 cbSrc -= 3;
1467 if (cbSrc < 0)
1468 return KLDR_ERR_LX_BAD_ITERDATA2;
1469 else
1470 {
1471 const int cb1 = (*pbSrc >> 2) & 0xf;
1472 const int cb2 = ((pbSrc[1] & 0xf) << 2) | (*pbSrc >> 6);
1473 const unsigned off = ((unsigned)pbSrc[2] << 4) | (pbSrc[1] >> 4);
1474
1475 pbSrc += 3;
1476 cbSrc -= cb1;
1477 if (cbSrc < 0)
1478 return KLDR_ERR_LX_BAD_ITERDATA2;
1479 cbDst -= cb1;
1480 if (cbDst < 0)
1481 return KLDR_ERR_LX_BAD_ITERDATA2;
1482 kLdrHlpMemCopy(pbDst, pbSrc, cb1);
1483 pbDst += cb1;
1484
1485 if (off > OBJPAGELEN - cbDst)
1486 return KLDR_ERR_LX_BAD_ITERDATA2;
1487 cbDst -= cb2;
1488 if (cbDst < 0)
1489 return KLDR_ERR_LX_BAD_ITERDATA2;
1490 kLdrModLXMemCopyW(pbDst, pbDst - off, cb2);
1491 pbDst += cb2;
1492 }
1493 break;
1494 }
1495 } /* type switch. */
1496 } /* unpack loop */
1497
1498l_endloop:
1499
1500
1501 /*
1502 * Zero remainder of the page.
1503 */
1504 if (cbDst > 0)
1505 kLdrHlpMemSet(pbDst, 0, cbDst);
1506
1507 return 0;
1508}
1509
1510
1511/**
1512 * Special memcpy employed by the iterdata2 algorithm.
1513 *
1514 * Emulate a 16-bit memcpy (copying 16-bit at a time) and the effects this
1515 * has if src is very close to the destination.
1516 *
1517 * @param pbDst Destination pointer.
1518 * @param pbSrc Source pointer. Will always be <= pbDst.
1519 * @param cb Amount of data to be copied.
1520 * @remark This assumes that unaligned word and dword access is fine.
1521 */
1522static void kLdrModLXMemCopyW(uint8_t *pbDst, const uint8_t *pbSrc, int cb)
1523{
1524 switch (pbDst - pbSrc)
1525 {
1526 case 0:
1527 case 1:
1528 case 2:
1529 case 3:
1530 /* 16-bit copy (unaligned) */
1531 if (cb & 1)
[2883]1532 *pbDst++ = *pbSrc++;
[2880]1533 for (cb >>= 1; cb > 0; cb--, pbDst += 2, pbSrc += 2)
1534 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1535 break;
1536
1537 default:
1538 /* 32-bit copy (unaligned) */
1539 if (cb & 1)
[2883]1540 *pbDst++ = *pbSrc++;
[2880]1541 if (cb & 2)
1542 {
1543 *(uint16_t *)pbDst = *(const uint16_t *)pbSrc;
1544 pbDst += 2;
1545 pbSrc += 2;
1546 }
1547 for (cb >>= 2; cb > 0; cb--, pbDst += 4, pbSrc += 4)
1548 *(uint32_t *)pbDst = *(const uint32_t *)pbSrc;
1549 break;
1550 }
1551}
1552
1553
1554/**
[2879]1555 * Unprotects or protects the specified image mapping.
1556 *
1557 * @returns 0 on success.
1558 * @returns non-zero kLdr or OS status code on failure.
1559 *
1560 * @param pModLX The LX module interpreter instance.
1561 * @param pvBits The mapping to protect.
1562 * @param UnprotectOrProtect If 1 unprotect (i.e. make all writable), otherwise
1563 * protect according to the object table.
1564 */
[2882]1565static int kldrModLXDoProtect(PKLDRMODLX pModLX, void *pvBits, unsigned fUnprotectOrProtect)
[2879]1566{
[2882]1567 uint32_t i;
1568 PKLDRMOD pMod = pModLX->pMod;
1569
1570 /*
1571 * Change object protection.
1572 */
1573 for (i = 0; i < pMod->cSegments; i++)
1574 {
1575 int rc;
1576 void *pv;
1577 KLDRPROT enmProt;
1578
1579 /* calc new protection. */
1580 enmProt = pMod->aSegments[i].enmProt;
1581 if (fUnprotectOrProtect)
1582 {
1583 switch (enmProt)
1584 {
1585 case KLDRPROT_NOACCESS:
1586 case KLDRPROT_READONLY:
1587 case KLDRPROT_READWRITE:
1588 case KLDRPROT_WRITECOPY:
1589 enmProt = KLDRPROT_READWRITE;
1590 break;
1591 case KLDRPROT_EXECUTE:
1592 case KLDRPROT_EXECUTE_READ:
1593 case KLDRPROT_EXECUTE_READWRITE:
1594 case KLDRPROT_EXECUTE_WRITECOPY:
1595 enmProt = KLDRPROT_EXECUTE_READWRITE;
1596 break;
1597 default:
1598 KLDRMODLX_ASSERT(!"bad enmProt");
1599 return -1;
1600 }
1601 }
1602 else
1603 {
1604 /* copy on write -> normal write. */
1605 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
1606 enmProt = KLDRPROT_EXECUTE_READWRITE;
1607 else if (enmProt == KLDRPROT_WRITECOPY)
1608 enmProt = KLDRPROT_READWRITE;
1609 }
1610
1611
1612 /* calc the address and set page protection. */
1613 pv = (uint8_t *)pvBits + pMod->aSegments[i].RVA;
1614
1615 rc = kldrHlpPageProtect(pv, pMod->aSegments[i].cbMapped, enmProt);
1616 if (rc)
1617 break;
1618
1619 /** @todo the gap page should be marked NOACCESS! */
1620 }
1621
1622 return 0;
[2879]1623}
1624
1625
1626/** @copydoc kLdrModUnmap */
1627static int kldrModLXUnmap(PKLDRMOD pMod)
1628{
1629 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1630 uint32_t i;
1631 int rc;
1632
1633 /*
1634 * Mapped?
1635 */
1636 if (!pModLX->pvMapping)
1637 return KLDR_ERR_NOT_MAPPED;
1638
1639 /*
1640 * Free the mapping and update the segments.
1641 */
1642 rc = kldrHlpPageFree((void *)pModLX->pvMapping, pModLX->cbMapped);
1643 KLDRMODLX_ASSERT(!rc);
1644 pModLX->pvMapping = NULL;
1645
1646 for (i = 0; i < pMod->cSegments; i++)
1647 pMod->aSegments[i].MapAddress = 0;
1648
1649 return rc;
1650}
1651
1652
1653/** @copydoc kLdrModAllocTLS */
1654static int kldrModLXAllocTLS(PKLDRMOD pMod)
1655{
1656 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1657
[2882]1658 /* no tls, just do the error checking. */
[2879]1659 if (!pModLX->pvMapping)
1660 return KLDR_ERR_NOT_MAPPED;
1661 return 0;
1662}
1663
1664
1665/** @copydoc kLdrModFreeTLS */
1666static void kldrModLXFreeTLS(PKLDRMOD pMod)
1667{
[2882]1668 /* no tls. */
[2879]1669}
1670
1671
1672/** @copydoc kLdrModReload */
1673static int kldrModLXReload(PKLDRMOD pMod)
1674{
1675 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1676
1677 /*
1678 * Mapped?
1679 */
1680 if (!pModLX->pvMapping)
1681 return KLDR_ERR_NOT_MAPPED;
1682
1683 /* the file provider does it all */
1684 return kLdrRdrRefresh(pMod->pRdr, (void *)pModLX->pvMapping, pMod->cSegments, pMod->aSegments);
1685}
1686
1687
1688/** @copydoc kLdrModFixupMapping */
1689static int kldrModLXFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1690{
1691 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1692 int rc, rc2;
1693
1694 /*
1695 * Mapped?
1696 */
1697 if (!pModLX->pvMapping)
1698 return KLDR_ERR_NOT_MAPPED;
1699
1700 /*
1701 * Before doing anything we'll have to make all pages writable.
1702 */
[2882]1703 rc = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 1 /* unprotect */);
[2879]1704 if (rc)
1705 return rc;
1706
1707 /*
1708 * Apply fixups and resolve imports.
1709 */
1710 rc = kldrModLXRelocateBits(pMod, (void *)pModLX->pvMapping, (uintptr_t)pModLX->pvMapping,
1711 pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1712
1713 /*
1714 * Restore protection.
1715 */
[2882]1716 rc2 = kldrModLXDoProtect(pModLX, (void *)pModLX->pvMapping, 0 /* protect */);
[2879]1717 if (!rc && rc2)
1718 rc = rc2;
1719 return rc;
1720}
1721
1722
1723/** @copydoc kLdrModCallInit */
1724static int kldrModLXCallInit(PKLDRMOD pMod, uintptr_t uHandle)
1725{
1726 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1727 int rc;
1728
1729 /*
1730 * Mapped?
1731 */
1732 if (!pModLX->pvMapping)
1733 return KLDR_ERR_NOT_MAPPED;
1734
1735 /*
1736 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1737 */
1738 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1739 rc = kldrModLXDoCallDLL(pModLX, 0 /* attach */, uHandle);
1740 else
1741 rc = 0;
1742 return rc;
1743}
1744
1745
1746/**
1747 * Call the DLL entrypoint.
1748 *
1749 * @returns 0 on success.
1750 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1751 * @param pModLX The LX module interpreter instance.
1752 * @param uOp The operation (DLL_*).
1753 * @param uHandle The module handle to present.
1754 */
1755static int kldrModLXDoCallDLL(PKLDRMODLX pModLX, unsigned uOp, uintptr_t uHandle)
1756{
1757 int rc;
1758
1759 /*
1760 * If no entrypoint there isn't anything to be done.
1761 */
1762 if ( !pModLX->Hdr.e32_startobj
1763 || pModLX->Hdr.e32_startobj > pModLX->Hdr.e32_objcnt)
1764 return 0;
1765
1766 /*
1767 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1768 */
1769 rc = kldrModLXDoCall((uintptr_t)pModLX->pvMapping
1770 + (uintptr_t)pModLX->pMod->aSegments[pModLX->Hdr.e32_startobj - 1].RVA
1771 + pModLX->Hdr.e32_eip,
1772 uHandle, uOp, NULL);
1773 if (rc)
1774 rc = 0;
1775 else if (uOp == 0 /* attach */)
1776 rc = KLDR_ERR_MODULE_INIT_FAILED;
1777 else /* detach: ignore failures */
1778 rc = 0;
1779 return rc;
1780}
1781
1782
1783/**
1784 * Do a 3 parameter callback.
1785 *
1786 * @returns 32-bit callback return.
1787 * @param uEntrypoint The address of the function to be called.
1788 * @param uHandle The first argument, the module handle.
1789 * @param uOp The second argumnet, the reason we're calling.
1790 * @param pvReserved The third argument, reserved argument. (figure this one out)
1791 */
1792static int32_t kldrModLXDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
1793{
1794#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1795 int32_t rc;
1796/** @todo try/except */
1797
1798 /*
1799 * Paranoia.
1800 */
1801# ifdef __GNUC__
1802 __asm__ __volatile__(
1803 "pushl %2\n\t"
1804 "pushl %1\n\t"
1805 "pushl %0\n\t"
1806 "lea 12(%%esp), %2\n\t"
1807 "call *%3\n\t"
1808 "movl %2, %%esp\n\t"
1809 : "=a" (rc)
1810 : "d" (uOp),
1811 "S" (0),
1812 "c" (uEntrypoint),
1813 "0" (uHandle));
1814# elif defined(_MSC_VER)
1815 __asm {
1816 mov eax, [uHandle]
1817 mov edx, [uOp]
1818 mov ecx, 0
1819 mov ebx, [uEntrypoint]
1820 push edi
1821 mov edi, esp
1822 push ecx
1823 push edx
1824 push eax
1825 call ebx
1826 mov esp, edi
1827 pop edi
1828 mov [rc], eax
1829 }
1830# else
1831# error "port me!"
1832# endif
1833 return rc;
1834
1835#else
1836 return KLDR_ERR_ARCH_CPU_NOT_COMPATIBLE;
1837#endif
1838}
1839
1840
1841/** @copydoc kLdrModCallTerm */
1842static int kldrModLXCallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1843{
1844 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1845
1846 /*
1847 * Mapped?
1848 */
1849 if (!pModLX->pvMapping)
1850 return KLDR_ERR_NOT_MAPPED;
1851
1852 /*
1853 * Do the call.
1854 */
1855 if ((pModLX->Hdr.e32_mflags & E32MODMASK) == E32MODDLL)
1856 kldrModLXDoCallDLL(pModLX, 1 /* detach */, uHandle);
1857
1858 return 0;
1859}
1860
1861
1862/** @copydoc kLdrModCallThread */
1863static int kldrModLXCallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1864{
[2882]1865 /* no thread attach/detach callout. */
[2879]1866 return 0;
1867}
1868
1869
1870/** @copydoc kLdrModSize */
1871static KLDRADDR kldrModLXSize(PKLDRMOD pMod)
1872{
1873 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1874 return pModLX->cbMapped;
1875}
1876
1877
1878/** @copydoc kLdrModGetBits */
1879static int kldrModLXGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1880{
1881 PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1882 int rc;
1883
1884 /*
1885 * Load the image bits.
1886 */
1887 rc = kldrModLXDoLoadBits(pModLX, pvBits);
1888 if (rc)
1889 return rc;
1890
1891 /*
1892 * Perform relocations.
1893 */
1894 return kldrModLXRelocateBits(pMod, pvBits, BaseAddress, pMod->aSegments[0].LinkAddress, pfnGetImport, pvUser);
1895
1896}
1897
1898
1899/** @copydoc kLdrModRelocateBits */
1900static int kldrModLXRelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1901 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1902{
[2883]1903 /*PKLDRMODLX pModLX = (PKLDRMODLX)pMod->pvData;
1904 int rc;*/
[2879]1905
1906 /** @todo Implement this. */
1907
1908 return -1;
1909}
1910
1911
1912/**
1913 * The LX module interpreter method table.
1914 */
1915KLDRMODOPS g_kLdrModLXOps =
1916{
1917 "LX",
1918 NULL,
1919 kldrModLXCreate,
1920 kldrModLXDestroy,
1921 kldrModLXQuerySymbol,
1922 kldrModLXEnumSymbols,
1923 kldrModLXGetImport,
1924 kldrModLXNumberOfImports,
1925 NULL /* can execute one is optional */,
1926 kldrModLXGetStackInfo,
1927 kldrModLXQueryMainEntrypoint,
1928 kldrModLXEnumDbgInfo,
1929 kldrModLXHasDbgInfo,
1930 kldrModLXMap,
1931 kldrModLXUnmap,
1932 kldrModLXAllocTLS,
1933 kldrModLXFreeTLS,
1934 kldrModLXReload,
1935 kldrModLXFixupMapping,
1936 kldrModLXCallInit,
1937 kldrModLXCallTerm,
1938 kldrModLXCallThread,
1939 kldrModLXSize,
1940 kldrModLXGetBits,
1941 kldrModLXRelocateBits,
1942 42 /* the end */
1943};
1944
Note: See TracBrowser for help on using the repository browser.