Introduce a flag to warn when ifunc symbols are used with text relocations.

Summary:
This patch adds a new flag, --warn-ifunc-textrel, to work around a glibc bug. When a code with ifunc symbols is used to produce an object file with text relocations, lld always succeeds. However, if that object file is linked using an old version of glibc, the resultant binary just crashes with segmentation fault when it is run (The bug is going to be corrected as of glibc 2.19).

Since there is no way to tell beforehand what library the object file will be linked against in the future, there does not seem to be a fool-proof way for lld to give an error only in cases where the binary will crash. So, with this change (dated 2018-09-25), lld starts to give a warning, contingent on a new command line flag that does not have a gnu counter part. The default value for --warn-ifunc-textrel is false, so lld behaviour will not change unless the user explicitly asks lld to give a warning. Users that link with a glibc library with version 2.19 or newer, or does not use ifunc symbols, or does not generate object files with text relocations do not need to take any action. Other users may consider to start passing warn-ifunc-textrel to lld to get early warnings.

Reviewers: ruiu, espindola

Reviewed By: ruiu

Subscribers: grimar, MaskRay, markj, emaste, arichardson, llvm-commits

Differential Revision: https://reviews.llvm.org/D52430

llvm-svn: 343628
This commit is contained in:
Ali Tamur 2018-10-02 20:30:22 +00:00
parent da0602c154
commit 63830b2794
6 changed files with 72 additions and 3 deletions

View File

@ -176,6 +176,7 @@ struct Configuration {
bool UseAndroidRelrTags = false;
bool WarnBackrefs;
bool WarnCommon;
bool WarnIfuncTextrel;
bool WarnMissingEntry;
bool WarnSymbolOrdering;
bool WriteAddends;

View File

@ -857,6 +857,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
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);

View File

@ -352,6 +352,10 @@ defm warn_common: B<"warn-common",
"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">;

View File

@ -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"
@ -979,12 +980,22 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// 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 "
"old version of glibc (glibc 2.28 and earlier). If this applies to "
"you, consider recompiling the object files without -fPIC and "
"without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
"turn off this warning." +
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.

View File

@ -446,6 +446,17 @@ This can be used to ensure linker invocation remains compatible with
traditional Unix-like linkers.
.It Fl -warn-common
Warn about duplicate common symbols.
.It Fl -warn-ifunc-textrel
Warn about using ifunc symbols in conjunction with text relocations.
Older versions of glibc library (2.28 and earlier) has a bug that causes
the segment that includes ifunc symbols to be marked as not executable when
they are relocated. As a result, although the program compiles and links
successfully, it gives segmentation fault when the instruction pointer reaches
an ifunc symbol. Use -warn-ifunc-textrel to let lld give a warning, if the
code may include ifunc symbols, may do text relocations and be linked with
an older glibc version. Otherwise, there is no need to use it, as the default
value does not give a warning. This flag has been introduced in late 2018,
has no counter part in ld and gold linkers, and may be removed in the future.
.It Fl -warn-unresolved-symbols
Report unresolved symbols as warnings.
.It Fl -whole-archive

40
lld/test/ELF/textrel.s Normal file
View File

@ -0,0 +1,40 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu %s -o %t.o
# Without --warn-text-ifunc, lld should run fine:
# RUN: ld.lld -z notext %t.o -o %t2
# With --warn-text-ifunc, lld should run with warnings:
# RUN: ld.lld --warn-ifunc-textrel -z notext %t.o -o /dev/null 2>&1 | FileCheck %s
# CHECK: using ifunc symbols when text relocations are allowed may produce
# CHECK-SAME: a binary that will segfault, if the object file is linked with
# CHECK-SAME: old version of glibc (glibc 2.28 and earlier). If this applies to
# CHECK-SAME: you, consider recompiling the object files without -fPIC and
# CHECK-SAME: without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to
# CHECK-SAME: turn off this warning.
# CHECK: >>> defined in {{.*}}
# CHECK: >>> referenced by {{.*}}:(.text+0x8)
# Without text relocations, lld should run fine:
# RUN: ld.lld --fatal-warnings %t.o -o /dev/null
.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 _start
.type _start,@function
main:
callq a_func
retq