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