]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/BasePeCoff.c
Sync BaseTool trunk (version r2599) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / C / Common / BasePeCoff.c
1 /** @file
2
3 Functions to get info and load PE/COFF image.
4
5 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
6 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <Common/UefiBaseTypes.h>
18 #include <CommonLib.h>
19 #include <IndustryStandard/PeImage.h>
20 #include "PeCoffLib.h"
21
22 typedef union {
23 VOID *Header;
24 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
25 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
26 } EFI_IMAGE_OPTIONAL_HEADER_POINTER;
27
28 STATIC
29 RETURN_STATUS
30 PeCoffLoaderGetPeHeader (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
32 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
33 OUT EFI_TE_IMAGE_HEADER **TeHdr
34 );
35
36 STATIC
37 RETURN_STATUS
38 PeCoffLoaderCheckImageType (
39 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
40 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
41 IN EFI_TE_IMAGE_HEADER *TeHdr
42 );
43
44 STATIC
45 VOID *
46 PeCoffLoaderImageAddress (
47 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
48 IN UINTN Address
49 );
50
51 RETURN_STATUS
52 PeCoffLoaderRelocateIa32Image (
53 IN UINT16 *Reloc,
54 IN OUT CHAR8 *Fixup,
55 IN OUT CHAR8 **FixupData,
56 IN UINT64 Adjust
57 );
58
59 RETURN_STATUS
60 PeCoffLoaderRelocateX64Image (
61 IN UINT16 *Reloc,
62 IN OUT CHAR8 *Fixup,
63 IN OUT CHAR8 **FixupData,
64 IN UINT64 Adjust
65 );
66
67 RETURN_STATUS
68 PeCoffLoaderRelocateIpfImage (
69 IN UINT16 *Reloc,
70 IN OUT CHAR8 *Fixup,
71 IN OUT CHAR8 **FixupData,
72 IN UINT64 Adjust
73 );
74
75 RETURN_STATUS
76 PeCoffLoaderRelocateArmImage (
77 IN UINT16 **Reloc,
78 IN OUT CHAR8 *Fixup,
79 IN OUT CHAR8 **FixupData,
80 IN UINT64 Adjust
81 );
82
83 RETURN_STATUS
84 PeCoffLoaderRelocateAArch64Image (
85 IN UINT16 *Reloc,
86 IN OUT CHAR8 *Fixup,
87 IN OUT CHAR8 **FixupData,
88 IN UINT64 Adjust
89 );
90
91 STATIC
92 RETURN_STATUS
93 PeCoffLoaderGetPeHeader (
94 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
95 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
96 OUT EFI_TE_IMAGE_HEADER **TeHdr
97 )
98 /*++
99
100 Routine Description:
101
102 Retrieves the PE or TE Header from a PE/COFF or TE image
103
104 Arguments:
105
106 ImageContext - The context of the image being loaded
107
108 PeHdr - The buffer in which to return the PE header
109
110 TeHdr - The buffer in which to return the TE header
111
112 Returns:
113
114 RETURN_SUCCESS if the PE or TE Header is read,
115 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
116
117 --*/
118 {
119 RETURN_STATUS Status;
120 EFI_IMAGE_DOS_HEADER DosHdr;
121 UINTN Size;
122
123 ImageContext->IsTeImage = FALSE;
124 //
125 // Read the DOS image headers
126 //
127 Size = sizeof (EFI_IMAGE_DOS_HEADER);
128 Status = ImageContext->ImageRead (
129 ImageContext->Handle,
130 0,
131 &Size,
132 &DosHdr
133 );
134 if (RETURN_ERROR (Status)) {
135 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
136 return Status;
137 }
138
139 ImageContext->PeCoffHeaderOffset = 0;
140 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
141 //
142 // DOS image header is present, so read the PE header after the DOS image header
143 //
144 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
145 }
146 //
147 // Get the PE/COFF Header pointer
148 //
149 *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
150 if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
151 //
152 // Check the PE/COFF Header Signature. If not, then try to get a TE header
153 //
154 *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr;
155 if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
156 return RETURN_UNSUPPORTED;
157 }
158 ImageContext->IsTeImage = TRUE;
159 }
160
161 return RETURN_SUCCESS;
162 }
163
164 STATIC
165 RETURN_STATUS
166 PeCoffLoaderCheckImageType (
167 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
168 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
169 IN EFI_TE_IMAGE_HEADER *TeHdr
170 )
171 /*++
172
173 Routine Description:
174
175 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
176
177 Arguments:
178
179 ImageContext - The context of the image being loaded
180
181 PeHdr - The buffer in which to return the PE header
182
183 TeHdr - The buffer in which to return the TE header
184
185 Returns:
186
187 RETURN_SUCCESS if the PE/COFF or TE image is supported
188 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
189
190 --*/
191 {
192 //
193 // See if the machine type is supported.
194 // We support a native machine type (IA-32/Itanium-based)
195 //
196 if (ImageContext->IsTeImage == FALSE) {
197 ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;
198 } else {
199 ImageContext->Machine = TeHdr->Machine;
200 }
201
202 if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \
203 ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \
204 ImageContext->Machine != EFI_IMAGE_MACHINE_X64 && \
205 ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \
206 ImageContext->Machine != EFI_IMAGE_MACHINE_EBC && \
207 ImageContext->Machine != EFI_IMAGE_MACHINE_AARCH64) {
208 if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {
209 //
210 // There are two types of ARM images. Pure ARM and ARM/Thumb.
211 // If we see the ARM say it is the ARM/Thumb so there is only
212 // a single machine type we need to check for ARM.
213 //
214 ImageContext->Machine = EFI_IMAGE_MACHINE_ARMT;
215 if (ImageContext->IsTeImage == FALSE) {
216 PeHdr->Pe32.FileHeader.Machine = ImageContext->Machine;
217 } else {
218 TeHdr->Machine = ImageContext->Machine;
219 }
220
221 } else {
222 //
223 // unsupported PeImage machine type
224 //
225 return RETURN_UNSUPPORTED;
226 }
227 }
228
229 //
230 // See if the image type is supported. We support EFI Applications,
231 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
232 //
233 if (ImageContext->IsTeImage == FALSE) {
234 ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;
235 } else {
236 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
237 }
238
239 if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
240 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \
241 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \
242 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {
243 //
244 // upsupported PeImage subsystem type
245 //
246 return RETURN_UNSUPPORTED;
247 }
248
249 return RETURN_SUCCESS;
250 }
251
252 RETURN_STATUS
253 EFIAPI
254 PeCoffLoaderGetImageInfo (
255 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
256 )
257 /*++
258
259 Routine Description:
260
261 Retrieves information on a PE/COFF image
262
263 Arguments:
264
265 This - Calling context
266 ImageContext - The context of the image being loaded
267
268 Returns:
269
270 RETURN_SUCCESS - The information on the PE/COFF image was collected.
271 RETURN_INVALID_PARAMETER - ImageContext is NULL.
272 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
273 Otherwise - The error status from reading the PE/COFF image using the
274 ImageContext->ImageRead() function
275
276 --*/
277 {
278 RETURN_STATUS Status;
279 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
280 EFI_TE_IMAGE_HEADER *TeHdr;
281 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
282 UINTN Size;
283 UINTN Index;
284 UINTN DebugDirectoryEntryRva;
285 UINTN DebugDirectoryEntryFileOffset;
286 UINTN SectionHeaderOffset;
287 EFI_IMAGE_SECTION_HEADER SectionHeader;
288 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
289 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
290
291 PeHdr = NULL;
292 TeHdr = NULL;
293 DebugDirectoryEntry = NULL;
294 DebugDirectoryEntryRva = 0;
295
296 if (NULL == ImageContext) {
297 return RETURN_INVALID_PARAMETER;
298 }
299 //
300 // Assume success
301 //
302 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
303
304 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
305 if (RETURN_ERROR (Status)) {
306 return Status;
307 }
308
309 //
310 // Verify machine type
311 //
312 Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);
313 if (RETURN_ERROR (Status)) {
314 return Status;
315 }
316 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
317
318 //
319 // Retrieve the base address of the image
320 //
321 if (!(ImageContext->IsTeImage)) {
322 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
323 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;
324 } else {
325 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;
326 }
327 } else {
328 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
329 }
330 //
331 // Initialize the alternate destination address to 0 indicating that it
332 // should not be used.
333 //
334 ImageContext->DestinationAddress = 0;
335
336 //
337 // Initialize the codeview pointer.
338 //
339 ImageContext->CodeView = NULL;
340 ImageContext->PdbPointer = NULL;
341
342 //
343 // Three cases with regards to relocations:
344 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
345 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
346 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
347 // has no base relocs to apply
348 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
349 //
350 // Look at the file header to determine if relocations have been stripped, and
351 // save this info in the image context for later use.
352 //
353 if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
354 ImageContext->RelocationsStripped = TRUE;
355 } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0)) {
356 ImageContext->RelocationsStripped = TRUE;
357 } else {
358 ImageContext->RelocationsStripped = FALSE;
359 }
360
361 if (!(ImageContext->IsTeImage)) {
362
363 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
364 ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage;
365 ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment;
366 ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders;
367
368 //
369 // Modify ImageSize to contain .PDB file name if required and initialize
370 // PdbRVA field...
371 //
372 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
373 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
374 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
375 }
376 } else {
377 ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage;
378 ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment;
379 ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders;
380
381 //
382 // Modify ImageSize to contain .PDB file name if required and initialize
383 // PdbRVA field...
384 //
385 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
386 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
387 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
388 }
389 }
390
391 if (DebugDirectoryEntryRva != 0) {
392 //
393 // Determine the file offset of the debug directory... This means we walk
394 // the sections to find which section contains the RVA of the debug
395 // directory
396 //
397 DebugDirectoryEntryFileOffset = 0;
398
399 SectionHeaderOffset = (UINTN)(
400 ImageContext->PeCoffHeaderOffset +
401 sizeof (UINT32) +
402 sizeof (EFI_IMAGE_FILE_HEADER) +
403 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
404 );
405
406 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {
407 //
408 // Read section header from file
409 //
410 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
411 Status = ImageContext->ImageRead (
412 ImageContext->Handle,
413 SectionHeaderOffset,
414 &Size,
415 &SectionHeader
416 );
417 if (RETURN_ERROR (Status)) {
418 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
419 return Status;
420 }
421
422 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
423 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
424 DebugDirectoryEntryFileOffset =
425 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
426 break;
427 }
428
429 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
430 }
431
432 if (DebugDirectoryEntryFileOffset != 0) {
433 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
434 //
435 // Read next debug directory entry
436 //
437 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
438 Status = ImageContext->ImageRead (
439 ImageContext->Handle,
440 DebugDirectoryEntryFileOffset + Index,
441 &Size,
442 &DebugEntry
443 );
444 if (RETURN_ERROR (Status)) {
445 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
446 return Status;
447 }
448
449 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
450 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
451 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
452 ImageContext->ImageSize += DebugEntry.SizeOfData;
453 }
454
455 return RETURN_SUCCESS;
456 }
457 }
458 }
459 }
460 } else {
461 ImageContext->ImageSize = 0;
462 ImageContext->SectionAlignment = 4096;
463 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;
464
465 DebugDirectoryEntry = &TeHdr->DataDirectory[1];
466 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
467 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
468
469 DebugDirectoryEntryFileOffset = 0;
470
471 for (Index = 0; Index < TeHdr->NumberOfSections;) {
472 //
473 // Read section header from file
474 //
475 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
476 Status = ImageContext->ImageRead (
477 ImageContext->Handle,
478 SectionHeaderOffset,
479 &Size,
480 &SectionHeader
481 );
482 if (RETURN_ERROR (Status)) {
483 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
484 return Status;
485 }
486
487 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
488 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
489 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
490 SectionHeader.VirtualAddress +
491 SectionHeader.PointerToRawData +
492 sizeof (EFI_TE_IMAGE_HEADER) -
493 TeHdr->StrippedSize;
494
495 //
496 // File offset of the debug directory was found, if this is not the last
497 // section, then skip to the last section for calculating the image size.
498 //
499 if (Index < (UINTN) TeHdr->NumberOfSections - 1) {
500 SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
501 Index = TeHdr->NumberOfSections - 1;
502 continue;
503 }
504 }
505
506 //
507 // In Te image header there is not a field to describe the ImageSize.
508 // Actually, the ImageSize equals the RVA plus the VirtualSize of
509 // the last section mapped into memory (Must be rounded up to
510 // a mulitple of Section Alignment). Per the PE/COFF specification, the
511 // section headers in the Section Table must appear in order of the RVA
512 // values for the corresponding sections. So the ImageSize can be determined
513 // by the RVA and the VirtualSize of the last section header in the
514 // Section Table.
515 //
516 if ((++Index) == (UINTN) TeHdr->NumberOfSections) {
517 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
518 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
519 }
520
521 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
522 }
523
524 if (DebugDirectoryEntryFileOffset != 0) {
525 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
526 //
527 // Read next debug directory entry
528 //
529 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
530 Status = ImageContext->ImageRead (
531 ImageContext->Handle,
532 DebugDirectoryEntryFileOffset,
533 &Size,
534 &DebugEntry
535 );
536 if (RETURN_ERROR (Status)) {
537 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
538 return Status;
539 }
540
541 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
542 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
543 return RETURN_SUCCESS;
544 }
545 }
546 }
547 }
548
549 return RETURN_SUCCESS;
550 }
551
552 STATIC
553 VOID *
554 PeCoffLoaderImageAddress (
555 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
556 IN UINTN Address
557 )
558 /*++
559
560 Routine Description:
561
562 Converts an image address to the loaded address
563
564 Arguments:
565
566 ImageContext - The context of the image being loaded
567
568 Address - The address to be converted to the loaded address
569
570 Returns:
571
572 NULL if the address can not be converted, otherwise, the converted address
573
574 --*/
575 {
576 if (Address >= ImageContext->ImageSize) {
577 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
578 return NULL;
579 }
580
581 return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);
582 }
583
584 RETURN_STATUS
585 EFIAPI
586 PeCoffLoaderRelocateImage (
587 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
588 )
589 /*++
590
591 Routine Description:
592
593 Relocates a PE/COFF image in memory
594
595 Arguments:
596
597 This - Calling context
598
599 ImageContext - Contains information on the loaded image to relocate
600
601 Returns:
602
603 RETURN_SUCCESS if the PE/COFF image was relocated
604 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
605 RETURN_UNSUPPORTED not support
606
607 --*/
608 {
609 RETURN_STATUS Status;
610 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
611 EFI_TE_IMAGE_HEADER *TeHdr;
612 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
613 UINT64 Adjust;
614 EFI_IMAGE_BASE_RELOCATION *RelocBase;
615 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
616 UINT16 *Reloc;
617 UINT16 *RelocEnd;
618 CHAR8 *Fixup;
619 CHAR8 *FixupBase;
620 UINT16 *F16;
621 UINT32 *F32;
622 CHAR8 *FixupData;
623 PHYSICAL_ADDRESS BaseAddress;
624 UINT16 MachineType;
625 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
626
627 PeHdr = NULL;
628 TeHdr = NULL;
629 //
630 // Assume success
631 //
632 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
633
634 //
635 // If there are no relocation entries, then we are done
636 //
637 if (ImageContext->RelocationsStripped) {
638 return RETURN_SUCCESS;
639 }
640
641 //
642 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
643 //
644 BaseAddress = ImageContext->DestinationAddress;
645
646 if (!(ImageContext->IsTeImage)) {
647 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress +
648 ImageContext->PeCoffHeaderOffset);
649 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
650 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
651 Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;
652 OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;
653 MachineType = ImageContext->Machine;
654 //
655 // Find the relocation block
656 //
657 // Per the PE/COFF spec, you can't assume that a given data directory
658 // is present in the image. You have to check the NumberOfRvaAndSizes in
659 // the optional header to verify a desired directory entry is there.
660 //
661 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
662 RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
663 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
664 RelocBaseEnd = PeCoffLoaderImageAddress (
665 ImageContext,
666 RelocDir->VirtualAddress + RelocDir->Size - 1
667 );
668 } else {
669 //
670 // Set base and end to bypass processing below.
671 //
672 RelocBase = RelocBaseEnd = 0;
673 }
674 } else {
675 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
676 OptionHeader.Optional64->ImageBase = BaseAddress;
677 MachineType = ImageContext->Machine;
678 //
679 // Find the relocation block
680 //
681 // Per the PE/COFF spec, you can't assume that a given data directory
682 // is present in the image. You have to check the NumberOfRvaAndSizes in
683 // the optional header to verify a desired directory entry is there.
684 //
685 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
686 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
687 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
688 RelocBaseEnd = PeCoffLoaderImageAddress (
689 ImageContext,
690 RelocDir->VirtualAddress + RelocDir->Size - 1
691 );
692 } else {
693 //
694 // Set base and end to bypass processing below.
695 //
696 RelocBase = RelocBaseEnd = 0;
697 }
698 }
699 } else {
700 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
701 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
702 TeHdr->ImageBase = (UINT64) (BaseAddress);
703 MachineType = TeHdr->Machine;
704
705 //
706 // Find the relocation block
707 //
708 RelocDir = &TeHdr->DataDirectory[0];
709 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
710 ImageContext->ImageAddress +
711 RelocDir->VirtualAddress +
712 sizeof(EFI_TE_IMAGE_HEADER) -
713 TeHdr->StrippedSize
714 );
715 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
716 }
717
718 //
719 // Run the relocation information and apply the fixups
720 //
721 FixupData = ImageContext->FixupData;
722 while (RelocBase < RelocBaseEnd) {
723
724 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
725 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
726 if (!(ImageContext->IsTeImage)) {
727 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
728 } else {
729 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
730 RelocBase->VirtualAddress +
731 sizeof(EFI_TE_IMAGE_HEADER) -
732 TeHdr->StrippedSize
733 );
734 }
735
736 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
737 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
738 (UINTN)ImageContext->ImageSize)) {
739 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
740 return RETURN_LOAD_ERROR;
741 }
742
743 //
744 // Run this relocation record
745 //
746 while (Reloc < RelocEnd) {
747
748 Fixup = FixupBase + (*Reloc & 0xFFF);
749 switch ((*Reloc) >> 12) {
750 case EFI_IMAGE_REL_BASED_ABSOLUTE:
751 break;
752
753 case EFI_IMAGE_REL_BASED_HIGH:
754 F16 = (UINT16 *) Fixup;
755 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
756 if (FixupData != NULL) {
757 *(UINT16 *) FixupData = *F16;
758 FixupData = FixupData + sizeof (UINT16);
759 }
760 break;
761
762 case EFI_IMAGE_REL_BASED_LOW:
763 F16 = (UINT16 *) Fixup;
764 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
765 if (FixupData != NULL) {
766 *(UINT16 *) FixupData = *F16;
767 FixupData = FixupData + sizeof (UINT16);
768 }
769 break;
770
771 case EFI_IMAGE_REL_BASED_HIGHLOW:
772 F32 = (UINT32 *) Fixup;
773 *F32 = *F32 + (UINT32) Adjust;
774 if (FixupData != NULL) {
775 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
776 *(UINT32 *) FixupData = *F32;
777 FixupData = FixupData + sizeof (UINT32);
778 }
779 break;
780
781 case EFI_IMAGE_REL_BASED_HIGHADJ:
782 //
783 // Return the same EFI_UNSUPPORTED return code as
784 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
785 // the relocation type.
786 //
787 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
788 return RETURN_UNSUPPORTED;
789
790 default:
791 switch (MachineType) {
792 case EFI_IMAGE_MACHINE_IA32:
793 Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
794 break;
795 case EFI_IMAGE_MACHINE_ARMT:
796 Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
797 break;
798 case EFI_IMAGE_MACHINE_X64:
799 Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);
800 break;
801 case EFI_IMAGE_MACHINE_IA64:
802 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
803 break;
804 case EFI_IMAGE_MACHINE_AARCH64:
805 Status = PeCoffLoaderRelocateAArch64Image (Reloc, Fixup, &FixupData, Adjust);
806 break;
807 default:
808 Status = RETURN_UNSUPPORTED;
809 break;
810 }
811 if (RETURN_ERROR (Status)) {
812 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
813 return Status;
814 }
815 }
816
817 //
818 // Next relocation record
819 //
820 Reloc += 1;
821 }
822
823 //
824 // Next reloc block
825 //
826 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
827 }
828
829 return RETURN_SUCCESS;
830 }
831
832 RETURN_STATUS
833 EFIAPI
834 PeCoffLoaderLoadImage (
835 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
836 )
837 /*++
838
839 Routine Description:
840
841 Loads a PE/COFF image into memory
842
843 Arguments:
844
845 This - Calling context
846
847 ImageContext - Contains information on image to load into memory
848
849 Returns:
850
851 RETURN_SUCCESS if the PE/COFF image was loaded
852 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
853 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
854 RETURN_INVALID_PARAMETER if the image address is invalid
855
856 --*/
857 {
858 RETURN_STATUS Status;
859 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
860 EFI_TE_IMAGE_HEADER *TeHdr;
861 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
862 EFI_IMAGE_SECTION_HEADER *FirstSection;
863 EFI_IMAGE_SECTION_HEADER *Section;
864 UINTN NumberOfSections;
865 UINTN Index;
866 CHAR8 *Base;
867 CHAR8 *End;
868 CHAR8 *MaxEnd;
869 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
870 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
871 UINTN Size;
872 UINT32 TempDebugEntryRva;
873 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
874
875 PeHdr = NULL;
876 TeHdr = NULL;
877 OptionHeader.Header = NULL;
878 //
879 // Assume success
880 //
881 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
882
883 //
884 // Copy the provided context info into our local version, get what we
885 // can from the original image, and then use that to make sure everything
886 // is legit.
887 //
888 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
889
890 Status = PeCoffLoaderGetImageInfo (&CheckContext);
891 if (RETURN_ERROR (Status)) {
892 return Status;
893 }
894
895 //
896 // Make sure there is enough allocated space for the image being loaded
897 //
898 if (ImageContext->ImageSize < CheckContext.ImageSize) {
899 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
900 return RETURN_BUFFER_TOO_SMALL;
901 }
902
903 //
904 // If there's no relocations, then make sure it's not a runtime driver,
905 // and that it's being loaded at the linked address.
906 //
907 if (CheckContext.RelocationsStripped) {
908 //
909 // If the image does not contain relocations and it is a runtime driver
910 // then return an error.
911 //
912 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
913 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
914 return RETURN_LOAD_ERROR;
915 }
916 //
917 // If the image does not contain relocations, and the requested load address
918 // is not the linked address, then return an error.
919 //
920 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
921 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
922 return RETURN_INVALID_PARAMETER;
923 }
924 }
925 //
926 // Make sure the allocated space has the proper section alignment
927 //
928 if (!(ImageContext->IsTeImage)) {
929 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
930 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
931 return RETURN_INVALID_PARAMETER;
932 }
933 }
934 //
935 // Read the entire PE/COFF or TE header into memory
936 //
937 if (!(ImageContext->IsTeImage)) {
938 Status = ImageContext->ImageRead (
939 ImageContext->Handle,
940 0,
941 &ImageContext->SizeOfHeaders,
942 (VOID *) (UINTN) ImageContext->ImageAddress
943 );
944
945 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
946 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
947
948 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
949
950 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
951 (UINTN)ImageContext->ImageAddress +
952 ImageContext->PeCoffHeaderOffset +
953 sizeof(UINT32) +
954 sizeof(EFI_IMAGE_FILE_HEADER) +
955 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
956 );
957 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
958 } else {
959 Status = ImageContext->ImageRead (
960 ImageContext->Handle,
961 0,
962 &ImageContext->SizeOfHeaders,
963 (VOID *) (UINTN) ImageContext->ImageAddress
964 );
965
966 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
967
968 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
969 (UINTN)ImageContext->ImageAddress +
970 sizeof(EFI_TE_IMAGE_HEADER)
971 );
972 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
973
974 }
975
976 if (RETURN_ERROR (Status)) {
977 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
978 return RETURN_LOAD_ERROR;
979 }
980
981 //
982 // Load each section of the image
983 //
984 Section = FirstSection;
985 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
986
987 //
988 // Compute sections address
989 //
990 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
991 End = PeCoffLoaderImageAddress (
992 ImageContext,
993 Section->VirtualAddress + Section->Misc.VirtualSize - 1
994 );
995
996 //
997 // If the base start or end address resolved to 0, then fail.
998 //
999 if ((Base == NULL) || (End == NULL)) {
1000 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1001 return RETURN_LOAD_ERROR;
1002 }
1003
1004
1005 if (ImageContext->IsTeImage) {
1006 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1007 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1008 }
1009
1010 if (End > MaxEnd) {
1011 MaxEnd = End;
1012 }
1013
1014 //
1015 // Read the section
1016 //
1017 Size = (UINTN) Section->Misc.VirtualSize;
1018 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1019 Size = (UINTN) Section->SizeOfRawData;
1020 }
1021
1022 if (Section->SizeOfRawData) {
1023 if (!(ImageContext->IsTeImage)) {
1024 Status = ImageContext->ImageRead (
1025 ImageContext->Handle,
1026 Section->PointerToRawData,
1027 &Size,
1028 Base
1029 );
1030 } else {
1031 Status = ImageContext->ImageRead (
1032 ImageContext->Handle,
1033 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1034 &Size,
1035 Base
1036 );
1037 }
1038
1039 if (RETURN_ERROR (Status)) {
1040 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1041 return Status;
1042 }
1043 }
1044
1045 //
1046 // If raw size is less then virt size, zero fill the remaining
1047 //
1048
1049 if (Size < Section->Misc.VirtualSize) {
1050 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1051 }
1052
1053 //
1054 // Next Section
1055 //
1056 Section += 1;
1057 }
1058
1059 //
1060 // Get image's entry point
1061 //
1062 if (!(ImageContext->IsTeImage)) {
1063 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1064 ImageContext,
1065 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
1066 );
1067 } else {
1068 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
1069 (UINTN)ImageContext->ImageAddress +
1070 (UINTN)TeHdr->AddressOfEntryPoint +
1071 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1072 (UINTN) TeHdr->StrippedSize
1073 );
1074 }
1075
1076 //
1077 // Determine the size of the fixup data
1078 //
1079 // Per the PE/COFF spec, you can't assume that a given data directory
1080 // is present in the image. You have to check the NumberOfRvaAndSizes in
1081 // the optional header to verify a desired directory entry is there.
1082 //
1083 if (!(ImageContext->IsTeImage)) {
1084 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1085 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1086 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1087 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1088 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1089 } else {
1090 ImageContext->FixupDataSize = 0;
1091 }
1092 } else {
1093 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1094 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1095 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1096 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1097 } else {
1098 ImageContext->FixupDataSize = 0;
1099 }
1100 }
1101 } else {
1102 DirectoryEntry = &TeHdr->DataDirectory[0];
1103 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1104 }
1105 //
1106 // Consumer must allocate a buffer for the relocation fixup log.
1107 // Only used for runtime drivers.
1108 //
1109 ImageContext->FixupData = NULL;
1110
1111 //
1112 // Load the Codeview info if present
1113 //
1114 if (ImageContext->DebugDirectoryEntryRva != 0) {
1115 if (!(ImageContext->IsTeImage)) {
1116 DebugEntry = PeCoffLoaderImageAddress (
1117 ImageContext,
1118 ImageContext->DebugDirectoryEntryRva
1119 );
1120 } else {
1121 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1122 ImageContext->ImageAddress +
1123 ImageContext->DebugDirectoryEntryRva +
1124 sizeof(EFI_TE_IMAGE_HEADER) -
1125 TeHdr->StrippedSize
1126 );
1127 }
1128
1129 if (DebugEntry != NULL) {
1130 TempDebugEntryRva = DebugEntry->RVA;
1131 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1132 Section--;
1133 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1134 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1135 } else {
1136 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1137 }
1138 }
1139
1140 if (TempDebugEntryRva != 0) {
1141 if (!(ImageContext->IsTeImage)) {
1142 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1143 } else {
1144 ImageContext->CodeView = (VOID *)(
1145 (UINTN)ImageContext->ImageAddress +
1146 (UINTN)TempDebugEntryRva +
1147 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1148 (UINTN) TeHdr->StrippedSize
1149 );
1150 }
1151
1152 if (ImageContext->CodeView == NULL) {
1153 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1154 return RETURN_LOAD_ERROR;
1155 }
1156
1157 if (DebugEntry->RVA == 0) {
1158 Size = DebugEntry->SizeOfData;
1159 if (!(ImageContext->IsTeImage)) {
1160 Status = ImageContext->ImageRead (
1161 ImageContext->Handle,
1162 DebugEntry->FileOffset,
1163 &Size,
1164 ImageContext->CodeView
1165 );
1166 } else {
1167 Status = ImageContext->ImageRead (
1168 ImageContext->Handle,
1169 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1170 &Size,
1171 ImageContext->CodeView
1172 );
1173 //
1174 // Should we apply fix up to this field according to the size difference between PE and TE?
1175 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1176 // in original PE image.
1177 //
1178 }
1179
1180 if (RETURN_ERROR (Status)) {
1181 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1182 return RETURN_LOAD_ERROR;
1183 }
1184
1185 DebugEntry->RVA = TempDebugEntryRva;
1186 }
1187
1188 switch (*(UINT32 *) ImageContext->CodeView) {
1189 case CODEVIEW_SIGNATURE_NB10:
1190 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1191 break;
1192
1193 case CODEVIEW_SIGNATURE_RSDS:
1194 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1195 break;
1196
1197 case CODEVIEW_SIGNATURE_MTOC:
1198 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1199
1200 default:
1201 break;
1202 }
1203 }
1204 }
1205 }
1206
1207 return Status;
1208 }
1209
1210 /**
1211 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1212 loaded into system memory with the PE/COFF Loader Library functions.
1213
1214 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1215 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1216 returned. If the PE/COFF image specified by Pe32Data does not contain a
1217 debug directory entry, then NULL is returned. If the debug directory entry
1218 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1219 then NULL is returned.
1220 If Pe32Data is NULL, then return NULL.
1221
1222 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1223 memory.
1224
1225 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1226 if it cannot be retrieved.
1227
1228 **/
1229 VOID *
1230 EFIAPI
1231 PeCoffLoaderGetPdbPointer (
1232 IN VOID *Pe32Data
1233 )
1234 {
1235 EFI_IMAGE_DOS_HEADER *DosHdr;
1236 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1237 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1238 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1239 UINTN DirCount;
1240 VOID *CodeViewEntryPointer;
1241 INTN TEImageAdjust;
1242 UINT32 NumberOfRvaAndSizes;
1243 UINT16 Magic;
1244 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1245 UINT32 Index, Index1;
1246
1247 if (Pe32Data == NULL) {
1248 return NULL;
1249 }
1250
1251 TEImageAdjust = 0;
1252 DirectoryEntry = NULL;
1253 DebugEntry = NULL;
1254 NumberOfRvaAndSizes = 0;
1255 Index = 0;
1256 Index1 = 0;
1257 SectionHeader = NULL;
1258
1259 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1260 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
1261 //
1262 // DOS image header is present, so read the PE header after the DOS image header.
1263 //
1264 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1265 } else {
1266 //
1267 // DOS image header is not present, so PE header is at the image base.
1268 //
1269 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1270 }
1271
1272 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
1273 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
1274 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
1275 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
1276
1277 //
1278 // Get the DebugEntry offset in the raw data image.
1279 //
1280 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
1281 Index = Hdr.Te->NumberOfSections;
1282 for (Index1 = 0; Index1 < Index; Index1 ++) {
1283 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1284 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1285 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
1286 DirectoryEntry->VirtualAddress -
1287 SectionHeader [Index1].VirtualAddress +
1288 SectionHeader [Index1].PointerToRawData +
1289 TEImageAdjust);
1290 break;
1291 }
1292 }
1293 }
1294 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
1295 //
1296 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1297 // It is due to backward-compatibility, for some system might
1298 // generate PE32+ image with PE32 Magic.
1299 //
1300 switch (Hdr.Pe32->FileHeader.Machine) {
1301 case EFI_IMAGE_MACHINE_IA32:
1302 case EFI_IMAGE_MACHINE_ARMT:
1303 //
1304 // Assume PE32 image with IA32 Machine field.
1305 //
1306 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1307 break;
1308 case EFI_IMAGE_MACHINE_X64:
1309 case EFI_IMAGE_MACHINE_IPF:
1310 //
1311 // Assume PE32+ image with X64 or IPF Machine field
1312 //
1313 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1314 break;
1315 default:
1316 //
1317 // For unknow Machine field, use Magic in optional Header
1318 //
1319 Magic = Hdr.Pe32->OptionalHeader.Magic;
1320 }
1321
1322 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
1323 (UINT8 *) Hdr.Pe32 +
1324 sizeof (UINT32) +
1325 sizeof (EFI_IMAGE_FILE_HEADER) +
1326 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1327 );
1328 Index = Hdr.Pe32->FileHeader.NumberOfSections;
1329
1330 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
1331 //
1332 // Use PE32 offset get Debug Directory Entry
1333 //
1334 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1335 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1336 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1337 //
1338 // Use PE32+ offset get Debug Directory Entry
1339 //
1340 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1341 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1342 }
1343
1344 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
1345 DirectoryEntry = NULL;
1346 DebugEntry = NULL;
1347 } else {
1348 //
1349 // Get the DebugEntry offset in the raw data image.
1350 //
1351 for (Index1 = 0; Index1 < Index; Index1 ++) {
1352 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1353 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1354 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
1355 (UINTN) Pe32Data +
1356 DirectoryEntry->VirtualAddress -
1357 SectionHeader[Index1].VirtualAddress +
1358 SectionHeader[Index1].PointerToRawData);
1359 break;
1360 }
1361 }
1362 }
1363 } else {
1364 return NULL;
1365 }
1366
1367 if (NULL == DebugEntry || NULL == DirectoryEntry) {
1368 return NULL;
1369 }
1370
1371 //
1372 // Scan the directory to find the debug entry.
1373 //
1374 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
1375 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
1376 if (DebugEntry->SizeOfData > 0) {
1377 //
1378 // Get the DebugEntry offset in the raw data image.
1379 //
1380 CodeViewEntryPointer = NULL;
1381 for (Index1 = 0; Index1 < Index; Index1 ++) {
1382 if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
1383 (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1384 CodeViewEntryPointer = (VOID *) (
1385 ((UINTN)Pe32Data) +
1386 (UINTN) DebugEntry->RVA -
1387 SectionHeader[Index1].VirtualAddress +
1388 SectionHeader[Index1].PointerToRawData +
1389 (UINTN)TEImageAdjust);
1390 break;
1391 }
1392 }
1393 if (Index1 >= Index) {
1394 //
1395 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1396 //
1397 continue;
1398 }
1399 switch (* (UINT32 *) CodeViewEntryPointer) {
1400 case CODEVIEW_SIGNATURE_NB10:
1401 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
1402 case CODEVIEW_SIGNATURE_RSDS:
1403 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
1404 case CODEVIEW_SIGNATURE_MTOC:
1405 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
1406 default:
1407 break;
1408 }
1409 }
1410 }
1411 }
1412
1413 return NULL;
1414 }
1415
1416
1417 RETURN_STATUS
1418 EFIAPI
1419 PeCoffLoaderGetEntryPoint (
1420 IN VOID *Pe32Data,
1421 OUT VOID **EntryPoint,
1422 OUT VOID **BaseOfImage
1423 )
1424 {
1425 EFI_IMAGE_DOS_HEADER *DosHdr;
1426 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1427
1428 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1429 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1430 //
1431 // DOS image header is present, so read the PE header after the DOS image header.
1432 //
1433 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1434 } else {
1435 //
1436 // DOS image header is not present, so PE header is at the image base.
1437 //
1438 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1439 }
1440
1441 //
1442 // Calculate the entry point relative to the start of the image.
1443 // AddressOfEntryPoint is common for PE32 & PE32+
1444 //
1445 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
1446 *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
1447 *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
1448 return RETURN_SUCCESS;
1449 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
1450 *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;
1451 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1452 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;
1453 } else {
1454 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;
1455 }
1456 *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);
1457 return RETURN_SUCCESS;
1458 }
1459
1460 return RETURN_UNSUPPORTED;
1461 }