forked from OSchip/llvm-project
Fix some confusion about what can be preempted.
For shared libraries we allow any weak undefined symbol to eventually be resolved, even if we never see a definition in another .so. This matches the behavior when handling other undefined symbols in a shared library. For executables, we require seeing a definition in a .so or resolve it to zero. This is also similar to how non weak symbols are handled. llvm-svn: 262017
This commit is contained in:
parent
31d315b349
commit
993f0273e3
|
@ -275,7 +275,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
|
|||
if (Target->needsPlt<ELFT>(Type, *Body)) {
|
||||
SymVA = Body->getPltVA<ELFT>();
|
||||
} else if (Target->needsGot(Type, *Body)) {
|
||||
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true))
|
||||
if (Config->EMachine == EM_MIPS && !canBePreempted(Body))
|
||||
// Under some conditions relocations against non-local symbols require
|
||||
// entries in the local part of MIPS GOT. In that case we need an entry
|
||||
// initialized by full address of the symbol.
|
||||
|
@ -289,7 +289,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
|
|||
continue;
|
||||
} else if (Target->isTlsDynRel(Type, *Body)) {
|
||||
continue;
|
||||
} else if (Target->isSizeRel(Type) && canBePreempted(Body, false)) {
|
||||
} else if (Target->isSizeRel(Type) && canBePreempted(Body)) {
|
||||
// A SIZE relocation is supposed to set a symbol size, but if a symbol
|
||||
// can be preempted, the size at runtime may be different than link time.
|
||||
// If that's the case, we leave the field alone rather than filling it
|
||||
|
|
|
@ -176,7 +176,7 @@ template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
// for detailed description:
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
// As the first approach, we can just store addresses for all symbols.
|
||||
if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
|
||||
if (Config->EMachine != EM_MIPS && canBePreempted(B))
|
||||
continue; // The dynamic linker will take care of it.
|
||||
uintX_t VA = B->getVA<ELFT>();
|
||||
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
|
||||
|
@ -926,7 +926,7 @@ elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
|
||||
// Returns true if a symbol can be replaced at load-time by a symbol
|
||||
// with the same name defined in other ELF executable or DSO.
|
||||
bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
|
||||
bool elf2::canBePreempted(const SymbolBody *Body) {
|
||||
if (!Body)
|
||||
return false; // Body is a local symbol.
|
||||
if (Body->isShared())
|
||||
|
@ -936,26 +936,14 @@ bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
|
|||
if (!Body->isWeak())
|
||||
return true;
|
||||
|
||||
// This is an horrible corner case. Ideally we would like to say that any
|
||||
// undefined symbol can be preempted so that the dynamic linker has a
|
||||
// chance of finding it at runtime.
|
||||
//
|
||||
// The problem is that the code sequence used to test for weak undef
|
||||
// functions looks like
|
||||
// if (func) func()
|
||||
// If the code is -fPIC the first reference is a load from the got and
|
||||
// everything works.
|
||||
// If the code is not -fPIC there is no reasonable way to solve it:
|
||||
// * A relocation writing to the text segment will fail (it is ro).
|
||||
// * A copy relocation doesn't work for functions.
|
||||
// * The trick of using a plt entry as the address would fail here since
|
||||
// the plt entry would have a non zero address.
|
||||
// Since we cannot do anything better, we just resolve the symbol to 0 and
|
||||
// don't produce a dynamic relocation.
|
||||
//
|
||||
// As an extra hack, assume that if we are producing a shared library the
|
||||
// user knows what he or she is doing and can handle a dynamic relocation.
|
||||
return Config->Shared || NeedsGot;
|
||||
// Ideally the static linker should see a definition for every symbol, but
|
||||
// shared object are normally allowed to have undefined references that the
|
||||
// static linker never sees a definition for.
|
||||
if (Config->Shared)
|
||||
return true;
|
||||
|
||||
// Otherwise, just resolve to 0.
|
||||
return false;
|
||||
}
|
||||
if (!Config->Shared)
|
||||
return false;
|
||||
|
|
|
@ -53,7 +53,7 @@ getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel,
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t Addend);
|
||||
|
||||
bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
|
||||
bool canBePreempted(const SymbolBody *Body);
|
||||
|
||||
bool isValidCIdentifier(StringRef S);
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
bool needsCopyRelImpl(uint32_t Type) const override;
|
||||
bool needsDynRelative(unsigned Type) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
uint64_t SA, uint64_t ZA = 0,
|
||||
uint8_t *PairedLoc = nullptr) const override;
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
bool needsCopyRelImpl(uint32_t Type) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
bool refersToGotEntry(uint32_t Type) const override;
|
||||
bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
uint64_t SA, uint64_t ZA = 0,
|
||||
uint8_t *PairedLoc = nullptr) const override;
|
||||
|
@ -165,7 +165,7 @@ public:
|
|||
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
|
||||
int32_t Index, unsigned RelOff) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
uint64_t SA, uint64_t ZA = 0,
|
||||
uint8_t *PairedLoc = nullptr) const override;
|
||||
|
@ -186,7 +186,7 @@ public:
|
|||
bool isRelRelative(uint32_t Type) const override;
|
||||
bool needsCopyRelImpl(uint32_t Type) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
uint64_t SA, uint64_t ZA = 0,
|
||||
uint8_t *PairedLoc = nullptr) const override;
|
||||
|
@ -222,7 +222,7 @@ public:
|
|||
void writeGotHeader(uint8_t *Buf) const override;
|
||||
bool needsCopyRelImpl(uint32_t Type) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
|
||||
bool needsPltImpl(uint32_t Type) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
uint64_t S, uint64_t ZA = 0,
|
||||
uint8_t *PairedLoc = nullptr) const override;
|
||||
|
@ -294,9 +294,7 @@ bool TargetInfo::isSizeRel(uint32_t Type) const { return false; }
|
|||
|
||||
bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; }
|
||||
|
||||
bool TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
||||
return false;
|
||||
}
|
||||
bool TargetInfo::needsPltImpl(uint32_t Type) const { return false; }
|
||||
|
||||
bool TargetInfo::refersToGotEntry(uint32_t Type) const { return false; }
|
||||
|
||||
|
@ -305,7 +303,7 @@ TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type,
|
|||
const SymbolBody &S) const {
|
||||
if (isGnuIFunc<ELFT>(S))
|
||||
return Plt_Explicit;
|
||||
if (needsPltImpl(Type, S))
|
||||
if (canBePreempted(&S) && needsPltImpl(Type))
|
||||
return Plt_Explicit;
|
||||
|
||||
// This handles a non PIC program call to function in a shared library.
|
||||
|
@ -401,7 +399,7 @@ bool X86TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
|
|||
Type == R_386_TLS_GOTIE)
|
||||
return Config->Shared;
|
||||
if (Type == R_386_TLS_IE)
|
||||
return canBePreempted(&S, true);
|
||||
return canBePreempted(&S);
|
||||
return Type == R_386_TLS_GD;
|
||||
}
|
||||
|
||||
|
@ -454,14 +452,14 @@ bool X86TargetInfo::needsCopyRelImpl(uint32_t Type) const {
|
|||
|
||||
bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
|
||||
if (S.IsTls && Type == R_386_TLS_GD)
|
||||
return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
|
||||
return Target->canRelaxTls(Type, &S) && canBePreempted(&S);
|
||||
if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
|
||||
return !canRelaxTls(Type, &S);
|
||||
return Type == R_386_GOT32 || needsPlt<ELF32LE>(Type, S);
|
||||
}
|
||||
|
||||
bool X86TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
||||
return Type == R_386_PLT32 && canBePreempted(&S, true);
|
||||
bool X86TargetInfo::needsPltImpl(uint32_t Type) const {
|
||||
return Type == R_386_PLT32;
|
||||
}
|
||||
|
||||
bool X86TargetInfo::isGotRelative(uint32_t Type) const {
|
||||
|
@ -527,9 +525,8 @@ bool X86TargetInfo::canRelaxTls(unsigned Type, const SymbolBody *S) const {
|
|||
if (Config->Shared || (S && !S->IsTls))
|
||||
return false;
|
||||
return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM ||
|
||||
Type == R_386_TLS_GD ||
|
||||
(Type == R_386_TLS_IE && !canBePreempted(S, true)) ||
|
||||
(Type == R_386_TLS_GOTIE && !canBePreempted(S, true));
|
||||
Type == R_386_TLS_GD || (Type == R_386_TLS_IE && !canBePreempted(S)) ||
|
||||
(Type == R_386_TLS_GOTIE && !canBePreempted(S));
|
||||
}
|
||||
|
||||
bool X86TargetInfo::needsDynRelative(unsigned Type) const {
|
||||
|
@ -541,7 +538,7 @@ unsigned X86TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|||
const SymbolBody *S) const {
|
||||
switch (Type) {
|
||||
case R_386_TLS_GD:
|
||||
if (canBePreempted(S, true))
|
||||
if (canBePreempted(S))
|
||||
relocateTlsGdToIe(Loc, BufEnd, P, SA);
|
||||
else
|
||||
relocateTlsGdToLe(Loc, BufEnd, P, SA);
|
||||
|
@ -725,7 +722,7 @@ bool X86_64TargetInfo::refersToGotEntry(uint32_t Type) const {
|
|||
|
||||
bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
|
||||
if (Type == R_X86_64_TLSGD)
|
||||
return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
|
||||
return Target->canRelaxTls(Type, &S) && canBePreempted(&S);
|
||||
if (Type == R_X86_64_GOTTPOFF)
|
||||
return !canRelaxTls(Type, &S);
|
||||
return refersToGotEntry(Type) || needsPlt<ELF64LE>(Type, S);
|
||||
|
@ -750,15 +747,8 @@ bool X86_64TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
|
|||
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
|
||||
}
|
||||
|
||||
bool X86_64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
||||
switch (Type) {
|
||||
default:
|
||||
return Plt_No;
|
||||
case R_X86_64_PLT32:
|
||||
if (canBePreempted(&S, true))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool X86_64TargetInfo::needsPltImpl(uint32_t Type) const {
|
||||
return Type == R_X86_64_PLT32;
|
||||
}
|
||||
|
||||
bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
|
||||
|
@ -785,7 +775,7 @@ bool X86_64TargetInfo::canRelaxTls(unsigned Type, const SymbolBody *S) const {
|
|||
return false;
|
||||
return Type == R_X86_64_TLSGD || Type == R_X86_64_TLSLD ||
|
||||
Type == R_X86_64_DTPOFF32 ||
|
||||
(Type == R_X86_64_GOTTPOFF && !canBePreempted(S, true));
|
||||
(Type == R_X86_64_GOTTPOFF && !canBePreempted(S));
|
||||
}
|
||||
|
||||
// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
|
||||
|
@ -902,7 +892,7 @@ unsigned X86_64TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd,
|
|||
relocateTlsIeToLe(Loc, BufEnd, P, SA);
|
||||
return 0;
|
||||
case R_X86_64_TLSGD: {
|
||||
if (canBePreempted(S, true))
|
||||
if (canBePreempted(S))
|
||||
relocateTlsGdToIe(Loc, BufEnd, P, SA);
|
||||
else
|
||||
relocateTlsGdToLe(Loc, BufEnd, P, SA);
|
||||
|
@ -1064,11 +1054,9 @@ bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool PPC64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
||||
bool PPC64TargetInfo::needsPltImpl(uint32_t Type) const {
|
||||
// These are function calls that need to be redirected through a PLT stub.
|
||||
if (Type == R_PPC64_REL24 && canBePreempted(&S, false))
|
||||
return true;
|
||||
return false;
|
||||
return Type == R_PPC64_REL24;
|
||||
}
|
||||
|
||||
bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
|
||||
|
@ -1330,7 +1318,7 @@ bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
||||
bool AArch64TargetInfo::needsPltImpl(uint32_t Type) const {
|
||||
switch (Type) {
|
||||
default:
|
||||
return false;
|
||||
|
@ -1338,9 +1326,7 @@ bool AArch64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
|
|||
case R_AARCH64_CONDBR19:
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_TSTBR14:
|
||||
if (canBePreempted(&S, true))
|
||||
return true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1477,13 +1463,13 @@ bool AArch64TargetInfo::canRelaxTls(unsigned Type, const SymbolBody *S) const {
|
|||
// an executable. And if the target is local it can also be fully relaxed to
|
||||
// Local-Exec.
|
||||
if (isTlsGlobalDynamicRel(Type))
|
||||
return !canBePreempted(S, true);
|
||||
return !canBePreempted(S);
|
||||
|
||||
// Initial-Exec relocs can be relaxed to Local-Exec if the target is a local
|
||||
// symbol.
|
||||
if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
|
||||
Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
|
||||
return !canBePreempted(S, true);
|
||||
return !canBePreempted(S);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1496,7 +1482,7 @@ unsigned AArch64TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd,
|
|||
case R_AARCH64_TLSDESC_LD64_LO12_NC:
|
||||
case R_AARCH64_TLSDESC_ADD_LO12_NC:
|
||||
case R_AARCH64_TLSDESC_CALL: {
|
||||
if (canBePreempted(S, true))
|
||||
if (canBePreempted(S))
|
||||
fatal("Unsupported TLS optimization");
|
||||
uint64_t X = S ? S->getVA<ELF64LE>() : SA;
|
||||
relocateTlsGdToLe(Type, Loc, BufEnd, P, X);
|
||||
|
@ -1707,11 +1693,8 @@ bool MipsTargetInfo<ELFT>::refersToGotEntry(uint32_t Type) const {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool MipsTargetInfo<ELFT>::needsPltImpl(uint32_t Type,
|
||||
const SymbolBody &S) const {
|
||||
if (Type == R_MIPS_26 && canBePreempted(&S, false))
|
||||
return true;
|
||||
return false;
|
||||
bool MipsTargetInfo<ELFT>::needsPltImpl(uint32_t Type) const {
|
||||
return Type == R_MIPS_26;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
private:
|
||||
virtual bool needsCopyRelImpl(uint32_t Type) const;
|
||||
virtual bool needsPltImpl(uint32_t Type, const SymbolBody &S) const;
|
||||
virtual bool needsPltImpl(uint32_t Type) const;
|
||||
};
|
||||
|
||||
uint64_t getPPC64TocBase();
|
||||
|
|
|
@ -281,7 +281,7 @@ static bool handleTlsRelocation(unsigned Type, SymbolBody *Body,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (!canBePreempted(Body, true))
|
||||
if (!canBePreempted(Body))
|
||||
return true;
|
||||
}
|
||||
return !Target->isTlsDynRel(Type, *Body);
|
||||
|
@ -335,7 +335,7 @@ void Writer<ELFT>::scanRelocs(
|
|||
Body, getAddend<ELFT>(RI)});
|
||||
|
||||
// MIPS has a special rule to create GOTs for local symbols.
|
||||
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true) &&
|
||||
if (Config->EMachine == EM_MIPS && !canBePreempted(Body) &&
|
||||
(Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16)) {
|
||||
// FIXME (simon): Do not add so many redundant entries.
|
||||
Out<ELFT>::Got->addMipsLocalEntry();
|
||||
|
@ -362,7 +362,7 @@ void Writer<ELFT>::scanRelocs(
|
|||
if (Body->isInPlt())
|
||||
continue;
|
||||
Out<ELFT>::Plt->addEntry(Body);
|
||||
bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
|
||||
bool CBP = canBePreempted(Body);
|
||||
if (Target->UseLazyBinding) {
|
||||
Out<ELFT>::GotPlt->addEntry(Body);
|
||||
Out<ELFT>::RelaPlt->addReloc(
|
||||
|
@ -419,7 +419,7 @@ void Writer<ELFT>::scanRelocs(
|
|||
continue;
|
||||
}
|
||||
|
||||
bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
|
||||
bool CBP = canBePreempted(Body);
|
||||
bool Dynrel = Config->Shared && !Target->isRelRelative(Type) &&
|
||||
!Target->isSizeRel(Type);
|
||||
if (CBP || Dynrel) {
|
||||
|
@ -452,7 +452,7 @@ void Writer<ELFT>::scanRelocs(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (canBePreempted(Body, /*NeedsGot=*/false)) {
|
||||
if (canBePreempted(Body)) {
|
||||
// We don't know anything about the finaly symbol. Just ask the dynamic
|
||||
// linker to handle the relocation for us.
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset,
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
.type sym1,@function
|
||||
.global sym1
|
||||
sym1:
|
||||
|
||||
.type sym2,@function
|
||||
.global sym2
|
||||
sym2:
|
||||
|
||||
.type sym3,@function
|
||||
.global sym3
|
||||
sym3:
|
|
@ -0,0 +1,5 @@
|
|||
.global bar
|
||||
bar:
|
||||
|
||||
.global weak
|
||||
weak:
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc-weak.s -o %t2.o
|
||||
// RUN: ld.lld -shared %t2.o -o %t2.so
|
||||
// RUN: ld.lld %t.o %t2.so -o %t
|
||||
// RUN: llvm-readobj -r %t | FileCheck %s
|
||||
|
@ -19,9 +19,12 @@ _start:
|
|||
.weak sym3
|
||||
.quad sym3
|
||||
|
||||
// Both gold and bfd ld will produce a relocation for sym1 and sym2 only. That
|
||||
// That seems odd. If the dynamic linker must get a chance to resolve sym1
|
||||
// and sym2, that should also be the case for sym3.
|
||||
.type sym4,@function
|
||||
.weak sym4
|
||||
.quad sym4
|
||||
|
||||
// Test that we produce dynamic relocation for every weak undefined symbol
|
||||
// we found.
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
|
||||
|
@ -29,5 +32,6 @@ _start:
|
|||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: Section ({{.*}}) .rela.plt {
|
||||
// CHECK-NEXT: 0x{{.*}} R_X86_64_JUMP_SLOT sym2 0x0
|
||||
// CHECK-NEXT: 0x{{.*}} R_X86_64_JUMP_SLOT sym3 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/shared.s -o %t2.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/plt-aarch64.s -o %t2.o
|
||||
// RUN: ld.lld -shared %t2.o -o %t2.so
|
||||
// RUN: ld.lld -shared %t.o %t2.so -o %t.so
|
||||
// RUN: ld.lld %t.o %t2.so -o %t.exe
|
||||
|
|
Loading…
Reference in New Issue