Skip to content

Conversation

@ur4t
Copy link
Contributor

@ur4t ur4t commented Oct 12, 2025

Solve #54516. llvm-ifs now preserves symbol versions when producing stubs for libraries which use ELF symbol versioning (e.g. glibc and bionic).

@llvmbot
Copy link
Member

llvmbot commented Oct 12, 2025

@llvm/pr-subscribers-llvm-binary-utilities

Author: None (ur4t)

Changes

Solve #54516. llvm-ifs now preserves symbol versions when producing stubs for libraries which use ELF symbol versioning (e.g. glibc and bionic).


Patch is 35.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/163030.diff

6 Files Affected:

  • (modified) llvm/docs/CommandGuide/llvm-ifs.rst (+25-1)
  • (modified) llvm/include/llvm/InterfaceStub/IFSStub.h (+35-1)
  • (modified) llvm/lib/InterfaceStub/ELFObjHandler.cpp (+424-13)
  • (modified) llvm/lib/InterfaceStub/IFSHandler.cpp (+59)
  • (modified) llvm/lib/InterfaceStub/IFSStub.cpp (+10)
  • (modified) llvm/tools/llvm-ifs/llvm-ifs.cpp (+17-2)
diff --git a/llvm/docs/CommandGuide/llvm-ifs.rst b/llvm/docs/CommandGuide/llvm-ifs.rst
index e3582b365b61d..d310e62b14eb6 100644
--- a/llvm/docs/CommandGuide/llvm-ifs.rst
+++ b/llvm/docs/CommandGuide/llvm-ifs.rst
@@ -40,6 +40,12 @@ by the :program:`llvm-ifs`:
     - { Name: sym2, Type: Func, Weak: false }
     - { Name: sym3, Type: TLS }
     - { Name: sym4, Type: Unknown, Warning: foo }
+    - { Name: sym5, Version: VER_1, Type: Func }
+  VersionDefinitions: /* Optional */
+    - { Name: libtest.so }
+    - { Name: VER_1 }
+  VersionRequirements: /* Optional */
+    - { File: libc.so.6, Names: [ GLIBC_2.14, GLIBC_2.4, GLIBC_2.2.5, GLIBC_2.3.4 ] }
   ...
 
 * ``IFSVersion``: Version of the IFS file for reader compatibility.
@@ -67,6 +73,10 @@ by the :program:`llvm-ifs`:
 
   + ``Warning`` (optional): Warning text to output when this symbol is linked against.
 
+* ``VersionDefinitions`` (optional): A collection of symbol versions defined in this shared object file.
+
+* ``VersionRequirements`` (optional): A collection of symbol versions defined in external shared objects that this library depends on.
+
 This YAML based text format contains everything that is needed to generate a
 linkable ELF shared object as well as an Apple TAPI format file. The ordering
 of symbols is sorted, so these files can be easily compared using diff tools.
@@ -81,12 +91,20 @@ A minimum ELF file that can be used by linker should have following sections pro
 
 * ELF header.
 
+* Program headers. (optional)
+
 * Section headers.
 
 * Dynamic symbol table (``.dynsym`` section).
 
 * Dynamic string table (``.dynstr`` section).
 
+* Version symbol table (``.gnu.version`` section). (optional)
+
+* Version definition table (``.gnu.version_d`` section). (optional)
+
+* Version requirement table (``.gnu.version_r`` section). (optional)
+
 * Dynamic table (``.dynamic`` section).
 
   + ``DT_SYMTAB`` entry.
@@ -99,6 +117,12 @@ A minimum ELF file that can be used by linker should have following sections pro
 
   + ``DT_SONAME`` entry. (optional)
 
+  + ``DT_VERSYM`` entry. (optional)
+
+  + ``DT_VERDEF`` entry. (optional)
+
+  + ``DT_VERNEED`` entry. (optional)
+
 * Section header string table (``.shstrtab`` section)
 
 This ELF file may have compatibility issues with ELF analysis tools that rely on the program headers.
@@ -163,7 +187,7 @@ OPTIONS
  triple in the output IFS file. If the value matches the target information
  from the object file, this value will be used in the 'Target:' filed in the
  generated IFS. If it conflicts with the input object file, an error will be
- reported and the program will stop. 
+ reported and the program will stop.
 
 .. option:: --hint-ifs-target
 
diff --git a/llvm/include/llvm/InterfaceStub/IFSStub.h b/llvm/include/llvm/InterfaceStub/IFSStub.h
index ddde889d46890..881a9d02c17aa 100644
--- a/llvm/include/llvm/InterfaceStub/IFSStub.h
+++ b/llvm/include/llvm/InterfaceStub/IFSStub.h
@@ -52,8 +52,10 @@ enum class IFSBitWidthType {
 
 struct IFSSymbol {
   IFSSymbol() = default;
-  explicit IFSSymbol(std::string SymbolName) : Name(std::move(SymbolName)) {}
+  explicit IFSSymbol(std::string SymbolName, std::string SymVer)
+      : Name(std::move(SymbolName)), Version(std::move(SymVer)) {}
   std::string Name;
+  std::string Version;
   std::optional<uint64_t> Size;
   IFSSymbolType Type = IFSSymbolType::NoType;
   bool Undefined = false;
@@ -62,6 +64,36 @@ struct IFSSymbol {
   bool operator<(const IFSSymbol &RHS) const { return Name < RHS.Name; }
 };
 
+struct IFSVerDef {
+  std::string Name;
+  std::vector<std::string> Parents;
+};
+
+inline bool operator==(const IFSVerDef &Lhs, const IFSVerDef &Rhs) {
+  if (Lhs.Name != Rhs.Name || Lhs.Parents != Rhs.Parents)
+    return false;
+  return true;
+}
+
+inline bool operator!=(const IFSVerDef &Lhs, const IFSVerDef &Rhs) {
+  return !(Lhs == Rhs);
+}
+
+struct IFSVerNeed {
+  std::string File;
+  std::vector<std::string> Names;
+};
+
+inline bool operator==(const IFSVerNeed &Lhs, const IFSVerNeed &Rhs) {
+  if (Lhs.File != Rhs.File || Lhs.Names != Rhs.Names)
+    return false;
+  return true;
+}
+
+inline bool operator!=(const IFSVerNeed &Lhs, const IFSVerNeed &Rhs) {
+  return !(Lhs == Rhs);
+}
+
 struct IFSTarget {
   std::optional<std::string> Triple;
   std::optional<std::string> ObjectFormat;
@@ -94,6 +126,8 @@ struct IFSStub {
   IFSTarget Target;
   std::vector<std::string> NeededLibs;
   std::vector<IFSSymbol> Symbols;
+  std::vector<IFSVerDef> VersionDefinitions;
+  std::vector<IFSVerNeed> VersionRequirements;
 
   IFSStub() = default;
   LLVM_ABI IFSStub(const IFSStub &Stub);
diff --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
index 9c81a8832c0f2..7f57a8a5f4f82 100644
--- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp
+++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp
@@ -39,6 +39,12 @@ struct DynamicEntries {
   // Hash tables:
   std::optional<uint64_t> ElfHash;
   std::optional<uint64_t> GnuHash;
+  // Version tables:
+  std::optional<uint64_t> VerSym;
+  std::optional<uint64_t> VerDef;
+  std::optional<uint64_t> VerDefNum;
+  std::optional<uint64_t> VerNeed;
+  std::optional<uint64_t> VerNeedNum;
 };
 
 /// This initializes an ELF file header with information specific to a binary
@@ -124,6 +130,148 @@ template <class ELFT> class ELFSymbolTableBuilder {
   llvm::SmallVector<Elf_Sym, 8> Symbols;
 };
 
+template <class ELFT> class ELFVersionSymbolBuilder {
+public:
+  using Elf_Versym = typename ELFT::Versym;
+
+  ELFVersionSymbolBuilder() { Versions.push_back({}); }
+
+  void add(uint16_t Index) {
+    Elf_Versym VerSym;
+    VerSym.vs_index = Index;
+    Versions.push_back(VerSym);
+  }
+
+  size_t getSize() const { return Versions.size() * sizeof(Elf_Versym); }
+
+  void write(uint8_t *Buf) const {
+    memcpy(Buf, Versions.data(), Versions.size() * sizeof(Elf_Versym));
+  }
+
+private:
+  llvm::SmallVector<Elf_Versym, 8> Versions;
+};
+
+template <class ELFT> class ELFVersionDefinitionBuilder {
+public:
+  using Elf_Verdef = typename ELFT::Verdef;
+  using Elf_Verdaux = typename ELFT::Verdaux;
+
+  ELFVersionDefinitionBuilder() { VerDAux.push_back({}); }
+
+  void addDef(uint16_t Index, uint16_t Count, uint32_t Hash) {
+    Elf_Verdef VerDef;
+    VerDef.vd_version = VER_DEF_CURRENT;
+    VerDef.vd_flags = Index == 1 ? VER_FLG_BASE : 0;
+    VerDef.vd_ndx = Index;
+    VerDef.vd_cnt = Count;
+    VerDef.vd_hash = Hash;
+    VerDef.vd_aux = sizeof(Elf_Verdef);
+    VerDef.vd_next = sizeof(Elf_Verdef) + Count * sizeof(Elf_Verdaux);
+    this->VerDef.push_back(VerDef);
+    this->VerDAux.push_back({});
+  }
+
+  void addAux(uint16_t Vdndx, uint32_t Name) {
+    Elf_Verdaux VerDAux;
+    VerDAux.vda_name = Name;
+    VerDAux.vda_next = sizeof(Elf_Verdaux);
+    this->VerDAux[Vdndx].push_back(VerDAux);
+  }
+
+  void finalize() {
+    if (!VerDef.empty())
+      VerDef.back().vd_next = 0;
+    for (llvm::SmallVector<Elf_Verdaux, 8> &VerDAux : VerDAux)
+      if (!VerDAux.empty())
+        VerDAux.back().vda_next = 0;
+  }
+
+  size_t getSize() const {
+    size_t Count = 0;
+    for (const llvm::SmallVector<Elf_Verdaux, 8> &I : VerDAux)
+      Count += I.size();
+    return Count * sizeof(Elf_Verdaux) + VerDef.size() * sizeof(Elf_Verdef);
+  }
+
+  void write(uint8_t *Buf) const {
+    uint8_t *Ptr = Buf;
+    size_t Count = 0;
+    for (const Elf_Verdef &VerDef : VerDef) {
+      Count = sizeof(Elf_Verdef);
+      memcpy(Ptr, &VerDef, Count);
+      Ptr += Count;
+      Count = VerDef.vd_cnt * sizeof(Elf_Verdaux);
+      memcpy(Ptr, VerDAux[VerDef.vd_ndx].data(), Count);
+      Ptr += Count;
+    }
+  }
+
+private:
+  llvm::SmallVector<Elf_Verdef, 8> VerDef;
+  std::vector<llvm::SmallVector<Elf_Verdaux, 8>> VerDAux;
+};
+
+template <class ELFT> class ELFVersionRequirementBuilder {
+public:
+  using Elf_Verneed = typename ELFT::Verneed;
+  using Elf_Vernaux = typename ELFT::Vernaux;
+
+  void addFile(uint16_t Count, uint32_t File) {
+    Elf_Verneed VerNeed;
+    VerNeed.vn_version = VER_NEED_CURRENT;
+    VerNeed.vn_cnt = Count;
+    VerNeed.vn_file = File;
+    VerNeed.vn_aux = sizeof(Elf_Verneed);
+    VerNeed.vn_next = sizeof(Elf_Verneed) + Count * sizeof(Elf_Vernaux);
+    this->VerNeed.push_back(VerNeed);
+    this->VerNAux.push_back({});
+  }
+
+  void addAux(uint16_t Vnndx, uint32_t Hash, uint16_t Vdndx, uint32_t Name) {
+    Elf_Vernaux VerNAux;
+    VerNAux.vna_hash = Hash;
+    VerNAux.vna_flags = 0;
+    VerNAux.vna_other = Vdndx;
+    VerNAux.vna_name = Name;
+    VerNAux.vna_next = sizeof(Elf_Vernaux);
+    this->VerNAux[Vnndx].push_back(VerNAux);
+  }
+
+  void finalize() {
+    if (!VerNeed.empty())
+      VerNeed.back().vn_next = 0;
+    for (llvm::SmallVector<Elf_Vernaux, 8> &VerNAux : VerNAux)
+      if (!VerNAux.empty())
+        VerNAux.back().vna_next = 0;
+  }
+
+  size_t getSize() const {
+    size_t Count = 0;
+    for (const llvm::SmallVector<Elf_Vernaux, 8> &I : VerNAux)
+      Count += I.size();
+    return Count * sizeof(Elf_Vernaux) + VerNeed.size() * sizeof(Elf_Verneed);
+  }
+
+  void write(uint8_t *Buf) const {
+    uint8_t *Ptr = Buf;
+    size_t Count = 0;
+    size_t Vnndx = 0;
+    for (const Elf_Verneed &VerNeed : VerNeed) {
+      Count = sizeof(Elf_Verneed);
+      memcpy(Ptr, &VerNeed, Count);
+      Ptr += Count;
+      Count = VerNeed.vn_cnt * sizeof(Elf_Vernaux);
+      memcpy(Ptr, VerNAux[Vnndx].data(), Count);
+      Ptr += Count;
+    }
+  }
+
+private:
+  llvm::SmallVector<Elf_Verneed, 8> VerNeed;
+  std::vector<llvm::SmallVector<Elf_Vernaux, 8>> VerNAux;
+};
+
 template <class ELFT> class ELFDynamicTableBuilder {
 public:
   using Elf_Dyn = typename ELFT::Dyn;
@@ -188,17 +336,43 @@ template <class ELFT> class ELFStubBuilder {
     DynTab.Align = sizeof(Elf_Addr);
     ShStrTab.Name = ".shstrtab";
     ShStrTab.Align = 1;
+    VerSym.Name = ".gnu.version";
+    VerSym.Align = 2;
+    VerDef.Name = ".gnu.version_d";
+    VerDef.Align = sizeof(Elf_Addr);
+    VerNeed.Name = ".gnu.version_r";
+    VerNeed.Align = sizeof(Elf_Addr);
 
     // Populate string tables.
     for (const IFSSymbol &Sym : Stub.Symbols)
       DynStr.Content.add(Sym.Name);
+    for (const IFSVerDef &VerDef : Stub.VersionDefinitions)
+      DynStr.Content.add(VerDef.Name);
+    for (const IFSVerNeed &VerNeed : Stub.VersionRequirements)
+      for (const std::string &VerNeedName : VerNeed.Names)
+        DynStr.Content.add(VerNeedName);
     for (const std::string &Lib : Stub.NeededLibs)
       DynStr.Content.add(Lib);
     if (Stub.SoName)
       DynStr.Content.add(*Stub.SoName);
 
-    std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab,
-                                                   &ShStrTab};
+    for (const IFSSymbol &Sym : Stub.Symbols)
+      if (!Sym.Version.empty())
+        WriteVerSym = true;
+    WriteVerDef = !Stub.VersionDefinitions.empty();
+    WriteVerNeed = !Stub.VersionRequirements.empty();
+
+    std::vector<OutputSection<ELFT> *> Sections;
+    Sections.push_back(&DynSym);
+    Sections.push_back(&DynStr);
+    if (WriteVerSym)
+      Sections.push_back(&VerSym);
+    if (WriteVerNeed)
+      Sections.push_back(&VerDef);
+    if (WriteVerNeed)
+      Sections.push_back(&VerNeed);
+    Sections.push_back(&DynTab);
+    Sections.push_back(&ShStrTab);
     const OutputSection<ELFT> *LastSection = Sections.back();
     // Now set the Index and put sections names into ".shstrtab".
     uint64_t Index = 1;
@@ -224,18 +398,65 @@ template <class ELFT> class ELFStubBuilder {
     }
     DynSym.Size = DynSym.Content.getSize();
 
+    std::map<std::string, uint16_t> VerDefMap;
+    size_t Vdndx = 0;
+    size_t Vnndx = 0;
+
+    // Populate symbol version definition table.
+    for (const IFSVerDef &IFSVerDef : Stub.VersionDefinitions) {
+      Vdndx++;
+      VerDef.Content.addDef(Vdndx, IFSVerDef.Parents.size() + 1,
+                            hashSysV(IFSVerDef.Name));
+      VerDef.Content.addAux(Vdndx, DynStr.Content.getOffset(IFSVerDef.Name));
+      for (const std::string &Parent : IFSVerDef.Parents) {
+        VerDef.Content.addAux(Vdndx, DynStr.Content.getOffset(Parent));
+      }
+      VerDefMap.insert({IFSVerDef.Name, Vdndx});
+    }
+    VerDef.Content.finalize();
+    VerDef.Size = VerDef.Content.getSize();
+
+    // Populate symbol version requirement table.
+    for (const IFSVerNeed &IFSVerNeed : Stub.VersionRequirements) {
+      VerNeed.Content.addFile(IFSVerNeed.Names.size(),
+                              DynStr.Content.getOffset(IFSVerNeed.File));
+      for (const std::string &Name : IFSVerNeed.Names) {
+        Vdndx++;
+        VerNeed.Content.addAux(Vnndx, hashSysV(Name), Vdndx,
+                               DynStr.Content.getOffset(Name));
+        VerDefMap.insert({Name, Vdndx});
+      }
+      Vnndx++;
+    }
+    VerNeed.Content.finalize();
+    VerNeed.Size = VerNeed.Content.getSize();
+
+    // Populate dynamic symbol version table.
+    for (const IFSSymbol &Sym : Stub.Symbols)
+      VerSym.Content.add(Sym.Version.empty() ? 1 : VerDefMap[Sym.Version]);
+    VerSym.Size = VerSym.Content.getSize();
+
     // Poplulate dynamic table.
     size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0);
     size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0);
+    size_t VerSymIndex;
+    size_t VerDefIndex;
+    size_t VerNeedIndex;
     DynTab.Content.addValue(DT_STRSZ, DynSym.Size);
     for (const std::string &Lib : Stub.NeededLibs)
       DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib));
     if (Stub.SoName)
       DynTab.Content.addValue(DT_SONAME,
                               DynStr.Content.getOffset(*Stub.SoName));
+    if (WriteVerSym)
+      VerSymIndex = DynTab.Content.addAddr(DT_VERSYM, 0);
+    if (WriteVerDef)
+      VerDefIndex = DynTab.Content.addAddr(DT_VERDEF, 0);
+    if (WriteVerNeed)
+      VerNeedIndex = DynTab.Content.addAddr(DT_VERNEED, 0);
     DynTab.Size = DynTab.Content.getSize();
     // Calculate sections' addresses and offsets.
-    uint64_t CurrentOffset = sizeof(Elf_Ehdr);
+    uint64_t CurrentOffset = sizeof(Elf_Ehdr) + ElfPhnum * sizeof(Elf_Phdr);
     for (OutputSection<ELFT> *Sec : Sections) {
       Sec->Offset = alignTo(CurrentOffset, Sec->Align);
       Sec->Addr = Sec->Offset;
@@ -244,18 +465,50 @@ template <class ELFT> class ELFStubBuilder {
     // Fill Addr back to dynamic table.
     DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr);
     DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr);
+    if (WriteVerSym)
+      DynTab.Content.modifyAddr(VerSymIndex, VerSym.Addr);
+    if (WriteVerDef)
+      DynTab.Content.modifyAddr(VerDefIndex, VerDef.Addr);
+    if (WriteVerNeed)
+      DynTab.Content.modifyAddr(VerNeedIndex, VerNeed.Addr);
     // Write section headers of string tables.
     fillSymTabShdr(DynSym, SHT_DYNSYM);
     fillStrTabShdr(DynStr, SHF_ALLOC);
     fillDynTabShdr(DynTab);
     fillStrTabShdr(ShStrTab);
+    if (WriteVerSym)
+      fillVerSymShdr(VerSym);
+    if (WriteVerDef)
+      fillVerDefShdr(VerDef, Stub.VersionDefinitions.size());
+    if (WriteVerNeed)
+      fillVerNeedShdr(VerNeed, Stub.VersionRequirements.size());
 
     // Finish initializing the ELF header.
     initELFHeader<ELFT>(ElfHeader, static_cast<uint16_t>(*Stub.Target.Arch));
     ElfHeader.e_shstrndx = ShStrTab.Index;
     ElfHeader.e_shnum = LastSection->Index + 1;
+    ElfHeader.e_phnum = ElfPhnum;
+    ElfHeader.e_phoff = sizeof(Elf_Ehdr);
     ElfHeader.e_shoff =
         alignTo(LastSection->Offset + LastSection->Size, sizeof(Elf_Addr));
+
+    ElfProgramHeaders[0].p_type = PT_LOAD;
+    ElfProgramHeaders[0].p_offset = 0;
+    ElfProgramHeaders[0].p_vaddr = 0;
+    ElfProgramHeaders[0].p_paddr = 0;
+    ElfProgramHeaders[0].p_filesz = DynTab.Shdr.sh_offset;
+    ElfProgramHeaders[0].p_memsz = DynTab.Shdr.sh_offset;
+    ElfProgramHeaders[0].p_flags = PF_R;
+    ElfProgramHeaders[0].p_align = 0x1000;
+
+    ElfProgramHeaders[1].p_type = PT_DYNAMIC;
+    ElfProgramHeaders[1].p_offset = DynTab.Shdr.sh_offset;
+    ElfProgramHeaders[1].p_vaddr = DynTab.Shdr.sh_offset;
+    ElfProgramHeaders[1].p_paddr = DynTab.Shdr.sh_offset;
+    ElfProgramHeaders[1].p_filesz = DynTab.Shdr.sh_size;
+    ElfProgramHeaders[1].p_memsz = DynTab.Shdr.sh_size;
+    ElfProgramHeaders[1].p_flags = PF_R | PF_W;
+    ElfProgramHeaders[1].p_align = DynTab.Shdr.sh_addralign;
   }
 
   size_t getSize() const {
@@ -264,22 +517,45 @@ template <class ELFT> class ELFStubBuilder {
 
   void write(uint8_t *Data) const {
     write(Data, ElfHeader);
+    for (size_t I = 0; I < ElfPhnum; I++)
+      write(Data + ElfHeader.e_phoff + I * sizeof(Elf_Phdr),
+            ElfProgramHeaders[I]);
     DynSym.Content.write(Data + DynSym.Shdr.sh_offset);
     DynStr.Content.write(Data + DynStr.Shdr.sh_offset);
     DynTab.Content.write(Data + DynTab.Shdr.sh_offset);
     ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset);
+    if (WriteVerSym)
+      VerSym.Content.write(Data + VerSym.Shdr.sh_offset);
+    if (WriteVerDef)
+      VerDef.Content.write(Data + VerDef.Shdr.sh_offset);
+    if (WriteVerNeed)
+      VerNeed.Content.write(Data + VerNeed.Shdr.sh_offset);
     writeShdr(Data, DynSym);
     writeShdr(Data, DynStr);
     writeShdr(Data, DynTab);
     writeShdr(Data, ShStrTab);
+    if (WriteVerSym)
+      writeShdr(Data, VerSym);
+    if (WriteVerDef)
+      writeShdr(Data, VerDef);
+    if (WriteVerNeed)
+      writeShdr(Data, VerNeed);
   }
 
 private:
   Elf_Ehdr ElfHeader;
+  static constexpr auto ElfPhnum = 2;
+  Elf_Phdr ElfProgramHeaders[ElfPhnum];
   ContentSection<ELFStringTableBuilder, ELFT> DynStr;
   ContentSection<ELFStringTableBuilder, ELFT> ShStrTab;
   ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> DynSym;
   ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> DynTab;
+  ContentSection<ELFVersionSymbolBuilder<ELFT>, ELFT> VerSym;
+  ContentSection<ELFVersionDefinitionBuilder<ELFT>, ELFT> VerDef;
+  ContentSection<ELFVersionRequirementBuilder<ELFT>, ELFT> VerNeed;
+  bool WriteVerSym = false;
+  bool WriteVerDef = false;
+  bool WriteVerNeed = false;
 
   template <class T> static void write(uint8_t *Data, const T &Value) {
     *reinterpret_cast<T *>(Data) = Value;
@@ -298,6 +574,7 @@ template <class ELFT> class ELFStubBuilder {
     StrTab.Shdr.sh_entsize = 0;
     StrTab.Shdr.sh_link = 0;
   }
+
   void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> &SymTab,
                       uint32_t ShType) const {
     SymTab.Shdr.sh_type = ShType;
@@ -314,6 +591,7 @@ template <class ELFT> class ELFStubBuilder {
     SymTab.Shdr.sh_entsize = sizeof(Elf_Sym);
     SymTab.Shdr.sh_link = this->DynStr.Index;
   }
+
   void fillDynTabShdr(
       ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> &DynTab) const {
     DynTab.Shdr.sh_type = SHT_DYNAMIC;
@@ -327,6 +605,51 @@ template <class ELFT> class ELFStubBuilder {
     DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn);
     DynTab.Shdr.sh_link = this->DynStr.Index;
   }
+
+  void fillVerSymShdr(
+      ContentSection<ELFVersionSymbolBuilder<ELFT>, ELFT> &VerSym) const {
+    VerSym.Shdr.sh_type = SHT_GNU_versym;
+    VerSym.Shdr.sh_flags = SHF_ALLOC;
+    VerSym.Shdr.sh_addr = VerSym.Addr;
+    VerSym.Shdr.sh_offset = VerSym.Offset;
+    VerSym.Shdr.sh_info = 0;
+    VerSym.Shdr.sh_size = VerSym.Size;
+    VerSym.Shdr.sh_name = this->ShStrTab.Content.getOffset(VerSym.Name);
+    VerSym.Shdr.sh_addralign = VerSym.Align;
+    VerSym.Shdr.sh_entsize = sizeof(uint16_t);
+    VerSym.Shdr.sh_link = this->DynSym.Index;
+  }
+
+  void fillVerDefShdr(
+      ContentSection<ELFVersionDefinitionBuilder<ELFT>, ELFT> &VerDef,
+      size_t Size) const {
+    VerDef.Shdr.sh_type = SHT_GNU_verdef;
+    VerDef.Shdr.sh_flags = SHF_ALLOC;
+    VerDef.Shdr.sh_addr = VerDef.Addr;
+    VerDef.Shdr.sh_offset = VerDef.Offset;
+    VerDef.Shdr.sh_info = Size;
+    VerDef.Shdr.sh_size = VerDef.Size;
+    VerDef.Shdr.sh_name = this->ShStrTab.Content.getOffset(VerDef.Name);
+    VerDef.Shdr.sh_addralign = VerDef.Align;
+    VerDef.Shdr.sh_entsize = sizeof(Elf_Dyn);
+    VerDef.Shdr.sh_link = this->DynStr.Index;
+  }
+
+  void fillVerNeedShdr(
+      ContentSection<ELFVersionRequirementBuilder<ELFT>, ELFT> &VerNeed,
+      size_t Size) const {
+    VerNeed.Shdr.sh_type = SHT_GNU_verneed;
+    VerNeed.Shdr.sh_flags = SHF_ALLOC;
+    VerNeed.Shdr.sh_addr = VerNeed.Addr;
+    VerNeed.Shdr.sh_offset = VerNeed.Offset;
+    VerNeed.Shdr.sh_info = Size;
...
[truncated]

@github-actions
Copy link

⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off Keep my email addresses private setting in your account.
See LLVM Developer Policy and LLVM Discourse for more information.

@ur4t
Copy link
Contributor Author

ur4t commented Oct 12, 2025

@smeenai Would you please review this PR?

@ur4t ur4t force-pushed the llvm-ifs-symbol-version branch from a3a5119 to 4c89a5a Compare October 12, 2025 03:31
@ur4t ur4t force-pushed the llvm-ifs-symbol-version branch from 4c89a5a to e2c16c8 Compare October 12, 2025 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants