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