diff options
author | Georgii Rymar <grimar@accesssoftek.com> | 2019-11-01 15:24:58 +0300 |
---|---|---|
committer | Georgii Rymar <grimar@accesssoftek.com> | 2019-11-11 11:48:23 +0300 |
commit | 06456daa9e59ffddc634e4f1aa592161653fbd36 (patch) | |
tree | ef5215d4fe03c131918ad84b85cbd7f8b5d5cd13 /llvm/lib/ObjectYAML/ELFEmitter.cpp | |
parent | b4f46a9bb42972e663f8b7b4d15e4c8ed3fecef4 (diff) | |
download | bcm5719-llvm-06456daa9e59ffddc634e4f1aa592161653fbd36.tar.gz bcm5719-llvm-06456daa9e59ffddc634e4f1aa592161653fbd36.zip |
[yaml2obj] - Add a way to describe the custom data that is not part of an output section.
Currently there is no way to describe the data that is not a part of an output section.
It can be a data used to align sections or to fill the gaps with something,
or another kind of custom data. In this patch I suggest a way to describe it. It looks like that:
```
Sections:
- Type: CustomFiller
Pattern: "CCDD"
Size: 4
- Name: .bar
Type: SHT_PROGBITS
Content: "FF"
```
I.e. I've added a kind of synthetic section with a synthetic type "CustomFiller".
In the code it is called a "SyntheticFiller", which is "a synthetic section which
might be used to write the custom data around regular output sections. It does
not present in the sections header table, but it might affect the output file size and
program headers produced. Think about it as about piece of data."
`SyntheticFiller` currently has a `Pattern` field and a `Size` field + an optional `Name`.
When written, `Size` of bytes in the output will be filled with a `Pattern`.
It is possible to reference a named filler it by name from the program headers description,
just like any other normal section.
Differential revision: https://reviews.llvm.org/D69709
Diffstat (limited to 'llvm/lib/ObjectYAML/ELFEmitter.cpp')
-rw-r--r-- | llvm/lib/ObjectYAML/ELFEmitter.cpp | 168 |
1 files changed, 123 insertions, 45 deletions
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index be733dca696..214318f2813 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" @@ -88,6 +89,15 @@ public: unsigned size() const { return Map.size(); } }; +namespace { +struct Fragment { + uint64_t Offset; + uint64_t Size; + uint32_t Type; + uint64_t AddrAlign; +}; +}; // namespace + /// "Single point of truth" for the ELF file construction. /// TODO: This class still has a ways to go before it is truly a "single /// point of truth". @@ -142,6 +152,11 @@ template <class ELFT> class ELFState { ELFYAML::Section *YAMLSec); void setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders, std::vector<Elf_Shdr> &SHeaders); + + std::vector<Fragment> + getPhdrFragments(const ELFYAML::ProgramHeader &Phdr, + ArrayRef<typename ELFT::Shdr> SHeaders); + void finalizeStrings(); void writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream &OS); void writeSectionContent(Elf_Shdr &SHeader, @@ -186,6 +201,8 @@ template <class ELFT> class ELFState { const ELFYAML::GnuHashSection &Section, ContiguousBlobAccumulator &CBA); + void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA); + ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); public: @@ -207,17 +224,18 @@ template <class T> static void zero(T &Obj) { memset(&Obj, 0, sizeof(Obj)); } template <class ELFT> ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) : Doc(D), ErrHandler(EH) { + std::vector<ELFYAML::Section *> Sections = Doc.getSections(); StringSet<> DocSections; - for (std::unique_ptr<ELFYAML::Section> &D : Doc.Sections) - if (!D->Name.empty()) - DocSections.insert(D->Name); + for (const ELFYAML::Section *Sec : Sections) + if (!Sec->Name.empty()) + DocSections.insert(Sec->Name); // Insert SHT_NULL section implicitly when it is not defined in YAML. - if (Doc.Sections.empty() || Doc.Sections.front()->Type != ELF::SHT_NULL) - Doc.Sections.insert( - Doc.Sections.begin(), + if (Sections.empty() || Sections.front()->Type != ELF::SHT_NULL) + Doc.Chunks.insert( + Doc.Chunks.begin(), std::make_unique<ELFYAML::Section>( - ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true)); + ELFYAML::Chunk::ChunkKind::RawContent, /*IsImplicit=*/true)); std::vector<StringRef> ImplicitSections; if (Doc.Symbols) @@ -233,10 +251,10 @@ ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH) if (DocSections.count(SecName)) continue; - std::unique_ptr<ELFYAML::Section> Sec = std::make_unique<ELFYAML::Section>( - ELFYAML::Section::SectionKind::RawContent, true /*IsImplicit*/); + std::unique_ptr<ELFYAML::Chunk> Sec = std::make_unique<ELFYAML::Section>( + ELFYAML::Chunk::ChunkKind::RawContent, true /*IsImplicit*/); Sec->Name = SecName; - Doc.Sections.push_back(std::move(Sec)); + Doc.Chunks.push_back(std::move(Sec)); } } @@ -274,7 +292,7 @@ void ELFState<ELFT>::writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream Header.e_shoff = Doc.Header.SHOff ? typename ELFT::uint(*Doc.Header.SHOff) : SHOff; Header.e_shnum = - Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.Sections.size(); + Doc.Header.SHNum ? (uint16_t)*Doc.Header.SHNum : Doc.getSections().size(); Header.e_shstrndx = Doc.Header.SHStrNdx ? (uint16_t)*Doc.Header.SHStrNdx : SN2I.get(".shstrtab"); @@ -371,18 +389,25 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, ContiguousBlobAccumulator &CBA) { // Ensure SHN_UNDEF entry is present. An all-zero section header is a // valid SHN_UNDEF entry since SHT_NULL == 0. - SHeaders.resize(Doc.Sections.size()); + SHeaders.resize(Doc.getSections().size()); + + size_t SecNdx = -1; + for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) { + if (auto S = dyn_cast<ELFYAML::Fill>(D.get())) { + writeFill(*S, CBA); + continue; + } - for (size_t I = 0; I < Doc.Sections.size(); ++I) { - ELFYAML::Section *Sec = Doc.Sections[I].get(); - if (I == 0 && Sec->IsImplicit) + ++SecNdx; + ELFYAML::Section *Sec = cast<ELFYAML::Section>(D.get()); + if (SecNdx == 0 && Sec->IsImplicit) continue; // We have a few sections like string or symbol tables that are usually // added implicitly to the end. However, if they are explicitly specified // in the YAML, we need to write them here. This ensures the file offset // remains correct. - Elf_Shdr &SHeader = SHeaders[I]; + Elf_Shdr &SHeader = SHeaders[SecNdx]; if (initImplicitHeader(CBA, SHeader, Sec->Name, Sec->IsImplicit ? nullptr : Sec)) continue; @@ -401,7 +426,7 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders, if (!Sec->Link.empty()) SHeader.sh_link = toSectionIndex(Sec->Link, Sec->Name); - if (I == 0) { + if (SecNdx == 0) { if (auto RawSec = dyn_cast<ELFYAML::RawContentSection>(Sec)) { // We do not write any content for special SHN_UNDEF section. if (RawSec->Size) @@ -641,22 +666,43 @@ template <class ELFT> void ELFState<ELFT>::reportError(const Twine &Msg) { } template <class ELFT> +std::vector<Fragment> +ELFState<ELFT>::getPhdrFragments(const ELFYAML::ProgramHeader &Phdr, + ArrayRef<typename ELFT::Shdr> SHeaders) { + DenseMap<StringRef, ELFYAML::Fill *> NameToFill; + for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) + if (auto S = dyn_cast<ELFYAML::Fill>(D.get())) + NameToFill[S->Name] = S; + + std::vector<Fragment> Ret; + for (const ELFYAML::SectionName &SecName : Phdr.Sections) { + unsigned Index; + if (SN2I.lookup(SecName.Section, Index)) { + const typename ELFT::Shdr &H = SHeaders[Index]; + Ret.push_back({H.sh_offset, H.sh_size, H.sh_type, H.sh_addralign}); + continue; + } + + if (ELFYAML::Fill *Fill = NameToFill.lookup(SecName.Section)) { + Ret.push_back({Fill->ShOffset, Fill->Size, llvm::ELF::SHT_PROGBITS, + /*ShAddrAlign=*/1}); + continue; + } + + reportError("unknown section or fill referenced: '" + SecName.Section + + "' by program header"); + } + + return Ret; +} + +template <class ELFT> void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders, std::vector<Elf_Shdr> &SHeaders) { uint32_t PhdrIdx = 0; for (auto &YamlPhdr : Doc.ProgramHeaders) { Elf_Phdr &PHeader = PHeaders[PhdrIdx++]; - - std::vector<Elf_Shdr *> Sections; - for (const ELFYAML::SectionName &SecName : YamlPhdr.Sections) { - unsigned Index; - if (!SN2I.lookup(SecName.Section, Index)) { - reportError("unknown section referenced: '" + SecName.Section + - "' by program header"); - continue; - } - Sections.push_back(&SHeaders[Index]); - } + std::vector<Fragment> Fragments = getPhdrFragments(YamlPhdr, SHeaders); if (YamlPhdr.Offset) { PHeader.p_offset = *YamlPhdr.Offset; @@ -667,19 +713,19 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders, PHeader.p_offset = 0; // Find the minimum offset for the program header. - for (Elf_Shdr *SHeader : Sections) - PHeader.p_offset = std::min(PHeader.p_offset, SHeader->sh_offset); + for (const Fragment &F : Fragments) + PHeader.p_offset = std::min((uint64_t)PHeader.p_offset, F.Offset); } // Find the maximum offset of the end of a section in order to set p_filesz // and p_memsz. When setting p_filesz, trailing SHT_NOBITS sections are not // counted. uint64_t FileOffset = PHeader.p_offset, MemOffset = PHeader.p_offset; - for (Elf_Shdr *SHeader : Sections) { - uint64_t End = SHeader->sh_offset + SHeader->sh_size; + for (const Fragment &F : Fragments) { + uint64_t End = F.Offset + F.Size; MemOffset = std::max(MemOffset, End); - if (SHeader->sh_type != llvm::ELF::SHT_NOBITS) + if (F.Type != llvm::ELF::SHT_NOBITS) FileOffset = std::max(FileOffset, End); } @@ -696,8 +742,8 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders, // sections so that by default the segment has a valid and sensible // alignment. PHeader.p_align = 1; - for (Elf_Shdr *SHeader : Sections) - PHeader.p_align = std::max(PHeader.p_align, SHeader->sh_addralign); + for (const Fragment &F : Fragments) + PHeader.p_align = std::max((uint64_t)PHeader.p_align, F.AddrAlign); } } } @@ -1160,16 +1206,45 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader, Section.HashValues->size() * 4; } +template <class ELFT> +void ELFState<ELFT>::writeFill(ELFYAML::Fill &Fill, + ContiguousBlobAccumulator &CBA) { + raw_ostream &OS = CBA.getOSAndAlignedOffset(Fill.ShOffset, /*Align=*/1); + + size_t PatternSize = Fill.Pattern ? Fill.Pattern->binary_size() : 0; + if (!PatternSize) { + OS.write_zeros(Fill.Size); + return; + } + + // Fill the content with the specified pattern. + uint64_t Written = 0; + for (; Written + PatternSize <= Fill.Size; Written += PatternSize) + Fill.Pattern->writeAsBinary(OS); + Fill.Pattern->writeAsBinary(OS, Fill.Size - Written); +} + template <class ELFT> void ELFState<ELFT>::buildSectionIndex() { - for (unsigned I = 0, E = Doc.Sections.size(); I != E; ++I) { - StringRef Name = Doc.Sections[I]->Name; - if (Name.empty()) + size_t SecNdx = -1; + StringSet<> Seen; + for (size_t I = 0; I < Doc.Chunks.size(); ++I) { + const std::unique_ptr<ELFYAML::Chunk> &C = Doc.Chunks[I]; + bool IsSection = isa<ELFYAML::Section>(C.get()); + if (IsSection) + ++SecNdx; + + if (C->Name.empty()) continue; - DotShStrtab.add(ELFYAML::dropUniqueSuffix(Name)); - if (!SN2I.addName(Name, I)) - reportError("repeated section name: '" + Name + - "' at YAML section number " + Twine(I)); + if (!Seen.insert(C->Name).second) + reportError("repeated section/fill name: '" + C->Name + + "' at YAML section/fill number " + Twine(I)); + if (!IsSection || HasError) + continue; + + if (!SN2I.addName(C->Name, SecNdx)) + llvm_unreachable("buildSectionIndex() failed"); + DotShStrtab.add(ELFYAML::dropUniqueSuffix(C->Name)); } DotShStrtab.finalize(); @@ -1202,14 +1277,14 @@ template <class ELFT> void ELFState<ELFT>::finalizeStrings() { // SHT_GNU_verdef and SHT_GNU_verneed sections might also // add strings to .dynstr section. - for (const std::unique_ptr<ELFYAML::Section> &Sec : Doc.Sections) { - if (auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec.get())) { + for (const ELFYAML::Chunk *Sec : Doc.getSections()) { + if (auto VerNeed = dyn_cast<ELFYAML::VerneedSection>(Sec)) { for (const ELFYAML::VerneedEntry &VE : VerNeed->VerneedV) { DotDynstr.add(VE.File); for (const ELFYAML::VernauxEntry &Aux : VE.AuxV) DotDynstr.add(Aux.Name); } - } else if (auto VerDef = dyn_cast<ELFYAML::VerdefSection>(Sec.get())) { + } else if (auto VerDef = dyn_cast<ELFYAML::VerdefSection>(Sec)) { for (const ELFYAML::VerdefEntry &E : VerDef->Entries) for (StringRef Name : E.VerNames) DotDynstr.add(Name); @@ -1230,6 +1305,9 @@ bool ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc, State.finalizeStrings(); State.buildSectionIndex(); + if (State.HasError) + return false; + State.buildSymbolIndexes(); std::vector<Elf_Phdr> PHeaders; |