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