Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -144,6 +144,9 @@ // For -defsym or -wrap. std::vector Defsyms; + // For -wrap. + std::vector> WrapSymbols; + // For LTO. std::unique_ptr LTO; }; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -164,6 +164,8 @@ defsym(Real, Sym); defsym(Sym, Wrap); + + WrapSymbols.push_back({Wrap, Real}); } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. @@ -183,11 +185,43 @@ // LTO (if LTO is running) not to include these symbols in IPO. Now that the // symbols are finalized, we can perform the replacement. void SymbolTable::applySymbolRenames() { + // This function rotates 3 symbols: + // + // __real_foo becomes foo + // foo becomes __wrap_foo + // __wrap_foo becomes __real_foo + // + // The last part is special in that we don't want to change what references to + // __wrap_foo point to, we just want have __real_foo in the symbol table. + + // First make a copy of __real_foo + std::vector Origs; + for (const auto &P : WrapSymbols) + Origs.push_back(*P.second); + + // Replace __real_foo with foo and foo with __wrap_foo for (SymbolRenaming &S : Defsyms) { S.Dst->body()->copyFrom(S.Src->body()); S.Dst->File = S.Src->File; S.Dst->Binding = S.Binding; } + + // Hide one of the copies of __wrap_foo, create a new symbol and copy + // __real_foo into it. + for (unsigned I = 0, N = WrapSymbols.size(); I < N; ++I) { + // We now have two copies of __wrap_foo. Drop one. + Symbol *Wrap = WrapSymbols[I].first; + Wrap->IsUsedInRegularObj = false; + + Symbol *Real = &Origs[I]; + // If __real_foo was undefined, we don't want it in the symbol table. + if (Real->body()->isUndefined()) + continue; + + auto *NewSym = make(); + memcpy(NewSym, Real, sizeof(Symbol)); + SymVector.push_back(NewSym); + } } static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { Index: test/ELF/Inputs/wrap-no-real.s =================================================================== --- /dev/null +++ test/ELF/Inputs/wrap-no-real.s @@ -0,0 +1,3 @@ +.globl foo, __wrap_foo +foo = 0x11000 +__wrap_foo = 0x11010 Index: test/ELF/lto/wrap-2.ll =================================================================== --- test/ELF/lto/wrap-2.ll +++ test/ELF/lto/wrap-2.ll @@ -28,11 +28,11 @@ ; THIN-NEXT: jmp{{.*}} ; Check that bar and __wrap_bar retain their original binding. -; BIND: Name: bar +; BIND: Name: __wrap_bar ; BIND-NEXT: Value: ; BIND-NEXT: Size: ; BIND-NEXT: Binding: Local -; BIND: Name: __wrap_bar +; BIND: Name: bar ; BIND-NEXT: Value: ; BIND-NEXT: Size: ; BIND-NEXT: Binding: Local Index: test/ELF/wrap-no-real.s =================================================================== --- /dev/null +++ test/ELF/wrap-no-real.s @@ -0,0 +1,26 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap-no-real.s -o %t2.o + +// RUN: ld.lld -o %t %t1.o %t2.o -wrap foo +// RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s + +// CHECK: _start: +// CHECK-NEXT: movl $0x11010, %edx +// CHECK-NEXT: movl $0x11010, %edx +// CHECK-NEXT: movl $0x11000, %edx + +// RUN: llvm-readobj -t -s %t | FileCheck -check-prefix=SYM %s +// SYM-NOT: Name: __real_foo +// SYM: Name: foo +// SYM-NEXT: Value: 0x11000 +// SYM-NOT: Name: __real_foo +// SYM: Name: __wrap_foo +// SYM-NEXT: Value: 0x11010 +// SYM-NOT: Name: __real_foo + +.global _start +_start: + movl $foo, %edx + movl $__wrap_foo, %edx + movl $__real_foo, %edx Index: test/ELF/wrap.s =================================================================== --- test/ELF/wrap.s +++ test/ELF/wrap.s @@ -12,17 +12,13 @@ // CHECK-NEXT: movl $0x11010, %edx // CHECK-NEXT: movl $0x11000, %edx -// This shows an oddity of our implementation. The symbol foo gets -// mapped to __wrap_foo, but stays in the symbol table. This results -// in it showing up twice in the output. - // RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s // SYM: Name: foo // SYM-NEXT: Value: 0x11000 // SYM: Name: __wrap_foo // SYM-NEXT: Value: 0x11010 -// SYM: Name: __wrap_foo -// SYM-NEXT: Value: 0x11010 +// SYM: Name: __real_foo +// SYM-NEXT: Value: 0x11020 .global _start _start: