1 /*
2 * w32dll.c -- a simplistic interface to Win32 DLLs (no thread support)
3 * Written by Andrew Church <achurch@achurch.org>
4 *
5 * This file is part of transcode, a video stream processing tool.
6 * transcode is free software, distributable under the terms of the GNU
7 * General Public License (version 2 or later). See the file COPYING
8 * for details.
9 */
10
11 #ifdef HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <sys/mman.h>
23
24 #if !defined(HAVE_MMAP)
25 # error Sorry, mmap() support is required.
26 #endif
27
28 #if defined(HAVE_ENDIAN_H)
29 # include <endian.h>
30 # if __BYTE_ORDER != __LITTLE_ENDIAN
31 # error Sorry, only little-endian architectures are supported.
32 # endif
33 #endif
34
35 #if defined(HAVE_SYSCONF_WITH_SC_PAGESIZE)
36 # define GETPAGESIZE() (sysconf(_SC_PAGESIZE))
37 #elif defined(HAVE_GETPAGESIZE)
38 # define GETPAGESIZE() (getpagesize())
39 #elif defined(PAGESIZE)
40 # define GETPAGESIZE() (PAGESIZE)
41 #elif defined(PAGE_SIZE)
42 # define GETPAGESIZE() (PAGE_SIZE)
43 #else
44 # error System page size is not available!
45 #endif
46
47 #include "w32dll.h"
48 #include "w32dll-local.h"
49
50 /*************************************************************************/
51
52 /* Contents of a DLL handle. */
53
54 struct w32dllhandle_ {
55 /* Signature (to protect against bad pointers and double-free */
56 uint32_t signature;
57
58 /* Overall file data */
59 struct pe_header header;
60 struct pe_ext_header extheader;
61
62 /* File position for each RVA entry */
63 off_t rva_filepos[RVA_MAX];
64
65 /* Data for each loaded section */
66 int nsections;
67 struct section_info {
68 void *base;
69 uint32_t size;
70 int prot; /* Protection flags for mprotect() */
71 uint32_t origbase; /* Virtual address given in section header */
72 uint32_t origsize; /* Likewise, for size */
73 } *sections;
74
75 /* Data for exported functions */
76 int export_ordinal_base;
77 int export_ordinal_count;
78 void **export_table;
79 int export_name_count;
80 struct export_name {
81 char *name;
82 uint32_t ordinal;
83 } *export_name_table;
84 };
85
86 #define HANDLE_SIGNATURE 0xD11DA7A5
87
88
89 /* Forward declarations for internal routines. */
90
91 static int w32dll_add_section(W32DLLHandle dll, int fd,
92 struct pe_section_header *secthdr);
93 static int w32dll_load_section(int fd, struct pe_section_header *secthdr,
94 struct section_info *sectinfo);
95 static void w32dll_update_rva(W32DLLHandle dll,
96 struct pe_section_header *secthdr);
97 static int w32dll_read_exports(W32DLLHandle dll, int fd);
98 static int w32dll_process_imports(W32DLLHandle dll,
99 struct import_directory *importdir);
100 static void *w32dll_import_by_name(const char *module,
101 const struct import_name_entry *name);
102 static void *w32dll_import_by_ordinal(const char *module, uint32_t ordinal);
103 static int w32dll_read_relocs(W32DLLHandle dll, int fd,
104 uint32_t **relocs_ptr, int *nrelocs_ptr);
105 static void w32dll_relocate(W32DLLHandle dll, uint32_t *relocs, int nrelocs);
106 static void *w32dll_relocate_addr(W32DLLHandle dll, uint32_t addr);
107 static char *w32dll_read_asciiz(int fd);
108 static int w32dll_init_fs(void);
109
110 /*************************************************************************/
111 /*************************************************************************/
112
113 /* External interface routines. */
114
115 /*************************************************************************/
116
117 /**
118 * w32dll_load: Load the given DLL file into memory, and return a handle
119 * to it.
120 *
121 * Parameters:
122 * path: DLL file pathname.
123 * compat: If nonzero, adds a memory mapping for the entire DLL to
124 * accommodate misbehaving DLLs that access memory outside the
125 * registered sections.
126 * Return value:
127 * DLL handle (nonzero), or zero on error.
128 * Side effects:
129 * Sets errno to an appropriate value on error, including ENOEXEC if
130 * the file is not recognized as a Win32 DLL file or is corrupt or
131 * truncated, or ETXTBSY if the DLL's DllMain() function returns an
132 * error. On successful return, errno is undefined.
133 */
134
w32dll_load(const char * path,int compat)135 W32DLLHandle w32dll_load(const char *path, int compat)
136 {
137 W32DLLHandle dll;
138 struct dos_header doshdr;
139 int fd, i;
140
141 /* Allocate and initialize the DLL handle. */
142 dll = malloc(sizeof(*dll));
143 if (!dll)
144 return NULL;
145 memset(&dll->header, 0, sizeof(dll->header));
146 memset(&dll->extheader, 0, sizeof(dll->extheader));
147 memset(&dll->rva_filepos, 0, sizeof(dll->rva_filepos));
148 dll->signature = HANDLE_SIGNATURE;
149 dll->nsections = 0;
150 dll->sections = NULL;
151 dll->export_ordinal_base = 0;
152 dll->export_ordinal_count = 0;
153 dll->export_table = NULL;
154 dll->export_name_count = 0;
155 dll->export_name_table = NULL;
156
157 /* Open the file, and ensure that it's seekable. */
158 fd = open(path, O_RDONLY);
159 if (fd == -1 || lseek(fd, 0, SEEK_SET) == -1) {
160 int errno_save = errno;
161 free(dll);
162 errno = errno_save;
163 return NULL;
164 }
165
166 /* Check for a valid (Win32-style) DOS executable header. */
167 if (read(fd, &doshdr, sizeof(doshdr)) != sizeof(doshdr)
168 || doshdr.signature != DOS_EXE_SIGNATURE
169 || doshdr.reloc_offset < 0x40
170 ) {
171 goto err_noexec;
172 }
173
174 /* Check for a valid PE header (standard and optional both required). */
175 if (lseek(fd, doshdr.winheader, SEEK_SET) == -1
176 || read(fd, &dll->header, sizeof(dll->header)) != sizeof(dll->header)
177 || dll->header.opt_header_size < sizeof(dll->extheader)
178 || read(fd, &dll->extheader, sizeof(dll->extheader))
179 != sizeof(dll->extheader)
180 || dll->header.signature != WIN_PE_SIGNATURE
181 || !(dll->header.flags & WIN_PE_FLAG_DLL)
182 #if defined(ARCH_X86)
183 || (dll->header.arch & ~3) != WIN_PE_ARCH_X86
184 || dll->extheader.magic != WIN_PE_OPT_MAGIC_32
185 #else
186 # error Sorry, this architecture is not supported.
187 #endif
188 ) {
189 goto err_noexec;
190 }
191 /* Skip past any extra header bytes we didn't need. */
192 if (dll->header.opt_header_size > sizeof(dll->extheader)) {
193 if (lseek(fd, dll->header.opt_header_size - sizeof(dll->extheader),
194 SEEK_CUR) == -1
195 ) {
196 goto err_noexec;
197 }
198 }
199
200 /* Go through the section table and attempt to load each section. Also
201 * determine file positions for each RVA entry. Note that we do not
202 * simply map the entire file because (1) sections may be larger in
203 * memory than in the file and (2) the system's page size may be larger
204 * than that specified in the file. */
205 for (i = 0; i < dll->header.nsections + (compat ? 1 : 0); i++) {
206 struct pe_section_header secthdr;
207
208 if (i >= dll->header.nsections) {
209 /* Set up compatibility entry */
210 off_t curpos = lseek(fd, 0, SEEK_CUR);
211 off_t filesize = lseek(fd, 0, SEEK_END);
212 if (curpos==-1 || filesize==-1 || lseek(fd,curpos,SEEK_SET)==-1)
213 goto error;
214 secthdr.virtaddr = 0;
215 secthdr.virtsize = dll->extheader.image_size;
216 secthdr.fileaddr = 0;
217 secthdr.filesize = filesize;
218 secthdr.flags = SECTION_FLAG_DATA | SECTION_FLAG_READ;
219 } else {
220 if (read(fd, §hdr, sizeof(secthdr)) != sizeof(secthdr))
221 goto err_noexec;
222 }
223 w32dll_update_rva(dll, §hdr);
224 w32dll_add_section(dll, fd, §hdr);
225 }
226
227 /* Load and process relocations. Note that once the sections are
228 * loaded, we could theoretically just retrieve these (and the other
229 * data below) from memory, but since we take the approach of only
230 * loading/mapping the sections we need, we do this the hard way and
231 * read the data directly from the file. */
232 if (dll->rva_filepos[RVA_BASE_RELOC]
233 && dll->extheader.rva[RVA_BASE_RELOC].size
234 ) {
235 uint32_t *relocs = NULL;
236 int nrelocs = 0;
237
238 if (lseek(fd, dll->rva_filepos[RVA_BASE_RELOC], SEEK_SET) == -1)
239 goto error;
240 while (lseek(fd, 0, SEEK_CUR)
241 <= dll->rva_filepos[RVA_BASE_RELOC]
242 + dll->extheader.rva[RVA_BASE_RELOC].size - 8
243 ) {
244 int res = w32dll_read_relocs(dll, fd, &relocs, &nrelocs);
245 if (res < 0)
246 goto error;
247 if (res == 0)
248 break;
249 }
250 w32dll_relocate(dll, relocs, nrelocs);
251 }
252
253 /* Load export table. */
254 if (dll->rva_filepos[RVA_EXPORT]
255 && dll->extheader.rva[RVA_EXPORT].size >= sizeof(struct export_directory)
256 ) {
257 if (!w32dll_read_exports(dll, fd))
258 goto error;
259 }
260
261 /* Load and process import table. */
262 if (dll->rva_filepos[RVA_IMPORT]
263 && dll->extheader.rva[RVA_IMPORT].size >= sizeof(struct import_directory)
264 ) {
265 struct import_directory importdir;
266
267 if (lseek(fd, dll->rva_filepos[RVA_IMPORT], SEEK_SET) == -1)
268 goto error;
269 while (lseek(fd, 0, SEEK_CUR)
270 <= dll->rva_filepos[RVA_IMPORT]
271 + dll->extheader.rva[RVA_IMPORT].size - sizeof(importdir)
272 ) {
273 if (read(fd, &importdir, sizeof(importdir)) != sizeof(importdir))
274 goto err_noexec;
275 if (!importdir.module_name)
276 break; /* Last entry in table */
277 if (!importdir.import_table || !importdir.import_addr_table)
278 goto err_noexec;
279 if (!w32dll_process_imports(dll, &importdir))
280 goto error;
281 }
282 }
283
284 /* Set section access privileges appropriately. */
285 for (i = 0; i < dll->nsections; i++) {
286 if (mprotect(dll->sections[i].base, dll->sections[i].size,
287 dll->sections[i].prot) != 0
288 ) {
289 goto error;
290 }
291 }
292
293 /* Close file descriptor (no longer needed). */
294 close(fd);
295 fd = -1;
296
297 /* Set up the FS register with a dummy thread information block.
298 * We deliberately don't support libraries that depend on the OS to
299 * put things here; we just provide the space so that accesses to
300 * %fs:... don't segfault. */
301 if (!w32dll_init_fs())
302 goto error;
303
304 /* Call the DllMain() entry point. */
305 if (dll->extheader.entry_point) {
306 WINAPI int (*DllMain)(uint32_t handle, uint32_t reason, void *resv);
307 DllMain = w32dll_relocate_addr(dll, dll->extheader.entry_point
308 + dll->extheader.image_base);
309 if (!DllMain)
310 goto err_noexec;
311 if (!(*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_ATTACH, NULL)) {
312 (*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_DETACH, NULL);
313 errno = ETXTBSY;
314 goto error;
315 }
316 }
317
318 /* Successful! */
319 return dll;
320
321 /* Error handling */
322 err_noexec:
323 errno = ENOEXEC;
324 error:
325 {
326 int errno_save = errno;
327 close(fd);
328 w32dll_unload(dll);
329 errno_save = errno;
330 return NULL;
331 }
332 }
333
334 /*************************************************************************/
335
336 /**
337 * w32dll_unload: Unload the given DLL from memory. Does nothing if the
338 * given handle is zero or invalid.
339 *
340 * Parameters:
341 * dll: DLL handle.
342 * Return value:
343 * None.
344 */
345
w32dll_unload(W32DLLHandle dll)346 void w32dll_unload(W32DLLHandle dll)
347 {
348 int i;
349
350 if (!dll || dll->signature != HANDLE_SIGNATURE)
351 return;
352
353 /* Call the DllMain() entry point with DLL_PROCESS_DETACH. */
354 if (dll->extheader.entry_point) {
355 WINAPI int (*DllMain)(uint32_t handle, uint32_t reason, void *resv);
356 DllMain = w32dll_relocate_addr(dll, dll->extheader.entry_point
357 + dll->extheader.image_base);
358 if (DllMain)
359 (*DllMain)(HANDLE_DEFAULT, DLL_PROCESS_DETACH, NULL);
360 }
361
362 /* Free DLL memory. */
363 for (i = 0; i < dll->nsections; i++) {
364 munmap(dll->sections[i].base, dll->sections[i].size);
365 dll->sections[i].base = NULL;
366 dll->sections[i].size = 0;
367 }
368 free(dll->sections);
369 dll->sections = NULL;
370 dll->nsections = 0;
371
372 /* Free export tables. */
373 free(dll->export_table);
374 dll->export_table = NULL;
375 for (i = 0; i < dll->export_name_count; i++) {
376 free(dll->export_name_table[i].name);
377 dll->export_name_table[i].name = NULL;
378 }
379 free(dll->export_name_table);
380 dll->export_name_table = NULL;
381
382 /* Free the handle structure itself. */
383 dll->signature = ~HANDLE_SIGNATURE;
384 free(dll);
385
386 return;
387 }
388
389 /*************************************************************************/
390
391 /**
392 * w32dll_lookup_by_name: Look up the address of an exported function in
393 * the given DLL, using the function's name.
394 *
395 * Parameters:
396 * dll: DLL handle.
397 * name: Function name.
398 * Return value:
399 * Function address, or NULL on error.
400 * Side effects:
401 * Sets errno to one of the following values on error:
402 * EINVAL: `dll' or `name' was invalid.
403 * ENOENT: The requested function does not exist.
404 * On successful return, errno is undefined.
405 */
406
w32dll_lookup_by_name(W32DLLHandle dll,const char * name)407 void *w32dll_lookup_by_name(W32DLLHandle dll, const char *name)
408 {
409 int i;
410
411 if (!dll || dll->signature != HANDLE_SIGNATURE || !name || !*name) {
412 errno = EINVAL;
413 return NULL;
414 }
415 for (i = 0; i < dll->export_name_count; i++) {
416 if (strcmp(name, dll->export_name_table[i].name) == 0) {
417 return w32dll_lookup_by_ordinal(dll,
418 dll->export_name_table[i].ordinal);
419 }
420 }
421 errno = ENOENT;
422 return NULL;
423 }
424
425 /*************************************************************************/
426
427 /**
428 * w32dll_lookup_by_ordinal: Look up the address of an exported function
429 * in the given DLL, using the function's ordinal value.
430 *
431 * Parameters:
432 * dll: DLL handle.
433 * ordinal: Function ordinal.
434 * Return value:
435 * Function address, or NULL on error.
436 * Side effects:
437 * Sets errno to one of the following values on error:
438 * EINVAL: `dll' was invalid.
439 * ENOENT: The requested function does not exist.
440 * On successful return, errno is undefined.
441 */
442
w32dll_lookup_by_ordinal(W32DLLHandle dll,uint32_t ordinal)443 void *w32dll_lookup_by_ordinal(W32DLLHandle dll, uint32_t ordinal)
444 {
445 if (!dll || dll->signature != HANDLE_SIGNATURE) {
446 errno = EINVAL;
447 return NULL;
448 }
449 if (ordinal < dll->export_ordinal_base) {
450 errno = ENOENT;
451 return NULL;
452 }
453 ordinal -= dll->export_ordinal_base;
454 if (ordinal >= dll->export_ordinal_count || !dll->export_table[ordinal]) {
455 errno = ENOENT;
456 return NULL;
457 }
458 return dll->export_table[ordinal];
459 }
460
461 /*************************************************************************/
462 /*************************************************************************/
463
464 /* Internal routines. */
465
466 /*************************************************************************/
467
468 /**
469 * w32dll_add_section: Checks the given section description, and loads it
470 * in from the DLL file, appending information to the dll->sections[]
471 * array, if appropriate.
472 *
473 * Parameters:
474 * dll: DLL handle.
475 * fd: File descriptor to read from.
476 * secthdr: Pointer to section header.
477 * Return value:
478 * Nonzero on success (including when the section was intentionally
479 * not loaded), zero on error.
480 * Notes:
481 * - On success, the file's current offset is not changed.
482 * - The allocated memory will be marked read/write; after relocation,
483 * use mprotect() to set the protection to sectinfo->prot.
484 * - On error, errno is set appropriately.
485 */
486
w32dll_add_section(W32DLLHandle dll,int fd,struct pe_section_header * secthdr)487 static int w32dll_add_section(W32DLLHandle dll, int fd,
488 struct pe_section_header *secthdr)
489 {
490 void *new_sections;
491
492 if (!(secthdr->flags & (SECTION_FLAG_CODE
493 | SECTION_FLAG_DATA
494 | SECTION_FLAG_BSS))
495 ) {
496 /* Don't know what kind of section this is, but we don't need it */
497 return 1;
498 }
499
500 if (!(secthdr->flags & (SECTION_FLAG_READ
501 | SECTION_FLAG_WRITE
502 | SECTION_FLAG_EXEC))
503 ) {
504 /* Don't bother loading--it wouldn't be accessible anyway */
505 return 1;
506 }
507
508 new_sections = realloc(dll->sections,
509 sizeof(*dll->sections) * (dll->nsections+1));
510 if (!new_sections)
511 return 0;
512 dll->sections = new_sections;
513 dll->sections[dll->nsections].base = NULL;
514 dll->sections[dll->nsections].size = 0;
515 dll->sections[dll->nsections].prot = 0;
516 dll->sections[dll->nsections].origbase = 0;
517 dll->sections[dll->nsections].origsize = 0;
518 dll->nsections++;
519 if (!w32dll_load_section(fd, secthdr, &dll->sections[dll->nsections-1]))
520 return 0;
521 dll->sections[dll->nsections-1].origbase += dll->extheader.image_base;
522
523 return 1;
524 }
525
526 /*************************************************************************/
527
528 /**
529 * w32dll_load_section: Loads the section described by `secthdr' from the
530 * file descriptor `fd', setting the `sectinfo' structure appropriately.
531 *
532 * Parameters:
533 * fd: File to load data from.
534 * secthdr: Section header loaded from the file.
535 * sectinfo: Structure to store information about the segment in.
536 * Return value:
537 * Nonzero on success, zero on error.
538 * Notes:
539 * - On success, the file's current offset is not changed.
540 * - The allocated memory will be marked read/write; after relocation,
541 * use mprotect() to set the protection to sectinfo->prot.
542 * - On error, errno is set appropriately.
543 */
544
w32dll_load_section(int fd,struct pe_section_header * secthdr,struct section_info * sectinfo)545 static int w32dll_load_section(int fd, struct pe_section_header *secthdr,
546 struct section_info *sectinfo)
547 {
548 int newfd;
549 void *base;
550 uint32_t size, toread;
551 off_t oldofs;
552
553 uint32_t pagesize = GETPAGESIZE();
554 if (pagesize < 0) {
555 errno = EINVAL;
556 return 0;
557 }
558
559 #ifdef MAP_ANONYMOUS
560 newfd = -1;
561 #else
562 newfd = open("/dev/zero", O_RDWR);
563 #endif
564 size = (secthdr->virtsize + pagesize-1) / pagesize * pagesize;
565 base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE
566 #ifdef MAP_ANONYMOUS
567 | MAP_ANONYMOUS
568 #endif
569 , newfd, 0);
570 #ifndef MAP_ANONYMOUS
571 if (newfd != -1) {
572 int errno_save = errno;
573 close(newfd);
574 errno = errno_save;
575 }
576 #endif
577 if (base == MAP_FAILED)
578 return 0;
579
580 oldofs = lseek(fd, 0, SEEK_CUR);
581 if (oldofs == -1) {
582 munmap(base, size);
583 return 0;
584 }
585 if (secthdr->filesize < secthdr->virtsize)
586 toread = secthdr->filesize;
587 else
588 toread = secthdr->virtsize;
589 if (lseek(fd, secthdr->fileaddr, SEEK_SET) == -1
590 || read(fd, base, toread) != toread
591 || lseek(fd, oldofs, SEEK_SET) == -1
592 ) {
593 munmap(base, size);
594 errno = ENOEXEC;
595 return 0;
596 }
597
598 sectinfo->base = base;
599 sectinfo->size = size;
600 sectinfo->prot = 0;
601 if (secthdr->flags & SECTION_FLAG_READ)
602 sectinfo->prot |= PROT_READ;
603 if (secthdr->flags & SECTION_FLAG_WRITE)
604 sectinfo->prot |= PROT_WRITE;
605 if (secthdr->flags & SECTION_FLAG_EXEC)
606 sectinfo->prot |= PROT_EXEC;
607 sectinfo->origbase = secthdr->virtaddr;
608 sectinfo->origsize = secthdr->virtsize;
609
610 return 1;
611 }
612
613 /*************************************************************************/
614
615 /**
616 * w32dll_update_rva: Update the rva_filepos[] table in the DLL handle
617 * for any RVAs within the given segment.
618 *
619 * Parameters:
620 * dll: DLL handle.
621 * secthdr: Pointer to section header.
622 * Return value:
623 * None.
624 */
625
w32dll_update_rva(W32DLLHandle dll,struct pe_section_header * secthdr)626 static void w32dll_update_rva(W32DLLHandle dll,
627 struct pe_section_header *secthdr)
628 {
629 int i;
630
631 for (i = 0; i < RVA_MAX; i++) {
632 if (!dll->rva_filepos[i]
633 && dll->extheader.rva[i].address >= secthdr->virtaddr
634 && dll->extheader.rva[i].address < secthdr->virtaddr+secthdr->virtsize
635 ) {
636 dll->rva_filepos[i] =
637 dll->extheader.rva[i].address - secthdr->virtaddr
638 + secthdr->fileaddr;
639 }
640 }
641 }
642
643 /*************************************************************************/
644
645 /**
646 * w32dll_read_exports: Read in the DLL's export table, and fill in the
647 * export data in the DLL handle.
648 *
649 * Parameters:
650 * dll: DLL handle.
651 * fd: File descriptor to read from.
652 * Return value:
653 * Nonzero on success, zero on failure.
654 * Notes:
655 * On error, errno is set appropriately.
656 */
657
w32dll_read_exports(W32DLLHandle dll,int fd)658 static int w32dll_read_exports(W32DLLHandle dll, int fd)
659 {
660 struct export_directory exportdir;
661 off_t secofs = (off_t)dll->rva_filepos[RVA_EXPORT]
662 - (off_t)dll->extheader.rva[RVA_EXPORT].address;
663
664 /* Read in the export table. */
665 if (lseek(fd, dll->rva_filepos[RVA_EXPORT], SEEK_SET) == -1)
666 goto error;
667 if (read(fd, &exportdir, sizeof(exportdir)) != sizeof(exportdir))
668 goto err_noexec;
669 dll->export_ordinal_base = exportdir.ordinal_base;
670
671 /* Read in each exported function address, relocate it, and store the
672 * relocated address in the DLL handle structure. */
673 if (exportdir.nfuncs) {
674 dll->export_table =
675 malloc(sizeof(*dll->export_table) * exportdir.nfuncs);
676 if (!dll->export_table)
677 goto error;
678 if (lseek(fd, exportdir.func_table + secofs, SEEK_SET) == -1)
679 goto error;
680 /* Use the entry count field itself as a loop variable, to ensure
681 * that the correct number of entries are cleaned up on error
682 * (doesn't matter here, but avoids a memory leak for the name
683 * array handling below) */
684 for (dll->export_ordinal_count = 0;
685 dll->export_ordinal_count < exportdir.nfuncs;
686 dll->export_ordinal_count++
687 ) {
688 uint32_t address;
689 if (read(fd, &address, 4) != 4)
690 goto err_noexec;
691 address += dll->extheader.image_base;
692 dll->export_table[dll->export_ordinal_count] =
693 w32dll_relocate_addr(dll, address);
694 }
695 }
696
697 /* Read in each exported function name, and store the name and its
698 * associated ordinal in the DLL handle structure. */
699 if (exportdir.nnames) {
700 int i;
701 dll->export_name_table =
702 malloc(sizeof(*dll->export_name_table) * exportdir.nnames);
703 if (!dll->export_name_table)
704 goto error;
705 if (lseek(fd, exportdir.name_ordinal_table + secofs, SEEK_SET) == -1)
706 goto error;
707 for (i = 0; i < exportdir.nnames; i++) {
708 uint16_t ordinal;
709 if (read(fd, &ordinal, 2) != 2)
710 goto err_noexec;
711 dll->export_name_table[i].ordinal =
712 dll->export_ordinal_base + ordinal;
713 }
714 for (dll->export_name_count = 0;
715 dll->export_name_count < exportdir.nnames;
716 dll->export_name_count++
717 ) {
718 uint32_t name_address;
719 char *s;
720 if (lseek(fd, exportdir.name_table+secofs+dll->export_name_count*4,
721 SEEK_SET) == -1
722 ) {
723 goto error;
724 }
725 if (read(fd, &name_address, 4) != 4)
726 goto err_noexec;
727 if (lseek(fd, name_address + secofs, SEEK_SET) == -1)
728 goto error;
729 s = w32dll_read_asciiz(fd);
730 if (!s)
731 goto error;
732 dll->export_name_table[dll->export_name_count].name = s;
733 }
734 }
735
736 /* Success! */
737 return 1;
738
739 err_noexec:
740 errno = ENOEXEC;
741 error:
742 return 0;
743 }
744
745 /*************************************************************************/
746
747 /**
748 * w32dll_process_imports: Reads the list of imports described by
749 * `importdir' and sets the pointers to appropriate values (emulation
750 * functions or a placeholder function).
751 *
752 * Parameters:
753 * dll: DLL handle.
754 * importdir: Import directory structure.
755 * Return value:
756 * Nonzero on success, zero on error.
757 * Notes:
758 * - On error, errno is set appropriately.
759 * - This routine assumes that all import data is located in the same
760 * section. Since the import address table has to be in a loaded
761 * section (usually a data section), this implies that the rest of
762 * the import data is also in a loaded section; therefore, we take
763 * the easy approach and access the data directly in memory.
764 */
765
w32dll_process_imports(W32DLLHandle dll,struct import_directory * importdir)766 static int w32dll_process_imports(W32DLLHandle dll,
767 struct import_directory *importdir)
768 {
769 const uint32_t imgbase = dll->extheader.image_base; // shorthand
770 const char *module;
771 const struct import_name_entry **names;
772 void **addrs;
773 int i;
774
775 /* Relocate import directory addresses. */
776 module = w32dll_relocate_addr(dll, importdir->module_name + imgbase);
777 names = w32dll_relocate_addr(dll, importdir->import_table + imgbase);
778 addrs = w32dll_relocate_addr(dll, importdir->import_addr_table + imgbase);
779 if (!module || !*module || !names || !addrs)
780 goto err_noexec;
781
782 /* Process the imports. */
783 for (i = 0; names[i]; i++) {
784 const struct import_name_entry *name;
785 uint32_t ordinal;
786 if ((uint32_t)names[i] & 0x80000000UL) {
787 name = NULL;
788 ordinal = (uint32_t)names[i] & 0x7FFFFFFFUL;
789 } else {
790 name = w32dll_relocate_addr(dll, (uint32_t)names[i] + imgbase);
791 if (!name)
792 goto err_noexec;
793 }
794 if (name)
795 addrs[i] = w32dll_import_by_name(module, name);
796 else
797 addrs[i] = w32dll_import_by_ordinal(module, ordinal);
798 }
799
800 /* All done. */
801 return 1;
802
803 err_noexec:
804 errno = ENOEXEC;
805 return 0;
806 }
807
808 /*************************************************************************/
809
810 /**
811 * w32dll_import_by_name, w32dll_import_by_ordinal: Return the address
812 * corresponding to the given import, selected by either name or ordinal.
813 *
814 * Parameters:
815 * module: Name of the module from which to import.
816 * name: Import name descriptor (w32dll_import_by_name() only).
817 * ordinal: Import ordinal (w32dll_import_by_ordinal() only).
818 * Return value:
819 * The address corresponding to the import, or NULL if the import
820 * failed.
821 * Notes:
822 * - A NULL return is *not* considered an error, and thus errno is
823 * undefined after returning from these functions.
824 * - Currently, these functions just ask the Win32 emulation layer for
825 * an appropriate function, and do not handle linking between
826 * multiple loaded DLLs.
827 */
828
w32dll_import_by_name(const char * module,const struct import_name_entry * name)829 static void *w32dll_import_by_name(const char *module,
830 const struct import_name_entry *name)
831 {
832 return w32dll_emu_import_by_name(module, name);
833 }
834
835 /************************************/
836
w32dll_import_by_ordinal(const char * module,uint32_t ordinal)837 static void *w32dll_import_by_ordinal(const char *module, uint32_t ordinal)
838 {
839 return w32dll_emu_import_by_ordinal(module, ordinal);
840 }
841
842 /*************************************************************************/
843
844 /**
845 * w32dll_read_relocs: Read a set of relocation offsets for the DLL from
846 * the given file descriptor.
847 *
848 * Parameters:
849 * dll: DLL handle.
850 * fd: File descriptor to read from.
851 * relocs_ptr: Pointer to relocation entry array (dynamically allocated).
852 * nrelocs_ptr: Pointer to relocation entry count.
853 * Return value:
854 * Positive if relocations were read successfully.
855 * Zero if the end of the relocation table was reached.
856 * Negative if an error cocurred.
857 * Notes:
858 * - *relocs_ptr and *nrelocs_ptr must be initialized to NULL and 0,
859 * respectively, before the first call; they will be updated with
860 * each call.
861 * - On error, errno is set appropriately.
862 */
863
w32dll_read_relocs(W32DLLHandle dll,int fd,uint32_t ** relocs_ptr,int * nrelocs_ptr)864 static int w32dll_read_relocs(W32DLLHandle dll, int fd,
865 uint32_t **relocs_ptr, int *nrelocs_ptr)
866 {
867 uint32_t base, size, *new_relocs;
868 int index;
869
870 if (read(fd, &base, 4) != 4
871 || read(fd, &size, 4) != 4
872 || (size > 0 && size < 8)
873 ) {
874 free(*relocs_ptr);
875 *relocs_ptr = NULL;
876 *nrelocs_ptr = 0;
877 errno = ENOEXEC;
878 return -1;
879 }
880 if (!size)
881 return 0;
882 if (size <= 8) // Technically == works too, but play it safe
883 return 1;
884 size = (size-8) / 2; // Number of entries in this group
885 index = *nrelocs_ptr;
886 new_relocs = realloc(*relocs_ptr,
887 sizeof(**relocs_ptr) * (*nrelocs_ptr + size));
888 if (!new_relocs)
889 goto err_noexec;
890 *relocs_ptr = new_relocs;
891 *nrelocs_ptr += size;
892 while (size > 0) {
893 uint16_t buf[1000];
894 int toread, i;
895 toread = size;
896 if (toread > sizeof(buf)/2)
897 toread = sizeof(buf)/2;
898 if (read(fd, buf, toread*2) != toread*2)
899 goto err_noexec;
900 for (i = 0; i < toread; i++) {
901 if (buf[i]>>12 == 3) {
902 (*relocs_ptr)[index++] = dll->extheader.image_base
903 + base + (buf[i] & 0xFFF);
904 } else {
905 (*nrelocs_ptr)--;
906 }
907 }
908 size -= toread;
909 }
910 return 1;
911
912 err_noexec:
913 {
914 int errno_save = errno;
915 free(*relocs_ptr);
916 *relocs_ptr = NULL;
917 *nrelocs_ptr = 0;
918 errno = errno_save;
919 return -1;
920 }
921 }
922
923 /*************************************************************************/
924
925 /**
926 * w32dll_relocate: Perform relocations on the loaded DLL.
927 *
928 * Parameters:
929 * dll: DLL handle with all sections loaded.
930 * relocs: Array of virtual addresses to be relocated.
931 * nrelocs: Number of relocations.
932 * Return value:
933 * None.
934 */
935
936 #include <stdio.h>
w32dll_relocate(W32DLLHandle dll,uint32_t * relocs,int nrelocs)937 static void w32dll_relocate(W32DLLHandle dll, uint32_t *relocs, int nrelocs)
938 {
939 int i;
940
941 for (i = 0; i < nrelocs; i++) {
942 uint32_t *addr = w32dll_relocate_addr(dll, relocs[i]);
943 if (addr)
944 *addr = (uint32_t)w32dll_relocate_addr(dll, *addr);
945 }
946 }
947
948 /*************************************************************************/
949
950 /**
951 * w32dll_relocate_addr: Relocate a single address.
952 *
953 * Parameters:
954 * dll: DLL handle.
955 * addr: Address to relocate.
956 * Return value:
957 * The relocated address, or NULL if the address is not in a loaded
958 * section.
959 */
960
w32dll_relocate_addr(W32DLLHandle dll,uint32_t addr)961 static void *w32dll_relocate_addr(W32DLLHandle dll, uint32_t addr)
962 {
963 int i;
964
965 for (i = 0; i < dll->nsections; i++) {
966 if (addr >= dll->sections[i].origbase
967 && addr < dll->sections[i].origbase + dll->sections[i].origsize
968 ) {
969 return (uint8_t *)dll->sections[i].base
970 + (addr - dll->sections[i].origbase);
971 }
972 }
973 return NULL;
974 }
975
976 /*************************************************************************/
977
978 /**
979 * w32dll_read_asciiz: Read a null-terminated string from the given file
980 * descriptor.
981 *
982 * Parameters:
983 * fd: File descriptor to read from.
984 * Return value:
985 * String read in (allocated with malloc()), or NULL on error.
986 * Notes:
987 * On error, errno is set appropriately.
988 */
989
w32dll_read_asciiz(int fd)990 static char *w32dll_read_asciiz(int fd)
991 {
992 char *str = NULL;
993 int size = 0, len = 0;
994
995 do {
996 if (len >= size) {
997 size = len+100;
998 char *newstr = realloc(str, size);
999 if (!newstr) {
1000 int errno_save = errno;
1001 free(str);
1002 errno = errno_save;
1003 return NULL;
1004 }
1005 str = newstr;
1006 }
1007 if (read(fd, str+len, 1) != 1) {
1008 free(str);
1009 errno = ENOEXEC;
1010 return NULL;
1011 }
1012 len++;
1013 } while (str[len-1] != 0);
1014 return str;
1015 }
1016
1017 /*************************************************************************/
1018
1019 /**
1020 * w32dll_init_fs: Set up the FS segment register to point to a page of
1021 * data (empty except for the linear address pointer at 0x18).
1022 *
1023 * Parameters:
1024 * None.
1025 * Return value:
1026 * Nonzero on success, zero on failure.
1027 * Notes:
1028 * On error, errno is set appropriately.
1029 */
1030
1031 #if defined(OS_LINUX)
1032 # include <asm/unistd.h>
1033 # include <asm/ldt.h>
1034 // This doesn't work, because of PIC:
1035 //static _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount);
modify_ldt(int func,void * ptr,unsigned long bytecount)1036 static int modify_ldt(int func, void *ptr, unsigned long bytecount) {
1037 long __res;
1038 __asm__ volatile ("push %%ebx; mov %%esi, %%ebx; int $0x80; pop %%ebx"
1039 : "=a" (__res)
1040 : "0" (__NR_modify_ldt), "S" ((long)(func)),
1041 "c" ((long)(ptr)), "d" ((long)(bytecount))
1042 : "memory");
1043 /* Errors are from -1 to -128, according to <asm/unistd.h> */
1044 if ((__res & 0xFFFFFF80UL) == 0xFFFFFF80UL) {
1045 errno = -__res & 0xFF;
1046 __res = (unsigned long)-1;
1047 }
1048 return (int)__res;
1049 }
1050 #else
1051 # error OS not supported in w32dll_init_fs()
1052 #endif
1053
w32dll_init_fs(void)1054 static int w32dll_init_fs(void)
1055 {
1056 int fd;
1057 void *base;
1058 int segment;
1059 #if defined(OS_LINUX)
1060 struct user_desc ldt;
1061 #endif
1062
1063 fd = open("/dev/zero", O_RDWR);
1064 if (fd < 0)
1065 return 0;
1066 base = mmap(NULL, GETPAGESIZE(), PROT_READ | PROT_WRITE,
1067 MAP_PRIVATE, fd, 0);
1068 if (base == MAP_FAILED) {
1069 int errno_save = errno;
1070 close(fd);
1071 errno = errno_save;
1072 return 0;
1073 }
1074 close(fd);
1075 *(void **)((uint8_t *)base + 0x18) = base;
1076
1077 #if defined(OS_LINUX)
1078 memset(&ldt, 0, sizeof(ldt));
1079 /* Pick a random number that's hopefully unused. How does one
1080 * determine which segment numbers are in use? */
1081 ldt.entry_number = 172;
1082 ldt.base_addr = (long)base;
1083 ldt.limit = GETPAGESIZE();
1084 ldt.seg_32bit = 1;
1085 ldt.read_exec_only = 0;
1086 ldt.seg_not_present = 0;
1087 ldt.contents = MODIFY_LDT_CONTENTS_DATA;
1088 ldt.limit_in_pages = 0;
1089 ldt.seg_not_present = 0;
1090 ldt.useable = 1;
1091 if (modify_ldt(17, &ldt, sizeof(ldt)) != 0) {
1092 int errno_save = errno;
1093 munmap(base, GETPAGESIZE());
1094 errno = errno_save;
1095 return 0;
1096 }
1097 segment = ldt.entry_number;
1098 #endif
1099
1100 /* Bit 2: 1 == use LDT; bits 1-0: 3 == privilege level 3 */
1101 asm("movw %%ax,%%fs" : : "a" (segment<<3 | 1<<2 | 3));
1102 return 1;
1103 }
1104
1105 /*************************************************************************/
1106 /*************************************************************************/
1107
1108 #ifdef TEST
1109
1110 #include <stdio.h>
1111
main(int ac,char ** av)1112 int main(int ac, char **av)
1113 {
1114 W32DLLHandle dll;
1115
1116 if (ac < 2 || strcmp(av[1], "-h") == 0 || strcmp(av[1], "--help") == 0) {
1117 fprintf(stderr, "Usage: %s file.dll [procname | =ordinal]\n", av[0]);
1118 return -1;
1119 }
1120 dll = w32dll_load(av[1], 1);
1121 if (!dll) {
1122 perror(av[1]);
1123 return 1;
1124 }
1125 if (ac >= 3) {
1126 int i;
1127 void *(*func)(void);
1128 void ***codec, **functable, ***vid, **vidtable, ***aud, **audtable;
1129 WINAPI void *(*init)(int, int);
1130 WINAPI void *(*fini)(void);
1131 WINAPI void *(*getvid)(void);
1132 WINAPI void *(*getaud)(void);
1133 static char buf[0x14000], buf2[720*480*4], buf2a[0x800], buf3[0x2000];
1134 struct { int dataset; void *workbuf; struct {uint8_t w8, h8, f02, f03; int ofs;} *inparam; void *inbuf; struct {int stride; void *outbuf;} *outparam;} vidparam;
1135 void *bufptr = buf;
1136 struct { int flag; char *buffer; } audparam;
1137 int fd = open("/scratch/pv3/060428-192352-720x480i.dv", O_RDONLY);
1138 read(fd, buf, 0x14000);
1139 close(fd);
1140 if (av[2][0] == '=')
1141 func = w32dll_lookup_by_ordinal(dll, strtoul(av[2]+1,NULL,0));
1142 else
1143 func = w32dll_lookup_by_name(dll, av[2]);
1144 if (!func) {
1145 perror(av[2]);
1146 w32dll_unload(dll);
1147 return 2;
1148 }
1149 printf("%s: %p\n", av[2], func);
1150 codec = func();
1151 functable = *codec;
1152 printf("--> %p [%p %p %p %p...]\n", codec,
1153 functable[0], functable[1], functable[2], functable[3]);
1154 init = functable[0];
1155 fini = functable[1];
1156 getvid = functable[2];
1157 getaud = functable[3];
1158 printf("calling init...\n");
1159 //(*init)(4, 2);
1160 asm("push $2; push $4; call *%0" : : "r" (init), "c" (codec));
1161 printf("...done!\n");
1162 printf("calling getvid...\n");
1163 asm("call *%1" : "=a" (vid) : "r" (getvid), "c" (codec));
1164 vidtable = *vid;
1165 printf("...done! (%p -> %p %p ... %p ...)\n", aud,
1166 vidtable[0], vidtable[1], vidtable[5]);
1167 memset(&vidparam, 0, sizeof(vidparam));
1168 vidparam.dataset = 0;
1169 vidparam.workbuf = buf2a;
1170 vidparam.inparam = calloc(sizeof(*vidparam.inparam), 1);
1171 vidparam.inparam->w8 = buf[4];
1172 vidparam.inparam->h8 = buf[5];
1173 vidparam.inparam->ofs = 0;
1174 vidparam.inbuf = &bufptr;
1175 vidparam.outparam = malloc(sizeof(*vidparam.outparam));
1176 vidparam.outparam->stride = (buf[4]*8)*2;
1177 vidparam.outparam->outbuf = buf2;
1178 printf("calling video_decode...\n"); // 10013830
1179 asm("push %2; call *%1"
1180 : "=a" (i)
1181 : "r" (vidtable[5]), "r" (&vidparam), "c" (vid));
1182 printf("...done! (%d)\n", i);
1183 printf("and again...\n");
1184 vidparam.dataset = 1;
1185 asm("push %2; call *%1"
1186 : "=a" (i)
1187 : "r" (vidtable[5]), "r" (&vidparam), "c" (vid));
1188 printf("...done! (%d)\n", i);
1189 printf("calling getaud...\n");
1190 asm("call *%1" : "=a" (aud) : "r" (getaud), "c" (codec));
1191 audtable = *aud;
1192 printf("...done! (%p -> %p %p %p ...)\n", aud,
1193 audtable[0], audtable[1], audtable[2]);
1194 audparam.flag = 0;
1195 audparam.buffer = buf;
1196 *(void **)(buf3+24) = buf3+32;
1197 printf("calling audio_decode...\n"); // 10013830
1198 asm("push %3; push %2; call *%1"
1199 : "=a" (i)
1200 : "r" (audtable[1]), "r" (&audparam), "r" (buf3), "c" (aud));
1201 printf("...done! (%d)\n", i);
1202 fd = open("/scratch/pv3/test.raw", O_WRONLY | O_CREAT | O_TRUNC, 0666);
1203 write(fd, buf3, sizeof(buf3));
1204 write(fd, buf2, sizeof(buf2));
1205 close(fd);
1206 printf("calling fini...\n");
1207 asm("call *%0" : : "r" (fini), "c" (codec));
1208 //(*fini)();
1209 printf("...done!\n");
1210 }
1211 w32dll_unload(dll);
1212 return 0;
1213 }
1214
1215 #endif
1216
1217 /*************************************************************************/
1218
1219 /*
1220 * Local variables:
1221 * c-file-style: "stroustrup"
1222 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
1223 * indent-tabs-mode: nil
1224 * End:
1225 *
1226 * vim: expandtab shiftwidth=4:
1227 */
1228