Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -103,6 +103,22 @@ return X86II::MO_GOTOFF; } +static bool shouldAssumeGlobalReferenceLocal(const X86Subtarget *ST, + const TargetMachine &TM, + const Module &M, + const GlobalValue *GV) { + if (!TM.shouldAssumeDSOLocal(M, GV)) + return false; + // A weak reference can end up being 0. If the code can be more that 4g away + // from zero and we are using the small code model we have to treat it as non + // local. + if (GV && GV->hasExternalWeakLinkage() && + TM.getCodeModel() == CodeModel::Small && TM.isPositionIndependent() && + ST->isTargetELF()) + return false; + return true; +} + unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV, const Module &M) const { // Large model never uses stubs. @@ -122,7 +138,7 @@ } } - if (TM.shouldAssumeDSOLocal(M, GV)) + if (shouldAssumeGlobalReferenceLocal(this, TM, M, GV)) return classifyLocalReference(GV); if (isTargetCOFF()) Index: test/CodeGen/X86/weak-undef.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/weak-undef.ll @@ -0,0 +1,45 @@ +; RUN: llc < %s -relocation-model=pic -mtriple=x86_64-pc-linux | FileCheck %s + +@foo1 = extern_weak hidden global i32, align 4 +define i32* @bar1() { + ret i32* @foo1 +} +; CHECK: bar1: +; CHECK: movq foo1@GOTPCREL(%rip), %rax + +@foo2 = external hidden global i32, align 4 +define i32* @bar2() { + ret i32* @foo2 +} +; CHECK: bar2: +; CHECK: leaq foo2(%rip), %rax + +declare extern_weak hidden void @foo3() +define void @bar3() { + call void @foo3() + ret void +} +; CHECK: bar3: +; CHECK: callq foo3 + +declare external hidden void @foo4() +define void @bar4() { + call void @foo4() + ret void +} +; CHECK: bar4: +; CHECK: callq foo4 + +declare extern_weak hidden i32 @foo5() +define i32()* @bar5() { + ret i32()* @foo5 +} +; CHECK: bar5: +; CHECK: movq foo5@GOTPCREL(%rip), %rax + +declare external hidden i32 @foo6() +define i32()* @bar6() { + ret i32()* @foo6 +} +; CHECK: bar6: +; CHECK: leaq foo6(%rip), %rax