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