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