You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

elf2efi.c 27KB

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