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