[lld][ELF] split ELF reader into multiple functions for readability (no change in functionality)

llvm-svn: 181288
This commit is contained in:
Shankar Easwaran 2013-05-07 04:58:09 +00:00
parent 43e77733c2
commit 790ede43de
1 changed files with 190 additions and 114 deletions

View File

@ -121,14 +121,13 @@ public:
ELFFile(const ELFTargetInfo &ti, std::unique_ptr<llvm::MemoryBuffer> MB,
llvm::error_code &EC)
: File(MB->getBufferIdentifier(), kindObject), _elfTargetInfo(ti) {
: File(MB->getBufferIdentifier(), kindObject), _elfTargetInfo(ti),
_doStringsMerge(false) {
llvm::OwningPtr<llvm::object::Binary> binaryFile;
EC = createBinary(MB.release(), binaryFile);
if (EC)
return;
int ordinal = 0;
// Point Obj to correct class and bitwidth ELF object
_objFile.reset(
llvm::dyn_cast<llvm::object::ELFObjectFile<ELFT> >(binaryFile.get()));
@ -140,13 +139,32 @@ public:
binaryFile.take();
std::map<const Elf_Shdr *, std::vector<const Elf_Sym *> > sectionSymbols;
_doStringsMerge = _elfTargetInfo.mergeCommonStrings();
// Sections that have merge string property
std::vector<const Elf_Shdr *> mergeStringSections;
// Read input sections from the input file
// that need to be converted to
// atoms
if (createAtomizableSections(EC))
return;
bool doStringsMerge = _elfTargetInfo.mergeCommonStrings();
// For mergeable strings, we would need to split the section
// into various atoms
if (createMergeableAtoms(EC))
return;
// Create the necessary symbols that are part of the section
// that we created in createAtomizableSections function
if (createSymbolsFromAtomizableSections(EC))
return;
// Create the appropriate atoms fom the file
if (createAtoms(EC))
return;
}
/// \brief Read input sections and populate necessary data structures
/// to read them later and create atoms
bool createAtomizableSections(llvm::error_code &EC) {
// Handle: SHT_REL and SHT_RELA sections:
// Increment over the sections, when REL/RELA section types are found add
// the contents to the RelocationReferences map.
@ -156,41 +174,26 @@ public:
uint64_t totalRelocs = 0;
for (; sit != sie; sit.increment(EC)) {
if (EC)
return;
return true;
const Elf_Shdr *section = _objFile->getElfSection(sit);
switch (section->sh_type) {
case llvm::ELF::SHT_NOTE:
case llvm::ELF::SHT_STRTAB:
case llvm::ELF::SHT_SYMTAB:
case llvm::ELF::SHT_SYMTAB_SHNDX:
continue;
}
if (section->sh_size == 0)
if (isIgnoredSection(section))
continue;
if (doStringsMerge) {
int64_t sectionFlags = section->sh_flags;
sectionFlags &= ~llvm::ELF::SHF_ALLOC;
// If the section have mergeable strings, the linker would
// need to split the section into multiple atoms and mark them
// mergeByContent
if ((section->sh_entsize < 2) &&
(sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
mergeStringSections.push_back(section);
continue;
}
if (isMergeableSection(section)) {
_mergeStringSections.push_back(section);
continue;
}
// Create a sectionSymbols entry for every progbits section.
if (section->sh_type == llvm::ELF::SHT_PROGBITS)
sectionSymbols[section];
_sectionSymbols[section];
if (section->sh_type == llvm::ELF::SHT_RELA) {
StringRef sectionName;
if ((EC = _objFile->getSectionName(section, sectionName)))
return;
return true;
// Get rid of the leading .rela so Atoms can use their own section
// name to find the relocs.
sectionName = sectionName.drop_front(5);
@ -198,14 +201,14 @@ public:
auto rai(_objFile->beginELFRela(section));
auto rae(_objFile->endELFRela(section));
_relocationAddendRefences[sectionName] = make_range(rai, rae);
_relocationAddendReferences[sectionName] = make_range(rai, rae);
totalRelocs += std::distance(rai, rae);
}
if (section->sh_type == llvm::ELF::SHT_REL) {
StringRef sectionName;
if ((EC = _objFile->getSectionName(section, sectionName)))
return;
return true;
// Get rid of the leading .rel so Atoms can use their own section
// name to find the relocs.
sectionName = sectionName.drop_front(4);
@ -218,20 +221,26 @@ public:
}
}
_references.reserve(totalRelocs);
return false;
}
/// \brief Create mergeable atoms from sections that have the merge attribute
/// set
bool createMergeableAtoms(llvm::error_code &EC) {
// Divide the section that contains mergeable strings into tokens
// TODO
// a) add resolver support to recognize multibyte chars
// b) Create a seperate section chunk to write mergeable atoms
std::vector<MergeString *> tokens;
for (auto msi : mergeStringSections) {
for (auto msi : _mergeStringSections) {
StringRef sectionContents;
StringRef sectionName;
if ((EC = _objFile->getSectionName(msi, sectionName)))
return;
return true;
if ((EC = _objFile->getSectionContents(msi, sectionContents)))
return;
return true;
unsigned int prev = 0;
for (std::size_t i = 0, e = sectionContents.size(); i != e; ++i) {
@ -255,6 +264,15 @@ public:
_definedAtoms._atoms.push_back(mergeAtom);
_mergeAtoms.push_back(mergeAtom);
}
return false;
}
/// \brief Add the symbols that the sections contain. The symbols will be
/// converted to atoms for
/// Undefined symbols, absolute symbols
bool createSymbolsFromAtomizableSections(llvm::error_code &EC) {
llvm::object::section_iterator sit(_objFile->begin_sections());
llvm::object::section_iterator sie(_objFile->end_sections());
// Increment over all the symbols collecting atoms and symbol names for
// later use.
@ -263,17 +281,17 @@ public:
for (; it != ie; it.increment(EC)) {
if (EC)
return;
return true;
if ((EC = it->getSection(sit)))
return;
return true;
const Elf_Shdr *section = _objFile->getElfSection(sit);
const Elf_Sym *symbol = _objFile->getElfSymbol(it);
StringRef symbolName;
if ((EC = _objFile->getSymbolName(section, symbol, symbolName)))
return;
return true;
if (symbol->st_shndx == llvm::ELF::SHN_ABS) {
// Create an absolute atom.
@ -292,25 +310,38 @@ public:
} else {
// This is actually a defined symbol. Add it to its section's list of
// symbols.
if (symbol->getType() == llvm::ELF::STT_NOTYPE || symbol->getType() ==
llvm::ELF::STT_OBJECT || symbol->getType() == llvm::ELF::STT_FUNC ||
if (symbol->getType() == llvm::ELF::STT_NOTYPE ||
symbol->getType() == llvm::ELF::STT_OBJECT ||
symbol->getType() == llvm::ELF::STT_FUNC ||
symbol->getType() == llvm::ELF::STT_GNU_IFUNC ||
symbol->getType() == llvm::ELF::STT_SECTION || symbol->getType() ==
llvm::ELF::STT_FILE || symbol->getType() == llvm::ELF::STT_TLS ||
symbol->getType() == llvm::ELF::STT_SECTION ||
symbol->getType() == llvm::ELF::STT_FILE ||
symbol->getType() == llvm::ELF::STT_TLS ||
symbol->getType() == llvm::ELF::STT_COMMON ||
symbol->st_shndx == llvm::ELF::SHN_COMMON) {
sectionSymbols[section].push_back(symbol);
_sectionSymbols[section].push_back(symbol);
} else {
llvm::errs() << "Unable to create atom for: " << symbolName << "\n";
EC = llvm::object::object_error::parse_failed;
return;
return true;
}
}
}
return false;
}
for (auto &i : sectionSymbols) {
/// \brief Create individual atoms
bool createAtoms(llvm::error_code &EC) {
int64_t ordinal = 0;
// Cached value of the targetHandler
TargetHandler<ELFT> &targetHandler =
_elfTargetInfo.template getTargetHandler<ELFT>();
for (auto &i : _sectionSymbols) {
auto &symbols = i.second;
// Sort symbols by position.
// Sort symbols by position.
std::stable_sort(symbols.begin(), symbols.end(),
[](const Elf_Sym * A, const Elf_Sym * B) {
return A->st_value < B->st_value;
@ -318,11 +349,11 @@ public:
StringRef sectionContents;
if ((EC = _objFile->getSectionContents(i.first, sectionContents)))
return;
return true;
StringRef sectionName;
if ((EC = _objFile->getSectionName(i.first, sectionName)))
return;
return true;
// If the section has no symbols, create a custom atom for it.
if (i.first->sh_type == llvm::ELF::SHT_PROGBITS && symbols.empty() &&
@ -355,28 +386,22 @@ public:
StringRef symbolName = "";
if ((*si)->getType() != llvm::ELF::STT_SECTION)
if ((EC = _objFile->getSymbolName(i.first, *si, symbolName)))
return;
return true;
const Elf_Shdr *section = _objFile->getSection(*si);
bool isCommon = (*si)->getType() == llvm::ELF::STT_COMMON ||
(*si)->st_shndx == llvm::ELF::SHN_COMMON;
if ((section && section->sh_flags & llvm::ELF::SHF_MASKPROC) ||
(((*si)->st_shndx >= llvm::ELF::SHN_LOPROC) &&
((*si)->st_shndx <= llvm::ELF::SHN_HIPROC))) {
TargetHandler<ELFT> &TargetHandler =
_elfTargetInfo.template getTargetHandler<ELFT>();
TargetAtomHandler<ELFT> &elfAtomHandler =
TargetHandler.targetAtomHandler();
int64_t targetSymType = elfAtomHandler.getType(*si);
if (targetSymType == llvm::ELF::STT_COMMON)
isCommon = true;
if (isTargetAtom(section, *si)) {
TargetAtomHandler<ELFT> &_targetAtomHandler =
targetHandler.targetAtomHandler();
isCommon =
((_targetAtomHandler.getType(*si)) == llvm::ELF::STT_COMMON);
}
// Get the symbol's content:
uint64_t contentSize;
// Get the symbol's content size
uint64_t contentSize = 0;
if (si + 1 == se) {
// if this is the last symbol, take up the remaining data.
contentSize = isCommon ? 0 : i.first->sh_size - (*si)->st_value;
@ -442,12 +467,7 @@ public:
// mergeable section, treat them as defined atoms as they shouldnt be
// merged away as well as these symbols have to be part of symbol
// resolution
int64_t sectionFlags = 0;
if (section)
sectionFlags = section->sh_flags;
sectionFlags &= ~llvm::ELF::SHF_ALLOC;
if (doStringsMerge && section && (section->sh_entsize < 2) &&
(sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
if (isMergeableSection(section)) {
if ((*si)->getBinding() == llvm::ELF::STB_GLOBAL) {
auto definedMergeAtom = new (_readerStorage) ELFDefinedAtom<ELFT>(
*this, symbolName, sectionName, (*si), section, symbolData,
@ -504,45 +524,8 @@ public:
}
}
// All the Atoms and References are created. Now update each Reference's
// target with the Atom pointer it refers to.
for (auto &ri : _references) {
if (ri->kind() >= lld::Reference::kindTargetLow) {
const Elf_Sym *Symbol = _objFile->getElfSymbol(ri->targetSymbolIndex());
const Elf_Shdr *shdr = _objFile->getSection(Symbol);
int64_t sectionFlags = 0;
if (shdr)
sectionFlags = shdr->sh_flags;
sectionFlags &= ~llvm::ELF::SHF_ALLOC;
// If the section has mergeable strings, then make the relocation
// refer to the MergeAtom to allow deduping
if (doStringsMerge && shdr && (shdr->sh_entsize < 2) &&
(sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
const TargetRelocationHandler<ELFT> &relHandler = _elfTargetInfo
.template getTargetHandler<ELFT>().getRelocationHandler();
int64_t relocAddend = relHandler.relocAddend(*ri);
uint64_t addend = ri->addend() + relocAddend;
const MergeSectionKey ms(shdr, addend);
auto msec = _mergedSectionMap.find(ms);
if (msec == _mergedSectionMap.end()) {
if (Symbol->getType() != llvm::ELF::STT_SECTION)
addend = Symbol->st_value + addend;
MergeAtomsIter mai = findMergeAtom(shdr, addend);
if (mai != _mergeAtoms.end()) {
ri->setOffset(addend - ((*mai)->offset()));
ri->setAddend(0);
ri->setTarget(*mai);
} // check
else
llvm_unreachable("unable to find a merge atom");
} // find
else
ri->setTarget(msec->second);
} else
ri->setTarget(findAtom(Symbol));
}
}
updateReferences();
return false;
}
virtual const atom_collection<DefinedAtom> &defined() const {
@ -577,9 +560,9 @@ private:
// Only relocations that are inside the domain of the atom are added.
// Add Rela (those with r_addend) references:
auto rari = _relocationAddendRefences.find(sectionName);
auto rari = _relocationAddendReferences.find(sectionName);
auto rri = _relocationReferences.find(sectionName);
if (rari != _relocationAddendRefences.end())
if (rari != _relocationAddendReferences.end())
for (auto &rai : rari->second) {
if (!((rai.r_offset >= symbol->st_value) &&
(rai.r_offset < symbol->st_value + content.size())))
@ -622,6 +605,86 @@ private:
return ret;
}
/// \brief After all the Atoms and References are created, update each
/// Reference's target with the Atom pointer it refers to.
void updateReferences() {
/// cached value of target relocation handler
const TargetRelocationHandler<ELFT> &_targetRelocationHandler =
_elfTargetInfo.template getTargetHandler<ELFT>().getRelocationHandler();
for (auto &ri : _references) {
if (ri->kind() >= lld::Reference::kindTargetLow) {
const Elf_Sym *Symbol = _objFile->getElfSymbol(ri->targetSymbolIndex());
const Elf_Shdr *shdr = _objFile->getSection(Symbol);
if (isMergeableSection(shdr)) {
int64_t relocAddend = _targetRelocationHandler.relocAddend(*ri);
uint64_t addend = ri->addend() + relocAddend;
const MergeSectionKey ms(shdr, addend);
auto msec = _mergedSectionMap.find(ms);
if (msec == _mergedSectionMap.end()) {
if (Symbol->getType() != llvm::ELF::STT_SECTION)
addend = Symbol->st_value + addend;
MergeAtomsIter mai = findMergeAtom(shdr, addend);
if (mai != _mergeAtoms.end()) {
ri->setOffset(addend - ((*mai)->offset()));
ri->setAddend(0);
ri->setTarget(*mai);
} // check
else
llvm_unreachable("unable to find a merge atom");
} // find
else
ri->setTarget(msec->second);
} else
ri->setTarget(findAtom(Symbol));
}
}
}
/// \brief Is the atom corresponding to the value of the section and the
/// symbol a targetAtom ? If so, let the target determine its contentType
inline bool isTargetAtom(const Elf_Shdr *shdr, const Elf_Sym *sym) {
if ((shdr && shdr->sh_flags & llvm::ELF::SHF_MASKPROC) ||
((sym->st_shndx >= llvm::ELF::SHN_LOPROC) &&
(sym->st_shndx <= llvm::ELF::SHN_HIPROC)))
return true;
return false;
}
/// \brief Do we want to ignore the section. Ignored sections are
/// not processed to create atoms
bool isIgnoredSection(const Elf_Shdr *section) {
if (section->sh_size == 0)
return true;
switch (section->sh_type) {
case llvm::ELF::SHT_NOTE:
case llvm::ELF::SHT_STRTAB:
case llvm::ELF::SHT_SYMTAB:
case llvm::ELF::SHT_SYMTAB_SHNDX:
return true;
default:
break;
}
return false;
}
/// \brief Is the current section be treated as a mergeable string section
bool isMergeableSection(const Elf_Shdr *section) {
if (_doStringsMerge && section) {
int64_t sectionFlags = section->sh_flags;
sectionFlags &= ~llvm::ELF::SHF_ALLOC;
// If the section have mergeable strings, the linker would
// need to split the section into multiple atoms and mark them
// mergeByContent
if ((section->sh_entsize < 2) &&
(sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) {
return true;
}
}
return false;
}
llvm::BumpPtrAllocator _readerStorage;
std::unique_ptr<llvm::object::ELFObjectFile<ELFT> > _objFile;
atom_collection_vector<DefinedAtom> _definedAtoms;
@ -629,24 +692,37 @@ private:
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
/// \brief _relocationAddendRefences and _relocationReferences contain the
/// \brief _relocationAddendReferences and _relocationReferences contain the
/// list of relocations references. In ELF, if a section named, ".text" has
/// relocations will also have a section named ".rel.text" or ".rela.text"
/// which will hold the entries. -- .rel or .rela is prepended to create
/// the SHT_REL(A) section name.
std::unordered_map<
StringRef,
range<typename llvm::object::ELFObjectFile<ELFT>::Elf_Rela_Iter>>
_relocationAddendRefences;
range<typename llvm::object::ELFObjectFile<ELFT>::Elf_Rela_Iter> >
_relocationAddendReferences;
MergedSectionMapT _mergedSectionMap;
std::unordered_map<
StringRef,
range<typename llvm::object::ELFObjectFile<ELFT>::Elf_Rel_Iter>>
_relocationReferences;
range<typename llvm::object::ELFObjectFile<ELFT>::Elf_Rel_Iter> >
_relocationReferences;
std::vector<ELFReference<ELFT> *> _references;
llvm::DenseMap<const Elf_Sym *, Atom *> _symbolToAtomMapping;
const ELFTargetInfo &_elfTargetInfo;
/// \brief Atoms that are created for a section that has the merge property
/// set
MergeAtomsT _mergeAtoms;
/// \brief the section and the symbols that are contained within it to create
/// used to create atoms
std::map<const Elf_Shdr *, std::vector<const Elf_Sym *> > _sectionSymbols;
/// \brief Sections that have merge string property
std::vector<const Elf_Shdr *> _mergeStringSections;
/// \brief the cached options relevant while reading the ELF File
bool _doStringsMerge : 1;
};
} // end namespace elf
} // end namespace lld