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 */
xmalloc(size_t len)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 */
efi_file_align(unsigned long offset)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 */
generate_pe_reloc(struct pe_relocs ** pe_reltab,unsigned long rva,size_t size)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 */
output_pe_reltab(struct pe_relocs * pe_reltab,void * buffer)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 */
read_elf_file(const char * name,struct elf_file * elf)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 */
elf_string(struct elf_file * elf,unsigned int section,size_t offset)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 */
set_machine(struct elf_file * elf,struct pe_header * pe_header)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 */
process_section(struct elf_file * elf,const Elf_Shdr * shdr,struct pe_header * pe_header)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 */
process_reloc(struct elf_file * elf,const Elf_Shdr * shdr,const Elf_Sym * syms,unsigned int nsyms,const Elf_Rel * rel,struct pe_relocs ** pe_reltab)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_X86_64, R_X86_64_PLT32 ) :
640 case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) :
641 case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) :
642 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) :
643 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_PG_HI21 ) :
644 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADD_ABS_LO12_NC ) :
645 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST8_ABS_LO12_NC ) :
646 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST16_ABS_LO12_NC ) :
647 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) :
648 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) :
649 /* Skip PC-relative relocations; all relative
650 * offsets remain unaltered when the object is
651 * loaded.
652 */
653 break;
654 default:
655 eprintf ( "Unrecognised relocation type %d\n", type );
656 exit ( 1 );
657 }
658 }
659 }
660
661 /**
662 * Process relocation records
663 *
664 * @v elf ELF file
665 * @v shdr ELF section header
666 * @v stride Relocation record size
667 * @v pe_reltab PE relocation table to fill in
668 */
process_relocs(struct elf_file * elf,const Elf_Shdr * shdr,size_t stride,struct pe_relocs ** pe_reltab)669 static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
670 size_t stride, struct pe_relocs **pe_reltab ) {
671 const Elf_Shdr *symtab;
672 const Elf_Sym *syms;
673 const Elf_Rel *rel;
674 unsigned int nsyms;
675 unsigned int nrels;
676 unsigned int i;
677
678 /* Identify symbol table */
679 symtab = ( elf->data + elf->ehdr->e_shoff +
680 ( shdr->sh_link * elf->ehdr->e_shentsize ) );
681 syms = ( elf->data + symtab->sh_offset );
682 nsyms = ( symtab->sh_size / sizeof ( syms[0] ) );
683
684 /* Process each relocation */
685 rel = ( elf->data + shdr->sh_offset );
686 nrels = ( shdr->sh_size / stride );
687 for ( i = 0 ; i < nrels ; i++ ) {
688 process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab );
689 rel = ( ( ( const void * ) rel ) + stride );
690 }
691 }
692
693 /**
694 * Create relocations section
695 *
696 * @v pe_header PE file header
697 * @v pe_reltab PE relocation table
698 * @ret section Relocation section
699 */
700 static struct pe_section *
create_reloc_section(struct pe_header * pe_header,struct pe_relocs * pe_reltab)701 create_reloc_section ( struct pe_header *pe_header,
702 struct pe_relocs *pe_reltab ) {
703 struct pe_section *reloc;
704 size_t section_memsz;
705 size_t section_filesz;
706 EFI_IMAGE_DATA_DIRECTORY *relocdir;
707
708 /* Allocate PE section */
709 section_memsz = output_pe_reltab ( pe_reltab, NULL );
710 section_filesz = efi_file_align ( section_memsz );
711 reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
712 memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
713
714 /* Fill in section header details */
715 strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
716 sizeof ( reloc->hdr.Name ) );
717 reloc->hdr.Misc.VirtualSize = section_memsz;
718 reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
719 reloc->hdr.SizeOfRawData = section_filesz;
720 reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
721 EFI_IMAGE_SCN_MEM_NOT_PAGED |
722 EFI_IMAGE_SCN_MEM_READ );
723
724 /* Copy in section contents */
725 output_pe_reltab ( pe_reltab, reloc->contents );
726
727 /* Update file header details */
728 pe_header->nt.FileHeader.NumberOfSections++;
729 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
730 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
731 relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
732 [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
733 relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
734 relocdir->Size = reloc->hdr.Misc.VirtualSize;
735
736 return reloc;
737 }
738
739 /**
740 * Fix up debug section
741 *
742 * @v debug Debug section
743 */
fixup_debug_section(struct pe_section * debug)744 static void fixup_debug_section ( struct pe_section *debug ) {
745 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *contents;
746
747 /* Fix up FileOffset */
748 contents = ( ( void * ) debug->contents );
749 contents->FileOffset += ( debug->hdr.PointerToRawData -
750 debug->hdr.VirtualAddress );
751 }
752
753 /**
754 * Create debug section
755 *
756 * @v pe_header PE file header
757 * @ret section Debug section
758 */
759 static struct pe_section *
create_debug_section(struct pe_header * pe_header,const char * filename)760 create_debug_section ( struct pe_header *pe_header, const char *filename ) {
761 struct pe_section *debug;
762 size_t section_memsz;
763 size_t section_filesz;
764 EFI_IMAGE_DATA_DIRECTORY *debugdir;
765 struct {
766 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
767 EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
768 char name[ strlen ( filename ) + 1 ];
769 } *contents;
770
771 /* Allocate PE section */
772 section_memsz = sizeof ( *contents );
773 section_filesz = efi_file_align ( section_memsz );
774 debug = xmalloc ( sizeof ( *debug ) + section_filesz );
775 memset ( debug, 0, sizeof ( *debug ) + section_filesz );
776 contents = ( void * ) debug->contents;
777
778 /* Fill in section header details */
779 strncpy ( ( char * ) debug->hdr.Name, ".debug",
780 sizeof ( debug->hdr.Name ) );
781 debug->hdr.Misc.VirtualSize = section_memsz;
782 debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
783 debug->hdr.SizeOfRawData = section_filesz;
784 debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
785 EFI_IMAGE_SCN_MEM_NOT_PAGED |
786 EFI_IMAGE_SCN_MEM_READ );
787 debug->fixup = fixup_debug_section;
788
789 /* Create section contents */
790 contents->debug.TimeDateStamp = 0x10d1a884;
791 contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
792 contents->debug.SizeOfData =
793 ( sizeof ( *contents ) - sizeof ( contents->debug ) );
794 contents->debug.RVA = ( debug->hdr.VirtualAddress +
795 offsetof ( typeof ( *contents ), rsds ) );
796 contents->debug.FileOffset = contents->debug.RVA;
797 contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
798 snprintf ( contents->name, sizeof ( contents->name ), "%s",
799 filename );
800
801 /* Update file header details */
802 pe_header->nt.FileHeader.NumberOfSections++;
803 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
804 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
805 debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
806 [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
807 debugdir->VirtualAddress = debug->hdr.VirtualAddress;
808 debugdir->Size = sizeof ( contents->debug );
809
810 return debug;
811 }
812
813 /**
814 * Write out PE file
815 *
816 * @v pe_header PE file header
817 * @v pe_sections List of PE sections
818 * @v pe Output file
819 */
write_pe_file(struct pe_header * pe_header,struct pe_section * pe_sections,FILE * pe)820 static void write_pe_file ( struct pe_header *pe_header,
821 struct pe_section *pe_sections,
822 FILE *pe ) {
823 struct pe_section *section;
824 unsigned long fpos = 0;
825
826 /* Align length of headers */
827 fpos = pe_header->nt.OptionalHeader.SizeOfHeaders =
828 efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
829
830 /* Assign raw data pointers */
831 for ( section = pe_sections ; section ; section = section->next ) {
832 if ( section->hdr.SizeOfRawData ) {
833 section->hdr.PointerToRawData = fpos;
834 fpos += section->hdr.SizeOfRawData;
835 fpos = efi_file_align ( fpos );
836 }
837 if ( section->fixup )
838 section->fixup ( section );
839 }
840
841 /* Write file header */
842 if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
843 perror ( "Could not write PE header" );
844 exit ( 1 );
845 }
846
847 /* Write section headers */
848 for ( section = pe_sections ; section ; section = section->next ) {
849 if ( fwrite ( §ion->hdr, sizeof ( section->hdr ),
850 1, pe ) != 1 ) {
851 perror ( "Could not write section header" );
852 exit ( 1 );
853 }
854 }
855
856 /* Write sections */
857 for ( section = pe_sections ; section ; section = section->next ) {
858 if ( fseek ( pe, section->hdr.PointerToRawData,
859 SEEK_SET ) != 0 ) {
860 eprintf ( "Could not seek to %x: %s\n",
861 section->hdr.PointerToRawData,
862 strerror ( errno ) );
863 exit ( 1 );
864 }
865 if ( section->hdr.SizeOfRawData &&
866 ( fwrite ( section->contents, section->hdr.SizeOfRawData,
867 1, pe ) != 1 ) ) {
868 eprintf ( "Could not write section %.8s: %s\n",
869 section->hdr.Name, strerror ( errno ) );
870 exit ( 1 );
871 }
872 }
873 }
874
875 /**
876 * Convert ELF to PE
877 *
878 * @v elf_name ELF file name
879 * @v pe_name PE file name
880 */
elf2pe(const char * elf_name,const char * pe_name,struct options * opts)881 static void elf2pe ( const char *elf_name, const char *pe_name,
882 struct options *opts ) {
883 char pe_name_tmp[ strlen ( pe_name ) + 1 ];
884 struct pe_relocs *pe_reltab = NULL;
885 struct pe_section *pe_sections = NULL;
886 struct pe_section **next_pe_section = &pe_sections;
887 struct pe_header pe_header;
888 struct elf_file elf;
889 const Elf_Shdr *shdr;
890 size_t offset;
891 unsigned int i;
892 FILE *pe;
893
894 /* Create a modifiable copy of the PE name */
895 memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
896
897 /* Read ELF file */
898 read_elf_file ( elf_name, &elf );
899
900 /* Initialise the PE header */
901 memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
902 set_machine ( &elf, &pe_header );
903 pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
904 pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
905
906 /* Process input sections */
907 for ( i = 0 ; i < elf.ehdr->e_shnum ; i++ ) {
908 offset = ( elf.ehdr->e_shoff + ( i * elf.ehdr->e_shentsize ) );
909 shdr = ( elf.data + offset );
910
911 /* Process section */
912 if ( shdr->sh_flags & SHF_ALLOC ) {
913
914 /* Create output section */
915 *(next_pe_section) = process_section ( &elf, shdr,
916 &pe_header );
917 next_pe_section = &(*next_pe_section)->next;
918
919 } else if ( shdr->sh_type == SHT_REL ) {
920
921 /* Process .rel relocations */
922 process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
923 &pe_reltab );
924
925 } else if ( shdr->sh_type == SHT_RELA ) {
926
927 /* Process .rela relocations */
928 process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
929 &pe_reltab );
930 }
931 }
932
933 /* Create the .reloc section */
934 *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
935 next_pe_section = &(*next_pe_section)->next;
936
937 /* Create the .debug section */
938 *(next_pe_section) = create_debug_section ( &pe_header,
939 basename ( pe_name_tmp ) );
940 next_pe_section = &(*next_pe_section)->next;
941
942 /* Write out PE file */
943 pe = fopen ( pe_name, "w" );
944 if ( ! pe ) {
945 eprintf ( "Could not open %s for writing: %s\n",
946 pe_name, strerror ( errno ) );
947 exit ( 1 );
948 }
949 write_pe_file ( &pe_header, pe_sections, pe );
950 fclose ( pe );
951
952 /* Unmap ELF file */
953 munmap ( elf.data, elf.len );
954 }
955
956 /**
957 * Print help
958 *
959 * @v program_name Program name
960 */
print_help(const char * program_name)961 static void print_help ( const char *program_name ) {
962 eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
963 program_name );
964 }
965
966 /**
967 * Parse command-line options
968 *
969 * @v argc Argument count
970 * @v argv Argument list
971 * @v opts Options structure to populate
972 */
parse_options(const int argc,char ** argv,struct options * opts)973 static int parse_options ( const int argc, char **argv,
974 struct options *opts ) {
975 char *end;
976 int c;
977
978 while (1) {
979 int option_index = 0;
980 static struct option long_options[] = {
981 { "subsystem", required_argument, NULL, 's' },
982 { "help", 0, NULL, 'h' },
983 { 0, 0, 0, 0 }
984 };
985
986 if ( ( c = getopt_long ( argc, argv, "s:h",
987 long_options,
988 &option_index ) ) == -1 ) {
989 break;
990 }
991
992 switch ( c ) {
993 case 's':
994 opts->subsystem = strtoul ( optarg, &end, 0 );
995 if ( *end ) {
996 eprintf ( "Invalid subsytem \"%s\"\n",
997 optarg );
998 exit ( 2 );
999 }
1000 break;
1001 case 'h':
1002 print_help ( argv[0] );
1003 exit ( 0 );
1004 case '?':
1005 default:
1006 exit ( 2 );
1007 }
1008 }
1009 return optind;
1010 }
1011
main(int argc,char ** argv)1012 int main ( int argc, char **argv ) {
1013 struct options opts = {
1014 .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
1015 };
1016 int infile_index;
1017 const char *infile;
1018 const char *outfile;
1019
1020 /* Parse command-line arguments */
1021 infile_index = parse_options ( argc, argv, &opts );
1022 if ( argc != ( infile_index + 2 ) ) {
1023 print_help ( argv[0] );
1024 exit ( 2 );
1025 }
1026 infile = argv[infile_index];
1027 outfile = argv[infile_index + 1];
1028
1029 /* Convert file */
1030 elf2pe ( infile, outfile, &opts );
1031
1032 return 0;
1033 }
1034