typedef EFI_STATUS()

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