[llvm-commits] [lld] support for adding absolute symbols in WriterELF
Shankar Easwaran
shankare at codeaurora.org
Wed Jan 9 07:38:04 PST 2013
Hi,
This functionality is to support adding absolute symbols / undefined
symbols in WriterELF.
Patch attached.
Thanks
Shankar Easwaran
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation
-------------- next part --------------
Index: test/Driver/x86_64-target.test
===================================================================
--- test/Driver/x86_64-target.test (revision 171973)
+++ test/Driver/x86_64-target.test (working copy)
@@ -1 +1,2 @@
-RUN: lld -flavor ld -target x86_64-linux
+# Will fail with unersolved symbol
+RUN: lld -flavor ld -target x86_64-linux || exit 0
Index: test/elf/Inputs/writersyms.o
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: test/elf/Inputs/writersyms.o
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: test/elf/sections.objtxt
===================================================================
--- test/elf/sections.objtxt (revision 171973)
+++ test/elf/sections.objtxt (working copy)
@@ -10,8 +10,8 @@
OBJDUMP: 4 .anotherspecial 000000004 00000000000001008 DATA
OBJDUMP: 5 .bss 000000001 0000000000000100c BSS
OBJDUMP: 6 .shstrtab 000000045 00000000000000000
-OBJDUMP: 7 .symtab 0000000c0 00000000000000000
-OBJDUMP: 8 .strtab 00000003b 00000000000000000
+OBJDUMP: 7 .symtab 000000110 00000000000000000
+OBJDUMP: 8 .strtab 000000061 00000000000000000
READOBJ: File Format : ELF32-i386
READOBJ: Arch : i386
Index: test/elf/symbols.objtxt
===================================================================
--- test/elf/symbols.objtxt (revision 0)
+++ test/elf/symbols.objtxt (revision 0)
@@ -0,0 +1,27 @@
+# Tests the functionality of archive libraries reading
+# and resolution
+# Note: The binary files would not be required once we have support to generate
+# binary archives from textual(yaml) input
+#
+# Tests generated using the source files below
+# main file
+#
+#extern int __bss_start __attribute__ ((weak));
+#int a;
+#int main()
+#{
+# return 0;
+#}
+#
+
+RUN: lld-core -reader ELF %p/Inputs/writersyms.o -writer ELF -o %t1
+RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+CHECKSYMS: 00000000 a 1.c
+CHECKSYMS: 00000094 T main
+CHECKSYMS: 00001000 A __bss_start
+CHECKSYMS: 00001000 B a
+CHECKSYMS: 00001004 A __bss_end
+CHECKSYMS: 00001004 A _end
+CHECKSYMS: 00001004 A end
+CHECKSYMS: w _start
Index: lib/ReaderWriter/ELF/WriterELF.cpp
===================================================================
--- lib/ReaderWriter/ELF/WriterELF.cpp (revision 171973)
+++ lib/ReaderWriter/ELF/WriterELF.cpp (working copy)
@@ -34,7 +34,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "AtomsELF.h"
+#include "ExecutableAtoms.h"
#include <map>
#include <unordered_map>
@@ -1101,7 +1101,7 @@
binding = ELF::STB_GLOBAL;
break;
}
- symbol->st_value = aa->value();
+ symbol->st_value = addr;
}
else {
symbol->st_value = 0;
@@ -1218,7 +1218,29 @@
class ELFProgramHeader : public Chunk<target_endianness, max_align, is64Bits> {
public:
typedef Elf_Phdr_Impl<target_endianness, max_align, is64Bits> Elf_Phdr;
+ typedef typename std::vector<Elf_Phdr *>::iterator PhIterT;
+ /// \brief Find a program header entry, given the type of entry that
+ /// we are looking for
+ class FindPhdr {
+ public:
+ FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear)
+ : _type(type)
+ , _flags(flags)
+ , _flagsClear(flagsClear)
+ {}
+
+ bool operator()(const Elf_Phdr* j) const {
+ return ((j->p_type == _type) &&
+ ((j->p_flags & _flags) == _flags) &&
+ (!(j->p_flags & _flagsClear)));
+ }
+ private:
+ uint64_t _type;
+ uint64_t _flags;
+ uint64_t _flagsClear;
+ };
+
ELFProgramHeader()
: Chunk<target_endianness, max_align, is64Bits>(
"elfphdr",
@@ -1283,6 +1305,20 @@
}
}
+ /// \brief find a program header entry in the list of program headers
+ PhIterT findProgramHeader(uint64_t type, uint64_t flags, uint64_t flagClear) {
+ return std::find_if(_ph.begin(), _ph.end(),
+ FindPhdr(type, flags, flagClear));
+ }
+
+ PhIterT begin() {
+ return _ph.begin();
+ }
+
+ PhIterT end() {
+ return _ph.end();
+ }
+
void finalize() { }
int64_t entsize() {
@@ -1295,8 +1331,7 @@
private:
std::vector<Elf_Phdr *> _ph;
- typedef typename std::vector<Elf_Phdr *>::iterator ph_iter;
- ph_iter _phi;
+ PhIterT _phi;
llvm::BumpPtrAllocator _allocator;
};
@@ -1482,6 +1517,35 @@
Segment<target_endianness, max_align, is64Bits>*,
SegmentHashKey> SegmentMapT;
+ /// \brief All absolute atoms are created in the ELF Layout by using
+ /// an AbsoluteAtomPair. Contains a pair of AbsoluteAtom and the
+ /// value which is the address of the absolute atom
+ class AbsoluteAtomPair {
+ public:
+ AbsoluteAtomPair(const AbsoluteAtom *a, int64_t value)
+ : _absoluteAtom(a)
+ , _value(value) { }
+
+ const AbsoluteAtom *absoluteAtom() { return _absoluteAtom; }
+ int64_t value() const { return _value; }
+ void setValue(int64_t val) { _value = val; }
+
+ private:
+ const AbsoluteAtom *_absoluteAtom;
+ int64_t _value;
+ };
+
+ /// \brief find a absolute atom pair given a absolute atom name
+ struct FindByName {
+ const std::string name;
+ FindByName(const StringRef name) : name(name) {}
+ bool operator()(AbsoluteAtomPair& j) {
+ return j.absoluteAtom()->name() == name;
+ }
+ };
+
+ typedef typename std::vector<AbsoluteAtomPair>::iterator AbsoluteAtomIterT;
+
DefaultELFLayout(const WriterOptionsELF &options):_options(options) { }
/// \brief Return the section order for a input section
@@ -1602,42 +1666,69 @@
// Adds an atom to the section
virtual error_code addAtom(const Atom *atom) {
- const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
- const StringRef sectionName =
- getSectionName(definedAtom->customSectionName(),
- definedAtom->contentType());
- const lld::DefinedAtom::ContentPermissions permissions =
- definedAtom->permissions();
- const lld::DefinedAtom::ContentType contentType =
- definedAtom->contentType();
- const Key key(sectionName, std::make_pair(contentType, permissions));
- const std::pair<Key, Section<target_endianness, max_align, is64Bits> *>
- currentSection(key, nullptr);
- std::pair<typename SectionMapT::iterator, bool>
- sectionInsert(_sectionMap.insert(currentSection));
- Section<target_endianness, max_align, is64Bits> *section;
- // the section is already in the map
- if (!sectionInsert.second) {
- section = sectionInsert.first->second;
- section->setContentPermissions(permissions);
+ const Atom::Definition atomType = atom->definition();
+ if (atomType == Atom::definitionRegular) {
+ const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
+ const StringRef sectionName =
+ getSectionName(definedAtom->customSectionName(),
+ definedAtom->contentType());
+ const lld::DefinedAtom::ContentPermissions permissions =
+ definedAtom->permissions();
+ const lld::DefinedAtom::ContentType contentType =
+ definedAtom->contentType();
+ const Key key(sectionName, std::make_pair(contentType, permissions));
+ const std::pair<Key, Section<target_endianness, max_align, is64Bits> *>
+ currentSection(key, nullptr);
+ std::pair<typename SectionMapT::iterator, bool>
+ sectionInsert(_sectionMap.insert(currentSection));
+ Section<target_endianness, max_align, is64Bits> *section;
+ // the section is already in the map
+ if (!sectionInsert.second) {
+ section = sectionInsert.first->second;
+ section->setContentPermissions(permissions);
+ }
+ else {
+ SectionOrder section_order = getSectionOrder(sectionName,
+ contentType,
+ permissions);
+ section = new (_allocator.Allocate
+ <Section<target_endianness, max_align, is64Bits>>())
+ Section<target_endianness, max_align, is64Bits>
+ (sectionName, contentType,
+ permissions, section_order);
+ sectionInsert.first->second = section;
+ section->setOrder(section_order);
+ _sections.push_back(section);
+ }
+ section->appendAtom(atom);
}
- else {
- SectionOrder section_order = getSectionOrder(sectionName,
- contentType,
- permissions);
- section = new (_allocator.Allocate
- <Section<target_endianness, max_align, is64Bits>>())
- Section<target_endianness, max_align, is64Bits>
- (sectionName, contentType,
- permissions, section_order);
- sectionInsert.first->second = section;
- section->setOrder(section_order);
- _sections.push_back(section);
+ // Absolute atoms are not part of any section, they are global for the whole
+ // link
+ else if (atomType == Atom::definitionAbsolute) {
+ const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom);
+ _absoluteAtoms.push_back(AbsoluteAtomPair(absoluteAtom,
+ absoluteAtom->value()));
}
- section->appendAtom(atom);
+ else
+ llvm_unreachable("Only absolute / defined atoms can be added here");
return error_code::success();
}
+ /// \brief find a absolute atom given a name
+ AbsoluteAtomIterT findAbsoluteAtom(const StringRef name) {
+ return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
+ FindByName(name));
+ }
+
+ /// \bried Begin/End iterators
+ AbsoluteAtomIterT absAtomsBegin() {
+ return _absoluteAtoms.begin();
+ }
+
+ AbsoluteAtomIterT absAtomsEnd() {
+ return _absoluteAtoms.end();
+ }
+
// Merge sections with the same name into a MergedSections
void mergeSimiliarSections() {
MergedSections<target_endianness, max_align, is64Bits> *mergedSection;
@@ -1922,13 +2013,13 @@
SectionMapT _sectionMap;
MergedSectionMapT _mergedSectionMap;
SegmentMapT _segmentMap;
-
std::vector<Chunk<target_endianness, max_align, is64Bits> *> _sections;
std::vector<Segment<target_endianness, max_align, is64Bits> *> _segments;
std::vector<MergedSections<target_endianness, max_align, is64Bits> *>
_mergedSections;
ELFHeader<target_endianness, max_align, is64Bits> *_elfHeader;
ELFProgramHeader<target_endianness, max_align, is64Bits> *_programHeader;
+ std::vector<AbsoluteAtomPair> _absoluteAtoms;
llvm::BumpPtrAllocator _allocator;
const WriterOptionsELF &_options;
};
@@ -1955,6 +2046,9 @@
void buildSectionHeaderTable();
void assignSectionsWithNoSegments();
void addAbsoluteUndefinedSymbols(const lld::File &File);
+ void addDefaultAtoms();
+ void addFiles(InputFiles&);
+ void finalizeDefaultAtomValues();
uint64_t addressOfAtom(const Atom *atom) {
return _atomToAddressMap[atom];
@@ -1977,6 +2071,7 @@
ELFStringTable<target_endianness, max_align, is64Bits> *_strtab;
ELFStringTable<target_endianness, max_align, is64Bits> *_shstrtab;
ELFSectionHeader<target_endianness, max_align, is64Bits> *_shdrtab;
+ CRuntimeFile<target_endianness, max_align, is64Bits> _runtimeFile;
};
//===----------------------------------------------------------------------===//
@@ -1989,7 +2084,8 @@
::ELFExecutableWriter(const WriterOptionsELF &options)
: _options(options)
, _referenceKindHandler(KindHandler::makeHandler(_options.machine(),
- target_endianness)) {
+ target_endianness))
+ , _runtimeFile(options) {
_layout =
new DefaultELFLayout<target_endianness, max_align, is64Bits>(options);
}
@@ -2002,6 +2098,10 @@
for (const DefinedAtom *definedAtom : file.defined() ) {
_layout->addAtom(definedAtom);
}
+ /// Add all the absolute atoms to the layout
+ for (const AbsoluteAtom *absoluteAtom : file.absolute()) {
+ _layout->addAtom(absoluteAtom);
+ }
}
template<support::endianness target_endianness,
@@ -2028,13 +2128,15 @@
bool is64Bits>
void ELFExecutableWriter<target_endianness, max_align, is64Bits>
::addAbsoluteUndefinedSymbols(const lld::File &file) {
+ /// add all the absolute symbols that the layout contains to the output symbol
+ /// table
+ for (auto absi = _layout->absAtomsBegin(), abse = _layout->absAtomsEnd();
+ absi != abse; ++absi) {
+ _symtab->addSymbol(absi->absoluteAtom(), ELF::SHN_ABS, absi->value());
+ }
for (const UndefinedAtom *a : file.undefined()) {
_symtab->addSymbol(a, ELF::SHN_UNDEF);
}
-
- for (const AbsoluteAtom *a : file.absolute()) {
- _symtab->addSymbol(a, ELF::SHN_ABS);
- }
}
template<support::endianness target_endianness,
@@ -2054,6 +2156,11 @@
_atomToAddressMap[ai->first] = (ai)->second.second;
}
}
+ /// build the atomToAddressMap that contains absolute symbols too
+ for (auto absi = _layout->absAtomsBegin(), abse = _layout->absAtomsEnd();
+ absi != abse; ++absi) {
+ _atomToAddressMap[absi->absoluteAtom()] = absi->value();
+ }
}
template<support::endianness target_endianness,
@@ -2099,9 +2206,66 @@
}
}
+/// \brief Add absolute symbols by default. These are linker added
+/// absolute symbols
template<support::endianness target_endianness,
std::size_t max_align,
bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+ ::addDefaultAtoms() {
+ _runtimeFile.addUndefinedAtom("_start");
+ _runtimeFile.addAbsoluteAtom("__bss_start");
+ _runtimeFile.addAbsoluteAtom("__bss_end");
+ _runtimeFile.addAbsoluteAtom("_end");
+ _runtimeFile.addAbsoluteAtom("end");
+}
+
+/// \brief Hook in lld to add CRuntime file
+template<support::endianness target_endianness,
+ std::size_t max_align,
+ bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+ ::addFiles(InputFiles &inputFiles) {
+ addDefaultAtoms();
+ inputFiles.prependFile(_runtimeFile);
+}
+
+/// Finalize the value of all the absolute symbols that we
+/// created
+template<support::endianness target_endianness,
+ std::size_t max_align,
+ bool is64Bits>
+void ELFExecutableWriter<target_endianness, max_align, is64Bits>
+ ::finalizeDefaultAtomValues() {
+ auto abse = _layout->absAtomsEnd();
+ auto bssStartAtomIter = _layout->findAbsoluteAtom("__bss_start");
+ auto bssEndAtomIter = _layout->findAbsoluteAtom("__bss_end");
+ auto underScoreEndAtomIter = _layout->findAbsoluteAtom("_end");
+ auto endAtomIter = _layout->findAbsoluteAtom("end");
+
+ if (bssStartAtomIter == abse ||
+ bssEndAtomIter == abse ||
+ underScoreEndAtomIter == abse ||
+ endAtomIter == abse)
+ assert(0 && "something has gone wrong with the ELFLayout");
+
+ auto phe = _programHeader->findProgramHeader(
+ llvm::ELF::PT_LOAD,
+ llvm::ELF::PF_W,
+ llvm::ELF::PF_X);
+
+ if (phe == _programHeader->end())
+ assert(0 && "something has gone wrong with the Program Header");
+
+ bssStartAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_filesz);
+ bssEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+ underScoreEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+ endAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
+}
+
+template<support::endianness target_endianness,
+ std::size_t max_align,
+ bool is64Bits>
error_code ELFExecutableWriter<target_endianness, max_align, is64Bits>
::writeFile(const lld::File &file, StringRef path) {
buildChunks(file);
@@ -2114,6 +2278,9 @@
_layout->assignFileOffsets();
_layout->assignVirtualAddress();
+ // Finalize the default value of symbols that the linker adds
+ finalizeDefaultAtomValues();
+
// Build the Atom To Address map for applying relocations
buildAtomToAddressMap();
Index: lib/ReaderWriter/ELF/ExecutableAtoms.h
===================================================================
--- lib/ReaderWriter/ELF/ExecutableAtoms.h (revision 0)
+++ lib/ReaderWriter/ELF/ExecutableAtoms.h (revision 0)
@@ -0,0 +1,103 @@
+//===- lib/ReaderWriter/ELF/ExecutableAtoms.h ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
+#define LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
+
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/ReaderWriter/WriterELF.h"
+#include "AtomsELF.h"
+
+namespace lld {
+namespace elf {
+
+/// \brief All atoms are owned by a File. To add linker specific atoms
+/// the atoms need to be inserted to a file called (CRuntimeFile) which
+/// are basically additional symbols required by libc and other runtime
+/// libraries part of executing a program. This class provides support
+/// for adding absolute symbols and undefined symbols
+template<llvm::support::endianness target_endianness,
+ std::size_t max_align,
+ bool is64Bits>
+class CRuntimeFile : public File {
+public:
+ typedef llvm::object::Elf_Sym_Impl<target_endianness, max_align, is64Bits> Elf_Sym;
+ CRuntimeFile(const WriterOptionsELF &options)
+ : File("C runtime")
+ { }
+
+ /// \brief add a global absolute atom
+ void addAbsoluteAtom(const StringRef symbolName) {
+ Elf_Sym *symbol = new(_allocator.Allocate<Elf_Sym>()) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_ABS;
+ symbol->setBindingAndType(llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STT_OBJECT);
+ symbol->st_other = llvm::ELF::STV_DEFAULT;
+ symbol->st_size = 0;
+ auto *newAtom = new (_allocator.Allocate<
+ ELFAbsoluteAtom<target_endianness, max_align, is64Bits> > ())
+ ELFAbsoluteAtom<target_endianness, max_align, is64Bits>(
+ *this, symbolName, symbol, -1);
+ _absoluteAtoms._atoms.push_back(newAtom);
+ }
+
+ /// \brief add an undefined atom
+ void addUndefinedAtom(const StringRef symbolName) {
+ Elf_Sym *symbol = new(_allocator.Allocate<Elf_Sym>()) Elf_Sym;
+ symbol->st_name = 0;
+ symbol->st_value = 0;
+ symbol->st_shndx = llvm::ELF::SHN_UNDEF;
+ symbol->st_other = llvm::ELF::STV_DEFAULT;
+ symbol->st_size = 0;
+ auto *newAtom = new (_allocator.Allocate<
+ ELFUndefinedAtom<target_endianness, max_align, is64Bits> > ())
+ ELFUndefinedAtom<target_endianness, max_align, is64Bits>(
+ *this, symbolName, symbol);
+ _undefinedAtoms._atoms.push_back(newAtom);
+ }
+
+ const atom_collection<DefinedAtom> &defined() const {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const {
+ return _absoluteAtoms;
+ }
+
+ // cannot add atoms to C Runtime file
+ virtual void addAtom(const Atom&) {
+ llvm_unreachable("cannot add atoms to C Runtime files");
+ }
+
+private:
+ llvm::BumpPtrAllocator _allocator;
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H_
Index: lib/Driver/LinkerInvocation.cpp
===================================================================
--- lib/Driver/LinkerInvocation.cpp (revision 171973)
+++ lib/Driver/LinkerInvocation.cpp (working copy)
@@ -72,11 +72,16 @@
_undefinesAreErrors = true;
}
} ro;
+
+ auto writer = target->getWriter();
+
+ // Give writer a chance to add files
+ writer->addFiles(inputs);
+
Resolver resolver(ro, inputs);
resolver.resolve();
File &merged = resolver.resultFile();
- auto writer = target->getWriter();
if (error_code ec = writer) {
llvm::errs() << "Failed to get writer: " << ec.message() << ".\n";
return;
More information about the llvm-commits
mailing list