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