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