]> git.proxmox.com Git - mirror_edk2.git/blame - 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
CommitLineData
878ddf1f 1/*++\r
2\r
18998564 3Copyright (c) 2004 - 2007, Intel Corporation \r
878ddf1f 4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 fwimage.c\r
15\r
16Abstract:\r
17\r
18 Converts a pe32+ image to an FW image type\r
19\r
20--*/\r
21\r
ce53a8c3 22#include "WinNtInclude.h"\r
23\r
8ba7afaf 24//\r
25// List of OS and CPU which support ELF to PE conversion\r
26//\r
27#if defined(linux)
28#if defined(i386)
29#define HAVE_ELF
30#endif
31#endif
32
878ddf1f 33#ifndef __GNUC__\r
34#include <windows.h>\r
35#endif\r
36#include <stdio.h>\r
37#include <stdlib.h>\r
38#include <string.h>\r
39#include <time.h>\r
8ba7afaf 40
41#ifdef HAVE_ELF
42#include <elf.h>
43#endif
878ddf1f 44\r
ce53a8c3 45#include <Common/UefiBaseTypes.h>\r
46#include <Common/EfiImage.h>\r
47\r
48#include "CommonLib.h"\r
49#include "EfiUtilityMsgs.c"\r
878ddf1f 50\r
f091efb3 51//\r
52// Version of this utility\r
53//\r
54#define UTILITY_NAME "FwImage"\r
55#define UTILITY_MAJOR_VERSION 1\r
56#define UTILITY_MINOR_VERSION 0\r
878ddf1f 57\r
58#ifdef __GNUC__\r
59typedef unsigned long ULONG;\r
60typedef unsigned char UCHAR;\r
61typedef unsigned char *PUCHAR;\r
62typedef unsigned short USHORT;\r
63#endif\r
64\r
8ba7afaf 65PUCHAR InImageName;\r
66\r
f091efb3 67static\r
68void\r
69Version (\r
70 VOID\r
71 )\r
72{\r
73 printf ("%s v%d.%d -EDK Utility for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
74 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
75}\r
76\r
77\r
878ddf1f 78VOID\r
79Usage (\r
80 VOID\r
81 )\r
82{\r
f091efb3 83 Version();\r
84 printf ("\nUsage: " UTILITY_NAME " {-t time-date} {-h|--help|-?|/?|-V|--version} \n\\r
85 [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\\r
86 DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\\r
8ba7afaf 87 USER_DEFINED] peimage [outimage]\n");\r
878ddf1f 88}\r
89\r
90static\r
91STATUS\r
92FCopyFile (\r
93 FILE *in,\r
94 FILE *out\r
95 )\r
96{\r
97 ULONG filesize;\r
98 ULONG offset;\r
99 ULONG length;\r
100 UCHAR Buffer[8 * 1024];\r
101\r
102 fseek (in, 0, SEEK_END);\r
103 filesize = ftell (in);\r
104\r
105 fseek (in, 0, SEEK_SET);\r
106 fseek (out, 0, SEEK_SET);\r
107\r
108 offset = 0;\r
109 while (offset < filesize) {\r
110 length = sizeof (Buffer);\r
111 if (filesize - offset < length) {\r
112 length = filesize - offset;\r
113 }\r
114\r
115 fread (Buffer, length, 1, in);\r
116 fwrite (Buffer, length, 1, out);\r
117 offset += length;\r
118 }\r
119\r
120 if ((ULONG) ftell (out) != filesize) {\r
121 Error (NULL, 0, 0, "write error", NULL);\r
122 return STATUS_ERROR;\r
123 }\r
124\r
125 return STATUS_SUCCESS;\r
126}\r
127\r
3edf127e 128static\r
129STATUS\r
130FReadFile (\r
131 FILE *in,\r
132 VOID **Buffer,\r
133 UINTN *Length\r
134 )\r
135{\r
136 fseek (in, 0, SEEK_END);\r
137 *Length = ftell (in);\r
138 *Buffer = malloc (*Length);\r
139 fseek (in, 0, SEEK_SET);\r
140 fread (*Buffer, *Length, 1, in);\r
141 return STATUS_SUCCESS;\r
142}\r
143\r
144static\r
145STATUS\r
146FWriteFile (\r
147 FILE *out,\r
148 VOID *Buffer,\r
149 UINTN Length\r
150 )\r
151{\r
152 fseek (out, 0, SEEK_SET);\r
153 fwrite (Buffer, Length, 1, out);\r
154 if ((ULONG) ftell (out) != Length) {\r
155 Error (NULL, 0, 0, "write error", NULL);\r
156 return STATUS_ERROR;\r
157 }\r
158 free (Buffer);\r
159 return STATUS_SUCCESS;\r
160}\r
161\r
8ba7afaf 162#ifdef HAVE_ELF
163INTN
164IsElfHeader(
165 UINT8 *FileBuffer
166)
167{
168 return (FileBuffer[EI_MAG0] == ELFMAG0
169 && FileBuffer[EI_MAG1] == ELFMAG1
170 && FileBuffer[EI_MAG2] == ELFMAG2
171 && FileBuffer[EI_MAG3] == ELFMAG3);
172}
173
174typedef Elf32_Shdr Elf_Shdr;
175typedef Elf32_Ehdr Elf_Ehdr;
176typedef Elf32_Rel Elf_Rel;
177typedef Elf32_Sym Elf_Sym;
178#define ELFCLASS ELFCLASS32
179#define ELF_R_TYPE(r) ELF32_R_TYPE(r)
180#define ELF_R_SYM(r) ELF32_R_SYM(r)
181
182//
183// Well known ELF structures.
184//
185Elf_Ehdr *Ehdr;
186Elf_Shdr *ShdrBase;
187
188//
189// PE section alignment.
190//
191const UINT32 CoffAlignment = 0x20;
192const UINT32 CoffNbrSections = 4;
193
194//
195// Current offset in coff file.
196//
197UINT32 CoffOffset;
198
199//
200// Result Coff file in memory.
201//
202UINT8 *CoffFile;
203
204//
205// Offset in Coff file of headers and sections.
206//
207UINT32 NtHdrOffset;
208UINT32 TableOffset;
209UINT32 TextOffset;
210UINT32 DataOffset;
211UINT32 RelocOffset;
212
213//
214// ELF sections to offset in Coff file.
215//
216UINT32 *CoffSectionsOffset;
217
218EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
219UINT16 *CoffEntryRel;
220
221UINT32
222CoffAlign(
223 UINT32 Offset
224 )
225{
226 return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
227}
228
229Elf_Shdr *
230GetShdrByIndex(
231 UINT32 Num
232 )
233{
234 if (Num >= Ehdr->e_shnum)
235 return NULL;
236 return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
237}
238
239INTN
240CheckElfHeader(
241 VOID
242 )
18998564 243{\r
8ba7afaf 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;
18998564 257\r
258 //\r
259 // Find the section header table\r
260 //
8ba7afaf 261 ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
262
18998564 263 CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));\r
264
265 memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));\r
8ba7afaf 266 return 1;
267}
268
269int
270IsTextShdr(
271 Elf_Shdr *Shdr
272 )
273{
274 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
275}
18998564 276\r
8ba7afaf 277int
278IsDataShdr(
279 Elf_Shdr *Shdr
280 )
281{
282 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
283}
284
285void
286CreateSectionHeader(
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
310void
311ScanSections(
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);
18998564 338 if (IsTextShdr(shdr)) {\r
339 //\r
340 // Align the coff offset\r
341 // \r
342 CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
8ba7afaf 343 /* Relocate entry. */
18998564 344 if ((Ehdr->e_entry >= shdr->sh_addr) && \r
345 (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
346 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
8ba7afaf 347 }
18998564 348 CoffSectionsOffset[i] = CoffOffset;\r
8ba7afaf 349 CoffOffset += shdr->sh_size;
18998564 350 }\r
351 }\r
8ba7afaf 352 CoffOffset = CoffAlign(CoffOffset);
18998564 353\r
8ba7afaf 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
426void
427WriteSections(
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
517void
518CoffAddFixupEntry(
519 UINT16 Val
520 )
521{
522 *CoffEntryRel = Val;
523 CoffEntryRel++;
524 CoffBaseRel->SizeOfBlock += 2;
525 CoffOffset += 2;
526}
527
528void
529CoffAddFixup(
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
568void
569WriteRelocations(
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
622void
623WriteDebug(
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
664void
665ConvertElf (
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
878ddf1f 712int\r
713main (\r
714 int argc,\r
715 char *argv[]\r
716 )\r
717/*++\r
718\r
719Routine Description:\r
720\r
721 Main function.\r
722\r
723Arguments:\r
724\r
725 argc - Number of command line parameters.\r
726 argv - Array of pointers to command line parameter strings.\r
727\r
728Returns:\r
729 STATUS_SUCCESS - Utility exits successfully.\r
730 STATUS_ERROR - Some error occurred during execution.\r
731\r
732--*/\r
733{\r
734 ULONG Type;\r
735 PUCHAR Ext;\r
736 PUCHAR p;\r
737 PUCHAR pe;\r
738 PUCHAR OutImageName;\r
739 UCHAR outname[500];\r
740 FILE *fpIn;\r
741 FILE *fpOut;\r
3edf127e 742 VOID *ZeroBuffer;\r
743 EFI_IMAGE_DOS_HEADER *DosHdr;\r
744 EFI_IMAGE_NT_HEADERS *PeHdr;\r
745 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;\r
746 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;\r
878ddf1f 747 time_t TimeStamp;\r
748 struct tm TimeStruct;\r
749 EFI_IMAGE_DOS_HEADER BackupDosHdr;\r
750 ULONG Index;\r
3edf127e 751 ULONG Index1;\r
307fd197 752 ULONG Index2;\r
753 ULONG Index3;\r
878ddf1f 754 BOOLEAN TimeStampPresent;\r
0411bcaf 755 UINTN AllignedRelocSize;\r
3edf127e 756 UINTN Delta;\r
757 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
758 UINT8 *FileBuffer;\r
759 UINTN FileLength;\r
307fd197 760 RUNTIME_FUNCTION *RuntimeFunction;\r
761 UNWIND_INFO *UnwindInfo;\r
878ddf1f 762\r
763 SetUtilityName (UTILITY_NAME);\r
764 //\r
765 // Assign to fix compile warning\r
766 //\r
767 OutImageName = NULL;\r
768 Type = 0;\r
769 Ext = 0;\r
770 TimeStamp = 0;\r
771 TimeStampPresent = FALSE;\r
772\r
db608e6b 773 if (argc == 1) {\r
f091efb3 774 Usage();\r
775 return STATUS_ERROR;\r
776 }\r
777 \r
778 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
779 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
780 Usage();\r
781 return STATUS_ERROR;\r
782 }\r
783 \r
784 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
785 Version();\r
786 return STATUS_ERROR;\r
787 }\r
788 \r
878ddf1f 789 //\r
790 // Look for -t time-date option first. If the time is "0", then\r
791 // skip it.\r
792 //\r
793 if ((argc > 2) && !strcmp (argv[1], "-t")) {\r
794 TimeStampPresent = TRUE;\r
795 if (strcmp (argv[2], "0") != 0) {\r
796 //\r
797 // Convert the string to a value\r
798 //\r
799 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));\r
800 if (sscanf(\r
801 argv[2], "%d/%d/%d,%d:%d:%d",\r
802 &TimeStruct.tm_mon, /* months since January - [0,11] */\r
803 &TimeStruct.tm_mday, /* day of the month - [1,31] */\r
804 &TimeStruct.tm_year, /* years since 1900 */\r
805 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */\r
806 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */\r
807 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */\r
808 ) != 6) {\r
809 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");\r
810 return STATUS_ERROR;\r
811 }\r
812 //\r
813 // Now fixup some of the fields\r
814 //\r
815 TimeStruct.tm_mon--;\r
816 TimeStruct.tm_year -= 1900;\r
817 //\r
818 // Sanity-check values?\r
819 // Convert\r
820 //\r
821 TimeStamp = mktime (&TimeStruct);\r
822 if (TimeStamp == (time_t) - 1) {\r
823 Error (NULL, 0, 0, argv[2], "failed to convert time");\r
824 return STATUS_ERROR;\r
825 }\r
826 }\r
827 //\r
828 // Skip over the args\r
829 //\r
830 argc -= 2;\r
831 argv += 2;\r
832 }\r
833 //\r
834 // Check for enough args\r
835 //\r
836 if (argc < 3) {\r
837 Usage ();\r
838 return STATUS_ERROR;\r
839 }\r
840\r
8ba7afaf 841 InImageName = argv[2];\r
842\r
878ddf1f 843 if (argc == 4) {\r
844 OutImageName = argv[3];\r
845 }\r
846 //\r
847 // Get new image type\r
848 //\r
849 p = argv[1];\r
850 if (*p == '/' || *p == '\\') {\r
851 p += 1;\r
852 }\r
853\r
8a286638 854 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {\r
878ddf1f 855 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
856 Ext = ".efi";\r
857\r
8a286638 858 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {\r
878ddf1f 859 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
860 Ext = ".efi";\r
861\r
8a286638 862 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {\r
878ddf1f 863 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
864 Ext = ".efi";\r
865\r
8a286638 866 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {\r
878ddf1f 867 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
868 Ext = ".efi";\r
8a286638 869 } else if (stricmp (p, "SEC") == 0) {\r
878ddf1f 870 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
871 Ext = ".sec";\r
872 } else if (stricmp (p, "peim") == 0 ||\r
8a286638 873 stricmp (p, "BASE") == 0 ||\r
878ddf1f 874 stricmp (p, "PEI_CORE") == 0 ||\r
8a286638 875 stricmp (p, "PEIM") == 0 ||\r
876 stricmp (p, "DXE_SMM_DRIVER") == 0 ||\r
877 stricmp (p, "TOOL") == 0 ||\r
878 stricmp (p, "UEFI_APPLICATION") == 0 ||\r
879 stricmp (p, "USER_DEFINED") == 0 ||\r
880 stricmp (p, "UEFI_DRIVER") == 0 ||\r
881 stricmp (p, "DXE_CORE") == 0\r
878ddf1f 882 ) {\r
883 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
884 Ext = ".pei";\r
885 } else {\r
8a286638 886 printf ("%s", p);\r
878ddf1f 887 Usage ();\r
888 return STATUS_ERROR;\r
889 }\r
890 //\r
891 // open source file\r
892 //\r
8ba7afaf 893 fpIn = fopen (InImageName, "rb");\r
878ddf1f 894 if (!fpIn) {\r
8ba7afaf 895 Error (NULL, 0, 0, InImageName, "failed to open input file for reading");\r
878ddf1f 896 return STATUS_ERROR;\r
897 }\r
3edf127e 898\r
899 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
900\r
8ba7afaf 901#ifdef HAVE_ELF
902 if (IsElfHeader(FileBuffer)) {
903 ConvertElf(&FileBuffer, &FileLength);
904 }
905#endif
878ddf1f 906 //\r
907 // Read the dos & pe hdrs of the image\r
908 //\r
3edf127e 909 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
910 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
8ba7afaf 911 Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");\r
878ddf1f 912 fclose (fpIn);\r
913 return STATUS_ERROR;\r
914 }\r
915\r
3edf127e 916 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
917 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
8ba7afaf 918 Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");\r
878ddf1f 919 fclose (fpIn);\r
920 return STATUS_ERROR;\r
921 }\r
3edf127e 922\r
878ddf1f 923 //\r
924 // open output file\r
925 //\r
8ba7afaf 926 strcpy (outname, InImageName);\r
878ddf1f 927 pe = NULL;\r
928 for (p = outname; *p; p++) {\r
929 if (*p == '.') {\r
930 pe = p;\r
931 }\r
932 }\r
933\r
934 if (!pe) {\r
935 pe = p;\r
936 }\r
937\r
938 strcpy (pe, Ext);\r
939\r
940 if (!OutImageName) {\r
941 OutImageName = outname;\r
942 }\r
943\r
944 fpOut = fopen (OutImageName, "w+b");\r
945 if (!fpOut) {\r
946 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
947 fclose (fpIn);\r
948 return STATUS_ERROR;\r
949 }\r
3edf127e 950\r
878ddf1f 951 //\r
952 // Zero all unused fields of the DOS header\r
953 //\r
3edf127e 954 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
955 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
956 DosHdr->e_magic = BackupDosHdr.e_magic;\r
957 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
958\r
959 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
960 FileBuffer[Index] = DosHdr->e_cp;\r
878ddf1f 961 }\r
3edf127e 962\r
878ddf1f 963 //\r
8ba7afaf 964 // Patch the PE header\r
878ddf1f 965 //\r
3edf127e 966 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
878ddf1f 967 if (TimeStampPresent) {\r
3edf127e 968 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
969 }\r
970\r
3edf127e 971 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
972 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
973 Optional32->MajorLinkerVersion = 0;\r
974 Optional32->MinorLinkerVersion = 0;\r
975 Optional32->MajorOperatingSystemVersion = 0;\r
976 Optional32->MinorOperatingSystemVersion = 0;\r
977 Optional32->MajorImageVersion = 0;\r
978 Optional32->MinorImageVersion = 0;\r
979 Optional32->MajorSubsystemVersion = 0;\r
980 Optional32->MinorSubsystemVersion = 0;\r
981 Optional32->Win32VersionValue = 0;\r
982 Optional32->CheckSum = 0;\r
983 Optional32->SizeOfStackReserve = 0;\r
984 Optional32->SizeOfStackCommit = 0;\r
985 Optional32->SizeOfHeapReserve = 0;\r
986 Optional32->SizeOfHeapCommit = 0;\r
987\r
3edf127e 988 //\r
989 // Strip zero padding at the end of the .reloc section \r
990 //\r
991 if (Optional32->NumberOfRvaAndSizes >= 6) {\r
992 if (Optional32->DataDirectory[5].Size != 0) {\r
993 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
994 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 995 //\r
996 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
997 //\r
3edf127e 998 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
0411bcaf 999 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;\r
1000 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
1001 //\r
1002 // Check to see if there is zero padding at the end of the base relocations\r
1003 //\r
1004 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1005 //\r
1006 // Check to see if the base relocations are at the end of the file\r
1007 //\r
1008 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
1009 //\r
1010 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1011 //\r
1012 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1013 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1014 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1015 FileLength = Optional32->SizeOfImage;\r
1016 }\r
1017 }\r
3edf127e 1018 }\r
1019 }\r
1020 }\r
1021 }\r
1022 } \r
1023 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1024 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
1025 Optional64->MajorLinkerVersion = 0;\r
1026 Optional64->MinorLinkerVersion = 0;\r
1027 Optional64->MajorOperatingSystemVersion = 0;\r
1028 Optional64->MinorOperatingSystemVersion = 0;\r
1029 Optional64->MajorImageVersion = 0;\r
1030 Optional64->MinorImageVersion = 0;\r
1031 Optional64->MajorSubsystemVersion = 0;\r
1032 Optional64->MinorSubsystemVersion = 0;\r
1033 Optional64->Win32VersionValue = 0;\r
1034 Optional64->CheckSum = 0;\r
1035 Optional64->SizeOfStackReserve = 0;\r
1036 Optional64->SizeOfStackCommit = 0;\r
1037 Optional64->SizeOfHeapReserve = 0;\r
1038 Optional64->SizeOfHeapCommit = 0;\r
1039\r
1040 //\r
1041 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
1042 //\r
1043 if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
1044 if (Optional64->NumberOfRvaAndSizes >= 4) {\r
1045 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
1046 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1047 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1048 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
307fd197 1049 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);\r
1050 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {\r
1051 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1052 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {\r
1053 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {\r
1054 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));\r
1055 if (UnwindInfo->Version == 1) {\r
1056 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));\r
1057 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));\r
1058 }\r
1059 }\r
1060 }\r
1061 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));\r
3edf127e 1062 }\r
d9e0f88e 1063\r
1064 break;\r
3edf127e 1065 }\r
1066 }\r
1067 Optional64->DataDirectory[3].Size = 0;\r
1068 Optional64->DataDirectory[3].VirtualAddress = 0;\r
1069 }\r
1070 }\r
1071 }\r
1072\r
1073 //\r
1074 // Strip zero padding at the end of the .reloc section \r
1075 //\r
1076 if (Optional64->NumberOfRvaAndSizes >= 6) {\r
1077 if (Optional64->DataDirectory[5].Size != 0) {\r
1078 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1079 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
0411bcaf 1080 //\r
1081 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1082 //\r
3edf127e 1083 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
0411bcaf 1084 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;\r
1085 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
1086 //\r
1087 // Check to see if there is zero padding at the end of the base relocations\r
1088 //\r
1089 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1090 //\r
1091 // Check to see if the base relocations are at the end of the file\r
1092 //\r
1093 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
1094 //\r
1095 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1096 //\r
1097 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1098 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1099 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1100 FileLength = Optional64->SizeOfImage;\r
1101 }\r
1102 }\r
3edf127e 1103 }\r
1104 }\r
1105 }\r
1106 }\r
1107 }\r
1108\r
3edf127e 1109 FWriteFile (fpOut, FileBuffer, FileLength);\r
878ddf1f 1110\r
1111 //\r
1112 // Done\r
1113 //\r
1114 fclose (fpIn);\r
1115 fclose (fpOut);\r
1116 //\r
1117 // printf ("Created %s\n", OutImageName);\r
1118 //\r
1119 return STATUS_SUCCESS;\r
1120}\r