Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -90,6 +90,8 @@ bool ZOrigin; bool ZRelro; bool DynamicListData; + bool DynamicListCppNew; + bool DynamicListCppTypeinfo; ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t EntryAddr = -1; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -319,6 +319,8 @@ if (!DynamicListPath.empty()) readDynamicList(DynamicListPath); Config->DynamicListData = Args.hasArg(OPT_dynamic_list_data); + Config->DynamicListCppNew = Args.hasArg(OPT_dynamic_list_cpp_new); + Config->DynamicListCppTypeinfo = Args.hasArg(OPT_dynamic_list_cpp_typeinfo); Config->Optimize = getInteger(Args, OPT_O, 0); Config->LtoO = getInteger(Args, OPT_lto_O, 2); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -158,6 +158,12 @@ def dynamic_list_data : Flag<["--", "-"], "dynamic-list-data">, HelpText<"Add all global data to the dynamic symbol list">; +def dynamic_list_cpp_new : Flag<["--"], "dynamic-list-cpp-new">, + HelpText<"Add the builtin C++ operator new and delete on the dynamic symbol list">; + +def dynamic_list_cpp_typeinfo : Flag<["--"], "dynamic-list-cpp-typeinfo">, + HelpText<"Add the builtin C++ runtime type indentification on the dynamic symbol list">; + // Aliases def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias; def alias_Bdynamic_dy: Flag<["-"], "dy">, Alias; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -845,6 +845,18 @@ return true; } +#define STRCOMPARE(__str, __cstr) \ + (__str.compare(0, sizeof(__cstr)-1, __cstr) == 0) + +static inline bool CheckNewPrefix(const std::string &N) { + return STRCOMPARE (N, "operator new") || STRCOMPARE (N, "operator delete"); +} + +static inline bool CheckTypeInfoPrefix(const std::string &N) { + return STRCOMPARE (N, "typeinfo name for") || + STRCOMPARE (N, "typeinfo for"); +} + template static bool includeInDynsym(const SymbolBody &B) { uint8_t V = B.getVisibility(); @@ -858,6 +870,15 @@ if (Config->DynamicListData) if (B.Type == STT_OBJECT) return true; + // Handle --dynamic-list-cpp-new and --dynamic-list-cpp-typeinfo + if (Config->DynamicListCppNew) { + if (CheckNewPrefix(demangle(B.getName()))) + return true; + } + if (Config->DynamicListCppTypeinfo) { + if (CheckTypeInfoPrefix(demangle(B.getName()))) + return true; + } return B.MustBeInDynSym; } Index: test/ELF/dynamic-list-new-typeinfo.s =================================================================== --- /dev/null +++ test/ELF/dynamic-list-new-typeinfo.s @@ -0,0 +1,164 @@ +# REQUIRES: x86 + +## This object is build in linked against to force dynamic loading without +## the use of full paths in linking command. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +# RUN: ld.lld -shared %t2.o -soname shared -o %t2.so + +# Check export new and delete symbols. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld --dynamic-list-cpp-new %t %t2.so -o %t.exe +# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck %s + +# CHECK: DynamicSymbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: @ (0) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local (0x0) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined (0x0) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _ZdaPv@ (1) +# CHECK-NEXT: Value: 0x11003 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x4) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _ZdlPv@ (8) +# CHECK-NEXT: Value: 0x11002 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x4) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _Znam@ (15) +# CHECK-NEXT: Value: 0x11001 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x4) +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _Znwm@ (21) +# CHECK-NEXT: Value: 0x11000 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: None (0x0) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text (0x4) +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# Check export typeinfo symbols. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld --dynamic-list-cpp-typeinfo %t %t2.so -o %t.exe +# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=CHECK2 %s + +# CHECK2: DynamicSymbols [ +#CHECK2-NEXT: Symbol { +#CHECK2-NEXT: Name: @ (0) +#CHECK2-NEXT: Value: 0x0 +#CHECK2-NEXT: Size: 0 +#CHECK2-NEXT: Binding: Local (0x0) +#CHECK2-NEXT: Type: None (0x0) +#CHECK2-NEXT: Other: 0 +#CHECK2-NEXT: Section: Undefined (0x0) +#CHECK2-NEXT: } +#CHECK2-NEXT: Symbol { +#CHECK2-NEXT: Name: _ZTI3Bar@ (1) +#CHECK2-NEXT: Value: 0x11004 +#CHECK2-NEXT: Size: 8 +#CHECK2-NEXT: Binding: Global (0x1) +#CHECK2-NEXT: Type: Object (0x1) +#CHECK2-NEXT: Other: 0 +#CHECK2-NEXT: Section: .text (0x4) +#CHECK2-NEXT: } +#CHECK2-NEXT: Symbol { +#CHECK2-NEXT: Name: _ZTI3Foo@ (10) +#CHECK2-NEXT: Value: 0x11004 +#CHECK2-NEXT: Size: 8 +#CHECK2-NEXT: Binding: Global (0x1) +#CHECK2-NEXT: Type: Object (0x1) +#CHECK2-NEXT: Other: 0 +#CHECK2-NEXT: Section: .text (0x4) +#CHECK2-NEXT: } +#CHECK2-NEXT: Symbol { +#CHECK2-NEXT: Name: _ZTS3Bar@ (19) +#CHECK2-NEXT: Value: 0x11004 +#CHECK2-NEXT: Size: 5 +#CHECK2-NEXT: Binding: Global (0x1) +#CHECK2-NEXT: Type: Object (0x1) +#CHECK2-NEXT: Other: 0 +#CHECK2-NEXT: Section: .text (0x4) +#CHECK2-NEXT: } +#CHECK2-NEXT: Symbol { +#CHECK2-NEXT: Name: _ZTS3Foo@ (28) +#CHECK2-NEXT: Value: 0x11009 +#CHECK2-NEXT: Size: 5 +#CHECK2-NEXT: Binding: Global (0x1) +#CHECK2-NEXT: Type: Object (0x1) +#CHECK2-NEXT: Other: 0 +#CHECK2-NEXT: Section: .text (0x4) +#CHECK2-NEXT: } +# CHECK2-NEXT: ] + +## operator new (size_t) +.globl _Znwm +_Znwm: + ret + +## operator new[] (size_t) +.globl _Znam +_Znam: + ret + +## operator delete (void *) +.globl _ZdlPv +_ZdlPv: + ret + +## operator delete[] (void *) +.globl _ZdaPv +_ZdaPv: + ret + +## typeinfo for Bar +.type _ZTI3Bar, @object +.size _ZTI3Bar, 8 +.globl _ZTI3Bar +_ZTI3Bar: +.quad + +## typeinfo for Foo +.type _ZTI3Foo, @object +.size _ZTI3Foo, 8 +.globl _ZTI3Foo +_ZTI3Foo: +.quad + +## typeinfo name for Bar +.type _ZTS3Bar, @object +.size _ZTS3Bar, 5 +.globl _ZTS3Bar +_ZTS3Bar: +.string "3Bar" + +## typeinfo name for Foo +.type _ZTS3Foo, @object +.size _ZTS3Foo, 5 +.globl _ZTS3Foo +_ZTS3Foo: +.string "3Foo" + +.globl _start +_start: + ret