diff options
| author | Peter Smith <peter.smith@linaro.org> | 2017-01-04 09:45:45 +0000 |
|---|---|---|
| committer | Peter Smith <peter.smith@linaro.org> | 2017-01-04 09:45:45 +0000 |
| commit | 97c6d78f3e7582ce717b24063e765a4246ce6f79 (patch) | |
| tree | b2d7d4a2ca91e9c02771e2e4a7b51cbf2c22b9f4 | |
| parent | 3c6ce733f5720b4e13eae85d9aa3ce87b2084f4a (diff) | |
| download | bcm5719-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.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/LTO.cpp | 15 | ||||
| -rw-r--r-- | lld/ELF/LTO.h | 2 | ||||
| -rw-r--r-- | lld/ELF/SymbolTable.cpp | 6 | ||||
| -rw-r--r-- | lld/ELF/Symbols.cpp | 12 | ||||
| -rw-r--r-- | lld/ELF/Symbols.h | 11 | ||||
| -rw-r--r-- | lld/ELF/Target.cpp | 7 | ||||
| -rw-r--r-- | lld/ELF/Thunks.cpp | 2 | ||||
| -rw-r--r-- | lld/test/ELF/arm-thumb-interwork-shared.s | 44 |
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 |

