1 /*
2  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 #define _GNU_SOURCE
20 #include <stdint.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <getopt.h>
29 #include <bfd.h>
30 #include <gpxe/efi/efi.h>
31 #include <gpxe/efi/IndustryStandard/PeImage.h>
32 #include <libgen.h>
33 
34 #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
35 
36 #define EFI_FILE_ALIGN 0x20
37 
38 struct pe_section {
39 	struct pe_section *next;
40 	EFI_IMAGE_SECTION_HEADER hdr;
41 	uint8_t contents[0];
42 };
43 
44 struct pe_relocs {
45 	struct pe_relocs *next;
46 	unsigned long start_rva;
47 	unsigned int used_relocs;
48 	unsigned int total_relocs;
49 	uint16_t *relocs;
50 };
51 
52 struct pe_header {
53 	EFI_IMAGE_DOS_HEADER dos;
54 	uint8_t padding[128];
55 #if defined(MDE_CPU_IA32)
56 	EFI_IMAGE_NT_HEADERS32 nt;
57 #elif defined(MDE_CPU_X64)
58 	EFI_IMAGE_NT_HEADERS64 nt;
59 #endif
60 };
61 
62 static struct pe_header efi_pe_header = {
63 	.dos = {
64 		.e_magic = EFI_IMAGE_DOS_SIGNATURE,
65 		.e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
66 	},
67 	.nt = {
68 		.Signature = EFI_IMAGE_NT_SIGNATURE,
69 		.FileHeader = {
70 #if defined(MDE_CPU_IA32)
71 			.Machine = EFI_IMAGE_MACHINE_IA32,
72 #elif defined(MDE_CPU_X64)
73 			.Machine = EFI_IMAGE_MACHINE_X64,
74 #endif
75 			.TimeDateStamp = 0x10d1a884,
76 			.SizeOfOptionalHeader =
77 				sizeof ( efi_pe_header.nt.OptionalHeader ),
78 			.Characteristics = ( EFI_IMAGE_FILE_DLL |
79 #if defined(MDE_CPU_IA32)
80 					     EFI_IMAGE_FILE_32BIT_MACHINE |
81 #endif
82 					     EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
83 		},
84 		.OptionalHeader = {
85 #if defined(MDE_CPU_IA32)
86 			.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
87 #elif defined(MDE_CPU_X64)
88 			.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
89 #endif
90 			.SectionAlignment = EFI_FILE_ALIGN,
91 			.FileAlignment = EFI_FILE_ALIGN,
92 			.SizeOfImage = sizeof ( efi_pe_header ),
93 			.SizeOfHeaders = sizeof ( efi_pe_header ),
94 			.NumberOfRvaAndSizes =
95 				EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
96 		},
97 	},
98 };
99 
100 /** Command-line options */
101 struct options {
102 	unsigned int subsystem;
103 };
104 
105 /**
106  * Allocate memory
107  *
108  * @v len		Length of memory to allocate
109  * @ret ptr		Pointer to allocated memory
110  */
xmalloc(size_t len)111 static void * xmalloc ( size_t len ) {
112 	void *ptr;
113 
114 	ptr = malloc ( len );
115 	if ( ! ptr ) {
116 		eprintf ( "Could not allocate %zd bytes\n", len );
117 		exit ( 1 );
118 	}
119 
120 	return ptr;
121 }
122 
123 /**
124  * Align section within PE file
125  *
126  * @v offset		Unaligned offset
127  * @ret aligned_offset	Aligned offset
128  */
efi_file_align(unsigned long offset)129 static unsigned long efi_file_align ( unsigned long offset ) {
130 	return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
131 }
132 
133 /**
134  * Generate entry in PE relocation table
135  *
136  * @v pe_reltab		PE relocation table
137  * @v rva		RVA
138  * @v size		Size of relocation entry
139  */
generate_pe_reloc(struct pe_relocs ** pe_reltab,unsigned long rva,size_t size)140 static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
141 				unsigned long rva, size_t size ) {
142 	unsigned long start_rva;
143 	uint16_t reloc;
144 	struct pe_relocs *pe_rel;
145 	uint16_t *relocs;
146 
147 	/* Construct */
148 	start_rva = ( rva & ~0xfff );
149 	reloc = ( rva & 0xfff );
150 	switch ( size ) {
151 	case 8:
152 		reloc |= 0xa000;
153 		break;
154 	case 4:
155 		reloc |= 0x3000;
156 		break;
157 	case 2:
158 		reloc |= 0x2000;
159 		break;
160 	default:
161 		eprintf ( "Unsupported relocation size %zd\n", size );
162 		exit ( 1 );
163 	}
164 
165 	/* Locate or create PE relocation table */
166 	for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
167 		if ( pe_rel->start_rva == start_rva )
168 			break;
169 	}
170 	if ( ! pe_rel ) {
171 		pe_rel = xmalloc ( sizeof ( *pe_rel ) );
172 		memset ( pe_rel, 0, sizeof ( *pe_rel ) );
173 		pe_rel->next = *pe_reltab;
174 		*pe_reltab = pe_rel;
175 		pe_rel->start_rva = start_rva;
176 	}
177 
178 	/* Expand relocation list if necessary */
179 	if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
180 		relocs = pe_rel->relocs;
181 	} else {
182 		pe_rel->total_relocs = ( pe_rel->total_relocs ?
183 					 ( pe_rel->total_relocs * 2 ) : 256 );
184 		relocs = xmalloc ( pe_rel->total_relocs *
185 				   sizeof ( pe_rel->relocs[0] ) );
186 		memset ( relocs, 0,
187 			 pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
188 		memcpy ( relocs, pe_rel->relocs,
189 			 pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
190 		free ( pe_rel->relocs );
191 		pe_rel->relocs = relocs;
192 	}
193 
194 	/* Store relocation */
195 	pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
196 }
197 
198 /**
199  * Calculate size of binary PE relocation table
200  *
201  * @v pe_reltab		PE relocation table
202  * @v buffer		Buffer to contain binary table, or NULL
203  * @ret size		Size of binary table
204  */
output_pe_reltab(struct pe_relocs * pe_reltab,void * buffer)205 static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
206 				 void *buffer ) {
207 	struct pe_relocs *pe_rel;
208 	unsigned int num_relocs;
209 	size_t size;
210 	size_t total_size = 0;
211 
212 	for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
213 		num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
214 		size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
215 			 sizeof ( uint32_t ) /* SizeOfBlock */ +
216 			 ( num_relocs * sizeof ( uint16_t ) ) );
217 		if ( buffer ) {
218 			*( (uint32_t *) ( buffer + total_size + 0 ) )
219 				= pe_rel->start_rva;
220 			*( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
221 			memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
222 				 ( num_relocs * sizeof ( uint16_t ) ) );
223 		}
224 		total_size += size;
225 	}
226 
227 	return total_size;
228 }
229 
230 /**
231  * Open input BFD file
232  *
233  * @v filename		File name
234  * @ret ibfd		BFD file
235  */
open_input_bfd(const char * filename)236 static bfd * open_input_bfd ( const char *filename ) {
237 	bfd *bfd;
238 
239 	/* Open the file */
240 	bfd = bfd_openr ( filename, NULL );
241 	if ( ! bfd ) {
242 		eprintf ( "Cannot open %s: ", filename );
243 		bfd_perror ( NULL );
244 		exit ( 1 );
245 	}
246 
247 	/* The call to bfd_check_format() must be present, otherwise
248 	 * we get a segfault from later BFD calls.
249 	 */
250 	if ( bfd_check_format ( bfd, bfd_object ) < 0 ) {
251 		eprintf ( "%s is not an object file\n", filename );
252 		exit ( 1 );
253 	}
254 
255 	return bfd;
256 }
257 
258 /**
259  * Read symbol table
260  *
261  * @v bfd		BFD file
262  */
read_symtab(bfd * bfd)263 static asymbol ** read_symtab ( bfd *bfd ) {
264 	long symtab_size;
265 	asymbol **symtab;
266 	long symcount;
267 
268 	/* Get symbol table size */
269 	symtab_size = bfd_get_symtab_upper_bound ( bfd );
270 	if ( symtab_size < 0 ) {
271 		bfd_perror ( "Could not get symbol table upper bound" );
272 		exit ( 1 );
273 	}
274 
275 	/* Allocate and read symbol table */
276 	symtab = xmalloc ( symtab_size );
277 	symcount = bfd_canonicalize_symtab ( bfd, symtab );
278 	if ( symcount < 0 ) {
279 		bfd_perror ( "Cannot read symbol table" );
280 		exit ( 1 );
281 	}
282 
283 	return symtab;
284 }
285 
286 /**
287  * Read relocation table
288  *
289  * @v bfd		BFD file
290  * @v symtab		Symbol table
291  * @v section		Section
292  * @v symtab		Symbol table
293  * @ret reltab		Relocation table
294  */
read_reltab(bfd * bfd,asymbol ** symtab,asection * section)295 static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
296 				asection *section ) {
297 	long reltab_size;
298 	arelent **reltab;
299 	long numrels;
300 
301 	/* Get relocation table size */
302 	reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
303 	if ( reltab_size < 0 ) {
304 		bfd_perror ( "Could not get relocation table upper bound" );
305 		exit ( 1 );
306 	}
307 
308 	/* Allocate and read relocation table */
309 	reltab = xmalloc ( reltab_size );
310 	numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
311 	if ( numrels < 0 ) {
312 		bfd_perror ( "Cannot read relocation table" );
313 		exit ( 1 );
314 	}
315 
316 	return reltab;
317 }
318 
319 /**
320  * Process section
321  *
322  * @v bfd		BFD file
323  * @v pe_header		PE file header
324  * @v section		Section
325  * @ret new		New PE section
326  */
process_section(bfd * bfd,struct pe_header * pe_header,asection * section)327 static struct pe_section * process_section ( bfd *bfd,
328 					     struct pe_header *pe_header,
329 					     asection *section ) {
330 	struct pe_section *new;
331 	size_t section_memsz;
332 	size_t section_filesz;
333 	unsigned long flags = bfd_get_section_flags ( bfd, section );
334 	unsigned long code_start;
335 	unsigned long code_end;
336 	unsigned long data_start;
337 	unsigned long data_mid;
338 	unsigned long data_end;
339 	unsigned long start;
340 	unsigned long end;
341 	unsigned long *applicable_start;
342 	unsigned long *applicable_end;
343 
344 	/* Extract current RVA limits from file header */
345 	code_start = pe_header->nt.OptionalHeader.BaseOfCode;
346 	code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
347 #if defined(MDE_CPU_IA32)
348 	data_start = pe_header->nt.OptionalHeader.BaseOfData;
349 #elif defined(MDE_CPU_X64)
350 	data_start = code_end;
351 #endif
352 	data_mid = ( data_start +
353 		     pe_header->nt.OptionalHeader.SizeOfInitializedData );
354 	data_end = ( data_mid +
355 		     pe_header->nt.OptionalHeader.SizeOfUninitializedData );
356 
357 	/* Allocate PE section */
358 	section_memsz = bfd_section_size ( bfd, section );
359 	section_filesz = ( ( flags & SEC_LOAD ) ?
360 			   efi_file_align ( section_memsz ) : 0 );
361 	new = xmalloc ( sizeof ( *new ) + section_filesz );
362 	memset ( new, 0, sizeof ( *new ) + section_filesz );
363 
364 	/* Fill in section header details */
365 	strncpy ( ( char * ) new->hdr.Name, section->name,
366 		  sizeof ( new->hdr.Name ) );
367 	new->hdr.Misc.VirtualSize = section_memsz;
368 	new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
369 	new->hdr.SizeOfRawData = section_filesz;
370 
371 	/* Fill in section characteristics and update RVA limits */
372 	if ( flags & SEC_CODE ) {
373 		/* .text-type section */
374 		new->hdr.Characteristics =
375 			( EFI_IMAGE_SCN_CNT_CODE |
376 			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
377 			  EFI_IMAGE_SCN_MEM_EXECUTE |
378 			  EFI_IMAGE_SCN_MEM_READ );
379 		applicable_start = &code_start;
380 		applicable_end = &code_end;
381 	} else if ( flags & SEC_DATA ) {
382 		/* .data-type section */
383 		new->hdr.Characteristics =
384 			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
385 			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
386 			  EFI_IMAGE_SCN_MEM_READ |
387 			  EFI_IMAGE_SCN_MEM_WRITE );
388 		applicable_start = &data_start;
389 		applicable_end = &data_mid;
390 	} else if ( flags & SEC_READONLY ) {
391 		/* .rodata-type section */
392 		new->hdr.Characteristics =
393 			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
394 			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
395 			  EFI_IMAGE_SCN_MEM_READ );
396 		applicable_start = &data_start;
397 		applicable_end = &data_mid;
398 	} else if ( ! ( flags & SEC_LOAD ) ) {
399 		/* .bss-type section */
400 		new->hdr.Characteristics =
401 			( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
402 			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
403 			  EFI_IMAGE_SCN_MEM_READ |
404 			  EFI_IMAGE_SCN_MEM_WRITE );
405 		applicable_start = &data_mid;
406 		applicable_end = &data_end;
407 	}
408 
409 	/* Copy in section contents */
410 	if ( flags & SEC_LOAD ) {
411 		if ( ! bfd_get_section_contents ( bfd, section, new->contents,
412 						  0, section_memsz ) ) {
413 			eprintf ( "Cannot read section %s: ", section->name );
414 			bfd_perror ( NULL );
415 			exit ( 1 );
416 		}
417 	}
418 
419 	/* Update RVA limits */
420 	start = new->hdr.VirtualAddress;
421 	end = ( start + new->hdr.Misc.VirtualSize );
422 	if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
423 		*applicable_start = start;
424 	if ( *applicable_end < end )
425 		*applicable_end = end;
426 	if ( data_start < code_end )
427 		data_start = code_end;
428 	if ( data_mid < data_start )
429 		data_mid = data_start;
430 	if ( data_end < data_mid )
431 		data_end = data_mid;
432 
433 	/* Write RVA limits back to file header */
434 	pe_header->nt.OptionalHeader.BaseOfCode = code_start;
435 	pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
436 #if defined(MDE_CPU_IA32)
437 	pe_header->nt.OptionalHeader.BaseOfData = data_start;
438 #endif
439 	pe_header->nt.OptionalHeader.SizeOfInitializedData =
440 		( data_mid - data_start );
441 	pe_header->nt.OptionalHeader.SizeOfUninitializedData =
442 		( data_end - data_mid );
443 
444 	/* Update remaining file header fields */
445 	pe_header->nt.FileHeader.NumberOfSections++;
446 	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
447 	pe_header->nt.OptionalHeader.SizeOfImage =
448 		efi_file_align ( data_end );
449 
450 	return new;
451 }
452 
453 /**
454  * Process relocation record
455  *
456  * @v bfd		BFD file
457  * @v section		Section
458  * @v rel		Relocation entry
459  * @v pe_reltab		PE relocation table to fill in
460  */
process_reloc(bfd * bfd,asection * section,arelent * rel,struct pe_relocs ** pe_reltab)461 static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
462 			    struct pe_relocs **pe_reltab ) {
463 	reloc_howto_type *howto = rel->howto;
464 	asymbol *sym = *(rel->sym_ptr_ptr);
465 	unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
466 				 rel->address );
467 
468 	if ( bfd_is_abs_section ( sym->section ) ) {
469 		/* Skip absolute symbols; the symbol value won't
470 		 * change when the object is loaded.
471 		 */
472 	} else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
473 		/* Generate an 8-byte PE relocation */
474 		generate_pe_reloc ( pe_reltab, offset, 8 );
475 	} else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
476 		    ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
477 		/* Generate a 4-byte PE relocation */
478 		generate_pe_reloc ( pe_reltab, offset, 4 );
479 	} else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
480 		/* Generate a 2-byte PE relocation */
481 		generate_pe_reloc ( pe_reltab, offset, 2 );
482 	} else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
483 		    ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
484 		/* Skip PC-relative relocations; all relative offsets
485 		 * remain unaltered when the object is loaded.
486 		 */
487 	} else {
488 		eprintf ( "Unrecognised relocation type %s\n", howto->name );
489 		exit ( 1 );
490 	}
491 }
492 
493 /**
494  * Create relocations section
495  *
496  * @v pe_header		PE file header
497  * @v pe_reltab		PE relocation table
498  * @ret section		Relocation section
499  */
500 static struct pe_section *
create_reloc_section(struct pe_header * pe_header,struct pe_relocs * pe_reltab)501 create_reloc_section ( struct pe_header *pe_header,
502 		       struct pe_relocs *pe_reltab ) {
503 	struct pe_section *reloc;
504 	size_t section_memsz;
505 	size_t section_filesz;
506 	EFI_IMAGE_DATA_DIRECTORY *relocdir;
507 
508 	/* Allocate PE section */
509 	section_memsz = output_pe_reltab ( pe_reltab, NULL );
510 	section_filesz = efi_file_align ( section_memsz );
511 	reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
512 	memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
513 
514 	/* Fill in section header details */
515 	strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
516 		  sizeof ( reloc->hdr.Name ) );
517 	reloc->hdr.Misc.VirtualSize = section_memsz;
518 	reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
519 	reloc->hdr.SizeOfRawData = section_filesz;
520 	reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
521 				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
522 				       EFI_IMAGE_SCN_MEM_READ );
523 
524 	/* Copy in section contents */
525 	output_pe_reltab ( pe_reltab, reloc->contents );
526 
527 	/* Update file header details */
528 	pe_header->nt.FileHeader.NumberOfSections++;
529 	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
530 	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
531 	relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
532 		     [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
533 	relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
534 	relocdir->Size = reloc->hdr.Misc.VirtualSize;
535 
536 	return reloc;
537 }
538 
539 /**
540  * Create debug section
541  *
542  * @v pe_header		PE file header
543  * @ret section		Debug section
544  */
545 static struct pe_section *
create_debug_section(struct pe_header * pe_header,const char * filename)546 create_debug_section ( struct pe_header *pe_header, const char *filename ) {
547 	struct pe_section *debug;
548 	size_t section_memsz;
549 	size_t section_filesz;
550 	EFI_IMAGE_DATA_DIRECTORY *debugdir;
551 	struct {
552 		EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
553 		EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
554 		char name[ strlen ( filename ) + 1 ];
555 	} *contents;
556 
557 	/* Allocate PE section */
558 	section_memsz = sizeof ( *contents );
559 	section_filesz = efi_file_align ( section_memsz );
560 	debug = xmalloc ( sizeof ( *debug ) + section_filesz );
561 	memset ( debug, 0, sizeof ( *debug ) + section_filesz );
562 	contents = ( void * ) debug->contents;
563 
564 	/* Fill in section header details */
565 	strncpy ( ( char * ) debug->hdr.Name, ".debug",
566 		  sizeof ( debug->hdr.Name ) );
567 	debug->hdr.Misc.VirtualSize = section_memsz;
568 	debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
569 	debug->hdr.SizeOfRawData = section_filesz;
570 	debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
571 				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
572 				       EFI_IMAGE_SCN_MEM_READ );
573 
574 	/* Create section contents */
575 	contents->debug.TimeDateStamp = 0x10d1a884;
576 	contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
577 	contents->debug.SizeOfData =
578 		( sizeof ( *contents ) - sizeof ( contents->debug ) );
579 	contents->debug.RVA = ( debug->hdr.VirtualAddress +
580 				offsetof ( typeof ( *contents ), rsds ) );
581 	contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
582 	snprintf ( contents->name, sizeof ( contents->name ), "%s",
583 		   filename );
584 
585 	/* Update file header details */
586 	pe_header->nt.FileHeader.NumberOfSections++;
587 	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
588 	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
589 	debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
590 		     [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
591 	debugdir->VirtualAddress = debug->hdr.VirtualAddress;
592 	debugdir->Size = debug->hdr.Misc.VirtualSize;
593 
594 	return debug;
595 }
596 
597 /**
598  * Write out PE file
599  *
600  * @v pe_header		PE file header
601  * @v pe_sections	List of PE sections
602  * @v pe		Output file
603  */
write_pe_file(struct pe_header * pe_header,struct pe_section * pe_sections,FILE * pe)604 static void write_pe_file ( struct pe_header *pe_header,
605 			    struct pe_section *pe_sections,
606 			    FILE *pe ) {
607 	struct pe_section *section;
608 	unsigned long fpos = 0;
609 
610 	/* Assign raw data pointers */
611 	fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
612 	for ( section = pe_sections ; section ; section = section->next ) {
613 		if ( section->hdr.SizeOfRawData ) {
614 			section->hdr.PointerToRawData = fpos;
615 			fpos += section->hdr.SizeOfRawData;
616 			fpos = efi_file_align ( fpos );
617 		}
618 	}
619 
620 	/* Write file header */
621 	if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
622 		perror ( "Could not write PE header" );
623 		exit ( 1 );
624 	}
625 
626 	/* Write section headers */
627 	for ( section = pe_sections ; section ; section = section->next ) {
628 		if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
629 			      1, pe ) != 1 ) {
630 			perror ( "Could not write section header" );
631 			exit ( 1 );
632 		}
633 	}
634 
635 	/* Write sections */
636 	for ( section = pe_sections ; section ; section = section->next ) {
637 		if ( fseek ( pe, section->hdr.PointerToRawData,
638 			     SEEK_SET ) != 0 ) {
639 			eprintf ( "Could not seek to %lx: %s\n",
640 				  section->hdr.PointerToRawData,
641 				  strerror ( errno ) );
642 			exit ( 1 );
643 		}
644 		if ( section->hdr.SizeOfRawData &&
645 		     ( fwrite ( section->contents, section->hdr.SizeOfRawData,
646 				1, pe ) != 1 ) ) {
647 			eprintf ( "Could not write section %.8s: %s\n",
648 				  section->hdr.Name, strerror ( errno ) );
649 			exit ( 1 );
650 		}
651 	}
652 }
653 
654 /**
655  * Convert ELF to PE
656  *
657  * @v elf_name		ELF file name
658  * @v pe_name		PE file name
659  */
elf2pe(const char * elf_name,const char * pe_name,struct options * opts)660 static void elf2pe ( const char *elf_name, const char *pe_name,
661 		     struct options *opts ) {
662 	char pe_name_tmp[ strlen ( pe_name ) + 1 ];
663 	bfd *bfd;
664 	asymbol **symtab;
665 	asection *section;
666 	arelent **reltab;
667 	arelent **rel;
668 	struct pe_relocs *pe_reltab = NULL;
669 	struct pe_section *pe_sections = NULL;
670 	struct pe_section **next_pe_section = &pe_sections;
671 	struct pe_header pe_header;
672 	FILE *pe;
673 
674 	/* Create a modifiable copy of the PE name */
675 	memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
676 
677 	/* Open the file */
678 	bfd = open_input_bfd ( elf_name );
679 	symtab = read_symtab ( bfd );
680 
681 	/* Initialise the PE header */
682 	memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
683 	pe_header.nt.OptionalHeader.AddressOfEntryPoint =
684 		bfd_get_start_address ( bfd );
685 	pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
686 
687 	/* For each input section, build an output section and create
688 	 * the appropriate relocation records
689 	 */
690 	for ( section = bfd->sections ; section ; section = section->next ) {
691 		/* Discard non-allocatable sections */
692 		if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
693 			continue;
694 		/* Create output section */
695 		*(next_pe_section) = process_section ( bfd, &pe_header,
696 						       section );
697 		next_pe_section = &(*next_pe_section)->next;
698 		/* Add relocations from this section */
699 		reltab = read_reltab ( bfd, symtab, section );
700 		for ( rel = reltab ; *rel ; rel++ )
701 			process_reloc ( bfd, section, *rel, &pe_reltab );
702 		free ( reltab );
703 	}
704 
705 	/* Create the .reloc section */
706 	*(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
707 	next_pe_section = &(*next_pe_section)->next;
708 
709 	/* Create the .reloc section */
710 	*(next_pe_section) = create_debug_section ( &pe_header,
711 						    basename ( pe_name_tmp ) );
712 	next_pe_section = &(*next_pe_section)->next;
713 
714 	/* Write out PE file */
715 	pe = fopen ( pe_name, "w" );
716 	if ( ! pe ) {
717 		eprintf ( "Could not open %s for writing: %s\n",
718 			  pe_name, strerror ( errno ) );
719 		exit ( 1 );
720 	}
721 	write_pe_file ( &pe_header, pe_sections, pe );
722 	fclose ( pe );
723 
724 	/* Close BFD file */
725 	bfd_close ( bfd );
726 }
727 
728 /**
729  * Print help
730  *
731  * @v program_name	Program name
732  */
print_help(const char * program_name)733 static void print_help ( const char *program_name ) {
734 	eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
735 		  program_name );
736 }
737 
738 /**
739  * Parse command-line options
740  *
741  * @v argc		Argument count
742  * @v argv		Argument list
743  * @v opts		Options structure to populate
744  */
parse_options(const int argc,char ** argv,struct options * opts)745 static int parse_options ( const int argc, char **argv,
746 			   struct options *opts ) {
747 	char *end;
748 	int c;
749 
750 	while (1) {
751 		int option_index = 0;
752 		static struct option long_options[] = {
753 			{ "subsystem", required_argument, NULL, 's' },
754 			{ "help", 0, NULL, 'h' },
755 			{ 0, 0, 0, 0 }
756 		};
757 
758 		if ( ( c = getopt_long ( argc, argv, "s:h",
759 					 long_options,
760 					 &option_index ) ) == -1 ) {
761 			break;
762 		}
763 
764 		switch ( c ) {
765 		case 's':
766 			opts->subsystem = strtoul ( optarg, &end, 0 );
767 			if ( *end ) {
768 				eprintf ( "Invalid subsytem \"%s\"\n",
769 					  optarg );
770 				exit ( 2 );
771 			}
772 			break;
773 		case 'h':
774 			print_help ( argv[0] );
775 			exit ( 0 );
776 		case '?':
777 		default:
778 			exit ( 2 );
779 		}
780 	}
781 	return optind;
782 }
783 
main(int argc,char ** argv)784 int main ( int argc, char **argv ) {
785 	struct options opts = {
786 		.subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
787 	};
788 	unsigned int infile_index;
789 	const char *infile;
790 	const char *outfile;
791 
792 	/* Initialise libbfd */
793 	bfd_init();
794 
795 	/* Parse command-line arguments */
796 	infile_index = parse_options ( argc, argv, &opts );
797 	if ( argc != ( infile_index + 2 ) ) {
798 		print_help ( argv[0] );
799 		exit ( 2 );
800 	}
801 	infile = argv[infile_index];
802 	outfile = argv[infile_index + 1];
803 
804 	/* Convert file */
805 	elf2pe ( infile, outfile, &opts );
806 
807 	return 0;
808 }
809