Author: Fangrui Song Date: 2021-08-05T10:33:31-07:00 New Revision: 6b6aef5dbacef31a3c7b3a54f7f1ba54cafc7077
URL: https://github.com/llvm/llvm-project/commit/6b6aef5dbacef31a3c7b3a54f7f1ba54cafc7077 DIFF: https://github.com/llvm/llvm-project/commit/6b6aef5dbacef31a3c7b3a54f7f1ba54cafc7077.diff LOG: [ELF] Support copy relocation on non-default version symbols Copy relocation on a non-default version symbol is unsupported and can crash at runtime. Fortunately there is a one-line fix which works for most cases: ensure `getSymbolsAt` unconditionally returns `ss`. If two non-default version symbols are defined at the same place and both are copy relocated, our implementation will copy relocated them into different addresses. The pointer inequality is very unlikely an issue. In GNU ld, copy relocating version aliases seems to create more pointer inequality problems than us. ( In glibc, sys_errlist@GLIBC_2.2.5 sys_errlist@GLIBC_2.3 sys_errlist@GLIBC_2.4 are defined at the same place, but it is unlikely they are all copy relocated in one executable. Even if so, the variables are read-only and pointer inequality should not be a problem. ) Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D107535 (cherry picked from commit 72d070b4db2da7216f63f09407bd96f49dc90bd1) Added: Modified: lld/ELF/Relocations.cpp lld/test/ELF/Inputs/copy-rel-version.s lld/test/ELF/copy-rel-version.s Removed: ################################################################################ diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index e3cc210972b2f..537859f9e0b5b 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -527,6 +527,13 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) { if (auto *alias = dyn_cast_or_null<SharedSymbol>(sym)) ret.insert(alias); } + + // The loop does not check SHT_GNU_verneed, so ret does not contain + // non-default version symbols. If ss has a non-default version, ret won't + // contain ss. Just add ss unconditionally. If a non-default version alias is + // separately copy relocated, it and ss will have diff erent addresses. + // Fortunately this case is impractical and fails with GNU ld as well. + ret.insert(&ss); return ret; } diff --git a/lld/test/ELF/Inputs/copy-rel-version.s b/lld/test/ELF/Inputs/copy-rel-version.s index 36bb1ba54c9f5..1477527d829e7 100644 --- a/lld/test/ELF/Inputs/copy-rel-version.s +++ b/lld/test/ELF/Inputs/copy-rel-version.s @@ -1,11 +1,22 @@ .data -.global foo@v1 -.type foo@v1, @object -.size foo@v1, 4 -.global foo@@v2 -.type foo@@v2, @object -.size foo@@v2, 8 -foo@v1: -foo@@v2: +.global foo_v1 +.symver foo_v1, foo@v1, remove +.type foo_v1, @object +.size foo_v1, 4 + +.global foo_v2 +.symver foo_v2, foo@v2, remove +.type foo_v2, @object +.size foo_v2, 8 + +.global foo +.symver foo, foo@@@v3 +.type foo, @object +.size foo, 12 + +foo_v1: +foo_v2: +foo: +.int 0 .int 0 .int 0 diff --git a/lld/test/ELF/copy-rel-version.s b/lld/test/ELF/copy-rel-version.s index afa5ebeb6e4da..feaa59f8eb8cb 100644 --- a/lld/test/ELF/copy-rel-version.s +++ b/lld/test/ELF/copy-rel-version.s @@ -1,15 +1,27 @@ -// REQUIRES: x86 -// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-rel-version.s -o %t1.o -// RUN: echo "v1 {}; v2 {};" > %t.ver -// RUN: ld.lld %t1.o -shared -soname t1.so --version-script=%t.ver -o %t1.so -// RUN: ld.lld %t.o %t1.so -o %t -// RUN: llvm-readobj --symbols %t | FileCheck %s +# REQUIRES: x86 +## Copy relocate a versioned symbol which has a versioned alias. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/copy-rel-version.s -o %t.o +# RUN: echo 'v1 {}; v2 {}; v3 {};' > %t.ver +# RUN: ld.lld %t.o -shared -soname t.so --version-script=%t.ver -o %t.so + +## Copy relocate the default version symbol. +# RUN: ld.lld %t1.o %t.so -o %t1 +# RUN: llvm-readelf --dyn-syms %t1 | FileCheck %s --check-prefix=CHECK1 + +# CHECK1: 1: {{.+}} 12 OBJECT GLOBAL DEFAULT [[#]] foo@v3 +# CHECK1-EMPTY: + +## Copy relocate the non-default version symbol. +# RUN: llvm-objcopy --redefine-sym foo=foo@v1 %t1.o %t2.o +# RUN: ld.lld %t2.o %t.so -o %t2 +# RUN: llvm-readelf --dyn-syms %t2 | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: 1: [[ADDR:[0-9a-f]+]] 4 OBJECT GLOBAL DEFAULT [[#]] foo@v1 +# CHECK2-NEXT: 2: [[ADDR]] 12 OBJECT GLOBAL DEFAULT [[#]] foo@v3 +# CHECK2-EMPTY: .global _start _start: leaq foo, %rax - -// CHECK: Name: foo ( -// CHECK-NEXT: Value: -// CHECK-NEXT: Size: 8 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits