[lld] 72d070b - [ELF] Support copy relocation on non-default version symbols

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 5 10:32:19 PDT 2021


Author: Fangrui Song
Date: 2021-08-05T10:32:14-07:00
New Revision: 72d070b4db2da7216f63f09407bd96f49dc90bd1

URL: https://github.com/llvm/llvm-project/commit/72d070b4db2da7216f63f09407bd96f49dc90bd1
DIFF: https://github.com/llvm/llvm-project/commit/72d070b4db2da7216f63f09407bd96f49dc90bd1.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 at GLIBC_2.2.5 sys_errlist at GLIBC_2.3 sys_errlist at 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

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 at v1
-.type foo at v1, @object
-.size foo at v1, 4
-.global foo@@v2
-.type foo@@v2, @object
-.size foo@@v2, 8
-foo at v1:
-foo@@v2:
+.global foo_v1
+.symver foo_v1, foo at v1, remove
+.type foo_v1, @object
+.size foo_v1, 4
+
+.global foo_v2
+.symver foo_v2, foo at 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 at v3
+# CHECK1-EMPTY:
+
+## Copy relocate the non-default version symbol.
+# RUN: llvm-objcopy --redefine-sym foo=foo at 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 at v1
+# CHECK2-NEXT:  2: [[ADDR]]          12 OBJECT  GLOBAL DEFAULT [[#]] foo at v3
+# CHECK2-EMPTY:
 
 .global _start
 _start:
   leaq foo, %rax
-
-// CHECK:      Name: foo (
-// CHECK-NEXT: Value:
-// CHECK-NEXT: Size: 8


        


More information about the llvm-commits mailing list