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 name_len;
462 size_t section_memsz;
463 size_t section_filesz;
464 unsigned long code_start;
465 unsigned long code_end;
466 unsigned long data_start;
467 unsigned long data_mid;
468 unsigned long data_end;
469 unsigned long start;
470 unsigned long end;
471 unsigned long *applicable_start;
472 unsigned long *applicable_end;
473
474 /* Get section name */
475 name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name );
476
477 /* Extract current RVA limits from file header */
478 code_start = pe_header->nt.OptionalHeader.BaseOfCode;
479 code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
480 #if defined(EFI_TARGET32)
481 data_start = pe_header->nt.OptionalHeader.BaseOfData;
482 #elif defined(EFI_TARGET64)
483 data_start = code_end;
484 #endif
485 data_mid = ( data_start +
486 pe_header->nt.OptionalHeader.SizeOfInitializedData );
487 data_end = ( data_mid +
488 pe_header->nt.OptionalHeader.SizeOfUninitializedData );
489
490 /* Allocate PE section */
491 section_memsz = shdr->sh_size;
492 section_filesz = ( ( shdr->sh_type == SHT_PROGBITS ) ?
493 efi_file_align ( section_memsz ) : 0 );
494 new = xmalloc ( sizeof ( *new ) + section_filesz );
495 memset ( new, 0, sizeof ( *new ) + section_filesz );
496
497 /* Fill in section header details */
498 name_len = strlen ( name );
499 if ( name_len > sizeof ( new->hdr.Name ) )
500 name_len = sizeof ( new->hdr.Name );
501 memcpy ( new->hdr.Name, name, name_len );
502 new->hdr.Misc.VirtualSize = section_memsz;
503 new->hdr.VirtualAddress = shdr->sh_addr;
504 new->hdr.SizeOfRawData = section_filesz;
505
506 /* Fill in section characteristics and update RVA limits */
507 if ( ( shdr->sh_type == SHT_PROGBITS ) &&
508 ( shdr->sh_flags & SHF_EXECINSTR ) ) {
509 /* .text-type section */
510 new->hdr.Characteristics =
511 ( EFI_IMAGE_SCN_CNT_CODE |
512 EFI_IMAGE_SCN_MEM_NOT_PAGED |
513 EFI_IMAGE_SCN_MEM_EXECUTE |
514 EFI_IMAGE_SCN_MEM_READ );
515 applicable_start = &code_start;
516 applicable_end = &code_end;
517 } else if ( ( shdr->sh_type == SHT_PROGBITS ) &&
518 ( shdr->sh_flags & SHF_WRITE ) ) {
519 /* .data-type section */
520 new->hdr.Characteristics =
521 ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
522 EFI_IMAGE_SCN_MEM_NOT_PAGED |
523 EFI_IMAGE_SCN_MEM_READ |
524 EFI_IMAGE_SCN_MEM_WRITE );
525 applicable_start = &data_start;
526 applicable_end = &data_mid;
527 } else if ( shdr->sh_type == SHT_PROGBITS ) {
528 /* .rodata-type section */
529 new->hdr.Characteristics =
530 ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
531 EFI_IMAGE_SCN_MEM_NOT_PAGED |
532 EFI_IMAGE_SCN_MEM_READ );
533 applicable_start = &data_start;
534 applicable_end = &data_mid;
535 } else if ( shdr->sh_type == SHT_NOBITS ) {
536 /* .bss-type section */
537 new->hdr.Characteristics =
538 ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
539 EFI_IMAGE_SCN_MEM_NOT_PAGED |
540 EFI_IMAGE_SCN_MEM_READ |
541 EFI_IMAGE_SCN_MEM_WRITE );
542 applicable_start = &data_mid;
543 applicable_end = &data_end;
544 } else {
545 eprintf ( "Unrecognised characteristics for section %s\n",
546 name );
547 exit ( 1 );
548 }
549
550 /* Copy in section contents */
551 if ( shdr->sh_type == SHT_PROGBITS ) {
552 memcpy ( new->contents, ( elf->data + shdr->sh_offset ),
553 shdr->sh_size );
554 }
555
556 /* Update RVA limits */
557 start = new->hdr.VirtualAddress;
558 end = ( start + new->hdr.Misc.VirtualSize );
559 if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
560 *applicable_start = start;
561 if ( *applicable_end < end )
562 *applicable_end = end;
563 if ( data_start < code_end )
564 data_start = code_end;
565 if ( data_mid < data_start )
566 data_mid = data_start;
567 if ( data_end < data_mid )
568 data_end = data_mid;
569
570 /* Write RVA limits back to file header */
571 pe_header->nt.OptionalHeader.BaseOfCode = code_start;
572 pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
573 #if defined(EFI_TARGET32)
574 pe_header->nt.OptionalHeader.BaseOfData = data_start;
575 #endif
576 pe_header->nt.OptionalHeader.SizeOfInitializedData =
577 ( data_mid - data_start );
578 pe_header->nt.OptionalHeader.SizeOfUninitializedData =
579 ( data_end - data_mid );
580
581 /* Update remaining file header fields */
582 pe_header->nt.FileHeader.NumberOfSections++;
583 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
584 pe_header->nt.OptionalHeader.SizeOfImage =
585 efi_file_align ( data_end );
586
587 return new;
588 }
589
590 /**
591 * Process relocation record
592 *
593 * @v elf ELF file
594 * @v shdr ELF section header
595 * @v syms Symbol table
596 * @v nsyms Number of symbol table entries
597 * @v rel Relocation record
598 * @v pe_reltab PE relocation table to fill in
599 */
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)600 static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
601 const Elf_Sym *syms, unsigned int nsyms,
602 const Elf_Rel *rel, struct pe_relocs **pe_reltab ) {
603 unsigned int type = ELF_R_TYPE ( rel->r_info );
604 unsigned int sym = ELF_R_SYM ( rel->r_info );
605 unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type );
606 size_t offset = ( shdr->sh_addr + rel->r_offset );
607
608 /* Look up symbol and process relocation */
609 if ( sym >= nsyms ) {
610 eprintf ( "Symbol out of range\n" );
611 exit ( 1 );
612 }
613 if ( syms[sym].st_shndx == SHN_ABS ) {
614 /* Skip absolute symbols; the symbol value won't
615 * change when the object is loaded.
616 */
617 } else {
618 switch ( mrel ) {
619 case ELF_MREL ( EM_386, R_386_NONE ) :
620 case ELF_MREL ( EM_ARM, R_ARM_NONE ) :
621 case ELF_MREL ( EM_X86_64, R_X86_64_NONE ) :
622 case ELF_MREL ( EM_AARCH64, R_AARCH64_NONE ) :
623 case ELF_MREL ( EM_AARCH64, R_AARCH64_NULL ) :
624 /* Ignore dummy relocations used by REQUIRE_SYMBOL() */
625 break;
626 case ELF_MREL ( EM_386, R_386_32 ) :
627 case ELF_MREL ( EM_ARM, R_ARM_ABS32 ) :
628 /* Generate a 4-byte PE relocation */
629 generate_pe_reloc ( pe_reltab, offset, 4 );
630 break;
631 case ELF_MREL ( EM_X86_64, R_X86_64_64 ) :
632 case ELF_MREL ( EM_AARCH64, R_AARCH64_ABS64 ) :
633 /* Generate an 8-byte PE relocation */
634 generate_pe_reloc ( pe_reltab, offset, 8 );
635 break;
636 case ELF_MREL ( EM_386, R_386_PC32 ) :
637 case ELF_MREL ( EM_ARM, R_ARM_CALL ) :
638 case ELF_MREL ( EM_ARM, R_ARM_REL32 ) :
639 case ELF_MREL ( EM_ARM, R_ARM_THM_PC22 ) :
640 case ELF_MREL ( EM_ARM, R_ARM_THM_JUMP24 ) :
641 case ELF_MREL ( EM_ARM, R_ARM_V4BX ):
642 case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) :
643 case ELF_MREL ( EM_X86_64, R_X86_64_PLT32 ) :
644 case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) :
645 case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) :
646 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) :
647 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_PG_HI21 ) :
648 case ELF_MREL ( EM_AARCH64, R_AARCH64_ADD_ABS_LO12_NC ) :
649 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST8_ABS_LO12_NC ) :
650 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST16_ABS_LO12_NC ) :
651 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) :
652 case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) :
653 /* Skip PC-relative relocations; all relative
654 * offsets remain unaltered when the object is
655 * loaded.
656 */
657 break;
658 default:
659 eprintf ( "Unrecognised relocation type %d\n", type );
660 exit ( 1 );
661 }
662 }
663 }
664
665 /**
666 * Process relocation records
667 *
668 * @v elf ELF file
669 * @v shdr ELF section header
670 * @v stride Relocation record size
671 * @v pe_reltab PE relocation table to fill in
672 */
process_relocs(struct elf_file * elf,const Elf_Shdr * shdr,size_t stride,struct pe_relocs ** pe_reltab)673 static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
674 size_t stride, struct pe_relocs **pe_reltab ) {
675 const Elf_Shdr *symtab;
676 const Elf_Sym *syms;
677 const Elf_Rel *rel;
678 unsigned int nsyms;
679 unsigned int nrels;
680 unsigned int i;
681
682 /* Identify symbol table */
683 symtab = ( elf->data + elf->ehdr->e_shoff +
684 ( shdr->sh_link * elf->ehdr->e_shentsize ) );
685 syms = ( elf->data + symtab->sh_offset );
686 nsyms = ( symtab->sh_size / sizeof ( syms[0] ) );
687
688 /* Process each relocation */
689 rel = ( elf->data + shdr->sh_offset );
690 nrels = ( shdr->sh_size / stride );
691 for ( i = 0 ; i < nrels ; i++ ) {
692 process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab );
693 rel = ( ( ( const void * ) rel ) + stride );
694 }
695 }
696
697 /**
698 * Create relocations section
699 *
700 * @v pe_header PE file header
701 * @v pe_reltab PE relocation table
702 * @ret section Relocation section
703 */
704 static struct pe_section *
create_reloc_section(struct pe_header * pe_header,struct pe_relocs * pe_reltab)705 create_reloc_section ( struct pe_header *pe_header,
706 struct pe_relocs *pe_reltab ) {
707 struct pe_section *reloc;
708 size_t section_memsz;
709 size_t section_filesz;
710 EFI_IMAGE_DATA_DIRECTORY *relocdir;
711
712 /* Allocate PE section */
713 section_memsz = output_pe_reltab ( pe_reltab, NULL );
714 section_filesz = efi_file_align ( section_memsz );
715 reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
716 memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
717
718 /* Fill in section header details */
719 strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
720 sizeof ( reloc->hdr.Name ) );
721 reloc->hdr.Misc.VirtualSize = section_memsz;
722 reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
723 reloc->hdr.SizeOfRawData = section_filesz;
724 reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
725 EFI_IMAGE_SCN_MEM_NOT_PAGED |
726 EFI_IMAGE_SCN_MEM_READ );
727
728 /* Copy in section contents */
729 output_pe_reltab ( pe_reltab, reloc->contents );
730
731 /* Update file header details */
732 pe_header->nt.FileHeader.NumberOfSections++;
733 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
734 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
735 relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
736 [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
737 relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
738 relocdir->Size = reloc->hdr.Misc.VirtualSize;
739
740 return reloc;
741 }
742
743 /**
744 * Fix up debug section
745 *
746 * @v debug Debug section
747 */
fixup_debug_section(struct pe_section * debug)748 static void fixup_debug_section ( struct pe_section *debug ) {
749 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *contents;
750
751 /* Fix up FileOffset */
752 contents = ( ( void * ) debug->contents );
753 contents->FileOffset += ( debug->hdr.PointerToRawData -
754 debug->hdr.VirtualAddress );
755 }
756
757 /**
758 * Create debug section
759 *
760 * @v pe_header PE file header
761 * @ret section Debug section
762 */
763 static struct pe_section *
create_debug_section(struct pe_header * pe_header,const char * filename)764 create_debug_section ( struct pe_header *pe_header, const char *filename ) {
765 struct pe_section *debug;
766 size_t section_memsz;
767 size_t section_filesz;
768 EFI_IMAGE_DATA_DIRECTORY *debugdir;
769 struct {
770 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
771 EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
772 char name[ strlen ( filename ) + 1 ];
773 } *contents;
774
775 /* Allocate PE section */
776 section_memsz = sizeof ( *contents );
777 section_filesz = efi_file_align ( section_memsz );
778 debug = xmalloc ( sizeof ( *debug ) + section_filesz );
779 memset ( debug, 0, sizeof ( *debug ) + section_filesz );
780 contents = ( void * ) debug->contents;
781
782 /* Fill in section header details */
783 strncpy ( ( char * ) debug->hdr.Name, ".debug",
784 sizeof ( debug->hdr.Name ) );
785 debug->hdr.Misc.VirtualSize = section_memsz;
786 debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
787 debug->hdr.SizeOfRawData = section_filesz;
788 debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
789 EFI_IMAGE_SCN_MEM_NOT_PAGED |
790 EFI_IMAGE_SCN_MEM_READ );
791 debug->fixup = fixup_debug_section;
792
793 /* Create section contents */
794 contents->debug.TimeDateStamp = 0x10d1a884;
795 contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
796 contents->debug.SizeOfData =
797 ( sizeof ( *contents ) - sizeof ( contents->debug ) );
798 contents->debug.RVA = ( debug->hdr.VirtualAddress +
799 offsetof ( typeof ( *contents ), rsds ) );
800 contents->debug.FileOffset = contents->debug.RVA;
801 contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
802 snprintf ( contents->name, sizeof ( contents->name ), "%s",
803 filename );
804
805 /* Update file header details */
806 pe_header->nt.FileHeader.NumberOfSections++;
807 pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
808 pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
809 debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
810 [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
811 debugdir->VirtualAddress = debug->hdr.VirtualAddress;
812 debugdir->Size = sizeof ( contents->debug );
813
814 return debug;
815 }
816
817 /**
818 * Write out PE file
819 *
820 * @v pe_header PE file header
821 * @v pe_sections List of PE sections
822 * @v pe Output file
823 */
write_pe_file(struct pe_header * pe_header,struct pe_section * pe_sections,FILE * pe)824 static void write_pe_file ( struct pe_header *pe_header,
825 struct pe_section *pe_sections,
826 FILE *pe ) {
827 struct pe_section *section;
828 unsigned long fpos = 0;
829
830 /* Align length of headers */
831 fpos = pe_header->nt.OptionalHeader.SizeOfHeaders =
832 efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
833
834 /* Assign raw data pointers */
835 for ( section = pe_sections ; section ; section = section->next ) {
836 if ( section->hdr.SizeOfRawData ) {
837 section->hdr.PointerToRawData = fpos;
838 fpos += section->hdr.SizeOfRawData;
839 fpos = efi_file_align ( fpos );
840 }
841 if ( section->fixup )
842 section->fixup ( section );
843 }
844
845 /* Write file header */
846 if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
847 perror ( "Could not write PE header" );
848 exit ( 1 );
849 }
850
851 /* Write section headers */
852 for ( section = pe_sections ; section ; section = section->next ) {
853 if ( fwrite ( §ion->hdr, sizeof ( section->hdr ),
854 1, pe ) != 1 ) {
855 perror ( "Could not write section header" );
856 exit ( 1 );
857 }
858 }
859
860 /* Write sections */
861 for ( section = pe_sections ; section ; section = section->next ) {
862 if ( fseek ( pe, section->hdr.PointerToRawData,
863 SEEK_SET ) != 0 ) {
864 eprintf ( "Could not seek to %x: %s\n",
865 section->hdr.PointerToRawData,
866 strerror ( errno ) );
867 exit ( 1 );
868 }
869 if ( section->hdr.SizeOfRawData &&
870 ( fwrite ( section->contents, section->hdr.SizeOfRawData,
871 1, pe ) != 1 ) ) {
872 eprintf ( "Could not write section %.8s: %s\n",
873 section->hdr.Name, strerror ( errno ) );
874 exit ( 1 );
875 }
876 }
877 }
878
879 /**
880 * Convert ELF to PE
881 *
882 * @v elf_name ELF file name
883 * @v pe_name PE file name
884 */
elf2pe(const char * elf_name,const char * pe_name,struct options * opts)885 static void elf2pe ( const char *elf_name, const char *pe_name,
886 struct options *opts ) {
887 char pe_name_tmp[ strlen ( pe_name ) + 1 ];
888 struct pe_relocs *pe_reltab = NULL;
889 struct pe_section *pe_sections = NULL;
890 struct pe_section **next_pe_section = &pe_sections;
891 struct pe_header pe_header;
892 struct elf_file elf;
893 const Elf_Shdr *shdr;
894 size_t offset;
895 unsigned int i;
896 FILE *pe;
897
898 /* Create a modifiable copy of the PE name */
899 memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
900
901 /* Read ELF file */
902 read_elf_file ( elf_name, &elf );
903
904 /* Initialise the PE header */
905 memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
906 set_machine ( &elf, &pe_header );
907 pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
908 pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
909
910 /* Process input sections */
911 for ( i = 0 ; i < elf.ehdr->e_shnum ; i++ ) {
912 offset = ( elf.ehdr->e_shoff + ( i * elf.ehdr->e_shentsize ) );
913 shdr = ( elf.data + offset );
914
915 /* Process section */
916 if ( shdr->sh_flags & SHF_ALLOC ) {
917
918 /* Create output section */
919 *(next_pe_section) = process_section ( &elf, shdr,
920 &pe_header );
921 next_pe_section = &(*next_pe_section)->next;
922
923 } else if ( shdr->sh_type == SHT_REL ) {
924
925 /* Process .rel relocations */
926 process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
927 &pe_reltab );
928
929 } else if ( shdr->sh_type == SHT_RELA ) {
930
931 /* Process .rela relocations */
932 process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
933 &pe_reltab );
934 }
935 }
936
937 /* Create the .reloc section */
938 *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
939 next_pe_section = &(*next_pe_section)->next;
940
941 /* Create the .debug section */
942 *(next_pe_section) = create_debug_section ( &pe_header,
943 basename ( pe_name_tmp ) );
944 next_pe_section = &(*next_pe_section)->next;
945
946 /* Write out PE file */
947 pe = fopen ( pe_name, "w" );
948 if ( ! pe ) {
949 eprintf ( "Could not open %s for writing: %s\n",
950 pe_name, strerror ( errno ) );
951 exit ( 1 );
952 }
953 write_pe_file ( &pe_header, pe_sections, pe );
954 fclose ( pe );
955
956 /* Unmap ELF file */
957 munmap ( elf.data, elf.len );
958 }
959
960 /**
961 * Print help
962 *
963 * @v program_name Program name
964 */
print_help(const char * program_name)965 static void print_help ( const char *program_name ) {
966 eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
967 program_name );
968 }
969
970 /**
971 * Parse command-line options
972 *
973 * @v argc Argument count
974 * @v argv Argument list
975 * @v opts Options structure to populate
976 */
parse_options(const int argc,char ** argv,struct options * opts)977 static int parse_options ( const int argc, char **argv,
978 struct options *opts ) {
979 char *end;
980 int c;
981
982 while (1) {
983 int option_index = 0;
984 static struct option long_options[] = {
985 { "subsystem", required_argument, NULL, 's' },
986 { "help", 0, NULL, 'h' },
987 { 0, 0, 0, 0 }
988 };
989
990 if ( ( c = getopt_long ( argc, argv, "s:h",
991 long_options,
992 &option_index ) ) == -1 ) {
993 break;
994 }
995
996 switch ( c ) {
997 case 's':
998 opts->subsystem = strtoul ( optarg, &end, 0 );
999 if ( *end || ( ! *optarg ) ) {
1000 eprintf ( "Invalid subsytem \"%s\"\n",
1001 optarg );
1002 exit ( 2 );
1003 }
1004 break;
1005 case 'h':
1006 print_help ( argv[0] );
1007 exit ( 0 );
1008 case '?':
1009 default:
1010 exit ( 2 );
1011 }
1012 }
1013 return optind;
1014 }
1015
main(int argc,char ** argv)1016 int main ( int argc, char **argv ) {
1017 struct options opts = {
1018 .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
1019 };
1020 int infile_index;
1021 const char *infile;
1022 const char *outfile;
1023
1024 /* Parse command-line arguments */
1025 infile_index = parse_options ( argc, argv, &opts );
1026 if ( argc != ( infile_index + 2 ) ) {
1027 print_help ( argv[0] );
1028 exit ( 2 );
1029 }
1030 infile = argv[infile_index];
1031 outfile = argv[infile_index + 1];
1032
1033 /* Convert file */
1034 elf2pe ( infile, outfile, &opts );
1035
1036 return 0;
1037 }
1038