forked from OSchip/llvm-project
[LinkerScript] Handle symbols defined in linker scripts
Puts symbols defined in linker script expressions in a runtime file that is added as input to the resolver, making the input object files see symbols defined in linker scripts. http://reviews.llvm.org/D8263 llvm-svn: 232409
This commit is contained in:
parent
18e92078f2
commit
01d73c9678
|
@ -306,6 +306,7 @@ public:
|
|||
void setUndefinesResolver(std::unique_ptr<File> resolver);
|
||||
|
||||
script::Sema &linkerScriptSema() { return _linkerScriptSema; }
|
||||
const script::Sema &linkerScriptSema() const { return _linkerScriptSema; }
|
||||
|
||||
private:
|
||||
ELFLinkingContext() = delete;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
@ -1264,6 +1265,14 @@ public:
|
|||
/// update our symbol table with new symbols calculated in this expression.
|
||||
std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos);
|
||||
|
||||
/// Retrieve the set of symbols defined in linker script expressions.
|
||||
const llvm::StringSet<> &getScriptDefinedSymbols() const;
|
||||
|
||||
/// Queries the linker script symbol table for the value of a given symbol.
|
||||
/// This function must be called after linker script expressions evaluation
|
||||
/// has been performed (by calling evalExpr() for all expressions).
|
||||
uint64_t getLinkerScriptExprValue(StringRef name) const;
|
||||
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
|
@ -1370,6 +1379,7 @@ private:
|
|||
mutable std::unordered_map<SectionKey, int, SectionKeyHash, SectionKeyEq>
|
||||
_cacheSectionOrder, _cacheExpressionOrder;
|
||||
llvm::DenseSet<int> _deliveredExprs;
|
||||
mutable llvm::StringSet<> _definedSymbols;
|
||||
|
||||
Expression::SymbolTableTy _symbolTable;
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ protected:
|
|||
unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override;
|
||||
|
||||
void processUndefinedSymbol(StringRef symName,
|
||||
CRuntimeFile<ELFT> &file) const override;
|
||||
RuntimeFile<ELFT> &file) const override;
|
||||
private:
|
||||
ARMLinkingContext &_context;
|
||||
ARMTargetLayout<ELFT> &_armLayout;
|
||||
|
@ -83,7 +83,7 @@ unique_bump_ptr<SymbolTable<ELFT>>
|
|||
|
||||
template <class ELFT>
|
||||
void ARMExecutableWriter<ELFT>::processUndefinedSymbol(
|
||||
StringRef symName, CRuntimeFile<ELFT> &file) const {
|
||||
StringRef symName, RuntimeFile<ELFT> &file) const {
|
||||
if (symName == _gotSymbol) {
|
||||
file.addAbsoluteAtom(_gotSymbol);
|
||||
} else if (symName.startswith("__exidx")) {
|
||||
|
|
|
@ -27,7 +27,7 @@ class DynamicLibraryWriter : public OutputELFWriter<ELFT> {
|
|||
public:
|
||||
DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
|
||||
: OutputELFWriter<ELFT>(context, layout),
|
||||
_runtimeFile(new CRuntimeFile<ELFT>(context)) {}
|
||||
_runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
|
||||
|
||||
protected:
|
||||
virtual void buildDynamicSymbolTable(const File &file);
|
||||
|
@ -36,7 +36,7 @@ protected:
|
|||
virtual void finalizeDefaultAtomValues();
|
||||
|
||||
protected:
|
||||
std::unique_ptr<CRuntimeFile<ELFT> > _runtimeFile;
|
||||
std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -430,14 +430,14 @@ protected:
|
|||
};
|
||||
|
||||
/// \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
|
||||
/// the atoms need to be inserted to a file called (RuntimeFile) 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 <class ELFT> class CRuntimeFile : public ELFFile<ELFT> {
|
||||
template <class ELFT> class RuntimeFile : public ELFFile<ELFT> {
|
||||
public:
|
||||
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
CRuntimeFile(ELFLinkingContext &context, StringRef name = "C runtime")
|
||||
RuntimeFile(ELFLinkingContext &context, StringRef name)
|
||||
: ELFFile<ELFT>(name, context) {}
|
||||
|
||||
/// \brief add a global absolute atom
|
||||
|
@ -470,7 +470,7 @@ public:
|
|||
return *newAtom;
|
||||
}
|
||||
|
||||
// cannot add atoms to C Runtime file
|
||||
// cannot add atoms to Runtime file
|
||||
virtual void addAtom(const Atom &) {
|
||||
llvm_unreachable("cannot add atoms to Runtime files");
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class ExecutableWriter : public OutputELFWriter<ELFT> {
|
|||
public:
|
||||
ExecutableWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout)
|
||||
: OutputELFWriter<ELFT>(context, layout),
|
||||
_runtimeFile(new CRuntimeFile<ELFT>(context)) {}
|
||||
_runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {}
|
||||
|
||||
protected:
|
||||
virtual void buildDynamicSymbolTable(const File &file);
|
||||
|
@ -41,7 +41,7 @@ protected:
|
|||
}
|
||||
|
||||
unique_bump_ptr<InterpSection<ELFT>> _interpSection;
|
||||
std::unique_ptr<CRuntimeFile<ELFT> > _runtimeFile;
|
||||
std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -80,6 +80,7 @@ void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
|
|||
/// absolute symbols
|
||||
template<class ELFT>
|
||||
void ExecutableWriter<ELFT>::addDefaultAtoms() {
|
||||
OutputELFWriter<ELFT>::addDefaultAtoms();
|
||||
_runtimeFile->addUndefinedAtom(this->_context.entrySymbolName());
|
||||
_runtimeFile->addAbsoluteAtom("__bss_start");
|
||||
_runtimeFile->addAbsoluteAtom("__bss_end");
|
||||
|
@ -124,6 +125,7 @@ template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
|
|||
/// Finalize the value of all the absolute symbols that we
|
||||
/// created
|
||||
template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
|
||||
OutputELFWriter<ELFT>::finalizeDefaultAtomValues();
|
||||
auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start");
|
||||
auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end");
|
||||
auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end");
|
||||
|
|
|
@ -18,10 +18,10 @@ typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType;
|
|||
class HexagonLinkingContext;
|
||||
|
||||
template <class HexagonELFType> class HexagonRuntimeFile
|
||||
: public CRuntimeFile<HexagonELFType> {
|
||||
: public RuntimeFile<HexagonELFType> {
|
||||
public:
|
||||
HexagonRuntimeFile(HexagonLinkingContext &context)
|
||||
: CRuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {}
|
||||
: RuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {}
|
||||
};
|
||||
} // elf
|
||||
} // lld
|
||||
|
|
|
@ -87,10 +87,10 @@ private:
|
|||
|
||||
/// \brief Mips Runtime file.
|
||||
template <class ELFType>
|
||||
class MipsRuntimeFile final : public CRuntimeFile<ELFType> {
|
||||
class MipsRuntimeFile final : public RuntimeFile<ELFType> {
|
||||
public:
|
||||
MipsRuntimeFile(MipsLinkingContext &ctx)
|
||||
: CRuntimeFile<ELFType>(ctx, "Mips runtime file") {}
|
||||
: RuntimeFile<ELFType>(ctx, "Mips runtime file") {}
|
||||
};
|
||||
|
||||
/// \brief Auxiliary class holds relocation's names table.
|
||||
|
|
|
@ -33,14 +33,14 @@ template <class ELFT> class TargetLayout;
|
|||
namespace {
|
||||
|
||||
template<class ELFT>
|
||||
class SymbolFile : public CRuntimeFile<ELFT> {
|
||||
class SymbolFile : public RuntimeFile<ELFT> {
|
||||
public:
|
||||
SymbolFile(ELFLinkingContext &context)
|
||||
: CRuntimeFile<ELFT>(context, "Dynamic absolute symbols"),
|
||||
: RuntimeFile<ELFT>(context, "Dynamic absolute symbols"),
|
||||
_atomsAdded(false) {}
|
||||
|
||||
Atom *addAbsoluteAtom(StringRef symbolName) override {
|
||||
auto *a = CRuntimeFile<ELFT>::addAbsoluteAtom(symbolName);
|
||||
auto *a = RuntimeFile<ELFT>::addAbsoluteAtom(symbolName);
|
||||
if (a) _atomsAdded = true;
|
||||
return a;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ private:
|
|||
|
||||
template<class ELFT>
|
||||
class DynamicSymbolFile : public SimpleArchiveLibraryFile {
|
||||
typedef std::function<void(StringRef, CRuntimeFile<ELFT> &)> Resolver;
|
||||
typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver;
|
||||
public:
|
||||
DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver)
|
||||
: SimpleArchiveLibraryFile("Dynamically added runtime symbols"),
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
typedef Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
typedef Elf_Dyn_Impl<ELFT> Elf_Dyn;
|
||||
|
||||
OutputELFWriter(const ELFLinkingContext &context, TargetLayout<ELFT> &layout);
|
||||
OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout);
|
||||
|
||||
protected:
|
||||
// build the sections that need to be created
|
||||
|
@ -141,13 +141,13 @@ protected:
|
|||
virtual void assignSectionsWithNoSegments();
|
||||
|
||||
// Add default atoms that need to be present in the output file
|
||||
virtual void addDefaultAtoms() = 0;
|
||||
virtual void addDefaultAtoms();
|
||||
|
||||
// Add any runtime files and their atoms to the output
|
||||
bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
|
||||
// Finalize the default atom values
|
||||
virtual void finalizeDefaultAtomValues() = 0;
|
||||
virtual void finalizeDefaultAtomValues();
|
||||
|
||||
// This is called by the write section to apply relocations
|
||||
uint64_t addressOfAtom(const Atom *atom) override {
|
||||
|
@ -180,11 +180,11 @@ protected:
|
|||
|
||||
/// \brief Process undefined symbols that left after resolution step.
|
||||
virtual void processUndefinedSymbol(StringRef symName,
|
||||
CRuntimeFile<ELFT> &file) const {}
|
||||
RuntimeFile<ELFT> &file) const {}
|
||||
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
|
||||
const ELFLinkingContext &_context;
|
||||
ELFLinkingContext &_context;
|
||||
TargetHandler<ELFT> &_targetHandler;
|
||||
|
||||
typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
|
||||
|
@ -205,6 +205,7 @@ protected:
|
|||
unique_bump_ptr<HashSection<ELFT>> _hashTable;
|
||||
llvm::StringSet<> _soNeeded;
|
||||
/// @}
|
||||
std::unique_ptr<RuntimeFile<ELFT>> _scriptFile;
|
||||
|
||||
private:
|
||||
static StringRef maybeGetSOName(Node *node);
|
||||
|
@ -214,10 +215,11 @@ private:
|
|||
// OutputELFWriter
|
||||
//===----------------------------------------------------------------------===//
|
||||
template <class ELFT>
|
||||
OutputELFWriter<ELFT>::OutputELFWriter(const ELFLinkingContext &context,
|
||||
OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &context,
|
||||
TargetLayout<ELFT> &layout)
|
||||
: _context(context), _targetHandler(context.getTargetHandler<ELFT>()),
|
||||
_layout(layout) {}
|
||||
_layout(layout),
|
||||
_scriptFile(new RuntimeFile<ELFT>(context, "Linker script runtime")) {}
|
||||
|
||||
template <class ELFT>
|
||||
void OutputELFWriter<ELFT>::buildChunks(const File &file) {
|
||||
|
@ -363,20 +365,41 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
|
|||
_shdrtab->updateSection(section);
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputELFWriter<ELFT>::addDefaultAtoms() {
|
||||
const llvm::StringSet<> &symbols =
|
||||
_context.linkerScriptSema().getScriptDefinedSymbols();
|
||||
for (auto &sym : symbols)
|
||||
_scriptFile->addAbsoluteAtom(sym.getKey());
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool OutputELFWriter<ELFT>::createImplicitFiles(
|
||||
std::vector<std::unique_ptr<File>> &) {
|
||||
std::vector<std::unique_ptr<File>> &result) {
|
||||
// Add the virtual archive to resolve undefined symbols.
|
||||
// The file will be added later in the linking context.
|
||||
auto callback = [this](StringRef sym, CRuntimeFile<ELFT> &file) {
|
||||
auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) {
|
||||
processUndefinedSymbol(sym, file);
|
||||
};
|
||||
auto &ctx = const_cast<ELFLinkingContext &>(_context);
|
||||
ctx.setUndefinesResolver(
|
||||
llvm::make_unique<DynamicSymbolFile<ELFT>>(ctx, std::move(callback)));
|
||||
// Add script defined symbols
|
||||
result.push_back(std::move(_scriptFile));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() {
|
||||
const llvm::StringSet<> &symbols =
|
||||
_context.linkerScriptSema().getScriptDefinedSymbols();
|
||||
for (auto &sym : symbols) {
|
||||
uint64_t res =
|
||||
_context.linkerScriptSema().getLinkerScriptExprValue(sym.getKey());
|
||||
auto a = _layout.findAbsoluteAtom(sym.getKey());
|
||||
(*a)->_virtualAddr = res;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
|
||||
_elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_context));
|
||||
_programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_context));
|
||||
|
|
|
@ -2232,6 +2232,28 @@ std::error_code Sema::evalExpr(const SymbolAssignment *assgn,
|
|||
return std::error_code();
|
||||
}
|
||||
|
||||
const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const {
|
||||
// Do we have cached results?
|
||||
if (!_definedSymbols.empty())
|
||||
return _definedSymbols;
|
||||
|
||||
// Populate our defined set and return it
|
||||
for (auto cmd : _layoutCommands)
|
||||
if (auto sa = dyn_cast<SymbolAssignment>(cmd)) {
|
||||
StringRef symbol = sa->symbol();
|
||||
if (!symbol.empty() && symbol != ".")
|
||||
_definedSymbols.insert(symbol);
|
||||
}
|
||||
|
||||
return _definedSymbols;
|
||||
}
|
||||
|
||||
uint64_t Sema::getLinkerScriptExprValue(StringRef name) const {
|
||||
auto it = _symbolTable.find(name);
|
||||
assert (it != _symbolTable.end() && "Invalid symbol name!");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void Sema::dump() const {
|
||||
raw_ostream &os = llvm::outs();
|
||||
os << "Linker script semantics dump\n";
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
OSABI: ELFOSABI_GNU
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: B80100000048C7C70100000048C7C60000000048C7C20E0000000F05C3E8DEFFFFFFB83C0000000F05C3
|
||||
- Name: .rela.text
|
||||
Type: SHT_RELA
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000008
|
||||
Info: .text
|
||||
Relocations:
|
||||
- Offset: 0x000000000000000F
|
||||
Symbol: .data
|
||||
Type: R_X86_64_32S
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: 48656C6C6F2C20576F726C64210A00
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: ''
|
||||
Symbols:
|
||||
Local:
|
||||
- Name: main
|
||||
Section: .text
|
||||
- Name: msg
|
||||
Section: .data
|
||||
- Name: .text
|
||||
Type: STT_SECTION
|
||||
Section: .text
|
||||
- Name: .data
|
||||
Type: STT_SECTION
|
||||
Section: .data
|
||||
- Name: .bss
|
||||
Type: STT_SECTION
|
||||
Section: .bss
|
||||
Global:
|
||||
- Name: _start
|
||||
Section: .text
|
||||
Value: 0x000000000000001D
|
||||
...
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
We test whether we can define symbols in a linker script and have them exported
|
||||
to the output file symbol table.
|
||||
|
||||
This test uses a single X86-64 input object, simple.o, created with the
|
||||
following X86-64 assembly code:
|
||||
|
||||
*** simple.S:
|
||||
|
||||
(command line clang -c simple.S -o simple.o)
|
||||
|
||||
.text
|
||||
main:
|
||||
mov $1, %eax
|
||||
movq $1, %rdi
|
||||
movq $msg, %rsi
|
||||
movq $14, %rdx
|
||||
syscall
|
||||
ret
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
call main
|
||||
mov $60, %eax
|
||||
syscall
|
||||
ret
|
||||
|
||||
.data
|
||||
msg: .asciz "Hello, World!\n"
|
||||
|
||||
|
||||
We use the following linker script for this test:
|
||||
*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x500000;
|
||||
.text : { *(.text) }
|
||||
MYSTRING = .;
|
||||
.data : { *(.data) }
|
||||
}
|
||||
|
||||
/*
|
||||
RUN: mkdir -p %T
|
||||
RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%T/simple.o
|
||||
|
||||
RUN: lld -flavor gnu -target x86_64 -T %s %T/simple.o -static -o %t1
|
||||
RUN: llvm-readobj -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
|
||||
|
||||
CHECKSYMS: Name: MYSTRING
|
||||
CHECKSYMS-NEXT: Value: 0x501000
|
||||
*/
|
Loading…
Reference in New Issue