Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ELF.h" @@ -36,6 +37,8 @@ llvm::StringRef Sysroot; std::string RPath; std::vector InputSearchPaths; + // If the name of an undefined symbol is in this list, it should be replaced. + llvm::StringMap UndefSymNameReplacement; bool AllowMultipleDefinition; bool DiscardAll; bool DiscardLocals; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -176,6 +176,13 @@ if (auto *Arg = Args.getLastArg(OPT_m)) setELFType(Arg->getValue()); + for (auto *Arg : Args.filtered(OPT_wrap)) { + Config->UndefSymNameReplacement.insert(std::make_pair( + Arg->getValue(), (Twine("__wrap_") + Arg->getValue()).str())); + Config->UndefSymNameReplacement.insert(std::make_pair( + (Twine("__real_") + Arg->getValue()).str(), Arg->getValue())); + } + Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->DiscardAll = Args.hasArg(OPT_discard_all); Config->DiscardLocals = Args.hasArg(OPT_discard_locals); Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -9,6 +9,7 @@ #include "InputFiles.h" #include "InputSection.h" +#include "Config.h" #include "Error.h" #include "Symbols.h" #include "llvm/ADT/STLExtras.h" @@ -159,8 +160,13 @@ switch (SecIndex) { case SHN_ABS: return new (Alloc) DefinedAbsolute(Name, *Sym); - case SHN_UNDEF: - return new (Alloc) Undefined(Name, *Sym); + case SHN_UNDEF: { + auto Replacement = Config->UndefSymNameReplacement.find(Name); + if (Replacement != Config->UndefSymNameReplacement.end()) + return new (Alloc) Undefined(Replacement->second, *Sym); + else + return new (Alloc) Undefined(Name, *Sym); + } case SHN_COMMON: return new (Alloc) DefinedCommon(Name, *Sym); case SHN_XINDEX: Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -82,6 +82,9 @@ def whole_archive : Flag<["--"], "whole-archive">, HelpText<"Force load of all members in a static library">; +def wrap : Separate<["--", "-"], "wrap">, MetaVarName<"">, + HelpText<"Use a wrapper function for symbol">; + // Aliases def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias; def alias_Bdynamic_dy: Flag<["-"], "dy">, Alias; @@ -99,6 +102,7 @@ def alias_soname_h : Separate<["-"], "h">, Alias; def alias_soname_soname : Separate<["-"], "soname">, Alias; def alias_undefined_u : Separate<["-"], "u">, Alias; +def alias_wrap_wrap : Joined<["--", "-"], "wrap=">, Alias; // Options listed below are silently ignored now. def O3 : Flag<["-"], "O3">; Index: test/elf2/Inputs/wrap.s =================================================================== --- /dev/null +++ test/elf2/Inputs/wrap.s @@ -0,0 +1,4 @@ +.globl foo,__wrap_foo,__real_foo; +foo = 0x11000 +__wrap_foo = 0x11010 +__real_foo = 0x11020 Index: test/elf2/wrap.s =================================================================== --- /dev/null +++ test/elf2/wrap.s @@ -0,0 +1,19 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap.s -o %t2 + +// 1) Should replace used symbols foo -> __wrap_foo, __real_foo -> foo +// 2) Should not fail on undefined symbol if it isn't used (bar) +// RUN: lld -flavor gnu2 -o %t3 %t %t2 -wrap foo -wrap bar +// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s + +// CHECK: _start: +// CHECK-NEXT: movl $0x11010, %edx +// CHECK-NEXT: movl $0x11010, %edx +// CHECK-NEXT: movl $0x11000, %edx + +.global _start; +_start: + movl $foo, %edx + movl $__wrap_foo, %edx + movl $__real_foo, %edx Index: test/elf2/wrap2.s =================================================================== --- /dev/null +++ test/elf2/wrap2.s @@ -0,0 +1,31 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t + +// RUN: lld -flavor gnu2 -shared -o %t2 %t -wrap foo -wrap bar -wrap baz +// RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=CHECK1 +// RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=CHECK2 +// Check aliases of the switch +// RUN: lld -flavor gnu2 -shared -o %t2 %t --wrap foo -wrap=bar --wrap=baz +// RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=CHECK1 +// RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=CHECK2 + +// CHECK1: Symbols [ +// CHECK1-DAG: Name: __wrap_foo +// CHECK1-DAG: Name: bar +// CHECK1-DAG: Name: __wrap_baz +// CHECK1: ] + +// CHECK2: Symbols [ +// CHECK2-NOT: Name: foo +// CHECK2-NOT: Name: __real_foo +// CHECK2-NOT: Name: __wrap_bar +// CHECK2-NOT: Name: __real_bar +// CHECK2-NOT: Name: baz +// CHECK2-NOT: Name: __real_baz +// CHECK2: ] + +.global _start; +_start: + jmp foo@PLT + jmp __real_bar@PLT + jmp __wrap_baz@PLT