mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[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
This commit is contained in:
parent
407077ed2f
commit
6f39af85a4
@ -130,8 +130,8 @@ struct NoteEntry {
|
||||
llvm::yaml::Hex32 Type;
|
||||
};
|
||||
|
||||
struct Section {
|
||||
enum class SectionKind {
|
||||
struct Chunk {
|
||||
enum class ChunkKind {
|
||||
Dynamic,
|
||||
Group,
|
||||
RawContent,
|
||||
@ -146,10 +146,18 @@ struct Section {
|
||||
SymtabShndxSection,
|
||||
Symver,
|
||||
MipsABIFlags,
|
||||
Addrsig
|
||||
Addrsig,
|
||||
Fill
|
||||
};
|
||||
SectionKind Kind;
|
||||
|
||||
ChunkKind Kind;
|
||||
StringRef Name;
|
||||
|
||||
Chunk(ChunkKind K) : Kind(K) {}
|
||||
virtual ~Chunk();
|
||||
};
|
||||
|
||||
struct Section : public Chunk {
|
||||
ELF_SHT Type;
|
||||
Optional<ELF_SHF> Flags;
|
||||
llvm::yaml::Hex64 Address;
|
||||
@ -161,9 +169,10 @@ struct Section {
|
||||
// When they are, this flag is used to signal about that.
|
||||
bool IsImplicit;
|
||||
|
||||
Section(SectionKind Kind, bool IsImplicit = false)
|
||||
: Kind(Kind), IsImplicit(IsImplicit) {}
|
||||
virtual ~Section();
|
||||
Section(ChunkKind Kind, bool IsImplicit = false)
|
||||
: Chunk(Kind), IsImplicit(IsImplicit) {}
|
||||
|
||||
static bool classof(const Chunk *S) { return S->Kind != ChunkKind::Fill; }
|
||||
|
||||
// The following members are used to override section fields which is
|
||||
// useful for creating invalid objects.
|
||||
@ -181,15 +190,32 @@ struct Section {
|
||||
Optional<llvm::yaml::Hex64> ShSize;
|
||||
};
|
||||
|
||||
// Fill is a block of data which is placed outside of sections. It is
|
||||
// not present in the sections header table, but it might affect the output file
|
||||
// size and program headers produced.
|
||||
struct Fill : Chunk {
|
||||
Optional<yaml::BinaryRef> Pattern;
|
||||
llvm::yaml::Hex64 Size;
|
||||
|
||||
// We have to remember the offset of the fill, because it does not have
|
||||
// a corresponding section header, unlike a section. We might need this
|
||||
// information when writing the output.
|
||||
uint64_t ShOffset;
|
||||
|
||||
Fill() : Chunk(ChunkKind::Fill) {}
|
||||
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Fill; }
|
||||
};
|
||||
|
||||
struct StackSizesSection : Section {
|
||||
Optional<yaml::BinaryRef> Content;
|
||||
Optional<llvm::yaml::Hex64> Size;
|
||||
Optional<std::vector<StackSizeEntry>> Entries;
|
||||
|
||||
StackSizesSection() : Section(SectionKind::StackSizes) {}
|
||||
StackSizesSection() : Section(ChunkKind::StackSizes) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::StackSizes;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::StackSizes;
|
||||
}
|
||||
|
||||
static bool nameMatches(StringRef Name) {
|
||||
@ -201,11 +227,9 @@ struct DynamicSection : Section {
|
||||
std::vector<DynamicEntry> Entries;
|
||||
Optional<yaml::BinaryRef> Content;
|
||||
|
||||
DynamicSection() : Section(SectionKind::Dynamic) {}
|
||||
DynamicSection() : Section(ChunkKind::Dynamic) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Dynamic;
|
||||
}
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Dynamic; }
|
||||
};
|
||||
|
||||
struct RawContentSection : Section {
|
||||
@ -213,21 +237,19 @@ struct RawContentSection : Section {
|
||||
Optional<llvm::yaml::Hex64> Size;
|
||||
Optional<llvm::yaml::Hex64> Info;
|
||||
|
||||
RawContentSection() : Section(SectionKind::RawContent) {}
|
||||
RawContentSection() : Section(ChunkKind::RawContent) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::RawContent;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::RawContent;
|
||||
}
|
||||
};
|
||||
|
||||
struct NoBitsSection : Section {
|
||||
llvm::yaml::Hex64 Size;
|
||||
|
||||
NoBitsSection() : Section(SectionKind::NoBits) {}
|
||||
NoBitsSection() : Section(ChunkKind::NoBits) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::NoBits;
|
||||
}
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::NoBits; }
|
||||
};
|
||||
|
||||
struct NoteSection : Section {
|
||||
@ -235,8 +257,9 @@ struct NoteSection : Section {
|
||||
Optional<llvm::yaml::Hex64> Size;
|
||||
Optional<std::vector<ELFYAML::NoteEntry>> Notes;
|
||||
|
||||
NoteSection() : Section(SectionKind::Note) {}
|
||||
static bool classof(const Section *S) { return S->Kind == SectionKind::Note; }
|
||||
NoteSection() : Section(ChunkKind::Note) {}
|
||||
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Note; }
|
||||
};
|
||||
|
||||
struct HashSection : Section {
|
||||
@ -245,9 +268,9 @@ struct HashSection : Section {
|
||||
Optional<std::vector<uint32_t>> Bucket;
|
||||
Optional<std::vector<uint32_t>> Chain;
|
||||
|
||||
HashSection() : Section(SectionKind::Hash) {}
|
||||
HashSection() : Section(ChunkKind::Hash) {}
|
||||
|
||||
static bool classof(const Section *S) { return S->Kind == SectionKind::Hash; }
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Hash; }
|
||||
};
|
||||
|
||||
struct GnuHashHeader {
|
||||
@ -278,9 +301,9 @@ struct GnuHashSection : Section {
|
||||
Optional<std::vector<llvm::yaml::Hex32>> HashBuckets;
|
||||
Optional<std::vector<llvm::yaml::Hex32>> HashValues;
|
||||
|
||||
GnuHashSection() : Section(SectionKind::GnuHash) {}
|
||||
GnuHashSection() : Section(ChunkKind::GnuHash) {}
|
||||
|
||||
static bool classof(const Section *S) { return S->Kind == SectionKind::GnuHash; }
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::GnuHash; }
|
||||
};
|
||||
|
||||
struct VernauxEntry {
|
||||
@ -300,10 +323,10 @@ struct VerneedSection : Section {
|
||||
std::vector<VerneedEntry> VerneedV;
|
||||
llvm::yaml::Hex64 Info;
|
||||
|
||||
VerneedSection() : Section(SectionKind::Verneed) {}
|
||||
VerneedSection() : Section(ChunkKind::Verneed) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Verneed;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::Verneed;
|
||||
}
|
||||
};
|
||||
|
||||
@ -321,20 +344,17 @@ struct AddrsigSection : Section {
|
||||
Optional<llvm::yaml::Hex64> Size;
|
||||
Optional<std::vector<AddrsigSymbol>> Symbols;
|
||||
|
||||
AddrsigSection() : Section(SectionKind::Addrsig) {}
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Addrsig;
|
||||
}
|
||||
AddrsigSection() : Section(ChunkKind::Addrsig) {}
|
||||
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; }
|
||||
};
|
||||
|
||||
struct SymverSection : Section {
|
||||
std::vector<uint16_t> Entries;
|
||||
|
||||
SymverSection() : Section(SectionKind::Symver) {}
|
||||
SymverSection() : Section(ChunkKind::Symver) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Symver;
|
||||
}
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Symver; }
|
||||
};
|
||||
|
||||
struct VerdefEntry {
|
||||
@ -349,11 +369,9 @@ struct VerdefSection : Section {
|
||||
std::vector<VerdefEntry> Entries;
|
||||
llvm::yaml::Hex64 Info;
|
||||
|
||||
VerdefSection() : Section(SectionKind::Verdef) {}
|
||||
VerdefSection() : Section(ChunkKind::Verdef) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Verdef;
|
||||
}
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Verdef; }
|
||||
};
|
||||
|
||||
struct Group : Section {
|
||||
@ -362,11 +380,9 @@ struct Group : Section {
|
||||
std::vector<SectionOrType> Members;
|
||||
Optional<StringRef> Signature; /* Info */
|
||||
|
||||
Group() : Section(SectionKind::Group) {}
|
||||
Group() : Section(ChunkKind::Group) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Group;
|
||||
}
|
||||
static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Group; }
|
||||
};
|
||||
|
||||
struct Relocation {
|
||||
@ -380,20 +396,20 @@ struct RelocationSection : Section {
|
||||
std::vector<Relocation> Relocations;
|
||||
StringRef RelocatableSec; /* Info */
|
||||
|
||||
RelocationSection() : Section(SectionKind::Relocation) {}
|
||||
RelocationSection() : Section(ChunkKind::Relocation) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::Relocation;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::Relocation;
|
||||
}
|
||||
};
|
||||
|
||||
struct SymtabShndxSection : Section {
|
||||
std::vector<uint32_t> Entries;
|
||||
|
||||
SymtabShndxSection() : Section(SectionKind::SymtabShndxSection) {}
|
||||
SymtabShndxSection() : Section(ChunkKind::SymtabShndxSection) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::SymtabShndxSection;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::SymtabShndxSection;
|
||||
}
|
||||
};
|
||||
|
||||
@ -411,23 +427,35 @@ struct MipsABIFlags : Section {
|
||||
MIPS_AFL_FLAGS1 Flags1;
|
||||
llvm::yaml::Hex32 Flags2;
|
||||
|
||||
MipsABIFlags() : Section(SectionKind::MipsABIFlags) {}
|
||||
MipsABIFlags() : Section(ChunkKind::MipsABIFlags) {}
|
||||
|
||||
static bool classof(const Section *S) {
|
||||
return S->Kind == SectionKind::MipsABIFlags;
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::MipsABIFlags;
|
||||
}
|
||||
};
|
||||
|
||||
struct Object {
|
||||
FileHeader Header;
|
||||
std::vector<ProgramHeader> ProgramHeaders;
|
||||
std::vector<std::unique_ptr<Section>> Sections;
|
||||
|
||||
// An object might contain output section descriptions as well as
|
||||
// custom data that does not belong to any section.
|
||||
std::vector<std::unique_ptr<Chunk>> Chunks;
|
||||
|
||||
// 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
|
||||
// being a single SHT_SYMTAB section are upheld.
|
||||
Optional<std::vector<Symbol>> Symbols;
|
||||
std::vector<Symbol> DynamicSymbols;
|
||||
|
||||
std::vector<Section *> getSections() {
|
||||
std::vector<Section *> Ret;
|
||||
for (const std::unique_ptr<Chunk> &Sec : Chunks)
|
||||
if (auto S = dyn_cast<ELFYAML::Section>(Sec.get()))
|
||||
Ret.push_back(S);
|
||||
return Ret;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace ELFYAML
|
||||
@ -438,7 +466,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Chunk>)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerdefEntry)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VernauxEntry)
|
||||
@ -607,10 +635,9 @@ template <> struct MappingTraits<ELFYAML::Relocation> {
|
||||
static void mapping(IO &IO, ELFYAML::Relocation &Rel);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MappingTraits<std::unique_ptr<ELFYAML::Section>> {
|
||||
static void mapping(IO &IO, std::unique_ptr<ELFYAML::Section> &Section);
|
||||
static StringRef validate(IO &io, std::unique_ptr<ELFYAML::Section> &Section);
|
||||
template <> struct MappingTraits<std::unique_ptr<ELFYAML::Chunk>> {
|
||||
static void mapping(IO &IO, std::unique_ptr<ELFYAML::Chunk> &C);
|
||||
static StringRef validate(IO &io, std::unique_ptr<ELFYAML::Chunk> &C);
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -85,7 +85,8 @@ public:
|
||||
|
||||
/// Write the contents (regardless of whether it is binary or a
|
||||
/// hex string) as binary to the given raw_ostream.
|
||||
void writeAsBinary(raw_ostream &OS) const;
|
||||
/// N can be used to specify the maximum number of bytes.
|
||||
void writeAsBinary(raw_ostream &OS, uint64_t N = UINT64_MAX) const;
|
||||
|
||||
/// Write the contents (regardless of whether it is binary or a
|
||||
/// hex string) as hex to the given raw_ostream.
|
||||
|
@ -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());
|
||||
|
||||
for (size_t I = 0; I < Doc.Sections.size(); ++I) {
|
||||
ELFYAML::Section *Sec = Doc.Sections[I].get();
|
||||
if (I == 0 && Sec->IsImplicit)
|
||||
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;
|
||||
}
|
||||
|
||||
++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)
|
||||
@ -640,23 +665,44 @@ template <class ELFT> void ELFState<ELFT>::reportError(const Twine &Msg) {
|
||||
HasError = true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
ELFYAML::Section::~Section() = default;
|
||||
ELFYAML::Chunk::~Chunk() = default;
|
||||
|
||||
namespace yaml {
|
||||
|
||||
@ -1094,6 +1094,12 @@ static void sectionMapping(IO &IO, ELFYAML::AddrsigSection &Section) {
|
||||
IO.mapOptional("Symbols", Section.Symbols);
|
||||
}
|
||||
|
||||
static void fillMapping(IO &IO, ELFYAML::Fill &Fill) {
|
||||
IO.mapOptional("Name", Fill.Name, StringRef());
|
||||
IO.mapOptional("Pattern", Fill.Pattern);
|
||||
IO.mapRequired("Size", Fill.Size);
|
||||
}
|
||||
|
||||
void MappingTraits<ELFYAML::SectionOrType>::mapping(
|
||||
IO &IO, ELFYAML::SectionOrType §ionOrType) {
|
||||
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
|
||||
@ -1124,15 +1130,27 @@ static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
|
||||
IO.mapOptional("Flags2", Section.Flags2, Hex32(0));
|
||||
}
|
||||
|
||||
void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
|
||||
IO &IO, std::unique_ptr<ELFYAML::Section> &Section) {
|
||||
ELFYAML::ELF_SHT sectionType;
|
||||
if (IO.outputting())
|
||||
sectionType = Section->Type;
|
||||
else
|
||||
IO.mapRequired("Type", sectionType);
|
||||
void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
|
||||
IO &IO, std::unique_ptr<ELFYAML::Chunk> &Section) {
|
||||
ELFYAML::ELF_SHT Type;
|
||||
if (IO.outputting()) {
|
||||
Type = cast<ELFYAML::Section>(Section.get())->Type;
|
||||
} else {
|
||||
// When the Type string does not have a "SHT_" prefix, we know it is not a
|
||||
// description of a regular ELF output section. Currently, we have one
|
||||
// special type named "Fill". See comments for Fill.
|
||||
StringRef StrType;
|
||||
IO.mapRequired("Type", StrType);
|
||||
if (StrType == "Fill") {
|
||||
Section.reset(new ELFYAML::Fill());
|
||||
fillMapping(IO, *cast<ELFYAML::Fill>(Section.get()));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sectionType) {
|
||||
IO.mapRequired("Type", Type);
|
||||
}
|
||||
|
||||
switch (Type) {
|
||||
case ELF::SHT_DYNAMIC:
|
||||
if (!IO.outputting())
|
||||
Section.reset(new ELFYAML::DynamicSection());
|
||||
@ -1218,17 +1236,17 @@ void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
|
||||
}
|
||||
}
|
||||
|
||||
StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
IO &io, std::unique_ptr<ELFYAML::Section> &Section) {
|
||||
StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
|
||||
IO &io, std::unique_ptr<ELFYAML::Chunk> &C) {
|
||||
if (const auto *RawSection =
|
||||
dyn_cast<ELFYAML::RawContentSection>(Section.get())) {
|
||||
dyn_cast<ELFYAML::RawContentSection>(C.get())) {
|
||||
if (RawSection->Size && RawSection->Content &&
|
||||
(uint64_t)(*RawSection->Size) < RawSection->Content->binary_size())
|
||||
return "Section size must be greater than or equal to the content size";
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *SS = dyn_cast<ELFYAML::StackSizesSection>(Section.get())) {
|
||||
if (const auto *SS = dyn_cast<ELFYAML::StackSizesSection>(C.get())) {
|
||||
if (!SS->Entries && !SS->Content && !SS->Size)
|
||||
return ".stack_sizes: one of Content, Entries and Size must be specified";
|
||||
|
||||
@ -1248,7 +1266,7 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *HS = dyn_cast<ELFYAML::HashSection>(Section.get())) {
|
||||
if (const auto *HS = dyn_cast<ELFYAML::HashSection>(C.get())) {
|
||||
if (!HS->Content && !HS->Bucket && !HS->Chain && !HS->Size)
|
||||
return "one of \"Content\", \"Size\", \"Bucket\" or \"Chain\" must be "
|
||||
"specified";
|
||||
@ -1271,7 +1289,7 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *Sec = dyn_cast<ELFYAML::AddrsigSection>(Section.get())) {
|
||||
if (const auto *Sec = dyn_cast<ELFYAML::AddrsigSection>(C.get())) {
|
||||
if (!Sec->Symbols && !Sec->Content && !Sec->Size)
|
||||
return "one of \"Content\", \"Size\" or \"Symbols\" must be specified";
|
||||
|
||||
@ -1296,7 +1314,7 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *NS = dyn_cast<ELFYAML::NoteSection>(Section.get())) {
|
||||
if (const auto *NS = dyn_cast<ELFYAML::NoteSection>(C.get())) {
|
||||
if (!NS->Content && !NS->Size && !NS->Notes)
|
||||
return "one of \"Content\", \"Size\" or \"Notes\" must be "
|
||||
"specified";
|
||||
@ -1314,7 +1332,7 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *Sec = dyn_cast<ELFYAML::GnuHashSection>(Section.get())) {
|
||||
if (const auto *Sec = dyn_cast<ELFYAML::GnuHashSection>(C.get())) {
|
||||
if (!Sec->Content && !Sec->Header && !Sec->BloomFilter &&
|
||||
!Sec->HashBuckets && !Sec->HashValues)
|
||||
return "either \"Content\" or \"Header\", \"BloomFilter\", "
|
||||
@ -1337,6 +1355,14 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
|
||||
return {};
|
||||
}
|
||||
|
||||
if (const auto *F = dyn_cast<ELFYAML::Fill>(C.get())) {
|
||||
if (!F->Pattern)
|
||||
return {};
|
||||
if (F->Pattern->binary_size() != 0 && !F->Size)
|
||||
return "\"Size\" can't be 0 when \"Pattern\" is not empty";
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -1455,7 +1481,7 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
|
||||
IO.mapTag("!ELF", true);
|
||||
IO.mapRequired("FileHeader", Object.Header);
|
||||
IO.mapOptional("ProgramHeaders", Object.ProgramHeaders);
|
||||
IO.mapOptional("Sections", Object.Sections);
|
||||
IO.mapOptional("Sections", Object.Chunks);
|
||||
IO.mapOptional("Symbols", Object.Symbols);
|
||||
IO.mapOptional("DynamicSymbols", Object.DynamicSymbols);
|
||||
IO.setContext(nullptr);
|
||||
|
@ -37,15 +37,16 @@ StringRef yaml::ScalarTraits<yaml::BinaryRef>::input(StringRef Scalar, void *,
|
||||
return {};
|
||||
}
|
||||
|
||||
void yaml::BinaryRef::writeAsBinary(raw_ostream &OS) const {
|
||||
void yaml::BinaryRef::writeAsBinary(raw_ostream &OS, uint64_t N) const {
|
||||
if (!DataIsHexString) {
|
||||
OS.write((const char *)Data.data(), Data.size());
|
||||
OS.write((const char *)Data.data(), std::min(N, Data.size()));
|
||||
return;
|
||||
}
|
||||
for (unsigned I = 0, N = Data.size(); I != N; I += 2) {
|
||||
uint8_t Byte = llvm::hexDigitValue(Data[I]);
|
||||
|
||||
for (uint64_t I = 0, E = std::min(N, Data.size() / 2); I != E; ++I) {
|
||||
uint8_t Byte = llvm::hexDigitValue(Data[I * 2]);
|
||||
Byte <<= 4;
|
||||
Byte |= llvm::hexDigitValue(Data[I + 1]);
|
||||
Byte |= llvm::hexDigitValue(Data[I * 2 + 1]);
|
||||
OS.write(Byte);
|
||||
}
|
||||
}
|
||||
|
298
test/tools/yaml2obj/custom-fill.yaml
Normal file
298
test/tools/yaml2obj/custom-fill.yaml
Normal file
@ -0,0 +1,298 @@
|
||||
## Here we check that we are able to define sections with a type of "Fill".
|
||||
## Fills are custom pieces of data that can be placed anywhere just like normal
|
||||
## output sections, but they are not real output sections and you'll never see them in
|
||||
## the section headers.
|
||||
|
||||
## Check we can create named and unnamed fills and use "Pattern" and "Size" fields
|
||||
## to describe the data emitted.
|
||||
## Check the data emitted and how it affects regular sections offsets.
|
||||
## Check that the "Name" field is optional for fills.
|
||||
## Check that "Size" can be greater than or equal to the pattern data size.
|
||||
|
||||
# RUN: yaml2obj --docnum=1 %s -o %t1
|
||||
# RUN: llvm-readelf --sections --headers %t1 | FileCheck %s --check-prefix=BASIC
|
||||
|
||||
# BASIC: Number of section headers: 5
|
||||
# BASIC: Section Headers:
|
||||
# BASIC-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
|
||||
# BASIC-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
|
||||
# BASIC-NEXT: [ 1] .foo PROGBITS 0000000000000000 000043 000002 00 0 0 0
|
||||
# BASIC-NEXT: [ 2] .bar PROGBITS 0000000000000000 000049 000001 00 0 0 0
|
||||
# BASIC-NEXT: [ 3] .strtab STRTAB 0000000000000000 00004b 000001 00 0 0 1
|
||||
# BASIC-NEXT: [ 4] .shstrtab STRTAB 0000000000000000 00004c 00001d 00 0 0 1
|
||||
|
||||
## The fill we dump starts at (offset of .foo - 3), which is (0x43 - 3) = 0x40.
|
||||
# RUN: od -t x1 -v -j 0x40 -N 11 %t1 | FileCheck %s --ignore-case --check-prefix=DATA
|
||||
# DATA: aa bb aa 11 22 cc dd cc dd ff ee
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: "AABB"
|
||||
Size: 0x3
|
||||
- Name: .foo
|
||||
Type: SHT_PROGBITS
|
||||
Content: "1122"
|
||||
- Type: Fill
|
||||
Name: unusedName
|
||||
Pattern: "CCDD"
|
||||
Size: 4
|
||||
- Name: .bar
|
||||
Type: SHT_PROGBITS
|
||||
Content: "FF"
|
||||
- Type: Fill
|
||||
Pattern: "EE"
|
||||
Size: 1
|
||||
|
||||
## Check we can have no explicit regular sections in the YAML description, and can
|
||||
## describe the content with the use of fills only.
|
||||
## Check that "Size" can be less than the pattern data size.
|
||||
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t2
|
||||
# RUN: llvm-readelf --sections --headers %t2 | FileCheck %s --check-prefix=NOSECTIONS
|
||||
|
||||
## The fill we dump starts at (offset of .strtab - 3 - 2), which is (0x45 - 5) = 0x40.
|
||||
# RUN: od -t x1 -v -j 0x40 -N 6 %t2 | FileCheck %s --ignore-case --check-prefix=NOSECTIONS-DATA
|
||||
|
||||
# NOSECTIONS: Number of section headers: 3
|
||||
# NOSECTIONS: Section Headers:
|
||||
# NOSECTIONS-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
|
||||
# NOSECTIONS-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
|
||||
# NOSECTIONS-NEXT: [ 1] .strtab STRTAB 0000000000000000 000045 000001 00 0 0 1
|
||||
# NOSECTIONS-NEXT: [ 2] .shstrtab STRTAB 0000000000000000 000046 000013 00 0 0 1
|
||||
|
||||
## .strtab that follows fills starts at 0x46 and always has a null character at the begining.
|
||||
# NOSECTIONS-DATA: aa bb cc dd ee 00
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: "AABBCCFF"
|
||||
Size: 0x3
|
||||
- Type: Fill
|
||||
Pattern: "DDEEFF"
|
||||
Size: 0x2
|
||||
|
||||
## Check we can use named fills when describing program headers.
|
||||
## Check that fills consume the file size and therefore affect the p_filesz fields of segments.
|
||||
## Check that the fill does not affect the p_align field of the segment.
|
||||
|
||||
# RUN: yaml2obj --docnum=3 %s -o %t3
|
||||
# RUN: llvm-readelf --sections --program-headers %t3 | FileCheck %s --check-prefix=PHDR
|
||||
|
||||
# PHDR: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
|
||||
# PHDR: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
|
||||
# PHDR: [ 1] .bar PROGBITS 0000000000000100 0000c0 000005 00 0 0 2
|
||||
# PHDR: [ 2] .strtab STRTAB 0000000000000000 00010a 000001 00 0 0 1
|
||||
# PHDR: [ 3] .shstrtab STRTAB 0000000000000000 00010b 000018 00 0 0 1
|
||||
|
||||
# PHDR: Program Headers:
|
||||
# PHDR: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
|
||||
# PHDR: LOAD 0x0000b0 0x0000000000000100 0x0000000000000100 0x00005a 0x00005a 0x2
|
||||
# PHDR: GNU_RELRO 0x0000c5 0x0000000000000105 0x0000000000000105 0x000045 0x000045 0x1
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Name: fill1
|
||||
Pattern: ""
|
||||
Size: 0x10
|
||||
- Name: .bar
|
||||
Type: SHT_PROGBITS
|
||||
Size: 0x5
|
||||
Address: 0x100
|
||||
AddressAlign: 2
|
||||
- Type: Fill
|
||||
Name: fill2
|
||||
Pattern: ""
|
||||
Size: 0x45
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
VAddr: 0x100
|
||||
PAddr: 0x100
|
||||
Sections:
|
||||
- Section: fill1
|
||||
- Section: .bar
|
||||
- Section: fill2
|
||||
- Type: PT_GNU_RELRO
|
||||
VAddr: 0x105
|
||||
PAddr: 0x105
|
||||
Sections:
|
||||
- Section: fill2
|
||||
|
||||
## Check that the "Pattern" field is not mandatory.
|
||||
# RUN: yaml2obj --docnum=4 2>&1 -o %t4 %s
|
||||
# RUN: llvm-readelf --sections %t4 | FileCheck %s --check-prefix=NOPATTERN
|
||||
|
||||
## The fill we dump starts at (offset of .strtab - 1 - 3 - 1), which is (0x45 - 5) = 0x40.
|
||||
# RUN: od -t x1 -v -j 0x40 -N 5 %t4 | FileCheck %s --ignore-case --check-prefix=NOPATTERN-DATA
|
||||
|
||||
# NOPATTERN: [Nr] Name Type Address Off
|
||||
# NOPATTERN: [ 1] .strtab STRTAB 0000000000000000 000045
|
||||
|
||||
# NOPATTERN-DATA: aa 00 00 00 bb
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Size: 0x1
|
||||
Pattern: "AA"
|
||||
- Type: Fill
|
||||
Size: 0x3
|
||||
- Type: Fill
|
||||
Size: 0x1
|
||||
Pattern: "BB"
|
||||
|
||||
## Check that the "Size" field is mandatory.
|
||||
# RUN: not yaml2obj --docnum=5 2>&1 %s | FileCheck %s --check-prefix=NOSIZE
|
||||
|
||||
## NOSIZE: error: missing required key 'Size'
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: "00"
|
||||
|
||||
## Check that fills are not allowed to have duplicate names.
|
||||
# RUN: not yaml2obj --docnum=6 2>&1 %s | FileCheck %s --check-prefix=UNIQUE-NAME
|
||||
|
||||
# UNIQUE-NAME: error: repeated section/fill name: 'foo' at YAML section/fill number 2
|
||||
# UNIQUE-NAME: error: repeated section/fill name: 'foo' at YAML section/fill number 3
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Name: foo
|
||||
Pattern: "00"
|
||||
Size: 1
|
||||
- Type: Fill
|
||||
Name: foo
|
||||
Pattern: "00"
|
||||
Size: 1
|
||||
- Name: foo
|
||||
Type: SHT_PROGBITS
|
||||
|
||||
## Check that "Pattern" can be empty, when "Size" is zero.
|
||||
# RUN: yaml2obj --docnum=7 2>&1 %s -o %t7
|
||||
# RUN: llvm-readelf --sections %t7 | FileCheck %s --check-prefix=NOOP
|
||||
|
||||
# NOOP: [Nr] Name Type Address Off
|
||||
# NOOP: [ 1] begin PROGBITS 0000000000000000 000040
|
||||
# NOOP: [ 2] end PROGBITS 0000000000000000 000041
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: begin
|
||||
Type: SHT_PROGBITS
|
||||
Size: 1
|
||||
- Type: Fill
|
||||
Pattern: ""
|
||||
Size: 0
|
||||
- Name: end
|
||||
Type: SHT_PROGBITS
|
||||
Size: 1
|
||||
|
||||
## Check that we can have an empty "Pattern", but have non-zero "Size".
|
||||
## In this case we emit Size number of zeroes to the output.
|
||||
|
||||
# RUN: yaml2obj --docnum=8 2>&1 -o %t8 %s
|
||||
# RUN: llvm-readelf --sections %t8 | FileCheck %s --check-prefix=EMPTY-PATTERN
|
||||
|
||||
## The fill we dump starts at (offset of .strtab - 1 - 3 - 1), which is (0x45 - 5) = 0x40.
|
||||
# RUN: od -t x1 -v -j 0x40 -N 5 %t8 | FileCheck %s --ignore-case --check-prefix=EMPTY-PATTERN-DATA
|
||||
|
||||
# EMPTY-PATTERN: Section Headers:
|
||||
# EMPTY-PATTERN-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
|
||||
# EMPTY-PATTERN-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
|
||||
# EMPTY-PATTERN-NEXT: [ 1] .strtab STRTAB 0000000000000000 000045 000001 00 0 0 1
|
||||
|
||||
# EMPTY-PATTERN-DATA: aa 00 00 00 bb
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: "AA"
|
||||
Size: 0x1
|
||||
- Type: Fill
|
||||
Size: 3
|
||||
Pattern: ""
|
||||
- Type: Fill
|
||||
Pattern: "BB"
|
||||
Size: 0x1
|
||||
|
||||
## Check that "Size" can't be 0, when "Pattern" is not empty.
|
||||
# RUN: not yaml2obj --docnum=9 2>&1 %s | FileCheck %s --check-prefix=ZERO-SIZE-ERR
|
||||
|
||||
# ZERO-SIZE-ERR: error: "Size" can't be 0 when "Pattern" is not empty
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: "00"
|
||||
Size: 0
|
||||
|
||||
## Check we report an error when a program header references
|
||||
## an unknown section or fill and have at least one Fill defined.
|
||||
|
||||
# RUN: not yaml2obj --docnum=10 2>&1 %s | FileCheck %s --check-prefix=UNKNOWN-ERR
|
||||
# UNKNOWN-ERR: error: unknown section or fill referenced: 'fill' by program header
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Type: Fill
|
||||
Pattern: ""
|
||||
Size: 0
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
Sections:
|
||||
- Section: fill
|
@ -29,8 +29,8 @@ Sections:
|
||||
## sections with equal names and suffixes.
|
||||
|
||||
# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=CASE2
|
||||
# CASE2: error: repeated section name: '.foo [1]' at YAML section number 2
|
||||
# CASE2: error: repeated section name: '.foo [1]' at YAML section number 3
|
||||
# CASE2: error: repeated section/fill name: '.foo [1]' at YAML section/fill number 2
|
||||
# CASE2: error: repeated section/fill name: '.foo [1]' at YAML section/fill number 3
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
@ -51,7 +51,7 @@ Sections:
|
||||
## names are equal.
|
||||
|
||||
# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=CASE3
|
||||
# CASE3: error: repeated section name: '.foo' at YAML section number 2
|
||||
# CASE3: error: repeated section/fill name: '.foo' at YAML section/fill number 2
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
|
@ -81,8 +81,8 @@ ProgramHeaders:
|
||||
## Check we do not allow referencing sections that do not exist.
|
||||
# RUN: not yaml2obj --docnum=2 %s -o %t 2>&1 | FileCheck %s --check-prefix=ERR
|
||||
|
||||
# ERR: error: unknown section referenced: '.foo' by program header
|
||||
# ERR: error: unknown section referenced: '.bar' by program header
|
||||
# ERR: error: unknown section or fill referenced: '.foo' by program header
|
||||
# ERR: error: unknown section or fill referenced: '.bar' by program header
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
|
@ -78,7 +78,7 @@ class ELFDumper {
|
||||
Expected<ELFYAML::StackSizesSection *>
|
||||
dumpStackSizesSection(const Elf_Shdr *Shdr);
|
||||
|
||||
Expected<ELFYAML::Section *> dumpSpecialSection(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::Chunk *> dumpSpecialSection(const Elf_Shdr *Shdr);
|
||||
|
||||
public:
|
||||
ELFDumper(const object::ELFFile<ELFT> &O);
|
||||
@ -221,7 +221,7 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
|
||||
Expected<ELFYAML::DynamicSection *> SecOrErr = dumpDynamicSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_STRTAB:
|
||||
@ -234,7 +234,7 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
|
||||
dumpSymtabShndxSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_REL:
|
||||
@ -242,77 +242,77 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
|
||||
Expected<ELFYAML::RelocationSection *> SecOrErr = dumpRelocSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_GROUP: {
|
||||
Expected<ELFYAML::Group *> GroupOrErr = dumpGroup(&Sec);
|
||||
if (!GroupOrErr)
|
||||
return GroupOrErr.takeError();
|
||||
Y->Sections.emplace_back(*GroupOrErr);
|
||||
Y->Chunks.emplace_back(*GroupOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_MIPS_ABIFLAGS: {
|
||||
Expected<ELFYAML::MipsABIFlags *> SecOrErr = dumpMipsABIFlags(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_NOBITS: {
|
||||
Expected<ELFYAML::NoBitsSection *> SecOrErr = dumpNoBitsSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_NOTE: {
|
||||
Expected<ELFYAML::NoteSection *> SecOrErr = dumpNoteSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_HASH: {
|
||||
Expected<ELFYAML::HashSection *> SecOrErr = dumpHashSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_GNU_HASH: {
|
||||
Expected<ELFYAML::GnuHashSection *> SecOrErr = dumpGnuHashSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_GNU_verdef: {
|
||||
Expected<ELFYAML::VerdefSection *> SecOrErr = dumpVerdefSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_GNU_versym: {
|
||||
Expected<ELFYAML::SymverSection *> SecOrErr = dumpSymverSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_GNU_verneed: {
|
||||
Expected<ELFYAML::VerneedSection *> SecOrErr = dumpVerneedSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_LLVM_ADDRSIG: {
|
||||
Expected<ELFYAML::AddrsigSection *> SecOrErr = dumpAddrsigSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_NULL: {
|
||||
@ -330,11 +330,11 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
|
||||
default: {
|
||||
// Recognize some special SHT_PROGBITS sections by name.
|
||||
if (Sec.sh_type == ELF::SHT_PROGBITS) {
|
||||
Expected<ELFYAML::Section *> SpecialSecOrErr = dumpSpecialSection(&Sec);
|
||||
Expected<ELFYAML::Chunk *> SpecialSecOrErr = dumpSpecialSection(&Sec);
|
||||
if (!SpecialSecOrErr)
|
||||
return SpecialSecOrErr.takeError();
|
||||
if (*SpecialSecOrErr) {
|
||||
Y->Sections.emplace_back(*SpecialSecOrErr);
|
||||
Y->Chunks.emplace_back(*SpecialSecOrErr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -343,7 +343,7 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
|
||||
dumpContentSection(&Sec);
|
||||
if (!SecOrErr)
|
||||
return SecOrErr.takeError();
|
||||
Y->Sections.emplace_back(*SecOrErr);
|
||||
Y->Chunks.emplace_back(*SecOrErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -486,7 +486,7 @@ Error ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr,
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Expected<ELFYAML::Section *>
|
||||
Expected<ELFYAML::Chunk *>
|
||||
ELFDumper<ELFT>::dumpSpecialSection(const Elf_Shdr *Shdr) {
|
||||
auto NameOrErr = getUniquedSectionName(Shdr);
|
||||
if (!NameOrErr)
|
||||
|
Loading…
Reference in New Issue
Block a user