forked from OSchip/llvm-project
[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
This commit is contained in:
parent
e970d2823c
commit
4a8de2832a
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
----------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
Loading…
Reference in New Issue