elfconv.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. elfconv.c
  5. Abstract:
  6. This module implements a UEFI build utility that converts an ELF image
  7. into a PE image.
  8. Author:
  9. Evan Green 7-Mar-2014
  10. Environment:
  11. Build
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <getopt.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/stat.h>
  23. #include <unistd.h>
  24. #include "uefifw.h"
  25. #include "elfconv.h"
  26. //
  27. // ---------------------------------------------------------------- Definitions
  28. //
  29. #define ELFCONV_VERSION_MAJOR 1
  30. #define ELFCONV_VERSION_MINOR 0
  31. #define ELFCONV_USAGE \
  32. "Usage: ElfConv [options] [files...]\n" \
  33. "The ElfConv utility takes an ELF file as input and produces a PE image.\n"\
  34. "Dynamic linking is not supported. Valid options are:\n" \
  35. " -o, --output=File -- Specify the output image name. The default is \n" \
  36. " the name of the input image followed by .efi\n" \
  37. " -t, --type=type -- Specify the EFI subsystem type. Valid values are \n" \
  38. " efiapp, efibootdriver, efiruntimedriver, efidriver, or a \n" \
  39. " numeric value.\n" \
  40. " -v, --verbose -- Print extra information.\n" \
  41. " --help -- Print this help and exit.\n" \
  42. " --version -- Print version information and exit.\n" \
  43. #define ELFCONV_OPTIONS_STRING "o:t:v"
  44. #define ELFCONV_RELOCATION_EXPANSION_SIZE (2 * 0x1000)
  45. //
  46. // ------------------------------------------------------ Data Type Definitions
  47. //
  48. //
  49. // ----------------------------------------------- Internal Function Prototypes
  50. //
  51. int
  52. ElfconvLoadFile (
  53. PELFCONV_CONTEXT Context
  54. );
  55. BOOLEAN
  56. ElfconvIsElfHeader (
  57. VOID *File,
  58. UINTN FileSize
  59. );
  60. //
  61. // -------------------------------------------------------------------- Globals
  62. //
  63. struct option ElfconvLongOptions[] = {
  64. {"output", required_argument, 0, 'o'},
  65. {"type", required_argument, 0, 't'},
  66. {"verbose", no_argument, 0, 'v'},
  67. {"help", no_argument, 0, 'h'},
  68. {"version", no_argument, 0, 'V'},
  69. {NULL, 0, 0, 0},
  70. };
  71. CHAR8 *ElfconvDebugSections[] = {
  72. ".stab",
  73. ".stabstr",
  74. ".debug_aranges",
  75. ".debug_info",
  76. ".debug_abbrev",
  77. ".debug_frame",
  78. ".debug_line",
  79. ".debug_str",
  80. ".debug_loc",
  81. ".debug_ranges",
  82. ".debug_macinfo",
  83. ".debug_pubtypes",
  84. ".eh_frame",
  85. NULL
  86. };
  87. //
  88. // ------------------------------------------------------------------ Functions
  89. //
  90. int
  91. main (
  92. int ArgumentCount,
  93. CHAR8 **Arguments
  94. )
  95. /*++
  96. Routine Description:
  97. This routine is the main entry point into the ElfConv utility, which
  98. converts and ELF binary into an EFI PE binary.
  99. Arguments:
  100. ArgumentCount - Supplies the number of command line parameters.
  101. Arguments - Supplies the array of pointers to parameter strings.
  102. Return Value:
  103. 0 on success.
  104. Non-zero on failure.
  105. --*/
  106. {
  107. CHAR8 *AfterScan;
  108. int ArgumentIndex;
  109. ssize_t BytesWritten;
  110. ELFCONV_CONTEXT Context;
  111. CHAR8 *DefaultOutputName;
  112. UINT8 ElfClass;
  113. ELFCONV_FUNCTION_TABLE FunctionTable;
  114. size_t InputNameLength;
  115. int Option;
  116. FILE *Output;
  117. BOOLEAN Result;
  118. int Status;
  119. memset(&Context, 0, sizeof(ELFCONV_CONTEXT));
  120. Context.SubsystemType = -1;
  121. memset(&FunctionTable, 0, sizeof(ELFCONV_FUNCTION_TABLE));
  122. DefaultOutputName = NULL;
  123. Output = NULL;
  124. //
  125. // Process the control arguments.
  126. //
  127. while (TRUE) {
  128. Option = getopt_long(ArgumentCount,
  129. Arguments,
  130. ELFCONV_OPTIONS_STRING,
  131. ElfconvLongOptions,
  132. NULL);
  133. if (Option == -1) {
  134. break;
  135. }
  136. if ((Option == '?') || (Option == ':')) {
  137. Status = 1;
  138. goto mainEnd;
  139. }
  140. switch (Option) {
  141. case 't':
  142. if (strcasecmp(optarg, "efiapp") == 0) {
  143. Context.SubsystemType = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
  144. } else if (strcasecmp(optarg, "efibootdriver") == 0) {
  145. Context.SubsystemType =
  146. EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
  147. } else if (strcasecmp(optarg, "efiruntimedriver") == 0) {
  148. Context.SubsystemType = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
  149. } else if (strcasecmp(optarg, "saldriver") == 0) {
  150. Context.SubsystemType = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
  151. } else {
  152. Context.SubsystemType = strtoul(optarg, &AfterScan, 0);
  153. if (AfterScan == optarg) {
  154. fprintf(stderr,
  155. "Error: Invalid PE subsystem type: %s.\n",
  156. optarg);
  157. Status = EINVAL;
  158. goto mainEnd;
  159. }
  160. }
  161. break;
  162. case 'o':
  163. Context.OutputName = optarg;
  164. break;
  165. case 'v':
  166. Context.Flags |= ELFCONV_OPTION_VERBOSE;
  167. break;
  168. case 'V':
  169. printf("ElfConv version %d.%d\n",
  170. ELFCONV_VERSION_MAJOR,
  171. ELFCONV_VERSION_MINOR);
  172. return 1;
  173. case 'h':
  174. printf(ELFCONV_USAGE);
  175. return 1;
  176. default:
  177. assert(FALSE);
  178. Status = 1;
  179. goto mainEnd;
  180. }
  181. }
  182. ArgumentIndex = optind;
  183. if (ArgumentIndex != ArgumentCount - 1) {
  184. fprintf(stderr, "ElfConv takes exactly one (non-option) argument.\n");
  185. Status = EINVAL;
  186. goto mainEnd;
  187. }
  188. Context.InputName = Arguments[ArgumentIndex];
  189. if (Context.OutputName == NULL) {
  190. InputNameLength = strlen(Context.InputName);
  191. DefaultOutputName = malloc(InputNameLength + sizeof(".efi"));
  192. if (DefaultOutputName == NULL) {
  193. Status = ENOMEM;
  194. goto mainEnd;
  195. }
  196. strcpy(DefaultOutputName, Context.InputName);
  197. strcpy(DefaultOutputName + InputNameLength, ".efi");
  198. Context.OutputName = DefaultOutputName;
  199. }
  200. if (Context.SubsystemType == -1) {
  201. fprintf(stderr, "Error: -t is a required argument.\n");
  202. Status = EINVAL;
  203. goto mainEnd;
  204. }
  205. Status = ElfconvLoadFile(&Context);
  206. if (Status != 0) {
  207. goto mainEnd;
  208. }
  209. if (ElfconvIsElfHeader(Context.InputFile, Context.InputFileSize) == FALSE) {
  210. fprintf(stderr,
  211. "Error: %s does not appear to be and ELF image.\n",
  212. Context.InputName);
  213. Status = EINVAL;
  214. goto mainEnd;
  215. }
  216. ElfClass = ((UINT8 *)(Context.InputFile))[EI_CLASS];
  217. if (ElfClass == ELFCLASS32) {
  218. if (ElfconvInitializeElf32(&Context, &FunctionTable) == FALSE) {
  219. Status = EINVAL;
  220. goto mainEnd;
  221. }
  222. } else {
  223. fprintf(stderr, "Error: Unrecogized ei_class %d.\n", ElfClass);
  224. Status = EINVAL;
  225. goto mainEnd;
  226. }
  227. Status = EINVAL;
  228. //
  229. // Perform an initial pass and set up the destination image.
  230. //
  231. Result = FunctionTable.ScanSections(&Context);
  232. if (Result == FALSE) {
  233. fprintf(stderr, "Error: Failed to scan sections.\n");
  234. goto mainEnd;
  235. }
  236. //
  237. // Write and relocate individual section types.
  238. //
  239. Result = FunctionTable.WriteSections(&Context, ElfconvSectionText);
  240. if (Result == FALSE) {
  241. fprintf(stderr, "Error: Failed to write text section.\n");
  242. goto mainEnd;
  243. }
  244. Result = FunctionTable.WriteSections(&Context, ElfconvSectionData);
  245. if (Result == FALSE) {
  246. fprintf(stderr, "Error: Failed to write data section.\n");
  247. goto mainEnd;
  248. }
  249. Result = FunctionTable.WriteSections(&Context, ElfconvSectionHii);
  250. if (Result == FALSE) {
  251. fprintf(stderr, "Error: Failed to write HII section.\n");
  252. goto mainEnd;
  253. }
  254. //
  255. // Translate and write the relocation information.
  256. //
  257. Result = FunctionTable.WriteRelocations(&Context);
  258. if (Result == FALSE) {
  259. fprintf(stderr, "Error: Failed to translate and write relocations.\n");
  260. goto mainEnd;
  261. }
  262. //
  263. // Write out the debug information.
  264. //
  265. Result = FunctionTable.WriteDebug(&Context);
  266. if (Result == FALSE) {
  267. fprintf(stderr, "Error: Failed to write debug data.\n");
  268. goto mainEnd;
  269. }
  270. FunctionTable.SetImageSize(&Context);
  271. //
  272. // Write out the new file buffer.
  273. //
  274. assert(Context.OutputName != NULL);
  275. Output = fopen(Context.OutputName, "wb");
  276. if (Output == NULL) {
  277. Status = errno;
  278. fprintf(stderr,
  279. "Error: Failed to open output %s: %s.\n",
  280. Context.OutputName,
  281. strerror(Status));
  282. goto mainEnd;
  283. }
  284. assert((Context.CoffFile != NULL) &&
  285. (Context.CoffOffset != 0));
  286. BytesWritten = fwrite(Context.CoffFile, 1, Context.CoffOffset, Output);
  287. if ((BytesWritten != Context.CoffOffset) || (ferror(Output) != 0)) {
  288. Status = errno;
  289. if (Status == 0) {
  290. errno = EIO;
  291. }
  292. fprintf(stderr,
  293. "Error: Failed to write %s: %s.\n",
  294. Context.OutputName,
  295. strerror(Status));
  296. goto mainEnd;
  297. }
  298. Status = 0;
  299. mainEnd:
  300. if (Output != NULL) {
  301. fclose(Output);
  302. }
  303. if (FunctionTable.CleanUp != NULL) {
  304. FunctionTable.CleanUp(&Context);
  305. }
  306. if (DefaultOutputName != NULL) {
  307. free(DefaultOutputName);
  308. }
  309. if (Context.InputFile != NULL) {
  310. free(Context.InputFile);
  311. }
  312. if (Context.CoffFile != NULL) {
  313. free(Context.CoffFile);
  314. }
  315. if (Context.StringTable != NULL) {
  316. free(Context.StringTable);
  317. }
  318. if ((Context.Flags & ELFCONV_OPTION_VERBOSE) != 0) {
  319. printf("ElfConv %s returning %d: %s.\n",
  320. Context.InputName,
  321. Status,
  322. strerror(Status));
  323. }
  324. return Status;
  325. }
  326. VOID
  327. ElfconvSetHiiResourceHeader (
  328. UINT8 *HiiBinData,
  329. UINT32 OffsetToFile
  330. )
  331. /*++
  332. Routine Description:
  333. This routine sets up the HII resource data in the destination image.
  334. Arguments:
  335. HiiBinData - Supplies a pointer to the raw resource data.
  336. OffsetToFile - Supplies the offset within the file where the data is going
  337. to reside.
  338. Return Value:
  339. None.
  340. --*/
  341. {
  342. UINT32 Index;
  343. VOID *NextEntry;
  344. UINT32 Offset;
  345. EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
  346. EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
  347. EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
  348. EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
  349. //
  350. // Fill in the resource section entry.
  351. //
  352. ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)HiiBinData;
  353. ResourceDirectoryEntry =
  354. (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
  355. for (Index = 0;
  356. Index < ResourceDirectory->NumberOfNamedEntries;
  357. Index += 1) {
  358. if (ResourceDirectoryEntry->u1.s.NameIsString != 0) {
  359. Offset = ResourceDirectoryEntry->u1.s.NameOffset;
  360. ResourceDirectoryString =
  361. (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(HiiBinData + Offset);
  362. if ((ResourceDirectoryString->Length == 3) &&
  363. (ResourceDirectoryString->String[0] == L'H') &&
  364. (ResourceDirectoryString->String[1] == L'I') &&
  365. (ResourceDirectoryString->String[2] == L'I')) {
  366. //
  367. // Resource Type "HII" was found.
  368. //
  369. if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
  370. //
  371. // Move to next level - resource Name.
  372. //
  373. Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory;
  374. ResourceDirectory =
  375. (EFI_IMAGE_RESOURCE_DIRECTORY *)(HiiBinData + Offset);
  376. NextEntry = ResourceDirectory + 1;
  377. ResourceDirectoryEntry = NextEntry;
  378. if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
  379. //
  380. // Move to next level - resource Language.
  381. //
  382. Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory;
  383. ResourceDirectory =
  384. (EFI_IMAGE_RESOURCE_DIRECTORY *)(HiiBinData +
  385. Offset);
  386. NextEntry = ResourceDirectory + 1;
  387. ResourceDirectoryEntry = NextEntry;
  388. }
  389. }
  390. //
  391. // Now it ought to be resource Data. Update its "offset to
  392. // data" value.
  393. //
  394. if (ResourceDirectoryEntry->u2.s.DataIsDirectory != 0) {
  395. Offset = ResourceDirectoryEntry->u2.OffsetToData;
  396. ResourceDataEntry =
  397. (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(HiiBinData + Offset);
  398. ResourceDataEntry->OffsetToData =
  399. ResourceDataEntry->OffsetToData + OffsetToFile;
  400. break;
  401. }
  402. }
  403. }
  404. ResourceDirectoryEntry += 1;
  405. }
  406. return;
  407. }
  408. VOID
  409. ElfconvCreateSectionHeader (
  410. PELFCONV_CONTEXT Context,
  411. CHAR8 *Name,
  412. UINT32 Offset,
  413. UINT32 Size,
  414. UINT32 Flags
  415. )
  416. /*++
  417. Routine Description:
  418. This routine initializes a PE section header in the output file buffer.
  419. Arguments:
  420. Context - Supplies a pointer to the conversion context.
  421. Name - Supplies a pointer to a string containing the name of the section.
  422. Offset - Supplies the file offset to the start of the section.
  423. Size - Supplies the size of the section in bytes.
  424. Flags - Supplies the section flags.
  425. Return Value:
  426. None.
  427. --*/
  428. {
  429. EFI_IMAGE_SECTION_HEADER *Header;
  430. UINT32 Length;
  431. UINT32 NewSize;
  432. CHAR8 *NewTable;
  433. Header =
  434. (EFI_IMAGE_SECTION_HEADER *)(Context->CoffFile + Context->TableOffset);
  435. Length = strlen(Name) + 1;
  436. if (Length > EFI_IMAGE_SIZEOF_SHORT_NAME) {
  437. //
  438. // Create a string table entry for it. The first 4 bytes of the string
  439. // table are its size.
  440. //
  441. NewSize = Context->StringTableSize + Length;
  442. if (Context->StringTableSize == 0) {
  443. NewSize += sizeof(UINT32);
  444. Context->StringTableSize = sizeof(UINT32);
  445. }
  446. NewTable = realloc(Context->StringTable, NewSize);
  447. if (NewTable == NULL) {
  448. assert(FALSE);
  449. return;
  450. }
  451. memcpy(NewTable + Context->StringTableSize, Name, Length);
  452. Context->StringTable = NewTable;
  453. snprintf((INT8 *)(Header->Name),
  454. EFI_IMAGE_SIZEOF_SHORT_NAME,
  455. "/%d",
  456. Context->StringTableSize);
  457. Context->StringTableSize += Length;
  458. } else {
  459. strncpy((INT8 *)(Header->Name), Name, EFI_IMAGE_SIZEOF_SHORT_NAME);
  460. }
  461. Header->Misc.VirtualSize = Size;
  462. Header->VirtualAddress = Offset;
  463. Header->SizeOfRawData = Size;
  464. Header->PointerToRawData = Offset;
  465. Header->PointerToRelocations = 0;
  466. Header->PointerToLinenumbers = 0;
  467. Header->NumberOfRelocations = 0;
  468. Header->NumberOfLinenumbers = 0;
  469. Header->Characteristics = Flags;
  470. Context->TableOffset += sizeof(EFI_IMAGE_SECTION_HEADER);
  471. if ((Context->Flags & ELFCONV_OPTION_VERBOSE) != 0) {
  472. printf("Creating section %s VA 0x%x, SizeOfRawData 0x%x, "
  473. "PointerToRawData 0x%x, Characteristics 0x%x.\n",
  474. Name,
  475. Header->VirtualAddress,
  476. Header->SizeOfRawData,
  477. Header->PointerToRawData,
  478. Header->Characteristics);
  479. }
  480. return;
  481. }
  482. BOOLEAN
  483. ElfconvCoffAddFixup (
  484. PELFCONV_CONTEXT Context,
  485. UINT32 Offset,
  486. UINT8 Type
  487. )
  488. /*++
  489. Routine Description:
  490. This routine adds a COFF relocation to the destination image buffer.
  491. Arguments:
  492. Context - Supplies a pointer to the conversion context.
  493. Offset - Supplies the file offset to the relocation.
  494. Type - Supplies the relocation type.
  495. Return Value:
  496. TRUE on success.
  497. FALSE on allocation failure.
  498. --*/
  499. {
  500. UINTN Difference;
  501. VOID *NewBuffer;
  502. UINTN NewSize;
  503. //
  504. // Create a new page entry if no relocations have been added or this one is
  505. // on a different page.
  506. //
  507. if ((Context->CoffBaseRelocation == NULL) ||
  508. (Context->CoffBaseRelocation->VirtualAddress !=
  509. (Offset & ~0x00000FFF))) {
  510. if (Context->CoffBaseRelocation != NULL) {
  511. //
  512. // Add a null entry, then pad for alignment.
  513. //
  514. ElfconvCoffAddFixupEntry(Context, 0);
  515. if ((Context->CoffOffset % 4) != 0) {
  516. ElfconvCoffAddFixupEntry(Context, 0);
  517. }
  518. }
  519. NewSize = Context->CoffOffset +
  520. sizeof(EFI_IMAGE_BASE_RELOCATION) +
  521. ELFCONV_RELOCATION_EXPANSION_SIZE;
  522. NewBuffer = realloc(Context->CoffFile, NewSize);
  523. if (NewBuffer == NULL) {
  524. return FALSE;
  525. }
  526. Context->CoffFile = NewBuffer;
  527. Difference = NewSize - Context->CoffOffset;
  528. memset(Context->CoffFile + Context->CoffOffset, 0, Difference);
  529. Context->CoffBaseRelocation =
  530. (EFI_IMAGE_BASE_RELOCATION *)(Context->CoffFile +
  531. Context->CoffOffset);
  532. Context->CoffBaseRelocation->VirtualAddress = Offset & ~0x00000FFF;
  533. Context->CoffBaseRelocation->SizeOfBlock =
  534. sizeof(EFI_IMAGE_BASE_RELOCATION);
  535. Context->CoffNextRelocation =
  536. (UINT16 *)(Context->CoffBaseRelocation + 1);
  537. Context->CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
  538. }
  539. ElfconvCoffAddFixupEntry(Context,
  540. (UINT16)((Type << 12) | (Offset & 0xFFF)));
  541. return TRUE;
  542. }
  543. VOID
  544. ElfconvCoffAddFixupEntry (
  545. PELFCONV_CONTEXT Context,
  546. UINT16 Value
  547. )
  548. /*++
  549. Routine Description:
  550. This routine adds a relocation entry to the current COFF location.
  551. Arguments:
  552. Context - Supplies a pointer to the application context.
  553. Value - Supplies the relocation value to add.
  554. Return Value:
  555. None.
  556. --*/
  557. {
  558. *(Context->CoffNextRelocation) = Value;
  559. Context->CoffNextRelocation += 1;
  560. Context->CoffBaseRelocation->SizeOfBlock += sizeof(UINT16);
  561. Context->CoffOffset += sizeof(UINT16);
  562. return;
  563. }
  564. //
  565. // --------------------------------------------------------- Internal Functions
  566. //
  567. int
  568. ElfconvLoadFile (
  569. PELFCONV_CONTEXT Context
  570. )
  571. /*++
  572. Routine Description:
  573. This routine loads the input file into memory.
  574. Arguments:
  575. Context - Supplies a pointer to the conversion context.
  576. Return Value:
  577. 0 on success.
  578. Non-zero on failure.
  579. --*/
  580. {
  581. CHAR8 *Buffer;
  582. ssize_t BytesRead;
  583. FILE *File;
  584. struct stat Stat;
  585. int Status;
  586. Buffer = NULL;
  587. File = fopen(Context->InputName, "rb");
  588. if (File == NULL) {
  589. Status = errno;
  590. fprintf(stderr,
  591. "Error: Failed to open %s: %s.\n",
  592. Context->InputName,
  593. strerror(Status));
  594. goto LoadFileEnd;
  595. }
  596. Status = stat(Context->InputName, &Stat);
  597. if (Status != 0) {
  598. Status = errno;
  599. goto LoadFileEnd;
  600. }
  601. if (Stat.st_size > 0xFFFFFFFF) {
  602. Status = ERANGE;
  603. fprintf(stderr, "Error: File too big.\n");
  604. goto LoadFileEnd;
  605. }
  606. Buffer = malloc(Stat.st_size);
  607. if (Buffer == NULL) {
  608. fprintf(stderr,
  609. "Error: Failed to allocate 0x%x for input file buffer.\n",
  610. Stat.st_size);
  611. Status = ENOMEM;
  612. goto LoadFileEnd;
  613. }
  614. BytesRead = fread(Buffer, 1, Stat.st_size, File);
  615. if (BytesRead != Stat.st_size) {
  616. Status = errno;
  617. if (Status == 0) {
  618. Status = EIO;
  619. }
  620. fprintf(stderr,
  621. "Error: Failed to read input file %s: %s.\n",
  622. Context->InputName,
  623. strerror(Status));
  624. goto LoadFileEnd;
  625. }
  626. Context->InputFile = Buffer;
  627. Context->InputFileSize = Stat.st_size;
  628. Buffer = 0;
  629. Status = 0;
  630. LoadFileEnd:
  631. if (File != NULL) {
  632. fclose(File);
  633. }
  634. if (Buffer != NULL) {
  635. free(Buffer);
  636. }
  637. return Status;
  638. }
  639. BOOLEAN
  640. ElfconvIsElfHeader (
  641. VOID *File,
  642. UINTN FileSize
  643. )
  644. /*++
  645. Routine Description:
  646. This routine determines if the given file starts with a valid ELF header.
  647. Arguments:
  648. File - Supplies a pointer to the file buffer.
  649. FileSize - Supplies the size of the file in bytes.
  650. Return Value:
  651. TRUE if the given file is ELF.
  652. FALSE if the file is not ELF or is too small.
  653. --*/
  654. {
  655. INT8 *Buffer;
  656. if (FileSize < EI_PAD) {
  657. return FALSE;
  658. }
  659. Buffer = File;
  660. if ((Buffer[EI_MAG0] == ELFMAG0) && (Buffer[EI_MAG1] == ELFMAG1) &&
  661. (Buffer[EI_MAG2] == ELFMAG2) && (Buffer[EI_MAG3] == ELFMAG3)) {
  662. return TRUE;
  663. }
  664. return FALSE;
  665. }