*** empty log message ***
[bpt/emacs.git] / nt / addsection.c
CommitLineData
6012853d
AI
1/* Add an uninitialized data section to an executable.
2 Copyright (C) 1999 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
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
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
20
21 Andrew Innes <andrewi@harlequin.co.uk> 04-Jan-1999
22 based on code from unexw32.c
23*/
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <time.h>
29#include <windows.h>
30
31/* Include relevant definitions from IMAGEHLP.H, which can be found
32 in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
33
34PIMAGE_NT_HEADERS
35(__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
36 DWORD FileLength,
37 LPDWORD HeaderSum,
38 LPDWORD CheckSum);
39
40#undef min
41#undef max
42#define min(x, y) (((x) < (y)) ? (x) : (y))
43#define max(x, y) (((x) > (y)) ? (x) : (y))
44
45
46/* File handling. */
47
48typedef struct file_data {
49 char *name;
50 unsigned long size;
51 HANDLE file;
52 HANDLE file_mapping;
53 unsigned char *file_base;
54} file_data;
55
56int
57open_input_file (file_data *p_file, char *filename)
58{
59 HANDLE file;
60 HANDLE file_mapping;
61 void *file_base;
62 unsigned long size, upper_size;
63
64 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
65 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
66 if (file == INVALID_HANDLE_VALUE)
67 return FALSE;
68
69 size = GetFileSize (file, &upper_size);
70 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
71 0, size, NULL);
72 if (!file_mapping)
73 return FALSE;
74
75 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
76 if (file_base == 0)
77 return FALSE;
78
79 p_file->name = filename;
80 p_file->size = size;
81 p_file->file = file;
82 p_file->file_mapping = file_mapping;
83 p_file->file_base = file_base;
84
85 return TRUE;
86}
87
88int
89open_output_file (file_data *p_file, char *filename, unsigned long size)
90{
91 HANDLE file;
92 HANDLE file_mapping;
93 void *file_base;
94
95 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
96 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
97 if (file == INVALID_HANDLE_VALUE)
98 return FALSE;
99
100 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
101 0, size, NULL);
102 if (!file_mapping)
103 return FALSE;
104
105 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
106 if (file_base == 0)
107 return FALSE;
108
109 p_file->name = filename;
110 p_file->size = size;
111 p_file->file = file;
112 p_file->file_mapping = file_mapping;
113 p_file->file_base = file_base;
114
115 return TRUE;
116}
117
118/* Close the system structures associated with the given file. */
119void
120close_file_data (file_data *p_file)
121{
122 UnmapViewOfFile (p_file->file_base);
123 CloseHandle (p_file->file_mapping);
124 /* For the case of output files, set final size. */
125 SetFilePointer (p_file->file, p_file->size, NULL, FILE_BEGIN);
126 SetEndOfFile (p_file->file);
127 CloseHandle (p_file->file);
128}
129
130
131/* Routines to manipulate NT executable file sections. */
132
133unsigned long
134get_unrounded_section_size (PIMAGE_SECTION_HEADER p_section)
135{
136 /* The true section size, before rounding, for an initialized data or
137 code section. (Supposedly some linkers swap the meaning of these
138 two values.) */
139 return min (p_section->SizeOfRawData,
140 p_section->Misc.VirtualSize);
141}
142
143/* Return pointer to section header for named section. */
144IMAGE_SECTION_HEADER *
145find_section (char * name, IMAGE_NT_HEADERS * nt_header)
146{
147 PIMAGE_SECTION_HEADER section;
148 int i;
149
150 section = IMAGE_FIRST_SECTION (nt_header);
151
152 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
153 {
154 if (strcmp (section->Name, name) == 0)
155 return section;
156 section++;
157 }
158 return NULL;
159}
160
161/* Return pointer to section header for section containing the given
162 relative virtual address. */
163IMAGE_SECTION_HEADER *
164rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
165{
166 PIMAGE_SECTION_HEADER section;
167 int i;
168
169 section = IMAGE_FIRST_SECTION (nt_header);
170
171 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
172 {
173 /* Some linkers (eg. the NT SDK linker I believe) swapped the
174 meaning of these two values - or rather, they ignored
175 VirtualSize entirely and always set it to zero. This affects
176 some very old exes (eg. gzip dated Dec 1993). Since
177 w32_executable_type relies on this function to work reliably,
178 we need to cope with this. */
179 DWORD real_size = max (section->SizeOfRawData,
180 section->Misc.VirtualSize);
181 if (rva >= section->VirtualAddress
182 && rva < section->VirtualAddress + real_size)
183 return section;
184 section++;
185 }
186 return NULL;
187}
188
189/* Return pointer to section header for section containing the given
190 offset in its raw data area. */
191IMAGE_SECTION_HEADER *
192offset_to_section (DWORD offset, IMAGE_NT_HEADERS * nt_header)
193{
194 PIMAGE_SECTION_HEADER section;
195 int i;
196
197 section = IMAGE_FIRST_SECTION (nt_header);
198
199 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
200 {
201 if (offset >= section->PointerToRawData
202 && offset < section->PointerToRawData + section->SizeOfRawData)
203 return section;
204 section++;
205 }
206 return NULL;
207}
208
209/* Return offset to an object in dst, given offset in src. We assume
210 there is at least one section in both src and dst images, and that
211 the some sections may have been added to dst (after sections in src). */
212static DWORD
213relocate_offset (DWORD offset,
214 IMAGE_NT_HEADERS * src_nt_header,
215 IMAGE_NT_HEADERS * dst_nt_header)
216{
217 PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
218 PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
219 int i = 0;
220
221 while (offset >= src_section->PointerToRawData)
222 {
223 if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
224 break;
225 i++;
226 if (i == src_nt_header->FileHeader.NumberOfSections)
227 {
228 /* Handle offsets after the last section. */
229 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
230 dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
231 while (dst_section->PointerToRawData == 0)
232 dst_section--;
233 while (src_section->PointerToRawData == 0)
234 src_section--;
235 return offset
236 + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
237 - (src_section->PointerToRawData + src_section->SizeOfRawData);
238 }
239 src_section++;
240 dst_section++;
241 }
242 return offset +
243 (dst_section->PointerToRawData - src_section->PointerToRawData);
244}
245
246#define OFFSET_TO_RVA(offset, section) \
247 (section->VirtualAddress + ((DWORD)(offset) - section->PointerToRawData))
248
249#define RVA_TO_OFFSET(rva, section) \
250 (section->PointerToRawData + ((DWORD)(rva) - section->VirtualAddress))
251
252#define RVA_TO_SECTION_OFFSET(rva, section) \
253 ((DWORD)(rva) - section->VirtualAddress)
254
255/* Convert address in executing image to RVA. */
256#define PTR_TO_RVA(ptr) ((DWORD)(ptr) - (DWORD) GetModuleHandle (NULL))
257
258#define PTR_TO_OFFSET(ptr, pfile_data) \
a56e5d17 259 ((unsigned char *)(ptr) - (pfile_data)->file_base)
6012853d
AI
260
261#define OFFSET_TO_PTR(offset, pfile_data) \
262 ((pfile_data)->file_base + (DWORD)(offset))
263
264#define ROUND_UP(p, align) (((DWORD)(p) + (align)-1) & ~((align)-1))
265#define ROUND_DOWN(p, align) ((DWORD)(p) & ~((align)-1))
266
267
268static void
269copy_executable_and_add_section (file_data *p_infile,
270 file_data *p_outfile,
271 char *new_section_name,
272 DWORD new_section_size)
273{
274 unsigned char *dst;
275 PIMAGE_DOS_HEADER dos_header;
276 PIMAGE_NT_HEADERS nt_header;
277 PIMAGE_NT_HEADERS dst_nt_header;
278 PIMAGE_SECTION_HEADER section;
279 PIMAGE_SECTION_HEADER dst_section;
280 DWORD offset;
281 int i;
282
283#define COPY_CHUNK(message, src, size) \
284 do { \
285 unsigned char *s = (void *)(src); \
286 unsigned long count = (size); \
287 printf ("%s\n", (message)); \
288 printf ("\t0x%08x Offset in input file.\n", s - p_infile->file_base); \
289 printf ("\t0x%08x Offset in output file.\n", dst - p_outfile->file_base); \
290 printf ("\t0x%08x Size in bytes.\n", count); \
291 memcpy (dst, s, count); \
292 dst += count; \
293 } while (0)
294
295#define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
7466aec4
AI
296#define ROUND_UP_DST_AND_ZERO(align) \
297 do { \
298 unsigned char *newdst = p_outfile->file_base \
299 + ROUND_UP (DST_TO_OFFSET (), (align)); \
300 /* Zero the alignment slop; it may actually initialize real data. */ \
301 memset (dst, 0, newdst - dst); \
302 dst = newdst; \
303 } while (0)
6012853d
AI
304
305 /* Copy the source image sequentially, ie. section by section after
306 copying the headers and section table, to simplify the process of
307 adding an extra section table entry (which might force the raw
308 section data to be relocated).
309
310 Note that dst is updated implicitly by each COPY_CHUNK. */
311
312 dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
313 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
314 dos_header->e_lfanew);
315 section = IMAGE_FIRST_SECTION (nt_header);
316
317 dst = (unsigned char *) p_outfile->file_base;
318
319 COPY_CHUNK ("Copying DOS header...", dos_header,
320 (DWORD) nt_header - (DWORD) dos_header);
321 dst_nt_header = (PIMAGE_NT_HEADERS) dst;
322 COPY_CHUNK ("Copying NT header...", nt_header,
323 (DWORD) section - (DWORD) nt_header);
324 dst_section = (PIMAGE_SECTION_HEADER) dst;
325 COPY_CHUNK ("Copying section table...", section,
326 nt_header->FileHeader.NumberOfSections * sizeof (*section));
327
328 /* To improve the efficiency of demand loading, make the file
329 alignment match the section alignment (VC++ 6.0 does this by
330 default anyway). */
331 dst_nt_header->OptionalHeader.FileAlignment =
332 dst_nt_header->OptionalHeader.SectionAlignment;
333
334 /* Add an uninitialized data section at the end, of the specified name
335 and virtual size. */
336 if (find_section (new_section_name, nt_header) == NULL)
337 /* Leave room for extra section table entry; filled in below. */
338 dst += sizeof (*section);
339 else
340 new_section_name = NULL;
341
7466aec4
AI
342 /* Align the first section's raw data area, and set the header size
343 field accordingly. */
344 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
345 dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
346
6012853d
AI
347 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
348 {
349 char msg[100];
350 sprintf (msg, "Copying raw data for %s...", section->Name);
351
6012853d
AI
352 /* Update the file-relative offset for this section's raw data (if
353 it has any) in case things have been relocated; we will update
354 the other offsets below once we know where everything is. */
355 if (dst_section->PointerToRawData)
356 dst_section->PointerToRawData = DST_TO_OFFSET ();
357
358 /* Can always copy the original raw data. */
359 COPY_CHUNK
360 (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
361 section->SizeOfRawData);
362
363 /* Round up the raw data size to the new alignment. */
364 dst_section->SizeOfRawData =
365 ROUND_UP (dst_section->SizeOfRawData,
366 dst_nt_header->OptionalHeader.FileAlignment);
367
7466aec4
AI
368 /* Align the next section's raw data area. */
369 ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
370
6012853d
AI
371 section++;
372 dst_section++;
373 }
374
6012853d
AI
375 /* Add the extra section entry (which adds no raw data). */
376 if (new_section_name != NULL)
377 {
378 dst_nt_header->FileHeader.NumberOfSections++;
379 dst_nt_header->OptionalHeader.SizeOfImage += new_section_size;
380 strncpy (dst_section->Name, new_section_name, sizeof (dst_section->Name));
381 dst_section->VirtualAddress =
382 section[-1].VirtualAddress
383 + ROUND_UP (section[-1].Misc.VirtualSize,
384 dst_nt_header->OptionalHeader.SectionAlignment);
385 dst_section->Misc.VirtualSize = new_section_size;
386 dst_section->PointerToRawData = 0;
387 dst_section->SizeOfRawData = 0;
388 dst_section->Characteristics =
389 IMAGE_SCN_CNT_UNINITIALIZED_DATA
390 | IMAGE_SCN_MEM_READ
391 | IMAGE_SCN_MEM_WRITE;
392 }
393
394 /* Copy remainder of source image. */
395 section--;
396 offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
397 nt_header->OptionalHeader.FileAlignment);
398 COPY_CHUNK
399 ("Copying remainder of executable...",
400 OFFSET_TO_PTR (offset, p_infile),
401 p_infile->size - offset);
402
403 /* Final size for new image. */
404 p_outfile->size = DST_TO_OFFSET ();
405
406 /* Now patch up remaining file-relative offsets. */
407 section = IMAGE_FIRST_SECTION (nt_header);
408 dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
409
410#define ADJUST_OFFSET(var) \
411 do { \
412 if ((var) != 0) \
413 (var) = relocate_offset ((var), nt_header, dst_nt_header); \
414 } while (0)
415
416 dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
417 dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
418 for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
419 {
420 /* Recompute data sizes for completeness. */
421 if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
422 dst_nt_header->OptionalHeader.SizeOfInitializedData +=
423 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
424 else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
425 dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
426 ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment);
427
428 ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
429 }
430
431 ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
432
433 /* Update offsets in debug directory entries. */
434 {
435 IMAGE_DATA_DIRECTORY debug_dir =
436 dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
437 PIMAGE_DEBUG_DIRECTORY debug_entry;
438
439 section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
440 if (section)
441 {
442 debug_entry = (PIMAGE_DEBUG_DIRECTORY)
443 (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base);
444 debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
445
446 for (i = 0; i < debug_dir.Size; i++, debug_entry++)
447 ADJUST_OFFSET (debug_entry->PointerToRawData);
448 }
449 }
450}
451
452
453int
454main (int argc, char **argv)
455{
456 file_data in_file, out_file;
457 char out_filename[MAX_PATH], in_filename[MAX_PATH];
458 unsigned long size;
459 PIMAGE_DOS_HEADER dos_header;
460 PIMAGE_NT_HEADERS nt_header;
461
462#define OLD_NAME argv[1]
463#define NEW_NAME argv[2]
464#define SECTION_NAME argv[3]
465#define SECTION_SIZE argv[4]
466
467 strcpy (in_filename, OLD_NAME);
468 strcpy (out_filename, NEW_NAME);
469
470 printf ("Dumping from %s\n", in_filename);
471 printf (" to %s\n", out_filename);
472
473 /* Open the undumped executable file. */
474 if (!open_input_file (&in_file, in_filename))
475 {
476 printf ("Failed to open %s (%d)...bailing.\n",
477 in_filename, GetLastError ());
478 exit (1);
479 }
480 dos_header = (PIMAGE_DOS_HEADER) in_file.file_base;
481 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
482 /* Allow for expansion due to increasing file align to section align.
483 We can overestimate here, since close_file_data will update the
484 size exactly. */
485 size = in_file.size
486 + nt_header->OptionalHeader.SectionAlignment
487 * nt_header->FileHeader.NumberOfSections;
488 if (!open_output_file (&out_file, out_filename, size))
489 {
490 printf ("Failed to open %s (%d)...bailing.\n",
491 out_filename, GetLastError ());
492 exit (1);
493 }
494
495 copy_executable_and_add_section (&in_file, &out_file,
496 SECTION_NAME,
497 atoi (SECTION_SIZE) * 1024 * 1024);
498
499 /* Patch up header fields; profiler is picky about this. */
500 {
501 HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
502 DWORD headersum;
503 DWORD checksum;
504
505 dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
506 nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
507
508 nt_header->OptionalHeader.CheckSum = 0;
509// nt_header->FileHeader.TimeDateStamp = time (NULL);
510// dos_header->e_cp = size / 512;
511// nt_header->OptionalHeader.SizeOfImage = size;
512
513 pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
514 if (pfnCheckSumMappedFile)
515 {
516// nt_header->FileHeader.TimeDateStamp = time (NULL);
517 pfnCheckSumMappedFile (out_file.file_base,
518 out_file.size,
519 &headersum,
520 &checksum);
521 nt_header->OptionalHeader.CheckSum = checksum;
522 }
523 FreeLibrary (hImagehelp);
524 }
525
526 close_file_data (&in_file);
527 close_file_data (&out_file);
528
529 return 0;
530}
531
532/* eof */