Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -461,7 +461,7 @@ 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(Name, /*IsLocal=*/true, StOther, Type, this); return new (BAlloc) DefinedRegular(Name, /*IsLocal=*/true, StOther, Type, Value, Size, Sec, this); Index: ELF/LTO.h =================================================================== --- ELF/LTO.h +++ ELF/LTO.h @@ -43,7 +43,7 @@ BitcodeCompiler(); ~BitcodeCompiler(); - void add(BitcodeFile &F); + template void add(BitcodeFile &F); std::vector compile(); private: Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -96,12 +96,12 @@ BitcodeCompiler::~BitcodeCompiler() = default; -static void undefine(Symbol *S) { - replaceBody(S, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type, nullptr); +template static void undefine(Symbol *S) { + replaceBody>(S, S->body()->getName(), /*IsLocal=*/false, + STV_DEFAULT, S->body()->Type, nullptr); } -void BitcodeCompiler::add(BitcodeFile &F) { +template void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector Syms = F.getSymbols(); @@ -126,7 +126,7 @@ R.VisibleToRegularObj = Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) - undefine(Sym); + undefine(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } @@ -157,3 +157,8 @@ } return Ret; } + +template void BitcodeCompiler::template add(BitcodeFile &); +template void BitcodeCompiler::template add(BitcodeFile &); +template void BitcodeCompiler::template add(BitcodeFile &); +template void BitcodeCompiler::template add(BitcodeFile &); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -115,7 +115,7 @@ // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) - LTO->add(*F); + LTO->add(*F); for (InputFile *File : LTO->compile()) { ObjectFile *Obj = cast>(File); @@ -256,7 +256,7 @@ insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File); if (WasInserted) { S->Binding = Binding; - replaceBody(S, Name, IsLocal, StOther, Type, File); + replaceBody>(S, Name, IsLocal, StOther, Type, File); return S; } if (Binding != STB_WEAK) { @@ -432,7 +432,7 @@ if (S->VersionId == VER_NDX_LOCAL) S->VersionId = VER_NDX_GLOBAL; } - if (WasInserted || isa(S->body())) { + if (WasInserted || isa>(S->body())) { replaceBody>(S, F, Name, Sym, Verdef); if (!S->isWeak()) F->IsUsed = true; Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -236,7 +236,7 @@ const OutputSectionBase *Section; }; -class Undefined : public SymbolBody { +template class Undefined : public SymbolBody { public: Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *F); @@ -245,6 +245,12 @@ 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 *ThunkData = nullptr; InputFile *file() { return this->File; } }; @@ -416,7 +422,8 @@ // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< DefinedCommon, DefinedRegular, DefinedSynthetic, - Undefined, SharedSymbol, LazyArchive, LazyObject> + Undefined, SharedSymbol, + LazyArchive, LazyObject> Body; SymbolBody *body() { return reinterpret_cast(Body.buffer); } Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -173,6 +173,8 @@ return DR->ThunkData->getVA(); if (const auto *S = dyn_cast>(this)) return S->ThunkData->getVA(); + if (const auto *S = dyn_cast>(this)) + return S->ThunkData->getVA(); fatal("getThunkVA() not supported for Symbol class\n"); } @@ -232,8 +234,9 @@ (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC); } -Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type, InputFile *File) +template +Undefined::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 uint64_t SymbolBody::template getSize() const; template uint64_t SymbolBody::template getSize() const; +template class elf::Undefined; +template class elf::Undefined; +template class elf::Undefined; +template class elf::Undefined; + template class elf::DefinedRegular; template class elf::DefinedRegular; template class elf::DefinedRegular; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -1730,8 +1730,11 @@ 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 Index: ELF/Thunks.cpp =================================================================== --- ELF/Thunks.cpp +++ ELF/Thunks.cpp @@ -226,6 +226,8 @@ Sym->ThunkData = T; else if (auto *Sym = dyn_cast>(&S)) Sym->ThunkData = T; + else if (auto *Sym = dyn_cast>(&S)) + Sym->ThunkData = T; else fatal("symbol not DefinedRegular or Shared"); } Index: test/ELF/arm-thumb-interwork-shared.s =================================================================== --- /dev/null +++ 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