]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/BasePeCoff.c
BaseTools/C/Common: Avoid possible NULL pointer dereference
[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 - 2016, 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) && (TeHdr->DataDirectory[0].VirtualAddress == 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 if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
654 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
655 return RETURN_LOAD_ERROR;
656 }
657 } else {
658 //
659 // Set base and end to bypass processing below.
660 //
661 RelocBase = RelocBaseEnd = 0;
662 }
663 } else {
664 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
665 OptionHeader.Optional64->ImageBase = BaseAddress;
666 MachineType = ImageContext->Machine;
667 //
668 // Find the relocation block
669 //
670 // Per the PE/COFF spec, you can't assume that a given data directory
671 // is present in the image. You have to check the NumberOfRvaAndSizes in
672 // the optional header to verify a desired directory entry is there.
673 //
674 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
675 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
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 }
692 } else {
693 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
694 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
695 TeHdr->ImageBase = (UINT64) (BaseAddress);
696 MachineType = TeHdr->Machine;
697
698 //
699 // Find the relocation block
700 //
701 RelocDir = &TeHdr->DataDirectory[0];
702 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
703 ImageContext->ImageAddress +
704 RelocDir->VirtualAddress +
705 sizeof(EFI_TE_IMAGE_HEADER) -
706 TeHdr->StrippedSize
707 );
708 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
709 }
710
711 //
712 // Run the relocation information and apply the fixups
713 //
714 FixupData = ImageContext->FixupData;
715 while (RelocBase < RelocBaseEnd) {
716
717 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
718 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
719 if (!(ImageContext->IsTeImage)) {
720 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
721 if (FixupBase == NULL) {
722 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
723 return RETURN_LOAD_ERROR;
724 }
725 } else {
726 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
727 RelocBase->VirtualAddress +
728 sizeof(EFI_TE_IMAGE_HEADER) -
729 TeHdr->StrippedSize
730 );
731 }
732
733 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
734 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
735 (UINTN)ImageContext->ImageSize)) {
736 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
737 return RETURN_LOAD_ERROR;
738 }
739
740 //
741 // Run this relocation record
742 //
743 while (Reloc < RelocEnd) {
744
745 Fixup = FixupBase + (*Reloc & 0xFFF);
746 switch ((*Reloc) >> 12) {
747 case EFI_IMAGE_REL_BASED_ABSOLUTE:
748 break;
749
750 case EFI_IMAGE_REL_BASED_HIGH:
751 F16 = (UINT16 *) Fixup;
752 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
753 if (FixupData != NULL) {
754 *(UINT16 *) FixupData = *F16;
755 FixupData = FixupData + sizeof (UINT16);
756 }
757 break;
758
759 case EFI_IMAGE_REL_BASED_LOW:
760 F16 = (UINT16 *) Fixup;
761 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
762 if (FixupData != NULL) {
763 *(UINT16 *) FixupData = *F16;
764 FixupData = FixupData + sizeof (UINT16);
765 }
766 break;
767
768 case EFI_IMAGE_REL_BASED_HIGHLOW:
769 F32 = (UINT32 *) Fixup;
770 *F32 = *F32 + (UINT32) Adjust;
771 if (FixupData != NULL) {
772 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
773 *(UINT32 *) FixupData = *F32;
774 FixupData = FixupData + sizeof (UINT32);
775 }
776 break;
777
778 case EFI_IMAGE_REL_BASED_DIR64:
779 F64 = (UINT64 *) Fixup;
780 *F64 = *F64 + (UINT64) Adjust;
781 if (FixupData != NULL) {
782 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
783 *(UINT64 *) FixupData = *F64;
784 FixupData = FixupData + sizeof (UINT64);
785 }
786 break;
787
788 case EFI_IMAGE_REL_BASED_HIGHADJ:
789 //
790 // Return the same EFI_UNSUPPORTED return code as
791 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
792 // the relocation type.
793 //
794 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
795 return RETURN_UNSUPPORTED;
796
797 default:
798 switch (MachineType) {
799 case EFI_IMAGE_MACHINE_IA32:
800 Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
801 break;
802 case EFI_IMAGE_MACHINE_ARMT:
803 Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
804 break;
805 case EFI_IMAGE_MACHINE_IA64:
806 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
807 break;
808 default:
809 Status = RETURN_UNSUPPORTED;
810 break;
811 }
812 if (RETURN_ERROR (Status)) {
813 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
814 return Status;
815 }
816 }
817
818 //
819 // Next relocation record
820 //
821 Reloc += 1;
822 }
823
824 //
825 // Next reloc block
826 //
827 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
828 }
829
830 return RETURN_SUCCESS;
831 }
832
833 RETURN_STATUS
834 EFIAPI
835 PeCoffLoaderLoadImage (
836 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
837 )
838 /*++
839
840 Routine Description:
841
842 Loads a PE/COFF image into memory
843
844 Arguments:
845
846 This - Calling context
847
848 ImageContext - Contains information on image to load into memory
849
850 Returns:
851
852 RETURN_SUCCESS if the PE/COFF image was loaded
853 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
854 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
855 RETURN_INVALID_PARAMETER if the image address is invalid
856
857 --*/
858 {
859 RETURN_STATUS Status;
860 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
861 EFI_TE_IMAGE_HEADER *TeHdr;
862 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
863 EFI_IMAGE_SECTION_HEADER *FirstSection;
864 EFI_IMAGE_SECTION_HEADER *Section;
865 UINTN NumberOfSections;
866 UINTN Index;
867 CHAR8 *Base;
868 CHAR8 *End;
869 CHAR8 *MaxEnd;
870 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
871 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
872 UINTN Size;
873 UINT32 TempDebugEntryRva;
874 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
875
876 PeHdr = NULL;
877 TeHdr = NULL;
878 OptionHeader.Header = NULL;
879 //
880 // Assume success
881 //
882 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
883
884 //
885 // Copy the provided context info into our local version, get what we
886 // can from the original image, and then use that to make sure everything
887 // is legit.
888 //
889 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
890
891 Status = PeCoffLoaderGetImageInfo (&CheckContext);
892 if (RETURN_ERROR (Status)) {
893 return Status;
894 }
895
896 //
897 // Make sure there is enough allocated space for the image being loaded
898 //
899 if (ImageContext->ImageSize < CheckContext.ImageSize) {
900 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
901 return RETURN_BUFFER_TOO_SMALL;
902 }
903
904 //
905 // If there's no relocations, then make sure it's not a runtime driver,
906 // and that it's being loaded at the linked address.
907 //
908 if (CheckContext.RelocationsStripped) {
909 //
910 // If the image does not contain relocations and it is a runtime driver
911 // then return an error.
912 //
913 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
914 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
915 return RETURN_LOAD_ERROR;
916 }
917 //
918 // If the image does not contain relocations, and the requested load address
919 // is not the linked address, then return an error.
920 //
921 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
922 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
923 return RETURN_INVALID_PARAMETER;
924 }
925 }
926 //
927 // Make sure the allocated space has the proper section alignment
928 //
929 if (!(ImageContext->IsTeImage)) {
930 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
931 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
932 return RETURN_INVALID_PARAMETER;
933 }
934 }
935 //
936 // Read the entire PE/COFF or TE header into memory
937 //
938 if (!(ImageContext->IsTeImage)) {
939 Status = ImageContext->ImageRead (
940 ImageContext->Handle,
941 0,
942 &ImageContext->SizeOfHeaders,
943 (VOID *) (UINTN) ImageContext->ImageAddress
944 );
945
946 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
947 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
948
949 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
950
951 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
952 (UINTN)ImageContext->ImageAddress +
953 ImageContext->PeCoffHeaderOffset +
954 sizeof(UINT32) +
955 sizeof(EFI_IMAGE_FILE_HEADER) +
956 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
957 );
958 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
959 } else {
960 Status = ImageContext->ImageRead (
961 ImageContext->Handle,
962 0,
963 &ImageContext->SizeOfHeaders,
964 (VOID *) (UINTN) ImageContext->ImageAddress
965 );
966
967 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
968
969 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
970 (UINTN)ImageContext->ImageAddress +
971 sizeof(EFI_TE_IMAGE_HEADER)
972 );
973 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
974
975 }
976
977 if (RETURN_ERROR (Status)) {
978 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
979 return RETURN_LOAD_ERROR;
980 }
981
982 //
983 // Load each section of the image
984 //
985 Section = FirstSection;
986 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
987
988 //
989 // Compute sections address
990 //
991 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
992 End = PeCoffLoaderImageAddress (
993 ImageContext,
994 Section->VirtualAddress + Section->Misc.VirtualSize - 1
995 );
996
997 //
998 // If the base start or end address resolved to 0, then fail.
999 //
1000 if ((Base == NULL) || (End == NULL)) {
1001 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1002 return RETURN_LOAD_ERROR;
1003 }
1004
1005
1006 if (ImageContext->IsTeImage) {
1007 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1008 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1009 }
1010
1011 if (End > MaxEnd) {
1012 MaxEnd = End;
1013 }
1014
1015 //
1016 // Read the section
1017 //
1018 Size = (UINTN) Section->Misc.VirtualSize;
1019 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1020 Size = (UINTN) Section->SizeOfRawData;
1021 }
1022
1023 if (Section->SizeOfRawData) {
1024 if (!(ImageContext->IsTeImage)) {
1025 Status = ImageContext->ImageRead (
1026 ImageContext->Handle,
1027 Section->PointerToRawData,
1028 &Size,
1029 Base
1030 );
1031 } else {
1032 Status = ImageContext->ImageRead (
1033 ImageContext->Handle,
1034 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1035 &Size,
1036 Base
1037 );
1038 }
1039
1040 if (RETURN_ERROR (Status)) {
1041 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1042 return Status;
1043 }
1044 }
1045
1046 //
1047 // If raw size is less then virt size, zero fill the remaining
1048 //
1049
1050 if (Size < Section->Misc.VirtualSize) {
1051 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1052 }
1053
1054 //
1055 // Next Section
1056 //
1057 Section += 1;
1058 }
1059
1060 //
1061 // Get image's entry point
1062 //
1063 if (!(ImageContext->IsTeImage)) {
1064 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1065 ImageContext,
1066 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
1067 );
1068 } else {
1069 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
1070 (UINTN)ImageContext->ImageAddress +
1071 (UINTN)TeHdr->AddressOfEntryPoint +
1072 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1073 (UINTN) TeHdr->StrippedSize
1074 );
1075 }
1076
1077 //
1078 // Determine the size of the fixup data
1079 //
1080 // Per the PE/COFF spec, you can't assume that a given data directory
1081 // is present in the image. You have to check the NumberOfRvaAndSizes in
1082 // the optional header to verify a desired directory entry is there.
1083 //
1084 if (!(ImageContext->IsTeImage)) {
1085 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1086 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1087 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1088 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1089 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1090 } else {
1091 ImageContext->FixupDataSize = 0;
1092 }
1093 } else {
1094 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1095 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1096 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1097 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1098 } else {
1099 ImageContext->FixupDataSize = 0;
1100 }
1101 }
1102 } else {
1103 DirectoryEntry = &TeHdr->DataDirectory[0];
1104 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1105 }
1106 //
1107 // Consumer must allocate a buffer for the relocation fixup log.
1108 // Only used for runtime drivers.
1109 //
1110 ImageContext->FixupData = NULL;
1111
1112 //
1113 // Load the Codeview info if present
1114 //
1115 if (ImageContext->DebugDirectoryEntryRva != 0) {
1116 if (!(ImageContext->IsTeImage)) {
1117 DebugEntry = PeCoffLoaderImageAddress (
1118 ImageContext,
1119 ImageContext->DebugDirectoryEntryRva
1120 );
1121 } else {
1122 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1123 ImageContext->ImageAddress +
1124 ImageContext->DebugDirectoryEntryRva +
1125 sizeof(EFI_TE_IMAGE_HEADER) -
1126 TeHdr->StrippedSize
1127 );
1128 }
1129
1130 if (DebugEntry != NULL) {
1131 TempDebugEntryRva = DebugEntry->RVA;
1132 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1133 Section--;
1134 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1135 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1136 } else {
1137 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1138 }
1139 }
1140
1141 if (TempDebugEntryRva != 0) {
1142 if (!(ImageContext->IsTeImage)) {
1143 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1144 } else {
1145 ImageContext->CodeView = (VOID *)(
1146 (UINTN)ImageContext->ImageAddress +
1147 (UINTN)TempDebugEntryRva +
1148 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1149 (UINTN) TeHdr->StrippedSize
1150 );
1151 }
1152
1153 if (ImageContext->CodeView == NULL) {
1154 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1155 return RETURN_LOAD_ERROR;
1156 }
1157
1158 if (DebugEntry->RVA == 0) {
1159 Size = DebugEntry->SizeOfData;
1160 if (!(ImageContext->IsTeImage)) {
1161 Status = ImageContext->ImageRead (
1162 ImageContext->Handle,
1163 DebugEntry->FileOffset,
1164 &Size,
1165 ImageContext->CodeView
1166 );
1167 } else {
1168 Status = ImageContext->ImageRead (
1169 ImageContext->Handle,
1170 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1171 &Size,
1172 ImageContext->CodeView
1173 );
1174 //
1175 // Should we apply fix up to this field according to the size difference between PE and TE?
1176 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1177 // in original PE image.
1178 //
1179 }
1180
1181 if (RETURN_ERROR (Status)) {
1182 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1183 return RETURN_LOAD_ERROR;
1184 }
1185
1186 DebugEntry->RVA = TempDebugEntryRva;
1187 }
1188
1189 switch (*(UINT32 *) ImageContext->CodeView) {
1190 case CODEVIEW_SIGNATURE_NB10:
1191 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1192 break;
1193
1194 case CODEVIEW_SIGNATURE_RSDS:
1195 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1196 break;
1197
1198 case CODEVIEW_SIGNATURE_MTOC:
1199 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1200
1201 default:
1202 break;
1203 }
1204 }
1205 }
1206 }
1207
1208 return Status;
1209 }
1210
1211 /**
1212 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1213 loaded into system memory with the PE/COFF Loader Library functions.
1214
1215 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1216 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1217 returned. If the PE/COFF image specified by Pe32Data does not contain a
1218 debug directory entry, then NULL is returned. If the debug directory entry
1219 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1220 then NULL is returned.
1221 If Pe32Data is NULL, then return NULL.
1222
1223 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1224 memory.
1225
1226 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1227 if it cannot be retrieved.
1228
1229 **/
1230 VOID *
1231 EFIAPI
1232 PeCoffLoaderGetPdbPointer (
1233 IN VOID *Pe32Data
1234 )
1235 {
1236 EFI_IMAGE_DOS_HEADER *DosHdr;
1237 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1238 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1239 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1240 UINTN DirCount;
1241 VOID *CodeViewEntryPointer;
1242 INTN TEImageAdjust;
1243 UINT32 NumberOfRvaAndSizes;
1244 UINT16 Magic;
1245 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1246 UINT32 Index, Index1;
1247
1248 if (Pe32Data == NULL) {
1249 return NULL;
1250 }
1251
1252 TEImageAdjust = 0;
1253 DirectoryEntry = NULL;
1254 DebugEntry = NULL;
1255 NumberOfRvaAndSizes = 0;
1256 Index = 0;
1257 Index1 = 0;
1258 SectionHeader = NULL;
1259
1260 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1261 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
1262 //
1263 // DOS image header is present, so read the PE header after the DOS image header.
1264 //
1265 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1266 } else {
1267 //
1268 // DOS image header is not present, so PE header is at the image base.
1269 //
1270 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1271 }
1272
1273 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
1274 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
1275 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
1276 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
1277
1278 //
1279 // Get the DebugEntry offset in the raw data image.
1280 //
1281 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
1282 Index = Hdr.Te->NumberOfSections;
1283 for (Index1 = 0; Index1 < Index; Index1 ++) {
1284 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1285 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1286 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
1287 DirectoryEntry->VirtualAddress -
1288 SectionHeader [Index1].VirtualAddress +
1289 SectionHeader [Index1].PointerToRawData +
1290 TEImageAdjust);
1291 break;
1292 }
1293 }
1294 }
1295 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
1296 //
1297 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1298 // It is due to backward-compatibility, for some system might
1299 // generate PE32+ image with PE32 Magic.
1300 //
1301 switch (Hdr.Pe32->FileHeader.Machine) {
1302 case EFI_IMAGE_MACHINE_IA32:
1303 case EFI_IMAGE_MACHINE_ARMT:
1304 //
1305 // Assume PE32 image with IA32 Machine field.
1306 //
1307 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1308 break;
1309 case EFI_IMAGE_MACHINE_X64:
1310 case EFI_IMAGE_MACHINE_IPF:
1311 //
1312 // Assume PE32+ image with X64 or IPF 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 }