[edk2-devel] [PATCH v2] BaseTools/GenFw: Enhance GenFw to support PRM GCC build

Huang, Li-Xia posted 1 patch 2 years, 1 month ago
Failed in applying to current master (apply log)
BaseTools/Source/C/GenFw/Elf64Convert.c       | 242 +++++++++++++++++-
BaseTools/Source/C/GenFw/ElfConvert.c         |   8 +
BaseTools/Source/C/GenFw/ElfConvert.h         |  43 +++-
BaseTools/Source/C/GenFw/GenFw.c              |  20 +-
.../C/Include/IndustryStandard/PeImage.h      |   7 +
5 files changed, 315 insertions(+), 5 deletions(-)
[edk2-devel] [PATCH v2] BaseTools/GenFw: Enhance GenFw to support PRM GCC build
Posted by Huang, Li-Xia 2 years, 1 month ago
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>
---
 BaseTools/Source/C/GenFw/Elf64Convert.c       | 242 +++++++++++++++++-
 BaseTools/Source/C/GenFw/ElfConvert.c         |   8 +
 BaseTools/Source/C/GenFw/ElfConvert.h         |  43 +++-
 BaseTools/Source/C/GenFw/GenFw.c              |  20 +-
 .../C/Include/IndustryStandard/PeImage.h      |   7 +
 5 files changed, 315 insertions(+), 5 deletions(-)

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-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) ();
 
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
-- 
2.26.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#87530): https://edk2.groups.io/g/devel/message/87530
Mute This Topic: https://groups.io/mt/89765933/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v2] BaseTools/GenFw: Enhance GenFw to support PRM GCC build
Posted by Bob Feng 2 years, 1 month ago
This patch looks good to me.

Reviewed-by: Bob Feng <bob.c.feng@intel.com>

-----Original Message-----
From: Huang, Li-Xia <lisa.huang@intel.com> 
Sent: Monday, March 14, 2022 1:27 PM
To: devel@edk2.groups.io
Cc: Huang, Li-Xia <lisa.huang@intel.com>; Gao, Liming <gaoliming@byosoft.com.cn>; Feng, Bob C <bob.c.feng@intel.com>; Chen, Christine <yuwei.chen@intel.com>
Subject: [edk2-devel] [PATCH v2] 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>
---
 BaseTools/Source/C/GenFw/Elf64Convert.c       | 242 +++++++++++++++++-
 BaseTools/Source/C/GenFw/ElfConvert.c         |   8 +
 BaseTools/Source/C/GenFw/ElfConvert.h         |  43 +++-
 BaseTools/Source/C/GenFw/GenFw.c              |  20 +-
 .../C/Include/IndustryStandard/PeImage.h      |   7 +
 5 files changed, 315 insertions(+), 5 deletions(-)

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-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) (); 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-- 
2.26.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#87532): https://edk2.groups.io/g/devel/message/87532
Mute This Topic: https://groups.io/mt/89765933/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-