No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / ndis / subr_pe.c
blobecaa1969ad5f90a1ba8de1e10155d70bd33226ad
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.
33 #include <sys/cdefs.h>
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7.2.3 2005/03/31 04:24:36 wpaul Exp $");
36 #endif
37 #ifdef __NetBSD__
38 __KERNEL_RCSID(0, "$NetBSD: subr_pe.c,v 1.5 2009/03/14 15:36:16 dsl Exp $");
39 #endif
43 * This file contains routines for relocating and dynamically linking
44 * executable object code files in the Windows(r) PE (Portable Executable)
45 * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
46 * considered an executable, and all such files have some structures in
47 * common. The PE format was apparently based largely on COFF but has
48 * mutated significantly over time. We are mainly concerned with .SYS files,
49 * so this module implements only enough routines to be able to parse the
50 * headers and sections of a .SYS object file and perform the necessary
51 * relocations and jump table patching to allow us to call into it
52 * (and to have it call back to us). Note that while this module
53 * can handle fixups for imported symbols, it knows nothing about
54 * exporting them.
57 #include <sys/param.h>
58 #include <sys/types.h>
59 #include <sys/errno.h>
60 #include <sys/lock.h>
61 #ifdef _KERNEL
62 #include <sys/systm.h>
63 extern int ndis_strncasecmp(const char *, const char *, size_t);
64 #define strncasecmp(a, b, c) ndis_strncasecmp(a, b, c)
65 #else
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <unistd.h>
69 #include <string.h>
70 #endif
72 #include <compat/ndis/pe_var.h>
74 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
77 * Check for an MS-DOS executable header. All Windows binaries
78 * have a small MS-DOS executable prepended to them to print out
79 * the "This program requires Windows" message. Even .SYS files
80 * have this header, in spite of the fact that you're can't actually
81 * run them directly.
84 int
85 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
87 uint16_t signature;
89 if (imgbase == 0 || hdr == NULL)
90 return (EINVAL);
92 signature = *(uint16_t *)imgbase;
93 if (signature != IMAGE_DOS_SIGNATURE)
94 return (ENOEXEC);
96 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
98 return(0);
102 * Verify that this image has a Windows NT PE signature.
106 pe_is_nt_image(vm_offset_t imgbase)
108 uint32_t signature;
109 image_dos_header *dos_hdr;
111 if (imgbase == 0)
112 return (EINVAL);
114 signature = *(uint16_t *)imgbase;
115 if (signature == IMAGE_DOS_SIGNATURE) {
116 dos_hdr = (image_dos_header *)imgbase;
117 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
118 if (signature == IMAGE_NT_SIGNATURE)
119 return(0);
122 return(ENOEXEC);
126 * Return a copy of the optional header. This contains the
127 * executable entry point and the directory listing which we
128 * need to find the relocations and imports later.
132 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
134 image_dos_header *dos_hdr;
135 image_nt_header *nt_hdr;
137 if (imgbase == 0 || hdr == NULL)
138 return(EINVAL);
140 if (pe_is_nt_image(imgbase))
141 return (EINVAL);
143 dos_hdr = (image_dos_header *)(imgbase);
144 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
146 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
147 sizeof(image_optional_header));
149 return(0);
153 * Return a copy of the file header. Contains the number of
154 * sections in this image.
158 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
160 image_dos_header *dos_hdr;
161 image_nt_header *nt_hdr;
163 if (imgbase == 0 || hdr == NULL)
164 return(EINVAL);
166 if (pe_is_nt_image(imgbase))
167 return (EINVAL);
169 dos_hdr = (image_dos_header *)imgbase;
170 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
172 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
173 sizeof(image_file_header));
175 return(0);
179 * Return the header of the first section in this image (usually
180 * .text).
184 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
186 image_dos_header *dos_hdr;
187 image_nt_header *nt_hdr;
188 image_section_header *sect_hdr;
190 if (imgbase == 0 || hdr == NULL)
191 return(EINVAL);
193 if (pe_is_nt_image(imgbase))
194 return (EINVAL);
196 dos_hdr = (image_dos_header *)imgbase;
197 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
198 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
199 sizeof(image_nt_header));
201 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
203 return(0);
207 * Return the number of sections in this executable, or 0 on error.
211 pe_numsections(vm_offset_t imgbase)
213 image_file_header file_hdr;
215 if (pe_get_file_header(imgbase, &file_hdr))
216 return(0);
218 return (file_hdr.ifh_numsections);
222 * Return the base address that this image was linked for.
223 * This helps us calculate relocation addresses later.
226 vm_offset_t
227 pe_imagebase(vm_offset_t imgbase)
229 image_optional_header optional_hdr;
231 if (pe_get_optional_header(imgbase, &optional_hdr))
232 return(0);
234 return (optional_hdr.ioh_imagebase);
238 * Return the offset of a given directory structure within the
239 * image. Directories reside within sections.
242 vm_offset_t
243 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
245 image_optional_header opt_hdr;
246 vm_offset_t dir;
248 if (pe_get_optional_header(imgbase, &opt_hdr))
249 return(0);
251 if (diridx >= opt_hdr.ioh_rva_size_cnt)
252 return(0);
254 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
256 return(pe_translate_addr(imgbase, dir));
259 vm_offset_t
260 pe_translate_addr(vm_offset_t imgbase, vm_offset_t rva)
262 image_optional_header opt_hdr;
263 image_section_header *sect_hdr;
264 image_dos_header *dos_hdr;
265 image_nt_header *nt_hdr;
266 int i = 0, sections, fixedlen;
268 if (pe_get_optional_header(imgbase, &opt_hdr))
269 return(0);
271 sections = pe_numsections(imgbase);
273 dos_hdr = (image_dos_header *)imgbase;
274 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
275 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
276 sizeof(image_nt_header));
279 * The test here is to see if the RVA falls somewhere
280 * inside the section, based on the section's start RVA
281 * and its length. However it seems sometimes the
282 * virtual length isn't enough to cover the entire
283 * area of the section. We fudge by taking into account
284 * the section alignment and rounding the section length
285 * up to a page boundary.
287 while (i++ < sections) {
288 fixedlen = sect_hdr->ish_misc.ish_vsize;
289 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
290 sect_hdr->ish_misc.ish_vsize) &
291 (opt_hdr.ioh_sectalign - 1);
292 if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
293 (sect_hdr->ish_vaddr + fixedlen) >
294 (uint32_t)rva)
295 break;
296 sect_hdr++;
299 if (i > sections)
300 return(0);
302 return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
303 sect_hdr->ish_rawdataaddr));
307 * Get the section header for a particular section. Note that
308 * section names can be anything, but there are some standard
309 * ones (.text, .data, .rdata, .reloc).
313 pe_get_section(vm_offset_t imgbase, image_section_header *hdr, const char *name)
315 image_dos_header *dos_hdr;
316 image_nt_header *nt_hdr;
317 image_section_header *sect_hdr;
319 int i, sections;
321 if (imgbase == 0 || hdr == NULL)
322 return(EINVAL);
324 if (pe_is_nt_image(imgbase))
325 return (EINVAL);
327 sections = pe_numsections(imgbase);
329 dos_hdr = (image_dos_header *)imgbase;
330 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
331 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
332 sizeof(image_nt_header));
334 for (i = 0; i < sections; i++) {
335 if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
336 memcpy( (char *)hdr, (char *)sect_hdr,
337 sizeof(image_section_header));
338 return(0);
339 } else
340 sect_hdr++;
343 return (ENOEXEC);
347 * Apply the base relocations to this image. The relocation table
348 * resides within the .reloc section. Relocations are specified in
349 * blocks which refer to a particular page. We apply the relocations
350 * one page block at a time.
354 pe_relocate(vm_offset_t imgbase)
356 image_section_header sect;
357 image_base_reloc *relhdr;
358 uint16_t rel, *sloc;
359 vm_offset_t base;
360 vm_size_t delta;
361 uint32_t *lloc;
362 uint64_t *qloc;
363 int i, count;
364 vm_offset_t txt;
366 base = pe_imagebase(imgbase);
367 pe_get_section(imgbase, &sect, ".text");
368 txt = pe_translate_addr(imgbase, sect.ish_vaddr);
369 delta = (uint32_t)(txt) - base - sect.ish_vaddr;
371 pe_get_section(imgbase, &sect, ".reloc");
373 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
375 do {
376 count = (relhdr->ibr_blocksize -
377 (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
378 for (i = 0; i < count; i++) {
379 rel = relhdr->ibr_rel[i];
380 switch (IMR_RELTYPE(rel)) {
381 case IMAGE_REL_BASED_ABSOLUTE:
382 break;
383 case IMAGE_REL_BASED_HIGHLOW:
384 lloc = (uint32_t *)pe_translate_addr(imgbase,
385 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
386 *lloc = pe_translate_addr(imgbase,
387 (*lloc - base));
388 break;
389 case IMAGE_REL_BASED_HIGH:
390 sloc = (uint16_t *)pe_translate_addr(imgbase,
391 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
392 *sloc += (delta & 0xFFFF0000) >> 16;
393 break;
394 case IMAGE_REL_BASED_LOW:
395 sloc = (uint16_t *)pe_translate_addr(imgbase,
396 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
397 *sloc += (delta & 0xFFFF);
398 break;
399 case IMAGE_REL_BASED_DIR64:
400 qloc = (uint64_t *)pe_translate_addr(imgbase,
401 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
402 *qloc = pe_translate_addr(imgbase,
403 (*qloc - base));
404 break;
406 default:
407 printf ("[%d]reloc type: %d\n",i,
408 IMR_RELTYPE(rel));
409 break;
412 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
413 relhdr->ibr_blocksize);
414 } while (relhdr->ibr_blocksize);
416 return(0);
420 * Return the import descriptor for a particular module. An image
421 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
422 * and NDIS.SYS. For each module, there is a list of imported function
423 * names and their addresses.
425 * Note: module names are case insensitive!
429 pe_get_import_descriptor(imgbase, desc, module)
430 vm_offset_t imgbase;
431 image_import_descriptor *desc;
432 const char *module;
434 vm_offset_t offset;
435 image_import_descriptor *imp_desc;
436 char *modname;
438 if (imgbase == 0 || module == NULL || desc == NULL)
439 return(EINVAL);
441 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
442 if (offset == 0)
443 return (ENOENT);
445 imp_desc = (void *)offset;
447 while (imp_desc->iid_nameaddr) {
448 modname = (char *)pe_translate_addr(imgbase,
449 imp_desc->iid_nameaddr);
450 if (!strncasecmp(module, modname, strlen(module))) {
451 memcpy( (char *)desc, (char *)imp_desc,
452 sizeof(image_import_descriptor));
453 return(0);
455 imp_desc++;
458 return (ENOENT);
462 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
464 image_resource_directory *rdir, *rtype;
465 image_resource_directory_entry *dent, *dent2;
466 image_resource_data_entry *rent;
467 vm_offset_t offset;
468 int i;
470 if (imgbase == 0)
471 return(EINVAL);
473 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
474 if (offset == 0)
475 return (ENOENT);
477 rdir = (image_resource_directory *)offset;
479 dent = (image_resource_directory_entry *)(offset +
480 sizeof(image_resource_directory));
482 for (i = 0; i < rdir->ird_id_entries; i++){
483 if (dent->irde_name != RT_MESSAGETABLE) {
484 dent++;
485 continue;
487 dent2 = dent;
488 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
489 rtype = (image_resource_directory *)(offset +
490 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
491 dent2 = (image_resource_directory_entry *)
492 ((uintptr_t)rtype +
493 sizeof(image_resource_directory));
495 rent = (image_resource_data_entry *)(offset +
496 dent2->irde_dataoff);
497 *md = (message_resource_data *)pe_translate_addr(imgbase,
498 rent->irde_offset);
499 return(0);
502 return(ENOENT);
506 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len, uint16_t *flags)
508 message_resource_data *md = NULL;
509 message_resource_block *mb;
510 message_resource_entry *me;
511 uint32_t i;
513 pe_get_messagetable(imgbase, &md);
515 if (md == NULL)
516 return(ENOENT);
518 mb = (message_resource_block *)((uintptr_t)md +
519 sizeof(message_resource_data));
521 for (i = 0; i < md->mrd_numblocks; i++) {
522 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
523 me = (message_resource_entry *)((uintptr_t)md +
524 mb->mrb_entryoff);
525 for (i = id - mb->mrb_lowid; i > 0; i--)
526 me = (message_resource_entry *)((uintptr_t)me +
527 me->mre_len);
528 *str = me->mre_text;
529 *len = me->mre_len;
530 *flags = me->mre_flags;
531 return(0);
533 mb++;
536 return(ENOENT);
540 * Find the function that matches a particular name. This doesn't
541 * need to be particularly speedy since it's only run when loading
542 * a module for the first time.
545 static vm_offset_t
546 pe_functbl_match(image_patch_table *functbl, char *name)
548 image_patch_table *p;
550 if (functbl == NULL || name == NULL)
551 return(0);
553 p = functbl;
555 while (p->ipt_name != NULL) {
556 if (!strcmp(p->ipt_name, name))
557 return((vm_offset_t)p->ipt_wrap);
558 p++;
560 printf ("no match for %s\n", name);
563 * Return the wrapper pointer for this routine.
564 * For x86, this is the same as the funcptr.
565 * For amd64, this points to a wrapper routine
566 * that does calling convention translation and
567 * then invokes the underlying routine.
569 return((vm_offset_t)p->ipt_wrap);
573 * Patch the imported function addresses for a given module.
574 * The caller must specify the module name and provide a table
575 * of function pointers that will be patched into the jump table.
576 * Note that there are actually two copies of the jump table: one
577 * copy is left alone. In a .SYS file, the jump tables are usually
578 * merged into the INIT segment.
582 pe_patch_imports(vm_offset_t imgbase, const char *module, image_patch_table *functbl)
584 image_import_descriptor imp_desc;
585 char *fname;
586 vm_offset_t *nptr, *fptr;
587 vm_offset_t func;
589 if (imgbase == 0 || module == NULL || functbl == NULL)
590 return(EINVAL);
592 if (pe_get_import_descriptor(imgbase, &imp_desc, module))
593 return(ENOEXEC);
595 nptr = (vm_offset_t *)pe_translate_addr(imgbase,
596 imp_desc.iid_import_name_table_addr);
597 fptr = (vm_offset_t *)pe_translate_addr(imgbase,
598 imp_desc.iid_import_address_table_addr);
600 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
601 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
602 func = pe_functbl_match(functbl, fname);
603 if (func)
604 *fptr = func;
605 #ifdef notdef
606 if (*fptr == 0)
607 return(ENOENT);
608 #endif
609 nptr++;
610 fptr++;
613 return(0);