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