Skip to content

Commit

Permalink
[yaml2obj] - Allow setting st_value explicitly for Symbol.
Browse files Browse the repository at this point in the history
In some cases it is useful to explicitly set symbol's st_name value.
For example, I am using it in a patch for LLD to remove the broken
binary from a test case and replace it with a YAML test.

Differential revision: https://reviews.llvm.org/D61180

llvm-svn: 360137
  • Loading branch information
George Rimar authored and MrSidims committed May 24, 2019
1 parent 87c262a commit 26b8968
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 50 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/ObjectYAML/ELFYAML.h
Expand Up @@ -95,6 +95,7 @@ struct ProgramHeader {

struct Symbol {
StringRef Name;
Optional<uint32_t> NameIndex;
ELF_STT Type;
StringRef Section;
Optional<ELF_SHN> Index;
Expand Down
9 changes: 5 additions & 4 deletions llvm/lib/ObjectYAML/ELFYAML.cpp
Expand Up @@ -854,6 +854,7 @@ struct NormalizedOther {

void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {
IO.mapOptional("Name", Symbol.Name, StringRef());
IO.mapOptional("NameIndex", Symbol.NameIndex);
IO.mapOptional("Type", Symbol.Type, ELFYAML::ELF_STT(0));
IO.mapOptional("Section", Symbol.Section, StringRef());
IO.mapOptional("Index", Symbol.Index);
Expand All @@ -867,12 +868,12 @@ void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {

StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
ELFYAML::Symbol &Symbol) {
if (Symbol.Index && Symbol.Section.data()) {
if (Symbol.Index && Symbol.Section.data())
return "Index and Section cannot both be specified for Symbol";
}
if (Symbol.Index && *Symbol.Index == ELFYAML::ELF_SHN(ELF::SHN_XINDEX)) {
if (Symbol.Index && *Symbol.Index == ELFYAML::ELF_SHN(ELF::SHN_XINDEX))
return "Large indexes are not supported";
}
if (Symbol.NameIndex && !Symbol.Name.empty())
return "Name and NameIndex cannot both be specified for Symbol";
return StringRef();
}

Expand Down
37 changes: 37 additions & 0 deletions llvm/test/tools/yaml2obj/symbol-name.yaml
@@ -0,0 +1,37 @@
## Check we are able to use integers as both
## symbol name indices (st_name values) and symbol names.
# RUN: yaml2obj --docnum=1 %s > %t
# RUN: llvm-readobj --symbols %t | FileCheck %s

# CHECK: Name: test (1)
# CHECK: Name: test (1)
# CHECK: Name: est (2)
# CHECK: Name: 1 (8)
# CHECK: Name: 2 (6)

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Symbols:
- Name: test
- NameIndex: 1
- NameIndex: 2
- Name: 1
- Name: 2

## Check we do not allow specifying both Name and NameIndex at once.
# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=ERR
# ERR: error: Name and NameIndex cannot both be specified for Symbol

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Symbols:
- Name: foo
NameIndex: 0
99 changes: 53 additions & 46 deletions llvm/tools/yaml2obj/yaml2elf.cpp
Expand Up @@ -57,34 +57,34 @@ class ContiguousBlobAccumulator {
} // end anonymous namespace

// Used to keep track of section and symbol names, so that in the YAML file
// sections and symbols can be referenced by name instead of by index.
namespace {
class NameToIdxMap {
// sections and symbols can be referenced by name instead of by index.
namespace {
class NameToIdxMap {
StringMap<unsigned> Map;

public:
public:
/// \Returns false if name is already present in the map.
bool addName(StringRef Name, unsigned Ndx) {
return Map.insert({Name, Ndx}).second;
}
}
/// \Returns false if name is not present in the map.
bool lookup(StringRef Name, unsigned &Idx) const {
bool lookup(StringRef Name, unsigned &Idx) const {
auto I = Map.find(Name);
if (I == Map.end())
if (I == Map.end())
return false;
Idx = I->getValue();
Idx = I->getValue();
return true;
}
}
/// Asserts if name is not present in the map.
unsigned get(StringRef Name) const {
unsigned get(StringRef Name) const {
unsigned Idx;
if (lookup(Name, Idx))
return Idx;
assert(false && "Expected section not found in index");
return 0;
}
unsigned size() const { return Map.size(); }
};
}
unsigned size() const { return Map.size(); }
};
} // end anonymous namespace

template <class T>
Expand Down Expand Up @@ -236,13 +236,13 @@ void ELFState<ELFT>::initProgramHeaders(std::vector<Elf_Phdr> &PHeaders) {
PHeaders.push_back(Phdr);
}
}

static bool convertSectionIndex(NameToIdxMap &SN2I, StringRef SecName,
StringRef IndexSrc, unsigned &IndexDest) {

static bool convertSectionIndex(NameToIdxMap &SN2I, StringRef SecName,
StringRef IndexSrc, unsigned &IndexDest) {
if (!SN2I.lookup(IndexSrc, IndexDest) && !to_integer(IndexSrc, IndexDest)) {
WithColor::error() << "Unknown section referenced: '" << IndexSrc
<< "' at YAML section '" << SecName << "'.\n";
return false;
WithColor::error() << "Unknown section referenced: '" << IndexSrc
<< "' at YAML section '" << SecName << "'.\n";
return false;
}
return true;
}
Expand Down Expand Up @@ -468,15 +468,22 @@ void ELFState<ELFT>::addSymbols(ArrayRef<ELFYAML::Symbol> Symbols,
for (const auto &Sym : Symbols) {
Elf_Sym Symbol;
zero(Symbol);
if (!Sym.Name.empty())

// If NameIndex, which contains the name offset, is explicitly specified, we
// use it. This is useful for preparing broken objects. Otherwise, we add
// the specified Name to the string table builder to get its offset.
if (Sym.NameIndex)
Symbol.st_name = *Sym.NameIndex;
else if (!Sym.Name.empty())
Symbol.st_name = Strtab.getOffset(Sym.Name);
Symbol.setBindingAndType(Sym.Binding, Sym.Type);
if (!Sym.Section.empty()) {
unsigned Index;

Symbol.setBindingAndType(Sym.Binding, Sym.Type);
if (!Sym.Section.empty()) {
unsigned Index;
if (!SN2I.lookup(Sym.Section, Index)) {
WithColor::error() << "Unknown section referenced: '" << Sym.Section
<< "' by YAML symbol " << Sym.Name << ".\n";
exit(1);
WithColor::error() << "Unknown section referenced: '" << Sym.Section
<< "' by YAML symbol " << Sym.Name << ".\n";
exit(1);
}
Symbol.st_shndx = Index;
} else if (Sym.Index) {
Expand Down Expand Up @@ -544,13 +551,13 @@ ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);

for (const auto &Rel : Section.Relocations) {
unsigned SymIdx = 0;
// If a relocation references a symbol, try to look one up in the symbol
// table. If it is not there, treat the value as a symbol index.
unsigned SymIdx = 0;
// If a relocation references a symbol, try to look one up in the symbol
// table. If it is not there, treat the value as a symbol index.
if (Rel.Symbol && !SymN2I.lookup(*Rel.Symbol, SymIdx) &&
!to_integer(*Rel.Symbol, SymIdx)) {
WithColor::error() << "Unknown symbol referenced: '" << *Rel.Symbol
<< "' at YAML section '" << Section.Name << "'.\n";
!to_integer(*Rel.Symbol, SymIdx)) {
WithColor::error() << "Unknown symbol referenced: '" << *Rel.Symbol
<< "' at YAML section '" << Section.Name << "'.\n";
return false;
}

Expand Down Expand Up @@ -580,8 +587,8 @@ bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
"Section type is not SHT_GROUP");

SHeader.sh_entsize = 4;
SHeader.sh_size = SHeader.sh_entsize * Section.Members.size();

SHeader.sh_size = SHeader.sh_entsize * Section.Members.size();

unsigned SymIdx;
if (!SymN2I.lookup(Section.Signature, SymIdx) &&
!to_integer(Section.Signature, SymIdx)) {
Expand Down Expand Up @@ -781,13 +788,13 @@ bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,

template <class ELFT> bool ELFState<ELFT>::buildSectionIndex() {
for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) {
StringRef Name = Doc.Sections[i]->Name;
DotShStrtab.add(Name);
// "+ 1" to take into account the SHT_NULL entry.
StringRef Name = Doc.Sections[i]->Name;
DotShStrtab.add(Name);
// "+ 1" to take into account the SHT_NULL entry.
if (!SN2I.addName(Name, i + 1)) {
WithColor::error() << "Repeated section name: '" << Name
<< "' at YAML section number " << i << ".\n";
return false;
WithColor::error() << "Repeated section name: '" << Name
<< "' at YAML section number " << i << ".\n";
return false;
}
}

Expand Down Expand Up @@ -817,13 +824,13 @@ bool ELFState<ELFT>::buildSymbolIndex(ArrayRef<ELFYAML::Symbol> Symbols) {
"' after global in Symbols list.\n";
return false;
}
if (Sym.Binding.value != ELF::STB_LOCAL)
GlobalSymbolSeen = true;

if (Sym.Binding.value != ELF::STB_LOCAL)
GlobalSymbolSeen = true;

if (!Name.empty() && !SymN2I.addName(Name, I)) {
WithColor::error() << "Repeated symbol name: '" << Name << "'.\n";
return false;
}
WithColor::error() << "Repeated symbol name: '" << Name << "'.\n";
return false;
}
}
return true;
}
Expand Down

0 comments on commit 26b8968

Please sign in to comment.