Fix permissions handling (CVE-2010-0825).
[emacs.git] / nt / preprep.c
blobdbcc8a8568202ef85fb5caf6cd8466f9dd710858
1 /* Pro-process emacs.exe for profiling by MSVC.
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008, 2009, 2010 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 3 of the License, or
10 (at your option) 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. If not, see <http://www.gnu.org/licenses/>.
21 Andrew Innes <andrewi@harlequin.co.uk> 16-Jan-1999
22 based on code from addsection.c
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #ifdef __GNUC__
30 #define _ANONYMOUS_UNION
31 #define _ANONYMOUS_STRUCT
32 #endif
33 #include <windows.h>
35 /* Include relevant definitions from IMAGEHLP.H, which can be found
36 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
38 PIMAGE_NT_HEADERS
39 (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
40 DWORD FileLength,
41 LPDWORD HeaderSum,
42 LPDWORD CheckSum);
44 #undef min
45 #undef max
46 #define min(x, y) (((x) < (y)) ? (x) : (y))
47 #define max(x, y) (((x) > (y)) ? (x) : (y))
50 /* File handling. */
52 typedef struct file_data {
53 char *name;
54 unsigned long size;
55 HANDLE file;
56 HANDLE file_mapping;
57 unsigned char *file_base;
58 } file_data;
60 int
61 open_input_file (file_data *p_file, char *filename)
63 HANDLE file;
64 HANDLE file_mapping;
65 void *file_base;
66 unsigned long size, upper_size;
68 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
69 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
70 if (file == INVALID_HANDLE_VALUE)
71 return FALSE;
73 size = GetFileSize (file, &upper_size);
74 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
75 0, size, NULL);
76 if (!file_mapping)
77 return FALSE;
79 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
80 if (file_base == 0)
81 return FALSE;
83 p_file->name = filename;
84 p_file->size = size;
85 p_file->file = file;
86 p_file->file_mapping = file_mapping;
87 p_file->file_base = file_base;
89 return TRUE;
92 int
93 open_output_file (file_data *p_file, char *filename, unsigned long size)
95 HANDLE file;
96 HANDLE file_mapping;
97 void *file_base;
99 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
100 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
101 if (file == INVALID_HANDLE_VALUE)
102 return FALSE;
104 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
105 0, size, NULL);
106 if (!file_mapping)
107 return FALSE;
109 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
110 if (file_base == 0)
111 return FALSE;
113 p_file->name = filename;
114 p_file->size = size;
115 p_file->file = file;
116 p_file->file_mapping = file_mapping;
117 p_file->file_base = file_base;
119 return TRUE;
123 open_inout_file (file_data *p_file, char *filename)
125 HANDLE file;
126 HANDLE file_mapping;
127 void *file_base;
128 unsigned long size, upper_size;
130 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
131 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
132 if (file == INVALID_HANDLE_VALUE)
133 return FALSE;
135 size = GetFileSize (file, &upper_size);
136 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
137 0, size, NULL);
138 if (!file_mapping)
139 return FALSE;
141 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
142 if (file_base == 0)
143 return FALSE;
145 p_file->name = filename;
146 p_file->size = size;
147 p_file->file = file;
148 p_file->file_mapping = file_mapping;
149 p_file->file_base = file_base;
151 return TRUE;
154 /* Close the system structures associated with the given file. */
155 void
156 close_file_data (file_data *p_file)
158 UnmapViewOfFile (p_file->file_base);
159 CloseHandle (p_file->file_mapping);
160 /* For the case of output files, set final size. */
161 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
162 SetEndOfFile (p_file->file);
163 CloseHandle (p_file->file);
167 /* Routines to manipulate NT executable file sections. */
169 unsigned long
170 get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section)
172 /* The true section size, before rounding, for an initialized data or
173 code section. (Supposedly some linkers swap the meaning of these
174 two values.) */
175 return min (p_section->SizeOfRawData,
176 p_section->Misc.VirtualSize);
179 /* Return pointer to section header for named section. */
180 IMAGE_SECTION_HEADER *
181 find_section (char * name, IMAGE_NT_HEADERS * nt_header)
183 PIMAGE_SECTION_HEADER section;
184 int i;
186 section = IMAGE_FIRST_SECTION (nt_header);
188 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
190 if (strcmp (section->Name, name) == 0)
191 return section;
192 section++;
194 return NULL;
197 /* Return pointer to section header for section containing the given
198 relative virtual address. */
199 IMAGE_SECTION_HEADER *
200 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
202 PIMAGE_SECTION_HEADER section;
203 int i;
205 section = IMAGE_FIRST_SECTION (nt_header);
207 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
209 /* Some linkers (eg. the NT SDK linker I believe) swapped the
210 meaning of these two values - or rather, they ignored
211 VirtualSize entirely and always set it to zero. This affects
212 some very old exes (eg. gzip dated Dec 1993). Since
213 w32_executable_type relies on this function to work reliably,
214 we need to cope with this. */
215 DWORD real_size = max (section->SizeOfRawData,
216 section->Misc.VirtualSize);
217 if (rva >= section->VirtualAddress
218 && rva < section->VirtualAddress + real_size)
219 return section;
220 section++;
222 return NULL;
225 /* Return pointer to section header for section containing the given
226 offset in its raw data area. */
227 IMAGE_SECTION_HEADER *
228 offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
230 PIMAGE_SECTION_HEADER section;
231 int i;
233 section = IMAGE_FIRST_SECTION (nt_header);
235 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
237 if (offset >= section->PointerToRawData
238 && offset < section->PointerToRawData + section->SizeOfRawData)
239 return section;
240 section++;
242 return NULL;
245 /* Return offset to an object in dst, given offset in src. We assume
246 there is at least one section in both src and dst images, and that
247 the some sections may have been added to dst (after sections in src). */
248 static DWORD
249 relocate_offset (DWORD offset,
250 IMAGE_NT_HEADERS * src_nt_header,
251 IMAGE_NT_HEADERS * dst_nt_header)
253 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
254 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
255 int i = 0;
257 while (offset >= src_section->PointerToRawData)
259 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
260 break;
261 i++;
262 if (i == src_nt_header->FileHeader.NumberOfSections)
264 /* Handle offsets after the last section. */
265 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
266 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
267 while (dst_section->PointerToRawData == 0)
268 dst_section--;
269 while (src_section->PointerToRawData == 0)
270 src_section--;
271 return offset
272 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
273 - (src_section->PointerToRawData + src_section->SizeOfRawData);
275 src_section++;
276 dst_section++;
278 return offset +
279 (dst_section->PointerToRawData - src_section->PointerToRawData);
282 #define OFFSET_TO_RVA(offset, section) \
283 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
285 #define RVA_TO_OFFSET(rva, section) \
286 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
288 #define RVA_TO_SECTION_OFFSET(rva, section) \
289 ((DWORD)(rva) - section->VirtualAddress)
291 #define RVA_TO_PTR(var,section,filedata) \
292 ((void *)(RVA_TO_OFFSET(var,section) + (filedata)->file_base))
294 /* Convert address in executing image to RVA. */
295 #define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
297 #define PTR_TO_OFFSET(ptr, pfile_data) \
298 ((unsigned char *)(ptr) - (pfile_data)->file_base)
300 #define OFFSET_TO_PTR(offset, pfile_data) \
301 ((pfile_data)->file_base + (DWORD)(offset))
303 #define ROUND_UP(p, align) (((DWORD)(p) + (align)-1) & ~((align)-1))
304 #define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
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.
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.]
324 We could potentially generate the relocation data ourselves by making
325 two versions of temacs, one with an extra dummmy section before
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.
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. */
343 static void
344 copy_executable_and_move_sections (file_data *p_infile,
345 file_data *p_outfile)
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;
357 DWORD import_delta_rva;
358 DWORD reloc_delta_rva;
359 DWORD offset;
360 int i;
362 #define COPY_CHUNK(message, src, size) \
363 do { \
364 unsigned char *s = (void *)(src); \
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)
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)
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).
389 Note that dst is updated implicitly by each COPY_CHUNK. */
391 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
392 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
393 dos_header->e_lfanew);
394 section = IMAGE_FIRST_SECTION (nt_header);
396 import_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
397 import_section = rva_to_section (import_dir->VirtualAddress, nt_header);
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)
403 printf ("No relocation data, cannot prepare for profile prepping.\n");
404 exit (1);
407 dst = (unsigned char *) p_outfile->file_base;
409 COPY_CHUNK ("Copying DOS header...", dos_header,
410 (DWORD) nt_header - (DWORD) dos_header);
411 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
412 COPY_CHUNK ("Copying NT header...", nt_header,
413 (DWORD) section - (DWORD) nt_header);
414 dst_section = (PIMAGE_SECTION_HEADER) dst;
415 COPY_CHUNK ("Copying section table...", section,
416 nt_header->FileHeader.NumberOfSections * sizeof (*section));
418 /* Leave room for extra section table entries; filled in below. */
419 dst += 2 * sizeof (*section);
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 ();
426 for (i = 0; i < nt_header->FileHeader.NumberOfSections;
427 i++, section++, dst_section++)
429 char msg[100];
430 sprintf (msg, "Copying raw data for %s...", section->Name);
432 /* "Blank out" the two sections being relocated. */
433 if (section == import_section || section == reloc_section)
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;
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 ();
453 /* Copy the original raw data. */
454 COPY_CHUNK
455 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
456 section->SizeOfRawData);
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);
463 /* Align the next section's raw data area. */
464 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
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)
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++;
490 if (reloc_section != NULL)
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++;
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);
523 /* Final size for new image. */
524 p_outfile->size = DST_TO_OFFSET ();
526 /* Now patch up remaining file-relative offsets. */
527 printf ("Patching up raw data offsets...\n");
529 section = IMAGE_FIRST_SECTION (nt_header);
530 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
532 #define ADJUST_OFFSET(var) \
533 do { \
534 if ((var) != 0) \
535 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
536 } while (0)
538 #define ADJUST_IMPORT_RVA(var) \
539 do { \
540 if ((var) != 0) \
541 *((DWORD *)&(var)) += import_delta_rva; \
542 } while (0)
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++)
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);
556 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
559 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
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. */
565 PIMAGE_DATA_DIRECTORY debug_dir =
566 &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
567 PIMAGE_DEBUG_DIRECTORY debug_entry;
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;
573 section = rva_to_section (debug_dir->VirtualAddress, dst_nt_header);
574 if (section)
576 int size;
578 debug_entry = RVA_TO_PTR (debug_dir->VirtualAddress, section, p_outfile);
579 size = debug_dir->Size / sizeof (IMAGE_DEBUG_DIRECTORY);
581 for (i = 0; i < size; i++, debug_entry++)
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);
592 /* Update RVAs in import directory entries. */
594 PIMAGE_IMPORT_DESCRIPTOR imports;
595 PIMAGE_THUNK_DATA import_thunks;
597 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
598 import_dir->VirtualAddress += import_delta_rva;
600 section = rva_to_section (import_dir->VirtualAddress, dst_nt_header);
601 imports = RVA_TO_PTR (import_dir->VirtualAddress, section, p_outfile);
603 for ( ; imports->Name != 0; imports++)
605 ADJUST_IMPORT_RVA (imports->OriginalFirstThunk);
606 ADJUST_IMPORT_RVA (imports->FirstThunk);
607 ADJUST_IMPORT_RVA (imports->Name);
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);
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);
622 import_dir = &dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT];
623 import_dir->VirtualAddress += import_delta_rva;
626 /* Fix up references to the import section. */
627 printf ("Applying fixups to import references...\n");
630 IMAGE_BASE_RELOCATION *relocs, *block, *start_block, *end_block;
631 DWORD import_start = import_section->VirtualAddress + dst_nt_header->OptionalHeader.ImageBase;
632 DWORD import_end = import_start + import_section->Misc.VirtualSize;
633 DWORD len_import_relocs;
634 DWORD len_remaining_relocs;
635 int seen_high = 0;
636 WORD * high_word;
637 void * holder;
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);
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;
647 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
648 block = (void *)((DWORD) block + block->SizeOfBlock))
650 if (block->VirtualAddress >= import_section->VirtualAddress + import_section->Misc.VirtualSize)
652 end_block = block;
653 break;
655 if (block->VirtualAddress >= import_section->VirtualAddress)
657 if (start_block == 0)
658 start_block = block;
659 block->VirtualAddress += import_delta_rva;
662 if (start_block)
664 len_import_relocs = (DWORD) end_block - (DWORD) start_block;
665 len_remaining_relocs = (DWORD) relocs + reloc_dir->Size - (DWORD) end_block;
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);
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;
679 (DWORD) block - (DWORD) relocs < reloc_dir->Size;
680 block = (void *)((DWORD) block + block->SizeOfBlock))
682 DWORD page_rva = block->VirtualAddress;
683 DWORD page_offset;
684 union {
685 WORD word;
686 DWORD dword;
687 } * ploc;
688 WORD *fixup;
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;
695 for (fixup = (WORD *) &block[1];
696 (DWORD) fixup - (DWORD) block < block->SizeOfBlock;
697 fixup++)
699 page_offset = (*fixup) & 0xfff;
700 ploc = RVA_TO_PTR (page_rva + page_offset, section, p_outfile);
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 ();
707 switch ((*fixup) >> 12)
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)
725 (*high_word) += import_delta_rva >> 16;
726 ploc->dword += import_delta_rva & 0xffff;
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;
748 #ifdef IMAGE_REL_BASED_SECTION
749 case IMAGE_REL_BASED_SECTION:
750 case IMAGE_REL_BASED_REL32:
751 /* Docs don't say what these values mean. */
752 #endif
753 default:
754 abort ();
763 main (int argc, char **argv)
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];
769 char *ptr;
771 strcpy (in_filename, argv[1]);
772 strcpy (out_filename, argv[2]);
774 printf ("Preparing %s for profile prepping\n", out_filename);
776 /* Open the original (dumped) executable file for reference. */
777 if (!open_input_file (&in_file, in_filename))
779 printf ("Failed to open %s (%d)...bailing.\n",
780 in_filename, GetLastError ());
781 exit (1);
784 /* Create a new image that can be prepped; we don't expect the size to
785 change because we are only adding two new section table entries,
786 which should fit in the alignment slop. */
787 if (!open_output_file (&out_file, out_filename, in_file.size))
789 printf ("Failed to open %s (%d)...bailing.\n",
790 out_filename, GetLastError ());
791 exit (1);
794 copy_executable_and_move_sections (&in_file, &out_file);
796 /* Patch up header fields; profiler is picky about this. */
798 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
799 DWORD headersum;
800 DWORD checksum;
802 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
803 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
805 nt_header->OptionalHeader.CheckSum = 0;
806 // nt_header->FileHeader.TimeDateStamp = time (NULL);
807 // dos_header->e_cp = size / 512;
808 // nt_header->OptionalHeader.SizeOfImage = size;
810 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
811 if (pfnCheckSumMappedFile)
813 // nt_header->FileHeader.TimeDateStamp = time (NULL);
814 pfnCheckSumMappedFile (out_file.file_base,
815 out_file.size,
816 &headersum,
817 &checksum);
818 nt_header->OptionalHeader.CheckSum = checksum;
820 FreeLibrary (hImagehelp);
823 close_file_data (&out_file);
824 close_file_data (&in_file);
826 return 0;
829 /* eof */
831 /* arch-tag: 144ca747-168e-43a0-9736-3f4c0ba1657f
832 (do not change this comment) */