Annotation of qemu/roms/ipxe/src/util/elf2efi.c, revision 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.