|
@@ -17,9 +17,6 @@
|
17
|
17
|
* 02110-1301, USA.
|
18
|
18
|
*/
|
19
|
19
|
|
20
|
|
-#define _GNU_SOURCE
|
21
|
|
-#define PACKAGE "elf2efi"
|
22
|
|
-#define PACKAGE_VERSION "1"
|
23
|
20
|
#define FILE_LICENCE(...) extern void __file_licence ( void )
|
24
|
21
|
#include <stdint.h>
|
25
|
22
|
#include <stddef.h>
|
|
@@ -30,15 +27,65 @@
|
30
|
27
|
#include <errno.h>
|
31
|
28
|
#include <assert.h>
|
32
|
29
|
#include <getopt.h>
|
33
|
|
-#include <bfd.h>
|
|
30
|
+#include <sys/types.h>
|
|
31
|
+#include <sys/stat.h>
|
|
32
|
+#include <sys/mman.h>
|
|
33
|
+#include <fcntl.h>
|
|
34
|
+#include <elf.h>
|
34
|
35
|
#include <ipxe/efi/Uefi.h>
|
35
|
36
|
#include <ipxe/efi/IndustryStandard/PeImage.h>
|
36
|
37
|
#include <libgen.h>
|
37
|
38
|
|
38
|
39
|
#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
|
39
|
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
|
+
|
40
|
73
|
#define EFI_FILE_ALIGN 0x20
|
41
|
74
|
|
|
75
|
+struct elf_machine {
|
|
76
|
+ unsigned int pe_machine;
|
|
77
|
+ unsigned int r_none;
|
|
78
|
+ unsigned int r_abs;
|
|
79
|
+ unsigned int r_pcrel;
|
|
80
|
+};
|
|
81
|
+
|
|
82
|
+struct elf_file {
|
|
83
|
+ void *data;
|
|
84
|
+ size_t len;
|
|
85
|
+ const Elf_Ehdr *ehdr;
|
|
86
|
+ struct elf_machine *machine;
|
|
87
|
+};
|
|
88
|
+
|
42
|
89
|
struct pe_section {
|
43
|
90
|
struct pe_section *next;
|
44
|
91
|
EFI_IMAGE_SECTION_HEADER hdr;
|
|
@@ -57,11 +104,7 @@ struct pe_relocs {
|
57
|
104
|
struct pe_header {
|
58
|
105
|
EFI_IMAGE_DOS_HEADER dos;
|
59
|
106
|
uint8_t padding[128];
|
60
|
|
-#if defined(EFI_TARGET_IA32)
|
61
|
|
- EFI_IMAGE_NT_HEADERS32 nt;
|
62
|
|
-#elif defined(EFI_TARGET_X64)
|
63
|
|
- EFI_IMAGE_NT_HEADERS64 nt;
|
64
|
|
-#endif
|
|
107
|
+ EFI_IMAGE_NT_HEADERS nt;
|
65
|
108
|
};
|
66
|
109
|
|
67
|
110
|
static struct pe_header efi_pe_header = {
|
|
@@ -72,26 +115,15 @@ static struct pe_header efi_pe_header = {
|
72
|
115
|
.nt = {
|
73
|
116
|
.Signature = EFI_IMAGE_NT_SIGNATURE,
|
74
|
117
|
.FileHeader = {
|
75
|
|
-#if defined(EFI_TARGET_IA32)
|
76
|
|
- .Machine = EFI_IMAGE_MACHINE_IA32,
|
77
|
|
-#elif defined(EFI_TARGET_X64)
|
78
|
|
- .Machine = EFI_IMAGE_MACHINE_X64,
|
79
|
|
-#endif
|
80
|
118
|
.TimeDateStamp = 0x10d1a884,
|
81
|
119
|
.SizeOfOptionalHeader =
|
82
|
120
|
sizeof ( efi_pe_header.nt.OptionalHeader ),
|
83
|
121
|
.Characteristics = ( EFI_IMAGE_FILE_DLL |
|
84
|
|
-#if defined(EFI_TARGET_IA32)
|
85
|
|
- EFI_IMAGE_FILE_32BIT_MACHINE |
|
86
|
|
-#endif
|
|
122
|
+ EFI_IMAGE_FILE_MACHINE |
|
87
|
123
|
EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
|
88
|
124
|
},
|
89
|
125
|
.OptionalHeader = {
|
90
|
|
-#if defined(EFI_TARGET_IA32)
|
91
|
|
- .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
|
92
|
|
-#elif defined(EFI_TARGET_X64)
|
93
|
|
- .Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
|
94
|
|
-#endif
|
|
126
|
+ .Magic = EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC,
|
95
|
127
|
.MajorLinkerVersion = 42,
|
96
|
128
|
.MinorLinkerVersion = 42,
|
97
|
129
|
.SectionAlignment = EFI_FILE_ALIGN,
|
|
@@ -104,6 +136,20 @@ static struct pe_header efi_pe_header = {
|
104
|
136
|
},
|
105
|
137
|
};
|
106
|
138
|
|
|
139
|
+static struct elf_machine machine_i386 = {
|
|
140
|
+ .pe_machine = EFI_IMAGE_MACHINE_IA32,
|
|
141
|
+ .r_none = R_386_NONE,
|
|
142
|
+ .r_abs = R_386_32,
|
|
143
|
+ .r_pcrel = R_386_PC32,
|
|
144
|
+};
|
|
145
|
+
|
|
146
|
+static struct elf_machine machine_x86_64 = {
|
|
147
|
+ .pe_machine = EFI_IMAGE_MACHINE_X64,
|
|
148
|
+ .r_none = R_X86_64_NONE,
|
|
149
|
+ .r_abs = R_X86_64_64,
|
|
150
|
+ .r_pcrel = R_X86_64_PC32,
|
|
151
|
+};
|
|
152
|
+
|
107
|
153
|
/** Command-line options */
|
108
|
154
|
struct options {
|
109
|
155
|
unsigned int subsystem;
|
|
@@ -235,110 +281,155 @@ static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
|
235
|
281
|
}
|
236
|
282
|
|
237
|
283
|
/**
|
238
|
|
- * Open input BFD file
|
|
284
|
+ * Read input ELF file
|
239
|
285
|
*
|
240
|
|
- * @v filename File name
|
241
|
|
- * @ret ibfd BFD file
|
|
286
|
+ * @v name File name
|
|
287
|
+ * @v elf ELF file
|
242
|
288
|
*/
|
243
|
|
-static bfd * open_input_bfd ( const char *filename ) {
|
244
|
|
- bfd *bfd;
|
245
|
|
-
|
246
|
|
- /* Open the file */
|
247
|
|
- bfd = bfd_openr ( filename, NULL );
|
248
|
|
- if ( ! bfd ) {
|
249
|
|
- eprintf ( "Cannot open %s: ", filename );
|
250
|
|
- bfd_perror ( NULL );
|
|
289
|
+static void read_elf_file ( const char *name, struct elf_file *elf ) {
|
|
290
|
+ static const unsigned char ident[] = {
|
|
291
|
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS, ELFDATA2LSB
|
|
292
|
+ };
|
|
293
|
+ struct stat stat;
|
|
294
|
+ const Elf_Ehdr *ehdr;
|
|
295
|
+ const Elf_Shdr *shdr;
|
|
296
|
+ void *data;
|
|
297
|
+ size_t offset;
|
|
298
|
+ unsigned int i;
|
|
299
|
+ int fd;
|
|
300
|
+
|
|
301
|
+ /* Open file */
|
|
302
|
+ fd = open ( name, O_RDONLY );
|
|
303
|
+ if ( fd < 0 ) {
|
|
304
|
+ eprintf ( "Could not open %s: %s\n", name, strerror ( errno ) );
|
251
|
305
|
exit ( 1 );
|
252
|
306
|
}
|
253
|
307
|
|
254
|
|
- /* The call to bfd_check_format() must be present, otherwise
|
255
|
|
- * we get a segfault from later BFD calls.
|
256
|
|
- */
|
257
|
|
- if ( ! bfd_check_format ( bfd, bfd_object ) ) {
|
258
|
|
- eprintf ( "%s is not an object file: ", filename );
|
259
|
|
- bfd_perror ( NULL );
|
|
308
|
+ /* Get file size */
|
|
309
|
+ if ( fstat ( fd, &stat ) < 0 ) {
|
|
310
|
+ eprintf ( "Could not get size of %s: %s\n",
|
|
311
|
+ name, strerror ( errno ) );
|
260
|
312
|
exit ( 1 );
|
261
|
313
|
}
|
|
314
|
+ elf->len = stat.st_size;
|
262
|
315
|
|
263
|
|
- return bfd;
|
264
|
|
-}
|
265
|
|
-
|
266
|
|
-/**
|
267
|
|
- * Read symbol table
|
268
|
|
- *
|
269
|
|
- * @v bfd BFD file
|
270
|
|
- */
|
271
|
|
-static asymbol ** read_symtab ( bfd *bfd ) {
|
272
|
|
- long symtab_size;
|
273
|
|
- asymbol **symtab;
|
274
|
|
- long symcount;
|
275
|
|
-
|
276
|
|
- /* Get symbol table size */
|
277
|
|
- symtab_size = bfd_get_symtab_upper_bound ( bfd );
|
278
|
|
- if ( symtab_size < 0 ) {
|
279
|
|
- bfd_perror ( "Could not get symbol table upper bound" );
|
|
316
|
+ /* Map file */
|
|
317
|
+ data = mmap ( NULL, elf->len, PROT_READ, MAP_SHARED, fd, 0 );
|
|
318
|
+ if ( data == MAP_FAILED ) {
|
|
319
|
+ eprintf ( "Could not map %s: %s\n", name, strerror ( errno ) );
|
280
|
320
|
exit ( 1 );
|
281
|
321
|
}
|
|
322
|
+ elf->data = data;
|
282
|
323
|
|
283
|
|
- /* Allocate and read symbol table */
|
284
|
|
- symtab = xmalloc ( symtab_size );
|
285
|
|
- symcount = bfd_canonicalize_symtab ( bfd, symtab );
|
286
|
|
- if ( symcount < 0 ) {
|
287
|
|
- bfd_perror ( "Cannot read symbol table" );
|
|
324
|
+ /* Close file */
|
|
325
|
+ close ( fd );
|
|
326
|
+
|
|
327
|
+ /* Check header */
|
|
328
|
+ ehdr = elf->data;
|
|
329
|
+ if ( ( elf->len < sizeof ( *ehdr ) ) ||
|
|
330
|
+ ( memcmp ( ident, ehdr->e_ident, sizeof ( ident ) ) != 0 ) ) {
|
|
331
|
+ eprintf ( "Invalid ELF header in %s\n", name );
|
288
|
332
|
exit ( 1 );
|
289
|
333
|
}
|
|
334
|
+ elf->ehdr = ehdr;
|
|
335
|
+
|
|
336
|
+ /* Check section headers */
|
|
337
|
+ for ( i = 0 ; i < ehdr->e_shnum ; i++ ) {
|
|
338
|
+ offset = ( ehdr->e_shoff + ( i * ehdr->e_shentsize ) );
|
|
339
|
+ if ( elf->len < ( offset + sizeof ( *shdr ) ) ) {
|
|
340
|
+ eprintf ( "ELF section header outside file in %s\n",
|
|
341
|
+ name );
|
|
342
|
+ exit ( 1 );
|
|
343
|
+ }
|
|
344
|
+ shdr = ( data + offset );
|
|
345
|
+ if ( ( shdr->sh_type != SHT_NOBITS ) &&
|
|
346
|
+ ( ( elf->len < shdr->sh_offset ) ||
|
|
347
|
+ ( ( ( elf->len - shdr->sh_offset ) < shdr->sh_size ) ))){
|
|
348
|
+ eprintf ( "ELF section %d outside file in %s\n",
|
|
349
|
+ i, name );
|
|
350
|
+ exit ( 1 );
|
|
351
|
+ }
|
|
352
|
+ if ( shdr->sh_link >= ehdr->e_shnum ) {
|
|
353
|
+ eprintf ( "ELF section %d link section %d out of "
|
|
354
|
+ "range\n", i, shdr->sh_link );
|
|
355
|
+ exit ( 1 );
|
|
356
|
+ }
|
|
357
|
+ }
|
290
|
358
|
|
291
|
|
- return symtab;
|
|
359
|
+ /* Identify architecture */
|
|
360
|
+ switch ( ehdr->e_machine ) {
|
|
361
|
+ case EM_386:
|
|
362
|
+ elf->machine = &machine_i386;
|
|
363
|
+ break;
|
|
364
|
+ case EM_X86_64:
|
|
365
|
+ elf->machine = &machine_x86_64;
|
|
366
|
+ break;
|
|
367
|
+ default:
|
|
368
|
+ eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
|
|
369
|
+ exit ( 1 );
|
|
370
|
+ }
|
292
|
371
|
}
|
293
|
372
|
|
294
|
373
|
/**
|
295
|
|
- * Read relocation table
|
|
374
|
+ * Get ELF string
|
296
|
375
|
*
|
297
|
|
- * @v bfd BFD file
|
298
|
|
- * @v symtab Symbol table
|
299
|
|
- * @v section Section
|
300
|
|
- * @v symtab Symbol table
|
301
|
|
- * @ret reltab Relocation table
|
|
376
|
+ * @v elf ELF file
|
|
377
|
+ * @v section String table section number
|
|
378
|
+ * @v offset String table offset
|
|
379
|
+ * @ret string ELF string
|
302
|
380
|
*/
|
303
|
|
-static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
|
304
|
|
- asection *section ) {
|
305
|
|
- long reltab_size;
|
306
|
|
- arelent **reltab;
|
307
|
|
- long numrels;
|
308
|
|
-
|
309
|
|
- /* Get relocation table size */
|
310
|
|
- reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
|
311
|
|
- if ( reltab_size < 0 ) {
|
312
|
|
- bfd_perror ( "Could not get relocation table upper bound" );
|
|
381
|
+static const char * elf_string ( struct elf_file *elf, unsigned int section,
|
|
382
|
+ size_t offset ) {
|
|
383
|
+ const Elf_Ehdr *ehdr = elf->ehdr;
|
|
384
|
+ const Elf_Shdr *shdr;
|
|
385
|
+ char *string;
|
|
386
|
+ char *last;
|
|
387
|
+
|
|
388
|
+ /* Locate section header */
|
|
389
|
+ if ( section >= ehdr->e_shnum ) {
|
|
390
|
+ eprintf ( "Invalid ELF string section %d\n", section );
|
313
|
391
|
exit ( 1 );
|
314
|
392
|
}
|
|
393
|
+ shdr = ( elf->data + ehdr->e_shoff + ( section * ehdr->e_shentsize ) );
|
315
|
394
|
|
316
|
|
- /* Allocate and read relocation table */
|
317
|
|
- reltab = xmalloc ( reltab_size );
|
318
|
|
- numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
|
319
|
|
- if ( numrels < 0 ) {
|
320
|
|
- bfd_perror ( "Cannot read relocation table" );
|
|
395
|
+ /* Sanity check section */
|
|
396
|
+ if ( shdr->sh_type != SHT_STRTAB ) {
|
|
397
|
+ eprintf ( "ELF section %d (type %d) is not a string table\n",
|
|
398
|
+ section, shdr->sh_type );
|
|
399
|
+ exit ( 1 );
|
|
400
|
+ }
|
|
401
|
+ last = ( elf->data + shdr->sh_offset + shdr->sh_size - 1 );
|
|
402
|
+ if ( *last != '\0' ) {
|
|
403
|
+ eprintf ( "ELF section %d is not NUL-terminated\n", section );
|
321
|
404
|
exit ( 1 );
|
322
|
405
|
}
|
323
|
406
|
|
324
|
|
- return reltab;
|
|
407
|
+ /* Locate string */
|
|
408
|
+ if ( offset >= shdr->sh_size ) {
|
|
409
|
+ eprintf ( "Invalid ELF string offset %zd in section %d\n",
|
|
410
|
+ offset, section );
|
|
411
|
+ exit ( 1 );
|
|
412
|
+ }
|
|
413
|
+ string = ( elf->data + shdr->sh_offset + offset );
|
|
414
|
+
|
|
415
|
+ return string;
|
325
|
416
|
}
|
326
|
417
|
|
327
|
418
|
/**
|
328
|
419
|
* Process section
|
329
|
420
|
*
|
330
|
|
- * @v bfd BFD file
|
|
421
|
+ * @v elf ELF file
|
|
422
|
+ * @v shdr ELF section header
|
331
|
423
|
* @v pe_header PE file header
|
332
|
|
- * @v section Section
|
333
|
424
|
* @ret new New PE section
|
334
|
425
|
*/
|
335
|
|
-static struct pe_section * process_section ( bfd *bfd,
|
336
|
|
- struct pe_header *pe_header,
|
337
|
|
- asection *section ) {
|
|
426
|
+static struct pe_section * process_section ( struct elf_file *elf,
|
|
427
|
+ const Elf_Shdr *shdr,
|
|
428
|
+ struct pe_header *pe_header ) {
|
338
|
429
|
struct pe_section *new;
|
|
430
|
+ const char *name;
|
339
|
431
|
size_t section_memsz;
|
340
|
432
|
size_t section_filesz;
|
341
|
|
- unsigned long flags = bfd_get_section_flags ( bfd, section );
|
342
|
433
|
unsigned long code_start;
|
343
|
434
|
unsigned long code_end;
|
344
|
435
|
unsigned long data_start;
|
|
@@ -349,12 +440,15 @@ static struct pe_section * process_section ( bfd *bfd,
|
349
|
440
|
unsigned long *applicable_start;
|
350
|
441
|
unsigned long *applicable_end;
|
351
|
442
|
|
|
443
|
+ /* Get section name */
|
|
444
|
+ name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name );
|
|
445
|
+
|
352
|
446
|
/* Extract current RVA limits from file header */
|
353
|
447
|
code_start = pe_header->nt.OptionalHeader.BaseOfCode;
|
354
|
448
|
code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
|
355
|
|
-#if defined(EFI_TARGET_IA32)
|
|
449
|
+#if defined(EFI_TARGET32)
|
356
|
450
|
data_start = pe_header->nt.OptionalHeader.BaseOfData;
|
357
|
|
-#elif defined(EFI_TARGET_X64)
|
|
451
|
+#elif defined(EFI_TARGET64)
|
358
|
452
|
data_start = code_end;
|
359
|
453
|
#endif
|
360
|
454
|
data_mid = ( data_start +
|
|
@@ -363,21 +457,21 @@ static struct pe_section * process_section ( bfd *bfd,
|
363
|
457
|
pe_header->nt.OptionalHeader.SizeOfUninitializedData );
|
364
|
458
|
|
365
|
459
|
/* Allocate PE section */
|
366
|
|
- section_memsz = bfd_section_size ( bfd, section );
|
367
|
|
- section_filesz = ( ( flags & SEC_LOAD ) ?
|
|
460
|
+ section_memsz = shdr->sh_size;
|
|
461
|
+ section_filesz = ( ( shdr->sh_type == SHT_PROGBITS ) ?
|
368
|
462
|
efi_file_align ( section_memsz ) : 0 );
|
369
|
463
|
new = xmalloc ( sizeof ( *new ) + section_filesz );
|
370
|
464
|
memset ( new, 0, sizeof ( *new ) + section_filesz );
|
371
|
465
|
|
372
|
466
|
/* Fill in section header details */
|
373
|
|
- strncpy ( ( char * ) new->hdr.Name, section->name,
|
374
|
|
- sizeof ( new->hdr.Name ) );
|
|
467
|
+ strncpy ( ( char * ) new->hdr.Name, name, sizeof ( new->hdr.Name ) );
|
375
|
468
|
new->hdr.Misc.VirtualSize = section_memsz;
|
376
|
|
- new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
|
|
469
|
+ new->hdr.VirtualAddress = shdr->sh_addr;
|
377
|
470
|
new->hdr.SizeOfRawData = section_filesz;
|
378
|
471
|
|
379
|
472
|
/* Fill in section characteristics and update RVA limits */
|
380
|
|
- if ( flags & SEC_CODE ) {
|
|
473
|
+ if ( ( shdr->sh_type == SHT_PROGBITS ) &&
|
|
474
|
+ ( shdr->sh_flags & SHF_EXECINSTR ) ) {
|
381
|
475
|
/* .text-type section */
|
382
|
476
|
new->hdr.Characteristics =
|
383
|
477
|
( EFI_IMAGE_SCN_CNT_CODE |
|
|
@@ -386,7 +480,8 @@ static struct pe_section * process_section ( bfd *bfd,
|
386
|
480
|
EFI_IMAGE_SCN_MEM_READ );
|
387
|
481
|
applicable_start = &code_start;
|
388
|
482
|
applicable_end = &code_end;
|
389
|
|
- } else if ( flags & SEC_DATA ) {
|
|
483
|
+ } else if ( ( shdr->sh_type == SHT_PROGBITS ) &&
|
|
484
|
+ ( shdr->sh_flags & SHF_WRITE ) ) {
|
390
|
485
|
/* .data-type section */
|
391
|
486
|
new->hdr.Characteristics =
|
392
|
487
|
( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
@@ -395,7 +490,7 @@ static struct pe_section * process_section ( bfd *bfd,
|
395
|
490
|
EFI_IMAGE_SCN_MEM_WRITE );
|
396
|
491
|
applicable_start = &data_start;
|
397
|
492
|
applicable_end = &data_mid;
|
398
|
|
- } else if ( flags & SEC_READONLY ) {
|
|
493
|
+ } else if ( shdr->sh_type == SHT_PROGBITS ) {
|
399
|
494
|
/* .rodata-type section */
|
400
|
495
|
new->hdr.Characteristics =
|
401
|
496
|
( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
@@ -403,7 +498,7 @@ static struct pe_section * process_section ( bfd *bfd,
|
403
|
498
|
EFI_IMAGE_SCN_MEM_READ );
|
404
|
499
|
applicable_start = &data_start;
|
405
|
500
|
applicable_end = &data_mid;
|
406
|
|
- } else if ( ! ( flags & SEC_LOAD ) ) {
|
|
501
|
+ } else if ( shdr->sh_type == SHT_NOBITS ) {
|
407
|
502
|
/* .bss-type section */
|
408
|
503
|
new->hdr.Characteristics =
|
409
|
504
|
( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
|
|
@@ -413,19 +508,15 @@ static struct pe_section * process_section ( bfd *bfd,
|
413
|
508
|
applicable_start = &data_mid;
|
414
|
509
|
applicable_end = &data_end;
|
415
|
510
|
} else {
|
416
|
|
- eprintf ( "Unrecognised characteristics %#lx for section %s\n",
|
417
|
|
- flags, section->name );
|
|
511
|
+ eprintf ( "Unrecognised characteristics for section %s\n",
|
|
512
|
+ name );
|
418
|
513
|
exit ( 1 );
|
419
|
514
|
}
|
420
|
515
|
|
421
|
516
|
/* Copy in section contents */
|
422
|
|
- if ( flags & SEC_LOAD ) {
|
423
|
|
- if ( ! bfd_get_section_contents ( bfd, section, new->contents,
|
424
|
|
- 0, section_memsz ) ) {
|
425
|
|
- eprintf ( "Cannot read section %s: ", section->name );
|
426
|
|
- bfd_perror ( NULL );
|
427
|
|
- exit ( 1 );
|
428
|
|
- }
|
|
517
|
+ if ( shdr->sh_type == SHT_PROGBITS ) {
|
|
518
|
+ memcpy ( new->contents, ( elf->data + shdr->sh_offset ),
|
|
519
|
+ shdr->sh_size );
|
429
|
520
|
}
|
430
|
521
|
|
431
|
522
|
/* Update RVA limits */
|
|
@@ -445,7 +536,7 @@ static struct pe_section * process_section ( bfd *bfd,
|
445
|
536
|
/* Write RVA limits back to file header */
|
446
|
537
|
pe_header->nt.OptionalHeader.BaseOfCode = code_start;
|
447
|
538
|
pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
|
448
|
|
-#if defined(EFI_TARGET_IA32)
|
|
539
|
+#if defined(EFI_TARGET32)
|
449
|
540
|
pe_header->nt.OptionalHeader.BaseOfData = data_start;
|
450
|
541
|
#endif
|
451
|
542
|
pe_header->nt.OptionalHeader.SizeOfInitializedData =
|
|
@@ -465,46 +556,76 @@ static struct pe_section * process_section ( bfd *bfd,
|
465
|
556
|
/**
|
466
|
557
|
* Process relocation record
|
467
|
558
|
*
|
468
|
|
- * @v bfd BFD file
|
469
|
|
- * @v section Section
|
470
|
|
- * @v rel Relocation entry
|
|
559
|
+ * @v elf ELF file
|
|
560
|
+ * @v shdr ELF section header
|
|
561
|
+ * @v syms Symbol table
|
|
562
|
+ * @v nsyms Number of symbol table entries
|
|
563
|
+ * @v rel Relocation record
|
471
|
564
|
* @v pe_reltab PE relocation table to fill in
|
472
|
565
|
*/
|
473
|
|
-static void process_reloc ( bfd *bfd __attribute__ (( unused )),
|
474
|
|
- asection *section, arelent *rel,
|
475
|
|
- struct pe_relocs **pe_reltab ) {
|
476
|
|
- reloc_howto_type *howto = rel->howto;
|
477
|
|
- asymbol *sym = *(rel->sym_ptr_ptr);
|
478
|
|
- unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
|
479
|
|
- rel->address );
|
480
|
|
-
|
481
|
|
- if ( bfd_is_abs_section ( sym->section ) ) {
|
|
566
|
+static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
|
|
567
|
+ const Elf_Sym *syms, unsigned int nsyms,
|
|
568
|
+ const Elf_Rel *rel, struct pe_relocs **pe_reltab ) {
|
|
569
|
+ unsigned int type = ELF_R_TYPE ( rel->r_info );
|
|
570
|
+ unsigned int sym = ELF_R_SYM ( rel->r_info );
|
|
571
|
+ size_t offset = ( shdr->sh_addr + rel->r_offset );
|
|
572
|
+
|
|
573
|
+ /* Look up symbol and process relocation */
|
|
574
|
+ if ( sym >= nsyms ) {
|
|
575
|
+ eprintf ( "Symbol out of range\n" );
|
|
576
|
+ exit ( 1 );
|
|
577
|
+ }
|
|
578
|
+ if ( syms[sym].st_shndx == SHN_ABS ) {
|
482
|
579
|
/* Skip absolute symbols; the symbol value won't
|
483
|
580
|
* change when the object is loaded.
|
484
|
581
|
*/
|
485
|
|
- } else if ( ( strcmp ( howto->name, "R_386_NONE" ) == 0 ) ||
|
486
|
|
- ( strcmp ( howto->name, "R_X86_64_NONE" ) == 0 ) ) {
|
|
582
|
+ } else if ( type == elf->machine->r_none ) {
|
487
|
583
|
/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
|
488
|
|
- } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
|
489
|
|
- /* Generate an 8-byte PE relocation */
|
490
|
|
- generate_pe_reloc ( pe_reltab, offset, 8 );
|
491
|
|
- } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) {
|
492
|
|
- /* Generate a 4-byte PE relocation */
|
493
|
|
- generate_pe_reloc ( pe_reltab, offset, 4 );
|
494
|
|
- } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
|
495
|
|
- /* Generate a 2-byte PE relocation */
|
496
|
|
- generate_pe_reloc ( pe_reltab, offset, 2 );
|
497
|
|
- } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
|
498
|
|
- ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
|
|
584
|
+ } else if ( type == elf->machine->r_abs ) {
|
|
585
|
+ /* Generate an 8-byte or 4-byte PE relocation */
|
|
586
|
+ generate_pe_reloc ( pe_reltab, offset, sizeof ( Elf_Addr ) );
|
|
587
|
+ } else if ( type == elf->machine->r_pcrel ) {
|
499
|
588
|
/* Skip PC-relative relocations; all relative offsets
|
500
|
589
|
* remain unaltered when the object is loaded.
|
501
|
590
|
*/
|
502
|
591
|
} else {
|
503
|
|
- eprintf ( "Unrecognised relocation type %s\n", howto->name );
|
|
592
|
+ eprintf ( "Unrecognised relocation type %d\n", type );
|
504
|
593
|
exit ( 1 );
|
505
|
594
|
}
|
506
|
595
|
}
|
507
|
596
|
|
|
597
|
+/**
|
|
598
|
+ * Process relocation records
|
|
599
|
+ *
|
|
600
|
+ * @v elf ELF file
|
|
601
|
+ * @v shdr ELF section header
|
|
602
|
+ * @v stride Relocation record size
|
|
603
|
+ * @v pe_reltab PE relocation table to fill in
|
|
604
|
+ */
|
|
605
|
+static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
|
|
606
|
+ size_t stride, struct pe_relocs **pe_reltab ) {
|
|
607
|
+ const Elf_Shdr *symtab;
|
|
608
|
+ const Elf_Sym *syms;
|
|
609
|
+ const Elf_Rel *rel;
|
|
610
|
+ unsigned int nsyms;
|
|
611
|
+ unsigned int nrels;
|
|
612
|
+ unsigned int i;
|
|
613
|
+
|
|
614
|
+ /* Identify symbol table */
|
|
615
|
+ symtab = ( elf->data + elf->ehdr->e_shoff +
|
|
616
|
+ ( shdr->sh_link * elf->ehdr->e_shentsize ) );
|
|
617
|
+ syms = ( elf->data + symtab->sh_offset );
|
|
618
|
+ nsyms = ( symtab->sh_size / sizeof ( syms[0] ) );
|
|
619
|
+
|
|
620
|
+ /* Process each relocation */
|
|
621
|
+ rel = ( elf->data + shdr->sh_offset );
|
|
622
|
+ nrels = ( shdr->sh_size / stride );
|
|
623
|
+ for ( i = 0 ; i < nrels ; i++ ) {
|
|
624
|
+ process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab );
|
|
625
|
+ rel = ( ( ( const void * ) rel ) + stride );
|
|
626
|
+ }
|
|
627
|
+}
|
|
628
|
+
|
508
|
629
|
/**
|
509
|
630
|
* Create relocations section
|
510
|
631
|
*
|
|
@@ -696,53 +817,60 @@ static void write_pe_file ( struct pe_header *pe_header,
|
696
|
817
|
static void elf2pe ( const char *elf_name, const char *pe_name,
|
697
|
818
|
struct options *opts ) {
|
698
|
819
|
char pe_name_tmp[ strlen ( pe_name ) + 1 ];
|
699
|
|
- bfd *bfd;
|
700
|
|
- asymbol **symtab;
|
701
|
|
- asection *section;
|
702
|
|
- arelent **reltab;
|
703
|
|
- arelent **rel;
|
704
|
820
|
struct pe_relocs *pe_reltab = NULL;
|
705
|
821
|
struct pe_section *pe_sections = NULL;
|
706
|
822
|
struct pe_section **next_pe_section = &pe_sections;
|
707
|
823
|
struct pe_header pe_header;
|
|
824
|
+ struct elf_file elf;
|
|
825
|
+ const Elf_Shdr *shdr;
|
|
826
|
+ size_t offset;
|
|
827
|
+ unsigned int i;
|
708
|
828
|
FILE *pe;
|
709
|
829
|
|
710
|
830
|
/* Create a modifiable copy of the PE name */
|
711
|
831
|
memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
|
712
|
832
|
|
713
|
|
- /* Open the file */
|
714
|
|
- bfd = open_input_bfd ( elf_name );
|
715
|
|
- symtab = read_symtab ( bfd );
|
|
833
|
+ /* Read ELF file */
|
|
834
|
+ read_elf_file ( elf_name, &elf );
|
716
|
835
|
|
717
|
836
|
/* Initialise the PE header */
|
718
|
837
|
memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
|
719
|
|
- pe_header.nt.OptionalHeader.AddressOfEntryPoint =
|
720
|
|
- bfd_get_start_address ( bfd );
|
|
838
|
+ pe_header.nt.FileHeader.Machine = elf.machine->pe_machine;
|
|
839
|
+ pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
|
721
|
840
|
pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
|
722
|
841
|
|
723
|
|
- /* For each input section, build an output section and create
|
724
|
|
- * the appropriate relocation records
|
725
|
|
- */
|
726
|
|
- for ( section = bfd->sections ; section ; section = section->next ) {
|
727
|
|
- /* Discard non-allocatable sections */
|
728
|
|
- if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
|
729
|
|
- continue;
|
730
|
|
- /* Create output section */
|
731
|
|
- *(next_pe_section) = process_section ( bfd, &pe_header,
|
732
|
|
- section );
|
733
|
|
- next_pe_section = &(*next_pe_section)->next;
|
734
|
|
- /* Add relocations from this section */
|
735
|
|
- reltab = read_reltab ( bfd, symtab, section );
|
736
|
|
- for ( rel = reltab ; *rel ; rel++ )
|
737
|
|
- process_reloc ( bfd, section, *rel, &pe_reltab );
|
738
|
|
- free ( reltab );
|
|
842
|
+ /* Process input sections */
|
|
843
|
+ for ( i = 0 ; i < elf.ehdr->e_shnum ; i++ ) {
|
|
844
|
+ offset = ( elf.ehdr->e_shoff + ( i * elf.ehdr->e_shentsize ) );
|
|
845
|
+ shdr = ( elf.data + offset );
|
|
846
|
+
|
|
847
|
+ /* Process section */
|
|
848
|
+ if ( shdr->sh_flags & SHF_ALLOC ) {
|
|
849
|
+
|
|
850
|
+ /* Create output section */
|
|
851
|
+ *(next_pe_section) = process_section ( &elf, shdr,
|
|
852
|
+ &pe_header );
|
|
853
|
+ next_pe_section = &(*next_pe_section)->next;
|
|
854
|
+
|
|
855
|
+ } else if ( shdr->sh_type == SHT_REL ) {
|
|
856
|
+
|
|
857
|
+ /* Process .rel relocations */
|
|
858
|
+ process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
|
|
859
|
+ &pe_reltab );
|
|
860
|
+
|
|
861
|
+ } else if ( shdr->sh_type == SHT_RELA ) {
|
|
862
|
+
|
|
863
|
+ /* Process .rela relocations */
|
|
864
|
+ process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
|
|
865
|
+ &pe_reltab );
|
|
866
|
+ }
|
739
|
867
|
}
|
740
|
868
|
|
741
|
869
|
/* Create the .reloc section */
|
742
|
870
|
*(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
|
743
|
871
|
next_pe_section = &(*next_pe_section)->next;
|
744
|
872
|
|
745
|
|
- /* Create the .reloc section */
|
|
873
|
+ /* Create the .debug section */
|
746
|
874
|
*(next_pe_section) = create_debug_section ( &pe_header,
|
747
|
875
|
basename ( pe_name_tmp ) );
|
748
|
876
|
next_pe_section = &(*next_pe_section)->next;
|
|
@@ -757,8 +885,8 @@ static void elf2pe ( const char *elf_name, const char *pe_name,
|
757
|
885
|
write_pe_file ( &pe_header, pe_sections, pe );
|
758
|
886
|
fclose ( pe );
|
759
|
887
|
|
760
|
|
- /* Close BFD file */
|
761
|
|
- bfd_close ( bfd );
|
|
888
|
+ /* Unmap ELF file */
|
|
889
|
+ munmap ( elf.data, elf.len );
|
762
|
890
|
}
|
763
|
891
|
|
764
|
892
|
/**
|
|
@@ -825,9 +953,6 @@ int main ( int argc, char **argv ) {
|
825
|
953
|
const char *infile;
|
826
|
954
|
const char *outfile;
|
827
|
955
|
|
828
|
|
- /* Initialise libbfd */
|
829
|
|
- bfd_init();
|
830
|
|
-
|
831
|
956
|
/* Parse command-line arguments */
|
832
|
957
|
infile_index = parse_options ( argc, argv, &opts );
|
833
|
958
|
if ( argc != ( infile_index + 2 ) ) {
|