Annotation of qemu/roms/ipxe/src/util/elf2efi.c, revision 1.1.1.1

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 ( &section->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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.