]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CCode/Source/FwImage/fwimage.c
Merge the patch provided by Johnson
[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__) || defined(__x86_64__)
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 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
344 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
345 }
346
347 /* Relocate entry. */
348 if ((Ehdr->e_entry >= shdr->sh_addr) &&
349 (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
350 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
351 }
352 CoffSectionsOffset[i] = CoffOffset;
353 CoffOffset += shdr->sh_size;
354 }
355 }
356 CoffOffset = CoffAlign(CoffOffset);
357
358 //
359 // Then data sections.
360 //
361 DataOffset = CoffOffset;
362 for (i = 0; i < Ehdr->e_shnum; i++) {
363 Elf_Shdr *shdr = GetShdrByIndex(i);
364 if (IsDataShdr(shdr)) {
365 //
366 // Align the coff offset to meet with the alignment requirement of section
367 // itself.
368 //
369 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
370 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
371 }
372
373 CoffSectionsOffset[i] = CoffOffset;
374 CoffOffset += shdr->sh_size;
375 }
376 }
377 CoffOffset = CoffAlign(CoffOffset);
378
379 RelocOffset = CoffOffset;
380
381 //
382 // Allocate base Coff file. Will be expanded later for relocations.
383 //
384 CoffFile = (UINT8 *)malloc(CoffOffset);
385 memset(CoffFile, 0, CoffOffset);
386
387 //
388 // Fill headers.
389 //
390 DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
391 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
392 DosHdr->e_lfanew = NtHdrOffset;
393
394 NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
395
396 NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
397
398 NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
399 NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
400 NtHdr->FileHeader.TimeDateStamp = time(NULL);
401 NtHdr->FileHeader.PointerToSymbolTable = 0;
402 NtHdr->FileHeader.NumberOfSymbols = 0;
403 NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
404 NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
405 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
406 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
407 | EFI_IMAGE_FILE_32BIT_MACHINE;
408
409 NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
410 NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
411 NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
412 NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
413 NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
414 NtHdr->OptionalHeader.BaseOfCode = TextOffset;
415
416 NtHdr->OptionalHeader.BaseOfData = DataOffset;
417 NtHdr->OptionalHeader.ImageBase = 0;
418 NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
419 NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
420 NtHdr->OptionalHeader.SizeOfImage = 0;
421
422 NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
423 NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
424
425 //
426 // Section headers.
427 //
428 CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
429 EFI_IMAGE_SCN_CNT_CODE
430 | EFI_IMAGE_SCN_MEM_EXECUTE
431 | EFI_IMAGE_SCN_MEM_READ);
432 CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
433 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
434 | EFI_IMAGE_SCN_MEM_WRITE
435 | EFI_IMAGE_SCN_MEM_READ);
436 }
437
438 void
439 WriteSections(
440 int (*Filter)(Elf_Shdr *)
441 )
442 {
443 UINT32 Idx;
444
445 //
446 // First: copy sections.
447 //
448 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
449 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
450 if ((*Filter)(Shdr)) {
451 switch (Shdr->sh_type) {
452 case SHT_PROGBITS:
453 /* Copy. */
454 memcpy(CoffFile + CoffSectionsOffset[Idx],
455 (UINT8*)Ehdr + Shdr->sh_offset,
456 Shdr->sh_size);
457 break;
458 case SHT_NOBITS:
459 memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
460 break;
461 default:
462 Error (NULL, 0, 0, InImageName, "unhandle section type %x",
463 (UINTN)Shdr->sh_type);
464 }
465 }
466 }
467
468 //
469 // Second: apply relocations.
470 //
471 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
472 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
473 if (RelShdr->sh_type != SHT_REL)
474 continue;
475 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
476 UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
477 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
478 UINT32 RelIdx;
479 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
480 UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
481
482 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
483 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
484 Elf_Sym *Sym = (Elf_Sym *)
485 (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
486 Elf_Shdr *SymShdr;
487 UINT8 *Targ;
488
489 if (Sym->st_shndx == SHN_UNDEF
490 || Sym->st_shndx == SHN_ABS
491 || Sym->st_shndx > Ehdr->e_shnum) {
492 Error (NULL, 0, 0, InImageName, "bad symbol definition");
493 }
494 SymShdr = GetShdrByIndex(Sym->st_shndx);
495
496 //
497 // Note: r_offset in a memory address.
498 // Convert it to a pointer in the coff file.
499 //
500 Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
501
502 switch (ELF_R_TYPE(Rel->r_info)) {
503 case R_386_NONE:
504 break;
505 case R_386_32:
506 //
507 // Absolute relocation.
508 //
509 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
510 + CoffSectionsOffset[Sym->st_shndx];
511 break;
512 case R_386_PC32:
513 //
514 // Relative relocation: Symbol - Ip + Addend
515 //
516 *(UINT32 *)Targ = *(UINT32 *)Targ
517 + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
518 - (SecOffset - SecShdr->sh_addr);
519 break;
520 default:
521 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
522 ELF_R_TYPE(Rel->r_info));
523 }
524 }
525 }
526 }
527 }
528
529 void
530 CoffAddFixupEntry(
531 UINT16 Val
532 )
533 {
534 *CoffEntryRel = Val;
535 CoffEntryRel++;
536 CoffBaseRel->SizeOfBlock += 2;
537 CoffOffset += 2;
538 }
539
540 void
541 CoffAddFixup(
542 UINT32 Offset,
543 UINT8 Type
544 )
545 {
546 if (CoffBaseRel == NULL
547 || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
548 if (CoffBaseRel != NULL) {
549 //
550 // Add a null entry (is it required ?)
551 //
552 CoffAddFixupEntry (0);
553 //
554 // Pad for alignment.
555 //
556 if (CoffOffset % 4 != 0)
557 CoffAddFixupEntry (0);
558 }
559
560 CoffFile = realloc
561 (CoffFile,
562 CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
563 memset(CoffFile + CoffOffset, 0,
564 sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
565
566 CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
567 CoffBaseRel->VirtualAddress = Offset & ~0xfff;
568 CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
569
570 CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
571 CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
572 }
573
574 //
575 // Fill the entry.
576 //
577 CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
578 }
579
580 void
581 WriteRelocations(
582 VOID
583 )
584 {
585 UINT32 Idx;
586 EFI_IMAGE_NT_HEADERS *NtHdr;
587 EFI_IMAGE_DATA_DIRECTORY *Dir;
588
589 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
590 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
591 if (RelShdr->sh_type == SHT_REL) {
592 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
593 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
594 UINT32 RelIdx;
595 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
596 Elf_Rel *Rel = (Elf_Rel *)
597 ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
598 switch (ELF_R_TYPE(Rel->r_info)) {
599 case R_386_NONE:
600 case R_386_PC32:
601 break;
602 case R_386_32:
603 CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
604 + (Rel->r_offset - SecShdr->sh_addr),
605 EFI_IMAGE_REL_BASED_HIGHLOW);
606 break;
607 default:
608 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
609 ELF_R_TYPE(Rel->r_info));
610 }
611 }
612 }
613 }
614 }
615
616 //
617 // Pad by adding empty entries.
618 //
619 while (CoffOffset & (CoffAlignment - 1)) {
620 CoffAddFixupEntry(0);
621 }
622
623 CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
624 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
625 | EFI_IMAGE_SCN_MEM_DISCARDABLE
626 | EFI_IMAGE_SCN_MEM_READ);
627
628 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
629 Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
630 Dir->VirtualAddress = RelocOffset;
631 Dir->Size = CoffOffset - RelocOffset;
632 }
633
634 void
635 WriteDebug(
636 VOID
637 )
638 {
639 UINT32 Len = strlen(InImageName) + 1;
640 UINT32 DebugOffset = CoffOffset;
641 EFI_IMAGE_NT_HEADERS *NtHdr;
642 EFI_IMAGE_DATA_DIRECTORY *DataDir;
643 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
644 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
645
646 CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
647 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
648 + Len;
649 CoffOffset = CoffAlign(CoffOffset);
650
651 CoffFile = realloc
652 (CoffFile, CoffOffset);
653 memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
654
655 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
656 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
657 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
658 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
659 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
660
661 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
662 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
663 strcpy ((PUCHAR)(Nb10 + 1), InImageName);
664
665 CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
666 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
667 | EFI_IMAGE_SCN_MEM_DISCARDABLE
668 | EFI_IMAGE_SCN_MEM_READ);
669
670 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
671 DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
672 DataDir->VirtualAddress = DebugOffset;
673 DataDir->Size = CoffOffset - DebugOffset;
674 }
675
676 void
677 ConvertElf (
678 UINT8 **FileBuffer,
679 UINTN *FileLength
680 )
681 {
682 EFI_IMAGE_NT_HEADERS *NtHdr;
683
684 //
685 // Check header, read section table.
686 //
687 Ehdr = (Elf32_Ehdr*)*FileBuffer;
688 if (!CheckElfHeader())
689 return;
690
691 //
692 // Compute sections new address.
693 //
694 ScanSections();
695
696 //
697 // Write and relocate sections.
698 //
699 WriteSections(IsTextShdr);
700 WriteSections(IsDataShdr);
701
702 //
703 // Translate and write relocations.
704 //
705 WriteRelocations();
706
707 //
708 // Write debug info.
709 //
710 WriteDebug();
711
712 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
713 NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
714
715 //
716 // Replace.
717 //
718 free(*FileBuffer);
719 *FileBuffer = CoffFile;
720 *FileLength = CoffOffset;
721 }
722 #endif // HAVE_ELF
723
724 int
725 main (
726 int argc,
727 char *argv[]
728 )
729 /*++
730
731 Routine Description:
732
733 Main function.
734
735 Arguments:
736
737 argc - Number of command line parameters.
738 argv - Array of pointers to command line parameter strings.
739
740 Returns:
741 STATUS_SUCCESS - Utility exits successfully.
742 STATUS_ERROR - Some error occurred during execution.
743
744 --*/
745 {
746 ULONG Type;
747 PUCHAR Ext;
748 PUCHAR p;
749 PUCHAR pe;
750 PUCHAR OutImageName;
751 UCHAR outname[500];
752 FILE *fpIn;
753 FILE *fpOut;
754 VOID *ZeroBuffer;
755 EFI_IMAGE_DOS_HEADER *DosHdr;
756 EFI_IMAGE_NT_HEADERS *PeHdr;
757 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
758 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
759 time_t TimeStamp;
760 struct tm TimeStruct;
761 EFI_IMAGE_DOS_HEADER BackupDosHdr;
762 ULONG Index;
763 ULONG Index1;
764 ULONG Index2;
765 ULONG Index3;
766 BOOLEAN TimeStampPresent;
767 UINTN AllignedRelocSize;
768 UINTN Delta;
769 EFI_IMAGE_SECTION_HEADER *SectionHeader;
770 UINT8 *FileBuffer;
771 UINTN FileLength;
772 RUNTIME_FUNCTION *RuntimeFunction;
773 UNWIND_INFO *UnwindInfo;
774
775 SetUtilityName (UTILITY_NAME);
776 //
777 // Assign to fix compile warning
778 //
779 OutImageName = NULL;
780 Type = 0;
781 Ext = 0;
782 TimeStamp = 0;
783 TimeStampPresent = FALSE;
784
785 if (argc == 1) {
786 Usage();
787 return STATUS_ERROR;
788 }
789
790 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
791 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
792 Usage();
793 return STATUS_ERROR;
794 }
795
796 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
797 Version();
798 return STATUS_ERROR;
799 }
800
801 //
802 // Look for -t time-date option first. If the time is "0", then
803 // skip it.
804 //
805 if ((argc > 2) && !strcmp (argv[1], "-t")) {
806 TimeStampPresent = TRUE;
807 if (strcmp (argv[2], "0") != 0) {
808 //
809 // Convert the string to a value
810 //
811 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
812 if (sscanf(
813 argv[2], "%d/%d/%d,%d:%d:%d",
814 &TimeStruct.tm_mon, /* months since January - [0,11] */
815 &TimeStruct.tm_mday, /* day of the month - [1,31] */
816 &TimeStruct.tm_year, /* years since 1900 */
817 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */
818 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */
819 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */
820 ) != 6) {
821 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
822 return STATUS_ERROR;
823 }
824 //
825 // Now fixup some of the fields
826 //
827 TimeStruct.tm_mon--;
828 TimeStruct.tm_year -= 1900;
829 //
830 // Sanity-check values?
831 // Convert
832 //
833 TimeStamp = mktime (&TimeStruct);
834 if (TimeStamp == (time_t) - 1) {
835 Error (NULL, 0, 0, argv[2], "failed to convert time");
836 return STATUS_ERROR;
837 }
838 }
839 //
840 // Skip over the args
841 //
842 argc -= 2;
843 argv += 2;
844 }
845 //
846 // Check for enough args
847 //
848 if (argc < 3) {
849 Usage ();
850 return STATUS_ERROR;
851 }
852
853 InImageName = argv[2];
854
855 if (argc == 4) {
856 OutImageName = argv[3];
857 }
858 //
859 // Get new image type
860 //
861 p = argv[1];
862 if (*p == '/' || *p == '\\') {
863 p += 1;
864 }
865
866 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {
867 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
868 Ext = ".efi";
869
870 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {
871 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
872 Ext = ".efi";
873
874 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {
875 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
876 Ext = ".efi";
877
878 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {
879 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
880 Ext = ".efi";
881 } else if (stricmp (p, "SEC") == 0) {
882 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
883 Ext = ".sec";
884 } else if (stricmp (p, "peim") == 0 ||
885 stricmp (p, "BASE") == 0 ||
886 stricmp (p, "PEI_CORE") == 0 ||
887 stricmp (p, "PEIM") == 0 ||
888 stricmp (p, "DXE_SMM_DRIVER") == 0 ||
889 stricmp (p, "TOOL") == 0 ||
890 stricmp (p, "UEFI_APPLICATION") == 0 ||
891 stricmp (p, "USER_DEFINED") == 0 ||
892 stricmp (p, "UEFI_DRIVER") == 0 ||
893 stricmp (p, "DXE_CORE") == 0
894 ) {
895 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
896 Ext = ".pei";
897 } else {
898 printf ("%s", p);
899 Usage ();
900 return STATUS_ERROR;
901 }
902 //
903 // open source file
904 //
905 fpIn = fopen (InImageName, "rb");
906 if (!fpIn) {
907 Error (NULL, 0, 0, InImageName, "failed to open input file for reading");
908 return STATUS_ERROR;
909 }
910
911 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
912
913 #ifdef HAVE_ELF
914 if (IsElfHeader(FileBuffer)) {
915 ConvertElf(&FileBuffer, &FileLength);
916 }
917 #endif
918 //
919 // Read the dos & pe hdrs of the image
920 //
921 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
922 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
923 Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");
924 fclose (fpIn);
925 return STATUS_ERROR;
926 }
927
928 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);
929 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
930 Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");
931 fclose (fpIn);
932 return STATUS_ERROR;
933 }
934
935 //
936 // open output file
937 //
938 strcpy (outname, InImageName);
939 pe = NULL;
940 for (p = outname; *p; p++) {
941 if (*p == '.') {
942 pe = p;
943 }
944 }
945
946 if (!pe) {
947 pe = p;
948 }
949
950 strcpy (pe, Ext);
951
952 if (!OutImageName) {
953 OutImageName = outname;
954 }
955
956 fpOut = fopen (OutImageName, "w+b");
957 if (!fpOut) {
958 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
959 fclose (fpIn);
960 return STATUS_ERROR;
961 }
962
963 //
964 // Zero all unused fields of the DOS header
965 //
966 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
967 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
968 DosHdr->e_magic = BackupDosHdr.e_magic;
969 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
970
971 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
972 FileBuffer[Index] = DosHdr->e_cp;
973 }
974
975 //
976 // Patch the PE header
977 //
978 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;
979 if (TimeStampPresent) {
980 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;
981 }
982
983 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
984 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;
985 Optional32->MajorLinkerVersion = 0;
986 Optional32->MinorLinkerVersion = 0;
987 Optional32->MajorOperatingSystemVersion = 0;
988 Optional32->MinorOperatingSystemVersion = 0;
989 Optional32->MajorImageVersion = 0;
990 Optional32->MinorImageVersion = 0;
991 Optional32->MajorSubsystemVersion = 0;
992 Optional32->MinorSubsystemVersion = 0;
993 Optional32->Win32VersionValue = 0;
994 Optional32->CheckSum = 0;
995 Optional32->SizeOfStackReserve = 0;
996 Optional32->SizeOfStackCommit = 0;
997 Optional32->SizeOfHeapReserve = 0;
998 Optional32->SizeOfHeapCommit = 0;
999
1000 //
1001 // Strip zero padding at the end of the .reloc section
1002 //
1003 if (Optional32->NumberOfRvaAndSizes >= 6) {
1004 if (Optional32->DataDirectory[5].Size != 0) {
1005 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1006 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
1007 //
1008 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
1009 //
1010 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {
1011 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;
1012 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
1013 //
1014 // Check to see if there is zero padding at the end of the base relocations
1015 //
1016 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
1017 //
1018 // Check to see if the base relocations are at the end of the file
1019 //
1020 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
1021 //
1022 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1023 //
1024 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1025 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1026 SectionHeader->SizeOfRawData = AllignedRelocSize;
1027 FileLength = Optional32->SizeOfImage;
1028 }
1029 }
1030 }
1031 }
1032 }
1033 }
1034 }
1035 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1036 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;
1037 Optional64->MajorLinkerVersion = 0;
1038 Optional64->MinorLinkerVersion = 0;
1039 Optional64->MajorOperatingSystemVersion = 0;
1040 Optional64->MinorOperatingSystemVersion = 0;
1041 Optional64->MajorImageVersion = 0;
1042 Optional64->MinorImageVersion = 0;
1043 Optional64->MajorSubsystemVersion = 0;
1044 Optional64->MinorSubsystemVersion = 0;
1045 Optional64->Win32VersionValue = 0;
1046 Optional64->CheckSum = 0;
1047 Optional64->SizeOfStackReserve = 0;
1048 Optional64->SizeOfStackCommit = 0;
1049 Optional64->SizeOfHeapReserve = 0;
1050 Optional64->SizeOfHeapCommit = 0;
1051
1052 //
1053 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
1054 //
1055 if (PeHdr->FileHeader.Machine == 0x8664) { // X64
1056 if (Optional64->NumberOfRvaAndSizes >= 4) {
1057 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {
1058 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1059 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
1060 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {
1061 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);
1062 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {
1063 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1064 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {
1065 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {
1066 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));
1067 if (UnwindInfo->Version == 1) {
1068 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));
1069 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));
1070 }
1071 }
1072 }
1073 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
1074 }
1075
1076 break;
1077 }
1078 }
1079 Optional64->DataDirectory[3].Size = 0;
1080 Optional64->DataDirectory[3].VirtualAddress = 0;
1081 }
1082 }
1083 }
1084
1085 //
1086 // Strip zero padding at the end of the .reloc section
1087 //
1088 if (Optional64->NumberOfRvaAndSizes >= 6) {
1089 if (Optional64->DataDirectory[5].Size != 0) {
1090 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1091 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
1092 //
1093 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
1094 //
1095 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {
1096 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;
1097 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
1098 //
1099 // Check to see if there is zero padding at the end of the base relocations
1100 //
1101 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
1102 //
1103 // Check to see if the base relocations are at the end of the file
1104 //
1105 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
1106 //
1107 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1108 //
1109 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1110 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1111 SectionHeader->SizeOfRawData = AllignedRelocSize;
1112 FileLength = Optional64->SizeOfImage;
1113 }
1114 }
1115 }
1116 }
1117 }
1118 }
1119 }
1120
1121 FWriteFile (fpOut, FileBuffer, FileLength);
1122
1123 //
1124 // Done
1125 //
1126 fclose (fpIn);
1127 fclose (fpOut);
1128 //
1129 // printf ("Created %s\n", OutImageName);
1130 //
1131 return STATUS_SUCCESS;
1132 }