pecoffloader.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,408 行 · 第 1/4 页
C
1,408 行
Retrieves information on a PE/COFF image
Arguments:
This - Calling context
ImageContext - The context of the image being loaded
Returns:
EFI_SUCCESS if the information on the PE/COFF image was collected.
EFI_UNSUPPORTED of the PE/COFF image is not supported.
Otherwise, the error status from reading the PE/COFF image using the
ImageContext->ImageRead() function
EFI_INVALID_PARAMETER - ImageContext is NULL.
--*/
{
EFI_STATUS Status;
EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
UINTN Size;
UINTN Index;
UINTN DebugDirectoryEntryRva;
UINTN DebugDirectoryEntryFileOffset;
UINTN SectionHeaderOffset;
EFI_IMAGE_SECTION_HEADER SectionHeader;
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
UINT32 NumberOfRvaAndSizes;
UINT16 Magic;
if (NULL == ImageContext) {
return EFI_INVALID_PARAMETER;
}
//
// Assume success
//
ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;
Hdr.Union = &HdrData;
Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Verify machine type
//
Status = PeCoffLoaderCheckImageType (ImageContext);
if (EFI_ERROR (Status)) {
return Status;
}
Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
//
// Retrieve the base address of the image
//
if (!(ImageContext->IsTeImage)) {
//
// NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
// It is for backward-compatibility consideration, because
// some system will generate PE32+ image with PE32 Magic.
//
if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) {
Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
} else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) {
Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
} else if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) {
Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
} else {
Magic = Hdr.Pe32->OptionalHeader.Magic;
}
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
} else {
//
// Use PE32+ offset
//
ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
}
} else {
ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS)(Hdr.Te->ImageBase);
}
//
// Initialize the alternate destination address to 0 indicating that it
// should not be used.
//
ImageContext->DestinationAddress = 0;
//
// Initialize the codeview pointer.
//
ImageContext->CodeView = NULL;
ImageContext->PdbPointer = NULL;
//
// Three cases with regards to relocations:
// - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
// - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
// - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
// has no base relocs to apply
// Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
//
// Look at the file header to determine if relocations have been stripped, and
// save this info in the image context for later use.
//
if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
ImageContext->RelocationsStripped = TRUE;
} else {
ImageContext->RelocationsStripped = FALSE;
}
if (!(ImageContext->IsTeImage)) {
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
ImageContext->ImageSize = (UINT64) Hdr.Pe32->OptionalHeader.SizeOfImage;
ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
} else {
//
// Use PE32+ offset
//
ImageContext->ImageSize = (UINT64)Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
}
if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
//
// Determine the file offset of the debug directory... This means we walk
// the sections to find which section contains the RVA of the debug
// directory
//
DebugDirectoryEntryFileOffset = 0;
SectionHeaderOffset = (UINTN)(
ImageContext->PeCoffHeaderOffset +
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
//
// Read section header from file
//
Size = sizeof (EFI_IMAGE_SECTION_HEADER);
Status = ImageContext->ImageRead (
ImageContext->Handle,
SectionHeaderOffset,
&Size,
&SectionHeader
);
if (EFI_ERROR (Status)) {
ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
return Status;
}
if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
break;
}
SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (DebugDirectoryEntryFileOffset != 0) {
for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {
//
// Read next debug directory entry
//
Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
Status = ImageContext->ImageRead (
ImageContext->Handle,
DebugDirectoryEntryFileOffset,
&Size,
&DebugEntry
);
if (EFI_ERROR (Status)) {
ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
return Status;
}
if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
ImageContext->ImageSize += DebugEntry.SizeOfData;
}
return EFI_SUCCESS;
}
}
}
}
} else {
//
// Because Te image only extracts base relocations and debug directory entries from
// Pe image and in Te image header there is not a field to describe the imagesize,
// we use the largest VirtualAddress plus Size in each directory entry to describe the imagesize
//
ImageContext->ImageSize = (UINT64) (Hdr.Te->DataDirectory[0].VirtualAddress + Hdr.Te->DataDirectory[0].Size);
ImageContext->SectionAlignment = 4096;
ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) Hdr.Te->BaseOfCode - (UINTN) Hdr.Te->StrippedSize;
DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
DebugDirectoryEntryFileOffset = 0;
for (Index = 0; Index < Hdr.Te->NumberOfSections; Index++) {
//
// Read section header from file
//
Size = sizeof (EFI_IMAGE_SECTION_HEADER);
Status = ImageContext->ImageRead (
ImageContext->Handle,
SectionHeaderOffset,
&Size,
&SectionHeader
);
if (EFI_ERROR (Status)) {
ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
return Status;
}
if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
SectionHeader.VirtualAddress +
SectionHeader.PointerToRawData +
sizeof (EFI_TE_IMAGE_HEADER) -
Hdr.Te->StrippedSize;
break;
}
SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
}
if (DebugDirectoryEntryFileOffset != 0) {
for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {
//
// Read next debug directory entry
//
Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
Status = ImageContext->ImageRead (
ImageContext->Handle,
DebugDirectoryEntryFileOffset,
&Size,
&DebugEntry
);
if (EFI_ERROR (Status)) {
ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
return Status;
}
if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
return EFI_SUCCESS;
}
}
}
}
return EFI_SUCCESS;
}
STATIC
VOID *
PeCoffLoaderImageAddress (
IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN UINTN Address
)
/*++
Routine Description:
Converts an image address to the loaded address
Arguments:
ImageContext - The context of the image being loaded
Address - The address to be converted to the loaded address
Returns:
NULL if the address can not be converted, otherwise, the converted address
--*/
{
if (Address >= ImageContext->ImageSize) {
ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
return NULL;
}
return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);
}
EFI_STATUS
EFIAPI
PeCoffLoaderRelocateImage (
IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
/*++
Routine Description:
Relocates a PE/COFF image in memory
Arguments:
This - Calling context
ImageContext - Contains information on the loaded image to relocate
Returns:
EFI_SUCCESS if the PE/COFF image was relocated
EFI_LOAD_ERROR if the image is not a valid PE/COFF image
EFI_UNSUPPORTED not support
--*/
{
EFI_STATUS Status;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
EFI_IMAGE_DATA_DIRECTORY *RelocDir;
UINT64 Adjust;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?