Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

elf2efi.c 26KB

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