in lsvmload/image.c [363:512]
typedef EFI_STATUS (EFIAPI *EntryPoint)(
EFI_HANDLE image_handle,
EFI_SYSTEM_TABLE *system_table);
static EFI_STATUS _FixupImage(
const UINT8 *image,
unsigned int imageSize,
EFI_LOADED_IMAGE *li,
EntryPoint* entryPoint)
{
EFI_STATUS status = EFI_UNSUPPORTED;
Headers headers;
UINT8 *newImage = NULL;
UINT8* baseReloc;
UINT32 baseRelocSize;
const EFI_IMAGE_SECTION_HEADER *relocSection = NULL;
const EFI_IMAGE_SECTION_HEADER *section = NULL;
int i;
/* Get and check the headers */
if ((status = _GetHeaders(image, imageSize, &headers)) != EFI_SUCCESS)
{
GOTO(done);
}
/* SizeOfImage could be smaller due to extra data at end of image */
imageSize = headers.oh.SizeOfImage;
/* Allocate a newImage to hold the new image */
if (!(newImage = Calloc(headers.oh.SizeOfImage, 1)))
{
GOTO(done);
}
/* Copy over the headers to the new image */
CHKBOUNDS(image, imageSize, image, headers.oh.SizeOfHeaders);
Memcpy(newImage, image, headers.oh.SizeOfHeaders);
/* Assign pointer and size to relocation region */
baseReloc = newImage + headers.relocDir->VirtualAddress;
baseRelocSize = headers.relocDir->Size;
CHKBOUNDS(
newImage,
imageSize,
newImage + headers.relocDir->VirtualAddress,
headers.relocDir->Size);
/* Get pointer to first section (already bounds checked) */
section = headers.firstSection;
/* For each section */
for (i = 0; i < headers.fh.NumberOfSections; i++, section++)
{
UINT8 *base = newImage + section->VirtualAddress;
UINT32 baseSize = section->Misc.VirtualSize;
const UINT8 RELOC_NAME[EFI_IMAGE_SIZEOF_SHORT_NAME] =
{ '.', 'r', 'e', 'l', 'o', 'c', '\0', '\0' };
CHKBOUNDS(image, imageSize, section, sizeof(EFI_IMAGE_SECTION_HEADER));
CHKBOUNDS(newImage, imageSize, base, baseSize);
if (baseSize > section->SizeOfRawData)
baseSize = section->SizeOfRawData;
/* If this is a relocation section */
if (Memcmp(section->Name, RELOC_NAME, sizeof(RELOC_NAME)) == 0)
{
/* Duplicate relocation section */
if (relocSection)
GOTO(done);
if (section->SizeOfRawData > 0 && section->Misc.VirtualSize > 0 &&
baseReloc == base && baseRelocSize == baseSize)
{
relocSection = section;
}
}
/* Skip discardable sections */
if (section->Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE)
continue;
/* Copy the section to the new newImage */
if (section->SizeOfRawData > 0)
{
CHKBOUNDS(
image,
imageSize,
image + section->PointerToRawData,
baseSize);
Memcpy(base, image + section->PointerToRawData, baseSize);
}
/* Zero out an residual memory */
if (section->Misc.VirtualSize > baseSize)
{
CHKBOUNDS(
newImage,
imageSize,
base + baseSize,
section->Misc.VirtualSize - baseSize);
Memset(base + baseSize, 0, section->Misc.VirtualSize - baseSize);
}
}
/* If no base relocation directory entry */
if (headers.oh.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)
GOTO(done);
/* If relocation entry found and non-zero in size, perform relocations */
if (relocSection && headers.relocDir->Size > 0)
{
if ((status = _ApplyRelocations(
&headers,
relocSection,
image,
imageSize,
newImage)) != EFI_SUCCESS)
{
GOTO(done);
}
}
/* Set the entry point */
CHKBOUNDS(
newImage,
imageSize,
newImage + headers.oh.AddressOfEntryPoint,
sizeof(entryPoint));
*entryPoint = (EntryPoint)(newImage + headers.oh.AddressOfEntryPoint);
/* Set the image base and size */
CHKBOUNDS(newImage, imageSize, newImage, headers.oh.SizeOfImage);
li->ImageBase = newImage;
li->ImageSize = headers.oh.SizeOfImage;
/* Set the load options (none for now) */
li->LoadOptions = NULL;
li->LoadOptionsSize = 0;
status = EFI_SUCCESS;
done:
if (status != EFI_SUCCESS)
Free(newImage);
return status;
}