summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Smith <peter.smith@linaro.org>2017-01-04 09:45:45 +0000
committerPeter Smith <peter.smith@linaro.org>2017-01-04 09:45:45 +0000
commit97c6d78f3e7582ce717b24063e765a4246ce6f79 (patch)
treeb2d7d4a2ca91e9c02771e2e4a7b51cbf2c22b9f4
parent3c6ce733f5720b4e13eae85d9aa3ce87b2084f4a (diff)
downloadbcm5719-llvm-97c6d78f3e7582ce717b24063e765a4246ce6f79.tar.gz
bcm5719-llvm-97c6d78f3e7582ce717b24063e765a4246ce6f79.zip
[ELF] Add support for thunks to undefined non-weak symbols
In a shared library an undefined symbol is implicitly imported. If the symbol is called as a function a PLT entry is generated for it. When the caller is a Thumb b.w a thunk to the PLT entry is needed as all PLT entries are in ARM state. This change allows undefined symbols to have thunks in the same way that shared symbols may have thunks. llvm-svn: 290951
-rw-r--r--lld/ELF/InputFiles.cpp2
-rw-r--r--lld/ELF/LTO.cpp15
-rw-r--r--lld/ELF/LTO.h2
-rw-r--r--lld/ELF/SymbolTable.cpp6
-rw-r--r--lld/ELF/Symbols.cpp12
-rw-r--r--lld/ELF/Symbols.h11
-rw-r--r--lld/ELF/Target.cpp7
-rw-r--r--lld/ELF/Thunks.cpp2
-rw-r--r--lld/test/ELF/arm-thumb-interwork-shared.s44
9 files changed, 85 insertions, 16 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 2a865992146..f4128c5096c 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -461,7 +461,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
return new (BAlloc)
- Undefined(Name, /*IsLocal=*/true, StOther, Type, this);
+ Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
Type, Value, Size, Sec, this);
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index a3d6a141a20..b342b6195f1 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -96,12 +96,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
-static void undefine(Symbol *S) {
- replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
- STV_DEFAULT, S->body()->Type, nullptr);
+template <class ELFT> static void undefine(Symbol *S) {
+ replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
+ STV_DEFAULT, S->body()->Type, nullptr);
}
-void BitcodeCompiler::add(BitcodeFile &F) {
+template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<Symbol *> Syms = F.getSymbols();
@@ -126,7 +126,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
R.VisibleToRegularObj =
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
if (R.Prevailing)
- undefine(Sym);
+ undefine<ELFT>(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
@@ -157,3 +157,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
}
return Ret;
}
+
+template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
+template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);
diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h
index b3d734f2d38..3cb763650e1 100644
--- a/lld/ELF/LTO.h
+++ b/lld/ELF/LTO.h
@@ -43,7 +43,7 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
- void add(BitcodeFile &F);
+ template <class ELFT> void add(BitcodeFile &F);
std::vector<InputFile *> compile();
private:
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 79097e176e6..f08fa6229c1 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -115,7 +115,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
// Compile bitcode files and replace bitcode symbols.
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
- LTO->add(*F);
+ LTO->add<ELFT>(*F);
for (InputFile *File : LTO->compile()) {
ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
@@ -256,7 +256,7 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
if (WasInserted) {
S->Binding = Binding;
- replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
+ replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
return S;
}
if (Binding != STB_WEAK) {
@@ -432,7 +432,7 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
if (S->VersionId == VER_NDX_LOCAL)
S->VersionId = VER_NDX_GLOBAL;
}
- if (WasInserted || isa<Undefined>(S->body())) {
+ if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
if (!S->isWeak())
F->IsUsed = true;
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index a2133f411c2..f168d37bdf0 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -173,6 +173,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
return DR->ThunkData->getVA();
if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
return S->ThunkData->getVA();
+ if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
+ return S->ThunkData->getVA();
fatal("getThunkVA() not supported for Symbol class\n");
}
@@ -232,8 +234,9 @@ template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
(Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
}
-Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type, InputFile *File)
+template <typename ELFT>
+Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type, InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
@@ -354,6 +357,11 @@ template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
+template class elf::Undefined<ELF32LE>;
+template class elf::Undefined<ELF32BE>;
+template class elf::Undefined<ELF64LE>;
+template class elf::Undefined<ELF64BE>;
+
template class elf::DefinedRegular<ELF32LE>;
template class elf::DefinedRegular<ELF32BE>;
template class elf::DefinedRegular<ELF64LE>;
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index c95241a5293..cbf8fa81a13 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -236,7 +236,7 @@ public:
const OutputSectionBase *Section;
};
-class Undefined : public SymbolBody {
+template <class ELFT> class Undefined : public SymbolBody {
public:
Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
InputFile *F);
@@ -245,6 +245,12 @@ public:
return S->kind() == UndefinedKind;
}
+ // If non-null the symbol has a Thunk that may be used as an alternative
+ // destination for callers of this Symbol. When linking a DSO undefined
+ // symbols are implicitly imported, the symbol lookup will be performed by
+ // the dynamic loader. A call to an undefined symbol will be given a PLT
+ // entry and on ARM this may need a Thunk if the caller is in Thumb state.
+ Thunk<ELFT> *ThunkData = nullptr;
InputFile *file() { return this->File; }
};
@@ -416,7 +422,8 @@ struct Symbol {
// ELFT, and we verify this with the static_asserts in replaceBody.
llvm::AlignedCharArrayUnion<
DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
- Undefined, SharedSymbol<llvm::object::ELF64LE>, LazyArchive, LazyObject>
+ Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
+ LazyArchive, LazyObject>
Body;
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index edae7c65c1b..d82e654b9c4 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -1730,8 +1730,11 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
const InputFile &File,
const SymbolBody &S) const {
- // If S is an undefined weak symbol we don't need a Thunk
- if (S.isUndefined())
+ // If S is an undefined weak symbol in an executable we don't need a Thunk.
+ // In a DSO calls to undefined symbols, including weak ones get PLT entries
+ // which may need a thunk.
+ if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
+ && !Config->Shared)
return Expr;
// A state change from ARM to Thumb and vice versa must go through an
// interworking thunk if the relocation type is not R_ARM_CALL or
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 34b630ac251..397a0ee6631 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -226,6 +226,8 @@ static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
Sym->ThunkData = T;
else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
Sym->ThunkData = T;
+ else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S))
+ Sym->ThunkData = T;
else
fatal("symbol not DefinedRegular or Shared");
}
diff --git a/lld/test/ELF/arm-thumb-interwork-shared.s b/lld/test/ELF/arm-thumb-interwork-shared.s
new file mode 100644
index 00000000000..ffd055e5b62
--- /dev/null
+++ b/lld/test/ELF/arm-thumb-interwork-shared.s
@@ -0,0 +1,44 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --shared -o %t.so
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t.so | FileCheck %s
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s -check-prefix=PLT
+// REQUIRES: arm
+ .syntax unified
+ .global sym1
+ .global elsewhere
+ .weak weakref
+sym1:
+ b.w elsewhere
+ b.w weakref
+
+// Check that we generate a thunk for an undefined symbol called via a plt
+// entry.
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: sym1:
+// CHECK: 1000: 00 f0 02 b8 b.w #4
+// CHECK-NEXT: 1004: 00 f0 06 b8 b.w #12
+// CHECK-NEXT: 1008: 40 f2 20 0c movw r12, #32
+// CHECK-NEXT: 100c: c0 f2 00 0c movt r12, #0
+// CHECK-NEXT: 1010: fc 44 add r12, pc
+// CHECK-NEXT: 1012: 60 47 bx r12
+// CHECK-NEXT: 1014: 40 f2 24 0c movw r12, #36
+// CHECK-NEXT: 1018: c0 f2 00 0c movt r12, #0
+// CHECK-NEXT: 101c: fc 44 add r12, pc
+// CHECK-NEXT: 101e: 60 47 bx r12
+
+// PLT: Disassembly of section .plt:
+// PLT-NEXT: .plt:
+// PLT: 1020: 04 e0 2d e5 str lr, [sp, #-4]!
+// PLT-NEXT: 1024: 04 e0 9f e5 ldr lr, [pc, #4]
+// PLT-NEXT: 1028: 0e e0 8f e0 add lr, pc, lr
+// PLT-NEXT: 102c: 08 f0 be e5 ldr pc, [lr, #8]!
+// PLT-NEXT: 1030: d0 1f 00 00
+// PLT-NEXT: 1034: 04 c0 9f e5 ldr r12, [pc, #4]
+// PLT-NEXT: 1038: 0f c0 8c e0 add r12, r12, pc
+// PLT-NEXT: 103c: 00 f0 9c e5 ldr pc, [r12]
+// PLT-NEXT: 1040: cc 1f 00 00
+// PLT-NEXT: 1044: 04 c0 9f e5 ldr r12, [pc, #4]
+// PLT-NEXT: 1048: 0f c0 8c e0 add r12, r12, pc
+// PLT-NEXT: 104c: 00 f0 9c e5 ldr pc, [r12]
+// PLT-NEXT: 1050: c0 1f 00 00
OpenPOWER on IntegriCloud