From e8f3b0782a44ac27c4a53969d66556f29af4bdc2 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Tue, 13 Mar 2018 23:06:19 +0000 Subject: [PATCH] [LTO/gold] Support --wrap Summary: Utilize new gold plugin api interface for obtaining --wrap option arguments, and LTO API handling (added for --wrap support in lld LTO), to mark symbols so that LTO does not optimize them inappropriately. Note the test cases will be in a new gold test subdirectory that is dependent on the next release of gold which will contain the new interfaces. Reviewers: pcc, tmsriram Subscribers: mehdi_amini, llvm-commits, inglorion Differential Revision: https://reviews.llvm.org/D44235 llvm-svn: 327459 --- llvm/test/tools/gold/X86/v1.16/Inputs/wrap-bar.ll | 14 ++++++ llvm/test/tools/gold/X86/v1.16/lit.local.cfg | 28 ++++++++++++ llvm/test/tools/gold/X86/v1.16/wrap-1.ll | 42 +++++++++++++++++ llvm/test/tools/gold/X86/v1.16/wrap-2.ll | 55 +++++++++++++++++++++++ llvm/tools/gold/gold-plugin.cpp | 35 +++++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 llvm/test/tools/gold/X86/v1.16/Inputs/wrap-bar.ll create mode 100644 llvm/test/tools/gold/X86/v1.16/lit.local.cfg create mode 100644 llvm/test/tools/gold/X86/v1.16/wrap-1.ll create mode 100644 llvm/test/tools/gold/X86/v1.16/wrap-2.ll diff --git a/llvm/test/tools/gold/X86/v1.16/Inputs/wrap-bar.ll b/llvm/test/tools/gold/X86/v1.16/Inputs/wrap-bar.ll new file mode 100644 index 0000000..407ebfb --- /dev/null +++ b/llvm/test/tools/gold/X86/v1.16/Inputs/wrap-bar.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define hidden void @bar() { + ret void +} + +define hidden void @__real_bar() { + ret void +} + +define hidden void @__wrap_bar() { + ret void +} diff --git a/llvm/test/tools/gold/X86/v1.16/lit.local.cfg b/llvm/test/tools/gold/X86/v1.16/lit.local.cfg new file mode 100644 index 0000000..9dbf14be --- /dev/null +++ b/llvm/test/tools/gold/X86/v1.16/lit.local.cfg @@ -0,0 +1,28 @@ +import re +import subprocess + +def is_gold_v1_16_linker_available(): + + if not config.gold_executable: + return False + try: + ld_cmd = subprocess.Popen([config.gold_executable, '-v'], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + ld_out, _ = ld_cmd.communicate() + ld_out = ld_out.decode() + except: + return False + + match = re.search(r'GNU gold \(.*\) (\d+)\.(\d+)', ld_out) + if not match: + return False + major = int(match.group(1)) + minor = int(match.group(2)) + if major < 1 or (major == 1 and minor < 16): + return False + + return True + +if not is_gold_v1_16_linker_available(): + config.unsupported = True diff --git a/llvm/test/tools/gold/X86/v1.16/wrap-1.ll b/llvm/test/tools/gold/X86/v1.16/wrap-1.ll new file mode 100644 index 0000000..5ea83b0 --- /dev/null +++ b/llvm/test/tools/gold/X86/v1.16/wrap-1.ll @@ -0,0 +1,42 @@ +; LTO +; RUN: llvm-as %s -o %t.o +; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext %t.o -o %t.out -wrap=bar -plugin-opt=save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext %t.o -o %t.out -wrap=bar -plugin-opt=save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + +; CHECK: Name: __wrap_bar +; CHECK-NEXT: Value: +; CHECK-NEXT: Size: +; CHECK-NEXT: Binding: Global +; CHECK-NEXT: Type: Function + +; Make sure that the 'r' (linker redefined) bit is set for bar and __real_bar +; in the resolutions file, and that the 'x' (visible to regular obj) bit is set +; for bar and __wrap_bar. +; RESOLS: ,bar,lxr +; RESOLS: ,__wrap_bar,plx +; RESOLS: ,__real_bar,plr + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() + +define void @_start() { + call void @bar() + ret void +} + +define void @__wrap_bar() { + ret void +} + +define void @__real_bar() { + ret void +} diff --git a/llvm/test/tools/gold/X86/v1.16/wrap-2.ll b/llvm/test/tools/gold/X86/v1.16/wrap-2.ll new file mode 100644 index 0000000..7c1d95d --- /dev/null +++ b/llvm/test/tools/gold/X86/v1.16/wrap-2.ll @@ -0,0 +1,55 @@ +; LTO +; This doesn't currently work with gold, because it does not apply defsym +; renaming to symbols in the same module (apparently by design for consistency +; with GNU ld). Because regular LTO hands back a single object file to gold, +; it doesn't perform the desired defsym renaming. This isn't an issue with +; ThinLTO which hands back multiple native objects to gold. For regular +; LTO defsym handling, gold will need a fix (not the gold plugin). +; RUN-TODO: llvm-as %s -o %t.o +; RUN-TODO: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o +; RUN-TODO: %gold -plugin %llvmshlibdir/LLVMgold%shlibext %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN-TODO: llvm-objdump -d %t.so | FileCheck %s +; RUN-TODO: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o +; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN +; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + +; Make sure that calls in foo() are not eliminated and that bar is +; routed to __wrap_bar and __real_bar is routed to bar. + +; CHECK: foo: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq{{.*}}<__wrap_bar> +; CHECK-NEXT: callq{{.*}} + +; THIN: foo: +; THIN-NEXT: pushq %rax +; THIN-NEXT: callq{{.*}}<__wrap_bar> +; THIN-NEXT: popq %rax +; THIN-NEXT: jmp{{.*}} + +; Check that bar and __wrap_bar retain their original binding. +; BIND: Name: bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local +; BIND: Name: __wrap_bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() +declare void @__real_bar() + +define void @foo() { + call void @bar() + call void @__real_bar() + ret void +} diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index 19804a1..17268ef 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -56,6 +56,7 @@ static ld_plugin_status discard_message(int level, const char *format, ...) { static ld_plugin_release_input_file release_input_file = nullptr; static ld_plugin_get_input_file get_input_file = nullptr; static ld_plugin_message message = discard_message; +static ld_plugin_get_wrap_symbols get_wrap_symbols = nullptr; namespace { struct claimed_file { @@ -93,6 +94,8 @@ struct PluginInputFile { struct ResolutionInfo { bool CanOmitFromDynSym = true; bool DefaultVisibility = true; + bool CanInline = true; + bool IsUsedInRegularObj = false; }; } @@ -367,6 +370,9 @@ ld_plugin_status onload(ld_plugin_tv *tv) { case LDPT_MESSAGE: message = tv->tv_u.tv_message; break; + case LDPT_GET_WRAP_SYMBOLS: + get_wrap_symbols = tv->tv_u.tv_get_wrap_symbols; + break; default: break; } @@ -563,6 +569,29 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, } } + // Handle any --wrap options passed to gold, which are than passed + // along to the plugin. + if (get_wrap_symbols) { + const char **wrap_symbols; + uint64_t count = 0; + if (get_wrap_symbols(&count, &wrap_symbols) != LDPS_OK) { + message(LDPL_ERROR, "Unable to get wrap symbols!"); + return LDPS_ERR; + } + for (uint64_t i = 0; i < count; i++) { + StringRef Name = wrap_symbols[i]; + ResolutionInfo &Res = ResInfo[Name]; + ResolutionInfo &WrapRes = ResInfo["__wrap_" + Name.str()]; + ResolutionInfo &RealRes = ResInfo["__real_" + Name.str()]; + // Tell LTO not to inline symbols that will be overwritten. + Res.CanInline = false; + RealRes.CanInline = false; + // Tell LTO not to eliminate symbols that will be used after renaming. + Res.IsUsedInRegularObj = true; + WrapRes.IsUsedInRegularObj = true; + } + } + return LDPS_OK; } @@ -686,6 +715,12 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View, (IsExecutable || !Res.DefaultVisibility)) R.FinalDefinitionInLinkageUnit = true; + if (!Res.CanInline) + R.LinkerRedefined = true; + + if (Res.IsUsedInRegularObj) + R.VisibleToRegularObj = true; + freeSymName(Sym); } -- 2.7.4