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