mirror of https://github.com/acidanthera/audk.git
BaseTools/GenFw: Enhance GenFw to support PRM GCC build
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3802 Since PRM module needs to support export table in PE-COFF, we'll enhance GenFw tool to support this. Add one export flag in GenFw tool. If export flag is set: Step1: Scan ELF symbol table based on PRM module descriptor to get descriptor offset address; Step2: Find PRM handlers number and name in COFF file based on the address from step1; Step3: Write PRM info such as handler name and export RVA into COFF export table. PRM option currently only supports DXE RUNTIME driver and X64 arch. Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Bob Feng <bob.c.feng@intel.com> Cc: Yuwei Chen <yuwei.chen@intel.com> Signed-off-by: Lixia Huang <lisa.huang@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
This commit is contained in:
parent
c8ea48bdf9
commit
414cd2a4d5
|
@ -56,6 +56,12 @@ WriteDebug64 (
|
|||
VOID
|
||||
);
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
WriteExport64 (
|
||||
VOID
|
||||
);
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
SetImageSize64 (
|
||||
|
@ -106,7 +112,7 @@ STATIC UINT32 mCoffAlignment = 0x20;
|
|||
//
|
||||
// PE section alignment.
|
||||
//
|
||||
STATIC const UINT16 mCoffNbrSections = 4;
|
||||
STATIC UINT16 mCoffNbrSections = 4;
|
||||
|
||||
//
|
||||
// ELF sections to offset in Coff file.
|
||||
|
@ -122,7 +128,7 @@ STATIC UINT32 mDataOffset;
|
|||
STATIC UINT32 mHiiRsrcOffset;
|
||||
STATIC UINT32 mRelocOffset;
|
||||
STATIC UINT32 mDebugOffset;
|
||||
|
||||
STATIC UINT32 mExportOffset;
|
||||
//
|
||||
// Used for RISC-V relocations.
|
||||
//
|
||||
|
@ -132,6 +138,14 @@ STATIC Elf64_Half mRiscVPass1SymSecIndex = 0;
|
|||
STATIC INT32 mRiscVPass1Offset;
|
||||
STATIC INT32 mRiscVPass1GotFixup;
|
||||
|
||||
//
|
||||
// Used for Export section.
|
||||
//
|
||||
STATIC UINT32 mExportSize;
|
||||
STATIC UINT32 mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM];
|
||||
STATIC UINT32 mExportSymNum;
|
||||
STATIC CHAR8 mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH];
|
||||
|
||||
//
|
||||
// Initialization Function
|
||||
//
|
||||
|
@ -171,6 +185,13 @@ InitializeElf64 (
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (mExportFlag) {
|
||||
if (mEhdr->e_machine != EM_X86_64) {
|
||||
Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 arch.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update section header pointers
|
||||
//
|
||||
|
@ -200,6 +221,11 @@ InitializeElf64 (
|
|||
ElfFunctions->SetImageSize = SetImageSize64;
|
||||
ElfFunctions->CleanUp = CleanUp64;
|
||||
|
||||
if (mExportFlag) {
|
||||
mCoffNbrSections ++;
|
||||
ElfFunctions->WriteExport = WriteExport64;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -263,6 +289,17 @@ IsHiiRsrcShdr (
|
|||
return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
IsSymbolShdr (
|
||||
Elf_Shdr *Shdr
|
||||
)
|
||||
{
|
||||
Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx);
|
||||
|
||||
return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0);
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
IsDataShdr (
|
||||
|
@ -335,6 +372,37 @@ GetSymName (
|
|||
return StrtabContents + Sym->st_name;
|
||||
}
|
||||
|
||||
//
|
||||
// Get Prm Handler number and name
|
||||
//
|
||||
STATIC
|
||||
VOID
|
||||
FindPrmHandler (
|
||||
UINT64 Offset
|
||||
)
|
||||
{
|
||||
PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport;
|
||||
PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *PrmHandler;
|
||||
UINT32 HandlerNum;
|
||||
|
||||
PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset);
|
||||
PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1);
|
||||
|
||||
for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) {
|
||||
strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName);
|
||||
mExportSymNum ++;
|
||||
PrmHandler += 1;
|
||||
|
||||
//
|
||||
// Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)
|
||||
//
|
||||
if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) {
|
||||
Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Find the ELF section hosting the GOT from an ELF Rva
|
||||
// of a single GOT entry. Normally, GOT is placed in
|
||||
|
@ -717,6 +785,7 @@ ScanSections64 (
|
|||
UINT32 CoffEntry;
|
||||
UINT32 SectionCount;
|
||||
BOOLEAN FoundSection;
|
||||
UINT32 Offset;
|
||||
|
||||
CoffEntry = 0;
|
||||
mCoffOffset = 0;
|
||||
|
@ -880,6 +949,82 @@ ScanSections64 (
|
|||
Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);
|
||||
}
|
||||
|
||||
//
|
||||
// The Symbol sections.
|
||||
//
|
||||
if (mExportFlag) {
|
||||
UINT32 SymIndex;
|
||||
Elf_Sym *Sym;
|
||||
UINT64 SymNum;
|
||||
const UINT8 *SymName;
|
||||
|
||||
mExportOffset = mCoffOffset;
|
||||
mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1;
|
||||
|
||||
for (i = 0; i < mEhdr->e_shnum; i++) {
|
||||
|
||||
//
|
||||
// Determine if this is a symbol section.
|
||||
//
|
||||
Elf_Shdr *shdr = GetShdrByIndex(i);
|
||||
if (!IsSymbolShdr(shdr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UINT8 *Symtab = (UINT8*)mEhdr + shdr->sh_offset;
|
||||
SymNum = (shdr->sh_size) / (shdr->sh_entsize);
|
||||
|
||||
//
|
||||
// First Get PrmModuleExportDescriptor
|
||||
//
|
||||
for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {
|
||||
Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);
|
||||
SymName = GetSymName(Sym);
|
||||
if (SymName == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) {
|
||||
//
|
||||
// Find PrmHandler Number and Name
|
||||
//
|
||||
FindPrmHandler(Sym->st_value);
|
||||
|
||||
strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName);
|
||||
mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value);
|
||||
mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;
|
||||
mExportSymNum ++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Second Get PrmHandler
|
||||
//
|
||||
for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {
|
||||
UINT32 ExpIndex;
|
||||
Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);
|
||||
SymName = GetSymName(Sym);
|
||||
if (SymName == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) {
|
||||
if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) {
|
||||
continue;
|
||||
}
|
||||
mExportRVA[ExpIndex] = (UINT32)(Sym->st_value);
|
||||
mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mCoffOffset += mExportSize;
|
||||
mCoffOffset = CoffAlign(mCoffOffset);
|
||||
}
|
||||
|
||||
//
|
||||
// The HII resource sections.
|
||||
//
|
||||
|
@ -989,8 +1134,17 @@ ScanSections64 (
|
|||
NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
|
||||
}
|
||||
|
||||
//
|
||||
// If found symbol, add edata section between data and rsrc section
|
||||
//
|
||||
if(mExportFlag) {
|
||||
Offset = mExportOffset;
|
||||
} else {
|
||||
Offset = mHiiRsrcOffset;
|
||||
}
|
||||
|
||||
if ((mHiiRsrcOffset - mDataOffset) > 0) {
|
||||
CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,
|
||||
CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset,
|
||||
EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
|
||||
| EFI_IMAGE_SCN_MEM_WRITE
|
||||
| EFI_IMAGE_SCN_MEM_READ);
|
||||
|
@ -999,6 +1153,20 @@ ScanSections64 (
|
|||
NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
|
||||
}
|
||||
|
||||
if(mExportFlag) {
|
||||
if ((mHiiRsrcOffset - mExportOffset) > 0) {
|
||||
CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset,
|
||||
EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
|
||||
| EFI_IMAGE_SCN_MEM_READ);
|
||||
NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset;
|
||||
NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset;
|
||||
|
||||
} else {
|
||||
// Don't make a section of size 0.
|
||||
NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mRelocOffset - mHiiRsrcOffset) > 0) {
|
||||
CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,
|
||||
EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
|
||||
|
@ -1757,4 +1925,72 @@ CleanUp64 (
|
|||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
WriteExport64 (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
|
||||
EFI_IMAGE_EXPORT_DIRECTORY *ExportDir;
|
||||
EFI_IMAGE_DATA_DIRECTORY *DataDir;
|
||||
UINT32 FileNameOffset;
|
||||
UINT32 NameOffset;
|
||||
UINT16 Index;
|
||||
UINT8 *Tdata = NULL;
|
||||
|
||||
ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset);
|
||||
ExportDir->Characteristics = 0;
|
||||
ExportDir->TimeDateStamp = 0;
|
||||
ExportDir->MajorVersion = 0;
|
||||
ExportDir->MinorVersion =0;
|
||||
ExportDir->Name = 0;
|
||||
ExportDir->NumberOfFunctions = mExportSymNum;
|
||||
ExportDir->NumberOfNames = mExportSymNum;
|
||||
ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE;
|
||||
ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY);
|
||||
ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;
|
||||
ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;
|
||||
|
||||
FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum;
|
||||
NameOffset = FileNameOffset + strlen(mInImageName) + 1;
|
||||
|
||||
// Write Input image Name RVA
|
||||
ExportDir->Name = FileNameOffset;
|
||||
|
||||
// Write Input image Name
|
||||
strcpy((char *)(mCoffFile + FileNameOffset), mInImageName);
|
||||
|
||||
for (Index = 0; Index < mExportSymNum; Index++) {
|
||||
//
|
||||
// Write Export Address Table
|
||||
//
|
||||
Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;
|
||||
*(UINT32 *)Tdata = mExportRVA[Index];
|
||||
|
||||
//
|
||||
// Write Export Name Pointer Table
|
||||
//
|
||||
Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;
|
||||
*(UINT32 *)Tdata = NameOffset;
|
||||
|
||||
//
|
||||
// Write Export Ordinal table
|
||||
//
|
||||
Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE;
|
||||
*(UINT16 *)Tdata = Index;
|
||||
|
||||
//
|
||||
// Write Export Name Table
|
||||
//
|
||||
strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]);
|
||||
NameOffset += strlen(mExportSymName[Index]) + 1;
|
||||
}
|
||||
|
||||
NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
|
||||
DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
DataDir->VirtualAddress = mExportOffset;
|
||||
DataDir->Size = mExportSize;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -223,6 +223,14 @@ ConvertElf (
|
|||
VerboseMsg ("Write debug info.");
|
||||
ElfFunctions.WriteDebug ();
|
||||
|
||||
//
|
||||
// For PRM Driver to Write export info.
|
||||
//
|
||||
if (mExportFlag) {
|
||||
VerboseMsg ("Write export info.");
|
||||
ElfFunctions.WriteExport ();
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure image size is correct before returning the new image.
|
||||
//
|
||||
|
|
|
@ -24,6 +24,7 @@ extern UINT8 *mCoffFile;
|
|||
extern UINT32 mTableOffset;
|
||||
extern UINT32 mOutImageType;
|
||||
extern UINT32 mFileBufferSize;
|
||||
extern BOOLEAN mExportFlag;
|
||||
|
||||
//
|
||||
// Common EFI specific data.
|
||||
|
@ -31,6 +32,44 @@ extern UINT32 mFileBufferSize;
|
|||
#define ELF_HII_SECTION_NAME ".hii"
|
||||
#define ELF_STRTAB_SECTION_NAME ".strtab"
|
||||
#define MAX_COFF_ALIGNMENT 0x10000
|
||||
#define ELF_SYMBOL_SECTION_NAME ".symtab"
|
||||
|
||||
//
|
||||
// Platform Runtime Mechanism (PRM) specific data.
|
||||
//
|
||||
#define PRM_MODULE_EXPORT_SYMBOL_NUM 256
|
||||
|
||||
// <to-do> to include PRM header directly once PrmPkg is in main repo
|
||||
#define PRM_HANDLER_NAME_MAXIMUM_LENGTH 128
|
||||
|
||||
#define PRM_MODULE_EXPORT_DESCRIPTOR_NAME "PrmModuleExportDescriptor"
|
||||
#define PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE SIGNATURE_64 ('P', 'R', 'M', '_', 'M', 'E', 'D', 'T')
|
||||
#define PRM_MODULE_EXPORT_REVISION 0x0
|
||||
|
||||
//
|
||||
// Platform Runtime Mechanism (PRM) Export Descriptor Structures
|
||||
//
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID PrmHandlerGuid;
|
||||
CHAR8 PrmHandlerName[PRM_HANDLER_NAME_MAXIMUM_LENGTH];
|
||||
} PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT;
|
||||
|
||||
typedef struct {
|
||||
UINT64 Signature;
|
||||
UINT16 Revision;
|
||||
UINT16 NumberPrmHandlers;
|
||||
EFI_GUID PlatformGuid;
|
||||
EFI_GUID ModuleGuid;
|
||||
} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER;
|
||||
|
||||
typedef struct {
|
||||
PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER Header;
|
||||
PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT PrmHandlerExportDescriptors[1];
|
||||
} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// Filter Types
|
||||
|
@ -38,7 +77,8 @@ extern UINT32 mFileBufferSize;
|
|||
typedef enum {
|
||||
SECTION_TEXT,
|
||||
SECTION_HII,
|
||||
SECTION_DATA
|
||||
SECTION_DATA,
|
||||
SECTION_SYMBOL
|
||||
|
||||
} SECTION_FILTER_TYPES;
|
||||
|
||||
|
@ -50,6 +90,7 @@ typedef struct {
|
|||
BOOLEAN (*WriteSections) (SECTION_FILTER_TYPES FilterType);
|
||||
VOID (*WriteRelocations) ();
|
||||
VOID (*WriteDebug) ();
|
||||
VOID (*WriteExport) ();
|
||||
VOID (*SetImageSize) ();
|
||||
VOID (*CleanUp) ();
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ UINT32 mImageTimeStamp = 0;
|
|||
UINT32 mImageSize = 0;
|
||||
UINT32 mOutImageType = FW_DUMMY_IMAGE;
|
||||
BOOLEAN mIsConvertXip = FALSE;
|
||||
|
||||
BOOLEAN mExportFlag = FALSE;
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
|
@ -279,6 +279,10 @@ Returns:
|
|||
except for -o or -r option. It is a action option.\n\
|
||||
If it is combined with other action options, the later\n\
|
||||
input action option will override the previous one.\n");
|
||||
fprintf (stdout, " --prm Scan symbol section from ELF image and \n\
|
||||
write export table into PE-COFF.\n\
|
||||
This option can be used together with -e.\n\
|
||||
It doesn't work for other options.\n");
|
||||
fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
|
||||
fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
|
||||
fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
|
||||
|
@ -1436,6 +1440,20 @@ Returns:
|
|||
continue;
|
||||
}
|
||||
|
||||
if (stricmp (argv[0], "--prm") == 0) {
|
||||
if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") != 0 ){
|
||||
Error (NULL, 0, 1001, "Invalid", "--prm option only supports DXE RUNTIME driver.");
|
||||
goto Finish;
|
||||
}
|
||||
|
||||
if (!mExportFlag) {
|
||||
mExportFlag = TRUE;
|
||||
}
|
||||
argc --;
|
||||
argv ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argv[0][0] == '-') {
|
||||
Error (NULL, 0, 1000, "Unknown option", argv[0]);
|
||||
goto Finish;
|
||||
|
|
|
@ -571,6 +571,13 @@ typedef struct {
|
|||
UINT32 AddressOfNameOrdinals;
|
||||
} EFI_IMAGE_EXPORT_DIRECTORY;
|
||||
|
||||
//
|
||||
// Based export types.
|
||||
//
|
||||
#define EFI_IMAGE_EXPORT_ORDINAL_BASE 1
|
||||
#define EFI_IMAGE_EXPORT_ADDR_SIZE 4
|
||||
#define EFI_IMAGE_EXPORT_ORDINAL_SIZE 2
|
||||
|
||||
///
|
||||
/// DLL support.
|
||||
/// Import Format
|
||||
|
|
Loading…
Reference in New Issue