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