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