summaryrefslogtreecommitdiffstats
path: root/lld/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib')
-rw-r--r--lld/lib/CMakeLists.txt1
-rw-r--r--lld/lib/Core/Atom.cpp51
-rw-r--r--lld/lib/Core/CMakeLists.txt8
-rw-r--r--lld/lib/Core/File.cpp16
-rw-r--r--lld/lib/Core/Resolver.cpp337
-rw-r--r--lld/lib/Core/SymbolTable.cpp140
-rw-r--r--lld/lib/Core/YamlReader.cpp559
-rw-r--r--lld/lib/Core/YamlWriter.cpp100
8 files changed, 1212 insertions, 0 deletions
diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt
new file mode 100644
index 00000000000..194a13a1af8
--- /dev/null
+++ b/lld/lib/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(Core)
diff --git a/lld/lib/Core/Atom.cpp b/lld/lib/Core/Atom.cpp
new file mode 100644
index 00000000000..482a21fe17e
--- /dev/null
+++ b/lld/lib/Core/Atom.cpp
@@ -0,0 +1,51 @@
+//===- Core/Atom.cpp - The Fundimental Unit of Linking --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Atom.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lld {
+
+ Atom::~Atom() {}
+
+ bool Atom::translationUnitSource(llvm::StringRef &path) const {
+ return false;
+ }
+
+ llvm::StringRef Atom::name() const {
+ return llvm::StringRef();
+ }
+
+ llvm::StringRef Atom::customSectionName() const {
+ return llvm::StringRef();
+ }
+
+ llvm::ArrayRef<uint8_t> Atom::rawContent() const {
+ return llvm::ArrayRef<uint8_t>();
+ }
+
+ Reference::iterator Atom::referencesBegin() const {
+ return 0;
+ }
+
+ Reference::iterator Atom::referencesEnd() const{
+ return 0;
+ }
+
+ Atom::UnwindInfo::iterator Atom::beginUnwind() const{
+ return 0;
+ }
+
+ Atom::UnwindInfo::iterator Atom::endUnwind() const{
+ return 0;
+ }
+
+} // namespace lld
diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt
new file mode 100644
index 00000000000..66de63d65a4
--- /dev/null
+++ b/lld/lib/Core/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_lld_library(lldCore
+ Atom.cpp
+ File.cpp
+ Resolver.cpp
+ SymbolTable.cpp
+ YamlReader.cpp
+ YamlWriter.cpp
+ )
diff --git a/lld/lib/Core/File.cpp b/lld/lib/Core/File.cpp
new file mode 100644
index 00000000000..e123d5ec192
--- /dev/null
+++ b/lld/lib/Core/File.cpp
@@ -0,0 +1,16 @@
+//===- Core/File.cpp - A Contaier of Atoms --------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/File.h"
+
+namespace lld {
+
+File::~File() {}
+
+}
diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp
new file mode 100644
index 00000000000..b3be26bf188
--- /dev/null
+++ b/lld/lib/Core/Resolver.cpp
@@ -0,0 +1,337 @@
+//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Resolver.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/InputFiles.h"
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Platform/Platform.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+namespace lld {
+
+class NotLive {
+public:
+ bool operator()(const Atom *atom) const {
+ return !(atom->live() || !atom->deadStrip());
+ }
+};
+
+class AtomCoalescedAway {
+public:
+ AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}
+
+ bool operator()(const Atom *atom) const {
+ const Atom *rep = _symbolTable.replacement(atom);
+ return rep != atom;
+ }
+
+private:
+ SymbolTable &_symbolTable;
+};
+
+void Resolver::initializeState() {
+ _platform.initialize();
+}
+
+// add initial undefines from -u option
+void Resolver::addInitialUndefines() {
+
+}
+
+// add all atoms from all initial .o files
+void Resolver::buildInitialAtomList() {
+ // each input files contributes initial atoms
+ _atoms.reserve(1024);
+ _inputFiles.forEachInitialAtom(*this);
+
+ _completedInitialObjectFiles = true;
+}
+
+
+// called before the first atom in any file is added with doAtom()
+void Resolver::doFile(const File &file) {
+ // notify platform
+ _platform.fileAdded(file);
+}
+
+// called on each atom when a file is added
+void Resolver::doAtom(const Atom &atom) {
+ // notify platform
+ _platform.atomAdded(atom);
+
+ // add to list of known atoms
+ _atoms.push_back(&atom);
+
+ // adjust scope (e.g. force some globals to be hidden)
+ _platform.adjustScope(atom);
+
+ // non-static atoms need extra handling
+ if (atom.scope() != Atom::scopeTranslationUnit) {
+ // tell symbol table about non-static atoms
+ _symbolTable.add(atom);
+
+ // platform can add aliases for any symbol
+ std::vector<const Atom *> aliases;
+ if (_platform.getAliasAtoms(atom, aliases))
+ this->addAtoms(aliases);
+ }
+
+ if (_platform.deadCodeStripping()) {
+ // add to set of dead-strip-roots, all symbols that
+ // the compiler marks as don't strip
+ if (!atom.deadStrip())
+ _deadStripRoots.insert(&atom);
+
+ // add to set of dead-strip-roots, all symbols that
+ // the platform decided must remain
+ if (_platform.isDeadStripRoot(atom))
+ _deadStripRoots.insert(&atom);
+ }
+}
+
+// utility to add a vector of atoms
+void Resolver::addAtoms(const std::vector<const Atom *> &newAtoms) {
+ for (std::vector<const Atom *>::const_iterator it = newAtoms.begin();
+ it != newAtoms.end(); ++it) {
+ this->doAtom(**it);
+ }
+}
+
+// ask symbol table if any definitionUndefined atoms still exist
+// if so, keep searching libraries until no more atoms being added
+void Resolver::resolveUndefines() {
+ const bool searchArchives =
+ _platform.searchArchivesToOverrideTentativeDefinitions();
+ const bool searchDylibs =
+ _platform.searchSharedLibrariesToOverrideTentativeDefinitions();
+
+ // keep looping until no more undefines were added in last loop
+ unsigned int undefineGenCount = 0xFFFFFFFF;
+ while (undefineGenCount != _symbolTable.size()) {
+ undefineGenCount = _symbolTable.size();
+ std::vector<const Atom *> undefines;
+ _symbolTable.undefines(undefines);
+ for (std::vector<const Atom *>::iterator it = undefines.begin();
+ it != undefines.end(); ++it) {
+ llvm::StringRef undefName = (*it)->name();
+ // load for previous undefine may also have loaded this undefine
+ if (!_symbolTable.isDefined(undefName)) {
+ _inputFiles.searchLibraries(undefName, true, true, false, *this);
+
+ // give platform a chance to instantiate platform
+ // specific atoms (e.g. section boundary)
+ if (!_symbolTable.isDefined(undefName)) {
+ std::vector<const Atom *> platAtoms;
+ if (_platform.getPlatformAtoms(undefName, platAtoms))
+ this->addAtoms(platAtoms);
+ }
+ }
+ }
+ // search libraries for overrides of common symbols
+ if (searchArchives || searchDylibs) {
+ std::vector<const Atom *> tents;
+ for (std::vector<const Atom *>::iterator ait = _atoms.begin();
+ ait != _atoms.end(); ++ait) {
+ const Atom *atom = *ait;
+ if (atom->definition() == Atom::definitionTentative)
+ tents.push_back(atom);
+ }
+ for (std::vector<const Atom *>::iterator dit = tents.begin();
+ dit != tents.end(); ++dit) {
+ // load for previous tentative may also have loaded
+ // this tentative, so check again
+ llvm::StringRef tentName = (*dit)->name();
+ const Atom *curAtom = _symbolTable.findByName(tentName);
+ assert(curAtom != NULL);
+ if (curAtom->definition() == Atom::definitionTentative) {
+ _inputFiles.searchLibraries(tentName, searchDylibs, true, true,
+ *this);
+ }
+ }
+ }
+ }
+}
+
+// switch all references to undefined or coalesced away atoms
+// to the new defined atom
+void Resolver::updateReferences() {
+ for (std::vector<const Atom *>::iterator it = _atoms.begin();
+ it != _atoms.end(); ++it) {
+ const Atom *atom = *it;
+ for (Reference::iterator rit = atom->referencesBegin(),
+ end = atom->referencesEnd(); rit != end; ++rit) {
+ rit->target = _symbolTable.replacement(rit->target);
+ }
+ }
+}
+
+// for dead code stripping, recursively mark atom "live"
+void Resolver::markLive(const Atom &atom, WhyLiveBackChain *previous) {
+ // if -why_live cares about this symbol, then dump chain
+ if ((previous->referer != NULL) && _platform.printWhyLive(atom.name())) {
+ llvm::errs() << atom.name() << " from " << atom.file()->path() << "\n";
+ int depth = 1;
+ for (WhyLiveBackChain *p = previous; p != NULL;
+ p = p->previous, ++depth) {
+ for (int i = depth; i > 0; --i)
+ llvm::errs() << " ";
+ llvm::errs() << p->referer->name() << " from "
+ << p->referer->file()->path() << "\n";
+ }
+ }
+
+ // if already marked live, then done (stop recursion)
+ if (atom.live())
+ return;
+
+ // mark this atom is live
+ const_cast<Atom *>(&atom)->setLive(true);
+
+ // mark all atoms it references as live
+ WhyLiveBackChain thisChain;
+ thisChain.previous = previous;
+ thisChain.referer = &atom;
+ for (Reference::iterator rit = atom.referencesBegin(),
+ end = atom.referencesEnd(); rit != end; ++rit) {
+ this->markLive(*(rit->target), &thisChain);
+ }
+}
+
+// remove all atoms not actually used
+void Resolver::deadStripOptimize() {
+ // only do this optimization with -dead_strip
+ if (!_platform.deadCodeStripping())
+ return;
+
+ // clear liveness on all atoms
+ for (std::vector<const Atom *>::iterator it = _atoms.begin();
+ it != _atoms.end(); ++it) {
+ const Atom *atom = *it;
+ const_cast<Atom *>(atom)->setLive(0);
+ }
+
+ // add entry point (main) to live roots
+ const Atom *entry = this->entryPoint();
+ if (entry != NULL)
+ _deadStripRoots.insert(entry);
+
+ // add -exported_symbols_list, -init, and -u entries to live roots
+ for (Platform::UndefinesIterator uit = _platform.initialUndefinesBegin();
+ uit != _platform.initialUndefinesEnd(); ++uit) {
+ llvm::StringRef sym = *uit;
+ const Atom *symAtom = _symbolTable.findByName(sym);
+ assert(symAtom->definition() != Atom::definitionUndefined);
+ _deadStripRoots.insert(symAtom);
+ }
+
+ // add platform specific helper atoms
+ std::vector<const Atom *> platRootAtoms;
+ if (_platform.getImplicitDeadStripRoots(platRootAtoms))
+ this->addAtoms(platRootAtoms);
+
+ // mark all roots as live, and recursively all atoms they reference
+ for (std::set<const Atom *>::iterator it = _deadStripRoots.begin();
+ it != _deadStripRoots.end(); ++it) {
+ WhyLiveBackChain rootChain;
+ rootChain.previous = NULL;
+ rootChain.referer = *it;
+ this->markLive(**it, &rootChain);
+ }
+
+ // now remove all non-live atoms from _atoms
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ NotLive()), _atoms.end());
+}
+
+// error out if some undefines remain
+void Resolver::checkUndefines(bool final) {
+ // when using LTO, undefines are checked after bitcode is optimized
+ if (_haveLLVMObjs && !final)
+ return;
+
+ // build vector of remaining undefined symbols
+ std::vector<const Atom *> undefinedAtoms;
+ _symbolTable.undefines(undefinedAtoms);
+ if (_platform.deadCodeStripping()) {
+ // when dead code stripping we don't care if dead atoms are undefined
+ undefinedAtoms.erase(std::remove_if(
+ undefinedAtoms.begin(), undefinedAtoms.end(),
+ NotLive()), undefinedAtoms.end());
+ }
+
+ // let platform make error message about missing symbols
+ if (undefinedAtoms.size() != 0)
+ _platform.errorWithUndefines(undefinedAtoms, _atoms);
+}
+
+// remove from _atoms all coaleseced away atoms
+void Resolver::removeCoalescedAwayAtoms() {
+ _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
+ AtomCoalescedAway(_symbolTable)), _atoms.end());
+}
+
+// check for interactions between symbols defined in this linkage unit
+// and same symbol name in linked dynamic shared libraries
+void Resolver::checkDylibSymbolCollisions() {
+ for (std::vector<const Atom *>::const_iterator it = _atoms.begin();
+ it != _atoms.end(); ++it) {
+ const Atom *atom = *it;
+ if (atom->scope() == Atom::scopeGlobal) {
+ if (atom->definition() == Atom::definitionTentative) {
+ // See if any shared library also has symbol which
+ // collides with the tentative definition.
+ // SymbolTable will warn if needed.
+ _inputFiles.searchLibraries(atom->name(), true, false, false, *this);
+ }
+ }
+ }
+}
+
+// get "main" atom for linkage unit
+const Atom *Resolver::entryPoint() {
+ llvm::StringRef symbolName = _platform.entryPointName();
+ if (symbolName != NULL)
+ return _symbolTable.findByName(symbolName);
+
+ return NULL;
+}
+
+// give platform a chance to tweak the set of atoms
+void Resolver::tweakAtoms() {
+ _platform.postResolveTweaks(_atoms);
+}
+
+void Resolver::linkTimeOptimize() {
+ // FIX ME
+}
+
+std::vector<const Atom *> &Resolver::resolve() {
+ this->initializeState();
+ this->addInitialUndefines();
+ this->buildInitialAtomList();
+ this->resolveUndefines();
+ this->updateReferences();
+ this->deadStripOptimize();
+ this->checkUndefines(false);
+ this->removeCoalescedAwayAtoms();
+ this->checkDylibSymbolCollisions();
+ this->linkTimeOptimize();
+ this->tweakAtoms();
+ return _atoms;
+}
+
+} // namespace lld
diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp
new file mode 100644
index 00000000000..3b770626f6b
--- /dev/null
+++ b/lld/lib/Core/SymbolTable.cpp
@@ -0,0 +1,140 @@
+//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/SymbolTable.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/InputFiles.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Platform/Platform.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+#include <algorithm>
+#include <cassert>
+#include <stdlib.h>
+#include <vector>
+
+namespace lld {
+
+void SymbolTable::add(const Atom &atom) {
+ assert(atom.scope() != Atom::scopeTranslationUnit);
+ switch (atom.combine()) {
+ case Atom::combineNever:
+ case Atom::combineByName:
+ this->addByName(atom);
+ break;
+ case Atom::combineByTypeContent:
+ case Atom::combineByTypeContentDeep:
+ // TO DO: support constants merging
+ break;
+ }
+}
+
+enum NameCollisionResolution {
+ NCR_First,
+ NCR_Second,
+ NCR_Weak,
+ NCR_Larger,
+ NCR_Error
+};
+
+static NameCollisionResolution cases[5][5] = {
+ //regular tentative absolute undef sharedLib
+ {
+ // first is regular
+ NCR_Error, NCR_First, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is tentative
+ NCR_Second, NCR_Larger, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is absolute
+ NCR_Error, NCR_Error, NCR_Error, NCR_First, NCR_First
+ },
+ {
+ // first is undef
+ NCR_Second, NCR_Second, NCR_Second, NCR_First, NCR_Second
+ },
+ {
+ // first is sharedLib
+ NCR_Second, NCR_Second, NCR_Second, NCR_First, NCR_First
+ }
+};
+
+static NameCollisionResolution collide(Atom::Definition first,
+ Atom::Definition second) {
+ return cases[first][second];
+}
+
+void SymbolTable::addByName(const Atom &atom) {
+ llvm::StringRef name = atom.name();
+ const Atom *existing = this->findByName(name);
+ if (existing == NULL) {
+ // name is not in symbol table yet, add it associate with this atom
+ _nameTable[name] = &atom;
+ } else {
+ // name is already in symbol table and associated with another atom
+ switch (collide(existing->definition(), atom.definition())) {
+ case NCR_First:
+ // using first, just add new to _replacedAtoms
+ _replacedAtoms[&atom] = existing;
+ break;
+ case NCR_Second:
+ // using second, update tables
+ _nameTable[name] = &atom;
+ _replacedAtoms[existing] = &atom;
+ break;
+ default:
+ llvm::report_fatal_error("unhandled switch clause");
+ }
+ }
+}
+
+const Atom *SymbolTable::findByName(llvm::StringRef sym) {
+ NameToAtom::iterator pos = _nameTable.find(sym);
+ if (pos == _nameTable.end())
+ return NULL;
+ return pos->second;
+}
+
+bool SymbolTable::isDefined(llvm::StringRef sym) {
+ const Atom *atom = this->findByName(sym);
+ if (atom == NULL)
+ return false;
+ if (atom->definition() == Atom::definitionUndefined)
+ return false;
+ return true;
+}
+
+const Atom *SymbolTable::replacement(const Atom *atom) {
+ AtomToAtom::iterator pos = _replacedAtoms.find(atom);
+ if (pos == _replacedAtoms.end())
+ return atom;
+ // might be chain, recurse to end
+ return this->replacement(pos->second);
+}
+
+unsigned int SymbolTable::size() {
+ return _nameTable.size();
+}
+
+void SymbolTable::undefines(std::vector<const Atom *> &undefs) {
+ for (NameToAtom::iterator it = _nameTable.begin(),
+ end = _nameTable.end(); it != end; ++it) {
+ const Atom *atom = it->second;
+ assert(atom != NULL);
+ if (atom->definition() == Atom::definitionUndefined)
+ undefs.push_back(atom);
+ }
+}
+
+} // namespace lld
diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp
new file mode 100644
index 00000000000..86dea545858
--- /dev/null
+++ b/lld/lib/Core/YamlReader.cpp
@@ -0,0 +1,559 @@
+//===- Core/YamlReader.cpp - Reads YAML -----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/YamlReader.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/system_error.h"
+
+#include <vector>
+
+namespace { const llvm::error_code success; }
+
+namespace lld {
+namespace yaml {
+class YAML {
+public:
+ struct Entry {
+ Entry(const char *k, const char *v, int d, bool bd, bool bs)
+ : key(strdup(k))
+ , value(strdup(v))
+ , depth(d)
+ , beginSequence(bs)
+ , beginDocument(bd) {}
+
+ const char *key;
+ const char *value;
+ int depth;
+ bool beginSequence;
+ bool beginDocument;
+ };
+
+ static void parse(llvm::MemoryBuffer *mb, std::vector<const Entry *>&);
+
+private:
+ enum State {
+ start,
+ inHeaderComment,
+ inTripleDash,
+ inTriplePeriod,
+ inDocument,
+ inKey,
+ inSpaceBeforeValue,
+ inValue,
+ inValueSequence,
+ inValueSequenceEnd
+ };
+};
+
+
+void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
+ State state = start;
+ char key[64];
+ char value[64];
+ char *p = NULL;
+ unsigned int lineNumber = 1;
+ int depth = 0;
+ bool nextKeyIsStartOfDocument = false;
+ bool nextKeyIsStartOfSequence = false;
+ for (const char *s = mb->getBufferStart(); s < mb->getBufferEnd(); ++s) {
+ char c = *s;
+ if (c == '\n')
+ ++lineNumber;
+ switch (state) {
+ case start:
+ if (c == '#')
+ state = inHeaderComment;
+ else if (c == '-') {
+ p = &key[0];
+ *p++ = c;
+ state = inTripleDash;
+ }
+ break;
+ case inHeaderComment:
+ if (c == '\n') {
+ state = start;
+ }
+ break;
+ case inTripleDash:
+ if (c == '-') {
+ *p++ = c;
+ } else if (c == '\n') {
+ *p = '\0';
+ if (strcmp(key, "---") != 0)
+ return;
+ depth = 0;
+ state = inDocument;
+ nextKeyIsStartOfDocument = true;
+ } else {
+ return;
+ }
+ break;
+ case inTriplePeriod:
+ if (c == '.') {
+ *p++ = c;
+ } else if (c == '\n') {
+ *p = '\0';
+ if (strcmp(key, "...") != 0)
+ return;
+ depth = 0;
+ state = inHeaderComment;
+ } else {
+ return;
+ }
+ break;
+ case inDocument:
+ if (isalnum(c)) {
+ state = inKey;
+ p = &key[0];
+ *p++ = c;
+ } else if (c == '-') {
+ if (depth == 0) {
+ p = &key[0];
+ *p++ = c;
+ state = inTripleDash;
+ } else {
+ nextKeyIsStartOfSequence = true;
+ ++depth;
+ }
+ } else if (c == ' ') {
+ ++depth;
+ } else if (c == '.') {
+ p = &key[0];
+ *p++ = c;
+ state = inTriplePeriod;
+ } else if (c == '\n') {
+ // ignore empty lines
+ } else {
+ return;
+ }
+ break;
+ case inKey:
+ if (isalnum(c) || (c == '-')) {
+ *p++ = c;
+ } else if (c == ':') {
+ *p = '\0';
+ state = inSpaceBeforeValue;
+ } else if (c == '\n') {
+ *p = '\0';
+ if (strcmp(key, "---") == 0)
+ state = inDocument;
+ else
+ return;
+ } else {
+ return;
+ }
+ break;
+ case inSpaceBeforeValue:
+ if (isalnum(c) || (c == '-') || (c == '_')) {
+ p = &value[0];
+ *p++ = c;
+ state = inValue;
+ } else if (c == '\n') {
+ entries.push_back(new Entry(key, "", depth,
+ nextKeyIsStartOfDocument,
+ nextKeyIsStartOfSequence));
+ nextKeyIsStartOfSequence = false;
+ nextKeyIsStartOfDocument = false;
+ state = inDocument;
+ depth = 0;
+ } else if (c == '[') {
+ state = inValueSequence;
+ } else if (c == ' ') {
+ // eat space
+ } else {
+ return;
+ }
+ break;
+ case inValue:
+ if (isalnum(c) || (c == '-') || (c == '_')) {
+ *p++ = c;
+ } else if (c == '\n') {
+ *p = '\0';
+ entries.push_back(new Entry(key, value, depth,
+ nextKeyIsStartOfDocument,
+ nextKeyIsStartOfSequence));
+ nextKeyIsStartOfSequence = false;
+ nextKeyIsStartOfDocument = false;
+ state = inDocument;
+ depth = 0;
+ }
+ break;
+ case inValueSequence:
+ if (c == ']')
+ state = inValueSequenceEnd;
+ break;
+ case inValueSequenceEnd:
+ if (c == '\n') {
+ state = inDocument;
+ depth = 0;
+ }
+ break;
+ }
+ }
+}
+
+class YAMLFile : public File {
+public:
+ YAMLFile()
+ : File("path")
+ , _lastRefIndex(0) {}
+
+ virtual bool forEachAtom(File::AtomHandler &) const;
+ virtual bool justInTimeforEachAtom(llvm::StringRef name,
+ File::AtomHandler &) const;
+
+ std::vector<Atom *> _atoms;
+ std::vector<Reference> _references;
+ unsigned int _lastRefIndex;
+};
+
+bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
+ handler.doFile(*this);
+ for (std::vector<Atom *>::const_iterator it = _atoms.begin();
+ it != _atoms.end(); ++it) {
+ handler.doAtom(**it);
+ }
+ return true;
+}
+
+bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
+ File::AtomHandler &handler) const {
+ return false;
+}
+
+
+class YAMLAtom : public Atom {
+public:
+ YAMLAtom( Definition d
+ , Combine c
+ , Scope s
+ , ContentType ct
+ , SectionChoice sc
+ , bool uvn
+ , bool dds
+ , bool tb
+ , bool al
+ , Alignment a
+ , YAMLFile *f
+ , const char *n)
+ : Atom(d, c, s, ct, sc, uvn, dds, tb, al, a)
+ , _file(f)
+ , _name(n)
+ , _size(0)
+ , _refStartIndex(f->_lastRefIndex)
+ , _refEndIndex(f->_references.size()) {
+ f->_lastRefIndex = _refEndIndex;
+ }
+
+ virtual const class File *file() const {
+ return _file;
+ }
+
+ virtual bool translationUnitSource(const char* *dir, const char* *name) const{
+ return false;
+ }
+
+ virtual llvm::StringRef name() const {
+ return _name;
+ }
+
+ virtual uint64_t objectAddress() const {
+ return 0;
+ }
+
+ virtual uint64_t size() const {
+ return _size;
+ }
+
+ virtual void copyRawContent(uint8_t buffer[]) const { }
+ virtual Reference::iterator referencesBegin() const;
+ virtual Reference::iterator referencesEnd() const;
+private:
+ YAMLFile *_file;
+ const char *_name;
+ unsigned long _size;
+ unsigned int _refStartIndex;
+ unsigned int _refEndIndex;
+};
+
+Reference::iterator YAMLAtom::referencesBegin() const {
+ if (_file->_references.size() < _refStartIndex)
+ return (Reference::iterator)&_file->_references[_refStartIndex];
+ return 0;
+}
+
+Reference::iterator YAMLAtom::referencesEnd() const {
+ if (_file->_references.size() < _refEndIndex)
+ return (Reference::iterator)&_file->_references[_refEndIndex];
+ return 0;
+}
+
+class YAMLAtomState {
+public:
+ YAMLAtomState();
+
+ void setName(const char *n);
+ void setScope(const char *n);
+ void setType(const char *n);
+ void setAlign2(const char *n);
+ void setDefinition(const char *n);
+
+ void setFixupKind(const char *n);
+ void setFixupOffset(const char *n);
+ void setFixupTarget(const char *n);
+ void addFixup(YAMLFile *f);
+
+ void makeAtom(YAMLFile *);
+
+private:
+ const char *_name;
+ Atom::Alignment _align;
+ Atom::Combine _combine;
+ Atom::ContentType _type;
+ Atom::Scope _scope;
+ Atom::Definition _def;
+ Atom::SectionChoice _sectionChoice;
+ bool _userVisibleName;
+ bool _dontDeadStrip;
+ bool _thumb;
+ bool _alias;
+ Reference _ref;
+};
+
+YAMLAtomState::YAMLAtomState()
+ : _name(NULL)
+ , _align(0, 0)
+ , _combine(Atom::combineNever)
+ , _type(Atom::typeData)
+ , _scope(Atom::scopeGlobal)
+ , _userVisibleName(true)
+ , _dontDeadStrip(false)
+ , _thumb(false)
+ , _alias(false) {
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+void YAMLAtomState::makeAtom(YAMLFile *f) {
+ Atom *a = new YAMLAtom(_def, _combine, _scope, _type, _sectionChoice,
+ _userVisibleName, _dontDeadStrip, _thumb, _alias,
+ _align, f, _name);
+
+ f->_atoms.push_back(a);
+
+ // reset state for next atom
+ _name = NULL;
+ _align.powerOf2 = 0;
+ _align.modulus = 0;
+ _combine = Atom::combineNever;
+ _type = Atom::typeData;
+ _scope = Atom::scopeGlobal;
+ _def = Atom::definitionRegular;
+ _sectionChoice = Atom::sectionBasedOnContent;
+ _userVisibleName = true;
+ _dontDeadStrip = false;
+ _thumb = false;
+ _alias = false;
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+void YAMLAtomState::setName(const char *n) {
+ _name = n;
+}
+
+void YAMLAtomState::setScope(const char *s) {
+ if (strcmp(s, "global") == 0)
+ _scope = Atom::scopeGlobal;
+ else if (strcmp(s, "hidden") == 0)
+ _scope = Atom::scopeLinkageUnit;
+ else if (strcmp(s, "static") == 0)
+ _scope = Atom::scopeTranslationUnit;
+ else
+ llvm::report_fatal_error("bad scope value");
+}
+
+void YAMLAtomState::setType(const char *s) {
+ if (strcmp(s, "code") == 0)
+ _type = Atom::typeCode;
+ else if (strcmp(s, "c-string") == 0)
+ _type = Atom::typeCString;
+ else if (strcmp(s, "zero-fill") == 0)
+ _type = Atom::typeZeroFill;
+ else if (strcmp(s, "data") == 0)
+ _type = Atom::typeData;
+ else
+ llvm::report_fatal_error("bad type value");
+}
+
+void YAMLAtomState::setAlign2(const char *s) {
+ llvm::StringRef str(s);
+ uint32_t res;
+ str.getAsInteger(10, res);
+ _align.powerOf2 = static_cast<uint16_t>(res);
+}
+
+void YAMLAtomState::setDefinition(const char *s) {
+ if (strcmp(s, "regular") == 0)
+ _def = Atom::definitionRegular;
+ else if (strcmp(s, "tentative") == 0)
+ _def = Atom::definitionTentative;
+ else if (strcmp(s, "absolute") == 0)
+ _def = Atom::definitionAbsolute;
+ else
+ llvm::report_fatal_error("bad definition value");
+}
+
+void YAMLAtomState::setFixupKind(const char *s) {
+ if (strcmp(s, "pcrel32") == 0)
+ _ref.kind = 1;
+ else if (strcmp(s, "call32") == 0)
+ _ref.kind = 2;
+ else
+ llvm::report_fatal_error("bad fixup kind value");
+}
+
+void YAMLAtomState::setFixupOffset(const char *s) {
+ if ((s[0] == '0') && (s[1] == 'x'))
+ llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
+ else
+ llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
+}
+
+void YAMLAtomState::setFixupTarget(const char *s) {
+}
+
+void YAMLAtomState::addFixup(YAMLFile *f) {
+ f->_references.push_back(_ref);
+ // clear for next ref
+ _ref.target = NULL;
+ _ref.addend = 0;
+ _ref.offsetInAtom = 0;
+ _ref.kind = 0;
+ _ref.flags = 0;
+}
+
+llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
+ , std::vector<File *> &result) {
+ std::vector<const YAML::Entry *> entries;
+ YAML::parse(mb, entries);
+
+ YAMLFile *file = NULL;
+ YAMLAtomState atomState;
+ bool inAtoms = false;
+ bool inFixups = false;
+ int depthForAtoms = -1;
+ int depthForFixups = -1;
+ int lastDepth = -1;
+ bool haveAtom = false;
+ bool haveFixup = false;
+
+ for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ const YAML::Entry *entry = *it;
+
+ if (entry->beginDocument) {
+ if (file != NULL) {
+ if (haveAtom) {
+ atomState.makeAtom(file);
+ haveAtom = false;
+ }
+ result.push_back(file);
+ }
+ file = new YAMLFile();
+ inAtoms = false;
+ depthForAtoms = -1;
+ }
+ if (lastDepth > entry->depth) {
+ // end of fixup sequence
+ if (haveFixup) {
+ atomState.addFixup(file);
+ haveFixup = false;
+ }
+ }
+
+ if (inAtoms && (depthForAtoms == -1)) {
+ depthForAtoms = entry->depth;
+ }
+ if (inFixups && (depthForFixups == -1)) {
+ depthForFixups = entry->depth;
+ }
+ if (strcmp(entry->key, "atoms") == 0) {
+ inAtoms = true;
+ }
+ if (inAtoms) {
+ if (depthForAtoms == entry->depth) {
+ if (entry->beginSequence) {
+ if (haveAtom) {
+ atomState.makeAtom(file);
+ haveAtom = false;
+ }
+ }
+ if (strcmp(entry->key, "name") == 0) {
+ atomState.setName(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "scope") == 0) {
+ atomState.setScope(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "type") == 0) {
+ atomState.setType(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "align2") == 0) {
+ atomState.setAlign2(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "definition") == 0) {
+ atomState.setDefinition(entry->value);
+ haveAtom = true;
+ } else if (strcmp(entry->key, "fixups") == 0) {
+ inFixups = true;
+ }
+ } else if (depthForFixups == entry->depth) {
+ if (entry->beginSequence) {
+ if (haveFixup) {
+ atomState.addFixup(file);
+ haveFixup = false;
+ }
+ }
+ if (strcmp(entry->key, "kind") == 0) {
+ atomState.setFixupKind(entry->value);
+ haveFixup = true;
+ } else if (strcmp(entry->key, "offset") == 0) {
+ atomState.setFixupOffset(entry->value);
+ haveFixup = true;
+ } else if (strcmp(entry->key, "target") == 0) {
+ atomState.setFixupTarget(entry->value);
+ haveFixup = true;
+ }
+ }
+ }
+ lastDepth = entry->depth;
+ }
+ if (haveAtom) {
+ atomState.makeAtom(file);
+ }
+
+ result.push_back(file);
+ return success;
+}
+} // namespace yaml
+} // namespace lld
diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp
new file mode 100644
index 00000000000..ae27c7e3129
--- /dev/null
+++ b/lld/lib/Core/YamlWriter.cpp
@@ -0,0 +1,100 @@
+//===- Core/YamlWriter.cpp - Writes YAML ----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/YamlWriter.h"
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/system_error.h"
+
+#include <vector>
+
+namespace lld {
+namespace yaml {
+
+class Handler : public File::AtomHandler {
+public:
+ Handler(llvm::raw_ostream &out) : _out(out) { }
+
+ virtual void doFile(const class File &) { }
+ virtual void doAtom(const class Atom &atom) {
+ _out << " - name: " << atom.name() << "\n";
+ _out << " definition: " << definitionString(atom.definition()) <<"\n";
+ _out << " user-visible:" << atom.userVisibleName() << "\n";
+ _out << " scope: " << scopeString(atom.scope()) << "\n";
+ _out << " type: " << typeString(atom.contentType()) << "\n";
+ if (atom.referencesBegin() != atom.referencesEnd()) {
+ _out << " fixups:\n";
+ for (Reference::iterator it = atom.referencesBegin(),
+ end = atom.referencesEnd(); it != end; ++it) {
+ _out << " - kind: " << it->kind << "\n";
+ _out << " offset: " << it->offsetInAtom << "\n";
+ }
+ }
+
+ }
+
+private:
+ const char *scopeString(Atom::Scope scope) {
+ switch (scope) {
+ case Atom::scopeTranslationUnit:
+ return "static";
+ case Atom::scopeLinkageUnit:
+ return "hidden";
+ case Atom::scopeGlobal:
+ return "global";
+ }
+ return "???";
+ }
+
+ const char *typeString(Atom::ContentType type) {
+ switch (type) {
+ case Atom::typeCode:
+ return "code";
+ case Atom::typeCString:
+ return "c-string";
+ case Atom::typeZeroFill:
+ return "zero-fill";
+ case Atom::typeData:
+ return "data";
+ default:
+ return "???";
+ }
+ }
+
+ const char *definitionString(Atom::Definition def) {
+ switch (def) {
+ case Atom::definitionRegular:
+ return "regular";
+ case Atom::definitionTentative:
+ return "tentative";
+ case Atom::definitionAbsolute:
+ return "absolute";
+ default:
+ return "???";
+ }
+ }
+
+ llvm::raw_ostream &_out;
+};
+
+void writeObjectText(File *file, llvm::raw_ostream &out) {
+ Handler h(out);
+ out << "---\n";
+ out << "atoms:\n";
+ file->forEachAtom(h);
+ out << "...\n";
+}
+
+} // namespace yaml
+} // namespace lld
OpenPOWER on IntegriCloud