From eb0c9094acd5f5a28c0adafb1784797d1d7a4e2d Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Fri, 11 Apr 2014 04:13:39 +0000 Subject: [PATCH] [yaml2obj][ELF] ELF Relocations Support. The patch implements support for both relocation record formats: Elf_Rel and Elf_Rela. It is possible to define relocation against symbol only. Relocations against sections will be implemented later. Now yaml2obj recognizes X86_64, MIPS and Hexagon relocation types. Example of relocation section specification: Sections: - Name: .text Type: SHT_PROGBITS Content: "0000000000000000" AddressAlign: 16 Flags: [SHF_ALLOC] - Name: .rel.text Type: SHT_REL Info: .text AddressAlign: 4 Relocations: - Offset: 0x1 Symbol: glob1 Type: R_MIPS_32 - Offset: 0x2 Symbol: glob2 Type: R_MIPS_CALL16 The patch reviewed by Michael Spencer, Sean Silva, Shankar Easwaran. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206017 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELFYAML.h | 44 ++++- lib/Object/ELFYAML.cpp | 259 +++++++++++++++++++++++++++++- test/Object/yaml2obj-elf-rel.yaml | 118 ++++++++++++++ tools/yaml2obj/yaml2elf.cpp | 134 ++++++++++++++-- 4 files changed, 531 insertions(+), 24 deletions(-) create mode 100644 test/Object/yaml2obj-elf-rel.yaml diff --git a/include/llvm/Object/ELFYAML.h b/include/llvm/Object/ELFYAML.h index 1eba6602082e..38707776abea 100644 --- a/include/llvm/Object/ELFYAML.h +++ b/include/llvm/Object/ELFYAML.h @@ -40,6 +40,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFOSABI) // Just use 64, since it can hold 32-bit values too. LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_EF) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_SHT) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_REL) // Just use 64, since it can hold 32-bit values too. LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_SHF) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STT) @@ -68,17 +69,40 @@ struct LocalGlobalWeakSymbols { std::vector Weak; }; struct Section { + enum class SectionKind { RawContent, Relocation }; + SectionKind Kind; StringRef Name; ELF_SHT Type; ELF_SHF Flags; llvm::yaml::Hex64 Address; - object::yaml::BinaryRef Content; StringRef Link; + StringRef Info; llvm::yaml::Hex64 AddressAlign; + Section(SectionKind Kind) : Kind(Kind) {} +}; +struct RawContentSection : Section { + object::yaml::BinaryRef Content; + RawContentSection() : Section(SectionKind::RawContent) {} + static bool classof(const Section *S) { + return S->Kind == SectionKind::RawContent; + } +}; +struct Relocation { + uint32_t Offset; + uint32_t Addend; + ELF_REL Type; + StringRef Symbol; +}; +struct RelocationSection : Section { + std::vector Relocations; + RelocationSection() : Section(SectionKind::Relocation) {} + static bool classof(const Section *S) { + return S->Kind == SectionKind::Relocation; + } }; struct Object { FileHeader Header; - std::vector
Sections; + std::vector> Sections; // Although in reality the symbols reside in a section, it is a lot // cleaner and nicer if we read them from the YAML as a separate // top-level key, which automatically ensures that invariants like there @@ -89,8 +113,9 @@ struct Object { } // end namespace ELFYAML } // end namespace llvm -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Section) +LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) namespace llvm { namespace yaml { @@ -140,6 +165,11 @@ struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFYAML::ELF_STT &Value); }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_REL &Value); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr); @@ -155,9 +185,13 @@ struct MappingTraits { static void mapping(IO &IO, ELFYAML::LocalGlobalWeakSymbols &Symbols); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::Relocation &Rel); +}; + template <> -struct MappingTraits { - static void mapping(IO &IO, ELFYAML::Section &Section); +struct MappingTraits> { + static void mapping(IO &IO, std::unique_ptr &Section); }; template <> diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp index d51367026a62..59d9c06f370e 100644 --- a/lib/Object/ELFYAML.cpp +++ b/lib/Object/ELFYAML.cpp @@ -334,6 +334,218 @@ void ScalarEnumerationTraits::enumeration( #undef ECase } +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_REL &Value) { + const auto *Object = static_cast(IO.getContext()); + assert(Object && "The IO context is not initialized"); +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + switch (Object->Header.Machine) { + case ELF::EM_X86_64: + ECase(R_X86_64_NONE) + ECase(R_X86_64_64) + ECase(R_X86_64_PC32) + ECase(R_X86_64_GOT32) + ECase(R_X86_64_PLT32) + ECase(R_X86_64_COPY) + ECase(R_X86_64_GLOB_DAT) + ECase(R_X86_64_JUMP_SLOT) + ECase(R_X86_64_RELATIVE) + ECase(R_X86_64_GOTPCREL) + ECase(R_X86_64_32) + ECase(R_X86_64_32S) + ECase(R_X86_64_16) + ECase(R_X86_64_PC16) + ECase(R_X86_64_8) + ECase(R_X86_64_PC8) + ECase(R_X86_64_DTPMOD64) + ECase(R_X86_64_DTPOFF64) + ECase(R_X86_64_TPOFF64) + ECase(R_X86_64_TLSGD) + ECase(R_X86_64_TLSLD) + ECase(R_X86_64_DTPOFF32) + ECase(R_X86_64_GOTTPOFF) + ECase(R_X86_64_TPOFF32) + ECase(R_X86_64_PC64) + ECase(R_X86_64_GOTOFF64) + ECase(R_X86_64_GOTPC32) + ECase(R_X86_64_GOT64) + ECase(R_X86_64_GOTPCREL64) + ECase(R_X86_64_GOTPC64) + ECase(R_X86_64_GOTPLT64) + ECase(R_X86_64_PLTOFF64) + ECase(R_X86_64_SIZE32) + ECase(R_X86_64_SIZE64) + ECase(R_X86_64_GOTPC32_TLSDESC) + ECase(R_X86_64_TLSDESC_CALL) + ECase(R_X86_64_TLSDESC) + ECase(R_X86_64_IRELATIVE) + break; + case ELF::EM_MIPS: + ECase(R_MIPS_NONE) + ECase(R_MIPS_16) + ECase(R_MIPS_32) + ECase(R_MIPS_REL32) + ECase(R_MIPS_26) + ECase(R_MIPS_HI16) + ECase(R_MIPS_LO16) + ECase(R_MIPS_GPREL16) + ECase(R_MIPS_LITERAL) + ECase(R_MIPS_GOT16) + ECase(R_MIPS_PC16) + ECase(R_MIPS_CALL16) + ECase(R_MIPS_GPREL32) + ECase(R_MIPS_UNUSED1) + ECase(R_MIPS_UNUSED2) + ECase(R_MIPS_SHIFT5) + ECase(R_MIPS_SHIFT6) + ECase(R_MIPS_64) + ECase(R_MIPS_GOT_DISP) + ECase(R_MIPS_GOT_PAGE) + ECase(R_MIPS_GOT_OFST) + ECase(R_MIPS_GOT_HI16) + ECase(R_MIPS_GOT_LO16) + ECase(R_MIPS_SUB) + ECase(R_MIPS_INSERT_A) + ECase(R_MIPS_INSERT_B) + ECase(R_MIPS_DELETE) + ECase(R_MIPS_HIGHER) + ECase(R_MIPS_HIGHEST) + ECase(R_MIPS_CALL_HI16) + ECase(R_MIPS_CALL_LO16) + ECase(R_MIPS_SCN_DISP) + ECase(R_MIPS_REL16) + ECase(R_MIPS_ADD_IMMEDIATE) + ECase(R_MIPS_PJUMP) + ECase(R_MIPS_RELGOT) + ECase(R_MIPS_JALR) + ECase(R_MIPS_TLS_DTPMOD32) + ECase(R_MIPS_TLS_DTPREL32) + ECase(R_MIPS_TLS_DTPMOD64) + ECase(R_MIPS_TLS_DTPREL64) + ECase(R_MIPS_TLS_GD) + ECase(R_MIPS_TLS_LDM) + ECase(R_MIPS_TLS_DTPREL_HI16) + ECase(R_MIPS_TLS_DTPREL_LO16) + ECase(R_MIPS_TLS_GOTTPREL) + ECase(R_MIPS_TLS_TPREL32) + ECase(R_MIPS_TLS_TPREL64) + ECase(R_MIPS_TLS_TPREL_HI16) + ECase(R_MIPS_TLS_TPREL_LO16) + ECase(R_MIPS_GLOB_DAT) + ECase(R_MIPS_COPY) + ECase(R_MIPS_JUMP_SLOT) + ECase(R_MICROMIPS_26_S1) + ECase(R_MICROMIPS_HI16) + ECase(R_MICROMIPS_LO16) + ECase(R_MICROMIPS_GOT16) + ECase(R_MICROMIPS_PC16_S1) + ECase(R_MICROMIPS_CALL16) + ECase(R_MICROMIPS_GOT_DISP) + ECase(R_MICROMIPS_GOT_PAGE) + ECase(R_MICROMIPS_GOT_OFST) + ECase(R_MICROMIPS_TLS_GD) + ECase(R_MICROMIPS_TLS_LDM) + ECase(R_MICROMIPS_TLS_DTPREL_HI16) + ECase(R_MICROMIPS_TLS_DTPREL_LO16) + ECase(R_MICROMIPS_TLS_TPREL_HI16) + ECase(R_MICROMIPS_TLS_TPREL_LO16) + ECase(R_MIPS_NUM) + ECase(R_MIPS_PC32) + break; + case ELF::EM_HEXAGON: + ECase(R_HEX_NONE) + ECase(R_HEX_B22_PCREL) + ECase(R_HEX_B15_PCREL) + ECase(R_HEX_B7_PCREL) + ECase(R_HEX_LO16) + ECase(R_HEX_HI16) + ECase(R_HEX_32) + ECase(R_HEX_16) + ECase(R_HEX_8) + ECase(R_HEX_GPREL16_0) + ECase(R_HEX_GPREL16_1) + ECase(R_HEX_GPREL16_2) + ECase(R_HEX_GPREL16_3) + ECase(R_HEX_HL16) + ECase(R_HEX_B13_PCREL) + ECase(R_HEX_B9_PCREL) + ECase(R_HEX_B32_PCREL_X) + ECase(R_HEX_32_6_X) + ECase(R_HEX_B22_PCREL_X) + ECase(R_HEX_B15_PCREL_X) + ECase(R_HEX_B13_PCREL_X) + ECase(R_HEX_B9_PCREL_X) + ECase(R_HEX_B7_PCREL_X) + ECase(R_HEX_16_X) + ECase(R_HEX_12_X) + ECase(R_HEX_11_X) + ECase(R_HEX_10_X) + ECase(R_HEX_9_X) + ECase(R_HEX_8_X) + ECase(R_HEX_7_X) + ECase(R_HEX_6_X) + ECase(R_HEX_32_PCREL) + ECase(R_HEX_COPY) + ECase(R_HEX_GLOB_DAT) + ECase(R_HEX_JMP_SLOT) + ECase(R_HEX_RELATIVE) + ECase(R_HEX_PLT_B22_PCREL) + ECase(R_HEX_GOTREL_LO16) + ECase(R_HEX_GOTREL_HI16) + ECase(R_HEX_GOTREL_32) + ECase(R_HEX_GOT_LO16) + ECase(R_HEX_GOT_HI16) + ECase(R_HEX_GOT_32) + ECase(R_HEX_GOT_16) + ECase(R_HEX_DTPMOD_32) + ECase(R_HEX_DTPREL_LO16) + ECase(R_HEX_DTPREL_HI16) + ECase(R_HEX_DTPREL_32) + ECase(R_HEX_DTPREL_16) + ECase(R_HEX_GD_PLT_B22_PCREL) + ECase(R_HEX_GD_GOT_LO16) + ECase(R_HEX_GD_GOT_HI16) + ECase(R_HEX_GD_GOT_32) + ECase(R_HEX_GD_GOT_16) + ECase(R_HEX_IE_LO16) + ECase(R_HEX_IE_HI16) + ECase(R_HEX_IE_32) + ECase(R_HEX_IE_GOT_LO16) + ECase(R_HEX_IE_GOT_HI16) + ECase(R_HEX_IE_GOT_32) + ECase(R_HEX_IE_GOT_16) + ECase(R_HEX_TPREL_LO16) + ECase(R_HEX_TPREL_HI16) + ECase(R_HEX_TPREL_32) + ECase(R_HEX_TPREL_16) + ECase(R_HEX_6_PCREL_X) + ECase(R_HEX_GOTREL_32_6_X) + ECase(R_HEX_GOTREL_16_X) + ECase(R_HEX_GOTREL_11_X) + ECase(R_HEX_GOT_32_6_X) + ECase(R_HEX_GOT_16_X) + ECase(R_HEX_GOT_11_X) + ECase(R_HEX_DTPREL_32_6_X) + ECase(R_HEX_DTPREL_16_X) + ECase(R_HEX_DTPREL_11_X) + ECase(R_HEX_GD_GOT_32_6_X) + ECase(R_HEX_GD_GOT_16_X) + ECase(R_HEX_GD_GOT_11_X) + ECase(R_HEX_IE_32_6_X) + ECase(R_HEX_IE_16_X) + ECase(R_HEX_IE_GOT_32_6_X) + ECase(R_HEX_IE_GOT_16_X) + ECase(R_HEX_IE_GOT_11_X) + ECase(R_HEX_TPREL_32_6_X) + ECase(R_HEX_TPREL_16_X) + ECase(R_HEX_TPREL_11_X) + break; + default: + llvm_unreachable("Unsupported architecture"); + } +#undef ECase +} + void MappingTraits::mapping(IO &IO, ELFYAML::FileHeader &FileHdr) { IO.mapRequired("Class", FileHdr.Class); @@ -360,21 +572,62 @@ void MappingTraits::mapping( IO.mapOptional("Weak", Symbols.Weak); } -void MappingTraits::mapping(IO &IO, - ELFYAML::Section &Section) { +static void commonSectionMapping(IO &IO, ELFYAML::Section &Section) { IO.mapOptional("Name", Section.Name, StringRef()); IO.mapRequired("Type", Section.Type); IO.mapOptional("Flags", Section.Flags, ELFYAML::ELF_SHF(0)); IO.mapOptional("Address", Section.Address, Hex64(0)); - IO.mapOptional("Content", Section.Content); IO.mapOptional("Link", Section.Link); + IO.mapOptional("Info", Section.Info); IO.mapOptional("AddressAlign", Section.AddressAlign, Hex64(0)); } +static void sectionMapping(IO &IO, ELFYAML::RawContentSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Content", Section.Content); +} + +static void sectionMapping(IO &IO, ELFYAML::RelocationSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Relocations", Section.Relocations); +} + +void MappingTraits>::mapping( + IO &IO, std::unique_ptr &Section) { + ELFYAML::ELF_SHT sectionType; + if (IO.outputting()) + sectionType = Section->Type; + IO.mapRequired("Type", sectionType); + + switch (sectionType) { + case ELF::SHT_REL: + case ELF::SHT_RELA: + if (!IO.outputting()) + Section.reset(new ELFYAML::RelocationSection()); + sectionMapping(IO, *cast(Section.get())); + break; + default: + if (!IO.outputting()) + Section.reset(new ELFYAML::RawContentSection()); + sectionMapping(IO, *cast(Section.get())); + } +} + +void MappingTraits::mapping(IO &IO, + ELFYAML::Relocation &Rel) { + IO.mapRequired("Offset", Rel.Offset); + IO.mapRequired("Symbol", Rel.Symbol); + IO.mapRequired("Type", Rel.Type); + IO.mapOptional("Addend", Rel.Addend); +} + void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { + assert(!IO.getContext() && "The IO context is initialized already"); + IO.setContext(&Object); IO.mapRequired("FileHeader", Object.Header); IO.mapOptional("Sections", Object.Sections); IO.mapOptional("Symbols", Object.Symbols); + IO.setContext(nullptr); } } // end namespace yaml diff --git a/test/Object/yaml2obj-elf-rel.yaml b/test/Object/yaml2obj-elf-rel.yaml new file mode 100644 index 000000000000..121a533b8cba --- /dev/null +++ b/test/Object/yaml2obj-elf-rel.yaml @@ -0,0 +1,118 @@ +# RUN: yaml2obj -format=elf %s | llvm-readobj -sections -relocations - | FileCheck %s + +!ELF +FileHeader: !FileHeader + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + +Sections: +- Name: .text + Type: SHT_PROGBITS + Content: "0000000000000000" + AddressAlign: 16 + Flags: [SHF_ALLOC] + +- Name: .rel.text + Type: SHT_REL + Info: .text + AddressAlign: 4 + Relocations: + - Offset: 0x1 + Symbol: glob1 + Type: R_MIPS_32 + - Offset: 0x1 + Symbol: glob2 + Type: R_MIPS_CALL16 + - Offset: 0x2 + Symbol: loc1 + Type: R_MIPS_LO16 + +- Name: .rela.text + Type: SHT_RELA + Link: .symtab + Info: .text + AddressAlign: 4 + Relocations: + - Offset: 0x1 + Addend: 1 + Symbol: glob1 + Type: R_MIPS_32 + - Offset: 0x1 + Addend: 2 + Symbol: glob2 + Type: R_MIPS_CALL16 + - Offset: 0x2 + Addend: 3 + Symbol: loc1 + Type: R_MIPS_LO16 + +Symbols: + Local: + - Name: loc1 + - Name: loc2 + Global: + - Name: glob1 + Section: .text + Value: 0x0 + Size: 4 + - Name: glob2 + Weak: + - Name: weak1 + +# CHECK: Section { +# CHECK-NEXT: Index: 0 +# CHECK: } +# CHECK: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .text (1) +# CHECK: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .rel.text (7) +# CHECK-NEXT: Type: SHT_REL (0x9) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x160 +# CHECK-NEXT: Size: 24 +# CHECK-NEXT: Link: 4 +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 8 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .rela.text (17) +# CHECK-NEXT: Type: SHT_RELA (0x4) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x180 +# CHECK-NEXT: Size: 36 +# CHECK-NEXT: Link: 4 +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 12 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .symtab (28) +# CHECK: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Name: .strtab (36) +# CHECK: } +# CHECK: Relocations [ +# CHECK-NEXT: Section (2) .rel.text { +# CHECK-NEXT: 0x1 R_MIPS_32 glob1 0x0 +# CHECK-NEXT: 0x1 R_MIPS_CALL16 glob2 0x0 +# CHECK-NEXT: 0x2 R_MIPS_LO16 loc1 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Section (3) .rela.text { +# CHECK-NEXT: 0x1 R_MIPS_32 glob1 0x1 +# CHECK-NEXT: 0x1 R_MIPS_CALL16 glob2 0x2 +# CHECK-NEXT: 0x2 R_MIPS_LO16 loc1 0x3 +# CHECK-NEXT: } +# CHECK-NEXT: ] diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 4e9ee4dcd671..acbac9c60577 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -143,6 +143,8 @@ class ELFState { typedef typename object::ELFFile::Elf_Ehdr Elf_Ehdr; typedef typename object::ELFFile::Elf_Shdr Elf_Shdr; typedef typename object::ELFFile::Elf_Sym Elf_Sym; + typedef typename object::ELFFile::Elf_Rel Elf_Rel; + typedef typename object::ELFFile::Elf_Rela Elf_Rela; /// \brief The future ".strtab" section. StringTableBuilder DotStrtab; @@ -151,9 +153,12 @@ class ELFState { StringTableBuilder DotShStrtab; NameToIdxMap SN2I; + NameToIdxMap SymN2I; const ELFYAML::Object &Doc; bool buildSectionIndex(); + bool buildSymbolIndex(std::size_t &StartIndex, + const std::vector &Symbols); void initELFHeader(Elf_Ehdr &Header); bool initSectionHeaders(std::vector &SHeaders, ContiguousBlobAccumulator &CBA); @@ -164,6 +169,12 @@ class ELFState { ContiguousBlobAccumulator &CBA); void addSymbols(const std::vector &Symbols, std::vector &Syms, unsigned SymbolBinding); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RawContentSection &Section, + ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RelocationSection &Section, + ContiguousBlobAccumulator &CBA); // - SHT_NULL entry (placed first, i.e. 0'th entry) // - symbol table (.symtab) (placed third to last) @@ -219,26 +230,42 @@ bool ELFState::initSectionHeaders(std::vector &SHeaders, for (const auto &Sec : Doc.Sections) { zero(SHeader); - SHeader.sh_name = DotShStrtab.addString(Sec.Name); - SHeader.sh_type = Sec.Type; - SHeader.sh_flags = Sec.Flags; - SHeader.sh_addr = Sec.Address; + SHeader.sh_name = DotShStrtab.addString(Sec->Name); + SHeader.sh_type = Sec->Type; + SHeader.sh_flags = Sec->Flags; + SHeader.sh_addr = Sec->Address; + SHeader.sh_addralign = Sec->AddressAlign; - Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); - SHeader.sh_size = Sec.Content.binary_size(); - - if (!Sec.Link.empty()) { + if (!Sec->Link.empty()) { unsigned Index; - if (SN2I.lookup(Sec.Link, Index)) { - errs() << "error: Unknown section referenced: '" << Sec.Link - << "' at YAML section '" << Sec.Name << "'.\n"; - return false;; + if (SN2I.lookup(Sec->Link, Index)) { + errs() << "error: Unknown section referenced: '" << Sec->Link + << "' at YAML section '" << Sec->Name << "'.\n"; + return false; } SHeader.sh_link = Index; } - SHeader.sh_info = 0; - SHeader.sh_addralign = Sec.AddressAlign; - SHeader.sh_entsize = 0; + + if (auto S = dyn_cast(Sec.get())) + writeSectionContent(SHeader, *S, CBA); + 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)) { + errs() << "error: Unknown section referenced: '" << S->Info + << "' at YAML section '" << S->Name << "'.\n"; + return false; + } + SHeader.sh_info = Index; + + if (!writeSectionContent(SHeader, *S, CBA)) + return false; + } else + llvm_unreachable("Unknown section type"); + SHeaders.push_back(SHeader); } return true; @@ -308,13 +335,66 @@ void ELFState::addSymbols(const std::vector &Symbols, } } +template +void +ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RawContentSection &Section, + ContiguousBlobAccumulator &CBA) { + Section.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset)); + SHeader.sh_entsize = 0; + SHeader.sh_size = Section.Content.binary_size(); +} + +template +bool +ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RelocationSection &Section, + ContiguousBlobAccumulator &CBA) { + if (Section.Type != llvm::ELF::SHT_REL && + Section.Type != llvm::ELF::SHT_RELA) { + errs() << "error: Invalid relocation section type.\n"; + return false; + } + + bool IsRela = Section.Type == llvm::ELF::SHT_RELA; + SHeader.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); + SHeader.sh_size = SHeader.sh_entsize * Section.Relocations.size(); + + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); + + for (const auto &Rel : Section.Relocations) { + unsigned SymIdx; + if (SymN2I.lookup(Rel.Symbol, SymIdx)) { + errs() << "error: Unknown symbol referenced: '" << Rel.Symbol + << "' at YAML relocation.\n"; + return false; + } + + if (IsRela) { + Elf_Rela REntry; + zero(REntry); + REntry.r_offset = Rel.Offset; + REntry.r_addend = Rel.Addend; + REntry.setSymbolAndType(SymIdx, Rel.Type); + OS.write((const char *)&REntry, sizeof(REntry)); + } else { + Elf_Rel REntry; + zero(REntry); + REntry.r_offset = Rel.Offset; + REntry.setSymbolAndType(SymIdx, Rel.Type); + OS.write((const char *)&REntry, sizeof(REntry)); + } + } + return true; +} + template bool ELFState::buildSectionIndex() { SN2I.addName(".symtab", getDotSymTabSecNo()); SN2I.addName(".strtab", getDotStrTabSecNo()); SN2I.addName(".shstrtab", getDotShStrTabSecNo()); for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { - StringRef Name = Doc.Sections[i].Name; + StringRef Name = Doc.Sections[i]->Name; if (Name.empty()) continue; // "+ 1" to take into account the SHT_NULL entry. @@ -327,12 +407,34 @@ template bool ELFState::buildSectionIndex() { return true; } +template +bool +ELFState::buildSymbolIndex(std::size_t &StartIndex, + const std::vector &Symbols) { + for (const auto &Sym : Symbols) { + ++StartIndex; + if (Sym.Name.empty()) + continue; + if (SymN2I.addName(Sym.Name, StartIndex)) { + errs() << "error: Repeated symbol name: '" << Sym.Name << "'.\n"; + return false; + } + } + return true; +} + template int ELFState::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { ELFState State(Doc); if (!State.buildSectionIndex()) return 1; + std::size_t StartSymIndex = 0; + if (!State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Local) || + !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Global) || + !State.buildSymbolIndex(StartSymIndex, Doc.Symbols.Weak)) + return 1; + Elf_Ehdr Header; State.initELFHeader(Header);