]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/BasePeCoff.c
Sync EDKII BaseTools to BaseTools project r1971
[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 - 2008, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Common/UefiBaseTypes.h>
17 #include <CommonLib.h>
18 #include <IndustryStandard/PeImage.h>
19 #include "PeCoffLib.h"
20
21 typedef union {
22 VOID *Header;
23 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
24 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
25 } EFI_IMAGE_OPTIONAL_HEADER_POINTER;
26
27 STATIC
28 RETURN_STATUS
29 PeCoffLoaderGetPeHeader (
30 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
31 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
32 OUT EFI_TE_IMAGE_HEADER **TeHdr
33 );
34
35 STATIC
36 RETURN_STATUS
37 PeCoffLoaderCheckImageType (
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
39 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
40 IN EFI_TE_IMAGE_HEADER *TeHdr
41 );
42
43 STATIC
44 VOID *
45 PeCoffLoaderImageAddress (
46 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
47 IN UINTN Address
48 );
49
50 RETURN_STATUS
51 PeCoffLoaderRelocateIa32Image (
52 IN UINT16 *Reloc,
53 IN OUT CHAR8 *Fixup,
54 IN OUT CHAR8 **FixupData,
55 IN UINT64 Adjust
56 );
57
58 RETURN_STATUS
59 PeCoffLoaderRelocateX64Image (
60 IN UINT16 *Reloc,
61 IN OUT CHAR8 *Fixup,
62 IN OUT CHAR8 **FixupData,
63 IN UINT64 Adjust
64 );
65
66 RETURN_STATUS
67 PeCoffLoaderRelocateIpfImage (
68 IN UINT16 *Reloc,
69 IN OUT CHAR8 *Fixup,
70 IN OUT CHAR8 **FixupData,
71 IN UINT64 Adjust
72 );
73
74 RETURN_STATUS
75 PeCoffLoaderRelocateArmImage (
76 IN UINT16 **Reloc,
77 IN OUT CHAR8 *Fixup,
78 IN OUT CHAR8 **FixupData,
79 IN UINT64 Adjust
80 );
81
82 STATIC
83 RETURN_STATUS
84 PeCoffLoaderGetPeHeader (
85 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
86 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
87 OUT EFI_TE_IMAGE_HEADER **TeHdr
88 )
89 /*++
90
91 Routine Description:
92
93 Retrieves the PE or TE Header from a PE/COFF or TE image
94
95 Arguments:
96
97 ImageContext - The context of the image being loaded
98
99 PeHdr - The buffer in which to return the PE header
100
101 TeHdr - The buffer in which to return the TE header
102
103 Returns:
104
105 RETURN_SUCCESS if the PE or TE Header is read,
106 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
107
108 --*/
109 {
110 RETURN_STATUS Status;
111 EFI_IMAGE_DOS_HEADER DosHdr;
112 UINTN Size;
113
114 ImageContext->IsTeImage = FALSE;
115 //
116 // Read the DOS image headers
117 //
118 Size = sizeof (EFI_IMAGE_DOS_HEADER);
119 Status = ImageContext->ImageRead (
120 ImageContext->Handle,
121 0,
122 &Size,
123 &DosHdr
124 );
125 if (RETURN_ERROR (Status)) {
126 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
127 return Status;
128 }
129
130 ImageContext->PeCoffHeaderOffset = 0;
131 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
132 //
133 // DOS image header is present, so read the PE header after the DOS image header
134 //
135 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
136 }
137 //
138 // Get the PE/COFF Header pointer
139 //
140 *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
141 if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
142 //
143 // Check the PE/COFF Header Signature. If not, then try to get a TE header
144 //
145 *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr;
146 if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
147 return RETURN_UNSUPPORTED;
148 }
149 ImageContext->IsTeImage = TRUE;
150 }
151
152 return RETURN_SUCCESS;
153 }
154
155 STATIC
156 RETURN_STATUS
157 PeCoffLoaderCheckImageType (
158 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
159 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
160 IN EFI_TE_IMAGE_HEADER *TeHdr
161 )
162 /*++
163
164 Routine Description:
165
166 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
167
168 Arguments:
169
170 ImageContext - The context of the image being loaded
171
172 PeHdr - The buffer in which to return the PE header
173
174 TeHdr - The buffer in which to return the TE header
175
176 Returns:
177
178 RETURN_SUCCESS if the PE/COFF or TE image is supported
179 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
180
181 --*/
182 {
183 //
184 // See if the machine type is supported.
185 // We support a native machine type (IA-32/Itanium-based)
186 //
187 if (ImageContext->IsTeImage == FALSE) {
188 ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;
189 } else {
190 ImageContext->Machine = TeHdr->Machine;
191 }
192
193 if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \
194 ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \
195 ImageContext->Machine != EFI_IMAGE_MACHINE_X64 && \
196 ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \
197 ImageContext->Machine != EFI_IMAGE_MACHINE_EBC) {
198 if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {
199 //
200 // There are two types of ARM images. Pure ARM and ARM/Thumb.
201 // If we see the ARM say it is the ARM/Thumb so there is only
202 // a single machine type we need to check for ARM.
203 //
204 ImageContext->Machine = EFI_IMAGE_MACHINE_ARMT;
205 if (ImageContext->IsTeImage == FALSE) {
206 PeHdr->Pe32.FileHeader.Machine = ImageContext->Machine;
207 } else {
208 TeHdr->Machine = ImageContext->Machine;
209 }
210
211 } else {
212 //
213 // unsupported PeImage machine type
214 //
215 return RETURN_UNSUPPORTED;
216 }
217 }
218
219 //
220 // See if the image type is supported. We support EFI Applications,
221 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
222 //
223 if (ImageContext->IsTeImage == FALSE) {
224 ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;
225 } else {
226 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
227 }
228
229 if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
230 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \
231 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \
232 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {
233 //
234 // upsupported PeImage subsystem type
235 //
236 return RETURN_UNSUPPORTED;
237 }
238
239 return RETURN_SUCCESS;
240 }
241
242 RETURN_STATUS
243 EFIAPI
244 PeCoffLoaderGetImageInfo (
245 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
246 )
247 /*++
248
249 Routine Description:
250
251 Retrieves information on a PE/COFF image
252
253 Arguments:
254
255 This - Calling context
256 ImageContext - The context of the image being loaded
257
258 Returns:
259
260 RETURN_SUCCESS - The information on the PE/COFF image was collected.
261 RETURN_INVALID_PARAMETER - ImageContext is NULL.
262 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
263 Otherwise - The error status from reading the PE/COFF image using the
264 ImageContext->ImageRead() function
265
266 --*/
267 {
268 RETURN_STATUS Status;
269 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
270 EFI_TE_IMAGE_HEADER *TeHdr;
271 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
272 UINTN Size;
273 UINTN Index;
274 UINTN DebugDirectoryEntryRva;
275 UINTN DebugDirectoryEntryFileOffset;
276 UINTN SectionHeaderOffset;
277 EFI_IMAGE_SECTION_HEADER SectionHeader;
278 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
279 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
280
281 PeHdr = NULL;
282 TeHdr = NULL;
283 DebugDirectoryEntry = NULL;
284 DebugDirectoryEntryRva = 0;
285
286 if (NULL == ImageContext) {
287 return RETURN_INVALID_PARAMETER;
288 }
289 //
290 // Assume success
291 //
292 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
293
294 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
295 if (RETURN_ERROR (Status)) {
296 return Status;
297 }
298
299 //
300 // Verify machine type
301 //
302 Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);
303 if (RETURN_ERROR (Status)) {
304 return Status;
305 }
306 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
307
308 //
309 // Retrieve the base address of the image
310 //
311 if (!(ImageContext->IsTeImage)) {
312 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
313 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;
314 } else {
315 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;
316 }
317 } else {
318 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
319 }
320 //
321 // Initialize the alternate destination address to 0 indicating that it
322 // should not be used.
323 //
324 ImageContext->DestinationAddress = 0;
325
326 //
327 // Initialize the codeview pointer.
328 //
329 ImageContext->CodeView = NULL;
330 ImageContext->PdbPointer = NULL;
331
332 //
333 // Three cases with regards to relocations:
334 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
335 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
336 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
337 // has no base relocs to apply
338 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
339 //
340 // Look at the file header to determine if relocations have been stripped, and
341 // save this info in the image context for later use.
342 //
343 if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
344 ImageContext->RelocationsStripped = TRUE;
345 } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0)) {
346 ImageContext->RelocationsStripped = TRUE;
347 } else {
348 ImageContext->RelocationsStripped = FALSE;
349 }
350
351 if (!(ImageContext->IsTeImage)) {
352
353 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
354 ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage;
355 ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment;
356 ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders;
357
358 //
359 // Modify ImageSize to contain .PDB file name if required and initialize
360 // PdbRVA field...
361 //
362 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
363 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
364 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
365 }
366 } else {
367 ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage;
368 ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment;
369 ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders;
370
371 //
372 // Modify ImageSize to contain .PDB file name if required and initialize
373 // PdbRVA field...
374 //
375 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
376 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
377 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
378 }
379 }
380
381 if (DebugDirectoryEntryRva != 0) {
382 //
383 // Determine the file offset of the debug directory... This means we walk
384 // the sections to find which section contains the RVA of the debug
385 // directory
386 //
387 DebugDirectoryEntryFileOffset = 0;
388
389 SectionHeaderOffset = (UINTN)(
390 ImageContext->PeCoffHeaderOffset +
391 sizeof (UINT32) +
392 sizeof (EFI_IMAGE_FILE_HEADER) +
393 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
394 );
395
396 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {
397 //
398 // Read section header from file
399 //
400 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
401 Status = ImageContext->ImageRead (
402 ImageContext->Handle,
403 SectionHeaderOffset,
404 &Size,
405 &SectionHeader
406 );
407 if (RETURN_ERROR (Status)) {
408 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
409 return Status;
410 }
411
412 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
413 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
414 DebugDirectoryEntryFileOffset =
415 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
416 break;
417 }
418
419 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
420 }
421
422 if (DebugDirectoryEntryFileOffset != 0) {
423 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
424 //
425 // Read next debug directory entry
426 //
427 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
428 Status = ImageContext->ImageRead (
429 ImageContext->Handle,
430 DebugDirectoryEntryFileOffset + Index,
431 &Size,
432 &DebugEntry
433 );
434 if (RETURN_ERROR (Status)) {
435 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
436 return Status;
437 }
438
439 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
440 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
441 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
442 ImageContext->ImageSize += DebugEntry.SizeOfData;
443 }
444
445 return RETURN_SUCCESS;
446 }
447 }
448 }
449 }
450 } else {
451 ImageContext->ImageSize = 0;
452 ImageContext->SectionAlignment = 4096;
453 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;
454
455 DebugDirectoryEntry = &TeHdr->DataDirectory[1];
456 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
457 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
458
459 DebugDirectoryEntryFileOffset = 0;
460
461 for (Index = 0; Index < TeHdr->NumberOfSections;) {
462 //
463 // Read section header from file
464 //
465 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
466 Status = ImageContext->ImageRead (
467 ImageContext->Handle,
468 SectionHeaderOffset,
469 &Size,
470 &SectionHeader
471 );
472 if (RETURN_ERROR (Status)) {
473 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
474 return Status;
475 }
476
477 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
478 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
479 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
480 SectionHeader.VirtualAddress +
481 SectionHeader.PointerToRawData +
482 sizeof (EFI_TE_IMAGE_HEADER) -
483 TeHdr->StrippedSize;
484
485 //
486 // File offset of the debug directory was found, if this is not the last
487 // section, then skip to the last section for calculating the image size.
488 //
489 if (Index < (UINTN) TeHdr->NumberOfSections - 1) {
490 SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
491 Index = TeHdr->NumberOfSections - 1;
492 continue;
493 }
494 }
495
496 //
497 // In Te image header there is not a field to describe the ImageSize.
498 // Actually, the ImageSize equals the RVA plus the VirtualSize of
499 // the last section mapped into memory (Must be rounded up to
500 // a mulitple of Section Alignment). Per the PE/COFF specification, the
501 // section headers in the Section Table must appear in order of the RVA
502 // values for the corresponding sections. So the ImageSize can be determined
503 // by the RVA and the VirtualSize of the last section header in the
504 // Section Table.
505 //
506 if ((++Index) == (UINTN) TeHdr->NumberOfSections) {
507 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
508 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
509 }
510
511 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
512 }
513
514 if (DebugDirectoryEntryFileOffset != 0) {
515 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
516 //
517 // Read next debug directory entry
518 //
519 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
520 Status = ImageContext->ImageRead (
521 ImageContext->Handle,
522 DebugDirectoryEntryFileOffset,
523 &Size,
524 &DebugEntry
525 );
526 if (RETURN_ERROR (Status)) {
527 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
528 return Status;
529 }
530
531 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
532 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
533 return RETURN_SUCCESS;
534 }
535 }
536 }
537 }
538
539 return RETURN_SUCCESS;
540 }
541
542 STATIC
543 VOID *
544 PeCoffLoaderImageAddress (
545 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
546 IN UINTN Address
547 )
548 /*++
549
550 Routine Description:
551
552 Converts an image address to the loaded address
553
554 Arguments:
555
556 ImageContext - The context of the image being loaded
557
558 Address - The address to be converted to the loaded address
559
560 Returns:
561
562 NULL if the address can not be converted, otherwise, the converted address
563
564 --*/
565 {
566 if (Address >= ImageContext->ImageSize) {
567 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
568 return NULL;
569 }
570
571 return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);
572 }
573
574 RETURN_STATUS
575 EFIAPI
576 PeCoffLoaderRelocateImage (
577 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
578 )
579 /*++
580
581 Routine Description:
582
583 Relocates a PE/COFF image in memory
584
585 Arguments:
586
587 This - Calling context
588
589 ImageContext - Contains information on the loaded image to relocate
590
591 Returns:
592
593 RETURN_SUCCESS if the PE/COFF image was relocated
594 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
595 RETURN_UNSUPPORTED not support
596
597 --*/
598 {
599 RETURN_STATUS Status;
600 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
601 EFI_TE_IMAGE_HEADER *TeHdr;
602 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
603 UINT64 Adjust;
604 EFI_IMAGE_BASE_RELOCATION *RelocBase;
605 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
606 UINT16 *Reloc;
607 UINT16 *RelocEnd;
608 CHAR8 *Fixup;
609 CHAR8 *FixupBase;
610 UINT16 *F16;
611 UINT32 *F32;
612 CHAR8 *FixupData;
613 PHYSICAL_ADDRESS BaseAddress;
614 UINT16 MachineType;
615 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
616
617 PeHdr = NULL;
618 TeHdr = NULL;
619 //
620 // Assume success
621 //
622 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
623
624 //
625 // If there are no relocation entries, then we are done
626 //
627 if (ImageContext->RelocationsStripped) {
628 return RETURN_SUCCESS;
629 }
630
631 //
632 // If the destination address is not 0, use that rather than the
633 // image address as the relocation target.
634 //
635 if (ImageContext->DestinationAddress) {
636 BaseAddress = ImageContext->DestinationAddress;
637 } else {
638 BaseAddress = ImageContext->ImageAddress;
639 }
640
641 if (!(ImageContext->IsTeImage)) {
642 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress +
643 ImageContext->PeCoffHeaderOffset);
644 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
645 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
646 Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;
647 OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;
648 MachineType = ImageContext->Machine;
649 //
650 // Find the relocation block
651 //
652 // Per the PE/COFF spec, you can't assume that a given data directory
653 // is present in the image. You have to check the NumberOfRvaAndSizes in
654 // the optional header to verify a desired directory entry is there.
655 //
656 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
657 RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
658 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
659 RelocBaseEnd = PeCoffLoaderImageAddress (
660 ImageContext,
661 RelocDir->VirtualAddress + RelocDir->Size - 1
662 );
663 } else {
664 //
665 // Set base and end to bypass processing below.
666 //
667 RelocBase = RelocBaseEnd = 0;
668 }
669 } else {
670 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
671 OptionHeader.Optional64->ImageBase = BaseAddress;
672 MachineType = ImageContext->Machine;
673 //
674 // Find the relocation block
675 //
676 // Per the PE/COFF spec, you can't assume that a given data directory
677 // is present in the image. You have to check the NumberOfRvaAndSizes in
678 // the optional header to verify a desired directory entry is there.
679 //
680 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
681 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
682 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
683 RelocBaseEnd = PeCoffLoaderImageAddress (
684 ImageContext,
685 RelocDir->VirtualAddress + RelocDir->Size - 1
686 );
687 } else {
688 //
689 // Set base and end to bypass processing below.
690 //
691 RelocBase = RelocBaseEnd = 0;
692 }
693 }
694 } else {
695 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
696 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
697 TeHdr->ImageBase = (UINT64) (BaseAddress);
698 MachineType = TeHdr->Machine;
699
700 //
701 // Find the relocation block
702 //
703 RelocDir = &TeHdr->DataDirectory[0];
704 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
705 ImageContext->ImageAddress +
706 RelocDir->VirtualAddress +
707 sizeof(EFI_TE_IMAGE_HEADER) -
708 TeHdr->StrippedSize
709 );
710 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
711 }
712
713 //
714 // Run the relocation information and apply the fixups
715 //
716 FixupData = ImageContext->FixupData;
717 while (RelocBase < RelocBaseEnd) {
718
719 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
720 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
721 if (!(ImageContext->IsTeImage)) {
722 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
723 } else {
724 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
725 RelocBase->VirtualAddress +
726 sizeof(EFI_TE_IMAGE_HEADER) -
727 TeHdr->StrippedSize
728 );
729 }
730
731 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
732 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
733 (UINTN)ImageContext->ImageSize)) {
734 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
735 return RETURN_LOAD_ERROR;
736 }
737
738 //
739 // Run this relocation record
740 //
741 while (Reloc < RelocEnd) {
742
743 Fixup = FixupBase + (*Reloc & 0xFFF);
744 switch ((*Reloc) >> 12) {
745 case EFI_IMAGE_REL_BASED_ABSOLUTE:
746 break;
747
748 case EFI_IMAGE_REL_BASED_HIGH:
749 F16 = (UINT16 *) Fixup;
750 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
751 if (FixupData != NULL) {
752 *(UINT16 *) FixupData = *F16;
753 FixupData = FixupData + sizeof (UINT16);
754 }
755 break;
756
757 case EFI_IMAGE_REL_BASED_LOW:
758 F16 = (UINT16 *) Fixup;
759 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
760 if (FixupData != NULL) {
761 *(UINT16 *) FixupData = *F16;
762 FixupData = FixupData + sizeof (UINT16);
763 }
764 break;
765
766 case EFI_IMAGE_REL_BASED_HIGHLOW:
767 F32 = (UINT32 *) Fixup;
768 *F32 = *F32 + (UINT32) Adjust;
769 if (FixupData != NULL) {
770 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
771 *(UINT32 *) FixupData = *F32;
772 FixupData = FixupData + sizeof (UINT32);
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_X64:
794 Status = PeCoffLoaderRelocateX64Image (Reloc, Fixup, &FixupData, Adjust);
795 break;
796 case EFI_IMAGE_MACHINE_IA64:
797 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
798 break;
799 default:
800 Status = RETURN_UNSUPPORTED;
801 break;
802 }
803 if (RETURN_ERROR (Status)) {
804 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
805 return Status;
806 }
807 }
808
809 //
810 // Next relocation record
811 //
812 Reloc += 1;
813 }
814
815 //
816 // Next reloc block
817 //
818 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
819 }
820
821 return RETURN_SUCCESS;
822 }
823
824 RETURN_STATUS
825 EFIAPI
826 PeCoffLoaderLoadImage (
827 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
828 )
829 /*++
830
831 Routine Description:
832
833 Loads a PE/COFF image into memory
834
835 Arguments:
836
837 This - Calling context
838
839 ImageContext - Contains information on image to load into memory
840
841 Returns:
842
843 RETURN_SUCCESS if the PE/COFF image was loaded
844 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
845 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
846 RETURN_INVALID_PARAMETER if the image address is invalid
847
848 --*/
849 {
850 RETURN_STATUS Status;
851 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
852 EFI_TE_IMAGE_HEADER *TeHdr;
853 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
854 EFI_IMAGE_SECTION_HEADER *FirstSection;
855 EFI_IMAGE_SECTION_HEADER *Section;
856 UINTN NumberOfSections;
857 UINTN Index;
858 CHAR8 *Base;
859 CHAR8 *End;
860 CHAR8 *MaxEnd;
861 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
862 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
863 UINTN Size;
864 UINT32 TempDebugEntryRva;
865 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
866
867 PeHdr = NULL;
868 TeHdr = NULL;
869 OptionHeader.Header = NULL;
870 //
871 // Assume success
872 //
873 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
874
875 //
876 // Copy the provided context info into our local version, get what we
877 // can from the original image, and then use that to make sure everything
878 // is legit.
879 //
880 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
881
882 Status = PeCoffLoaderGetImageInfo (&CheckContext);
883 if (RETURN_ERROR (Status)) {
884 return Status;
885 }
886
887 //
888 // Make sure there is enough allocated space for the image being loaded
889 //
890 if (ImageContext->ImageSize < CheckContext.ImageSize) {
891 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
892 return RETURN_BUFFER_TOO_SMALL;
893 }
894
895 //
896 // If there's no relocations, then make sure it's not a runtime driver,
897 // and that it's being loaded at the linked address.
898 //
899 if (CheckContext.RelocationsStripped) {
900 //
901 // If the image does not contain relocations and it is a runtime driver
902 // then return an error.
903 //
904 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
905 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
906 return RETURN_LOAD_ERROR;
907 }
908 //
909 // If the image does not contain relocations, and the requested load address
910 // is not the linked address, then return an error.
911 //
912 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
913 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
914 return RETURN_INVALID_PARAMETER;
915 }
916 }
917 //
918 // Make sure the allocated space has the proper section alignment
919 //
920 if (!(ImageContext->IsTeImage)) {
921 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
922 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
923 return RETURN_INVALID_PARAMETER;
924 }
925 }
926 //
927 // Read the entire PE/COFF or TE header into memory
928 //
929 if (!(ImageContext->IsTeImage)) {
930 Status = ImageContext->ImageRead (
931 ImageContext->Handle,
932 0,
933 &ImageContext->SizeOfHeaders,
934 (VOID *) (UINTN) ImageContext->ImageAddress
935 );
936
937 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
938 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
939
940 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
941
942 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
943 (UINTN)ImageContext->ImageAddress +
944 ImageContext->PeCoffHeaderOffset +
945 sizeof(UINT32) +
946 sizeof(EFI_IMAGE_FILE_HEADER) +
947 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
948 );
949 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
950 } else {
951 Status = ImageContext->ImageRead (
952 ImageContext->Handle,
953 0,
954 &ImageContext->SizeOfHeaders,
955 (VOID *) (UINTN) ImageContext->ImageAddress
956 );
957
958 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
959
960 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
961 (UINTN)ImageContext->ImageAddress +
962 sizeof(EFI_TE_IMAGE_HEADER)
963 );
964 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
965
966 }
967
968 if (RETURN_ERROR (Status)) {
969 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
970 return RETURN_LOAD_ERROR;
971 }
972
973 //
974 // Load each section of the image
975 //
976 Section = FirstSection;
977 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
978
979 //
980 // Compute sections address
981 //
982 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
983 End = PeCoffLoaderImageAddress (
984 ImageContext,
985 Section->VirtualAddress + Section->Misc.VirtualSize - 1
986 );
987 if (ImageContext->IsTeImage) {
988 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
989 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
990 }
991
992 if (End > MaxEnd) {
993 MaxEnd = End;
994 }
995 //
996 // If the base start or end address resolved to 0, then fail.
997 //
998 if ((Base == NULL) || (End == NULL)) {
999 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1000 return RETURN_LOAD_ERROR;
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 }