871 lines
25 KiB
C

/** @file
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
**/
#include "ImageTool.h"
static Elf_Ehdr *mEhdr = NULL;
static Elf_Size mPeAlignment = 0x0;
#if defined(EFI_TARGET64)
// static UINT8 *mGotData = NULL;
static UINT32 mWGotOffset = 0x0;
static const Elf_Shdr *mGOTShdr = NULL;
static UINT32 *mGOTPeEntries = NULL;
static UINT32 mGOTMaxEntries = 0;
static UINT32 mGOTNumEntries = 0;
#endif
#if defined (_MSC_EXTENSIONS)
#define EFI_IMAGE_MACHINE_IA32 0x014C
#define EFI_IMAGE_MACHINE_X64 0x8664
#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01C2
#define EFI_IMAGE_MACHINE_AARCH64 0xAA64
#endif
extern image_tool_image_info_t mImageInfo;
static
Elf_Shdr *
GetShdrByIndex (
IN UINT32 Index
)
{
UINTN Offset;
assert (Index < mEhdr->e_shnum);
Offset = (UINTN)mEhdr->e_shoff + Index * mEhdr->e_shentsize;
return (Elf_Shdr *)((UINT8 *)mEhdr + Offset);
}
static
Elf_Sym *
GetSymbol (
IN UINT32 TableIndex,
IN UINT32 SymbolIndex
)
{
const Elf_Shdr *TableShdr;
UINT8 *Symtab;
TableShdr = GetShdrByIndex (TableIndex);
Symtab = (UINT8 *)mEhdr + TableShdr->sh_offset;
return (Elf_Sym *)(Symtab + SymbolIndex * TableShdr->sh_entsize);
}
static
char *
GetString (
IN UINT32 Offset
)
{
const Elf_Shdr *Shdr;
char *String;
Shdr = GetShdrByIndex (mEhdr->e_shstrndx);
if (Offset >= Shdr->sh_size) {
fprintf (stderr, "ImageTool: Invalid ELF string offset\n");
return NULL;
}
String = (char *)((UINT8 *)mEhdr + Shdr->sh_offset + Offset);
return String;
}
static
BOOLEAN
IsTextShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
return ((((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) ||
((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC))
&& (Shdr->sh_type == SHT_PROGBITS));
}
static
BOOLEAN
IsHiiRsrcShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
Elf_Shdr *Namedr = GetShdrByIndex (mEhdr->e_shstrndx);
return (BOOLEAN) (strcmp ((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);
}
static
BOOLEAN
IsDataShdr (
IN const Elf_Shdr *Shdr
)
{
assert (Shdr != NULL);
if (IsHiiRsrcShdr (Shdr)) {
return FALSE;
}
return (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE))
&& ((Shdr->sh_type == SHT_PROGBITS) || (Shdr->sh_type == SHT_NOBITS)));
}
static
BOOLEAN
IsRelocShdr (
IN const Elf_Shdr *Shdr
)
{
const Elf_Shdr *SecShdr;
const Elf_Rel *Rel;
UINTN Index;
assert (Shdr != NULL);
if ((Shdr->sh_type != SHT_REL) && (Shdr->sh_type != SHT_RELA)) {
return FALSE;
}
SecShdr = GetShdrByIndex (Shdr->sh_info);
if ((!IsTextShdr (SecShdr)) && (!IsDataShdr (SecShdr))) {
return FALSE;
}
for (Index = 0; Index < Shdr->sh_size; Index += (UINTN)Shdr->sh_entsize) {
Rel = (Elf_Rel *)((UINT8 *)mEhdr + Shdr->sh_offset + Index);
#if defined(EFI_TARGET64)
if ((ELF_R_TYPE(Rel->r_info) == R_X86_64_64)
|| (ELF_R_TYPE(Rel->r_info) == R_X86_64_32)) {
return TRUE;
}
#elif defined(EFI_TARGET32)
if (ELF_R_TYPE(Rel->r_info) == R_386_32) {
return TRUE;
}
#endif
}
return FALSE;
}
static
VOID
SetHiiResourceHeader (
IN OUT UINT8 *Hii,
IN UINT32 Offset
)
{
UINT32 Index;
EFI_IMAGE_RESOURCE_DIRECTORY *RDir;
EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *RDirEntry;
EFI_IMAGE_RESOURCE_DIRECTORY_STRING *RDirString;
EFI_IMAGE_RESOURCE_DATA_ENTRY *RDataEntry;
assert (Hii != NULL);
//
// Fill Resource section entry
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)Hii;
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
for (Index = 0; Index < RDir->NumberOfNamedEntries; ++Index) {
if (RDirEntry->u1.s.NameIsString) {
RDirString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Hii + RDirEntry->u1.s.NameOffset);
if ((RDirString->Length == 3)
&& (RDirString->String[0] == L'H')
&& (RDirString->String[1] == L'I')
&& (RDirString->String[2] == L'I')) {
//
// Resource Type "HII" found
//
if (RDirEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Name
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Hii + RDirEntry->u2.s.OffsetToDirectory);
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
if (RDirEntry->u2.s.DataIsDirectory) {
//
// Move to next level - resource Language
//
RDir = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Hii + RDirEntry->u2.s.OffsetToDirectory);
RDirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(RDir + 1);
}
}
//
// Now it ought to be resource Data. Update its OffsetToData value
//
if (!RDirEntry->u2.s.DataIsDirectory) {
RDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Hii + RDirEntry->u2.OffsetToData);
RDataEntry->OffsetToData = RDataEntry->OffsetToData + Offset;
break;
}
}
}
RDirEntry++;
}
return;
}
#if defined(EFI_TARGET64)
RETURN_STATUS
FindElfGOTSectionFromGOTEntryElfRva (
IN Elf_Addr GOTEntryElfRva
)
{
UINT32 Index;
const Elf_Shdr *Shdr;
if (mGOTShdr != NULL) {
if ((GOTEntryElfRva >= mGOTShdr->sh_addr)
&& (GOTEntryElfRva < (mGOTShdr->sh_addr + mGOTShdr->sh_size))) {
return RETURN_SUCCESS;
}
fprintf (stderr, "ImageTool: GOT entries found in multiple sections\n");
return RETURN_UNSUPPORTED;
}
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex(Index);
if ((GOTEntryElfRva >= Shdr->sh_addr)
&& (GOTEntryElfRva < (Shdr->sh_addr + Shdr->sh_size))) {
mGOTShdr = Shdr;
// FindAddress (Index, &mGotData, &mWGotOffset);
return RETURN_SUCCESS;
}
}
fprintf (stderr, "ImageTool: ElfRva 0x%016llx for GOT entry not found in any section\n", GOTEntryElfRva);
return RETURN_VOLUME_CORRUPTED;
}
RETURN_STATUS
AccumulatePeGOTEntries (
IN UINT32 GOTPeEntry,
OUT BOOLEAN *IsNew
)
{
UINT32 Index;
assert (IsNew != NULL);
if (mGOTPeEntries != NULL) {
for (Index = 0; Index < mGOTNumEntries; ++Index) {
if (mGOTPeEntries[Index] == GOTPeEntry) {
*IsNew = FALSE;
return RETURN_SUCCESS;
}
}
}
if (mGOTPeEntries == NULL) {
mGOTMaxEntries = 5;
mGOTNumEntries = 0;
mGOTPeEntries = calloc (1, mGOTMaxEntries * sizeof (*mGOTPeEntries));
if (mGOTPeEntries == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for mGOTPeEntries\n");
return RETURN_OUT_OF_RESOURCES;
}
} else if (mGOTNumEntries == mGOTMaxEntries) {
mGOTMaxEntries *= 2;
mGOTPeEntries = realloc (mGOTPeEntries, mGOTMaxEntries * sizeof (*mGOTPeEntries));
if (mGOTPeEntries == NULL) {
fprintf (stderr, "ImageTool: Could not reallocate memory for mGOTPeEntries\n");
return RETURN_OUT_OF_RESOURCES;
}
}
mGOTPeEntries[mGOTNumEntries] = mWGotOffset + GOTPeEntry;
++mGOTNumEntries;
*IsNew = TRUE;
return RETURN_SUCCESS;
}
#endif
static
RETURN_STATUS
ReadElfFile (
IN const char *Name
)
{
static const unsigned char Ident[] = {
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS, ELFDATA2LSB
};
const Elf_Shdr *Shdr;
UINTN Offset;
UINT32 Index;
UINT32 FileSize;
char *Last;
assert (Name != NULL);
mEhdr = (Elf_Ehdr *)UserReadFile (Name, &FileSize);
if (mEhdr == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", Name, strerror (errno));
return RETURN_VOLUME_CORRUPTED;
}
//
// Check header
//
if ((FileSize < sizeof (*mEhdr))
|| (memcmp (Ident, mEhdr->e_ident, sizeof (Ident)) != 0)) {
fprintf (stderr, "ImageTool: Invalid ELF header in file %s\n", Name);
fprintf (stderr, "ImageTool: mEhdr->e_ident[0] = 0x%x expected 0x%x\n", mEhdr->e_ident[0], Ident[0]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[1] = 0x%x expected 0x%x\n", mEhdr->e_ident[1], Ident[1]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[2] = 0x%x expected 0x%x\n", mEhdr->e_ident[2], Ident[2]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[3] = 0x%x expected 0x%x\n", mEhdr->e_ident[3], Ident[3]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[4] = 0x%x expected 0x%x\n", mEhdr->e_ident[4], Ident[4]);
fprintf (stderr, "ImageTool: mEhdr->e_ident[5] = 0x%x expected 0x%x\n", mEhdr->e_ident[5], Ident[5]);
fprintf (stderr, "ImageTool: FileSize = 0x%x sizeof(*mEhdr) = 0x%lx\n", FileSize, sizeof (*mEhdr));
return RETURN_VOLUME_CORRUPTED;
}
if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {
fprintf (stderr, "ImageTool: ELF e_type not ET_EXEC or ET_DYN\n");
return RETURN_UNSUPPORTED;
}
#if defined(EFI_TARGET64)
if (mEhdr->e_machine != EM_X86_64) {
fprintf (stderr, "ImageTool: Unsupported ELF e_machine\n");
return RETURN_UNSUPPORTED;
}
#elif defined(EFI_TARGET32)
if (mEhdr->e_machine != EM_386) {
fprintf (stderr, "ImageTool: Unsupported ELF e_machine\n");
return RETURN_UNSUPPORTED;
}
#endif
//
// Check section headers
//
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Offset = (UINTN)mEhdr->e_shoff + Index * mEhdr->e_shentsize;
if (FileSize < (Offset + sizeof (*Shdr))) {
fprintf (stderr, "ImageTool: ELF section header is outside file %s\n", Name);
return RETURN_VOLUME_CORRUPTED;
}
Shdr = (Elf_Shdr *)((UINT8 *)mEhdr + Offset);
if ((Shdr->sh_type != SHT_NOBITS)
&& ((FileSize < Shdr->sh_offset) || ((FileSize - Shdr->sh_offset) < Shdr->sh_size))) {
fprintf (stderr, "ImageTool: ELF section %d points outside file %s\n", Index, Name);
return RETURN_VOLUME_CORRUPTED;
}
if (Shdr->sh_link >= mEhdr->e_shnum) {
fprintf (stderr, "ImageTool: ELF %d-th section's sh_link is out of range\n", Index);
return RETURN_VOLUME_CORRUPTED;
}
if (((Shdr->sh_type == SHT_RELA) || (Shdr->sh_type == SHT_REL))
&& (Shdr->sh_info >= mEhdr->e_shnum)) {
fprintf (stderr, "ImageTool: ELF %d-th section's sh_info is out of range\n", Index);
return RETURN_VOLUME_CORRUPTED;
}
if (Shdr->sh_addralign <= mPeAlignment) {
continue;
}
if ((IsTextShdr (Shdr)) || (IsDataShdr (Shdr)) || (IsHiiRsrcShdr (Shdr))) {
mPeAlignment = Shdr->sh_addralign;
}
}
if (mEhdr->e_shstrndx >= mEhdr->e_shnum) {
fprintf (stderr, "ImageTool: Invalid section name string table\n");
return RETURN_VOLUME_CORRUPTED;
}
Shdr = GetShdrByIndex (mEhdr->e_shstrndx);
if (Shdr->sh_type != SHT_STRTAB) {
fprintf (stderr, "ImageTool: ELF string table section has wrong type\n");
return RETURN_VOLUME_CORRUPTED;
}
Last = (char *)((UINT8 *)mEhdr + Shdr->sh_offset + Shdr->sh_size - 1);
if (*Last != '\0') {
fprintf (stderr, "ImageTool: ELF string table section is not NUL-terminated\n");
return RETURN_VOLUME_CORRUPTED;
}
if ((!IS_POW2(mPeAlignment)) || (mPeAlignment > MAX_PE_ALIGNMENT)) {
fprintf (stderr, "ImageTool: Invalid section alignment\n");
return RETURN_VOLUME_CORRUPTED;
}
return RETURN_SUCCESS;
}
static
RETURN_STATUS
FixSegmentsSetRelocs (
VOID
)
{
UINT32 Index;
const Elf_Shdr *RelShdr;
const Elf_Shdr *SecShdr;
UINTN RelIdx;
const Elf_Rela *Rel;
const Elf_Sym *Sym;
UINT32 RelNum;
UINTN Offset;
#if defined(EFI_TARGET64)
// Elf_Addr GOTEntryRva;
// RETURN_STATUS Status;
// BOOLEAN IsNew;
#endif
RelNum = 0;
for (Index = 0; Index < mEhdr->e_shnum; Index++) {
RelShdr = GetShdrByIndex (Index);
if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
continue;
}
if (RelShdr->sh_info == 0) {
continue;
}
SecShdr = GetShdrByIndex (RelShdr->sh_info);
#if defined(EFI_TARGET64)
if ((RelShdr->sh_type != SHT_RELA) || (!((IsTextShdr (SecShdr)) || (IsDataShdr (SecShdr))))) {
continue;
}
#elif defined(EFI_TARGET32)
if ((RelShdr->sh_type != SHT_REL) || (!((IsTextShdr (SecShdr)) || (IsDataShdr (SecShdr))))) {
continue;
}
#endif
//
// Process all relocation entries for this section.
//
for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINTN)RelShdr->sh_entsize) {
Rel = (Elf_Rela *)((UINT8 *)mEhdr + RelShdr->sh_offset + RelIdx);
Offset = (UINTN)Rel->r_offset;
//
// Set pointer to symbol table entry associated with the relocation entry.
//
Sym = GetSymbol (RelShdr->sh_link, ELF_R_SYM(Rel->r_info));
if ((Sym->st_shndx == SHN_UNDEF) || (Sym->st_shndx >= mEhdr->e_shnum)) {
continue;
}
#if defined(EFI_TARGET64)
switch (ELF_R_TYPE(Rel->r_info)) {
case R_X86_64_NONE:
break;
case R_X86_64_64:
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_DIR64;
mImageInfo.RelocInfo.Relocs[RelNum].Target = (uint32_t)Offset;
++RelNum;
break;
case R_X86_64_32:
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_HIGHLOW;
mImageInfo.RelocInfo.Relocs[RelNum].Target = (uint32_t)Offset;
++RelNum;
break;
case R_X86_64_32S:
case R_X86_64_PLT32:
case R_X86_64_PC32:
break;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
// GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ;
//
// Status = FindElfGOTSectionFromGOTEntryElfRva (GOTEntryRva);
// if (RETURN_ERROR (Status)) {
// return Status;
// }
//
// WriteUnaligned32 ((UINT32 *)Targ, (UINT32)(ReadUnaligned32((UINT32 *)Targ) + (mWGotOffset - mGOTShdr->sh_addr) - (WSecOffset - SecShdr->sh_addr)));
// //
// // ELF Rva -> Offset in PE GOT
// //
// GOTEntryRva -= mGOTShdr->sh_addr;
//
// Status = AccumulatePeGOTEntries ((UINT32)GOTEntryRva, &IsNew);
// if (RETURN_ERROR (Status)) {
// return Status;
// }
//
// if (IsNew) {
// //
// // Relocate GOT entry if it's the first time we run into it
// //
// Targ = mGotData + GOTEntryRva;
//
// WriteUnaligned64 ((UINT64 *)Targ, ReadUnaligned64((UINT64 *)Targ) - SymShdr->sh_addr + WSymOffset);
// }
break;
default:
fprintf (stderr, "ImageTool: Unsupported ELF EM_X86_64 relocation 0x%llx\n", ELF_R_TYPE(Rel->r_info));
return RETURN_UNSUPPORTED;
}
#elif defined(EFI_TARGET32)
switch (ELF_R_TYPE(Rel->r_info)) {
case R_386_NONE:
break;
case R_386_32:
mImageInfo.RelocInfo.Relocs[RelNum].Type = EFI_IMAGE_REL_BASED_HIGHLOW;
mImageInfo.RelocInfo.Relocs[RelNum].Target = Offset;
++RelNum;
break;
case R_386_PLT32:
case R_386_PC32:
break;
default:
fprintf (stderr, "ImageTool: Unsupported ELF EM_386 relocation 0x%x\n", ELF_R_TYPE(Rel->r_info));
return RETURN_UNSUPPORTED;
}
#endif
}
}
assert (RelNum == mImageInfo.RelocInfo.NumRelocs);
return RETURN_SUCCESS;
}
static
RETURN_STATUS
FixAddresses (
VOID
)
{
RETURN_STATUS Status;
#if defined(EFI_TARGET64)
UINT32 Index;
UINT32 NewSize;
#endif
Status = FixSegmentsSetRelocs ();
if (RETURN_ERROR (Status)) {
return Status;
}
#if defined(EFI_TARGET64)
if (mGOTPeEntries != NULL) {
NewSize = (mImageInfo.RelocInfo.NumRelocs + mGOTNumEntries) * sizeof (*mImageInfo.RelocInfo.Relocs);
mImageInfo.RelocInfo.Relocs = realloc (mImageInfo.RelocInfo.Relocs, NewSize);
if (mImageInfo.RelocInfo.Relocs == NULL) {
fprintf (stderr, "ImageTool: Could not reallocate memory for Relocs\n");
return RETURN_OUT_OF_RESOURCES;
}
for (Index = 0; Index < mGOTNumEntries; ++Index) {
mImageInfo.RelocInfo.Relocs[mImageInfo.RelocInfo.NumRelocs + Index].Type = EFI_IMAGE_REL_BASED_DIR64;
mImageInfo.RelocInfo.Relocs[mImageInfo.RelocInfo.NumRelocs + Index].Target = mGOTPeEntries[Index];
}
}
#endif
return RETURN_SUCCESS;
}
static
RETURN_STATUS
CreateIntermediate (
VOID
)
{
const Elf_Shdr *Shdr;
UINT32 Index;
image_tool_segment_t *Segments;
image_tool_reloc_t *Relocs;
UINT32 SIndex;
const Elf_Rel *Rel;
UINTN RIndex;
char *Name;
UINT64 Pointer;
Segments = NULL;
SIndex = 0;
Relocs = NULL;
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex (Index);
if ((IsTextShdr (Shdr)) || (IsDataShdr (Shdr))) {
++mImageInfo.SegmentInfo.NumSegments;
}
if (IsRelocShdr (Shdr)) {
for (RIndex = 0; RIndex < Shdr->sh_size; RIndex += (UINTN)Shdr->sh_entsize) {
Rel = (Elf_Rel *)((UINT8 *)mEhdr + Shdr->sh_offset + RIndex);
#if defined(EFI_TARGET64)
if ((ELF_R_TYPE(Rel->r_info) == R_X86_64_64)
|| (ELF_R_TYPE(Rel->r_info) == R_X86_64_32)) {
++mImageInfo.RelocInfo.NumRelocs;
}
#elif defined(EFI_TARGET32)
if (ELF_R_TYPE(Rel->r_info) == R_386_32) {
++mImageInfo.RelocInfo.NumRelocs;
}
#endif
}
}
}
if (mImageInfo.SegmentInfo.NumSegments == 0) {
fprintf (stderr, "ImageTool: No .text or .data sections\n");
return RETURN_VOLUME_CORRUPTED;
}
Segments = calloc (1, sizeof (*Segments) * mImageInfo.SegmentInfo.NumSegments);
if (Segments == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segments\n");
return RETURN_OUT_OF_RESOURCES;
};
mImageInfo.SegmentInfo.Segments = Segments;
if (mImageInfo.RelocInfo.NumRelocs != 0) {
Relocs = calloc (1, sizeof (*Relocs) * mImageInfo.RelocInfo.NumRelocs);
if (Relocs == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Relocs\n");
return RETURN_OUT_OF_RESOURCES;
};
mImageInfo.RelocInfo.Relocs = Relocs;
}
//
// Assume 4K alignment, which must be enough for all PE headers.
//
Pointer = mPeAlignment;
for (Index = 0; Index < mEhdr->e_shnum; ++Index) {
Shdr = GetShdrByIndex (Index);
if (IsTextShdr (Shdr)) {
Name = GetString (Shdr->sh_name);
if (Name == NULL) {
return RETURN_VOLUME_CORRUPTED;
}
Segments[SIndex].Name = calloc (1, strlen (Name) + 1);
if (Segments[SIndex].Name == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Name\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
Segments[SIndex].Data = calloc (1, Segments[SIndex].DataSize);
if (Segments[SIndex].Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Data\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
Segments[SIndex].ImageAddress = Pointer;
Segments[SIndex].ImageSize = Segments[SIndex].DataSize;
Segments[SIndex].Read = true;
Segments[SIndex].Write = false;
Segments[SIndex].Execute = true;
Segments[SIndex].Type = ToolImageSectionTypeCode;
Pointer += Segments[SIndex].DataSize;
++SIndex;
continue;
}
if (IsDataShdr (Shdr)) {
Name = GetString (Shdr->sh_name);
if (Name == NULL) {
return RETURN_VOLUME_CORRUPTED;
}
Segments[SIndex].Name = calloc (1, strlen (Name) + 1);
if (Segments[SIndex].Name == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Name\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
Segments[SIndex].Data = calloc (1, Segments[SIndex].DataSize);
if (Segments[SIndex].Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Segment #%d Data\n", SIndex);
return RETURN_OUT_OF_RESOURCES;
};
if (Shdr->sh_type == SHT_PROGBITS) {
memcpy (Segments[SIndex].Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
}
Segments[SIndex].ImageAddress = Pointer;
Segments[SIndex].ImageSize = Segments[SIndex].DataSize;
Segments[SIndex].Read = true;
Segments[SIndex].Write = true;
Segments[SIndex].Execute = false;
Segments[SIndex].Type = ToolImageSectionTypeInitialisedData;
Pointer += Segments[SIndex].DataSize;
++SIndex;
continue;
}
if (IsHiiRsrcShdr (Shdr)) {
mImageInfo.HiiInfo.DataSize = (uint32_t)ALIGN_VALUE (Shdr->sh_size, mPeAlignment);
mImageInfo.HiiInfo.Data = calloc (1, mImageInfo.HiiInfo.DataSize);
if (mImageInfo.HiiInfo.Data == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Hii Data\n");
return RETURN_OUT_OF_RESOURCES;
};
if (Shdr->sh_type == SHT_PROGBITS) {
memcpy (mImageInfo.HiiInfo.Data, (UINT8 *)mEhdr + Shdr->sh_offset, (size_t)Shdr->sh_size);
SetHiiResourceHeader (mImageInfo.HiiInfo.Data, (UINT32)Pointer);
Pointer += mImageInfo.HiiInfo.DataSize;
}
}
}
assert (SIndex == mImageInfo.SegmentInfo.NumSegments);
return FixAddresses();
}
RETURN_STATUS
ScanElf (
IN const char *ElfName,
IN const char *ModuleType
)
{
RETURN_STATUS Status;
assert (ElfName != NULL);
assert (ModuleType != NULL);
Status = ReadElfFile (ElfName);
if (RETURN_ERROR (Status)) {
if (mEhdr != NULL) {
free (mEhdr);
}
return Status;
}
memset (&mImageInfo, 0, sizeof (mImageInfo));
mImageInfo.HeaderInfo.PreferredAddress = 0;
mImageInfo.HeaderInfo.EntryPointAddress = (uint32_t)mEhdr->e_entry;
mImageInfo.HeaderInfo.IsXip = true;
mImageInfo.SegmentInfo.SegmentAlignment = (uint32_t)mPeAlignment;
mImageInfo.RelocInfo.RelocsStripped = false;
mImageInfo.DebugInfo.SymbolsPathLen = strlen (ElfName) + 1;
switch (mEhdr->e_machine) {
case EM_386:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_IA32;
break;
case EM_X86_64:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_X64;
break;
case EM_ARM:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED;
break;
case EM_AARCH64:
mImageInfo.HeaderInfo.Machine = EFI_IMAGE_MACHINE_AARCH64;
break;
default:
fprintf (stderr, "ImageTool: Unknown ELF architecture %d\n", mEhdr->e_machine);
free (mEhdr);
return RETURN_UNSUPPORTED;
}
mImageInfo.DebugInfo.SymbolsPath = calloc (1, mImageInfo.DebugInfo.SymbolsPathLen);
if (mImageInfo.DebugInfo.SymbolsPath == NULL) {
fprintf (stderr, "ImageTool: Could not allocate memory for Debug Data\n");
free (mEhdr);
return RETURN_OUT_OF_RESOURCES;
};
memcpy (mImageInfo.DebugInfo.SymbolsPath, ElfName, mImageInfo.DebugInfo.SymbolsPathLen);
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)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
} else if ((strcmp (ModuleType, "UEFI_APPLICATION") == 0)
|| (strcmp (ModuleType, "APPLICATION") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
} else if ((strcmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0)
|| (strcmp (ModuleType, "RT_DRIVER") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
} else if ((strcmp (ModuleType, "DXE_SAL_DRIVER") == 0)
|| (strcmp (ModuleType, "SAL_RT_DRIVER") == 0)) {
mImageInfo.HeaderInfo.Subsystem = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
} else {
fprintf (stderr, "ImageTool: Unknown EFI_FILETYPE = %s\n", ModuleType);
free (mImageInfo.DebugInfo.SymbolsPath);
free (mEhdr);
return RETURN_UNSUPPORTED;
}
Status = CreateIntermediate ();
if (RETURN_ERROR (Status)) {
ToolImageDestruct (&mImageInfo);
}
#if defined(EFI_TARGET64)
if (mGOTPeEntries != NULL) {
free (mGOTPeEntries);
}
#endif
free (mEhdr);
return Status;
}