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