[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