automagically convert ELF to PE/COFF (i386 only)
[mirror_edk2.git] / Tools / CCode / Source / FwImage / fwimage.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2004, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 fwimage.c\r
15\r
16Abstract:\r
17\r
18 Converts a pe32+ image to an FW image type\r
19\r
20--*/\r
21\r
ce53a8c3 22#include "WinNtInclude.h"\r
23\r
8ba7afaf 24//\r
25// List of OS and CPU which support ELF to PE conversion\r
26//\r
27#if defined(linux)
28#if defined(i386)
29#define HAVE_ELF
30#endif
31#endif
32
878ddf1f 33#ifndef __GNUC__\r
34#include <windows.h>\r
35#endif\r
36#include <stdio.h>\r
37#include <stdlib.h>\r
38#include <string.h>\r
39#include <time.h>\r
8ba7afaf 40
41#ifdef HAVE_ELF
42#include <elf.h>
43#endif
878ddf1f 44\r
ce53a8c3 45#include <Common/UefiBaseTypes.h>\r
46#include <Common/EfiImage.h>\r
47\r
48#include "CommonLib.h"\r
49#include "EfiUtilityMsgs.c"\r
878ddf1f 50\r
f091efb3 51//\r
52// Version of this utility\r
53//\r
54#define UTILITY_NAME "FwImage"\r
55#define UTILITY_MAJOR_VERSION 1\r
56#define UTILITY_MINOR_VERSION 0\r
878ddf1f 57\r
58#ifdef __GNUC__\r
59typedef unsigned long ULONG;\r
60typedef unsigned char UCHAR;\r
61typedef unsigned char *PUCHAR;\r
62typedef unsigned short USHORT;\r
63#endif\r
64\r
8ba7afaf 65PUCHAR InImageName;\r
66\r
f091efb3 67static\r
68void\r
69Version (\r
70 VOID\r
71 )\r
72{\r
73 printf ("%s v%d.%d -EDK Utility for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
74 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
75}\r
76\r
77\r
878ddf1f 78VOID\r
79Usage (\r
80 VOID\r
81 )\r
82{\r
f091efb3 83 Version();\r
84 printf ("\nUsage: " UTILITY_NAME " {-t time-date} {-h|--help|-?|/?|-V|--version} \n\\r
85 [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\\r
86 DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\\r
8ba7afaf 87 USER_DEFINED] peimage [outimage]\n");\r
878ddf1f 88}\r
89\r
90static\r
91STATUS\r
92FCopyFile (\r
93 FILE *in,\r
94 FILE *out\r
95 )\r
96{\r
97 ULONG filesize;\r
98 ULONG offset;\r
99 ULONG length;\r
100 UCHAR Buffer[8 * 1024];\r
101\r
102 fseek (in, 0, SEEK_END);\r
103 filesize = ftell (in);\r
104\r
105 fseek (in, 0, SEEK_SET);\r
106 fseek (out, 0, SEEK_SET);\r
107\r
108 offset = 0;\r
109 while (offset < filesize) {\r
110 length = sizeof (Buffer);\r
111 if (filesize - offset < length) {\r
112 length = filesize - offset;\r
113 }\r
114\r
115 fread (Buffer, length, 1, in);\r
116 fwrite (Buffer, length, 1, out);\r
117 offset += length;\r
118 }\r
119\r
120 if ((ULONG) ftell (out) != filesize) {\r
121 Error (NULL, 0, 0, "write error", NULL);\r
122 return STATUS_ERROR;\r
123 }\r
124\r
125 return STATUS_SUCCESS;\r
126}\r
127\r
3edf127e 128static\r
129STATUS\r
130FReadFile (\r
131 FILE *in,\r
132 VOID **Buffer,\r
133 UINTN *Length\r
134 )\r
135{\r
136 fseek (in, 0, SEEK_END);\r
137 *Length = ftell (in);\r
138 *Buffer = malloc (*Length);\r
139 fseek (in, 0, SEEK_SET);\r
140 fread (*Buffer, *Length, 1, in);\r
141 return STATUS_SUCCESS;\r
142}\r
143\r
144static\r
145STATUS\r
146FWriteFile (\r
147 FILE *out,\r
148 VOID *Buffer,\r
149 UINTN Length\r
150 )\r
151{\r
152 fseek (out, 0, SEEK_SET);\r
153 fwrite (Buffer, Length, 1, out);\r
154 if ((ULONG) ftell (out) != Length) {\r
155 Error (NULL, 0, 0, "write error", NULL);\r
156 return STATUS_ERROR;\r
157 }\r
158 free (Buffer);\r
159 return STATUS_SUCCESS;\r
160}\r
161\r
8ba7afaf 162#ifdef HAVE_ELF
163INTN
164IsElfHeader(
165 UINT8 *FileBuffer
166)
167{
168 return (FileBuffer[EI_MAG0] == ELFMAG0
169 && FileBuffer[EI_MAG1] == ELFMAG1
170 && FileBuffer[EI_MAG2] == ELFMAG2
171 && FileBuffer[EI_MAG3] == ELFMAG3);
172}
173
174typedef Elf32_Shdr Elf_Shdr;
175typedef Elf32_Ehdr Elf_Ehdr;
176typedef Elf32_Rel Elf_Rel;
177typedef Elf32_Sym Elf_Sym;
178#define ELFCLASS ELFCLASS32
179#define ELF_R_TYPE(r) ELF32_R_TYPE(r)
180#define ELF_R_SYM(r) ELF32_R_SYM(r)
181
182//
183// Well known ELF structures.
184//
185Elf_Ehdr *Ehdr;
186Elf_Shdr *ShdrBase;
187
188//
189// PE section alignment.
190//
191const UINT32 CoffAlignment = 0x20;
192const UINT32 CoffNbrSections = 4;
193
194//
195// Current offset in coff file.
196//
197UINT32 CoffOffset;
198
199//
200// Result Coff file in memory.
201//
202UINT8 *CoffFile;
203
204//
205// Offset in Coff file of headers and sections.
206//
207UINT32 NtHdrOffset;
208UINT32 TableOffset;
209UINT32 TextOffset;
210UINT32 DataOffset;
211UINT32 RelocOffset;
212
213//
214// ELF sections to offset in Coff file.
215//
216UINT32 *CoffSectionsOffset;
217
218EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
219UINT16 *CoffEntryRel;
220
221UINT32
222CoffAlign(
223 UINT32 Offset
224 )
225{
226 return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
227}
228
229Elf_Shdr *
230GetShdrByIndex(
231 UINT32 Num
232 )
233{
234 if (Num >= Ehdr->e_shnum)
235 return NULL;
236 return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
237}
238
239INTN
240CheckElfHeader(
241 VOID
242 )
243{
244 //
245 // Note: Magic has already been tested.
246 //
247 if (Ehdr->e_ident[EI_CLASS] != ELFCLASS)
248 return 0;
249 if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
250 return 0;
251 if (Ehdr->e_type != ET_EXEC)
252 return 0;
253 if (Ehdr->e_machine != EM_386)
254 return 0;
255 if (Ehdr->e_version != EV_CURRENT)
256 return 0;
257
258 ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
259
260 CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));
261 memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));
262 return 1;
263}
264
265int
266IsTextShdr(
267 Elf_Shdr *Shdr
268 )
269{
270 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
271}
272
273int
274IsDataShdr(
275 Elf_Shdr *Shdr
276 )
277{
278 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
279}
280
281void
282CreateSectionHeader(
283 const char *Name,
284 UINT32 Offset,
285 UINT32 Size,
286 UINT32 Flags
287 )
288{
289 EFI_IMAGE_SECTION_HEADER *Hdr;
290 Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
291
292 strcpy(Hdr->Name, Name);
293 Hdr->Misc.VirtualSize = Size;
294 Hdr->VirtualAddress = Offset;
295 Hdr->SizeOfRawData = Size;
296 Hdr->PointerToRawData = Offset;
297 Hdr->PointerToRelocations = 0;
298 Hdr->PointerToLinenumbers = 0;
299 Hdr->NumberOfRelocations = 0;
300 Hdr->NumberOfLinenumbers = 0;
301 Hdr->Characteristics = Flags;
302
303 TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
304}
305
306void
307ScanSections(
308 VOID
309 )
310{
311 UINT32 i;
312 EFI_IMAGE_DOS_HEADER *DosHdr;
313 EFI_IMAGE_NT_HEADERS *NtHdr;
314 UINT32 CoffEntry = 0;
315
316 CoffOffset = 0;
317
318 //
319 // Coff file start with a DOS header.
320 //
321 CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
322 NtHdrOffset = CoffOffset;
323 CoffOffset += sizeof(EFI_IMAGE_NT_HEADERS);
324 TableOffset = CoffOffset;
325 CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
326
327 //
328 // First text sections.
329 //
330 CoffOffset = CoffAlign(CoffOffset);
331 TextOffset = CoffOffset;
332 for (i = 0; i < Ehdr->e_shnum; i++) {
333 Elf_Shdr *shdr = GetShdrByIndex(i);
334 if (IsTextShdr(shdr)) {
335 /* Relocate entry. */
336 if (Ehdr->e_entry >= shdr->sh_addr
337 && Ehdr->e_entry < shdr->sh_addr + shdr->sh_size) {
338 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
339 }
340 CoffSectionsOffset[i] = CoffOffset;
341 CoffOffset += shdr->sh_size;
342 }
343 }
344 CoffOffset = CoffAlign(CoffOffset);
345
346 //
347 // Then data sections.
348 //
349 DataOffset = CoffOffset;
350 for (i = 0; i < Ehdr->e_shnum; i++) {
351 Elf_Shdr *shdr = GetShdrByIndex(i);
352 if (IsDataShdr(shdr)) {
353 CoffSectionsOffset[i] = CoffOffset;
354 CoffOffset += shdr->sh_size;
355 }
356 }
357 CoffOffset = CoffAlign(CoffOffset);
358
359 RelocOffset = CoffOffset;
360
361 //
362 // Allocate base Coff file. Will be expanded later for relocations.
363 //
364 CoffFile = (UINT8 *)malloc(CoffOffset);
365 memset(CoffFile, 0, CoffOffset);
366
367 //
368 // Fill headers.
369 //
370 DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
371 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
372 DosHdr->e_lfanew = NtHdrOffset;
373
374 NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
375
376 NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
377
378 NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
379 NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
380 NtHdr->FileHeader.TimeDateStamp = time(NULL);
381 NtHdr->FileHeader.PointerToSymbolTable = 0;
382 NtHdr->FileHeader.NumberOfSymbols = 0;
383 NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
384 NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
385 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
386 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
387 | EFI_IMAGE_FILE_32BIT_MACHINE;
388
389 NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
390 NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
391 NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
392 NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
393 NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
394 NtHdr->OptionalHeader.BaseOfCode = TextOffset;
395
396 NtHdr->OptionalHeader.BaseOfData = DataOffset;
397 NtHdr->OptionalHeader.ImageBase = 0;
398 NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
399 NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
400 NtHdr->OptionalHeader.SizeOfImage = 0;
401
402 NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
403 NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
404
405 //
406 // Section headers.
407 //
408 CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
409 EFI_IMAGE_SCN_CNT_CODE
410 | EFI_IMAGE_SCN_MEM_EXECUTE
411 | EFI_IMAGE_SCN_MEM_READ);
412 CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
413 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
414 | EFI_IMAGE_SCN_MEM_WRITE
415 | EFI_IMAGE_SCN_MEM_READ);
416}
417
418void
419WriteSections(
420 int (*Filter)(Elf_Shdr *)
421 )
422{
423 UINT32 Idx;
424
425 //
426 // First: copy sections.
427 //
428 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
429 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
430 if ((*Filter)(Shdr)) {
431 switch (Shdr->sh_type) {
432 case SHT_PROGBITS:
433 /* Copy. */
434 memcpy(CoffFile + CoffSectionsOffset[Idx],
435 (UINT8*)Ehdr + Shdr->sh_offset,
436 Shdr->sh_size);
437 break;
438 case SHT_NOBITS:
439 memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
440 break;
441 default:
442 Error (NULL, 0, 0, InImageName, "unhandle section type %x",
443 (UINTN)Shdr->sh_type);
444 }
445 }
446 }
447
448 //
449 // Second: apply relocations.
450 //
451 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
452 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
453 if (RelShdr->sh_type != SHT_REL)
454 continue;
455 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
456 UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
457 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
458 UINT32 RelIdx;
459 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
460 UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
461
462 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
463 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
464 Elf_Sym *Sym = (Elf_Sym *)
465 (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
466 Elf_Shdr *SymShdr;
467 UINT8 *Targ;
468
469 if (Sym->st_shndx == SHN_UNDEF
470 || Sym->st_shndx == SHN_ABS
471 || Sym->st_shndx > Ehdr->e_shnum) {
472 Error (NULL, 0, 0, InImageName, "bad symbol definition");
473 }
474 SymShdr = GetShdrByIndex(Sym->st_shndx);
475
476 //
477 // Note: r_offset in a memory address.
478 // Convert it to a pointer in the coff file.
479 //
480 Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
481
482 switch (ELF_R_TYPE(Rel->r_info)) {
483 case R_386_NONE:
484 break;
485 case R_386_32:
486 //
487 // Absolute relocation.
488 //
489 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
490 + CoffSectionsOffset[Sym->st_shndx];
491 break;
492 case R_386_PC32:
493 //
494 // Relative relocation: Symbol - Ip + Addend
495 //
496 *(UINT32 *)Targ = *(UINT32 *)Targ
497 + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
498 - (SecOffset - SecShdr->sh_addr);
499 break;
500 default:
501 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
502 ELF_R_TYPE(Rel->r_info));
503 }
504 }
505 }
506 }
507}
508
509void
510CoffAddFixupEntry(
511 UINT16 Val
512 )
513{
514 *CoffEntryRel = Val;
515 CoffEntryRel++;
516 CoffBaseRel->SizeOfBlock += 2;
517 CoffOffset += 2;
518}
519
520void
521CoffAddFixup(
522 UINT32 Offset,
523 UINT8 Type
524 )
525{
526 if (CoffBaseRel == NULL
527 || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
528 if (CoffBaseRel != NULL) {
529 //
530 // Add a null entry (is it required ?)
531 //
532 CoffAddFixupEntry (0);
533 //
534 // Pad for alignment.
535 //
536 if (CoffOffset % 4 != 0)
537 CoffAddFixupEntry (0);
538 }
539
540 CoffFile = realloc
541 (CoffFile,
542 CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
543 memset(CoffFile + CoffOffset, 0,
544 sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
545
546 CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
547 CoffBaseRel->VirtualAddress = Offset & ~0xfff;
548 CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
549
550 CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
551 CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
552 }
553
554 //
555 // Fill the entry.
556 //
557 CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
558}
559
560void
561WriteRelocations(
562 VOID
563 )
564{
565 UINT32 Idx;
566 EFI_IMAGE_NT_HEADERS *NtHdr;
567 EFI_IMAGE_DATA_DIRECTORY *Dir;
568
569 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
570 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
571 if (RelShdr->sh_type == SHT_REL) {
572 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
573 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
574 UINT32 RelIdx;
575 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
576 Elf_Rel *Rel = (Elf_Rel *)
577 ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
578 switch (ELF_R_TYPE(Rel->r_info)) {
579 case R_386_NONE:
580 case R_386_PC32:
581 break;
582 case R_386_32:
583 CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
584 + (Rel->r_offset - SecShdr->sh_addr),
585 EFI_IMAGE_REL_BASED_HIGHLOW);
586 break;
587 default:
588 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
589 ELF_R_TYPE(Rel->r_info));
590 }
591 }
592 }
593 }
594 }
595
596 //
597 // Pad by adding empty entries.
598 //
599 while (CoffOffset & (CoffAlignment - 1)) {
600 CoffAddFixupEntry(0);
601 }
602
603 CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
604 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
605 | EFI_IMAGE_SCN_MEM_DISCARDABLE
606 | EFI_IMAGE_SCN_MEM_READ);
607
608 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
609 Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
610 Dir->VirtualAddress = RelocOffset;
611 Dir->Size = CoffOffset - RelocOffset;
612}
613
614void
615WriteDebug(
616 VOID
617 )
618{
619 UINT32 Len = strlen(InImageName) + 1;
620 UINT32 DebugOffset = CoffOffset;
621 EFI_IMAGE_NT_HEADERS *NtHdr;
622 EFI_IMAGE_DATA_DIRECTORY *DataDir;
623 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
624 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
625
626 CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
627 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
628 + Len;
629 CoffOffset = CoffAlign(CoffOffset);
630
631 CoffFile = realloc
632 (CoffFile, CoffOffset);
633 memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
634
635 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
636 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
637 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
638 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
639 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
640
641 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
642 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
643 strcpy ((PUCHAR)(Nb10 + 1), InImageName);
644
645 CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
646 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
647 | EFI_IMAGE_SCN_MEM_DISCARDABLE
648 | EFI_IMAGE_SCN_MEM_READ);
649
650 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
651 DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
652 DataDir->VirtualAddress = DebugOffset;
653 DataDir->Size = CoffOffset - DebugOffset;
654}
655
656void
657ConvertElf (
658 UINT8 **FileBuffer,
659 UINTN *FileLength
660 )
661{
662 EFI_IMAGE_NT_HEADERS *NtHdr;
663
664 //
665 // Check header, read section table.
666 //
667 Ehdr = (Elf32_Ehdr*)*FileBuffer;
668 if (!CheckElfHeader())
669 return;
670
671 //
672 // Compute sections new address.
673 //
674 ScanSections();
675
676 //
677 // Write and relocate sections.
678 //
679 WriteSections(IsTextShdr);
680 WriteSections(IsDataShdr);
681
682 //
683 // Translate and write relocations.
684 //
685 WriteRelocations();
686
687 //
688 // Write debug info.
689 //
690 WriteDebug();
691
692 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
693 NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
694
695 //
696 // Replace.
697 //
698 free(*FileBuffer);
699 *FileBuffer = CoffFile;
700 *FileLength = CoffOffset;
701}
702#endif // HAVE_ELF
703
878ddf1f 704int\r
705main (\r
706 int argc,\r
707 char *argv[]\r
708 )\r
709/*++\r
710\r
711Routine Description:\r
712\r
713 Main function.\r
714\r
715Arguments:\r
716\r
717 argc - Number of command line parameters.\r
718 argv - Array of pointers to command line parameter strings.\r
719\r
720Returns:\r
721 STATUS_SUCCESS - Utility exits successfully.\r
722 STATUS_ERROR - Some error occurred during execution.\r
723\r
724--*/\r
725{\r
726 ULONG Type;\r
727 PUCHAR Ext;\r
728 PUCHAR p;\r
729 PUCHAR pe;\r
730 PUCHAR OutImageName;\r
731 UCHAR outname[500];\r
732 FILE *fpIn;\r
733 FILE *fpOut;\r
3edf127e 734 VOID *ZeroBuffer;\r
735 EFI_IMAGE_DOS_HEADER *DosHdr;\r
736 EFI_IMAGE_NT_HEADERS *PeHdr;\r
737 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
738 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
878ddf1f 739 time_t TimeStamp;\r
740 struct tm TimeStruct;\r
741 EFI_IMAGE_DOS_HEADER BackupDosHdr;\r
742 ULONG Index;\r
3edf127e 743 ULONG Index1;\r
307fd197 744 ULONG Index2;\r
745 ULONG Index3;\r
878ddf1f 746 BOOLEAN TimeStampPresent;\r
0411bcaf 747 UINTN AllignedRelocSize;\r
3edf127e 748 UINTN Delta;\r
749 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
750 UINT8 *FileBuffer;\r
751 UINTN FileLength;\r
307fd197 752 RUNTIME_FUNCTION *RuntimeFunction;\r
753 UNWIND_INFO *UnwindInfo;\r
878ddf1f 754\r
755 SetUtilityName (UTILITY_NAME);\r
756 //\r
757 // Assign to fix compile warning\r
758 //\r
759 OutImageName = NULL;\r
760 Type = 0;\r
761 Ext = 0;\r
762 TimeStamp = 0;\r
763 TimeStampPresent = FALSE;\r
764\r
f091efb3 765 if (argc < 1) {\r
766 Usage();\r
767 return STATUS_ERROR;\r
768 }\r
769 \r
770 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
771 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
772 Usage();\r
773 return STATUS_ERROR;\r
774 }\r
775 \r
776 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
777 Version();\r
778 return STATUS_ERROR;\r
779 }\r
780 \r
878ddf1f 781 //\r
782 // Look for -t time-date option first. If the time is "0", then\r
783 // skip it.\r
784 //\r
785 if ((argc > 2) && !strcmp (argv[1], "-t")) {\r
786 TimeStampPresent = TRUE;\r
787 if (strcmp (argv[2], "0") != 0) {\r
788 //\r
789 // Convert the string to a value\r
790 //\r
791 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));\r
792 if (sscanf(\r
793 argv[2], "%d/%d/%d,%d:%d:%d",\r
794 &TimeStruct.tm_mon, /* months since January - [0,11] */\r
795 &TimeStruct.tm_mday, /* day of the month - [1,31] */\r
796 &TimeStruct.tm_year, /* years since 1900 */\r
797 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */\r
798 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */\r
799 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */\r
800 ) != 6) {\r
801 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");\r
802 return STATUS_ERROR;\r
803 }\r
804 //\r
805 // Now fixup some of the fields\r
806 //\r
807 TimeStruct.tm_mon--;\r
808 TimeStruct.tm_year -= 1900;\r
809 //\r
810 // Sanity-check values?\r
811 // Convert\r
812 //\r
813 TimeStamp = mktime (&TimeStruct);\r
814 if (TimeStamp == (time_t) - 1) {\r
815 Error (NULL, 0, 0, argv[2], "failed to convert time");\r
816 return STATUS_ERROR;\r
817 }\r
818 }\r
819 //\r
820 // Skip over the args\r
821 //\r
822 argc -= 2;\r
823 argv += 2;\r
824 }\r
825 //\r
826 // Check for enough args\r
827 //\r
828 if (argc < 3) {\r
829 Usage ();\r
830 return STATUS_ERROR;\r
831 }\r
832\r
8ba7afaf 833 InImageName = argv[2];\r
834\r
878ddf1f 835 if (argc == 4) {\r
836 OutImageName = argv[3];\r
837 }\r
838 //\r
839 // Get new image type\r
840 //\r
841 p = argv[1];\r
842 if (*p == '/' || *p == '\\') {\r
843 p += 1;\r
844 }\r
845\r
8a286638 846 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {\r
878ddf1f 847 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
848 Ext = ".efi";\r
849\r
8a286638 850 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {\r
878ddf1f 851 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
852 Ext = ".efi";\r
853\r
8a286638 854 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {\r
878ddf1f 855 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
856 Ext = ".efi";\r
857\r
8a286638 858 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {\r
878ddf1f 859 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
860 Ext = ".efi";\r
8a286638 861 } else if (stricmp (p, "SEC") == 0) {\r
878ddf1f 862 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
863 Ext = ".sec";\r
864 } else if (stricmp (p, "peim") == 0 ||\r
8a286638 865 stricmp (p, "BASE") == 0 ||\r
878ddf1f 866 stricmp (p, "PEI_CORE") == 0 ||\r
8a286638 867 stricmp (p, "PEIM") == 0 ||\r
868 stricmp (p, "DXE_SMM_DRIVER") == 0 ||\r
869 stricmp (p, "TOOL") == 0 ||\r
870 stricmp (p, "UEFI_APPLICATION") == 0 ||\r
871 stricmp (p, "USER_DEFINED") == 0 ||\r
872 stricmp (p, "UEFI_DRIVER") == 0 ||\r
873 stricmp (p, "DXE_CORE") == 0\r
878ddf1f 874 ) {\r
875 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
876 Ext = ".pei";\r
877 } else {\r
8a286638 878 printf ("%s", p);\r
878ddf1f 879 Usage ();\r
880 return STATUS_ERROR;\r
881 }\r
882 //\r
883 // open source file\r
884 //\r
8ba7afaf 885 fpIn = fopen (InImageName, "rb");\r
878ddf1f 886 if (!fpIn) {\r
8ba7afaf 887 Error (NULL, 0, 0, InImageName, "failed to open input file for reading");\r
878ddf1f 888 return STATUS_ERROR;\r
889 }\r
3edf127e 890\r
891 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
892\r
8ba7afaf 893#ifdef HAVE_ELF
894 if (IsElfHeader(FileBuffer)) {
895 ConvertElf(&FileBuffer, &FileLength);
896 }
897#endif
878ddf1f 898 //\r
899 // Read the dos & pe hdrs of the image\r
900 //\r
3edf127e 901 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
902 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
8ba7afaf 903 Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");\r
878ddf1f 904 fclose (fpIn);\r
905 return STATUS_ERROR;\r
906 }\r
907\r
3edf127e 908 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
909 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
8ba7afaf 910 Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");\r
878ddf1f 911 fclose (fpIn);\r
912 return STATUS_ERROR;\r
913 }\r
3edf127e 914\r
878ddf1f 915 //\r
916 // open output file\r
917 //\r
8ba7afaf 918 strcpy (outname, InImageName);\r
878ddf1f 919 pe = NULL;\r
920 for (p = outname; *p; p++) {\r
921 if (*p == '.') {\r
922 pe = p;\r
923 }\r
924 }\r
925\r
926 if (!pe) {\r
927 pe = p;\r
928 }\r
929\r
930 strcpy (pe, Ext);\r
931\r
932 if (!OutImageName) {\r
933 OutImageName = outname;\r
934 }\r
935\r
936 fpOut = fopen (OutImageName, "w+b");\r
937 if (!fpOut) {\r
938 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
939 fclose (fpIn);\r
940 return STATUS_ERROR;\r
941 }\r
3edf127e 942\r
878ddf1f 943 //\r
944 // Zero all unused fields of the DOS header\r
945 //\r
3edf127e 946 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
947 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
948 DosHdr->e_magic = BackupDosHdr.e_magic;\r
949 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
950\r
951 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
952 FileBuffer[Index] = DosHdr->e_cp;\r
878ddf1f 953 }\r
3edf127e 954\r
878ddf1f 955 //\r
8ba7afaf 956 // Patch the PE header\r
878ddf1f 957 //\r
3edf127e 958 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
878ddf1f 959 if (TimeStampPresent) {\r
3edf127e 960 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
961 }\r
962\r
3edf127e 963 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
964 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
965 Optional32->MajorLinkerVersion = 0;\r
966 Optional32->MinorLinkerVersion = 0;\r
967 Optional32->MajorOperatingSystemVersion = 0;\r
968 Optional32->MinorOperatingSystemVersion = 0;\r
969 Optional32->MajorImageVersion = 0;\r
970 Optional32->MinorImageVersion = 0;\r
971 Optional32->MajorSubsystemVersion = 0;\r
972 Optional32->MinorSubsystemVersion = 0;\r
973 Optional32->Win32VersionValue = 0;\r
974 Optional32->CheckSum = 0;\r
975 Optional32->SizeOfStackReserve = 0;\r
976 Optional32->SizeOfStackCommit = 0;\r
977 Optional32->SizeOfHeapReserve = 0;\r
978 Optional32->SizeOfHeapCommit = 0;\r
979\r
3edf127e 980 //\r
981 // Strip zero padding at the end of the .reloc section \r
982 //\r
983 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
984 if (Optional32->DataDirectory[5].Size != 0) {\r
985 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
986 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 987 //\r
988 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
989 //\r
3edf127e 990 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
0411bcaf 991 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;\r
992 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
993 //\r
994 // Check to see if there is zero padding at the end of the base relocations\r
995 //\r
996 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
997 //\r
998 // Check to see if the base relocations are at the end of the file\r
999 //\r
1000 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
1001 //\r
1002 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1003 //\r
1004 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1005 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1006 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1007 FileLength = Optional32->SizeOfImage;\r
1008 }\r
1009 }\r
3edf127e 1010 }\r
1011 }\r
1012 }\r
1013 }\r
1014 } \r
1015 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1016 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
1017 Optional64->MajorLinkerVersion = 0;\r
1018 Optional64->MinorLinkerVersion = 0;\r
1019 Optional64->MajorOperatingSystemVersion = 0;\r
1020 Optional64->MinorOperatingSystemVersion = 0;\r
1021 Optional64->MajorImageVersion = 0;\r
1022 Optional64->MinorImageVersion = 0;\r
1023 Optional64->MajorSubsystemVersion = 0;\r
1024 Optional64->MinorSubsystemVersion = 0;\r
1025 Optional64->Win32VersionValue = 0;\r
1026 Optional64->CheckSum = 0;\r
1027 Optional64->SizeOfStackReserve = 0;\r
1028 Optional64->SizeOfStackCommit = 0;\r
1029 Optional64->SizeOfHeapReserve = 0;\r
1030 Optional64->SizeOfHeapCommit = 0;\r
1031\r
1032 //\r
1033 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
1034 //\r
1035 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
1036 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
1037 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
1038 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1039 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1040 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
307fd197 1041 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);\r
1042 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {\r
1043 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1044 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {\r
1045 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {\r
1046 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));\r
1047 if (UnwindInfo->Version == 1) {\r
1048 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));\r
1049 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));\r
1050 }\r
1051 }\r
1052 }\r
1053 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));\r
3edf127e 1054 }\r
d9e0f88e 1055\r
1056 break;\r
3edf127e 1057 }\r
1058 }\r
1059 Optional64->DataDirectory[3].Size = 0;\r
1060 Optional64->DataDirectory[3].VirtualAddress = 0;\r
1061 }\r
1062 }\r
1063 }\r
1064\r
1065 //\r
1066 // Strip zero padding at the end of the .reloc section \r
1067 //\r
1068 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
1069 if (Optional64->DataDirectory[5].Size != 0) {\r
1070 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1071 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 1072 //\r
1073 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1074 //\r
3edf127e 1075 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
0411bcaf 1076 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;\r
1077 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
1078 //\r
1079 // Check to see if there is zero padding at the end of the base relocations\r
1080 //\r
1081 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1082 //\r
1083 // Check to see if the base relocations are at the end of the file\r
1084 //\r
1085 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
1086 //\r
1087 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1088 //\r
1089 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1090 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1091 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1092 FileLength = Optional64->SizeOfImage;\r
1093 }\r
1094 }\r
3edf127e 1095 }\r
1096 }\r
1097 }\r
1098 }\r
1099 }\r
1100\r
3edf127e 1101 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 1102\r
1103 //\r
1104 // Done\r
1105 //\r
1106 fclose (fpIn);\r
1107 fclose (fpOut);\r
1108 //\r
1109 // printf ("Created %s\n", OutImageName);\r
1110 //\r
1111 return STATUS_SUCCESS;\r
1112}\r