Index: include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- include/llvm/ObjectYAML/ELFYAML.h +++ include/llvm/ObjectYAML/ELFYAML.h @@ -113,6 +113,7 @@ RawContent, Relocation, NoBits, + VersionNeed, MipsABIFlags }; SectionKind Kind; @@ -128,6 +129,7 @@ Section(SectionKind Kind) : Kind(Kind) {} virtual ~Section(); }; + struct RawContentSection : Section { yaml::BinaryRef Content; llvm::yaml::Hex64 Size; @@ -178,6 +180,30 @@ } }; +struct VersionNeedAux { + llvm::yaml::Hex64 Hash; + llvm::yaml::Hex32 Flags; + llvm::yaml::Hex32 Other; + llvm::yaml::Hex64 Name; +}; + +struct VersionNeed { + int32_t Version; + llvm::yaml::Hex64 File; + std::vector Auxiliaries; +}; + +// Represents .gnu.version_r section +struct VersionNeedSection : Section { + std::vector VersionNeeds; + + VersionNeedSection() : Section(SectionKind::VersionNeed) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::VersionNeed; + } +}; + // Represents .MIPS.abiflags section struct MipsABIFlags : Section { llvm::yaml::Hex16 Version; @@ -220,6 +246,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionNeed) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionNeedAux) namespace llvm { namespace yaml { @@ -374,6 +402,16 @@ static void mapping(IO &IO, ELFYAML::SectionName §ionName); }; +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionNeed &VNeed); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionNeedAux &VnAux); +}; + } // end namespace yaml } // end namespace llvm Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -853,6 +853,11 @@ IO.mapRequired("Section", sectionName.Section); } +static void sectionMapping(IO &IO, ELFYAML::VersionNeedSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("VersionNeeds", Section.VersionNeeds); +} + static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Version", Section.Version, Hex16(0)); @@ -898,6 +903,11 @@ Section.reset(new ELFYAML::NoBitsSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_GNU_verneed: + if (!IO.outputting()) + Section.reset(new ELFYAML::VersionNeedSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_MIPS_ABIFLAGS: if (!IO.outputting()) Section.reset(new ELFYAML::MipsABIFlags()); @@ -965,6 +975,23 @@ IO.mapOptional("Addend", Rel.Addend, (int64_t)0); } +void MappingTraits::mapping(IO &IO, + ELFYAML::VersionNeed &VNeed) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Version", VNeed.Version); + IO.mapRequired("File", VNeed.File); + IO.mapRequired("Auxiliaries", VNeed.Auxiliaries); +} + +void MappingTraits::mapping(IO &IO, + ELFYAML::VersionNeedAux &VnAux) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Hash", VnAux.Hash); + IO.mapRequired("Flags", VnAux.Flags); + IO.mapRequired("Other", VnAux.Other); + IO.mapRequired("Name", VnAux.Name); +} + void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { assert(!IO.getContext() && "The IO context is initialized already"); IO.setContext(&Object); Index: test/tools/yaml2obj/symbol-version-section.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/symbol-version-section.yaml @@ -0,0 +1,82 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj -V %t | FileCheck %s + +# CHECK: SHT_GNU_verneed { +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Count: 1 +# CHECK-NEXT: FileName: libfoo.so.0 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 6 +# CHECK-NEXT: Flags: 0x0 +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: GLIBFOO_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Count: 2 +# CHECK-NEXT: FileName: libbar.so.0 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 74565 +# CHECK-NEXT: Flags: Base (0x1) +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: GLIBBAR_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 344865 +# CHECK-NEXT: Flags: Weak (0x2) +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: GLIBFOO_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: } + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Content: 006c6962666f6f2e736f2e30006c69626261722e736f2e3000474c4942464f4f5f302e302e3000474c49424241525f302e302e3000 + # Content: "libfoo.so.0 libbar.so.0 GLIBFOO_0.0.0 GLIBBAR_0.0.0" + # Offset: 0x01 0x0d 0x19 0x27 + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Link: .dynstr + AddressAlign: 0x0510 + VersionNeeds: + - Version: 2 + File: 0x01 # libfoo.so.0 + Auxiliaries: + - Hash: 0x06 + Name: 0x19 # GLIBFOO_0.0.0 + Flags: 0x00 + Other: 0x00 + - Version: 1 + File: 0x0d # libbar.so.0 + Auxiliaries: + - Hash: 0x012345 + Name: 0x27 # GLIBBAR_0.0.0 + Flags: 0x01 + Other: 0x01 + - Hash: 0x054321 + Name: 0x19 # GLIBFOO_0.0.0 + Flags: 0x02 + Other: 0x02 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Link: .dynstr + Content: 0100000000000000010000000000000001000000000000000d000000000000000C00000000000000A0060000000000000D000000000000002409000000000000FFFFFF6F000000000200000000000000FEFFFF6F0000000010050000000000000000000000000000000000000000000000000000000000000000000000000000 +ProgramHeaders: + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + VAddr: 0xAAAA1000 + PAddr: 0xFFFF1000 + Sections: + - Section: .dynamic Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -158,6 +158,9 @@ bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, ContiguousBlobAccumulator &CBA); bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VersionNeedSection &Section, + ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); bool hasDynamicSymbols() const; @@ -226,6 +229,16 @@ } } +static bool checkSectionIndex(NameToIdxMap &SX2I, StringRef SecName, + StringRef SecField, unsigned &Index) { + if (SX2I.lookup(SecField, Index) && !to_integer(SecField, Index)) { + WithColor::error() << "Unknown section referenced: '" << SecField + << "' at YAML section '" << SecName << "'.\n"; + return false; + } + return true; +} + template bool ELFState::initSectionHeaders(std::vector &SHeaders, ContiguousBlobAccumulator &CBA) { @@ -245,39 +258,31 @@ if (!Sec->Link.empty()) { unsigned Index; - if (SN2I.lookup(Sec->Link, Index) && !to_integer(Sec->Link, Index)) { - WithColor::error() << "Unknown section referenced: '" << Sec->Link - << "' at YAML section '" << Sec->Name << "'.\n"; + if (!checkSectionIndex(SN2I, Sec->Name, Sec->Link, Index)) return false; - } SHeader.sh_link = Index; } - if (auto S = dyn_cast(Sec.get())) + if (auto S = dyn_cast(Sec.get())) { writeSectionContent(SHeader, *S, CBA); - else if (auto S = dyn_cast(Sec.get())) { + } else if (auto S = dyn_cast(Sec.get())) { if (S->Link.empty()) // For relocation section set link to .symtab by default. SHeader.sh_link = getDotSymTabSecNo(); unsigned Index; - if (SN2I.lookup(S->Info, Index) && !to_integer(S->Info, Index)) { - WithColor::error() << "Unknown section referenced: '" << S->Info - << "' at YAML section '" << S->Name << "'.\n"; + if (!checkSectionIndex(SN2I, S->Name, S->Info, Index)) return false; - } SHeader.sh_info = Index; if (!writeSectionContent(SHeader, *S, CBA)) return false; } else if (auto S = dyn_cast(Sec.get())) { unsigned SymIdx; - if (SymN2I.lookup(S->Info, SymIdx) && !to_integer(S->Info, SymIdx)) { - WithColor::error() << "Unknown symbol referenced: '" << S->Info - << "' at YAML section '" << S->Name << "'.\n"; + if (!checkSectionIndex(SymN2I, S->Name, S->Info, SymIdx)) return false; - } SHeader.sh_info = SymIdx; + if (!writeSectionContent(SHeader, *S, CBA)) return false; } else if (auto S = dyn_cast(Sec.get())) { @@ -289,6 +294,9 @@ // SHT_NOBITS section does not have content // so just to setup the section offset. CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + } else if (auto S = dyn_cast(Sec.get())) { + if (!writeSectionContent(SHeader, *S, CBA)) + return false; } else llvm_unreachable("Unknown section type"); @@ -549,6 +557,55 @@ } template +bool ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::VersionNeedSection &Section, + ContiguousBlobAccumulator &CBA) { + assert(Section.Type == llvm::ELF::SHT_GNU_verneed && + "Section type is not SHT_GNU_verneed"); + + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + uint64_t BlobSize = 0; + SHeader.sh_info = Section.VersionNeeds.size(); + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + for (auto VNeedIt = Section.VersionNeeds.begin(); + VNeedIt != Section.VersionNeeds.end(); ++VNeedIt) { + Elf_Verneed VNeed; + zero(VNeed); + + VNeed.vn_version = VNeedIt->Version; + VNeed.vn_cnt = VNeedIt->Auxiliaries.size(); + VNeed.vn_file = VNeedIt->File; + VNeed.vn_aux = sizeof(Elf_Verneed); + VNeed.vn_next = + (VNeedIt != Section.VersionNeeds.end() - 1) + ? sizeof(Elf_Verneed) + VNeed.vn_cnt * sizeof(Elf_Vernaux) + : 0; + BlobSize += sizeof(Elf_Verneed); + + OS.write((const char *)&VNeed, sizeof(VNeed)); + for (auto VnAuxIt = VNeedIt->Auxiliaries.begin(); + VnAuxIt != VNeedIt->Auxiliaries.end(); ++VnAuxIt) { + Elf_Vernaux VnAux; + zero(VnAux); + VnAux.vna_hash = VnAuxIt->Hash; + VnAux.vna_flags = VnAuxIt->Flags; + VnAux.vna_other = VnAuxIt->Other; + VnAux.vna_name = VnAuxIt->Name; + VnAux.vna_next = + (VnAuxIt != VNeedIt->Auxiliaries.end() - 1) ? sizeof(Elf_Vernaux) : 0; + BlobSize += sizeof(Elf_Vernaux); + + OS.write((const char *)&VnAux, sizeof(VnAux)); + } + } + SHeader.sh_size = BlobSize; + return true; +} + +template bool ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA) {