|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2009 Michael Brown <[email protected]>. ! 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 <ipxe/efi/efi.h> ! 31: #include <ipxe/efi/IndustryStandard/PeImage.h> ! 32: #include <libgen.h> ! 33: ! 34: #define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) ! 35: ! 36: #define EFI_FILE_ALIGN 0x20 ! 37: ! 38: struct pe_section { ! 39: struct pe_section *next; ! 40: EFI_IMAGE_SECTION_HEADER hdr; ! 41: uint8_t contents[0]; ! 42: }; ! 43: ! 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; ! 50: }; ! 51: ! 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 ! 60: }; ! 61: ! 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 ), ! 66: }, ! 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 ), ! 83: }, ! 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, ! 96: }, ! 97: }, ! 98: }; ! 99: ! 100: /** Command-line options */ ! 101: struct 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: */ ! 111: static 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: */ ! 129: static 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: */ ! 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; ! 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: */ ! 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; ! 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: */ ! 236: static 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 ) ) { ! 251: eprintf ( "%s is not an object file: ", filename ); ! 252: bfd_perror ( NULL ); ! 253: exit ( 1 ); ! 254: } ! 255: ! 256: return bfd; ! 257: } ! 258: ! 259: /** ! 260: * Read symbol table ! 261: * ! 262: * @v bfd BFD file ! 263: */ ! 264: static asymbol ** read_symtab ( bfd *bfd ) { ! 265: long symtab_size; ! 266: asymbol **symtab; ! 267: long symcount; ! 268: ! 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 ); ! 274: } ! 275: ! 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 ); ! 282: } ! 283: ! 284: return symtab; ! 285: } ! 286: ! 287: /** ! 288: * Read relocation table ! 289: * ! 290: * @v bfd BFD file ! 291: * @v symtab Symbol table ! 292: * @v section Section ! 293: * @v symtab Symbol table ! 294: * @ret reltab Relocation table ! 295: */ ! 296: static arelent ** read_reltab ( bfd *bfd, asymbol **symtab, ! 297: asection *section ) { ! 298: long reltab_size; ! 299: arelent **reltab; ! 300: long numrels; ! 301: ! 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 ); ! 307: } ! 308: ! 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 ); ! 315: } ! 316: ! 317: return reltab; ! 318: } ! 319: ! 320: /** ! 321: * Process section ! 322: * ! 323: * @v bfd BFD file ! 324: * @v pe_header PE file header ! 325: * @v section Section ! 326: * @ret new New PE section ! 327: */ ! 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; ! 344: ! 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 ); ! 357: ! 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 ); ! 364: ! 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; ! 371: ! 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; ! 408: } ! 409: ! 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 ); ! 417: } ! 418: } ! 419: ! 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; ! 433: ! 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 ); ! 444: ! 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 ); ! 450: ! 451: return new; ! 452: } ! 453: ! 454: /** ! 455: * Process relocation record ! 456: * ! 457: * @v bfd BFD file ! 458: * @v section Section ! 459: * @v rel Relocation entry ! 460: * @v pe_reltab PE relocation table to fill in ! 461: */ ! 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 ); ! 468: ! 469: if ( bfd_is_abs_section ( sym->section ) ) { ! 470: /* Skip absolute symbols; the symbol value won't ! 471: * change when the object is loaded. ! 472: */ ! 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. ! 487: */ ! 488: } else { ! 489: eprintf ( "Unrecognised relocation type %s\n", howto->name ); ! 490: exit ( 1 ); ! 491: } ! 492: } ! 493: ! 494: /** ! 495: * Create relocations section ! 496: * ! 497: * @v pe_header PE file header ! 498: * @v pe_reltab PE relocation table ! 499: * @ret section Relocation section ! 500: */ ! 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; ! 508: ! 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 ); ! 514: ! 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 ); ! 524: ! 525: /* Copy in section contents */ ! 526: output_pe_reltab ( pe_reltab, reloc->contents ); ! 527: ! 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; ! 536: ! 537: return reloc; ! 538: } ! 539: ! 540: /** ! 541: * Create debug section ! 542: * ! 543: * @v pe_header PE file header ! 544: * @ret section Debug section ! 545: */ ! 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; ! 557: ! 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; ! 564: ! 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 ); ! 574: ! 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 ); ! 585: ! 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; ! 594: ! 595: return debug; ! 596: } ! 597: ! 598: /** ! 599: * Write out PE file ! 600: * ! 601: * @v pe_header PE file header ! 602: * @v pe_sections List of PE sections ! 603: * @v pe Output file ! 604: */ ! 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; ! 610: ! 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 ); ! 618: } ! 619: } ! 620: ! 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 ); ! 625: } ! 626: ! 627: /* Write section headers */ ! 628: for ( section = pe_sections ; section ; section = section->next ) { ! 629: if ( fwrite ( §ion->hdr, sizeof ( section->hdr ), ! 630: 1, pe ) != 1 ) { ! 631: perror ( "Could not write section header" ); ! 632: exit ( 1 ); ! 633: } ! 634: } ! 635: ! 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 ); ! 644: } ! 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 ); ! 651: } ! 652: } ! 653: } ! 654: ! 655: /** ! 656: * Convert ELF to PE ! 657: * ! 658: * @v elf_name ELF file name ! 659: * @v pe_name PE file name ! 660: */ ! 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; ! 674: ! 675: /* Create a modifiable copy of the PE name */ ! 676: memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) ); ! 677: ! 678: /* Open the file */ ! 679: bfd = open_input_bfd ( elf_name ); ! 680: symtab = read_symtab ( bfd ); ! 681: ! 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; ! 687: ! 688: /* For each input section, build an output section and create ! 689: * the appropriate relocation records ! 690: */ ! 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 ); ! 704: } ! 705: ! 706: /* Create the .reloc section */ ! 707: *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab ); ! 708: next_pe_section = &(*next_pe_section)->next; ! 709: ! 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; ! 714: ! 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 ); ! 721: } ! 722: write_pe_file ( &pe_header, pe_sections, pe ); ! 723: fclose ( pe ); ! 724: ! 725: /* Close BFD file */ ! 726: bfd_close ( bfd ); ! 727: } ! 728: ! 729: /** ! 730: * Print help ! 731: * ! 732: * @v program_name Program name ! 733: */ ! 734: static void print_help ( const char *program_name ) { ! 735: eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n", ! 736: program_name ); ! 737: } ! 738: ! 739: /** ! 740: * Parse command-line options ! 741: * ! 742: * @v argc Argument count ! 743: * @v argv Argument list ! 744: * @v opts Options structure to populate ! 745: */ ! 746: static int parse_options ( const int argc, char **argv, ! 747: struct options *opts ) { ! 748: char *end; ! 749: int c; ! 750: ! 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 } ! 757: }; ! 758: ! 759: if ( ( c = getopt_long ( argc, argv, "s:h", ! 760: long_options, ! 761: &option_index ) ) == -1 ) { ! 762: break; ! 763: } ! 764: ! 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 ); ! 772: } ! 773: break; ! 774: case 'h': ! 775: print_help ( argv[0] ); ! 776: exit ( 0 ); ! 777: case '?': ! 778: default: ! 779: exit ( 2 ); ! 780: } ! 781: } ! 782: return optind; ! 783: } ! 784: ! 785: int main ( int argc, char **argv ) { ! 786: struct options opts = { ! 787: .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, ! 788: }; ! 789: unsigned int infile_index; ! 790: const char *infile; ! 791: const char *outfile; ! 792: ! 793: /* Initialise libbfd */ ! 794: bfd_init(); ! 795: ! 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 ); ! 801: } ! 802: infile = argv[infile_index]; ! 803: outfile = argv[infile_index + 1]; ! 804: ! 805: /* Convert file */ ! 806: elf2pe ( infile, outfile, &opts ); ! 807: ! 808: return 0; ! 809: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.