diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -187,6 +187,7 @@ bool printGcSections; bool printIcfSections; bool relocatable; + bool relPackDynRelocs; bool relrPackDynRelocs; bool saveTemps; llvm::Optional shuffleSectionSeed; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -734,18 +734,24 @@ return {BuildIdKind::None, {}}; } -static std::pair getPackDynRelocs(opt::InputArgList &args) { +static std::tuple getPackDynRelocs(opt::InputArgList &args) { StringRef s = args.getLastArgValue(OPT_pack_dyn_relocs, "none"); if (s == "android") - return {true, false}; + return {true, false, false}; if (s == "relr") - return {false, true}; + return {false, true, false}; + // Note there is no plain "rel" option here since rela->rel rewriting is + // motivated by space savings and relr is the biggest win for that, so "rel" + // alone is more likely to be a typo for "relr" than an intentional selection + // of rela->rel without relr. + if (s == "rel+relr") + return {false, true, true}; if (s == "android+relr") - return {true, true}; + return {true, true, false}; if (s != "none") error("unknown -pack-dyn-relocs format: " + s); - return {false, false}; + return {false, false, false}; } static void readCallGraph(MemoryBufferRef mb) { @@ -1118,8 +1124,8 @@ std::tie(config->buildId, config->buildIdVector) = getBuildId(args); - std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) = - getPackDynRelocs(args); + std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs, + config->relPackDynRelocs) = getPackDynRelocs(args); if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){ if (args.hasArg(OPT_call_graph_ordering_file)) @@ -1213,12 +1219,20 @@ // different mechanisms in the first place, but this is how the spec is // defined. // - // You cannot choose which one, Rel or Rela, you want to use. Instead each - // ABI defines which one you need to use. The following expression expresses - // that. + // The psABI for each processor specifies the canonical one to use. The + // following expression expresses that. But actual compatibility depends on + // the dynamic linker implementation (some can handle either format), so when + // targetting a particular OS environment with known dynamic linking ABI + // support, a contrary choice can be made. The REL format is more compact, + // and when TEXTRELs are not supported, all the dynamic relocation types that + // can be emitted encode their in-section addends straightforwardly with + // sufficient range for all cases supported by the small memory model (or + // never have addends at all, such as GLOB_DAT and JMP_SLOT). config->isRela = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || m == EM_X86_64; + if (config->relPackDynRelocs) + config->isRela = false; // If the output uses REL relocations we must store the dynamic relocation // addends to the output sections. We also store addends for RELA relocations diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -286,7 +286,7 @@ defm pack_dyn_relocs: Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">, - MetaVarName<"[none,android,relr,android+relr]">; + MetaVarName<"[none,android,relr,rel+relr,android+relr]">; defm use_android_relr_tags: B<"use-android-relr-tags", "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",