root/nt/preprep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. open_input_file
  2. open_output_file
  3. open_inout_file
  4. close_file_data
  5. get_unrounded_section_size
  6. find_section
  7. rva_to_section
  8. offset_to_section
  9. relocate_offset
  10. copy_executable_and_move_sections
  11. main

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

/* [<][>][^][v][top][bottom][index][help] */