Skip to content

Commit 4a8de28

Browse files
committed
[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 #53775 Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D120701
1 parent e970d28 commit 4a8de28

File tree

6 files changed

+99
-8
lines changed

6 files changed

+99
-8
lines changed

Diff for: lld/ELF/Config.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ struct Configuration {
148148
uint64_t>
149149
callGraphProfile;
150150
bool allowMultipleDefinition;
151-
bool androidPackDynRelocs;
151+
bool androidPackDynRelocs = false;
152152
bool armHasBlx = false;
153153
bool armHasMovtMovw = false;
154154
bool armJ1J2BranchEncoding = false;
@@ -206,7 +206,8 @@ struct Configuration {
206206
bool printIcfSections;
207207
bool relax;
208208
bool relocatable;
209-
bool relrPackDynRelocs;
209+
bool relrGlibc = false;
210+
bool relrPackDynRelocs = false;
210211
bool saveTemps;
211212
std::vector<std::pair<llvm::GlobPattern, uint32_t>> shuffleSections;
212213
bool singleRoRx;

Diff for: lld/ELF/Driver.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -465,13 +465,15 @@ constexpr const char *knownZFlags[] = {
465465
"noexecstack",
466466
"nognustack",
467467
"nokeep-text-section-prefix",
468+
"nopack-relative-relocs",
468469
"norelro",
469470
"noseparate-code",
470471
"nostart-stop-gc",
471472
"notext",
472473
"now",
473474
"origin",
474475
"pac-plt",
476+
"pack-relative-relocs",
475477
"rel",
476478
"rela",
477479
"relro",
@@ -1352,8 +1354,13 @@ static void readConfigs(opt::InputArgList &args) {
13521354

13531355
std::tie(config->buildId, config->buildIdVector) = getBuildId(args);
13541356

1355-
std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) =
1356-
getPackDynRelocs(args);
1357+
if (getZFlag(args, "pack-relative-relocs", "nopack-relative-relocs", false)) {
1358+
config->relrGlibc = true;
1359+
config->relrPackDynRelocs = true;
1360+
} else {
1361+
std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) =
1362+
getPackDynRelocs(args);
1363+
}
13571364

13581365
if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){
13591366
if (args.hasArg(OPT_call_graph_ordering_file))

Diff for: lld/ELF/SyntheticSections.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -3178,15 +3178,24 @@ template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
31783178
verneeds.emplace_back();
31793179
Verneed &vn = verneeds.back();
31803180
vn.nameStrTab = getPartition().dynStrTab->addString(f->soName);
3181+
bool isLibc = config->relrGlibc && f->soName.startswith("libc.so.");
3182+
bool isGlibc2 = false;
31813183
for (unsigned i = 0; i != f->vernauxs.size(); ++i) {
31823184
if (f->vernauxs[i] == 0)
31833185
continue;
31843186
auto *verdef =
31853187
reinterpret_cast<const typename ELFT::Verdef *>(f->verdefs[i]);
3186-
vn.vernauxs.push_back(
3187-
{verdef->vd_hash, f->vernauxs[i],
3188-
getPartition().dynStrTab->addString(f->getStringTable().data() +
3189-
verdef->getAux()->vda_name)});
3188+
StringRef ver(f->getStringTable().data() + verdef->getAux()->vda_name);
3189+
if (isLibc && ver.startswith("GLIBC_2."))
3190+
isGlibc2 = true;
3191+
vn.vernauxs.push_back({verdef->vd_hash, f->vernauxs[i],
3192+
getPartition().dynStrTab->addString(ver)});
3193+
}
3194+
if (isGlibc2) {
3195+
const char *ver = "GLIBC_ABI_DT_RELR";
3196+
vn.vernauxs.push_back({hashSysV(ver),
3197+
++SharedFile::vernauxNum + getVerDefNum(),
3198+
getPartition().dynStrTab->addString(ver)});
31903199
}
31913200
}
31923201

Diff for: lld/docs/ReleaseNotes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ Non-comprehensive list of changes in this release
2626
ELF Improvements
2727
----------------
2828

29+
* ``-z pack-relative-relocs`` is now available to support ``DT_RELR`` for glibc 2.36+.
30+
(`D120701 <https://reviews.llvm.org/D120701>`_)
31+
2932
Breaking changes
3033
----------------
3134

Diff for: lld/docs/ld.lld.1

+6
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,12 @@ processing.
807807
.It Cm pac-plt
808808
AArch64 only, use pointer authentication in PLT.
809809
.Pp
810+
.It Cm pack-relative-relocs
811+
Similar to
812+
.Cm -pack-dyn-relocs=relr
813+
, but synthesizes the GLIBC_ABI_DT_RELR version dependency if there is a GLIBC_2.* version dependency.
814+
glibc ld.so rejects loading a dynamically linked object without the GLIBC_ABI_DT_RELR version dependency.
815+
.Pp
810816
.It Cm rel
811817
Use REL format for dynamic relocations.
812818
.Pp

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

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# REQUIRES: x86
2+
## -z pack-relative-relocs is a variant of --pack-dyn-relocs=relr: add
3+
## GLIBC_ABI_DT_RELR verneed if there is a verneed named "GLIBC_2.*".
4+
5+
# RUN: rm -rf %t && split-file %s %t
6+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
7+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/libc.s -o %t/libc.o
8+
# RUN: ld.lld -shared --soname=libc.so.6 --version-script=%t/glibc.ver %t/libc.o -o %t/libc.so.6
9+
10+
# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs -o %t/glibc 2>&1 | count 0
11+
# RUN: llvm-readelf -r -V %t/glibc | FileCheck %s --check-prefix=GLIBC
12+
## Arbitrarily let -z pack-relative-relocs win.
13+
# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs --pack-dyn-relocs=relr -o %t/glibc2
14+
# RUN: cmp %t/glibc %t/glibc2
15+
16+
# GLIBC: Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
17+
# GLIBC: Version needs section '.gnu.version_r' contains 1 entries:
18+
# GLIBC-NEXT: Addr: {{.*}}
19+
# GLIBC-NEXT: 0x0000: Version: 1 File: libc.so.6 Cnt: 2
20+
# GLIBC-NEXT: 0x0010: Name: GLIBC_2.33 Flags: none Version: 2
21+
# GLIBC-NEXT: 0x0020: Name: GLIBC_ABI_DT_RELR Flags: none Version: 3
22+
# GLIBC-EMPTY:
23+
24+
# 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
25+
# RUN: llvm-readelf -r -V %t/notrelr | FileCheck %s --check-prefix=REGULAR
26+
27+
# REGULAR-NOT: Relocation section '.relr.dyn'
28+
# REGULAR-NOT: Name: GLIBC_ABI_DT_RELR
29+
30+
## soname is not "libc.so.*". Don't synthesize GLIBC_ABI_DT_RELR. In glibc, ld.so
31+
## doesn't define GLIBC_ABI_DT_RELR. libc.so itself should not reference GLIBC_ABI_DT_RELR.
32+
# RUN: ld.lld -shared --soname=ld-linux-x86-64.so.2 --version-script=%t/glibc.ver %t/libc.o -o %t/ld.so
33+
# RUN: ld.lld -pie %t/a.o %t/ld.so -z pack-relative-relocs -o %t/other 2>&1 | count 0
34+
# RUN: llvm-readelf -r -V %t/other | FileCheck %s --check-prefix=NOTLIBC
35+
36+
# NOTLIBC: Relocation section '.relr.dyn' at offset {{.*}} contains 1 entries:
37+
# NOTLIBC-NOT: Name: GLIBC_ABI_DT_RELR
38+
39+
## There is no GLIBC_2.* verneed. Don't add GLIBC_ABI_DT_RELR verneed.
40+
# RUN: ld.lld -shared --soname=libc.so.6 --version-script=%t/other.ver %t/libc.o -o %t/libc.so.6
41+
# RUN: ld.lld -pie %t/a.o %t/libc.so.6 -z pack-relative-relocs -o %t/other
42+
# RUN: llvm-readelf -r -V %t/other | FileCheck %s --check-prefix=NOTLIBC
43+
44+
#--- a.s
45+
.globl _start
46+
_start:
47+
call stat
48+
49+
.data
50+
.balign 8
51+
.dc.a .data
52+
53+
#--- libc.s
54+
.weak stat
55+
stat:
56+
57+
#--- glibc.ver
58+
GLIBC_2.33 {
59+
stat;
60+
};
61+
62+
#--- other.ver
63+
GLIBC_3 {
64+
stat;
65+
};

0 commit comments

Comments
 (0)