From: Huang, Li-Xia Date: Mon, 14 Mar 2022 05:27:21 +0000 (+0800) Subject: BaseTools/GenFw: Enhance GenFw to support PRM GCC build X-Git-Tag: edk2-stable202205~268 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=414cd2a4d536b444acee3fcdbe33bd0c8ef9819b 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 Cc: Bob Feng Cc: Yuwei Chen Signed-off-by: Lixia Huang Reviewed-by: Bob Feng --- diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c index 0bb3ead228..2aa9bfcc94 100644 --- a/BaseTools/Source/C/GenFw/Elf64Convert.c +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c @@ -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; + +} diff --git a/BaseTools/Source/C/GenFw/ElfConvert.c b/BaseTools/Source/C/GenFw/ElfConvert.c index 7db8721167..be98544056 100644 --- a/BaseTools/Source/C/GenFw/ElfConvert.c +++ b/BaseTools/Source/C/GenFw/ElfConvert.c @@ -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. // diff --git a/BaseTools/Source/C/GenFw/ElfConvert.h b/BaseTools/Source/C/GenFw/ElfConvert.h index 801e8de4a2..6ab4605227 100644 --- a/BaseTools/Source/C/GenFw/ElfConvert.h +++ b/BaseTools/Source/C/GenFw/ElfConvert.h @@ -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 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) (); diff --git a/BaseTools/Source/C/GenFw/GenFw.c b/BaseTools/Source/C/GenFw/GenFw.c index 8cab70ba4d..6f61f16788 100644 --- a/BaseTools/Source/C/GenFw/GenFw.c +++ b/BaseTools/Source/C/GenFw/GenFw.c @@ -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; diff --git a/BaseTools/Source/C/Include/IndustryStandard/PeImage.h b/BaseTools/Source/C/Include/IndustryStandard/PeImage.h index f17b8ee19b..21c968e650 100644 --- a/BaseTools/Source/C/Include/IndustryStandard/PeImage.h +++ b/BaseTools/Source/C/Include/IndustryStandard/PeImage.h @@ -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