(Searching and Matching): Mention property search.
[emacs.git] / nt / preprep.c
blobfb686f42b96a98298e59a4f65e62f8c51e942f05
1 /* Pro-process emacs.exe for profiling by MSVC.
2 Copyright (C) 1999, 2002, 2003, 2004, 2005,
3 2006 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Andrew Innes <andrewi@harlequin.co.uk> 16-Jan-1999
23 based on code from addsection.c
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <time.h>
30 #ifdef __GNUC__
31 #define _ANONYMOUS_UNION
32 #define _ANONYMOUS_STRUCT
33 #endif
34 #include <windows.h>
36 /* Include relevant definitions from IMAGEHLP.H, which can be found
37 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
39 PIMAGE_NT_HEADERS
40 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
41 DWORD FileLength,
42 LPDWORD HeaderSum,
43 LPDWORD CheckSum);
45 #undef min
46 #undef max
47 #define min(x, y) (((x) < (y)) ? (x) : (y))
48 #define max(x, y) (((x) > (y)) ? (x) : (y))
51 /* File handling. */
53 typedef struct file_data {
54 char *name;
55 unsigned long size;
56 HANDLE file;
57 HANDLE file_mapping;
58 unsigned char *file_base;
59 } file_data;
61 int
62 open_input_file (file_data *p_file, char *filename)
64 HANDLE file;
65 HANDLE file_mapping;
66 void *file_base;
67 unsigned long size, upper_size;
69 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
70 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
71 if (file == INVALID_HANDLE_VALUE)
72 return FALSE;
74 size = GetFileSize (file, &upper_size);
75 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
76 0, size, NULL);
77 if (!file_mapping)
78 return FALSE;
80 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
81 if (file_base == 0)
82 return FALSE;
84 p_file->name = filename;
85 p_file->size = size;
86 p_file->file = file;
87 p_file->file_mapping = file_mapping;
88 p_file->file_base = file_base;
90 return TRUE;
93 int
94 open_output_file (file_data *p_file, char *filename, unsigned long size)
96 HANDLE file;
97 HANDLE file_mapping;
98 void *file_base;
100 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
101 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
102 if (file == INVALID_HANDLE_VALUE)
103 return FALSE;
105 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
106 0, size, NULL);
107 if (!file_mapping)
108 return FALSE;
110 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
111 if (file_base == 0)
112 return FALSE;
114 p_file->name = filename;
115 p_file->size = size;
116 p_file->file = file;
117 p_file->file_mapping = file_mapping;
118 p_file->file_base = file_base;
120 return TRUE;
124 open_inout_file (file_data *p_file, char *filename)
126 HANDLE file;
127 HANDLE file_mapping;
128 void *file_base;
129 unsigned long size, upper_size;
131 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
132 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
133 if (file == INVALID_HANDLE_VALUE)
134 return FALSE;
136 size = GetFileSize (file, &upper_size);
137 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
138 0, size, NULL);
139 if (!file_mapping)
140 return FALSE;
142 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
143 if (file_base == 0)
144 return FALSE;
146 p_file->name = filename;
147 p_file->size = size;
148 p_file->file = file;
149 p_file->file_mapping = file_mapping;
150 p_file->file_base = file_base;
152 return TRUE;
155 /* Close the system structures associated with the given file. */
156 void
157 close_file_data (file_data *p_file)
159 UnmapViewOfFile (p_file->file_base);
160 CloseHandle (p_file->file_mapping);
161 /* For the case of output files, set final size. */
162 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
163 SetEndOfFile (p_file->file);
164 CloseHandle (p_file->file);
168 /* Routines to manipulate NT executable file sections. */
170 unsigned long
171 get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section)
173 /* The true section size, before rounding, for an initialized data or
174 code section. (Supposedly some linkers swap the meaning of these
175 two values.) */
176 return min (p_section->SizeOfRawData,
177 p_section->Misc.VirtualSize);
180 /* Return pointer to section header for named section. */
181 IMAGE_SECTION_HEADER *
182 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
184 PIMAGE_SECTION_HEADER section;
185 int i;
187 section = IMAGE_FIRST_SECTION (nt_header);
189 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
191 if (strcmp (section->Name, name) == 0)
192 return section;
193 section++;
195 return NULL;
198 /* Return pointer to section header for section containing the given
199 relative virtual address. */
200 IMAGE_SECTION_HEADER *
201 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
203 PIMAGE_SECTION_HEADER section;
204 int i;
206 section = IMAGE_FIRST_SECTION (nt_header);
208 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
210 /* Some linkers (eg. the NT SDK linker I believe) swapped the
211 meaning of these two values - or rather, they ignored
212 VirtualSize entirely and always set it to zero. This affects
213 some very old exes (eg. gzip dated Dec 1993). Since
214 w32_executable_type relies on this function to work reliably,
215 we need to cope with this. */
216 DWORD real_size = max (section->SizeOfRawData,
217 section->Misc.VirtualSize);
218 if (rva >= section->VirtualAddress
219 && rva < section->VirtualAddress + real_size)
220 return section;
221 section++;
223 return NULL;
226 /* Return pointer to section header for section containing the given
227 offset in its raw data area. */
228 IMAGE_SECTION_HEADER *
229 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
231 PIMAGE_SECTION_HEADER section;
232 int i;
234 section = IMAGE_FIRST_SECTION (nt_header);
236 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
238 if (offset >= section->PointerToRawData
239 && offset < section->PointerToRawData + section->SizeOfRawData)
240 return section;
241 section++;
243 return NULL;
246 /* Return offset to an object in dst, given offset in src. We assume
247 there is at least one section in both src and dst images, and that
248 the some sections may have been added to dst (after sections in src). */
249 static DWORD
250 relocate_offset (DWORD offset,
251 IMAGE_NT_HEADERS * src_nt_header,
252 IMAGE_NT_HEADERS * dst_nt_header)
254 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
255 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
256 int i = 0;
258 while (offset >= src_section->PointerToRawData)
260 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
261 break;
262 i++;
263 if (i == src_nt_header->FileHeader.NumberOfSections)
265 /* Handle offsets after the last section. */
266 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
267 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
268 while (dst_section->PointerToRawData == 0)
269 dst_section--;
270 while (src_section->PointerToRawData == 0)
271 src_section--;
272 return offset
273 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
274 - (src_section->PointerToRawData + src_section->SizeOfRawData);
276 src_section++;
277 dst_section++;
279 return offset +
280 (dst_section->PointerToRawData - src_section->PointerToRawData);
283 #define OFFSET_TO_RVA(offset, section) \
284 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
286 #define RVA_TO_OFFSET(rva, section) \
287 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
289 #define RVA_TO_SECTION_OFFSET(rva, section) \
290 ((DWORD)(rva) - section->VirtualAddress)
292 #define RVA_TO_PTR(var,section,filedata) \
293 ((void *)(RVA_TO_OFFSET(var,section) + (filedata)->file_base))
295 /* Convert address in executing image to RVA. */
296 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
298 #define PTR_TO_OFFSET(ptr, pfile_data) \
299 ((unsigned char *)(ptr) - (pfile_data)->file_base)
301 #define OFFSET_TO_PTR(offset, pfile_data) \
302 ((pfile_data)->file_base + (DWORD)(offset))
304 #define ROUND_UP(p, align) (((DWORD)(p) + (align)-1) & ~((align)-1))
305 #define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
308 /* The MSVC prep program generates a ._xe file from .exe, where relevant
309 function calls etc have been patched to go through thunks (generated
310 by prep) that record timing/call information. Because the thunks
311 need to make references to functions imported from profile.dll, the
312 import table must be expanded; the end result is that all the
313 sections following .rdata are relocated to higher RVAs (add a final
314 code section is added holding all the thunks). The .reloc section is
315 also expanded, so that the thunks themselves are relocatable.
317 It is this relocation which kills emacs._xe, because the dumped heap
318 pointers aren't relocated, because there is no relocation data for
319 either the relevant global/static variables or the heap section
320 itself, both of which contain pointers into the heap. [Note that
321 static variables which aren't initialized during linking may become
322 initialized with heap pointers, or even pointers to other static
323 variables, because of dumping.]
325 We could potentially generate the relocation data ourselves by making
326 two versions of temacs, one with an extra dummmy section before
327 EMHEAP to offset it, and then compare the dumped executables from
328 both. That is a lot of work though, and it doesn't solve the problem
329 of dumped pointers to static variables, which also can be relocated.
331 A better solution is to pre-process emacs.exe so that the .rdata and
332 .reloc sections are moved to the end of the section table, and thus
333 prep won't relocate anything else. (Of course, we leave "dead"
334 copies of these two sections in place, so that the virtual address of
335 everything else is unaffected.) Relocating the .reloc data is
336 trivial - we just update the IMAGE_BASE_RELOCATION address in the
337 header (the data itself doesn't change). Relocating the import table
338 is more complicated though, because the calls to imported functions
339 must be patched up. That requires us to selectively apply the base
340 relocations when we encounter references to imported functions (or
341 variables) in other sections, but at least the base relocations are
342 easy to parse. */
344 static void
345 copy_executable_and_move_sections (file_data *p_infile,
346 file_data *p_outfile)
348 unsigned char *dst;
349 PIMAGE_DOS_HEADER dos_header;
350 PIMAGE_NT_HEADERS nt_header;
351 PIMAGE_NT_HEADERS dst_nt_header;
352 PIMAGE_SECTION_HEADER section;
353 PIMAGE_SECTION_HEADER dst_section;
354 PIMAGE_SECTION_HEADER import_section;
355 PIMAGE_SECTION_HEADER reloc_section;
356 PIMAGE_DATA_DIRECTORY import_dir;
357 PIMAGE_DATA_DIRECTORY reloc_dir;
358 DWORD import_delta_rva;
359 DWORD reloc_delta_rva;
360 DWORD offset;
361 int i;
363 #define COPY_CHUNK(message, src, size) \
364 do { \
365 unsigned char *s = (void *)(src); \
366 unsigned long count = (size); \
367 printf ("%s\n", (message)); \
368 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
369 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
370 printf ("\t0x%08x Size in bytes.\n", count); \
371 memcpy (dst, s, count); \
372 dst += count; \
373 } while (0)
375 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
376 #define ROUND_UP_DST_AND_ZERO(align) \
377 do { \
378 unsigned char *newdst = p_outfile->file_base \
379 + ROUND_UP (DST_TO_OFFSET (), (align)); \
380 /* Zero the alignment slop; it may actually initialize real data. */ \
381 memset (dst, 0, newdst - dst); \
382 dst = newdst; \
383 } while (0)
385 /* Copy the source image sequentially, ie. section by section after
386 copying the headers and section table, to simplify the process of
387 relocating the .rdata and .reloc section table entries (which might
388 force the raw section data to be relocated).
390 Note that dst is updated implicitly by each COPY_CHUNK. */
392 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
393 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
394 dos_header->e_lfanew);
395 section = IMAGE_FIRST_SECTION (nt_header);
397 import_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
398 import_section = rva_to_section (import_dir->VirtualAddress, nt_header);
400 reloc_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
401 reloc_section = rva_to_section (reloc_dir->VirtualAddress, nt_header);
402 if (!reloc_section)
404 printf ("No relocation data, cannot prepare for profile prepping.\n");
405 exit (1);
408 dst = (unsigned char *) p_outfile->file_base;
410 COPY_CHUNK ("Copying DOS header...", dos_header,
411 (DWORD) nt_header - (DWORD) dos_header);
412 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
413 COPY_CHUNK ("Copying NT header...", nt_header,
414 (DWORD) section - (DWORD) nt_header);
415 dst_section = (PIMAGE_SECTION_HEADER) dst;
416 COPY_CHUNK ("Copying section table...", section,
417 nt_header->FileHeader.NumberOfSections * sizeof (*section));
419 /* Leave room for extra section table entries; filled in below. */
420 dst += 2 * sizeof (*section);
422 /* Align the first section's raw data area, and set the header size
423 field accordingly. */
424 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
425 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
427 for (i = 0; i < nt_header->FileHeader.NumberOfSections;
428 i++, section++, dst_section++)
430 char msg[100];
431 sprintf (msg, "Copying raw data for %s...", section->Name);
433 /* "Blank out" the two sections being relocated. */
434 if (section == import_section || section == reloc_section)
436 dst_section->Name[0] = 'X';
437 dst_section->Misc.VirtualSize =
438 ROUND_UP (dst_section->Misc.VirtualSize,
439 dst_nt_header->OptionalHeader.SectionAlignment);
440 dst_section->PointerToRawData = 0;
441 dst_section->SizeOfRawData = 0;
442 dst_section->Characteristics &= ~IMAGE_SCN_CNT_INITIALIZED_DATA;
443 dst_section->Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
444 dst_section->Characteristics &= ~IMAGE_SCN_MEM_WRITE;
445 continue;
448 /* Update the file-relative offset for this section's raw data (if
449 it has any) in case things have been relocated; we will update
450 the other offsets below once we know where everything is. */
451 if (dst_section->PointerToRawData)
452 dst_section->PointerToRawData = DST_TO_OFFSET ();
454 /* Copy the original raw data. */
455 COPY_CHUNK
456 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
457 section->SizeOfRawData);
459 /* Round up the raw data size to the new alignment. */
460 dst_section->SizeOfRawData =
461 ROUND_UP (dst_section->SizeOfRawData,
462 dst_nt_header->OptionalHeader.FileAlignment);
464 /* Align the next section's raw data area. */
465 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
468 /* Add the extra section entries, copying the raw data we skipped
469 earlier. We'll patch up the data itself below. */
470 if (import_section != NULL)
472 dst_nt_header->FileHeader.NumberOfSections++;
473 dst_nt_header->OptionalHeader.SizeOfImage +=
474 ROUND_UP (import_section->Misc.VirtualSize,
475 dst_nt_header->OptionalHeader.SectionAlignment);
476 *dst_section = *import_section;
477 dst_section->VirtualAddress =
478 dst_section[-1].VirtualAddress
479 + ROUND_UP (dst_section[-1].Misc.VirtualSize,
480 dst_nt_header->OptionalHeader.SectionAlignment);
481 dst_section->PointerToRawData = DST_TO_OFFSET ();
482 /* Remember delta applied to import section. */
483 import_delta_rva = dst_section->VirtualAddress - import_section->VirtualAddress;
484 COPY_CHUNK
485 ("Relocating import directory",
486 OFFSET_TO_PTR (import_section->PointerToRawData, p_infile),
487 import_section->SizeOfRawData);
488 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
489 dst_section++;
491 if (reloc_section != NULL)
493 dst_nt_header->FileHeader.NumberOfSections++;
494 dst_nt_header->OptionalHeader.SizeOfImage +=
495 ROUND_UP (reloc_section->Misc.VirtualSize,
496 dst_nt_header->OptionalHeader.SectionAlignment);
497 *dst_section = *reloc_section;
498 dst_section->VirtualAddress =
499 dst_section[-1].VirtualAddress
500 + ROUND_UP (dst_section[-1].Misc.VirtualSize,
501 dst_nt_header->OptionalHeader.SectionAlignment);
502 dst_section->PointerToRawData = DST_TO_OFFSET ();
503 /* Remember delta applied to reloc section. */
504 reloc_delta_rva = dst_section->VirtualAddress - reloc_section->VirtualAddress;
505 COPY_CHUNK
506 ("Relocating base relocations directory",
507 OFFSET_TO_PTR (reloc_section->PointerToRawData, p_infile),
508 reloc_section->SizeOfRawData);
509 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
510 reloc_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
511 reloc_dir->VirtualAddress += reloc_delta_rva;
512 dst_section++;
515 /* Copy remainder of source image. */
516 section--;
517 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
518 nt_header->OptionalHeader.FileAlignment);
519 COPY_CHUNK
520 ("Copying remainder of executable...",
521 OFFSET_TO_PTR (offset, p_infile),
522 p_infile->size - offset);
524 /* Final size for new image. */
525 p_outfile->size = DST_TO_OFFSET ();
527 /* Now patch up remaining file-relative offsets. */
528 printf ("Patching up raw data offsets...\n");
530 section = IMAGE_FIRST_SECTION (nt_header);
531 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
533 #define ADJUST_OFFSET(var) \
534 do { \
535 if ((var) != 0) \
536 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
537 } while (0)
539 #define ADJUST_IMPORT_RVA(var) \
540 do { \
541 if ((var) != 0) \
542 *((DWORD *)&(var)) += import_delta_rva; \
543 } while (0)
545 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
546 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
547 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
549 /* Recompute data sizes for completeness. */
550 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
551 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
552 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
553 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
554 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
555 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
557 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
560 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
562 /* Update offsets in debug directory entries. Note that the debug
563 directory may be in the same section as the import table, so its
564 RVA may need to be adjusted too. */
566 PIMAGE_DATA_DIRECTORY debug_dir =
567 &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
568 PIMAGE_DEBUG_DIRECTORY debug_entry;
570 /* Update debug_dir if part of import_section. */
571 if (rva_to_section (debug_dir->VirtualAddress, nt_header) == import_section)
572 debug_dir->VirtualAddress += import_delta_rva;
574 section = rva_to_section (debug_dir->VirtualAddress, dst_nt_header);
575 if (section)
577 int size;
579 debug_entry = RVA_TO_PTR (debug_dir->VirtualAddress, section, p_outfile);
580 size = debug_dir->Size / sizeof (IMAGE_DEBUG_DIRECTORY);
582 for (i = 0; i < size; i++, debug_entry++)
584 /* The debug data itself is normally not part of any
585 section, but stored after all the raw section data. So
586 let relocate_offset do the work. */
587 ADJUST_OFFSET (debug_entry->PointerToRawData);
588 ADJUST_IMPORT_RVA (debug_entry->AddressOfRawData);
593 /* Update RVAs in import directory entries. */
595 PIMAGE_IMPORT_DESCRIPTOR imports;
596 PIMAGE_THUNK_DATA import_thunks;
598 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
599 import_dir->VirtualAddress += import_delta_rva;
601 section = rva_to_section (import_dir->VirtualAddress, dst_nt_header);
602 imports = RVA_TO_PTR (import_dir->VirtualAddress, section, p_outfile);
604 for ( ; imports->Name != 0; imports++)
606 ADJUST_IMPORT_RVA (imports->OriginalFirstThunk);
607 ADJUST_IMPORT_RVA (imports->FirstThunk);
608 ADJUST_IMPORT_RVA (imports->Name);
610 for (import_thunks = RVA_TO_PTR (imports->OriginalFirstThunk, section, p_outfile);
611 import_thunks->u1.Function != 0;
612 import_thunks++)
613 if ((import_thunks->u1.Ordinal >> 31) == 0)
614 ADJUST_IMPORT_RVA (import_thunks->u1.Ordinal);
616 for (import_thunks = RVA_TO_PTR (imports->FirstThunk, section, p_outfile);
617 import_thunks->u1.Function != 0;
618 import_thunks++)
619 if ((import_thunks->u1.Ordinal >> 31) == 0)
620 ADJUST_IMPORT_RVA (import_thunks->u1.Ordinal);
623 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT];
624 import_dir->VirtualAddress += import_delta_rva;
627 /* Fix up references to the import section. */
628 printf ("Applying fixups to import references...\n");
631 IMAGE_BASE_RELOCATION *relocs, *block, *start_block, *end_block;
632 DWORD import_start = import_section->VirtualAddress + dst_nt_header->OptionalHeader.ImageBase;
633 DWORD import_end = import_start + import_section->Misc.VirtualSize;
634 DWORD len_import_relocs;
635 DWORD len_remaining_relocs;
636 int seen_high = 0;
637 WORD * high_word;
638 void * holder;
640 reloc_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
641 reloc_section = rva_to_section (reloc_dir->VirtualAddress, dst_nt_header);
642 relocs = RVA_TO_PTR (reloc_dir->VirtualAddress, reloc_section, p_outfile);
644 /* Move the base relocations for the import section, if there are
645 any; the profiler needs to be able to patch RVAs in the import
646 section itself. */
647 for (block = relocs, start_block = 0;
648 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
649 block = (void *)((DWORD) block + block->SizeOfBlock))
651 if (block->VirtualAddress >= import_section->VirtualAddress + import_section->Misc.VirtualSize)
653 end_block = block;
654 break;
656 if (block->VirtualAddress >= import_section->VirtualAddress)
658 if (start_block == 0)
659 start_block = block;
660 block->VirtualAddress += import_delta_rva;
663 if (start_block)
665 len_import_relocs = (DWORD) end_block - (DWORD) start_block;
666 len_remaining_relocs = (DWORD) relocs + reloc_dir->Size - (DWORD) end_block;
667 holder = malloc (len_import_relocs);
668 if (holder == 0)
669 abort ();
670 memcpy (holder, start_block, len_import_relocs);
671 memcpy (start_block, end_block, len_remaining_relocs);
672 memcpy ((char *) start_block + len_remaining_relocs, holder, len_import_relocs);
673 free (holder);
676 /* Walk up the list of base relocations, checking for references
677 to the old import section location, and patching them to
678 reference the new location. */
679 for (block = relocs;
680 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
681 block = (void *)((DWORD) block + block->SizeOfBlock))
683 DWORD page_rva = block->VirtualAddress;
684 DWORD page_offset;
685 union {
686 WORD word;
687 DWORD dword;
688 } * ploc;
689 WORD *fixup;
691 section = rva_to_section (page_rva, dst_nt_header);
692 /* Don't apply fixups to the blanked sections. */
693 if (section->Name[0] == 'X')
694 continue;
696 for (fixup = (WORD *) &block[1];
697 (DWORD) fixup - (DWORD) block < block->SizeOfBlock;
698 fixup++)
700 page_offset = (*fixup) & 0xfff;
701 ploc = RVA_TO_PTR (page_rva + page_offset, section, p_outfile);
703 /* Unless our assumption is wrong, all low word fixups
704 should immediately follow a high fixup. */
705 if (seen_high && ((*fixup) >> 12) != IMAGE_REL_BASED_LOW)
706 abort ();
708 switch ((*fixup) >> 12)
710 case IMAGE_REL_BASED_ABSOLUTE:
711 break;
712 case IMAGE_REL_BASED_HIGH:
713 /* We must assume that high and low fixups occur in
714 pairs, specifically a low fixup immediately follows a
715 high fixup (normally separated by two bytes). We
716 have to process the two fixups together, to find out
717 the full pointer value and decide whether to apply
718 the fixup. */
719 seen_high = 1;
720 high_word = &ploc->word;
721 break;
722 case IMAGE_REL_BASED_LOW:
723 offset = (*high_word << 16) + ploc->word;
724 if (offset >= import_start && offset < import_end)
726 (*high_word) += import_delta_rva >> 16;
727 ploc->dword += import_delta_rva & 0xffff;
729 seen_high = 0;
730 break;
731 case IMAGE_REL_BASED_HIGHLOW:
732 /* Docs imply two words in big-endian order, so perhaps
733 this is only used on big-endian platforms, in which
734 case the obvious code will work. */
735 if (ploc->dword >= import_start && ploc->dword < import_end)
736 ploc->dword += import_delta_rva;
737 break;
738 case IMAGE_REL_BASED_HIGHADJ:
739 /* Docs don't say, but I guess this is the equivalent
740 for little-endian platforms. */
741 if (ploc->dword >= import_start && ploc->dword < import_end)
742 ploc->dword += import_delta_rva;
743 break;
744 case IMAGE_REL_BASED_MIPS_JMPADDR:
745 /* Don't know how to handle this; MIPS support has been
746 dropped from NT4 anyway. */
747 abort ();
748 break;
749 #ifdef IMAGE_REL_BASED_SECTION
750 case IMAGE_REL_BASED_SECTION:
751 case IMAGE_REL_BASED_REL32:
752 /* Docs don't say what these values mean. */
753 #endif
754 default:
755 abort ();
764 main (int argc, char **argv)
766 PIMAGE_DOS_HEADER dos_header;
767 PIMAGE_NT_HEADERS nt_header;
768 file_data in_file, out_file;
769 char out_filename[MAX_PATH], in_filename[MAX_PATH];
770 char *ptr;
772 strcpy (in_filename, argv[1]);
773 strcpy (out_filename, argv[2]);
775 printf ("Preparing %s for profile prepping\n", out_filename);
777 /* Open the original (dumped) executable file for reference. */
778 if (!open_input_file (&in_file, in_filename))
780 printf ("Failed to open %s (%d)...bailing.\n",
781 in_filename, GetLastError ());
782 exit (1);
785 /* Create a new image that can be prepped; we don't expect the size to
786 change because we are only adding two new section table entries,
787 which should fit in the alignment slop. */
788 if (!open_output_file (&out_file, out_filename, in_file.size))
790 printf ("Failed to open %s (%d)...bailing.\n",
791 out_filename, GetLastError ());
792 exit (1);
795 copy_executable_and_move_sections (&in_file, &out_file);
797 /* Patch up header fields; profiler is picky about this. */
799 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
800 DWORD headersum;
801 DWORD checksum;
803 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
804 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
806 nt_header->OptionalHeader.CheckSum = 0;
807 // nt_header->FileHeader.TimeDateStamp = time (NULL);
808 // dos_header->e_cp = size / 512;
809 // nt_header->OptionalHeader.SizeOfImage = size;
811 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
812 if (pfnCheckSumMappedFile)
814 // nt_header->FileHeader.TimeDateStamp = time (NULL);
815 pfnCheckSumMappedFile (out_file.file_base,
816 out_file.size,
817 &headersum,
818 &checksum);
819 nt_header->OptionalHeader.CheckSum = checksum;
821 FreeLibrary (hImagehelp);
824 close_file_data (&out_file);
825 close_file_data (&in_file);
827 return 0;
830 /* eof */
832 /* arch-tag: 144ca747-168e-43a0-9736-3f4c0ba1657f
833 (do not change this comment) */