[tcp] Enable AF_INET6 transport for tcp connections
[gpxe.git] / src / util / elf2efi.c
blob74629933cee877f53476b0cf50a97d5b6c2c8ca9
1 /*
2 * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
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>
34 #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
36 #define EFI_FILE_ALIGN 0x20
38 struct pe_section {
39 struct pe_section *next;
40 EFI_IMAGE_SECTION_HEADER hdr;
41 uint8_t contents[0];
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;
52 struct pe_header {
53 EFI_IMAGE_DOS_HEADER dos;
54 uint8_t padding[128];
55 #if defined(EFI_TARGET_IA32)
56 EFI_IMAGE_NT_HEADERS32 nt;
57 #elif defined(EFI_TARGET_X64)
58 EFI_IMAGE_NT_HEADERS64 nt;
59 #endif
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 ),
67 .nt = {
68 .Signature = EFI_IMAGE_NT_SIGNATURE,
69 .FileHeader = {
70 #if defined(EFI_TARGET_IA32)
71 .Machine = EFI_IMAGE_MACHINE_IA32,
72 #elif defined(EFI_TARGET_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(EFI_TARGET_IA32)
80 EFI_IMAGE_FILE_32BIT_MACHINE |
81 #endif
82 EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
84 .OptionalHeader = {
85 #if defined(EFI_TARGET_IA32)
86 .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
87 #elif defined(EFI_TARGET_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,
100 /** Command-line options */
101 struct options {
102 unsigned int subsystem;
106 * Allocate memory
108 * @v len Length of memory to allocate
109 * @ret ptr Pointer to allocated memory
111 static void * xmalloc ( size_t len ) {
112 void *ptr;
114 ptr = malloc ( len );
115 if ( ! ptr ) {
116 eprintf ( "Could not allocate %zd bytes\n", len );
117 exit ( 1 );
120 return ptr;
124 * Align section within PE file
126 * @v offset Unaligned offset
127 * @ret aligned_offset Aligned offset
129 static unsigned long efi_file_align ( unsigned long offset ) {
130 return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
134 * Generate entry in PE relocation table
136 * @v pe_reltab PE relocation table
137 * @v rva RVA
138 * @v size Size of relocation entry
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;
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 );
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;
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;
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;
194 /* Store relocation */
195 pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
199 * Calculate size of binary PE relocation table
201 * @v pe_reltab PE relocation table
202 * @v buffer Buffer to contain binary table, or NULL
203 * @ret size Size of binary table
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;
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 ) ) );
224 total_size += size;
227 return total_size;
231 * Open input BFD file
233 * @v filename File name
234 * @ret ibfd BFD file
236 static bfd * open_input_bfd ( const char *filename ) {
237 bfd *bfd;
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 );
247 /* The call to bfd_check_format() must be present, otherwise
248 * we get a segfault from later BFD calls.
250 if ( ! bfd_check_format ( bfd, bfd_object ) ) {
251 eprintf ( "%s is not an object file: ", filename );
252 bfd_perror ( NULL );
253 exit ( 1 );
256 return bfd;
260 * Read symbol table
262 * @v bfd BFD file
264 static asymbol ** read_symtab ( bfd *bfd ) {
265 long symtab_size;
266 asymbol **symtab;
267 long symcount;
269 /* Get symbol table size */
270 symtab_size = bfd_get_symtab_upper_bound ( bfd );
271 if ( symtab_size < 0 ) {
272 bfd_perror ( "Could not get symbol table upper bound" );
273 exit ( 1 );
276 /* Allocate and read symbol table */
277 symtab = xmalloc ( symtab_size );
278 symcount = bfd_canonicalize_symtab ( bfd, symtab );
279 if ( symcount < 0 ) {
280 bfd_perror ( "Cannot read symbol table" );
281 exit ( 1 );
284 return symtab;
288 * Read relocation table
290 * @v bfd BFD file
291 * @v symtab Symbol table
292 * @v section Section
293 * @v symtab Symbol table
294 * @ret reltab Relocation table
296 static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
297 asection *section ) {
298 long reltab_size;
299 arelent **reltab;
300 long numrels;
302 /* Get relocation table size */
303 reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
304 if ( reltab_size < 0 ) {
305 bfd_perror ( "Could not get relocation table upper bound" );
306 exit ( 1 );
309 /* Allocate and read relocation table */
310 reltab = xmalloc ( reltab_size );
311 numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
312 if ( numrels < 0 ) {
313 bfd_perror ( "Cannot read relocation table" );
314 exit ( 1 );
317 return reltab;
321 * Process section
323 * @v bfd BFD file
324 * @v pe_header PE file header
325 * @v section Section
326 * @ret new New PE section
328 static struct pe_section * process_section ( bfd *bfd,
329 struct pe_header *pe_header,
330 asection *section ) {
331 struct pe_section *new;
332 size_t section_memsz;
333 size_t section_filesz;
334 unsigned long flags = bfd_get_section_flags ( bfd, section );
335 unsigned long code_start;
336 unsigned long code_end;
337 unsigned long data_start;
338 unsigned long data_mid;
339 unsigned long data_end;
340 unsigned long start;
341 unsigned long end;
342 unsigned long *applicable_start;
343 unsigned long *applicable_end;
345 /* Extract current RVA limits from file header */
346 code_start = pe_header->nt.OptionalHeader.BaseOfCode;
347 code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
348 #if defined(EFI_TARGET_IA32)
349 data_start = pe_header->nt.OptionalHeader.BaseOfData;
350 #elif defined(EFI_TARGET_X64)
351 data_start = code_end;
352 #endif
353 data_mid = ( data_start +
354 pe_header->nt.OptionalHeader.SizeOfInitializedData );
355 data_end = ( data_mid +
356 pe_header->nt.OptionalHeader.SizeOfUninitializedData );
358 /* Allocate PE section */
359 section_memsz = bfd_section_size ( bfd, section );
360 section_filesz = ( ( flags & SEC_LOAD ) ?
361 efi_file_align ( section_memsz ) : 0 );
362 new = xmalloc ( sizeof ( *new ) + section_filesz );
363 memset ( new, 0, sizeof ( *new ) + section_filesz );
365 /* Fill in section header details */
366 strncpy ( ( char * ) new->hdr.Name, section->name,
367 sizeof ( new->hdr.Name ) );
368 new->hdr.Misc.VirtualSize = section_memsz;
369 new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
370 new->hdr.SizeOfRawData = section_filesz;
372 /* Fill in section characteristics and update RVA limits */
373 if ( flags & SEC_CODE ) {
374 /* .text-type section */
375 new->hdr.Characteristics =
376 ( EFI_IMAGE_SCN_CNT_CODE |
377 EFI_IMAGE_SCN_MEM_NOT_PAGED |
378 EFI_IMAGE_SCN_MEM_EXECUTE |
379 EFI_IMAGE_SCN_MEM_READ );
380 applicable_start = &code_start;
381 applicable_end = &code_end;
382 } else if ( flags & SEC_DATA ) {
383 /* .data-type section */
384 new->hdr.Characteristics =
385 ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
386 EFI_IMAGE_SCN_MEM_NOT_PAGED |
387 EFI_IMAGE_SCN_MEM_READ |
388 EFI_IMAGE_SCN_MEM_WRITE );
389 applicable_start = &data_start;
390 applicable_end = &data_mid;
391 } else if ( flags & SEC_READONLY ) {
392 /* .rodata-type section */
393 new->hdr.Characteristics =
394 ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
395 EFI_IMAGE_SCN_MEM_NOT_PAGED |
396 EFI_IMAGE_SCN_MEM_READ );
397 applicable_start = &data_start;
398 applicable_end = &data_mid;
399 } else if ( ! ( flags & SEC_LOAD ) ) {
400 /* .bss-type section */
401 new->hdr.Characteristics =
402 ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
403 EFI_IMAGE_SCN_MEM_NOT_PAGED |
404 EFI_IMAGE_SCN_MEM_READ |
405 EFI_IMAGE_SCN_MEM_WRITE );
406 applicable_start = &data_mid;
407 applicable_end = &data_end;
410 /* Copy in section contents */
411 if ( flags & SEC_LOAD ) {
412 if ( ! bfd_get_section_contents ( bfd, section, new->contents,
413 0, section_memsz ) ) {
414 eprintf ( "Cannot read section %s: ", section->name );
415 bfd_perror ( NULL );
416 exit ( 1 );
420 /* Update RVA limits */
421 start = new->hdr.VirtualAddress;
422 end = ( start + new->hdr.Misc.VirtualSize );
423 if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
424 *applicable_start = start;
425 if ( *applicable_end < end )
426 *applicable_end = end;
427 if ( data_start < code_end )
428 data_start = code_end;
429 if ( data_mid < data_start )
430 data_mid = data_start;
431 if ( data_end < data_mid )
432 data_end = data_mid;
434 /* Write RVA limits back to file header */
435 pe_header->nt.OptionalHeader.BaseOfCode = code_start;
436 pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
437 #if defined(EFI_TARGET_IA32)
438 pe_header->nt.OptionalHeader.BaseOfData = data_start;
439 #endif
440 pe_header->nt.OptionalHeader.SizeOfInitializedData =
441 ( data_mid - data_start );
442 pe_header->nt.OptionalHeader.SizeOfUninitializedData =
443 ( data_end - data_mid );
445 /* Update remaining file header fields */
446 pe_header->nt.FileHeader.NumberOfSections++;
447 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
448 pe_header->nt.OptionalHeader.SizeOfImage =
449 efi_file_align ( data_end );
451 return new;
455 * Process relocation record
457 * @v bfd BFD file
458 * @v section Section
459 * @v rel Relocation entry
460 * @v pe_reltab PE relocation table to fill in
462 static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
463 struct pe_relocs **pe_reltab ) {
464 reloc_howto_type *howto = rel->howto;
465 asymbol *sym = *(rel->sym_ptr_ptr);
466 unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
467 rel->address );
469 if ( bfd_is_abs_section ( sym->section ) ) {
470 /* Skip absolute symbols; the symbol value won't
471 * change when the object is loaded.
473 } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
474 /* Generate an 8-byte PE relocation */
475 generate_pe_reloc ( pe_reltab, offset, 8 );
476 } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
477 ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
478 /* Generate a 4-byte PE relocation */
479 generate_pe_reloc ( pe_reltab, offset, 4 );
480 } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
481 /* Generate a 2-byte PE relocation */
482 generate_pe_reloc ( pe_reltab, offset, 2 );
483 } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
484 ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
485 /* Skip PC-relative relocations; all relative offsets
486 * remain unaltered when the object is loaded.
488 } else {
489 eprintf ( "Unrecognised relocation type %s\n", howto->name );
490 exit ( 1 );
495 * Create relocations section
497 * @v pe_header PE file header
498 * @v pe_reltab PE relocation table
499 * @ret section Relocation section
501 static struct pe_section *
502 create_reloc_section ( struct pe_header *pe_header,
503 struct pe_relocs *pe_reltab ) {
504 struct pe_section *reloc;
505 size_t section_memsz;
506 size_t section_filesz;
507 EFI_IMAGE_DATA_DIRECTORY *relocdir;
509 /* Allocate PE section */
510 section_memsz = output_pe_reltab ( pe_reltab, NULL );
511 section_filesz = efi_file_align ( section_memsz );
512 reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
513 memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
515 /* Fill in section header details */
516 strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
517 sizeof ( reloc->hdr.Name ) );
518 reloc->hdr.Misc.VirtualSize = section_memsz;
519 reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
520 reloc->hdr.SizeOfRawData = section_filesz;
521 reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
522 EFI_IMAGE_SCN_MEM_NOT_PAGED |
523 EFI_IMAGE_SCN_MEM_READ );
525 /* Copy in section contents */
526 output_pe_reltab ( pe_reltab, reloc->contents );
528 /* Update file header details */
529 pe_header->nt.FileHeader.NumberOfSections++;
530 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
531 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
532 relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
533 [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
534 relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
535 relocdir->Size = reloc->hdr.Misc.VirtualSize;
537 return reloc;
541 * Create debug section
543 * @v pe_header PE file header
544 * @ret section Debug section
546 static struct pe_section *
547 create_debug_section ( struct pe_header *pe_header, const char *filename ) {
548 struct pe_section *debug;
549 size_t section_memsz;
550 size_t section_filesz;
551 EFI_IMAGE_DATA_DIRECTORY *debugdir;
552 struct {
553 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
554 EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
555 char name[ strlen ( filename ) + 1 ];
556 } *contents;
558 /* Allocate PE section */
559 section_memsz = sizeof ( *contents );
560 section_filesz = efi_file_align ( section_memsz );
561 debug = xmalloc ( sizeof ( *debug ) + section_filesz );
562 memset ( debug, 0, sizeof ( *debug ) + section_filesz );
563 contents = ( void * ) debug->contents;
565 /* Fill in section header details */
566 strncpy ( ( char * ) debug->hdr.Name, ".debug",
567 sizeof ( debug->hdr.Name ) );
568 debug->hdr.Misc.VirtualSize = section_memsz;
569 debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
570 debug->hdr.SizeOfRawData = section_filesz;
571 debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
572 EFI_IMAGE_SCN_MEM_NOT_PAGED |
573 EFI_IMAGE_SCN_MEM_READ );
575 /* Create section contents */
576 contents->debug.TimeDateStamp = 0x10d1a884;
577 contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
578 contents->debug.SizeOfData =
579 ( sizeof ( *contents ) - sizeof ( contents->debug ) );
580 contents->debug.RVA = ( debug->hdr.VirtualAddress +
581 offsetof ( typeof ( *contents ), rsds ) );
582 contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
583 snprintf ( contents->name, sizeof ( contents->name ), "%s",
584 filename );
586 /* Update file header details */
587 pe_header->nt.FileHeader.NumberOfSections++;
588 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
589 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
590 debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
591 [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
592 debugdir->VirtualAddress = debug->hdr.VirtualAddress;
593 debugdir->Size = debug->hdr.Misc.VirtualSize;
595 return debug;
599 * Write out PE file
601 * @v pe_header PE file header
602 * @v pe_sections List of PE sections
603 * @v pe Output file
605 static void write_pe_file ( struct pe_header *pe_header,
606 struct pe_section *pe_sections,
607 FILE *pe ) {
608 struct pe_section *section;
609 unsigned long fpos = 0;
611 /* Assign raw data pointers */
612 fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
613 for ( section = pe_sections ; section ; section = section->next ) {
614 if ( section->hdr.SizeOfRawData ) {
615 section->hdr.PointerToRawData = fpos;
616 fpos += section->hdr.SizeOfRawData;
617 fpos = efi_file_align ( fpos );
621 /* Write file header */
622 if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
623 perror ( "Could not write PE header" );
624 exit ( 1 );
627 /* Write section headers */
628 for ( section = pe_sections ; section ; section = section->next ) {
629 if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
630 1, pe ) != 1 ) {
631 perror ( "Could not write section header" );
632 exit ( 1 );
636 /* Write sections */
637 for ( section = pe_sections ; section ; section = section->next ) {
638 if ( fseek ( pe, section->hdr.PointerToRawData,
639 SEEK_SET ) != 0 ) {
640 eprintf ( "Could not seek to %lx: %s\n",
641 section->hdr.PointerToRawData,
642 strerror ( errno ) );
643 exit ( 1 );
645 if ( section->hdr.SizeOfRawData &&
646 ( fwrite ( section->contents, section->hdr.SizeOfRawData,
647 1, pe ) != 1 ) ) {
648 eprintf ( "Could not write section %.8s: %s\n",
649 section->hdr.Name, strerror ( errno ) );
650 exit ( 1 );
656 * Convert ELF to PE
658 * @v elf_name ELF file name
659 * @v pe_name PE file name
661 static void elf2pe ( const char *elf_name, const char *pe_name,
662 struct options *opts ) {
663 char pe_name_tmp[ strlen ( pe_name ) + 1 ];
664 bfd *bfd;
665 asymbol **symtab;
666 asection *section;
667 arelent **reltab;
668 arelent **rel;
669 struct pe_relocs *pe_reltab = NULL;
670 struct pe_section *pe_sections = NULL;
671 struct pe_section **next_pe_section = &pe_sections;
672 struct pe_header pe_header;
673 FILE *pe;
675 /* Create a modifiable copy of the PE name */
676 memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
678 /* Open the file */
679 bfd = open_input_bfd ( elf_name );
680 symtab = read_symtab ( bfd );
682 /* Initialise the PE header */
683 memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
684 pe_header.nt.OptionalHeader.AddressOfEntryPoint =
685 bfd_get_start_address ( bfd );
686 pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
688 /* For each input section, build an output section and create
689 * the appropriate relocation records
691 for ( section = bfd->sections ; section ; section = section->next ) {
692 /* Discard non-allocatable sections */
693 if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
694 continue;
695 /* Create output section */
696 *(next_pe_section) = process_section ( bfd, &pe_header,
697 section );
698 next_pe_section = &(*next_pe_section)->next;
699 /* Add relocations from this section */
700 reltab = read_reltab ( bfd, symtab, section );
701 for ( rel = reltab ; *rel ; rel++ )
702 process_reloc ( bfd, section, *rel, &pe_reltab );
703 free ( reltab );
706 /* Create the .reloc section */
707 *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
708 next_pe_section = &(*next_pe_section)->next;
710 /* Create the .reloc section */
711 *(next_pe_section) = create_debug_section ( &pe_header,
712 basename ( pe_name_tmp ) );
713 next_pe_section = &(*next_pe_section)->next;
715 /* Write out PE file */
716 pe = fopen ( pe_name, "w" );
717 if ( ! pe ) {
718 eprintf ( "Could not open %s for writing: %s\n",
719 pe_name, strerror ( errno ) );
720 exit ( 1 );
722 write_pe_file ( &pe_header, pe_sections, pe );
723 fclose ( pe );
725 /* Close BFD file */
726 bfd_close ( bfd );
730 * Print help
732 * @v program_name Program name
734 static void print_help ( const char *program_name ) {
735 eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
736 program_name );
740 * Parse command-line options
742 * @v argc Argument count
743 * @v argv Argument list
744 * @v opts Options structure to populate
746 static int parse_options ( const int argc, char **argv,
747 struct options *opts ) {
748 char *end;
749 int c;
751 while (1) {
752 int option_index = 0;
753 static struct option long_options[] = {
754 { "subsystem", required_argument, NULL, 's' },
755 { "help", 0, NULL, 'h' },
756 { 0, 0, 0, 0 }
759 if ( ( c = getopt_long ( argc, argv, "s:h",
760 long_options,
761 &option_index ) ) == -1 ) {
762 break;
765 switch ( c ) {
766 case 's':
767 opts->subsystem = strtoul ( optarg, &end, 0 );
768 if ( *end ) {
769 eprintf ( "Invalid subsytem \"%s\"\n",
770 optarg );
771 exit ( 2 );
773 break;
774 case 'h':
775 print_help ( argv[0] );
776 exit ( 0 );
777 case '?':
778 default:
779 exit ( 2 );
782 return optind;
785 int main ( int argc, char **argv ) {
786 struct options opts = {
787 .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
789 unsigned int infile_index;
790 const char *infile;
791 const char *outfile;
793 /* Initialise libbfd */
794 bfd_init();
796 /* Parse command-line arguments */
797 infile_index = parse_options ( argc, argv, &opts );
798 if ( argc != ( infile_index + 2 ) ) {
799 print_help ( argv[0] );
800 exit ( 2 );
802 infile = argv[infile_index];
803 outfile = argv[infile_index + 1];
805 /* Convert file */
806 elf2pe ( infile, outfile, &opts );
808 return 0;