~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/util/elf2efi.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; either version 2 of the
 
7
 * License, or any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
17
 * 02110-1301, USA.
 
18
 */
 
19
 
 
20
#define FILE_LICENCE(...) extern void __file_licence ( void )
 
21
#include <stdint.h>
 
22
#include <stddef.h>
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <string.h>
 
26
#include <unistd.h>
 
27
#include <errno.h>
 
28
#include <assert.h>
 
29
#include <getopt.h>
 
30
#include <sys/types.h>
 
31
#include <sys/stat.h>
 
32
#include <sys/mman.h>
 
33
#include <fcntl.h>
 
34
#include <elf.h>
 
35
#include <ipxe/efi/Uefi.h>
 
36
#include <ipxe/efi/IndustryStandard/PeImage.h>
 
37
#include <libgen.h>
 
38
 
 
39
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
 
40
 
 
41
#ifdef EFI_TARGET32
 
42
 
 
43
#define EFI_IMAGE_NT_HEADERS            EFI_IMAGE_NT_HEADERS32
 
44
#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
 
45
#define EFI_IMAGE_FILE_MACHINE          EFI_IMAGE_FILE_32BIT_MACHINE
 
46
#define ELFCLASS   ELFCLASS32
 
47
#define Elf_Ehdr   Elf32_Ehdr
 
48
#define Elf_Shdr   Elf32_Shdr
 
49
#define Elf_Sym    Elf32_Sym
 
50
#define Elf_Addr   Elf32_Addr
 
51
#define Elf_Rel    Elf32_Rel
 
52
#define Elf_Rela   Elf32_Rela
 
53
#define ELF_R_TYPE ELF32_R_TYPE
 
54
#define ELF_R_SYM  ELF32_R_SYM
 
55
 
 
56
#elif defined(EFI_TARGET64)
 
57
 
 
58
#define EFI_IMAGE_NT_HEADERS            EFI_IMAGE_NT_HEADERS64
 
59
#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
 
60
#define EFI_IMAGE_FILE_MACHINE          0
 
61
#define ELFCLASS   ELFCLASS64
 
62
#define Elf_Ehdr   Elf64_Ehdr
 
63
#define Elf_Shdr   Elf64_Shdr
 
64
#define Elf_Sym    Elf64_Sym
 
65
#define Elf_Addr   Elf64_Addr
 
66
#define Elf_Rel    Elf64_Rel
 
67
#define Elf_Rela   Elf64_Rela
 
68
#define ELF_R_TYPE ELF64_R_TYPE
 
69
#define ELF_R_SYM  ELF64_R_SYM
 
70
 
 
71
#endif
 
72
 
 
73
#define ELF_MREL( mach, type ) ( (mach) | ( (type) << 16 ) )
 
74
 
 
75
/* Allow for building with older versions of elf.h */
 
76
#ifndef EM_AARCH64
 
77
#define EM_AARCH64 183
 
78
#define R_AARCH64_NONE 0
 
79
#define R_AARCH64_ABS64 257
 
80
#define R_AARCH64_CALL26 283
 
81
#define R_AARCH64_JUMP26 282
 
82
#define R_AARCH64_ADR_PREL_LO21 274
 
83
#define R_AARCH64_ADR_PREL_PG_HI21 275
 
84
#define R_AARCH64_ADD_ABS_LO12_NC 277
 
85
#define R_AARCH64_LDST8_ABS_LO12_NC 278
 
86
#define R_AARCH64_LDST16_ABS_LO12_NC 284
 
87
#define R_AARCH64_LDST32_ABS_LO12_NC 285
 
88
#define R_AARCH64_LDST64_ABS_LO12_NC 286
 
89
#endif /* EM_AARCH64 */
 
90
#ifndef R_ARM_CALL
 
91
#define R_ARM_CALL 28
 
92
#endif
 
93
#ifndef R_ARM_THM_JUMP24
 
94
#define R_ARM_THM_JUMP24 30
 
95
#endif
 
96
 
 
97
/* Seems to be missing from elf.h */
 
98
#ifndef R_AARCH64_NULL
 
99
#define R_AARCH64_NULL 256
 
100
#endif
 
101
 
 
102
#define EFI_FILE_ALIGN 0x20
 
103
 
 
104
struct elf_file {
 
105
        void *data;
 
106
        size_t len;
 
107
        const Elf_Ehdr *ehdr;
 
108
};
 
109
 
 
110
struct pe_section {
 
111
        struct pe_section *next;
 
112
        EFI_IMAGE_SECTION_HEADER hdr;
 
113
        void ( * fixup ) ( struct pe_section *section );
 
114
        uint8_t contents[0];
 
115
};
 
116
 
 
117
struct pe_relocs {
 
118
        struct pe_relocs *next;
 
119
        unsigned long start_rva;
 
120
        unsigned int used_relocs;
 
121
        unsigned int total_relocs;
 
122
        uint16_t *relocs;
 
123
};
 
124
 
 
125
struct pe_header {
 
126
        EFI_IMAGE_DOS_HEADER dos;
 
127
        uint8_t padding[128];
 
128
        EFI_IMAGE_NT_HEADERS nt;
 
129
};
 
130
 
 
131
static struct pe_header efi_pe_header = {
 
132
        .dos = {
 
133
                .e_magic = EFI_IMAGE_DOS_SIGNATURE,
 
134
                .e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
 
135
        },
 
136
        .nt = {
 
137
                .Signature = EFI_IMAGE_NT_SIGNATURE,
 
138
                .FileHeader = {
 
139
                        .TimeDateStamp = 0x10d1a884,
 
140
                        .SizeOfOptionalHeader =
 
141
                                sizeof ( efi_pe_header.nt.OptionalHeader ),
 
142
                        .Characteristics = ( EFI_IMAGE_FILE_DLL |
 
143
                                             EFI_IMAGE_FILE_MACHINE |
 
144
                                             EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
 
145
                },
 
146
                .OptionalHeader = {
 
147
                        .Magic = EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC,
 
148
                        .MajorLinkerVersion = 42,
 
149
                        .MinorLinkerVersion = 42,
 
150
                        .SectionAlignment = EFI_FILE_ALIGN,
 
151
                        .FileAlignment = EFI_FILE_ALIGN,
 
152
                        .SizeOfImage = sizeof ( efi_pe_header ),
 
153
                        .SizeOfHeaders = sizeof ( efi_pe_header ),
 
154
                        .NumberOfRvaAndSizes =
 
155
                                EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
 
156
                },
 
157
        },
 
158
};
 
159
 
 
160
/** Command-line options */
 
161
struct options {
 
162
        unsigned int subsystem;
 
163
};
 
164
 
 
165
/**
 
166
 * Allocate memory
 
167
 *
 
168
 * @v len               Length of memory to allocate
 
169
 * @ret ptr             Pointer to allocated memory
 
170
 */
 
171
static void * xmalloc ( size_t len ) {
 
172
        void *ptr;
 
173
 
 
174
        ptr = malloc ( len );
 
175
        if ( ! ptr ) {
 
176
                eprintf ( "Could not allocate %zd bytes\n", len );
 
177
                exit ( 1 );
 
178
        }
 
179
 
 
180
        return ptr;
 
181
}
 
182
 
 
183
/**
 
184
 * Align section within PE file
 
185
 *
 
186
 * @v offset            Unaligned offset
 
187
 * @ret aligned_offset  Aligned offset
 
188
 */
 
189
static unsigned long efi_file_align ( unsigned long offset ) {
 
190
        return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
 
191
}
 
192
 
 
193
/**
 
194
 * Generate entry in PE relocation table
 
195
 *
 
196
 * @v pe_reltab         PE relocation table
 
197
 * @v rva               RVA
 
198
 * @v size              Size of relocation entry
 
199
 */
 
200
static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
 
201
                                unsigned long rva, size_t size ) {
 
202
        unsigned long start_rva;
 
203
        uint16_t reloc;
 
204
        struct pe_relocs *pe_rel;
 
205
        uint16_t *relocs;
 
206
 
 
207
        /* Construct */
 
208
        start_rva = ( rva & ~0xfff );
 
209
        reloc = ( rva & 0xfff );
 
210
        switch ( size ) {
 
211
        case 8:
 
212
                reloc |= 0xa000;
 
213
                break;
 
214
        case 4:
 
215
                reloc |= 0x3000;
 
216
                break;
 
217
        case 2:
 
218
                reloc |= 0x2000;
 
219
                break;
 
220
        default:
 
221
                eprintf ( "Unsupported relocation size %zd\n", size );
 
222
                exit ( 1 );
 
223
        }
 
224
 
 
225
        /* Locate or create PE relocation table */
 
226
        for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
 
227
                if ( pe_rel->start_rva == start_rva )
 
228
                        break;
 
229
        }
 
230
        if ( ! pe_rel ) {
 
231
                pe_rel = xmalloc ( sizeof ( *pe_rel ) );
 
232
                memset ( pe_rel, 0, sizeof ( *pe_rel ) );
 
233
                pe_rel->next = *pe_reltab;
 
234
                *pe_reltab = pe_rel;
 
235
                pe_rel->start_rva = start_rva;
 
236
        }
 
237
 
 
238
        /* Expand relocation list if necessary */
 
239
        if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
 
240
                relocs = pe_rel->relocs;
 
241
        } else {
 
242
                pe_rel->total_relocs = ( pe_rel->total_relocs ?
 
243
                                         ( pe_rel->total_relocs * 2 ) : 256 );
 
244
                relocs = xmalloc ( pe_rel->total_relocs *
 
245
                                   sizeof ( pe_rel->relocs[0] ) );
 
246
                memset ( relocs, 0,
 
247
                         pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
 
248
                memcpy ( relocs, pe_rel->relocs,
 
249
                         pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
 
250
                free ( pe_rel->relocs );
 
251
                pe_rel->relocs = relocs;
 
252
        }
 
253
 
 
254
        /* Store relocation */
 
255
        pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
 
256
}
 
257
 
 
258
/**
 
259
 * Calculate size of binary PE relocation table
 
260
 *
 
261
 * @v pe_reltab         PE relocation table
 
262
 * @v buffer            Buffer to contain binary table, or NULL
 
263
 * @ret size            Size of binary table
 
264
 */
 
265
static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
 
266
                                 void *buffer ) {
 
267
        struct pe_relocs *pe_rel;
 
268
        unsigned int num_relocs;
 
269
        size_t size;
 
270
        size_t total_size = 0;
 
271
 
 
272
        for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
 
273
                num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
 
274
                size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
 
275
                         sizeof ( uint32_t ) /* SizeOfBlock */ +
 
276
                         ( num_relocs * sizeof ( uint16_t ) ) );
 
277
                if ( buffer ) {
 
278
                        *( (uint32_t *) ( buffer + total_size + 0 ) )
 
279
                                = pe_rel->start_rva;
 
280
                        *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
 
281
                        memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
 
282
                                 ( num_relocs * sizeof ( uint16_t ) ) );
 
283
                }
 
284
                total_size += size;
 
285
        }
 
286
 
 
287
        return total_size;
 
288
}
 
289
 
 
290
/**
 
291
 * Read input ELF file
 
292
 *
 
293
 * @v name              File name
 
294
 * @v elf               ELF file
 
295
 */
 
296
static void read_elf_file ( const char *name, struct elf_file *elf ) {
 
297
        static const unsigned char ident[] = {
 
298
                ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS, ELFDATA2LSB
 
299
        };
 
300
        struct stat stat;
 
301
        const Elf_Ehdr *ehdr;
 
302
        const Elf_Shdr *shdr;
 
303
        void *data;
 
304
        size_t offset;
 
305
        unsigned int i;
 
306
        int fd;
 
307
 
 
308
        /* Open file */
 
309
        fd = open ( name, O_RDONLY );
 
310
        if ( fd < 0 ) {
 
311
                eprintf ( "Could not open %s: %s\n", name, strerror ( errno ) );
 
312
                exit ( 1 );
 
313
        }
 
314
 
 
315
        /* Get file size */
 
316
        if ( fstat ( fd, &stat ) < 0 ) {
 
317
                eprintf ( "Could not get size of %s: %s\n",
 
318
                          name, strerror ( errno ) );
 
319
                exit ( 1 );
 
320
        }
 
321
        elf->len = stat.st_size;
 
322
 
 
323
        /* Map file */
 
324
        data = mmap ( NULL, elf->len, PROT_READ, MAP_SHARED, fd, 0 );
 
325
        if ( data == MAP_FAILED ) {
 
326
                eprintf ( "Could not map %s: %s\n", name, strerror ( errno ) );
 
327
                exit ( 1 );
 
328
        }
 
329
        elf->data = data;
 
330
 
 
331
        /* Close file */
 
332
        close ( fd );
 
333
 
 
334
        /* Check header */
 
335
        ehdr = elf->data;
 
336
        if ( ( elf->len < sizeof ( *ehdr ) ) ||
 
337
             ( memcmp ( ident, ehdr->e_ident, sizeof ( ident ) ) != 0 ) ) {
 
338
                eprintf ( "Invalid ELF header in %s\n", name );
 
339
                exit ( 1 );
 
340
        }
 
341
        elf->ehdr = ehdr;
 
342
 
 
343
        /* Check section headers */
 
344
        for ( i = 0 ; i < ehdr->e_shnum ; i++ ) {
 
345
                offset = ( ehdr->e_shoff + ( i * ehdr->e_shentsize ) );
 
346
                if ( elf->len < ( offset + sizeof ( *shdr ) ) ) {
 
347
                        eprintf ( "ELF section header outside file in %s\n",
 
348
                                  name );
 
349
                        exit ( 1 );
 
350
                }
 
351
                shdr = ( data + offset );
 
352
                if ( ( shdr->sh_type != SHT_NOBITS ) &&
 
353
                     ( ( elf->len < shdr->sh_offset ) ||
 
354
                       ( ( ( elf->len - shdr->sh_offset ) < shdr->sh_size ) ))){
 
355
                        eprintf ( "ELF section %d outside file in %s\n",
 
356
                                  i, name );
 
357
                        exit ( 1 );
 
358
                }
 
359
                if ( shdr->sh_link >= ehdr->e_shnum ) {
 
360
                        eprintf ( "ELF section %d link section %d out of "
 
361
                                  "range\n", i, shdr->sh_link );
 
362
                        exit ( 1 );
 
363
                }
 
364
        }
 
365
}
 
366
 
 
367
/**
 
368
 * Get ELF string
 
369
 *
 
370
 * @v elf               ELF file
 
371
 * @v section           String table section number
 
372
 * @v offset            String table offset
 
373
 * @ret string          ELF string
 
374
 */
 
375
static const char * elf_string ( struct elf_file *elf, unsigned int section,
 
376
                                 size_t offset ) {
 
377
        const Elf_Ehdr *ehdr = elf->ehdr;
 
378
        const Elf_Shdr *shdr;
 
379
        char *string;
 
380
        char *last;
 
381
 
 
382
        /* Locate section header */
 
383
        if ( section >= ehdr->e_shnum ) {
 
384
                eprintf ( "Invalid ELF string section %d\n", section );
 
385
                exit ( 1 );
 
386
        }
 
387
        shdr = ( elf->data + ehdr->e_shoff + ( section * ehdr->e_shentsize ) );
 
388
 
 
389
        /* Sanity check section */
 
390
        if ( shdr->sh_type != SHT_STRTAB ) {
 
391
                eprintf ( "ELF section %d (type %d) is not a string table\n",
 
392
                          section, shdr->sh_type );
 
393
                exit ( 1 );
 
394
        }
 
395
        last = ( elf->data + shdr->sh_offset + shdr->sh_size - 1 );
 
396
        if ( *last != '\0' ) {
 
397
                eprintf ( "ELF section %d is not NUL-terminated\n", section );
 
398
                exit ( 1 );
 
399
        }
 
400
 
 
401
        /* Locate string */
 
402
        if ( offset >= shdr->sh_size ) {
 
403
                eprintf ( "Invalid ELF string offset %zd in section %d\n",
 
404
                          offset, section );
 
405
                exit ( 1 );
 
406
        }
 
407
        string = ( elf->data + shdr->sh_offset + offset );
 
408
 
 
409
        return string;
 
410
}
 
411
 
 
412
/**
 
413
 * Set machine architecture
 
414
 *
 
415
 * @v elf               ELF file
 
416
 * @v pe_header         PE file header
 
417
 */
 
418
static void set_machine ( struct elf_file *elf, struct pe_header *pe_header ) {
 
419
        const Elf_Ehdr *ehdr = elf->ehdr;
 
420
        uint16_t machine;
 
421
 
 
422
        /* Identify machine architecture */
 
423
        switch ( ehdr->e_machine ) {
 
424
        case EM_386:
 
425
                machine = EFI_IMAGE_MACHINE_IA32;
 
426
                break;
 
427
        case EM_X86_64:
 
428
                machine = EFI_IMAGE_MACHINE_X64;
 
429
                break;
 
430
        case EM_ARM:
 
431
                machine = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED;
 
432
                break;
 
433
        case EM_AARCH64:
 
434
                machine = EFI_IMAGE_MACHINE_AARCH64;
 
435
                break;
 
436
        default:
 
437
                eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
 
438
                exit ( 1 );
 
439
        }
 
440
 
 
441
        /* Set machine architecture */
 
442
        pe_header->nt.FileHeader.Machine = machine;
 
443
}
 
444
 
 
445
/**
 
446
 * Process section
 
447
 *
 
448
 * @v elf               ELF file
 
449
 * @v shdr              ELF section header
 
450
 * @v pe_header         PE file header
 
451
 * @ret new             New PE section
 
452
 */
 
453
static struct pe_section * process_section ( struct elf_file *elf,
 
454
                                             const Elf_Shdr *shdr,
 
455
                                             struct pe_header *pe_header ) {
 
456
        struct pe_section *new;
 
457
        const char *name;
 
458
        size_t section_memsz;
 
459
        size_t section_filesz;
 
460
        unsigned long code_start;
 
461
        unsigned long code_end;
 
462
        unsigned long data_start;
 
463
        unsigned long data_mid;
 
464
        unsigned long data_end;
 
465
        unsigned long start;
 
466
        unsigned long end;
 
467
        unsigned long *applicable_start;
 
468
        unsigned long *applicable_end;
 
469
 
 
470
        /* Get section name */
 
471
        name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name );
 
472
 
 
473
        /* Extract current RVA limits from file header */
 
474
        code_start = pe_header->nt.OptionalHeader.BaseOfCode;
 
475
        code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
 
476
#if defined(EFI_TARGET32)
 
477
        data_start = pe_header->nt.OptionalHeader.BaseOfData;
 
478
#elif defined(EFI_TARGET64)
 
479
        data_start = code_end;
 
480
#endif
 
481
        data_mid = ( data_start +
 
482
                     pe_header->nt.OptionalHeader.SizeOfInitializedData );
 
483
        data_end = ( data_mid +
 
484
                     pe_header->nt.OptionalHeader.SizeOfUninitializedData );
 
485
 
 
486
        /* Allocate PE section */
 
487
        section_memsz = shdr->sh_size;
 
488
        section_filesz = ( ( shdr->sh_type == SHT_PROGBITS ) ?
 
489
                           efi_file_align ( section_memsz ) : 0 );
 
490
        new = xmalloc ( sizeof ( *new ) + section_filesz );
 
491
        memset ( new, 0, sizeof ( *new ) + section_filesz );
 
492
 
 
493
        /* Fill in section header details */
 
494
        strncpy ( ( char * ) new->hdr.Name, name, sizeof ( new->hdr.Name ) );
 
495
        new->hdr.Misc.VirtualSize = section_memsz;
 
496
        new->hdr.VirtualAddress = shdr->sh_addr;
 
497
        new->hdr.SizeOfRawData = section_filesz;
 
498
 
 
499
        /* Fill in section characteristics and update RVA limits */
 
500
        if ( ( shdr->sh_type == SHT_PROGBITS ) &&
 
501
             ( shdr->sh_flags & SHF_EXECINSTR ) ) {
 
502
                /* .text-type section */
 
503
                new->hdr.Characteristics =
 
504
                        ( EFI_IMAGE_SCN_CNT_CODE |
 
505
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
506
                          EFI_IMAGE_SCN_MEM_EXECUTE |
 
507
                          EFI_IMAGE_SCN_MEM_READ );
 
508
                applicable_start = &code_start;
 
509
                applicable_end = &code_end;
 
510
        } else if ( ( shdr->sh_type == SHT_PROGBITS ) &&
 
511
                    ( shdr->sh_flags & SHF_WRITE ) ) {
 
512
                /* .data-type section */
 
513
                new->hdr.Characteristics =
 
514
                        ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
 
515
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
516
                          EFI_IMAGE_SCN_MEM_READ |
 
517
                          EFI_IMAGE_SCN_MEM_WRITE );
 
518
                applicable_start = &data_start;
 
519
                applicable_end = &data_mid;
 
520
        } else if ( shdr->sh_type == SHT_PROGBITS ) {
 
521
                /* .rodata-type section */
 
522
                new->hdr.Characteristics =
 
523
                        ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
 
524
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
525
                          EFI_IMAGE_SCN_MEM_READ );
 
526
                applicable_start = &data_start;
 
527
                applicable_end = &data_mid;
 
528
        } else if ( shdr->sh_type == SHT_NOBITS ) {
 
529
                /* .bss-type section */
 
530
                new->hdr.Characteristics =
 
531
                        ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
 
532
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
533
                          EFI_IMAGE_SCN_MEM_READ |
 
534
                          EFI_IMAGE_SCN_MEM_WRITE );
 
535
                applicable_start = &data_mid;
 
536
                applicable_end = &data_end;
 
537
        } else {
 
538
                eprintf ( "Unrecognised characteristics for section %s\n",
 
539
                          name );
 
540
                exit ( 1 );
 
541
        }
 
542
 
 
543
        /* Copy in section contents */
 
544
        if ( shdr->sh_type == SHT_PROGBITS ) {
 
545
                memcpy ( new->contents, ( elf->data + shdr->sh_offset ),
 
546
                         shdr->sh_size );
 
547
        }
 
548
 
 
549
        /* Update RVA limits */
 
550
        start = new->hdr.VirtualAddress;
 
551
        end = ( start + new->hdr.Misc.VirtualSize );
 
552
        if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
 
553
                *applicable_start = start;
 
554
        if ( *applicable_end < end )
 
555
                *applicable_end = end;
 
556
        if ( data_start < code_end )
 
557
                data_start = code_end;
 
558
        if ( data_mid < data_start )
 
559
                data_mid = data_start;
 
560
        if ( data_end < data_mid )
 
561
                data_end = data_mid;
 
562
 
 
563
        /* Write RVA limits back to file header */
 
564
        pe_header->nt.OptionalHeader.BaseOfCode = code_start;
 
565
        pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
 
566
#if defined(EFI_TARGET32)
 
567
        pe_header->nt.OptionalHeader.BaseOfData = data_start;
 
568
#endif
 
569
        pe_header->nt.OptionalHeader.SizeOfInitializedData =
 
570
                ( data_mid - data_start );
 
571
        pe_header->nt.OptionalHeader.SizeOfUninitializedData =
 
572
                ( data_end - data_mid );
 
573
 
 
574
        /* Update remaining file header fields */
 
575
        pe_header->nt.FileHeader.NumberOfSections++;
 
576
        pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
 
577
        pe_header->nt.OptionalHeader.SizeOfImage =
 
578
                efi_file_align ( data_end );
 
579
 
 
580
        return new;
 
581
}
 
582
 
 
583
/**
 
584
 * Process relocation record
 
585
 *
 
586
 * @v elf               ELF file
 
587
 * @v shdr              ELF section header
 
588
 * @v syms              Symbol table
 
589
 * @v nsyms             Number of symbol table entries
 
590
 * @v rel               Relocation record
 
591
 * @v pe_reltab         PE relocation table to fill in
 
592
 */
 
593
static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
 
594
                            const Elf_Sym *syms, unsigned int nsyms,
 
595
                            const Elf_Rel *rel, struct pe_relocs **pe_reltab ) {
 
596
        unsigned int type = ELF_R_TYPE ( rel->r_info );
 
597
        unsigned int sym = ELF_R_SYM ( rel->r_info );
 
598
        unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type );
 
599
        size_t offset = ( shdr->sh_addr + rel->r_offset );
 
600
 
 
601
        /* Look up symbol and process relocation */
 
602
        if ( sym >= nsyms ) {
 
603
                eprintf ( "Symbol out of range\n" );
 
604
                exit ( 1 );
 
605
        }
 
606
        if ( syms[sym].st_shndx == SHN_ABS ) {
 
607
                /* Skip absolute symbols; the symbol value won't
 
608
                 * change when the object is loaded.
 
609
                 */
 
610
        } else {
 
611
                switch ( mrel ) {
 
612
                case ELF_MREL ( EM_386, R_386_NONE ) :
 
613
                case ELF_MREL ( EM_ARM, R_ARM_NONE ) :
 
614
                case ELF_MREL ( EM_X86_64, R_X86_64_NONE ) :
 
615
                case ELF_MREL ( EM_AARCH64, R_AARCH64_NONE ) :
 
616
                case ELF_MREL ( EM_AARCH64, R_AARCH64_NULL ) :
 
617
                        /* Ignore dummy relocations used by REQUIRE_SYMBOL() */
 
618
                        break;
 
619
                case ELF_MREL ( EM_386, R_386_32 ) :
 
620
                case ELF_MREL ( EM_ARM, R_ARM_ABS32 ) :
 
621
                        /* Generate a 4-byte PE relocation */
 
622
                        generate_pe_reloc ( pe_reltab, offset, 4 );
 
623
                        break;
 
624
                case ELF_MREL ( EM_X86_64, R_X86_64_64 ) :
 
625
                case ELF_MREL ( EM_AARCH64, R_AARCH64_ABS64 ) :
 
626
                        /* Generate an 8-byte PE relocation */
 
627
                        generate_pe_reloc ( pe_reltab, offset, 8 );
 
628
                        break;
 
629
                case ELF_MREL ( EM_386, R_386_PC32 ) :
 
630
                case ELF_MREL ( EM_ARM, R_ARM_CALL ) :
 
631
                case ELF_MREL ( EM_ARM, R_ARM_THM_PC22 ) :
 
632
                case ELF_MREL ( EM_ARM, R_ARM_THM_JUMP24 ) :
 
633
                case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) :
 
634
                case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) :
 
635
                case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) :
 
636
                case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) :
 
637
                case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_PG_HI21 ) :
 
638
                case ELF_MREL ( EM_AARCH64, R_AARCH64_ADD_ABS_LO12_NC ) :
 
639
                case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST8_ABS_LO12_NC ) :
 
640
                case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST16_ABS_LO12_NC ) :
 
641
                case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) :
 
642
                case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) :
 
643
                        /* Skip PC-relative relocations; all relative
 
644
                         * offsets remain unaltered when the object is
 
645
                         * loaded.
 
646
                         */
 
647
                        break;
 
648
                default:
 
649
                        eprintf ( "Unrecognised relocation type %d\n", type );
 
650
                        exit ( 1 );
 
651
                }
 
652
        }
 
653
}
 
654
 
 
655
/**
 
656
 * Process relocation records
 
657
 *
 
658
 * @v elf               ELF file
 
659
 * @v shdr              ELF section header
 
660
 * @v stride            Relocation record size
 
661
 * @v pe_reltab         PE relocation table to fill in
 
662
 */
 
663
static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
 
664
                             size_t stride, struct pe_relocs **pe_reltab ) {
 
665
        const Elf_Shdr *symtab;
 
666
        const Elf_Sym *syms;
 
667
        const Elf_Rel *rel;
 
668
        unsigned int nsyms;
 
669
        unsigned int nrels;
 
670
        unsigned int i;
 
671
 
 
672
        /* Identify symbol table */
 
673
        symtab = ( elf->data + elf->ehdr->e_shoff +
 
674
                   ( shdr->sh_link * elf->ehdr->e_shentsize ) );
 
675
        syms = ( elf->data + symtab->sh_offset );
 
676
        nsyms = ( symtab->sh_size / sizeof ( syms[0] ) );
 
677
 
 
678
        /* Process each relocation */
 
679
        rel = ( elf->data + shdr->sh_offset );
 
680
        nrels = ( shdr->sh_size / stride );
 
681
        for ( i = 0 ; i < nrels ; i++ ) {
 
682
                process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab );
 
683
                rel = ( ( ( const void * ) rel ) + stride );
 
684
        }
 
685
}
 
686
 
 
687
/**
 
688
 * Create relocations section
 
689
 *
 
690
 * @v pe_header         PE file header
 
691
 * @v pe_reltab         PE relocation table
 
692
 * @ret section         Relocation section
 
693
 */
 
694
static struct pe_section *
 
695
create_reloc_section ( struct pe_header *pe_header,
 
696
                       struct pe_relocs *pe_reltab ) {
 
697
        struct pe_section *reloc;
 
698
        size_t section_memsz;
 
699
        size_t section_filesz;
 
700
        EFI_IMAGE_DATA_DIRECTORY *relocdir;
 
701
 
 
702
        /* Allocate PE section */
 
703
        section_memsz = output_pe_reltab ( pe_reltab, NULL );
 
704
        section_filesz = efi_file_align ( section_memsz );
 
705
        reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
 
706
        memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
 
707
 
 
708
        /* Fill in section header details */
 
709
        strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
 
710
                  sizeof ( reloc->hdr.Name ) );
 
711
        reloc->hdr.Misc.VirtualSize = section_memsz;
 
712
        reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
 
713
        reloc->hdr.SizeOfRawData = section_filesz;
 
714
        reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
 
715
                                       EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
716
                                       EFI_IMAGE_SCN_MEM_READ );
 
717
 
 
718
        /* Copy in section contents */
 
719
        output_pe_reltab ( pe_reltab, reloc->contents );
 
720
 
 
721
        /* Update file header details */
 
722
        pe_header->nt.FileHeader.NumberOfSections++;
 
723
        pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
 
724
        pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
 
725
        relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
 
726
                     [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
 
727
        relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
 
728
        relocdir->Size = reloc->hdr.Misc.VirtualSize;
 
729
 
 
730
        return reloc;
 
731
}
 
732
 
 
733
/**
 
734
 * Fix up debug section
 
735
 *
 
736
 * @v debug             Debug section
 
737
 */
 
738
static void fixup_debug_section ( struct pe_section *debug ) {
 
739
        EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *contents;
 
740
 
 
741
        /* Fix up FileOffset */
 
742
        contents = ( ( void * ) debug->contents );
 
743
        contents->FileOffset += ( debug->hdr.PointerToRawData -
 
744
                                  debug->hdr.VirtualAddress );
 
745
}
 
746
 
 
747
/**
 
748
 * Create debug section
 
749
 *
 
750
 * @v pe_header         PE file header
 
751
 * @ret section         Debug section
 
752
 */
 
753
static struct pe_section *
 
754
create_debug_section ( struct pe_header *pe_header, const char *filename ) {
 
755
        struct pe_section *debug;
 
756
        size_t section_memsz;
 
757
        size_t section_filesz;
 
758
        EFI_IMAGE_DATA_DIRECTORY *debugdir;
 
759
        struct {
 
760
                EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
 
761
                EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
 
762
                char name[ strlen ( filename ) + 1 ];
 
763
        } *contents;
 
764
 
 
765
        /* Allocate PE section */
 
766
        section_memsz = sizeof ( *contents );
 
767
        section_filesz = efi_file_align ( section_memsz );
 
768
        debug = xmalloc ( sizeof ( *debug ) + section_filesz );
 
769
        memset ( debug, 0, sizeof ( *debug ) + section_filesz );
 
770
        contents = ( void * ) debug->contents;
 
771
 
 
772
        /* Fill in section header details */
 
773
        strncpy ( ( char * ) debug->hdr.Name, ".debug",
 
774
                  sizeof ( debug->hdr.Name ) );
 
775
        debug->hdr.Misc.VirtualSize = section_memsz;
 
776
        debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
 
777
        debug->hdr.SizeOfRawData = section_filesz;
 
778
        debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
 
779
                                       EFI_IMAGE_SCN_MEM_NOT_PAGED |
 
780
                                       EFI_IMAGE_SCN_MEM_READ );
 
781
        debug->fixup = fixup_debug_section;
 
782
 
 
783
        /* Create section contents */
 
784
        contents->debug.TimeDateStamp = 0x10d1a884;
 
785
        contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
 
786
        contents->debug.SizeOfData =
 
787
                ( sizeof ( *contents ) - sizeof ( contents->debug ) );
 
788
        contents->debug.RVA = ( debug->hdr.VirtualAddress +
 
789
                                offsetof ( typeof ( *contents ), rsds ) );
 
790
        contents->debug.FileOffset = contents->debug.RVA;
 
791
        contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
 
792
        snprintf ( contents->name, sizeof ( contents->name ), "%s",
 
793
                   filename );
 
794
 
 
795
        /* Update file header details */
 
796
        pe_header->nt.FileHeader.NumberOfSections++;
 
797
        pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
 
798
        pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
 
799
        debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
 
800
                     [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
 
801
        debugdir->VirtualAddress = debug->hdr.VirtualAddress;
 
802
        debugdir->Size = sizeof ( contents->debug );
 
803
 
 
804
        return debug;
 
805
}
 
806
 
 
807
/**
 
808
 * Write out PE file
 
809
 *
 
810
 * @v pe_header         PE file header
 
811
 * @v pe_sections       List of PE sections
 
812
 * @v pe                Output file
 
813
 */
 
814
static void write_pe_file ( struct pe_header *pe_header,
 
815
                            struct pe_section *pe_sections,
 
816
                            FILE *pe ) {
 
817
        struct pe_section *section;
 
818
        unsigned long fpos = 0;
 
819
 
 
820
        /* Align length of headers */
 
821
        fpos = pe_header->nt.OptionalHeader.SizeOfHeaders =
 
822
                efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
 
823
 
 
824
        /* Assign raw data pointers */
 
825
        for ( section = pe_sections ; section ; section = section->next ) {
 
826
                if ( section->hdr.SizeOfRawData ) {
 
827
                        section->hdr.PointerToRawData = fpos;
 
828
                        fpos += section->hdr.SizeOfRawData;
 
829
                        fpos = efi_file_align ( fpos );
 
830
                }
 
831
                if ( section->fixup )
 
832
                        section->fixup ( section );
 
833
        }
 
834
 
 
835
        /* Write file header */
 
836
        if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
 
837
                perror ( "Could not write PE header" );
 
838
                exit ( 1 );
 
839
        }
 
840
 
 
841
        /* Write section headers */
 
842
        for ( section = pe_sections ; section ; section = section->next ) {
 
843
                if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
 
844
                              1, pe ) != 1 ) {
 
845
                        perror ( "Could not write section header" );
 
846
                        exit ( 1 );
 
847
                }
 
848
        }
 
849
 
 
850
        /* Write sections */
 
851
        for ( section = pe_sections ; section ; section = section->next ) {
 
852
                if ( fseek ( pe, section->hdr.PointerToRawData,
 
853
                             SEEK_SET ) != 0 ) {
 
854
                        eprintf ( "Could not seek to %x: %s\n",
 
855
                                  section->hdr.PointerToRawData,
 
856
                                  strerror ( errno ) );
 
857
                        exit ( 1 );
 
858
                }
 
859
                if ( section->hdr.SizeOfRawData &&
 
860
                     ( fwrite ( section->contents, section->hdr.SizeOfRawData,
 
861
                                1, pe ) != 1 ) ) {
 
862
                        eprintf ( "Could not write section %.8s: %s\n",
 
863
                                  section->hdr.Name, strerror ( errno ) );
 
864
                        exit ( 1 );
 
865
                }
 
866
        }
 
867
}
 
868
 
 
869
/**
 
870
 * Convert ELF to PE
 
871
 *
 
872
 * @v elf_name          ELF file name
 
873
 * @v pe_name           PE file name
 
874
 */
 
875
static void elf2pe ( const char *elf_name, const char *pe_name,
 
876
                     struct options *opts ) {
 
877
        char pe_name_tmp[ strlen ( pe_name ) + 1 ];
 
878
        struct pe_relocs *pe_reltab = NULL;
 
879
        struct pe_section *pe_sections = NULL;
 
880
        struct pe_section **next_pe_section = &pe_sections;
 
881
        struct pe_header pe_header;
 
882
        struct elf_file elf;
 
883
        const Elf_Shdr *shdr;
 
884
        size_t offset;
 
885
        unsigned int i;
 
886
        FILE *pe;
 
887
 
 
888
        /* Create a modifiable copy of the PE name */
 
889
        memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
 
890
 
 
891
        /* Read ELF file */
 
892
        read_elf_file ( elf_name, &elf );
 
893
 
 
894
        /* Initialise the PE header */
 
895
        memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
 
896
        set_machine ( &elf, &pe_header );
 
897
        pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
 
898
        pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
 
899
 
 
900
        /* Process input sections */
 
901
        for ( i = 0 ; i < elf.ehdr->e_shnum ; i++ ) {
 
902
                offset = ( elf.ehdr->e_shoff + ( i * elf.ehdr->e_shentsize ) );
 
903
                shdr = ( elf.data + offset );
 
904
 
 
905
                /* Process section */
 
906
                if ( shdr->sh_flags & SHF_ALLOC ) {
 
907
 
 
908
                        /* Create output section */
 
909
                        *(next_pe_section) = process_section ( &elf, shdr,
 
910
                                                               &pe_header );
 
911
                        next_pe_section = &(*next_pe_section)->next;
 
912
 
 
913
                } else if ( shdr->sh_type == SHT_REL ) {
 
914
 
 
915
                        /* Process .rel relocations */
 
916
                        process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
 
917
                                         &pe_reltab );
 
918
 
 
919
                } else if ( shdr->sh_type == SHT_RELA ) {
 
920
 
 
921
                        /* Process .rela relocations */
 
922
                        process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
 
923
                                         &pe_reltab );
 
924
                }
 
925
        }
 
926
 
 
927
        /* Create the .reloc section */
 
928
        *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
 
929
        next_pe_section = &(*next_pe_section)->next;
 
930
 
 
931
        /* Create the .debug section */
 
932
        *(next_pe_section) = create_debug_section ( &pe_header,
 
933
                                                    basename ( pe_name_tmp ) );
 
934
        next_pe_section = &(*next_pe_section)->next;
 
935
 
 
936
        /* Write out PE file */
 
937
        pe = fopen ( pe_name, "w" );
 
938
        if ( ! pe ) {
 
939
                eprintf ( "Could not open %s for writing: %s\n",
 
940
                          pe_name, strerror ( errno ) );
 
941
                exit ( 1 );
 
942
        }
 
943
        write_pe_file ( &pe_header, pe_sections, pe );
 
944
        fclose ( pe );
 
945
 
 
946
        /* Unmap ELF file */
 
947
        munmap ( elf.data, elf.len );
 
948
}
 
949
 
 
950
/**
 
951
 * Print help
 
952
 *
 
953
 * @v program_name      Program name
 
954
 */
 
955
static void print_help ( const char *program_name ) {
 
956
        eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
 
957
                  program_name );
 
958
}
 
959
 
 
960
/**
 
961
 * Parse command-line options
 
962
 *
 
963
 * @v argc              Argument count
 
964
 * @v argv              Argument list
 
965
 * @v opts              Options structure to populate
 
966
 */
 
967
static int parse_options ( const int argc, char **argv,
 
968
                           struct options *opts ) {
 
969
        char *end;
 
970
        int c;
 
971
 
 
972
        while (1) {
 
973
                int option_index = 0;
 
974
                static struct option long_options[] = {
 
975
                        { "subsystem", required_argument, NULL, 's' },
 
976
                        { "help", 0, NULL, 'h' },
 
977
                        { 0, 0, 0, 0 }
 
978
                };
 
979
 
 
980
                if ( ( c = getopt_long ( argc, argv, "s:h",
 
981
                                         long_options,
 
982
                                         &option_index ) ) == -1 ) {
 
983
                        break;
 
984
                }
 
985
 
 
986
                switch ( c ) {
 
987
                case 's':
 
988
                        opts->subsystem = strtoul ( optarg, &end, 0 );
 
989
                        if ( *end ) {
 
990
                                eprintf ( "Invalid subsytem \"%s\"\n",
 
991
                                          optarg );
 
992
                                exit ( 2 );
 
993
                        }
 
994
                        break;
 
995
                case 'h':
 
996
                        print_help ( argv[0] );
 
997
                        exit ( 0 );
 
998
                case '?':
 
999
                default:
 
1000
                        exit ( 2 );
 
1001
                }
 
1002
        }
 
1003
        return optind;
 
1004
}
 
1005
 
 
1006
int main ( int argc, char **argv ) {
 
1007
        struct options opts = {
 
1008
                .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
 
1009
        };
 
1010
        int infile_index;
 
1011
        const char *infile;
 
1012
        const char *outfile;
 
1013
 
 
1014
        /* Parse command-line arguments */
 
1015
        infile_index = parse_options ( argc, argv, &opts );
 
1016
        if ( argc != ( infile_index + 2 ) ) {
 
1017
                print_help ( argv[0] );
 
1018
                exit ( 2 );
 
1019
        }
 
1020
        infile = argv[infile_index];
 
1021
        outfile = argv[infile_index + 1];
 
1022
 
 
1023
        /* Convert file */
 
1024
        elf2pe ( infile, outfile, &opts );
 
1025
 
 
1026
        return 0;
 
1027
}