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