[lld] 4a8de28 - [ELF] Add -z pack-relative-relocs

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 10 19:54:26 PST 2022


Author: Fangrui Song
Date: 2022-03-10T19:54:21-08:00
New Revision: 4a8de2832a2a730f63b71bdf1c1b446285ec5b6f

URL: https://github.com/llvm/llvm-project/commit/4a8de2832a2a730f63b71bdf1c1b446285ec5b6f
DIFF: https://github.com/llvm/llvm-project/commit/4a8de2832a2a730f63b71bdf1c1b446285ec5b6f.diff

LOG: [ELF] Add -z pack-relative-relocs

GNU ld 2.38 added -z pack-relative-relocs which is similar to
--pack-dyn-relocs=relr but synthesizes the `GLIBC_ABI_DT_RELR` version
dependency if a shared object named `libc.so.*` has a `GLIBC_2.*` version
dependency.

This is used to implement the (as some glibc folks call) version lockout
mechanism. Add this option, because glibc does not want to support
--pack-dyn-relocs=relr which does not add `GLIBC_ABI_DT_RELR`.
See https://maskray.me/blog/2021-10-31-relative-relocations-and-relr for
detail.

Close https://github.com/llvm/llvm-project/issues/53775

Reviewed By: peter.smith

Differential Revision: https://reviews.llvm.org/D120701

Added: 
    lld/test/ELF/pack-dyn-relocs-glibc.s

Modified: 
    lld/ELF/Config.h
    lld/ELF/Driver.cpp
    lld/ELF/SyntheticSections.cpp
    lld/docs/ReleaseNotes.rst
    lld/docs/ld.lld.1

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 4b2ad7eb15db5..7b7265c786724 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -148,7 +148,7 @@ struct Configuration {
                   uint64_t>
       callGraphProfile;
   bool allowMultipleDefinition;
-  bool androidPackDynRelocs;
+  bool androidPackDynRelocs = false;
   bool armHasBlx = false;
   bool armHasMovtMovw = false;
   bool armJ1J2BranchEncoding = false;
@@ -206,7 +206,8 @@ struct Configuration {
   bool printIcfSections;
   bool relax;
   bool relocatable;
-  bool relrPackDynRelocs;
+  bool relrGlibc = false;
+  bool relrPackDynRelocs = false;
   bool saveTemps;
   std::vector<std::pair<llvm::GlobPattern, uint32_t>> shuffleSections;
   bool singleRoRx;

diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 2a1fe198a9275..9f5d550e2c297 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -465,6 +465,7 @@ constexpr const char *knownZFlags[] = {
     "noexecstack",
     "nognustack",
     "nokeep-text-section-prefix",
+    "nopack-relative-relocs",
     "norelro",
     "noseparate-code",
     "nostart-stop-gc",
@@ -472,6 +473,7 @@ constexpr const char *knownZFlags[] = {
     "now",
     "origin",
     "pac-plt",
+    "pack-relative-relocs",
     "rel",
     "rela",
     "relro",
@@ -1352,8 +1354,13 @@ static void readConfigs(opt::InputArgList &args) {
 
   std::tie(config->buildId, config->buildIdVector) = getBuildId(args);
 
-  std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) =
-      getPackDynRelocs(args);
+  if (getZFlag(args, "pack-relative-relocs", "nopack-relative-relocs", false)) {
+    config->relrGlibc = true;
+    config->relrPackDynRelocs = true;
+  } else {
+    std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) =
+        getPackDynRelocs(args);
+  }
 
   if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){
     if (args.hasArg(OPT_call_graph_ordering_file))

diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 41c890b0ec0a1..7b8de80f156d8 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3178,15 +3178,24 @@ template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
     verneeds.emplace_back();
     Verneed &vn = verneeds.back();
     vn.nameStrTab = getPartition().dynStrTab->addString(f->soName);
+    bool isLibc = config->relrGlibc && f->soName.startswith("libc.so.");
+    bool isGlibc2 = false;
     for (unsigned i = 0; i != f->vernauxs.size(); ++i) {
       if (f->vernauxs[i] == 0)
         continue;
       auto *verdef =
           reinterpret_cast<const typename ELFT::Verdef *>(f->verdefs[i]);
-      vn.vernauxs.push_back(
-          {verdef->vd_hash, f->vernauxs[i],
-           getPartition().dynStrTab->addString(f->getStringTable().data() +
-                                               verdef->getAux()->vda_name)});
+      StringRef ver(f->getStringTable().data() + verdef->getAux()->vda_name);
+      if (isLibc && ver.startswith("GLIBC_2."))
+        isGlibc2 = true;
+      vn.vernauxs.push_back({verdef->vd_hash, f->vernauxs[i],
+                             getPartition().dynStrTab->addString(ver)});
+    }
+    if (isGlibc2) {
+      const char *ver = "GLIBC_ABI_DT_RELR";
+      vn.vernauxs.push_back({hashSysV(ver),
+                             ++SharedFile::vernauxNum + getVerDefNum(),
+                             getPartition().dynStrTab->addString(ver)});
     }
   }
 

diff  --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index af09e1e539b87..5878cddb4c88a 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -26,6 +26,9 @@ Non-comprehensive list of changes in this release
 ELF Improvements
 ----------------
 
+* ``-z pack-relative-relocs`` is now available to support ``DT_RELR`` for glibc 2.36+.
+  (`D120701 <https://reviews.llvm.org/D120701>`_)
+
 Breaking changes
 ----------------
 

diff  --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index acd2670aee6c9..b81eeb2232a2c 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -807,6 +807,12 @@ processing.
 .It Cm pac-plt
 AArch64 only, use pointer authentication in PLT.
 .Pp
+.It Cm pack-relative-relocs
+Similar to
+.Cm -pack-dyn-relocs=relr
+, but synthesizes the GLIBC_ABI_DT_RELR version dependency if there is a GLIBC_2.* version dependency.
+glibc ld.so rejects loading a dynamically linked object without the GLIBC_ABI_DT_RELR version dependency.
+.Pp
 .It Cm rel
 Use REL format for dynamic relocations.
 .Pp

diff  --git a/lld/test/ELF/pack-dyn-relocs-glibc.s b/lld/test/ELF/pack-dyn-relocs-glibc.s
new file mode 100644
index 0000000000000..32b6ba33c39b9
--- /dev/null
+++ b/lld/test/ELF/pack-dyn-relocs-glibc.s
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+## -z pack-relative-relocs is a variant of --pack-dyn-relocs=relr: add
+## GLIBC_ABI_DT_RELR verneed if there is a verneed named "GLIBC_2.*".
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/libc.s -o %t/libc.o
+# RUN: ld.lld -shared --soname=libc.so.6 --version-script=%t/glibc.ver %t/libc.o -o %t/libc.so.6
+
+# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs -o %t/glibc 2>&1 | count 0
+# RUN: llvm-readelf -r -V %t/glibc | FileCheck %s --check-prefix=GLIBC
+## Arbitrarily let -z pack-relative-relocs win.
+# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs --pack-dyn-relocs=relr -o %t/glibc2
+# RUN: cmp %t/glibc %t/glibc2
+
+# GLIBC:      Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
+# GLIBC:      Version needs section '.gnu.version_r' contains 1 entries:
+# GLIBC-NEXT:  Addr: {{.*}}
+# GLIBC-NEXT:   0x0000: Version: 1  File: libc.so.6  Cnt: 2
+# GLIBC-NEXT:   0x0010:   Name: GLIBC_2.33  Flags: none  Version: 2
+# GLIBC-NEXT:   0x0020:   Name: GLIBC_ABI_DT_RELR  Flags: none  Version: 3
+# GLIBC-EMPTY:
+
+# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs -z nopack-relative-relocs -o %t/notrelr 2>&1 | count 0
+# RUN: llvm-readelf -r -V %t/notrelr | FileCheck %s --check-prefix=REGULAR
+
+# REGULAR-NOT: Relocation section '.relr.dyn'
+# REGULAR-NOT: Name: GLIBC_ABI_DT_RELR
+
+## soname is not "libc.so.*". Don't synthesize GLIBC_ABI_DT_RELR. In glibc, ld.so
+## doesn't define GLIBC_ABI_DT_RELR. libc.so itself should not reference GLIBC_ABI_DT_RELR.
+# RUN: ld.lld -shared --soname=ld-linux-x86-64.so.2 --version-script=%t/glibc.ver %t/libc.o -o %t/ld.so
+# RUN: ld.lld -pie %t/a.o %t/ld.so -z pack-relative-relocs -o %t/other 2>&1 | count 0
+# RUN: llvm-readelf -r -V %t/other | FileCheck %s --check-prefix=NOTLIBC
+
+# NOTLIBC:     Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
+# NOTLIBC-NOT: Name: GLIBC_ABI_DT_RELR
+
+## There is no GLIBC_2.* verneed. Don't add GLIBC_ABI_DT_RELR verneed.
+# RUN: ld.lld -shared --soname=libc.so.6 --version-script=%t/other.ver %t/libc.o -o %t/libc.so.6
+# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs -o %t/other
+# RUN: llvm-readelf -r -V %t/other | FileCheck %s --check-prefix=NOTLIBC
+
+#--- a.s
+.globl _start
+_start:
+  call stat
+
+.data
+.balign 8
+.dc.a .data
+
+#--- libc.s
+.weak stat
+stat:
+
+#--- glibc.ver
+GLIBC_2.33 {
+  stat;
+};
+
+#--- other.ver
+GLIBC_3 {
+  stat;
+};


        


More information about the llvm-commits mailing list