Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -177,6 +177,7 @@ bool WarnCommon; bool WarnMissingEntry; bool WarnSymbolOrdering; + bool WarnIfuncTextrel; bool WriteAddends; bool ZCombreloc; bool ZCopyreloc; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -829,6 +829,8 @@ Config->WarnBackrefs = Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); + Config->WarnIfuncTextrel = + Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); Config->WarnSymbolOrdering = Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -348,6 +348,10 @@ "Warn about duplicate common symbols", "Do not warn about duplicate common symbols (default)">; +defm warn_ifunc_textrel: B<"warn-ifunc-textrel", + "Warn about using IFunc symbols with text relocations", + "Do not warn about using IFunc symbols with text relocations (default)">; + defm warn_symbol_ordering: B<"warn-symbol-ordering", "Warn about problems with the symbol ordering file (default)", "Do not warn about problems with the symbol ordering file">; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -50,6 +50,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/SmallSet.h" @@ -980,12 +981,19 @@ // all dynamic symbols that can be resolved within the executable will // actually be resolved that way at runtime, because the main exectuable // is always at the beginning of a search list. We can leverage that fact. - if (Sym.isGnuIFunc()) + if (Sym.isGnuIFunc()) { + if (!Config->ZText && Config->WarnIfuncTextrel) { + warn("using IFUNC symbols when text relocations are allowed may produce " + "a binary that will segfault, if the object file is linked with " + "glibc. Consider recompiling the object files without -fPIC and " + "without '-Wl,-z,notext' option: " + getLocation(Sec, Sym, Offset)); + } Expr = toPlt(Expr); - else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) { Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); - else if (!Sym.IsPreemptible) + } else if (!Sym.IsPreemptible) { Expr = fromPlt(Expr); + } // This relocation does not require got entry, but it is relative to got and // needs it to be created. Here we request for that. Index: test/ELF/textrel.s =================================================================== --- /dev/null +++ test/ELF/textrel.s @@ -0,0 +1,39 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu %s -o %t.o + +# Without --warn-text-ifunc, ld should run fine: +# RUN: ld.lld --entry=main -z notext %t.o -o %t2 + +# With --warn-text-ifunc, ld should run with warnings: +# RUN: ld.lld --warn-ifunc-textrel --entry=main -z notext %t.o -o /dev/null 2>&1 +# | FileCheck %s --check-prefix=warning +# CHECK: warning: Using IFUNC symbols when text relocations are allowed may + +# With --fatal-warnings, ld should fail with the error message: +# RUN: not ld.lld --entry=main --warn-ifunc-textrel --fatal-warnings -z notext +# %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=error +# CHECK: error: Using IFUNC symbols when text relocations are allowed may + +# Without text relocations, ld should run fine: +# RUN: ld.lld --entry=main --fatal-warnings %t.o -o /dev/null 2>&1 + +.text +.globl a_func_impl +a_func_impl: + nop + +.globl selector +.type selector,@function +selector: + movl $a_func_impl, %eax + retq + +.globl a_func +.type a_func,@gnu_indirect_function +.set a_func, selector + +.globl main +.type main,@function +main: + callq a_func + retq