[PATCH] D107535: [ELF] Support copy relocation on non-default version symbols

Fangrui Song via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 4 22:06:19 PDT 2021


MaskRay created this revision.
MaskRay added a reviewer: peter.smith.
Herald added subscribers: arichardson, emaste.
Herald added a reviewer: alexander-shaposhnikov.
MaskRay requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

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 and the pointer inequality may or may be an issue. In real world
the failing case is highly unlikely.

(
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.
)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D107535

Files:
  lld/ELF/Relocations.cpp
  lld/test/ELF/copy-rel-version.s


Index: lld/test/ELF/copy-rel-version.s
===================================================================
--- lld/test/ELF/copy-rel-version.s
+++ 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 {};' > %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: {{.+}}             8 OBJECT  GLOBAL DEFAULT [[#]] foo at v2
+# 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]]           8 OBJECT  GLOBAL DEFAULT [[#]] foo at v2
+# CHECK2-EMPTY:
 
 .global _start
 _start:
   leaq foo, %rax
-
-// CHECK:      Name: foo (
-// CHECK-NEXT: Value:
-// CHECK-NEXT: Size: 8
Index: lld/ELF/Relocations.cpp
===================================================================
--- lld/ELF/Relocations.cpp
+++ lld/ELF/Relocations.cpp
@@ -527,6 +527,13 @@
     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 different addresses.
+  // Fortunately this failing case is impractical.
+  ret.insert(&ss);
   return ret;
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D107535.364345.patch
Type: text/x-patch
Size: 2340 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210805/da2bf006/attachment.bin>


More information about the llvm-commits mailing list