]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf64Convert.c
BaseTools/GenFw: Enhance GenFw to support PRM GCC build
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
index 0bb3ead228c9066ec2af015e5b6f391c72c155bf..2aa9bfcc9460c0a68208808e036fc631ae14f90e 100644 (file)
@@ -56,6 +56,12 @@ WriteDebug64 (
   VOID\r
   );\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  );\r
+\r
 STATIC\r
 VOID\r
 SetImageSize64 (\r
@@ -106,7 +112,7 @@ STATIC UINT32 mCoffAlignment = 0x20;
 //\r
 // PE section alignment.\r
 //\r
-STATIC const UINT16 mCoffNbrSections = 4;\r
+STATIC UINT16 mCoffNbrSections = 4;\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
@@ -122,7 +128,7 @@ STATIC UINT32 mDataOffset;
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
 STATIC UINT32 mDebugOffset;\r
-\r
+STATIC UINT32 mExportOffset;\r
 //\r
 // Used for RISC-V relocations.\r
 //\r
@@ -132,6 +138,14 @@ STATIC Elf64_Half  mRiscVPass1SymSecIndex = 0;
 STATIC INT32       mRiscVPass1Offset;\r
 STATIC INT32       mRiscVPass1GotFixup;\r
 \r
+//\r
+// Used for Export section.\r
+//\r
+STATIC UINT32      mExportSize;\r
+STATIC UINT32      mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM];\r
+STATIC UINT32      mExportSymNum;\r
+STATIC CHAR8       mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH];\r
+\r
 //\r
 // Initialization Function\r
 //\r
@@ -171,6 +185,13 @@ InitializeElf64 (
     return FALSE;\r
   }\r
 \r
+  if (mExportFlag) {\r
+    if (mEhdr->e_machine != EM_X86_64) {\r
+      Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 arch.");\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
   //\r
   // Update section header pointers\r
   //\r
@@ -200,6 +221,11 @@ InitializeElf64 (
   ElfFunctions->SetImageSize = SetImageSize64;\r
   ElfFunctions->CleanUp = CleanUp64;\r
 \r
+  if (mExportFlag) {\r
+    mCoffNbrSections ++;\r
+    ElfFunctions->WriteExport = WriteExport64;\r
+  }\r
+\r
   return TRUE;\r
 }\r
 \r
@@ -263,6 +289,17 @@ IsHiiRsrcShdr (
   return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+IsSymbolShdr (\r
+  Elf_Shdr *Shdr\r
+  )\r
+{\r
+  Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx);\r
+\r
+  return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0);\r
+}\r
+\r
 STATIC\r
 BOOLEAN\r
 IsDataShdr (\r
@@ -335,6 +372,37 @@ GetSymName (
   return StrtabContents + Sym->st_name;\r
 }\r
 \r
+//\r
+// Get Prm Handler number and name\r
+//\r
+STATIC\r
+VOID\r
+FindPrmHandler (\r
+  UINT64 Offset\r
+  )\r
+{\r
+  PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport;\r
+  PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT       *PrmHandler;\r
+  UINT32   HandlerNum;\r
+\r
+  PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset);\r
+  PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1);\r
+\r
+  for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) {\r
+    strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName);\r
+    mExportSymNum ++;\r
+    PrmHandler += 1;\r
+\r
+    //\r
+    // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)\r
+    //\r
+    if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) {\r
+      Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum);\r
+      exit(EXIT_FAILURE);\r
+    }\r
+  }\r
+}\r
+\r
 //\r
 // Find the ELF section hosting the GOT from an ELF Rva\r
 //   of a single GOT entry.  Normally, GOT is placed in\r
@@ -717,6 +785,7 @@ ScanSections64 (
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
   BOOLEAN                         FoundSection;\r
+  UINT32                          Offset;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
@@ -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);\r
   }\r
 \r
+  //\r
+  //  The Symbol sections.\r
+  //\r
+  if (mExportFlag) {\r
+    UINT32      SymIndex;\r
+    Elf_Sym     *Sym;\r
+    UINT64      SymNum;\r
+    const UINT8 *SymName;\r
+\r
+    mExportOffset = mCoffOffset;\r
+    mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1;\r
+\r
+    for (i = 0; i < mEhdr->e_shnum; i++) {\r
+\r
+      //\r
+      // Determine if this is a symbol section.\r
+      //\r
+      Elf_Shdr *shdr = GetShdrByIndex(i);\r
+      if (!IsSymbolShdr(shdr)) {\r
+        continue;\r
+      }\r
+\r
+      UINT8    *Symtab = (UINT8*)mEhdr + shdr->sh_offset;\r
+      SymNum = (shdr->sh_size) / (shdr->sh_entsize);\r
+\r
+      //\r
+      // First Get PrmModuleExportDescriptor\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) {\r
+          //\r
+          // Find PrmHandler Number and Name\r
+          //\r
+          FindPrmHandler(Sym->st_value);\r
+\r
+          strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName);\r
+          mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+          mExportSymNum ++;\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Second Get PrmHandler\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        UINT32   ExpIndex;\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) {\r
+          if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) {\r
+            continue;\r
+          }\r
+          mExportRVA[ExpIndex] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+        }\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    mCoffOffset += mExportSize;\r
+    mCoffOffset = CoffAlign(mCoffOffset);\r
+  }\r
+\r
   //\r
   //  The HII resource sections.\r
   //\r
@@ -989,8 +1134,17 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  //\r
+  // If found symbol, add edata section between data and rsrc section\r
+  //\r
+  if(mExportFlag) {\r
+    Offset = mExportOffset;\r
+  } else {\r
+    Offset = mHiiRsrcOffset;\r
+  }\r
+\r
   if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
-    CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
+    CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
             | EFI_IMAGE_SCN_MEM_WRITE\r
             | EFI_IMAGE_SCN_MEM_READ);\r
@@ -999,6 +1153,20 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  if(mExportFlag) {\r
+    if ((mHiiRsrcOffset - mExportOffset) > 0) {\r
+      CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset,\r
+              EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
+              | EFI_IMAGE_SCN_MEM_READ);\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset;\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset;\r
+\r
+    } else {\r
+      // Don't make a section of size 0.\r
+      NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
+    }\r
+  }\r
+\r
   if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
     CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
@@ -1757,4 +1925,72 @@ CleanUp64 (
   }\r
 }\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  )\r
+{\r
+  EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
+  EFI_IMAGE_EXPORT_DIRECTORY          *ExportDir;\r
+  EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
+  UINT32                              FileNameOffset;\r
+  UINT32                              NameOffset;\r
+  UINT16                              Index;\r
+  UINT8                               *Tdata = NULL;\r
+\r
+  ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset);\r
+  ExportDir->Characteristics = 0;\r
+  ExportDir->TimeDateStamp = 0;\r
+  ExportDir->MajorVersion = 0;\r
+  ExportDir->MinorVersion =0;\r
+  ExportDir->Name = 0;\r
+  ExportDir->NumberOfFunctions = mExportSymNum;\r
+  ExportDir->NumberOfNames = mExportSymNum;\r
+  ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE;\r
+  ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY);\r
+  ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+  ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+\r
+  FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum;\r
+  NameOffset = FileNameOffset + strlen(mInImageName) + 1;\r
+\r
+  // Write Input image Name RVA\r
+  ExportDir->Name = FileNameOffset;\r
+\r
+  // Write Input image Name\r
+  strcpy((char *)(mCoffFile + FileNameOffset), mInImageName);\r
+\r
+  for (Index = 0; Index < mExportSymNum; Index++) {\r
+    //\r
+    // Write Export Address Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = mExportRVA[Index];\r
+\r
+    //\r
+    // Write Export Name Pointer Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = NameOffset;\r
+\r
+    //\r
+    // Write Export Ordinal table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE;\r
+    *(UINT16 *)Tdata = Index;\r
+\r
+    //\r
+    // Write Export Name Table\r
+    //\r
+    strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]);\r
+    NameOffset += strlen(mExportSymName[Index]) + 1;\r
+  }\r
+\r
+  NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
+  DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT];\r
+  DataDir->VirtualAddress = mExportOffset;\r
+  DataDir->Size = mExportSize;\r
+\r
+}\r
 \r