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 } 1477