1 /* Pre-process emacs.exe for profiling by MSVC.
2 Copyright (C) 1999, 2001-2016 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
20 Andrew Innes <andrewi@harlequin.co.uk> 16-Jan-1999
21 based on code from addsection.c
28 #if defined(__GNUC__) && !defined(MINGW_W64)
29 #define _ANONYMOUS_UNION
30 #define _ANONYMOUS_STRUCT
34 /* Include relevant definitions from IMAGEHLP.H, which can be found
35 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
37 PIMAGE_NT_HEADERS (__stdcall
* pfnCheckSumMappedFile
) (LPVOID BaseAddress
,
44 #define min(x, y) (((x) < (y)) ? (x) : (y))
45 #define max(x, y) (((x) > (y)) ? (x) : (y))
50 typedef struct file_data
{
55 unsigned char *file_base
;
59 open_input_file (file_data
*p_file
, const char *filename
)
64 unsigned long size
, upper_size
;
66 file
= CreateFile (filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
67 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
68 if (file
== INVALID_HANDLE_VALUE
)
71 size
= GetFileSize (file
, &upper_size
);
72 file_mapping
= CreateFileMapping (file
, NULL
, PAGE_READONLY
,
77 file_base
= MapViewOfFile (file_mapping
, FILE_MAP_READ
, 0, 0, size
);
81 p_file
->name
= filename
;
84 p_file
->file_mapping
= file_mapping
;
85 p_file
->file_base
= file_base
;
91 open_output_file (file_data
*p_file
, const char *filename
, unsigned long size
)
97 file
= CreateFile (filename
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
,
98 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
99 if (file
== INVALID_HANDLE_VALUE
)
102 file_mapping
= CreateFileMapping (file
, NULL
, PAGE_READWRITE
,
107 file_base
= MapViewOfFile (file_mapping
, FILE_MAP_WRITE
, 0, 0, size
);
111 p_file
->name
= filename
;
114 p_file
->file_mapping
= file_mapping
;
115 p_file
->file_base
= file_base
;
121 open_inout_file (file_data
*p_file
, const char *filename
)
126 unsigned long size
, upper_size
;
128 file
= CreateFile (filename
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
,
129 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
130 if (file
== INVALID_HANDLE_VALUE
)
133 size
= GetFileSize (file
, &upper_size
);
134 file_mapping
= CreateFileMapping (file
, NULL
, PAGE_READWRITE
,
139 file_base
= MapViewOfFile (file_mapping
, FILE_MAP_WRITE
, 0, 0, size
);
143 p_file
->name
= filename
;
146 p_file
->file_mapping
= file_mapping
;
147 p_file
->file_base
= file_base
;
152 /* Close the system structures associated with the given file. */
154 close_file_data (file_data
*p_file
)
156 UnmapViewOfFile (p_file
->file_base
);
157 CloseHandle (p_file
->file_mapping
);
158 /* For the case of output files, set final size. */
159 SetFilePointer (p_file
->file
, p_file
->size
, NULL
, FILE_BEGIN
);
160 SetEndOfFile (p_file
->file
);
161 CloseHandle (p_file
->file
);
165 /* Routines to manipulate NT executable file sections. */
168 get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section
)
170 /* The true section size, before rounding, for an initialized data or
171 code section. (Supposedly some linkers swap the meaning of these
173 return min (p_section
->SizeOfRawData
,
174 p_section
->Misc
.VirtualSize
);
177 /* Return pointer to section header for named section. */
178 IMAGE_SECTION_HEADER
*
179 find_section (const char *name
, IMAGE_NT_HEADERS
*nt_header
)
181 PIMAGE_SECTION_HEADER section
;
184 section
= IMAGE_FIRST_SECTION (nt_header
);
186 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
188 if (strcmp (section
->Name
, name
) == 0)
195 /* Return pointer to section header for section containing the given
196 relative virtual address. */
197 IMAGE_SECTION_HEADER
*
198 rva_to_section (DWORD_PTR rva
, IMAGE_NT_HEADERS
* nt_header
)
200 PIMAGE_SECTION_HEADER section
;
203 section
= IMAGE_FIRST_SECTION (nt_header
);
205 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
207 /* Some linkers (eg. the NT SDK linker I believe) swapped the
208 meaning of these two values - or rather, they ignored
209 VirtualSize entirely and always set it to zero. This affects
210 some very old exes (eg. gzip dated Dec 1993). Since
211 w32_executable_type relies on this function to work reliably,
212 we need to cope with this. */
213 DWORD_PTR real_size
= max (section
->SizeOfRawData
,
214 section
->Misc
.VirtualSize
);
215 if (rva
>= section
->VirtualAddress
216 && rva
< section
->VirtualAddress
+ real_size
)
223 /* Return pointer to section header for section containing the given
224 offset in its raw data area. */
225 IMAGE_SECTION_HEADER
*
226 offset_to_section (DWORD_PTR offset
, IMAGE_NT_HEADERS
* nt_header
)
228 PIMAGE_SECTION_HEADER section
;
231 section
= IMAGE_FIRST_SECTION (nt_header
);
233 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
; i
++)
235 if (offset
>= section
->PointerToRawData
236 && offset
< section
->PointerToRawData
+ section
->SizeOfRawData
)
243 /* Return offset to an object in dst, given offset in src. We assume
244 there is at least one section in both src and dst images, and that
245 the some sections may have been added to dst (after sections in src). */
247 relocate_offset (DWORD_PTR offset
,
248 IMAGE_NT_HEADERS
* src_nt_header
,
249 IMAGE_NT_HEADERS
* dst_nt_header
)
251 PIMAGE_SECTION_HEADER src_section
= IMAGE_FIRST_SECTION (src_nt_header
);
252 PIMAGE_SECTION_HEADER dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
255 while (offset
>= src_section
->PointerToRawData
)
257 if (offset
< src_section
->PointerToRawData
+ src_section
->SizeOfRawData
)
260 if (i
== src_nt_header
->FileHeader
.NumberOfSections
)
262 /* Handle offsets after the last section. */
263 dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
264 dst_section
+= dst_nt_header
->FileHeader
.NumberOfSections
- 1;
265 while (dst_section
->PointerToRawData
== 0)
267 while (src_section
->PointerToRawData
== 0)
270 + (dst_section
->PointerToRawData
+ dst_section
->SizeOfRawData
)
271 - (src_section
->PointerToRawData
+ src_section
->SizeOfRawData
);
277 (dst_section
->PointerToRawData
- src_section
->PointerToRawData
);
280 #define OFFSET_TO_RVA(offset, section) \
281 ((section)->VirtualAddress + ((DWORD_PTR)(offset) - (section)->PointerToRawData))
283 #define RVA_TO_OFFSET(rva, section) \
284 ((section)->PointerToRawData + ((DWORD_PTR)(rva) - (section)->VirtualAddress))
286 #define RVA_TO_SECTION_OFFSET(rva, section) \
287 ((DWORD_PTR)(rva) - (section)->VirtualAddress)
289 #define RVA_TO_PTR(var,section,filedata) \
290 ((void *)((unsigned char *)(RVA_TO_OFFSET(var,section) + (filedata)->file_base)))
292 /* Convert address in executing image to RVA. */
293 #define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL))
295 #define PTR_TO_OFFSET(ptr, pfile_data) \
296 ((unsigned const char *)(ptr) - (pfile_data)->file_base)
298 #define OFFSET_TO_PTR(offset, pfile_data) \
299 ((pfile_data)->file_base + (DWORD_PTR)(offset))
301 #define ROUND_UP(p, align) \
302 (((DWORD_PTR)(p) + (align)-1) & ~((DWORD_PTR)(align)-1))
303 #define ROUND_DOWN(p, align) ((DWORD_PTR)(p) & ~((DWORD_PTR)(align)-1))
306 /* The MSVC prep program generates a ._xe file from .exe, where relevant
307 function calls etc have been patched to go through thunks (generated
308 by prep) that record timing/call information. Because the thunks
309 need to make references to functions imported from profile.dll, the
310 import table must be expanded; the end result is that all the
311 sections following .rdata are relocated to higher RVAs (add a final
312 code section is added holding all the thunks). The .reloc section is
313 also expanded, so that the thunks themselves are relocatable.
315 It is this relocation which kills emacs._xe, because the dumped heap
316 pointers aren't relocated, because there is no relocation data for
317 either the relevant global/static variables or the heap section
318 itself, both of which contain pointers into the heap. [Note that
319 static variables which aren't initialized during linking may become
320 initialized with heap pointers, or even pointers to other static
321 variables, because of dumping.]
323 We could potentially generate the relocation data ourselves by making
324 two versions of temacs, one with an extra dummy section before
325 EMHEAP to offset it, and then compare the dumped executables from
326 both. That is a lot of work though, and it doesn't solve the problem
327 of dumped pointers to static variables, which also can be relocated.
329 A better solution is to pre-process emacs.exe so that the .rdata and
330 .reloc sections are moved to the end of the section table, and thus
331 prep won't relocate anything else. (Of course, we leave "dead"
332 copies of these two sections in place, so that the virtual address of
333 everything else is unaffected.) Relocating the .reloc data is
334 trivial - we just update the IMAGE_BASE_RELOCATION address in the
335 header (the data itself doesn't change). Relocating the import table
336 is more complicated though, because the calls to imported functions
337 must be patched up. That requires us to selectively apply the base
338 relocations when we encounter references to imported functions (or
339 variables) in other sections, but at least the base relocations are
343 copy_executable_and_move_sections (file_data
*p_infile
,
344 file_data
*p_outfile
)
347 PIMAGE_DOS_HEADER dos_header
;
348 PIMAGE_NT_HEADERS nt_header
;
349 PIMAGE_NT_HEADERS dst_nt_header
;
350 PIMAGE_SECTION_HEADER section
;
351 PIMAGE_SECTION_HEADER dst_section
;
352 PIMAGE_SECTION_HEADER import_section
;
353 PIMAGE_SECTION_HEADER reloc_section
;
354 PIMAGE_DATA_DIRECTORY import_dir
;
355 PIMAGE_DATA_DIRECTORY reloc_dir
;
356 DWORD_PTR import_delta_rva
;
357 DWORD_PTR reloc_delta_rva
;
361 #define COPY_CHUNK(message, src, size) \
363 unsigned const char *s = (void *)(src); \
364 unsigned long count = (size); \
365 printf ("%s\n", (message)); \
366 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
367 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
368 printf ("\t0x%08x Size in bytes.\n", count); \
369 memcpy (dst, s, count); \
373 #define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
374 #define ROUND_UP_DST_AND_ZERO(align) \
376 unsigned char *newdst = p_outfile->file_base \
377 + ROUND_UP (DST_TO_OFFSET (), (align)); \
378 /* Zero the alignment slop; it may actually initialize real data. */ \
379 memset (dst, 0, newdst - dst); \
383 /* Copy the source image sequentially, ie. section by section after
384 copying the headers and section table, to simplify the process of
385 relocating the .rdata and .reloc section table entries (which might
386 force the raw section data to be relocated).
388 Note that dst is updated implicitly by each COPY_CHUNK. */
390 dos_header
= (PIMAGE_DOS_HEADER
) p_infile
->file_base
;
391 nt_header
= (PIMAGE_NT_HEADERS
) (((unsigned char *) dos_header
) +
392 dos_header
->e_lfanew
);
393 section
= IMAGE_FIRST_SECTION (nt_header
);
395 import_dir
= &nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
];
396 import_section
= rva_to_section (import_dir
->VirtualAddress
, nt_header
);
398 reloc_dir
= &nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
399 reloc_section
= rva_to_section (reloc_dir
->VirtualAddress
, nt_header
);
402 printf ("No relocation data, cannot prepare for profile prepping.\n");
406 dst
= (unsigned char *) p_outfile
->file_base
;
408 COPY_CHUNK ("Copying DOS header...", dos_header
,
409 (DWORD_PTR
) nt_header
- (DWORD_PTR
) dos_header
);
410 dst_nt_header
= (PIMAGE_NT_HEADERS
) dst
;
411 COPY_CHUNK ("Copying NT header...", nt_header
,
412 (DWORD_PTR
) section
- (DWORD_PTR
) nt_header
);
413 dst_section
= (PIMAGE_SECTION_HEADER
) dst
;
414 COPY_CHUNK ("Copying section table...", section
,
415 nt_header
->FileHeader
.NumberOfSections
* sizeof (*section
));
417 /* Leave room for extra section table entries; filled in below. */
418 dst
+= 2 * sizeof (*section
);
420 /* Align the first section's raw data area, and set the header size
421 field accordingly. */
422 ROUND_UP_DST_AND_ZERO (dst_nt_header
->OptionalHeader
.FileAlignment
);
423 dst_nt_header
->OptionalHeader
.SizeOfHeaders
= DST_TO_OFFSET ();
425 for (i
= 0; i
< nt_header
->FileHeader
.NumberOfSections
;
426 i
++, section
++, dst_section
++)
429 sprintf (msg
, "Copying raw data for %s...", section
->Name
);
431 /* "Blank out" the two sections being relocated. */
432 if (section
== import_section
|| section
== reloc_section
)
434 dst_section
->Name
[0] = 'X';
435 dst_section
->Misc
.VirtualSize
=
436 ROUND_UP (dst_section
->Misc
.VirtualSize
,
437 dst_nt_header
->OptionalHeader
.SectionAlignment
);
438 dst_section
->PointerToRawData
= 0;
439 dst_section
->SizeOfRawData
= 0;
440 dst_section
->Characteristics
&= ~IMAGE_SCN_CNT_INITIALIZED_DATA
;
441 dst_section
->Characteristics
|= IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
442 dst_section
->Characteristics
&= ~IMAGE_SCN_MEM_WRITE
;
446 /* Update the file-relative offset for this section's raw data (if
447 it has any) in case things have been relocated; we will update
448 the other offsets below once we know where everything is. */
449 if (dst_section
->PointerToRawData
)
450 dst_section
->PointerToRawData
= DST_TO_OFFSET ();
452 /* Copy the original raw data. */
454 (msg
, OFFSET_TO_PTR (section
->PointerToRawData
, p_infile
),
455 section
->SizeOfRawData
);
457 /* Round up the raw data size to the new alignment. */
458 dst_section
->SizeOfRawData
=
459 ROUND_UP (dst_section
->SizeOfRawData
,
460 dst_nt_header
->OptionalHeader
.FileAlignment
);
462 /* Align the next section's raw data area. */
463 ROUND_UP_DST_AND_ZERO (dst_nt_header
->OptionalHeader
.FileAlignment
);
466 /* Add the extra section entries, copying the raw data we skipped
467 earlier. We'll patch up the data itself below. */
468 if (import_section
!= NULL
)
470 dst_nt_header
->FileHeader
.NumberOfSections
++;
471 dst_nt_header
->OptionalHeader
.SizeOfImage
+=
472 ROUND_UP (import_section
->Misc
.VirtualSize
,
473 dst_nt_header
->OptionalHeader
.SectionAlignment
);
474 *dst_section
= *import_section
;
475 dst_section
->VirtualAddress
=
476 dst_section
[-1].VirtualAddress
477 + ROUND_UP (dst_section
[-1].Misc
.VirtualSize
,
478 dst_nt_header
->OptionalHeader
.SectionAlignment
);
479 dst_section
->PointerToRawData
= DST_TO_OFFSET ();
480 /* Remember delta applied to import section. */
481 import_delta_rva
= dst_section
->VirtualAddress
- import_section
->VirtualAddress
;
483 ("Relocating import directory",
484 OFFSET_TO_PTR (import_section
->PointerToRawData
, p_infile
),
485 import_section
->SizeOfRawData
);
486 ROUND_UP_DST_AND_ZERO (dst_nt_header
->OptionalHeader
.FileAlignment
);
489 if (reloc_section
!= NULL
)
491 dst_nt_header
->FileHeader
.NumberOfSections
++;
492 dst_nt_header
->OptionalHeader
.SizeOfImage
+=
493 ROUND_UP (reloc_section
->Misc
.VirtualSize
,
494 dst_nt_header
->OptionalHeader
.SectionAlignment
);
495 *dst_section
= *reloc_section
;
496 dst_section
->VirtualAddress
=
497 dst_section
[-1].VirtualAddress
498 + ROUND_UP (dst_section
[-1].Misc
.VirtualSize
,
499 dst_nt_header
->OptionalHeader
.SectionAlignment
);
500 dst_section
->PointerToRawData
= DST_TO_OFFSET ();
501 /* Remember delta applied to reloc section. */
502 reloc_delta_rva
= dst_section
->VirtualAddress
- reloc_section
->VirtualAddress
;
504 ("Relocating base relocations directory",
505 OFFSET_TO_PTR (reloc_section
->PointerToRawData
, p_infile
),
506 reloc_section
->SizeOfRawData
);
507 ROUND_UP_DST_AND_ZERO (dst_nt_header
->OptionalHeader
.FileAlignment
);
508 reloc_dir
= &dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
509 reloc_dir
->VirtualAddress
+= reloc_delta_rva
;
513 /* Copy remainder of source image. */
515 offset
= ROUND_UP (section
->PointerToRawData
+ section
->SizeOfRawData
,
516 nt_header
->OptionalHeader
.FileAlignment
);
518 ("Copying remainder of executable...",
519 OFFSET_TO_PTR (offset
, p_infile
),
520 p_infile
->size
- offset
);
522 /* Final size for new image. */
523 p_outfile
->size
= DST_TO_OFFSET ();
525 /* Now patch up remaining file-relative offsets. */
526 printf ("Patching up raw data offsets...\n");
528 section
= IMAGE_FIRST_SECTION (nt_header
);
529 dst_section
= IMAGE_FIRST_SECTION (dst_nt_header
);
531 #define ADJUST_OFFSET(var) \
534 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
537 #define ADJUST_IMPORT_RVA(var) \
540 *((DWORD_PTR *)&(var)) += import_delta_rva; \
543 dst_nt_header
->OptionalHeader
.SizeOfInitializedData
= 0;
544 dst_nt_header
->OptionalHeader
.SizeOfUninitializedData
= 0;
545 for (i
= 0; i
< dst_nt_header
->FileHeader
.NumberOfSections
; i
++)
547 /* Recompute data sizes for completeness. */
548 if (dst_section
[i
].Characteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
549 dst_nt_header
->OptionalHeader
.SizeOfInitializedData
+=
550 ROUND_UP (dst_section
[i
].Misc
.VirtualSize
, dst_nt_header
->OptionalHeader
.FileAlignment
);
551 else if (dst_section
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
552 dst_nt_header
->OptionalHeader
.SizeOfUninitializedData
+=
553 ROUND_UP (dst_section
[i
].Misc
.VirtualSize
, dst_nt_header
->OptionalHeader
.FileAlignment
);
555 ADJUST_OFFSET (dst_section
[i
].PointerToLinenumbers
);
558 ADJUST_OFFSET (dst_nt_header
->FileHeader
.PointerToSymbolTable
);
560 /* Update offsets in debug directory entries. Note that the debug
561 directory may be in the same section as the import table, so its
562 RVA may need to be adjusted too. */
564 PIMAGE_DATA_DIRECTORY debug_dir
=
565 &dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_DEBUG
];
566 PIMAGE_DEBUG_DIRECTORY debug_entry
;
568 /* Update debug_dir if part of import_section. */
569 if (rva_to_section (debug_dir
->VirtualAddress
, nt_header
) == import_section
)
570 debug_dir
->VirtualAddress
+= import_delta_rva
;
572 section
= rva_to_section (debug_dir
->VirtualAddress
, dst_nt_header
);
577 debug_entry
= RVA_TO_PTR (debug_dir
->VirtualAddress
, section
, p_outfile
);
578 size
= debug_dir
->Size
/ sizeof (IMAGE_DEBUG_DIRECTORY
);
580 for (i
= 0; i
< size
; i
++, debug_entry
++)
582 /* The debug data itself is normally not part of any
583 section, but stored after all the raw section data. So
584 let relocate_offset do the work. */
585 ADJUST_OFFSET (debug_entry
->PointerToRawData
);
586 ADJUST_IMPORT_RVA (debug_entry
->AddressOfRawData
);
591 /* Update RVAs in import directory entries. */
593 PIMAGE_IMPORT_DESCRIPTOR imports
;
594 PIMAGE_THUNK_DATA import_thunks
;
596 import_dir
= &dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT
];
597 import_dir
->VirtualAddress
+= import_delta_rva
;
599 section
= rva_to_section (import_dir
->VirtualAddress
, dst_nt_header
);
600 imports
= RVA_TO_PTR (import_dir
->VirtualAddress
, section
, p_outfile
);
602 for ( ; imports
->Name
!= 0; imports
++)
604 ADJUST_IMPORT_RVA (imports
->OriginalFirstThunk
);
605 ADJUST_IMPORT_RVA (imports
->FirstThunk
);
606 ADJUST_IMPORT_RVA (imports
->Name
);
608 for (import_thunks
= RVA_TO_PTR (imports
->OriginalFirstThunk
, section
, p_outfile
);
609 import_thunks
->u1
.Function
!= 0;
611 if ((import_thunks
->u1
.Ordinal
>> 31) == 0)
612 ADJUST_IMPORT_RVA (import_thunks
->u1
.Ordinal
);
614 for (import_thunks
= RVA_TO_PTR (imports
->FirstThunk
, section
, p_outfile
);
615 import_thunks
->u1
.Function
!= 0;
617 if ((import_thunks
->u1
.Ordinal
>> 31) == 0)
618 ADJUST_IMPORT_RVA (import_thunks
->u1
.Ordinal
);
621 import_dir
= &dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_IAT
];
622 import_dir
->VirtualAddress
+= import_delta_rva
;
625 /* Fix up references to the import section. */
626 printf ("Applying fixups to import references...\n");
629 IMAGE_BASE_RELOCATION
*relocs
, *block
, *start_block
, *end_block
;
630 DWORD_PTR import_start
= import_section
->VirtualAddress
+ dst_nt_header
->OptionalHeader
.ImageBase
;
631 DWORD_PTR import_end
= import_start
+ import_section
->Misc
.VirtualSize
;
632 DWORD_PTR len_import_relocs
;
633 DWORD_PTR len_remaining_relocs
;
638 reloc_dir
= &dst_nt_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
];
639 reloc_section
= rva_to_section (reloc_dir
->VirtualAddress
, dst_nt_header
);
640 relocs
= RVA_TO_PTR (reloc_dir
->VirtualAddress
, reloc_section
, p_outfile
);
642 /* Move the base relocations for the import section, if there are
643 any; the profiler needs to be able to patch RVAs in the import
645 for (block
= relocs
, start_block
= 0;
646 (DWORD_PTR
) block
- (DWORD_PTR
) relocs
< reloc_dir
->Size
;
647 block
= (void *)((DWORD_PTR
) block
+ block
->SizeOfBlock
))
649 if (block
->VirtualAddress
>= import_section
->VirtualAddress
+ import_section
->Misc
.VirtualSize
)
654 if (block
->VirtualAddress
>= import_section
->VirtualAddress
)
656 if (start_block
== 0)
658 block
->VirtualAddress
+= import_delta_rva
;
663 len_import_relocs
= (DWORD_PTR
) end_block
- (DWORD_PTR
) start_block
;
664 len_remaining_relocs
= (DWORD_PTR
) relocs
+ reloc_dir
->Size
- (DWORD_PTR
) end_block
;
665 holder
= malloc (len_import_relocs
);
668 memcpy (holder
, start_block
, len_import_relocs
);
669 memcpy (start_block
, end_block
, len_remaining_relocs
);
670 memcpy ((char *) start_block
+ len_remaining_relocs
, holder
, len_import_relocs
);
674 /* Walk up the list of base relocations, checking for references
675 to the old import section location, and patching them to
676 reference the new location. */
678 (DWORD_PTR
) block
- (DWORD_PTR
) relocs
< reloc_dir
->Size
;
679 block
= (void *)((DWORD_PTR
) block
+ block
->SizeOfBlock
))
681 DWORD_PTR page_rva
= block
->VirtualAddress
;
682 DWORD_PTR page_offset
;
689 section
= rva_to_section (page_rva
, dst_nt_header
);
690 /* Don't apply fixups to the blanked sections. */
691 if (section
->Name
[0] == 'X')
694 for (fixup
= (WORD
*) &block
[1];
695 (DWORD_PTR
) fixup
- (DWORD_PTR
) block
< block
->SizeOfBlock
;
698 page_offset
= (*fixup
) & 0xfff;
699 ploc
= RVA_TO_PTR (page_rva
+ page_offset
, section
, p_outfile
);
701 /* Unless our assumption is wrong, all low word fixups
702 should immediately follow a high fixup. */
703 if (seen_high
&& ((*fixup
) >> 12) != IMAGE_REL_BASED_LOW
)
706 switch ((*fixup
) >> 12)
708 case IMAGE_REL_BASED_ABSOLUTE
:
710 case IMAGE_REL_BASED_HIGH
:
711 /* We must assume that high and low fixups occur in
712 pairs, specifically a low fixup immediately follows a
713 high fixup (normally separated by two bytes). We
714 have to process the two fixups together, to find out
715 the full pointer value and decide whether to apply
718 high_word
= &ploc
->word
;
720 case IMAGE_REL_BASED_LOW
:
721 offset
= (*high_word
<< 16) + ploc
->word
;
722 if (offset
>= import_start
&& offset
< import_end
)
724 (*high_word
) += import_delta_rva
>> 16;
725 ploc
->dword
+= import_delta_rva
& 0xffff;
729 case IMAGE_REL_BASED_HIGHLOW
:
730 /* Docs imply two words in big-endian order, so perhaps
731 this is only used on big-endian platforms, in which
732 case the obvious code will work. */
733 if (ploc
->dword
>= import_start
&& ploc
->dword
< import_end
)
734 ploc
->dword
+= import_delta_rva
;
736 case IMAGE_REL_BASED_HIGHADJ
:
737 /* Docs don't say, but I guess this is the equivalent
738 for little-endian platforms. */
739 if (ploc
->dword
>= import_start
&& ploc
->dword
< import_end
)
740 ploc
->dword
+= import_delta_rva
;
742 case IMAGE_REL_BASED_MIPS_JMPADDR
:
743 /* Don't know how to handle this; MIPS support has been
744 dropped from NT4 anyway. */
747 #ifdef IMAGE_REL_BASED_SECTION
748 case IMAGE_REL_BASED_SECTION
:
749 case IMAGE_REL_BASED_REL32
:
750 /* Docs don't say what these values mean. */
762 main (int argc
, char **argv
)
764 PIMAGE_DOS_HEADER dos_header
;
765 PIMAGE_NT_HEADERS nt_header
;
766 file_data in_file
, out_file
;
767 char out_filename
[MAX_PATH
], in_filename
[MAX_PATH
];
769 strcpy (in_filename
, argv
[1]);
770 strcpy (out_filename
, argv
[2]);
772 printf ("Preparing %s for profile prepping\n", out_filename
);
774 /* Open the original (dumped) executable file for reference. */
775 if (!open_input_file (&in_file
, in_filename
))
777 printf ("Failed to open %s (%d)...bailing.\n",
778 in_filename
, GetLastError ());
782 /* Create a new image that can be prepped; we don't expect the size to
783 change because we are only adding two new section table entries,
784 which should fit in the alignment slop. */
785 if (!open_output_file (&out_file
, out_filename
, in_file
.size
))
787 printf ("Failed to open %s (%d)...bailing.\n",
788 out_filename
, GetLastError ());
792 copy_executable_and_move_sections (&in_file
, &out_file
);
794 /* Patch up header fields; profiler is picky about this. */
796 HANDLE hImagehelp
= LoadLibrary ("imagehlp.dll");
800 dos_header
= (PIMAGE_DOS_HEADER
) out_file
.file_base
;
801 nt_header
= (PIMAGE_NT_HEADERS
) ((char *) dos_header
+ dos_header
->e_lfanew
);
803 nt_header
->OptionalHeader
.CheckSum
= 0;
804 // nt_header->FileHeader.TimeDateStamp = time (NULL);
805 // dos_header->e_cp = size / 512;
806 // nt_header->OptionalHeader.SizeOfImage = size;
808 pfnCheckSumMappedFile
= (void *) GetProcAddress (hImagehelp
, "CheckSumMappedFile");
809 if (pfnCheckSumMappedFile
)
811 // nt_header->FileHeader.TimeDateStamp = time (NULL);
812 pfnCheckSumMappedFile (out_file
.file_base
,
816 nt_header
->OptionalHeader
.CheckSum
= checksum
;
818 FreeLibrary (hImagehelp
);
821 close_file_data (&out_file
);
822 close_file_data (&in_file
);