mirror of
https://github.com/acidanthera/audk.git
synced 2025-09-26 19:18:42 +02:00
598 lines
20 KiB
C
598 lines
20 KiB
C
/** @file
|
|
Copyright (c) 2021, Marvin Häuser. All rights reserved.
|
|
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include "ImageTool.h"
|
|
|
|
#define PE_COFF_SECT_NAME_RELOC ".reloc\0"
|
|
#define PE_COFF_SECT_NAME_RESRC ".rsrc\0\0"
|
|
#define PE_COFF_SECT_NAME_DEBUG ".debug\0"
|
|
|
|
static
|
|
bool
|
|
ScanPeGetHeaderInfo (
|
|
OUT image_tool_header_info_t *HeaderInfo,
|
|
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context,
|
|
IN const char *ModuleType OPTIONAL
|
|
)
|
|
{
|
|
assert (HeaderInfo != NULL);
|
|
assert (Context != NULL);
|
|
|
|
HeaderInfo->PreferredAddress = (uint64_t)PeCoffGetImageBase (Context);
|
|
HeaderInfo->EntryPointAddress = PeCoffGetAddressOfEntryPoint (Context);
|
|
// FIXME:
|
|
HeaderInfo->Machine = PeCoffGetMachine (Context);
|
|
HeaderInfo->IsXip = true;
|
|
|
|
if (ModuleType == NULL) {
|
|
HeaderInfo->Subsystem = PeCoffGetSubsystem (Context);
|
|
return true;
|
|
}
|
|
|
|
if ((strcmp (ModuleType, "BASE") == 0)
|
|
|| (strcmp (ModuleType, "SEC") == 0)
|
|
|| (strcmp (ModuleType, "SECURITY_CORE") == 0)
|
|
|| (strcmp (ModuleType, "PEI_CORE") == 0)
|
|
|| (strcmp (ModuleType, "PEIM") == 0)
|
|
|| (strcmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "PIC_PEIM") == 0)
|
|
|| (strcmp (ModuleType, "RELOCATABLE_PEIM") == 0)
|
|
|| (strcmp (ModuleType, "DXE_CORE") == 0)
|
|
|| (strcmp (ModuleType, "BS_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "DXE_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "DXE_SMM_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "UEFI_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "SMM_CORE") == 0)
|
|
|| (strcmp (ModuleType, "MM_STANDALONE") == 0)
|
|
|| (strcmp (ModuleType, "MM_CORE_STANDALONE") == 0)) {
|
|
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
|
|
} else if ((strcmp (ModuleType, "UEFI_APPLICATION") == 0)
|
|
|| (strcmp (ModuleType, "APPLICATION") == 0)) {
|
|
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
|
|
} else if ((strcmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "RT_DRIVER") == 0)) {
|
|
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
|
|
} else if ((strcmp (ModuleType, "DXE_SAL_DRIVER") == 0)
|
|
|| (strcmp (ModuleType, "SAL_RT_DRIVER") == 0)) {
|
|
HeaderInfo->Subsystem = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
|
|
} else {
|
|
fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", ModuleType);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ScanPeGetRelocInfo (
|
|
OUT image_tool_reloc_info_t *RelocInfo,
|
|
IN const EFI_IMAGE_SECTION_HEADER *Section,
|
|
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
BOOLEAN Overflow;
|
|
UINT32 RelocBlockRvaMax;
|
|
UINT32 TopOfRelocDir;
|
|
UINT32 RelocBlockRva;
|
|
const EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock;
|
|
UINT32 RelocBlockSize;
|
|
UINT32 SizeOfRelocs;
|
|
UINT32 NumRelocs;
|
|
UINT32 RelocIndex;
|
|
uint32_t RelocDirSize;
|
|
const char *FileBuffer;
|
|
UINT16 RelocType;
|
|
UINT16 RelocOffset;
|
|
|
|
assert (Context != NULL);
|
|
assert (Section != NULL);
|
|
|
|
RelocInfo->RelocsStripped = false;
|
|
|
|
// FIXME: PE/COFF context access
|
|
RelocBlockRva = Section->PointerToRawData;
|
|
RelocDirSize = Section->VirtualSize;
|
|
//
|
|
// Verify the Relocation Directory is not empty.
|
|
//
|
|
if (RelocDirSize == 0) {
|
|
return true;
|
|
}
|
|
|
|
RelocInfo->Relocs = calloc (RelocDirSize / sizeof (UINT16), sizeof (*RelocInfo->Relocs));
|
|
if (RelocInfo->Relocs == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for Relocs[]\n");
|
|
return false;
|
|
}
|
|
|
|
TopOfRelocDir = RelocBlockRva + RelocDirSize;
|
|
|
|
RelocBlockRvaMax = TopOfRelocDir - sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK);
|
|
//
|
|
// Align TopOfRelocDir because, if the policy does not demand Relocation Block
|
|
// sizes to be aligned, the code below will manually align them. Thus, the
|
|
// end offset of the last Relocation Block must be compared to a manually
|
|
// aligned Relocation Directoriy end offset.
|
|
//
|
|
Overflow = BaseOverflowAlignUpU32 (
|
|
TopOfRelocDir,
|
|
ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK),
|
|
&TopOfRelocDir
|
|
);
|
|
if (Overflow) {
|
|
fprintf (stderr, "ImageTool: Overflow during TopOfRelocDir calculation\n");
|
|
return false;
|
|
}
|
|
//
|
|
// Apply all Base Relocations of the Image.
|
|
//
|
|
FileBuffer = (const char *)Context->FileBuffer;
|
|
while (RelocBlockRva <= RelocBlockRvaMax) {
|
|
RelocBlock = (const EFI_IMAGE_BASE_RELOCATION_BLOCK *)(const void *)(FileBuffer + RelocBlockRva);
|
|
//
|
|
// Verify the Base Relocation Block size is well-formed.
|
|
//
|
|
Overflow = BaseOverflowSubU32 (
|
|
RelocBlock->SizeOfBlock,
|
|
sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK),
|
|
&SizeOfRelocs
|
|
);
|
|
if (Overflow) {
|
|
fprintf (stderr, "ImageTool: Overflow during SizeOfRelocs calculation\n");
|
|
return false;
|
|
}
|
|
//
|
|
// Verify the Base Relocation Block is in bounds of the Relocation
|
|
// Directory.
|
|
//
|
|
if (SizeOfRelocs > RelocBlockRvaMax - RelocBlockRva) {
|
|
fprintf (stderr, "ImageTool: Base Relocation Block is out of bounds of the Relocation Directory\n");
|
|
return false;
|
|
}
|
|
//
|
|
// This arithmetic cannot overflow because we know
|
|
// 1) RelocBlock->SizeOfBlock <= RelocMax <= TopOfRelocDir
|
|
// 2) IS_ALIGNED (TopOfRelocDir, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)).
|
|
//
|
|
RelocBlockSize = ALIGN_VALUE (
|
|
RelocBlock->SizeOfBlock,
|
|
ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)
|
|
);
|
|
//
|
|
// This division is safe due to the guarantee made above.
|
|
//
|
|
NumRelocs = SizeOfRelocs / sizeof (*RelocBlock->Relocations);
|
|
//
|
|
// Process all Base Relocations of the current Block.
|
|
//
|
|
for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) {
|
|
RelocType = IMAGE_RELOC_TYPE (RelocBlock->Relocations[RelocIndex]);
|
|
RelocOffset = IMAGE_RELOC_OFFSET (RelocBlock->Relocations[RelocIndex]);
|
|
|
|
// FIXME: Make separate functions for UE
|
|
switch (RelocType) {
|
|
case EFI_IMAGE_REL_BASED_ABSOLUTE:
|
|
continue;
|
|
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
|
case EFI_IMAGE_REL_BASED_DIR64:
|
|
RelocInfo->Relocs[RelocInfo->NumRelocs].Type = (uint8_t)RelocType;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "ImageTool: Unknown RelocType = 0x%x\n", RelocType);
|
|
return false;
|
|
}
|
|
|
|
RelocInfo->Relocs[RelocInfo->NumRelocs].Target = RelocBlock->VirtualAddress + RelocOffset;
|
|
++RelocInfo->NumRelocs;
|
|
}
|
|
//
|
|
// This arithmetic cannot overflow because it has been checked that the
|
|
// Image Base Relocation Block is in bounds of the Image buffer.
|
|
//
|
|
RelocBlockRva += RelocBlockSize;
|
|
}
|
|
//
|
|
// Verify the Relocation Directory size matches the contained data.
|
|
//
|
|
if (RelocBlockRva != TopOfRelocDir) {
|
|
fprintf (stderr, "ImageTool: Relocation Directory size does not match the contained data\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ScanPeGetSegmentInfo (
|
|
OUT image_tool_segment_info_t *SegmentInfo,
|
|
OUT image_tool_hii_info_t *HiiInfo,
|
|
OUT image_tool_reloc_info_t *RelocInfo,
|
|
OUT image_tool_debug_info_t *DebugInfo,
|
|
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
const EFI_IMAGE_SECTION_HEADER *Section;
|
|
uint32_t NumSections;
|
|
image_tool_segment_t *ImageSegment;
|
|
const char *FileBuffer;
|
|
uint32_t Index;
|
|
UINT32 Size;
|
|
|
|
const EFI_IMAGE_NT_HEADERS *PeHdr;
|
|
const EFI_IMAGE_DATA_DIRECTORY *DebugDir;
|
|
UINT32 DebugDirTop;
|
|
bool Overflow;
|
|
UINT32 IndexD;
|
|
const EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
|
|
const char *CodeView;
|
|
UINT32 DebugTop;
|
|
UINT32 PdbOffset;
|
|
|
|
assert (SegmentInfo != NULL);
|
|
assert (HiiInfo != NULL);
|
|
assert (RelocInfo != NULL);
|
|
assert (DebugInfo != NULL);
|
|
assert (Context != NULL);
|
|
|
|
DebugDir = NULL;
|
|
|
|
SegmentInfo->SegmentAlignment = PeCoffGetSectionAlignment (Context);
|
|
|
|
NumSections = PeCoffGetSectionTable (Context, &Section);
|
|
|
|
SegmentInfo->Segments = calloc (NumSections, sizeof (*SegmentInfo->Segments));
|
|
if (SegmentInfo->Segments == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for Segments[]\n");
|
|
return false;
|
|
}
|
|
|
|
FileBuffer = (const char *)Context->FileBuffer;
|
|
|
|
PeHdr = (const EFI_IMAGE_NT_HEADERS *)(const void *)(FileBuffer + Context->ExeHdrOffset);
|
|
if (PeHdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
|
|
DebugDir = PeHdr->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_DEBUG;
|
|
Overflow = BaseOverflowAddU32 (DebugDir->VirtualAddress, DebugDir->Size, &DebugDirTop);
|
|
if (Overflow || (DebugDirTop > Context->SizeOfImage)) {
|
|
fprintf (stderr, "ImageTool: Corrupted DEBUG directory entry\n");
|
|
DebugDir = NULL;
|
|
}
|
|
}
|
|
|
|
ImageSegment = SegmentInfo->Segments;
|
|
for (Index = 0; Index < NumSections; ++Index, ++Section) {
|
|
STATIC_ASSERT (
|
|
sizeof(PE_COFF_SECT_NAME_RELOC) == sizeof(Section->Name) &&
|
|
sizeof(PE_COFF_SECT_NAME_RESRC) == sizeof(Section->Name) &&
|
|
sizeof(PE_COFF_SECT_NAME_DEBUG) == sizeof(Section->Name),
|
|
"Section names exceed section name bounds."
|
|
);
|
|
|
|
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) == 0
|
|
&& memcmp (Section->Name, PE_COFF_SECT_NAME_RELOC, sizeof (Section->Name)) != 0
|
|
&& memcmp (Section->Name, PE_COFF_SECT_NAME_RESRC, sizeof (Section->Name)) != 0
|
|
&& memcmp (Section->Name, PE_COFF_SECT_NAME_DEBUG, sizeof (Section->Name)) != 0) {
|
|
ImageSegment->Name = calloc (1, sizeof (Section->Name));
|
|
if (ImageSegment->Name == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for Segment Name\n");
|
|
return false;
|
|
}
|
|
|
|
memmove (ImageSegment->Name, Section->Name, sizeof (Section->Name));
|
|
|
|
Size = MAX (Section->VirtualSize, Section->SizeOfRawData);
|
|
Size = ALIGN_VALUE (Size, SegmentInfo->SegmentAlignment);
|
|
|
|
ImageSegment->Data = calloc (1, Size);
|
|
if (ImageSegment->Data == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for Segment Data\n");
|
|
free (ImageSegment->Name);
|
|
return false;
|
|
}
|
|
|
|
memmove (ImageSegment->Data, FileBuffer + Section->PointerToRawData, Section->SizeOfRawData);
|
|
|
|
ImageSegment->DataSize = Size;
|
|
ImageSegment->ImageAddress = Section->VirtualAddress;
|
|
ImageSegment->ImageSize = Size;
|
|
|
|
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_READ) != 0) {
|
|
ImageSegment->Read = true;
|
|
}
|
|
|
|
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) {
|
|
ImageSegment->Write = true;
|
|
}
|
|
|
|
if ((Section->Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) != 0) {
|
|
ImageSegment->Execute = true;
|
|
}
|
|
|
|
if (ImageSegment->Execute) {
|
|
ImageSegment->Type = ToolImageSectionTypeCode;
|
|
} else {
|
|
ImageSegment->Type = ToolImageSectionTypeInitialisedData;
|
|
}
|
|
|
|
++SegmentInfo->NumSegments;
|
|
++ImageSegment;
|
|
} else if (memcmp (Section->Name, PE_COFF_SECT_NAME_RESRC, sizeof (Section->Name)) == 0) {
|
|
Size = MAX (Section->VirtualSize, Section->SizeOfRawData);
|
|
Size = ALIGN_VALUE (Size, SegmentInfo->SegmentAlignment);
|
|
|
|
HiiInfo->Data = calloc (1, Size);
|
|
if (HiiInfo->Data == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for Hii Data\n");
|
|
return false;
|
|
}
|
|
|
|
memmove (HiiInfo->Data, FileBuffer + Section->PointerToRawData, Section->SizeOfRawData);
|
|
|
|
HiiInfo->DataSize = Size;
|
|
} else if (memcmp (Section->Name, PE_COFF_SECT_NAME_RELOC, sizeof (Section->Name)) == 0) {
|
|
if (!ScanPeGetRelocInfo (RelocInfo, Section, Context)) {
|
|
fprintf (stderr, "ImageTool: Could not retrieve reloc info\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ((DebugDir != NULL)
|
|
&& (DebugDir->VirtualAddress >= Section->VirtualAddress)
|
|
&& (DebugDirTop <= Section->VirtualAddress + Section->VirtualSize)) {
|
|
DebugEntry = (const EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(const void *)(
|
|
FileBuffer + Section->PointerToRawData + (DebugDir->VirtualAddress - Section->VirtualAddress));
|
|
|
|
for (IndexD = 0; (IndexD + sizeof (*DebugEntry)) <= DebugDir->Size; IndexD += sizeof (*DebugEntry), ++DebugEntry) {
|
|
if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
|
|
Overflow = BaseOverflowAddU32 (DebugEntry->FileOffset, DebugEntry->SizeOfData, &DebugTop);
|
|
if (Overflow || (DebugTop > Context->FileSize)) {
|
|
fprintf (stderr, "ImageTool: Corrupted DEBUG information\n");
|
|
continue;
|
|
}
|
|
|
|
CodeView = FileBuffer + DebugEntry->FileOffset;
|
|
switch (*(const UINT32 *)(const void *) CodeView) {
|
|
case CODEVIEW_SIGNATURE_NB10:
|
|
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
|
|
break;
|
|
case CODEVIEW_SIGNATURE_RSDS:
|
|
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
|
|
break;
|
|
case CODEVIEW_SIGNATURE_MTOC:
|
|
PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
|
|
break;
|
|
default:
|
|
fprintf (stderr, "ImageTool: Unknown CODEVIEW_SIGNATURE\n");
|
|
continue;
|
|
}
|
|
|
|
Overflow = BaseOverflowSubU32 (DebugEntry->SizeOfData, PdbOffset, &DebugInfo->SymbolsPathLen);
|
|
if (Overflow || (DebugInfo->SymbolsPathLen == 0)) {
|
|
fprintf (stderr, "ImageTool: Corrupted DEBUG string\n");
|
|
continue;
|
|
}
|
|
|
|
DebugInfo->SymbolsPath = calloc (1, DebugInfo->SymbolsPathLen);
|
|
if (DebugInfo->SymbolsPath == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n");
|
|
return false;
|
|
}
|
|
|
|
memmove (DebugInfo->SymbolsPath, CodeView + PdbOffset, DebugInfo->SymbolsPathLen - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ScanPeGetDebugInfo (
|
|
OUT image_tool_debug_info_t *DebugInfo,
|
|
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
const CHAR8 *PdbPath;
|
|
UINT32 PdbPathSize;
|
|
RETURN_STATUS Status;
|
|
|
|
assert (DebugInfo != NULL);
|
|
assert (Context != NULL);
|
|
|
|
Status = PeCoffGetPdbPath (Context, &PdbPath, &PdbPathSize);
|
|
if (Status == RETURN_NOT_FOUND) {
|
|
return true;
|
|
}
|
|
if (RETURN_ERROR (Status)) {
|
|
fprintf (stderr, "ImageTool: Could not get PdbPath\n");
|
|
return false;
|
|
}
|
|
|
|
DebugInfo->SymbolsPath = calloc (1, PdbPathSize);
|
|
if (DebugInfo->SymbolsPath == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n");
|
|
return false;
|
|
}
|
|
|
|
memmove (DebugInfo->SymbolsPath, PdbPath, PdbPathSize);
|
|
|
|
assert (PdbPathSize >= 1);
|
|
assert (DebugInfo->SymbolsPath[PdbPathSize - 1] == '\0');
|
|
|
|
DebugInfo->SymbolsPathLen = PdbPathSize - 1;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ScanPeGetHiiInfo (
|
|
OUT image_tool_hii_info_t *HiiInfo,
|
|
IN PE_COFF_LOADER_IMAGE_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT32 HiiRva;
|
|
UINT32 HiiSize;
|
|
RETURN_STATUS Status;
|
|
const char *ImageBuffer;
|
|
|
|
assert (HiiInfo != NULL);
|
|
assert (Context != NULL);
|
|
|
|
Status = PeCoffGetHiiDataRva (Context, &HiiRva, &HiiSize);
|
|
if (Status == RETURN_NOT_FOUND) {
|
|
return true;
|
|
}
|
|
if (RETURN_ERROR (Status)) {
|
|
fprintf (stderr, "ImageTool: Could not get HiiRva\n");
|
|
return false;
|
|
}
|
|
|
|
HiiInfo->Data = calloc (1, HiiSize);
|
|
if (HiiInfo->Data == NULL) {
|
|
fprintf (stderr, "ImageTool: Could not allocate memory for HiiInfo Data\n");
|
|
return false;
|
|
}
|
|
|
|
ImageBuffer = (char *)PeCoffLoaderGetImageAddress (Context);
|
|
|
|
memmove (HiiInfo->Data, ImageBuffer + HiiRva, HiiSize);
|
|
HiiInfo->DataSize = HiiSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
FixAddresses (
|
|
IN OUT image_tool_image_info_t *Image
|
|
)
|
|
{
|
|
UINT64 SizeOfHeaders;
|
|
UINT64 Delta;
|
|
UINT32 Index;
|
|
UINT32 IndexS;
|
|
image_tool_segment_t *Segment;
|
|
image_tool_reloc_t *Reloc;
|
|
UINT8 *Fixup;
|
|
UINT32 Fixup32;
|
|
UINT64 Fixup64;
|
|
|
|
assert (Image != NULL);
|
|
|
|
SizeOfHeaders = sizeof (EFI_IMAGE_DOS_HEADER) + sizeof (EFI_IMAGE_NT_HEADERS) +
|
|
EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES * sizeof (EFI_IMAGE_DATA_DIRECTORY) +
|
|
Image->SegmentInfo.NumSegments * sizeof (EFI_IMAGE_SECTION_HEADER);
|
|
|
|
if (Image->RelocInfo.Relocs != NULL) {
|
|
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
|
|
}
|
|
|
|
if (Image->DebugInfo.SymbolsPath != NULL) {
|
|
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
|
|
}
|
|
|
|
if (Image->HiiInfo.Data != NULL) {
|
|
SizeOfHeaders += sizeof (EFI_IMAGE_SECTION_HEADER);
|
|
}
|
|
|
|
SizeOfHeaders = ALIGN_VALUE (SizeOfHeaders, Image->SegmentInfo.SegmentAlignment);
|
|
if (SizeOfHeaders == Image->SegmentInfo.Segments[0].ImageAddress) {
|
|
return true;
|
|
}
|
|
|
|
Delta = Image->SegmentInfo.Segments[0].ImageAddress - SizeOfHeaders;
|
|
|
|
Image->HeaderInfo.EntryPointAddress -= (UINT32)Delta;
|
|
|
|
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
|
|
Image->SegmentInfo.Segments[Index].ImageAddress -= Delta;
|
|
}
|
|
|
|
if (Image->RelocInfo.Relocs != NULL) {
|
|
Segment = Image->SegmentInfo.Segments;
|
|
Reloc = Image->RelocInfo.Relocs;
|
|
|
|
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
|
|
Reloc[Index].Target -= (UINT32)Delta;
|
|
|
|
for (IndexS = 0; IndexS < Image->SegmentInfo.NumSegments; ++IndexS) {
|
|
if ((Reloc[Index].Target >= Segment[IndexS].ImageAddress)
|
|
&& ((Reloc[Index].Target - Segment[IndexS].ImageAddress) < Segment[IndexS].ImageSize)) {
|
|
Fixup = Segment[IndexS].Data + (Reloc[Index].Target - Segment[IndexS].ImageAddress);
|
|
switch (Reloc[Index].Type) {
|
|
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
|
Fixup32 = ReadUnaligned32 ((CONST VOID *) Fixup);
|
|
Fixup32 -= (UINT32)Delta;
|
|
WriteUnaligned32 ((VOID *) Fixup, Fixup32);
|
|
break;
|
|
case EFI_IMAGE_REL_BASED_DIR64:
|
|
Fixup64 = ReadUnaligned64 ((CONST VOID *) Fixup);
|
|
Fixup64 -= Delta;
|
|
WriteUnaligned64 ((VOID *) Fixup, Fixup64);
|
|
break;
|
|
default:
|
|
fprintf (stderr, "ImageTool: Unknown relocation type %u\n", Reloc[Index].Type);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Image->HiiInfo.Data != NULL) {
|
|
SetHiiResourceHeader (Image->HiiInfo.Data, (UINT32)(0ULL - Delta));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ToolContextConstructPe (
|
|
OUT image_tool_image_info_t *Image,
|
|
IN const void *File,
|
|
IN size_t FileSize,
|
|
IN const char *ModuleType OPTIONAL
|
|
)
|
|
{
|
|
PE_COFF_LOADER_IMAGE_CONTEXT Context;
|
|
RETURN_STATUS Status;
|
|
bool Result;
|
|
|
|
assert (Image != NULL);
|
|
assert (File != NULL || FileSize == 0);
|
|
|
|
if (FileSize > MAX_UINT32) {
|
|
fprintf (stderr, "ImageTool: FileSize is too huge\n");
|
|
return false;
|
|
}
|
|
|
|
Status = PeCoffInitializeContext (&Context, File, (UINT32)FileSize);
|
|
if (RETURN_ERROR (Status)) {
|
|
fprintf (stderr, "ImageTool: Could not initialise Context\n");
|
|
return false;
|
|
}
|
|
|
|
memset (Image, 0, sizeof (*Image));
|
|
|
|
Result = ScanPeGetHeaderInfo (&Image->HeaderInfo, &Context, ModuleType);
|
|
if (!Result) {
|
|
fprintf (stderr, "ImageTool: Could not retrieve header info\n");
|
|
return false;
|
|
}
|
|
|
|
Result = ScanPeGetSegmentInfo (&Image->SegmentInfo, &Image->HiiInfo, &Image->RelocInfo, &Image->DebugInfo, &Context);
|
|
if (!Result) {
|
|
fprintf (stderr, "ImageTool: Could not retrieve segment info\n");
|
|
return false;
|
|
}
|
|
|
|
Result = FixAddresses (Image);
|
|
|
|
return Result;
|
|
}
|