HAMMER 61E/Many: Stabilization, Performance
[dragonfly.git] / sys / emulation / ndis / subr_pe.c
blobba78ddf171ca36b21988971694199749621644ca
1 /*
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $DragonFly: src/sys/emulation/ndis/subr_pe.c,v 1.3 2006/12/23 00:27:02 swildner Exp $
33 * $FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7 2004/01/13 22:49:45 obrien Exp $
37 * This file contains routines for relocating and dynamically linking
38 * executable object code files in the Windows(r) PE (Portable Executable)
39 * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
40 * considered an executable, and all such files have some structures in
41 * common. The PE format was apparently based largely on COFF but has
42 * mutated significantly over time. We are mainly concerned with .SYS files,
43 * so this module implements only enough routines to be able to parse the
44 * headers and sections of a .SYS object file and perform the necessary
45 * relocations and jump table patching to allow us to call into it
46 * (and to have it call back to us). Note that while this module
47 * can handle fixups for imported symbols, it knows nothing about
48 * exporting them.
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/errno.h>
54 #ifdef _KERNEL
55 #include <sys/systm.h>
56 #else
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #define kprintf printf /* ndiscvt(8) uses this file */
62 #endif
64 #include "regcall.h"
65 #include "pe_var.h"
67 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
70 * Check for an MS-DOS executable header. All Windows binaries
71 * have a small MS-DOS executable prepended to them to print out
72 * the "This program requires Windows" message. Even .SYS files
73 * have this header, in spite of the fact that you're can't actually
74 * run them directly.
77 int
78 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
80 uint16_t signature;
82 if (imgbase == 0 || hdr == NULL)
83 return (EINVAL);
85 signature = *(uint16_t *)imgbase;
86 if (signature != IMAGE_DOS_SIGNATURE)
87 return (ENOEXEC);
89 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
91 return(0);
95 * Verify that this image has a Windows NT PE signature.
98 int
99 pe_is_nt_image(vm_offset_t imgbase)
101 uint32_t signature;
102 image_dos_header *dos_hdr;
104 if (imgbase == 0)
105 return (EINVAL);
107 signature = *(uint16_t *)imgbase;
108 if (signature == IMAGE_DOS_SIGNATURE) {
109 dos_hdr = (image_dos_header *)imgbase;
110 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
111 if (signature == IMAGE_NT_SIGNATURE)
112 return(0);
115 return(ENOEXEC);
119 * Return a copy of the optional header. This contains the
120 * executable entry point and the directory listing which we
121 * need to find the relocations and imports later.
125 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
127 image_dos_header *dos_hdr;
128 image_nt_header *nt_hdr;
130 if (imgbase == 0 || hdr == NULL)
131 return(EINVAL);
133 if (pe_is_nt_image(imgbase))
134 return (EINVAL);
136 dos_hdr = (image_dos_header *)(imgbase);
137 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
139 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
140 sizeof(image_optional_header));
142 return(0);
146 * Return a copy of the file header. Contains the number of
147 * sections in this image.
151 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
153 image_dos_header *dos_hdr;
154 image_nt_header *nt_hdr;
156 if (imgbase == 0 || hdr == NULL)
157 return(EINVAL);
159 if (pe_is_nt_image(imgbase))
160 return (EINVAL);
162 dos_hdr = (image_dos_header *)imgbase;
163 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
165 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
166 sizeof(image_file_header));
168 return(0);
172 * Return the header of the first section in this image (usually
173 * .text).
177 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
179 image_dos_header *dos_hdr;
180 image_nt_header *nt_hdr;
181 image_section_header *sect_hdr;
183 if (imgbase == 0 || hdr == NULL)
184 return(EINVAL);
186 if (pe_is_nt_image(imgbase))
187 return (EINVAL);
189 dos_hdr = (image_dos_header *)imgbase;
190 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
191 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
192 sizeof(image_nt_header));
194 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
196 return(0);
200 * Return the number of sections in this executable, or 0 on error.
204 pe_numsections(vm_offset_t imgbase)
206 image_file_header file_hdr;
208 if (pe_get_file_header(imgbase, &file_hdr))
209 return(0);
211 return (file_hdr.ifh_numsections);
215 * Return the base address that this image was linked for.
216 * This helps us calculate relocation addresses later.
219 vm_offset_t
220 pe_imagebase(vm_offset_t imgbase)
222 image_optional_header optional_hdr;
224 if (pe_get_optional_header(imgbase, &optional_hdr))
225 return(0);
227 return (optional_hdr.ioh_imagebase);
231 * Return the offset of a given directory structure within the
232 * image. Directories reside within sections.
235 vm_offset_t
236 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
238 image_optional_header opt_hdr;
239 vm_offset_t dir;
241 if (pe_get_optional_header(imgbase, &opt_hdr))
242 return(0);
244 if (diridx >= opt_hdr.ioh_rva_size_cnt)
245 return(0);
247 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
249 return(pe_translate_addr(imgbase, dir));
252 vm_offset_t
253 pe_translate_addr(vm_offset_t imgbase, uint32_t rva)
255 image_optional_header opt_hdr;
256 image_section_header *sect_hdr;
257 image_dos_header *dos_hdr;
258 image_nt_header *nt_hdr;
259 int i = 0, sections, fixedlen;
261 if (pe_get_optional_header(imgbase, &opt_hdr))
262 return(0);
264 sections = pe_numsections(imgbase);
266 dos_hdr = (image_dos_header *)imgbase;
267 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
268 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
269 sizeof(image_nt_header));
272 * The test here is to see if the RVA falls somewhere
273 * inside the section, based on the section's start RVA
274 * and its length. However it seems sometimes the
275 * virtual length isn't enough to cover the entire
276 * area of the section. We fudge by taking into account
277 * the section alignment and rounding the section length
278 * up to a page boundary.
280 while (i++ < sections) {
281 fixedlen = sect_hdr->ish_misc.ish_vsize;
282 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
283 sect_hdr->ish_misc.ish_vsize) &
284 (opt_hdr.ioh_sectalign - 1);
285 if (sect_hdr->ish_vaddr <= (u_int32_t)rva &&
286 (sect_hdr->ish_vaddr + fixedlen) >
287 (u_int32_t)rva)
288 break;
289 sect_hdr++;
292 if (i > sections)
293 return(0);
295 return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
296 sect_hdr->ish_rawdataaddr));
300 * Get the section header for a particular section. Note that
301 * section names can be anything, but there are some standard
302 * ones (.text, .data, .rdata, .reloc).
306 pe_get_section(vm_offset_t imgbase, image_section_header *hdr,
307 const char *name)
309 image_dos_header *dos_hdr;
310 image_nt_header *nt_hdr;
311 image_section_header *sect_hdr;
313 int i, sections;
315 if (imgbase == 0 || hdr == NULL)
316 return(EINVAL);
318 if (pe_is_nt_image(imgbase))
319 return (EINVAL);
321 sections = pe_numsections(imgbase);
323 dos_hdr = (image_dos_header *)imgbase;
324 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
325 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
326 sizeof(image_nt_header));
328 for (i = 0; i < sections; i++) {
329 if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
330 bcopy((char *)sect_hdr, (char *)hdr,
331 sizeof(image_section_header));
332 return(0);
333 } else
334 sect_hdr++;
337 return (ENOEXEC);
341 * Apply the base relocations to this image. The relocation table
342 * resides within the .reloc section. Relocations are specified in
343 * blocks which refer to a particular page. We apply the relocations
344 * one page block at a time.
348 pe_relocate(vm_offset_t imgbase)
350 image_section_header sect;
351 image_base_reloc *relhdr;
352 uint16_t rel, *sloc;
353 uint32_t base, delta, *lloc;
354 int i, count;
355 vm_offset_t txt;
357 base = pe_imagebase(imgbase);
358 pe_get_section(imgbase, &sect, ".text");
359 txt = pe_translate_addr(imgbase, sect.ish_vaddr);
360 delta = (uint32_t)(txt) - base - sect.ish_vaddr;
362 pe_get_section(imgbase, &sect, ".reloc");
364 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
366 do {
367 count = (relhdr->ibr_blocksize -
368 (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
369 for (i = 0; i < count; i++) {
370 rel = relhdr->ibr_rel[i];
371 switch (IMR_RELTYPE(rel)) {
372 case IMAGE_REL_BASED_ABSOLUTE:
373 break;
374 case IMAGE_REL_BASED_HIGHLOW:
375 lloc = (uint32_t *)pe_translate_addr(imgbase,
376 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
377 *lloc = pe_translate_addr(imgbase,
378 (*lloc - base));
379 break;
380 case IMAGE_REL_BASED_HIGH:
381 sloc = (uint16_t *)pe_translate_addr(imgbase,
382 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
383 *sloc += (delta & 0xFFFF0000) >> 16;
384 break;
385 case IMAGE_REL_BASED_LOW:
386 sloc = (uint16_t *)pe_translate_addr(imgbase,
387 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
388 *sloc += (delta & 0xFFFF);
389 break;
390 default:
391 kprintf ("[%d]reloc type: %d\n",i,
392 IMR_RELTYPE(rel));
393 break;
396 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
397 relhdr->ibr_blocksize);
398 } while (relhdr->ibr_blocksize);
400 return(0);
404 * Return the import descriptor for a particular module. An image
405 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
406 * and NDIS.SYS. For each module, there is a list of imported function
407 * names and their addresses.
411 pe_get_import_descriptor(vm_offset_t imgbase, image_import_descriptor *desc,
412 char *module)
414 vm_offset_t offset;
415 image_import_descriptor *imp_desc;
416 char *modname;
418 if (imgbase == 0 || module == NULL || desc == NULL)
419 return(EINVAL);
421 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
422 if (offset == 0)
423 return (ENOENT);
425 imp_desc = (void *)offset;
427 while (imp_desc->iid_nameaddr) {
428 modname = (char *)pe_translate_addr(imgbase,
429 imp_desc->iid_nameaddr);
430 if (!strncmp(module, modname, strlen(module))) {
431 bcopy((char *)imp_desc, (char *)desc,
432 sizeof(image_import_descriptor));
433 return(0);
435 imp_desc++;
438 return (ENOENT);
442 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
444 image_resource_directory *rdir, *rtype;
445 image_resource_directory_entry *dent, *dent2;
446 image_resource_data_entry *rent;
447 vm_offset_t offset;
448 int i;
450 if (imgbase == 0)
451 return(EINVAL);
453 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
454 if (offset == 0)
455 return (ENOENT);
457 rdir = (image_resource_directory *)offset;
459 dent = (image_resource_directory_entry *)(offset +
460 sizeof(image_resource_directory));
462 for (i = 0; i < rdir->ird_id_entries; i++){
463 if (dent->irde_name != RT_MESSAGETABLE) {
464 dent++;
465 continue;
467 dent2 = dent;
468 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
469 rtype = (image_resource_directory *)(offset +
470 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
471 dent2 = (image_resource_directory_entry *)
472 ((uintptr_t)rtype +
473 sizeof(image_resource_directory));
475 rent = (image_resource_data_entry *)(offset +
476 dent2->irde_dataoff);
477 *md = (message_resource_data *)pe_translate_addr(imgbase,
478 rent->irde_offset);
479 return(0);
482 return(ENOENT);
486 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len,
487 uint16_t *flags)
489 message_resource_data *md = NULL;
490 message_resource_block *mb;
491 message_resource_entry *me;
492 uint32_t i;
494 pe_get_messagetable(imgbase, &md);
496 if (md == NULL)
497 return(ENOENT);
499 mb = (message_resource_block *)((uintptr_t)md +
500 sizeof(message_resource_data));
502 for (i = 0; i < md->mrd_numblocks; i++) {
503 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
504 me = (message_resource_entry *)((uintptr_t)md +
505 mb->mrb_entryoff);
506 for (i = id - mb->mrb_lowid; i > 0; i--)
507 me = (message_resource_entry *)((uintptr_t)me +
508 me->mre_len);
509 *str = me->mre_text;
510 *len = me->mre_len;
511 *flags = me->mre_flags;
512 return(0);
514 mb++;
517 return(ENOENT);
521 * Find the function that matches a particular name. This doesn't
522 * need to be particularly speedy since it's only run when loading
523 * a module for the first time.
526 static vm_offset_t
527 pe_functbl_match(image_patch_table *functbl, char *name)
529 image_patch_table *p;
531 if (functbl == NULL || name == NULL)
532 return(0);
534 p = functbl;
536 while (p->ipt_name != NULL) {
537 if (!strcmp(p->ipt_name, name))
538 return((vm_offset_t)p->ipt_func);
539 p++;
541 kprintf ("no match for %s\n", name);
542 return((vm_offset_t)p->ipt_func);
546 * Patch the imported function addresses for a given module.
547 * The caller must specify the module name and provide a table
548 * of function pointers that will be patched into the jump table.
549 * Note that there are actually two copies of the jump table: one
550 * copy is left alone. In a .SYS file, the jump tables are usually
551 * merged into the INIT segment.
555 pe_patch_imports(vm_offset_t imgbase, char *module,
556 image_patch_table *functbl)
558 image_import_descriptor imp_desc;
559 char *fname;
560 vm_offset_t *nptr, *fptr;
561 vm_offset_t func;
563 if (imgbase == 0 || module == NULL || functbl == NULL)
564 return(EINVAL);
566 if (pe_get_import_descriptor(imgbase, &imp_desc, module))
567 return(ENOEXEC);
569 nptr = (vm_offset_t *)pe_translate_addr(imgbase,
570 imp_desc.iid_import_name_table_addr);
571 fptr = (vm_offset_t *)pe_translate_addr(imgbase,
572 imp_desc.iid_import_address_table_addr);
574 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
575 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
576 func = pe_functbl_match(functbl, fname);
577 if (func)
578 *fptr = func;
579 #ifdef notdef
580 if (*fptr == 0)
581 return(ENOENT);
582 #endif
583 nptr++;
584 fptr++;
587 return(0);