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