https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/91280
>From a0cfafb82db825512b0ca44778fa9d4bb435563d Mon Sep 17 00:00:00 2001 From: Fangrui Song <i...@maskray.me> Date: Mon, 6 May 2024 15:37:50 -0700 Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?= =?UTF-8?q?l=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.5-bogner --- clang/include/clang/Basic/CodeGenOptions.def | 1 + .../clang/Basic/DiagnosticDriverKinds.td | 3 + clang/include/clang/Driver/Options.td | 3 + clang/lib/CodeGen/BackendUtil.cpp | 1 + clang/lib/Driver/ToolChains/Clang.cpp | 18 ++ clang/lib/Driver/ToolChains/CommonArgs.cpp | 21 ++ clang/test/Driver/crel.c | 24 +++ clang/test/Misc/cc1as-crel.s | 6 + clang/tools/driver/cc1as_main.cpp | 6 + .../include/llvm/BinaryFormat/DynamicTags.def | 2 + llvm/include/llvm/BinaryFormat/ELF.h | 1 + llvm/include/llvm/MC/MCTargetOptions.h | 3 + .../llvm/MC/MCTargetOptionsCommandFlags.h | 1 + llvm/include/llvm/Object/ELF.h | 5 + llvm/include/llvm/Object/ELFObjectFile.h | 70 ++++++- llvm/include/llvm/Object/ELFTypes.h | 25 +++ llvm/lib/MC/ELFObjectWriter.cpp | 110 ++++++++--- llvm/lib/MC/MCTargetOptionsCommandFlags.cpp | 6 + llvm/lib/Object/ELF.cpp | 63 ++++++ llvm/lib/ObjectYAML/ELFEmitter.cpp | 60 +++++- llvm/lib/ObjectYAML/ELFYAML.cpp | 2 + llvm/test/MC/ELF/crel-32.s | 16 ++ llvm/test/MC/ELF/crel.s | 100 ++++++++++ llvm/test/tools/llvm-readobj/ELF/crel.test | 180 ++++++++++++++++++ .../tools/llvm-readobj/ELF/dynamic-reloc.test | 31 ++- .../llvm-readobj/ELF/relocation-errors.test | 19 +- .../yaml2obj/ELF/dynamic-relocations.yaml | 5 +- .../yaml2obj/ELF/reloc-sec-entry-size.yaml | 5 + .../tools/yaml2obj/ELF/relocation-crel.yaml | 63 ++++++ .../ELF/relocation-missing-symbol.yaml | 3 +- .../tools/yaml2obj/ELF/relocation-type.yaml | 4 +- llvm/tools/llvm-readobj/ELFDumper.cpp | 81 +++++++- 32 files changed, 883 insertions(+), 55 deletions(-) create mode 100644 clang/test/Driver/crel.c create mode 100644 clang/test/Misc/cc1as-crel.s create mode 100644 llvm/test/MC/ELF/crel-32.s create mode 100644 llvm/test/MC/ELF/crel.s create mode 100644 llvm/test/tools/llvm-readobj/ELF/crel.test create mode 100644 llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 340b08dd7e2a3..3229f77eef1fc 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -36,6 +36,7 @@ VALUE_CODEGENOPT(Name, Bits, Default) #endif CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as +CODEGENOPT(Crel, 1, 0) ///< -Wa,--crel CODEGENOPT(RelaxELFRelocations, 1, 1) ///< -Wa,-mrelax-relocations={yes,no} CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm. CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 9781fcaa4ff5e..e9cea8967c133 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -809,6 +809,9 @@ def warn_drv_missing_multilib : Warning< def note_drv_available_multilibs : Note< "available multilibs are:%0">; +def err_drv_experimental_crel : Error< + "-Wa,--experimental-crel must be specified to use -Wa,--crel. CREL is experimental and takes a non-standard section type code">; + def warn_android_unversioned_fallback : Warning< "Using unversioned Android target directory %0 for target %1. Unversioned" " directories will not be used in Clang 19. Provide a versioned directory" diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c9f7c4e5f718b..55f0c9aff6a49 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6958,6 +6958,9 @@ def massembler_no_warn : Flag<["-"], "massembler-no-warn">, def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">, HelpText<"Make assembler warnings fatal">, MarshallingInfoFlag<CodeGenOpts<"FatalWarnings">>; +def crel : Flag<["--"], "crel">, + HelpText<"Enable CREL relocation format (ELF only)">, + MarshallingInfoFlag<CodeGenOpts<"Crel">>; def mrelax_relocations_no : Flag<["-"], "mrelax-relocations=no">, HelpText<"Disable x86 relax relocations">, MarshallingInfoNegativeFlag<CodeGenOpts<"RelaxELFRelocations">>; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 22c3f8642ad8e..ed37085d69ac5 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -474,6 +474,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags, Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose; Options.MCOptions.Dwarf64 = CodeGenOpts.Dwarf64; Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments; + Options.MCOptions.Crel = CodeGenOpts.Crel; Options.MCOptions.X86RelaxRelocations = CodeGenOpts.RelaxELFRelocations; Options.MCOptions.CompressDebugSections = CodeGenOpts.getCompressDebugSections(); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0a2ea96de7382..0f4d8aa3ad793 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -2467,6 +2467,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, // arg after parsing the '-I' arg. bool TakeNextArg = false; + const llvm::Triple &Triple = C.getDefaultToolChain().getTriple(); + bool Crel = false, ExperimentalCrel = false; bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); bool UseNoExecStack = false; const char *MipsTargetFeature = nullptr; @@ -2590,6 +2592,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CmdArgs.push_back(Value.data()); + } else if (Value == "--crel") { + Crel = true; + } else if (Value == "--no-crel") { + Crel = false; + } else if (Value == "--experimental-crel") { + ExperimentalCrel = true; } else if (Value == "-mrelax-relocations=yes" || Value == "--mrelax-relocations=yes") { UseRelaxRelocations = true; @@ -2655,6 +2663,16 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } if (ImplicitIt.size()) AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt); + if (Crel) { + if (!ExperimentalCrel) + D.Diag(diag::err_drv_experimental_crel); + if (Triple.isOSBinFormatELF() && !Triple.isMIPS()) { + CmdArgs.push_back("--crel"); + } else { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-Wa,--crel" << D.getTargetTriple(); + } + } if (!UseRelaxRelocations) CmdArgs.push_back("-mrelax-relocations=no"); if (UseNoExecStack) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 6796b43a15502..8ba45aeafd056 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1072,6 +1072,27 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(), /*IsLTO=*/true, PluginOptPrefix); + + for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA)) { + bool Crel = false; + for (StringRef V : A->getValues()) { + if (V == "--crel") + Crel = true; + else if (V == "--no-crel") + Crel = false; + else + continue; + A->claim(); + } + if (Crel) { + if (Triple.isOSBinFormatELF() && !Triple.isMIPS()) { + CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "-crel")); + } else { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-Wa,--crel" << D.getTargetTriple(); + } + } + } } /// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the diff --git a/clang/test/Driver/crel.c b/clang/test/Driver/crel.c new file mode 100644 index 0000000000000..0dc0507705d72 --- /dev/null +++ b/clang/test/Driver/crel.c @@ -0,0 +1,24 @@ +// RUN: not %clang -### -c --target=x86_64 -Wa,--crel %s 2>&1 | FileCheck %s --check-prefix=NOEXP + +// NOEXP: error: -Wa,--experimental-crel must be specified to use -Wa,--crel. CREL is experimental and takes a non-standard section type code + +// RUN: %clang -### -c --target=x86_64 -Wa,--crel,--experimental-crel %s 2>&1 | FileCheck %s +// RUN: %clang -### -c --target=x86_64 -Wa,--crel,--no-crel,--experimental-crel %s 2>&1 | FileCheck %s --check-prefix=NO +// RUN: not %clang -### -c --target=arm64-apple-darwin -Wa,--crel,--experimental-crel %s 2>&1 | FileCheck %s --check-prefix=ERR +// RUN: not %clang -### -c --target=mips64 -Wa,--crel,--experimental-crel %s 2>&1 | FileCheck %s --check-prefix=ERR + +// RUN: %clang -### -c --target=aarch64 -Werror -Wa,--crel,--experimental-crel -x assembler %s -Werror 2>&1 | FileCheck %s --check-prefix=ASM +// RUN: not %clang -### -c --target=mips64 -Wa,--crel,--experimental-crel -x assembler %s 2>&1 | FileCheck %s --check-prefix=ERR + +// CHECK: "-cc1" {{.*}}"--crel" +// NO: "-cc1" +// NO-NOT: "--crel" +// ASM: "-cc1as" {{.*}}"--crel" +// ERR: error: unsupported option '-Wa,--crel' for target '{{.*}}' + +/// Don't bother with --experimental-crel for LTO. +// RUN: %clang -### --target=x86_64-linux -Werror -flto -Wa,--crel %s 2>&1 | FileCheck %s --check-prefix=LTO +// LTO: "-plugin-opt=-crel" + +// RUN: touch %t.o +// RUN: not %clang -### --target=mips64-linux-gnu -flto -Wa,--crel %t.o 2>&1 | FileCheck %s --check-prefix=ERR diff --git a/clang/test/Misc/cc1as-crel.s b/clang/test/Misc/cc1as-crel.s new file mode 100644 index 0000000000000..953f2a1f3d3bc --- /dev/null +++ b/clang/test/Misc/cc1as-crel.s @@ -0,0 +1,6 @@ +// REQUIRES: x86-registered-target +// RUN: %clang -cc1as -triple x86_64 %s -filetype obj --crel -o %t +// RUN: llvm-readelf -S %t | FileCheck %s + +// CHECK: .crel.text CREL +call foo diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index 86afe22fac24c..9d53cca7a0bf5 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -164,6 +164,9 @@ struct AssemblerInvocation { LLVM_PREFERRED_TYPE(bool) unsigned EmitCompactUnwindNonCanonical : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned Crel : 1; + /// The name of the relocation model to use. std::string RelocationModel; @@ -204,6 +207,7 @@ struct AssemblerInvocation { EmbedBitcode = 0; EmitDwarfUnwind = EmitDwarfUnwindType::Default; EmitCompactUnwindNonCanonical = false; + Crel = false; } static bool CreateFromArgs(AssemblerInvocation &Res, @@ -373,6 +377,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Opts.EmitCompactUnwindNonCanonical = Args.hasArg(OPT_femit_compact_unwind_non_canonical); + Opts.Crel = Args.hasArg(OPT_crel); Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file); @@ -429,6 +434,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, MCOptions.MCRelaxAll = Opts.RelaxAll; MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind; MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical; + MCOptions.Crel = Opts.Crel; MCOptions.X86RelaxRelocations = Opts.RelaxELFRelocations; MCOptions.CompressDebugSections = Opts.CompressDebugSections; MCOptions.AsSecureLogFile = Opts.AsSecureLogFile; diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def index 1502d375f5c45..d67a1e6de3678 100644 --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -86,6 +86,8 @@ DYNAMIC_TAG(RELRSZ, 35) // Size of Relr relocation table. DYNAMIC_TAG(RELR, 36) // Address of relocation table (Relr entries). DYNAMIC_TAG(RELRENT, 37) // Size of a Relr relocation entry. +DYNAMIC_TAG(CREL, 38) // CREL relocation table + DYNAMIC_TAG_MARKER(LOOS, 0x60000000) // Start of environment specific tags. DYNAMIC_TAG_MARKER(HIOS, 0x6FFFFFFF) // End of environment specific tags. DYNAMIC_TAG_MARKER(LOPROC, 0x70000000) // Start of processor specific tags. diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index f296acc2ca4bb..b5c546d8b67e7 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1079,6 +1079,7 @@ enum : unsigned { // Experimental support for SHT_RELR sections. For details, see proposal // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg SHT_RELR = 19, // Relocation entries; only offsets. + SHT_CREL = 20, // CREL relocation entries SHT_LOOS = 0x60000000, // Lowest operating system-specific type. // Android packed relocation section types. // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37 diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h index 0cf2806bd4804..98317712250bf 100644 --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -61,6 +61,9 @@ class MCTargetOptions { bool Dwarf64 : 1; + // Use CREL relocation format for ELF. + bool Crel = false; + // If true, prefer R_X86_64_[REX_]GOTPCRELX to R_X86_64_GOTPCREL on x86-64 // ELF. bool X86RelaxRelocations = true; diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h index fc35eea09c4b3..837f148e8f4ab 100644 --- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -49,6 +49,7 @@ bool getNoDeprecatedWarn(); bool getNoTypeCheck(); +bool getCrel(); bool getX86RelaxRelocations(); std::string getABIName(); diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 78b6b40cbddf6..26e38075f8db0 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -321,6 +321,11 @@ class ELFFile { std::vector<Elf_Rel> decode_relrs(Elf_Relr_Range relrs) const; + uint64_t crelHeader(ArrayRef<uint8_t> Content) const; + using RelsOrRelas = std::pair<std::vector<Elf_Rel>, std::vector<Elf_Rela>>; + Expected<RelsOrRelas> decodeCrel(ArrayRef<uint8_t> Content) const; + Expected<RelsOrRelas> crels(const Elf_Shdr &Sec) const; + Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr &Sec) const; /// Iterate over program header table. diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index 8cc09e7fd7d55..505ea9ede313a 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -29,6 +29,7 @@ #include "llvm/Support/ELFAttributes.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -292,6 +293,9 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section. + // Hold CREL relocations for SectionRef::relocations(). + mutable SmallVector<SmallVector<Elf_Crel, 0>, 0> Crels; + Error initContent() override; void moveSymbolNext(DataRefImpl &Symb) const override; @@ -446,6 +450,7 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { const Elf_Rel *getRel(DataRefImpl Rel) const; const Elf_Rela *getRela(DataRefImpl Rela) const; + Elf_Crel getCrel(DataRefImpl Rel) const; Expected<const Elf_Sym *> getSymbol(DataRefImpl Sym) const { return EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); @@ -1022,6 +1027,40 @@ ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const { uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin()); RelData.d.a = (Sec.p - SHT) / EF.getHeader().e_shentsize; RelData.d.b = 0; + if (reinterpret_cast<const Elf_Shdr *>(Sec.p)->sh_type == ELF::SHT_CREL) { + if (RelData.d.a + 1 > Crels.size()) + Crels.resize(RelData.d.a + 1); + if (Crels[RelData.d.a].empty()) { + ArrayRef<uint8_t> Content = cantFail(getSectionContents(Sec)); + DataExtractor Data(Content, true, 8); // endian/class is irrelevant + DataExtractor::Cursor Cur(0); + + const auto Hdr = Data.getULEB128(Cur); + const size_t Count = Hdr / 8, FlagBits = Hdr & 4 ? 3 : 2, Shift = Hdr % 4; + uintX_t Offset = 0, Addend = 0; + uint32_t Symidx = 0, Type = 0; + for (size_t i = 0; i != Count; ++i) { + const uint8_t B = Data.getU8(Cur); + Offset += B >> FlagBits; + if (B >= 0x80) + Offset += + (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits); + if (B & 1) + Symidx += Data.getSLEB128(Cur); + if (B & 2) + Type += Data.getSLEB128(Cur); + if (B & 4) + Addend += Data.getSLEB128(Cur); + if (!Cur) + break; + Crels[RelData.d.a].push_back( + Elf_Crel{Offset << Shift, uint32_t(Symidx), Type, + std::make_signed_t<typename ELFT::uint>(Addend)}); + } + if (!Cur) + consumeError(Cur.takeError()); + } + } return relocation_iterator(RelocationRef(RelData, this)); } @@ -1030,9 +1069,13 @@ relocation_iterator ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const { const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p); relocation_iterator Begin = section_rel_begin(Sec); + DataRefImpl RelData = Begin->getRawDataRefImpl(); + if (S->sh_type == ELF::SHT_CREL) { + RelData.d.b = Crels[RelData.d.a].size(); + return relocation_iterator(RelocationRef(RelData, this)); + } if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL) return Begin; - DataRefImpl RelData = Begin->getRawDataRefImpl(); const Elf_Shdr *RelSec = getRelSection(RelData); // Error check sh_link here so that getRelocationSymbol can just use it. @@ -1050,7 +1093,7 @@ Expected<section_iterator> ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { const Elf_Shdr *EShdr = getSection(Sec); uintX_t Type = EShdr->sh_type; - if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) + if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA && Type != ELF::SHT_CREL) return section_end(); Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info); @@ -1070,7 +1113,9 @@ symbol_iterator ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { uint32_t symbolIdx; const Elf_Shdr *sec = getRelSection(Rel); - if (sec->sh_type == ELF::SHT_REL) + if (sec->sh_type == ELF::SHT_CREL) + symbolIdx = getCrel(Rel).r_symidx; + else if (sec->sh_type == ELF::SHT_REL) symbolIdx = getRel(Rel)->getSymbol(EF.isMips64EL()); else symbolIdx = getRela(Rel)->getSymbol(EF.isMips64EL()); @@ -1087,6 +1132,8 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { template <class ELFT> uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const { const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_CREL) + return getCrel(Rel).r_offset; if (sec->sh_type == ELF::SHT_REL) return getRel(Rel)->r_offset; @@ -1096,6 +1143,8 @@ uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const { template <class ELFT> uint64_t ELFObjectFile<ELFT>::getRelocationType(DataRefImpl Rel) const { const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_CREL) + return getCrel(Rel).r_type; if (sec->sh_type == ELF::SHT_REL) return getRel(Rel)->getType(EF.isMips64EL()); else @@ -1117,9 +1166,11 @@ void ELFObjectFile<ELFT>::getRelocationTypeName( template <class ELFT> Expected<int64_t> ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const { - if (getRelSection(Rel)->sh_type != ELF::SHT_RELA) - return createError("Section is not SHT_RELA"); - return (int64_t)getRela(Rel)->r_addend; + if (getRelSection(Rel)->sh_type == ELF::SHT_RELA) + return (int64_t)getRela(Rel)->r_addend; + if (getRelSection(Rel)->sh_type == ELF::SHT_CREL) + return (int64_t)getCrel(Rel).r_addend; + return createError("Section is not SHT_RELA"); } template <class ELFT> @@ -1142,6 +1193,13 @@ ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const { return *Ret; } +template <class ELFT> +typename ELFObjectFile<ELFT>::Elf_Crel +ELFObjectFile<ELFT>::getCrel(DataRefImpl Rel) const { + assert(getRelSection(Rel)->sh_type == ELF::SHT_CREL); + return Crels[Rel.d.a][Rel.d.b]; +} + template <class ELFT> Expected<ELFObjectFile<ELFT>> ELFObjectFile<ELFT>::create(MemoryBufferRef Object, bool InitContent) { diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h index 4ab23e4ea81b1..aa07f4cacc4ab 100644 --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -32,6 +32,7 @@ template <class ELFT> struct Elf_Sym_Impl; template <class ELFT> struct Elf_Dyn_Impl; template <class ELFT> struct Elf_Phdr_Impl; template <class ELFT, bool isRela> struct Elf_Rel_Impl; +template <bool Is64> struct Elf_Crel_Impl; template <class ELFT> struct Elf_Verdef_Impl; template <class ELFT> struct Elf_Verdaux_Impl; template <class ELFT> struct Elf_Verneed_Impl; @@ -62,6 +63,7 @@ template <endianness E, bool Is64> struct ELFType { using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>; using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>; using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>; + using Crel = Elf_Crel_Impl<Is64>; using Relr = packed<uint>; using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>; using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>; @@ -117,6 +119,7 @@ using ELF64BE = ELFType<llvm::endianness::big, true>; using Elf_Phdr = typename ELFT::Phdr; \ using Elf_Rel = typename ELFT::Rel; \ using Elf_Rela = typename ELFT::Rela; \ + using Elf_Crel = typename ELFT::Crel; \ using Elf_Relr = typename ELFT::Relr; \ using Elf_Verdef = typename ELFT::Verdef; \ using Elf_Verdaux = typename ELFT::Verdaux; \ @@ -385,6 +388,7 @@ template <endianness Endianness> struct Elf_Rel_Impl<ELFType<Endianness, false>, false> { LLVM_ELF_IMPORT_TYPES(Endianness, false) static const bool IsRela = false; + static const bool IsCrel = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply @@ -421,6 +425,7 @@ struct Elf_Rel_Impl<ELFType<Endianness, false>, true> : public Elf_Rel_Impl<ELFType<Endianness, false>, false> { LLVM_ELF_IMPORT_TYPES(Endianness, false) static const bool IsRela = true; + static const bool IsCrel = false; Elf_Sword r_addend; // Compute value for relocatable field by adding this }; @@ -428,6 +433,7 @@ template <endianness Endianness> struct Elf_Rel_Impl<ELFType<Endianness, true>, false> { LLVM_ELF_IMPORT_TYPES(Endianness, true) static const bool IsRela = false; + static const bool IsCrel = false; Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply @@ -474,9 +480,28 @@ struct Elf_Rel_Impl<ELFType<Endianness, true>, true> : public Elf_Rel_Impl<ELFType<Endianness, true>, false> { LLVM_ELF_IMPORT_TYPES(Endianness, true) static const bool IsRela = true; + static const bool IsCrel = false; Elf_Sxword r_addend; // Compute value for relocatable field by adding this. }; +template <bool Is64> struct Elf_Crel_Impl { + using uint = std::conditional_t<Is64, uint64_t, uint32_t>; + static const bool IsRela = true; + static const bool IsCrel = true; + uint r_offset; + uint32_t r_symidx; + uint32_t r_type; + std::conditional_t<Is64, int64_t, int32_t> r_addend; + + // Dummy bool parameter is for compatibility with Elf_Rel_Impl. + uint32_t getType(bool) const { return r_type; } + uint32_t getSymbol(bool) const { return r_symidx; } + void setSymbolAndType(uint32_t s, unsigned char t, bool) { + r_symidx = s; + r_type = t; + } +}; + template <class ELFT> struct Elf_Ehdr_Impl { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index b8ef2654ed6e3..60a5d016b67aa 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -39,6 +39,7 @@ #include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" @@ -259,7 +260,7 @@ class ELFObjectWriter : public MCObjectWriter { void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override; - bool usesRela(const MCSectionELF &Sec) const; + bool usesRela(const MCTargetOptions *, const MCSectionELF &Sec) const; void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; @@ -831,7 +832,15 @@ MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx, Flags = ELF::SHF_GROUP; const StringRef SectionName = Sec.getName(); - const bool Rela = OWriter.usesRela(Sec); + const MCTargetOptions *TO = Ctx.getTargetOptions(); + if (TO && TO->Crel) { + MCSectionELF *RelaSection = + Ctx.createELFRelSection(".crel" + SectionName, ELF::SHT_CREL, Flags, + /*EntrySize=*/1, Sec.getGroup(), &Sec); + return RelaSection; + } + + const bool Rela = OWriter.usesRela(TO, Sec); unsigned EntrySize; if (Rela) EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); @@ -934,10 +943,50 @@ void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, WriteWord(EntrySize); // sh_entsize } +template <class uint> +static void encodeCrel(ArrayRef<ELFRelocationEntry> Relocs, raw_ostream &os) { + uint OffsetMask = 8, Offset = 0, Addend = 0; + uint32_t Symidx = 0, Type = 0; + // hdr & 4 indicates 3 flag bits in delta offset and flags members. + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) + OffsetMask |= Relocs[i].Offset; + const int Shift = llvm::countr_zero(OffsetMask); + encodeULEB128(Relocs.size() * 8 + /*addend_bit=*/4 + Shift, os); + for (const ELFRelocationEntry &Entry : Relocs) { + // The delta offset and flags member may be larger than uint64_t. Special + // case the first byte (3 flag bits and 4 offset bits). Other ULEB128 bytes + // encode the remaining delta offset bits. + auto DeltaOffset = static_cast<uint>((Entry.Offset - Offset) >> Shift); + Offset = Entry.Offset; + uint32_t CurSymidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; + uint8_t B = (DeltaOffset << 3) + (Symidx != CurSymidx) + + (Type != Entry.Type ? 2 : 0) + (Addend != Entry.Addend ? 4 : 0); + if (DeltaOffset < 0x10) { + os << char(B); + } else { + os << char(B | 0x80); + encodeULEB128(DeltaOffset >> 4, os); + } + if (B & 1) { + encodeSLEB128(static_cast<int32_t>(CurSymidx - Symidx), os); + Symidx = CurSymidx; + } + if (B & 2) { + encodeSLEB128(static_cast<int32_t>(Entry.Type - Type), os); + Type = Entry.Type; + } + if (B & 4) { + encodeSLEB128(std::make_signed_t<uint>(Entry.Addend - Addend), os); + Addend = Entry.Addend; + } + } +} + void ELFWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { std::vector<ELFRelocationEntry> &Relocs = OWriter.Relocations[&Sec]; - const bool Rela = OWriter.usesRela(Sec); + const MCTargetOptions *TO = Asm.getContext().getTargetOptions(); + const bool Rela = OWriter.usesRela(TO, Sec); // Sort the relocation entries. MIPS needs this. OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs); @@ -977,24 +1026,29 @@ void ELFWriter::writeRelocations(const MCAssembler &Asm, } } } - return; - } - for (const ELFRelocationEntry &Entry : Relocs) { - uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; - if (is64Bit()) { - write(Entry.Offset); - ELF::Elf64_Rela ERE; - ERE.setSymbolAndType(Symidx, Entry.Type); - write(ERE.r_info); - if (Rela) - write(Entry.Addend); - } else { - write(uint32_t(Entry.Offset)); - ELF::Elf32_Rela ERE; - ERE.setSymbolAndType(Symidx, Entry.Type); - write(ERE.r_info); - if (Rela) - write(uint32_t(Entry.Addend)); + } else if (TO && TO->Crel) { + if (is64Bit()) + encodeCrel<uint64_t>(Relocs, W.OS); + else + encodeCrel<uint32_t>(Relocs, W.OS); + } else { + for (const ELFRelocationEntry &Entry : Relocs) { + uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0; + if (is64Bit()) { + write(Entry.Offset); + ELF::Elf64_Rela ERE; + ERE.setSymbolAndType(Symidx, Entry.Type); + write(ERE.r_info); + if (Rela) + write(Entry.Addend); + } else { + write(uint32_t(Entry.Offset)); + ELF::Elf32_Rela ERE; + ERE.setSymbolAndType(Symidx, Entry.Type); + write(ERE.r_info); + if (Rela) + write(uint32_t(Entry.Addend)); + } } } } @@ -1014,7 +1068,8 @@ void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, llvm_unreachable("SHT_DYNAMIC in a relocatable object"); case ELF::SHT_REL: - case ELF::SHT_RELA: { + case ELF::SHT_RELA: + case ELF::SHT_CREL: { sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); const MCSection *InfoSection = Section.getLinkedToSection(); @@ -1443,6 +1498,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); + const MCTargetOptions *TO = Ctx.getTargetOptions(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol()); @@ -1498,7 +1554,7 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined() ? C + Layout.getSymbolOffset(*SymA) : C; - if (usesRela(FixupSection)) { + if (usesRela(TO, FixupSection)) { Addend = FixedValue; FixedValue = 0; } @@ -1527,9 +1583,11 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, Relocations[&FixupSection].push_back(Rec); } -bool ELFObjectWriter::usesRela(const MCSectionELF &Sec) const { - return hasRelocationAddend() && - Sec.getType() != ELF::SHT_LLVM_CALL_GRAPH_PROFILE; +bool ELFObjectWriter::usesRela(const MCTargetOptions *TO, + const MCSectionELF &Sec) const { + return (hasRelocationAddend() && + Sec.getType() != ELF::SHT_LLVM_CALL_GRAPH_PROFILE) || + (TO && TO->Crel); } bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl( diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp index 31bfcdc3e4e79..02279d6d90bc2 100644 --- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -46,6 +46,7 @@ MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) MCOPT(bool, NoDeprecatedWarn) MCOPT(bool, NoTypeCheck) +MCOPT(bool, Crel) MCOPT(bool, X86RelaxRelocations) MCOPT(std::string, ABIName) MCOPT(std::string, AsSecureLogFile) @@ -123,6 +124,10 @@ llvm::mc::RegisterMCTargetOptionsFlags::RegisterMCTargetOptionsFlags() { "no-type-check", cl::desc("Suppress type errors (Wasm)")); MCBINDOPT(NoTypeCheck); + static cl::opt<bool> Crel("crel", + cl::desc("Use CREL relocation format for ELF")); + MCBINDOPT(Crel); + static cl::opt<bool> X86RelaxRelocations( "x86-relax-relocations", cl::desc( @@ -156,6 +161,7 @@ MCTargetOptions llvm::mc::InitMCTargetOptionsFromFlags() { Options.MCNoWarn = getNoWarn(); Options.MCNoDeprecatedWarn = getNoDeprecatedWarn(); Options.MCNoTypeCheck = getNoTypeCheck(); + Options.Crel = getCrel(); Options.X86RelaxRelocations = getX86RelaxRelocations(); Options.EmitDwarfUnwind = getEmitDwarfUnwind(); Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical(); diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 0ac4e7a57759a..f7be77a792b44 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -303,6 +303,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); STRINGIFY_ENUM_CASE(ELF, SHT_RELR); + STRINGIFY_ENUM_CASE(ELF, SHT_CREL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR); @@ -392,6 +393,68 @@ ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const { return Relocs; } +template <class ELFT> +uint64_t ELFFile<ELFT>::crelHeader(ArrayRef<uint8_t> Content) const { + DataExtractor Data(Content, true, 8); // endian/class is irrelevant + DataExtractor::Cursor Cur(0); + uint64_t Hdr = Data.getULEB128(Cur); + // In case of an error, return 0 and postpone error reporting to decodeCrel. + consumeError(Cur.takeError()); + return Hdr; +} + +template <class ELFT> +Expected<typename ELFFile<ELFT>::RelsOrRelas> +ELFFile<ELFT>::decodeCrel(ArrayRef<uint8_t> Content) const { + DataExtractor Data(Content, true, 8); // endian/class is irrelevant + DataExtractor::Cursor Cur(0); + const uint64_t Hdr = Data.getULEB128(Cur); + const size_t Count = Hdr / 8, FlagBits = Hdr & 4 ? 3 : 2, Shift = Hdr % 4; + std::vector<Elf_Rel> Rels; + std::vector<Elf_Rela> Relas; + if (Hdr & 4) + Relas.resize(Count); + else + Rels.resize(Count); + typename ELFT::uint Offset = 0, Addend = 0; + uint32_t Symidx = 0, Type = 0; + for (size_t I = 0; I != Count; ++I) { + // For ELFCLASS64, decode a 65-bit integer where bit 0 indicates whether + // symidx/type are equal to the previous entry's. The remaining 64 bits + // encode the delta offset relative to the previous offset. + const uint8_t B = Data.getU8(Cur); + Offset += B >> FlagBits; + if (B >= 0x80) + Offset += (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits); + if (B & 1) + Symidx += Data.getSLEB128(Cur); + if (B & 2) + Type += Data.getSLEB128(Cur); + if (B & 4 & Hdr) + Addend += Data.getSLEB128(Cur); + if (Hdr & 4) { + Relas[I].r_offset = Offset << Shift; + Relas[I].setSymbolAndType(Symidx, Type, false); + Relas[I].r_addend = Addend; + } else { + Rels[I].r_offset = Offset << Shift; + Rels[I].setSymbolAndType(Symidx, Type, false); + } + } + if (!Cur) + return std::move(Cur.takeError()); + return std::make_pair(std::move(Rels), std::move(Relas)); +} + +template <class ELFT> +Expected<typename ELFFile<ELFT>::RelsOrRelas> +ELFFile<ELFT>::crels(const Elf_Shdr &Sec) const { + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + return decodeCrel(*ContentsOrErr); +} + template <class ELFT> Expected<std::vector<typename ELFT::Rela>> ELFFile<ELFT>::android_relas(const Elf_Shdr &Sec) const { diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp index b7118a543faed..6c700619f1ded 100644 --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -123,6 +123,12 @@ class ContiguousBlobAccumulator { return encodeULEB128(Val, OS); } + unsigned writeSLEB128(int64_t Val) { + if (!checkLimit(10)) + return 0; + return encodeSLEB128(Val, OS); + } + template <typename T> void write(T Val, llvm::endianness E) { if (checkLimit(sizeof(T))) support::endian::write<T>(OS, Val, E); @@ -1269,7 +1275,8 @@ void ELFState<ELFT>::writeSectionContent( Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section, ContiguousBlobAccumulator &CBA) { assert((Section.Type == llvm::ELF::SHT_REL || - Section.Type == llvm::ELF::SHT_RELA) && + Section.Type == llvm::ELF::SHT_RELA || + Section.Type == llvm::ELF::SHT_CREL) && "Section type is not SHT_REL nor SHT_RELA"); if (!Section.RelocatableSec.empty()) @@ -1278,29 +1285,68 @@ void ELFState<ELFT>::writeSectionContent( if (!Section.Relocations) return; + const bool IsCrel = Section.Type == llvm::ELF::SHT_CREL; const bool IsRela = Section.Type == llvm::ELF::SHT_RELA; + typename ELFT::uint OffsetMask = 8, Offset = 0, Addend = 0; + uint32_t Symidx = 0, Type = 0; + uint64_t CurrentOffset = CBA.getOffset(); + if (IsCrel) + for (const ELFYAML::Relocation &Rel : *Section.Relocations) + OffsetMask |= Rel.Offset; + const int Shift = llvm::countr_zero(OffsetMask); + if (IsCrel) + CBA.writeULEB128(Section.Relocations->size() * 8 + 4 + Shift); for (const ELFYAML::Relocation &Rel : *Section.Relocations) { const bool IsDynamic = Section.Link && (*Section.Link == ".dynsym"); - unsigned SymIdx = + uint32_t CurSymidx = Rel.Symbol ? toSymbolIndex(*Rel.Symbol, Section.Name, IsDynamic) : 0; - if (IsRela) { + if (IsCrel) { + // For 64-bit uint, encode a 65-bit integer where bit 0 indicates whether + // symidx/type are equal to the previous entry's. The remaining 64 bits + // encode the delta offset. + auto DeltaOffset = + (static_cast<typename ELFT::uint>(Rel.Offset) - Offset) >> Shift; + Offset = Rel.Offset; + uint8_t B = + DeltaOffset * 8 + (Symidx != CurSymidx) + (Type != Rel.Type ? 2 : 0) + + (Addend != static_cast<typename ELFT::uint>(Rel.Addend) ? 4 : 0); + if (DeltaOffset < 0x10) { + CBA.write(B); + } else { + CBA.write(B | 0x80); + CBA.writeULEB128(DeltaOffset >> 4); + } + if (B & 1) { + CBA.writeSLEB128( + std::make_signed_t<typename ELFT::uint>(CurSymidx - Symidx)); + Symidx = CurSymidx; + } + if (B & 2) { + CBA.writeSLEB128(static_cast<int32_t>(Rel.Type - Type)); + Type = Rel.Type; + } + if (B & 4) { + CBA.writeSLEB128( + std::make_signed_t<typename ELFT::uint>(Rel.Addend - Addend)); + Addend = Rel.Addend; + } + } else if (IsRela) { Elf_Rela REntry; zero(REntry); REntry.r_offset = Rel.Offset; REntry.r_addend = Rel.Addend; - REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); + REntry.setSymbolAndType(CurSymidx, Rel.Type, isMips64EL(Doc)); CBA.write((const char *)&REntry, sizeof(REntry)); } else { Elf_Rel REntry; zero(REntry); REntry.r_offset = Rel.Offset; - REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); + REntry.setSymbolAndType(CurSymidx, Rel.Type, isMips64EL(Doc)); CBA.write((const char *)&REntry, sizeof(REntry)); } } - SHeader.sh_size = (IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)) * - Section.Relocations->size(); + SHeader.sh_size = CBA.getOffset() - CurrentOffset; } template <class ELFT> diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 045211c44b907..e53bb06fefba2 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -686,6 +686,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration( ECase(SHT_GROUP); ECase(SHT_SYMTAB_SHNDX); ECase(SHT_RELR); + ECase(SHT_CREL); ECase(SHT_ANDROID_REL); ECase(SHT_ANDROID_RELA); ECase(SHT_ANDROID_RELR); @@ -1620,6 +1621,7 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping( break; case ELF::SHT_REL: case ELF::SHT_RELA: + case ELF::SHT_CREL: if (!IO.outputting()) Section.reset(new ELFYAML::RelocationSection()); sectionMapping(IO, *cast<ELFYAML::RelocationSection>(Section.get())); diff --git a/llvm/test/MC/ELF/crel-32.s b/llvm/test/MC/ELF/crel-32.s new file mode 100644 index 0000000000000..23303aeb53eaa --- /dev/null +++ b/llvm/test/MC/ELF/crel-32.s @@ -0,0 +1,16 @@ +# REQUIRES: powerpc-registered-target +# RUN: llvm-mc -filetype=obj -crel -triple=ppc %s -o %t.o +# RUN: llvm-readelf -Sr %t.o | FileCheck %s + +# CHECK: [ 3] .data PROGBITS 00000000 {{.*}} 000008 00 WA 0 0 1 +# CHECK-NEXT: [ 4] .crel.data CREL 00000000 {{.*}} 00000a 01 I 5 3 1 + +# CHECK: Relocation section '.crel.data' at offset {{.*}} contains 2 entries: +# CHECK-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend +# CHECK-NEXT: 00000000 {{.*}} R_PPC_NONE 00000000 a0 - 1 +# CHECK-NEXT: 00000004 {{.*}} R_PPC_ADDR32 00000000 a3 + 4000 + +.data +.reloc .+0, BFD_RELOC_NONE, a0-1 +.reloc .+4, BFD_RELOC_32, a3+0x4000 +.quad 0 diff --git a/llvm/test/MC/ELF/crel.s b/llvm/test/MC/ELF/crel.s new file mode 100644 index 0000000000000..221af9837f90a --- /dev/null +++ b/llvm/test/MC/ELF/crel.s @@ -0,0 +1,100 @@ +# RUN: llvm-mc -filetype=obj -crel -triple=x86_64 %s -o %t.o +# RUN: llvm-readelf -Sr -x .crelrodata2 -x .crelrodata16 %t.o | FileCheck %s + +# RUN: %if aarch64-registered-target %{ llvm-mc -filetype=obj -crel -triple=aarch64_be %s -o %t.be.o %} +# RUN: %if aarch64-registered-target %{ llvm-readelf -r %t.be.o | FileCheck %s --check-prefix=A64BE %} + +# CHECK: [ 4] .data PROGBITS 0000000000000000 {{.*}} 000008 00 WA 0 0 1 +# CHECK-NEXT: [ 5] .crel.data CREL 0000000000000000 {{.*}} 00002a 01 I 14 4 1 +# CHECK-NEXT: [ 6] .rodata PROGBITS 0000000000000000 {{.*}} 00002b 00 A 0 0 1 +# CHECK-NEXT: [ 7] .crel.rodata CREL 0000000000000000 {{.*}} 000010 01 I 14 6 1 +# CHECK-NEXT: [ 8] rodata2 PROGBITS 0000000000000000 {{.*}} 000008 00 A 0 0 1 +# CHECK-NEXT: [ 9] .crelrodata2 CREL 0000000000000000 {{.*}} 000005 01 I 14 8 1 +# CHECK-NEXT: [10] rodata16 PROGBITS 0000000000000000 {{.*}} 000010 00 A 0 0 1 +# CHECK-NEXT: [11] .crelrodata16 CREL 0000000000000000 {{.*}} 000004 01 I 14 10 1 +# CHECK-NEXT: [12] noalloc PROGBITS 0000000000000000 {{.*}} 000004 00 0 0 1 +# CHECK-NEXT: [13] .crelnoalloc CREL 0000000000000000 {{.*}} 000005 01 I 14 12 1 +# CHECK-NEXT: [14] .symtab SYMTAB + +# CHECK: Relocation section '.crel.data' at offset {{.*}} contains 7 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_NONE 0000000000000000 a0 + 0 +# CHECK-NEXT: 0000000000000001 {{.*}} R_X86_64_NONE 0000000000000000 a1 - 1 +# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_NONE 0000000000000000 a2 - 1 +# CHECK-NEXT: 0000000000000003 {{.*}} R_X86_64_32 0000000000000000 a3 + 4000 +# CHECK-NEXT: 0000000000000004 {{.*}} R_X86_64_64 0000000000000000 a0 - 8000000000000000 +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_64 0000000000000000 a1 + 7fffffffffffffff +# CHECK-NEXT: 0000000000000005 {{.*}} R_X86_64_32 0000000000000000 a1 - 1 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crel.rodata' at offset {{.*}} contains 4 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_PC32 0000000000000000 foo + 0 +# CHECK-NEXT: 000000000000000f {{.*}} R_X86_64_PC32 0000000000000000 foo + 3f +# CHECK-NEXT: 000000000000001f {{.*}} R_X86_64_PC64 0000000000000000 foo + 7f +# CHECK-NEXT: 0000000000000027 {{.*}} R_X86_64_PC32 0000000000000000 _start - 1f81 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelrodata2' at offset {{.*}} contains 2 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000002 {{.*}} R_X86_64_32 0000000000000000 .data + 0 +# CHECK-NEXT: 0000000000000008 {{.*}} R_X86_64_32 0000000000000000 .data + 0 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelrodata16' at offset {{.*}} contains 1 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000008 {{.*}} R_X86_64_64 0000000000000000 rodata16 + 0 +# CHECK-EMPTY: +# CHECK-NEXT: Relocation section '.crelnoalloc' at offset {{.*}} contains 1 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000000 {{.*}} R_X86_64_32 0000000000000000 .text + 4 + +## count * 8 + 4 + shift = 2*8+4+1 = 21 +# CHECK: Hex dump of section '.crelrodata2': +# CHECK-NEXT: 0x00000000 150b020a 18 . +## count * 8 + 4 + shift = 1*8+4+3 = 15 +# CHECK: Hex dump of section '.crelrodata16': +# CHECK-NEXT: 0x00000000 0f0b0301 . + +# A64BE: 0000000000000000 {{.*}} R_AARCH64_NONE 0000000000000000 a0 + 0 +# A64BE-NEXT: 0000000000000001 {{.*}} R_AARCH64_NONE 0000000000000000 a1 - 1 +# A64BE-NEXT: 0000000000000002 {{.*}} R_AARCH64_NONE 0000000000000000 a2 - 1 +# A64BE-NEXT: 0000000000000003 {{.*}} R_AARCH64_ABS32 0000000000000000 a3 + 4000 +# A64BE-NEXT: 0000000000000004 {{.*}} R_AARCH64_ABS64 0000000000000000 a0 - 8000000000000000 +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS64 0000000000000000 a1 + 7fffffffffffffff +# A64BE-NEXT: 0000000000000005 {{.*}} R_AARCH64_ABS32 0000000000000000 a1 - 1 + +.globl _start +_start: + ret + +.section .text.1,"ax" + ret + +.data +.reloc .+0, BFD_RELOC_NONE, a0 +.reloc .+1, BFD_RELOC_NONE, a1-1 +.reloc .+2, BFD_RELOC_NONE, a2-1 +.reloc .+3, BFD_RELOC_32, a3+0x4000 +.reloc .+4, BFD_RELOC_64, a0-0x8000000000000000 +.reloc .+5, BFD_RELOC_64, a1+0x7fffffffffffffff +.reloc .+5, BFD_RELOC_32, a1-1 +.quad 0 + +.section .rodata,"a" +.long foo - . +.space 15-4 +.long foo - . + 63 // offset+=15 +.space 16-4 +.quad foo - . + 127 // offset+=16 +.long _start - . - 8065 + +.section rodata2,"a" +.space 2 +.reloc ., BFD_RELOC_32, .data +.space 6 +.reloc ., BFD_RELOC_32, .data + +.section rodata16,"a" +.quad 0 +.quad rodata16 + +.section noalloc +.long .text + 4 diff --git a/llvm/test/tools/llvm-readobj/ELF/crel.test b/llvm/test/tools/llvm-readobj/ELF/crel.test new file mode 100644 index 0000000000000..383a8e26b2a77 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/crel.test @@ -0,0 +1,180 @@ +# RUN: yaml2obj --docnum=1 %s -o %t +# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=LLVM --match-full-lines +# RUN: llvm-readelf -r %t | FileCheck %s --check-prefix=GNU --match-full-lines + +# LLVM: Relocations [ +# LLVM-NEXT: Section ([[#]]) .crel.text { +# LLVM-NEXT: 0x1 R_X86_64_32 g1 0x1 +# LLVM-NEXT: 0x2 R_X86_64_64 l1 0x2 +# LLVM-NEXT: 0x0 R_X86_64_32S g1 0xFFFFFFFFFFFFFFFF +# LLVM-NEXT: 0x4 R_X86_64_32S .text 0x8000000000000000 +# LLVM-NEXT: } +# LLVM-NEXT: Section ([[#]]) .crelnonalloc { +# LLVM-NEXT: 0x10 R_X86_64_64 g1 0x1 +# LLVM-NEXT: 0x20 R_X86_64_64 g2 0x2 +# LLVM-NEXT: } +# LLVM-NEXT: ] + +# GNU: Relocation section '.crel.text' at offset 0x48 contains 4 entries: +# GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# GNU-NEXT: 0000000000000001 000000030000000a R_X86_64_32 0000000000000000 g1 + 1 +# GNU-NEXT: 0000000000000002 0000000200000001 R_X86_64_64 0000000000000000 l1 + 2 +# GNU-NEXT: 0000000000000000 000000030000000b R_X86_64_32S 0000000000000000 g1 - 1 +# GNU-NEXT: 0000000000000004 000000010000000b R_X86_64_32S 0000000000000000 .text - 8000000000000000 +# GNU-EMPTY: +# GNU-NEXT: Relocation section '.crelnonalloc' at offset 0xa2 contains 2 entries: +# GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# GNU-NEXT: 0000000000000010 0000000300000001 R_X86_64_64 0000000000000000 g1 + 1 +# GNU-NEXT: 0000000000000020 0000000400000001 R_X86_64_64 0000000000000000 g2 + 2 + +--- !ELF +FileHeader: !FileHeader + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +Sections: +- Name: .text + Type: SHT_PROGBITS + Content: "0000000000000000" + Flags: [SHF_ALLOC] +- Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 0x1 + Symbol: g1 + Type: R_X86_64_32 + Addend: 1 + - Offset: 0x2 + Symbol: l1 + Type: R_X86_64_64 + Addend: 2 + - Offset: 0x0 + Symbol: g1 + Type: R_X86_64_32S + Addend: 0xffffffffffffffff + - Offset: 0x4 + Symbol: .text + Type: R_X86_64_32S + Addend: 0x8000000000000000 +- Name: nonalloc + Type: SHT_PROGBITS + Size: 0x30 +- Name: .crelnonalloc + Type: SHT_CREL + Info: nonalloc + Link: .symtab + Relocations: + - Offset: 0x10 + Symbol: g1 + Type: R_X86_64_64 + Addend: 1 + - Offset: 0x20 + Symbol: g2 + Type: R_X86_64_64 + Addend: 2 + +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: l1 + - Name: g1 + Section: .text + Value: 0x0 + Size: 4 + Binding: STB_GLOBAL + - Name: g2 + Binding: STB_GLOBAL + +## Check relocation formatting on ELFCLASS32 as well. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=LLVM2 --match-full-lines +# RUN: llvm-readelf -r %t2 | FileCheck %s --check-prefix=GNU2 --match-full-lines + +# LLVM2: Relocations [ +# LLVM2-NEXT: Section (2) .crel.text { +# LLVM2-NEXT: 0x8 R_386_PC32 l1 0x1 +# LLVM2-NEXT: 0x4 R_386_32 g1 0x0 +# LLVM2-NEXT: } +# LLVM2-NEXT: ] + +# GNU2: Relocation section '.crel.text' at offset {{.*}} contains 2 entries: +# GNU2-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend +# GNU2-NEXT: 00000008 00000102 R_386_PC32 00000000 l1 + 1 +# GNU2-NEXT: 00000004 00000201 R_386_32 00000000 g1 + 0 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: +- Name: .text + Type: SHT_PROGBITS + Size: 0x10 +- Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 0x8 + Symbol: l1 + Type: R_386_PC32 + Addend: 1 + - Offset: 0x4 + Symbol: g1 + Type: R_386_32 +Symbols: + - Name: l1 + - Name: g1 + Binding: STB_GLOBAL + +## Check CREL with implicit addends. +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readobj -r %t3 | FileCheck %s --check-prefix=LLVM3 --match-full-lines +# RUN: llvm-readelf -r %t3 | FileCheck %s --check-prefix=GNU3 --match-full-lines + +# LLVM3: Relocations [ +# LLVM3-NEXT: Section (3) .crel.data { +# LLVM3-NEXT: 0x1F R_X86_64_32 g1 +# LLVM3-NEXT: 0x3F R_X86_64_64 g1 +# LLVM3-NEXT: 0x0 R_X86_64_32S l1 +# LLVM3-NEXT: } +# LLVM3-NEXT: ] + +# GNU3: Relocation section '.crel.data' at offset {{.*}} contains 3 entries: +# GNU3-NEXT: Offset Info Type Symbol's Value Symbol's Name +# GNU3-NEXT: 000000000000001f 000000030000000a R_X86_64_32 0000000000000000 g1 +# GNU3-NEXT: 000000000000003f 0000000300000001 R_X86_64_64 0000000000000000 g1 +# GNU3-NEXT: 0000000000000000 000000020000000b R_X86_64_32S 0000000000000000 l1 +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .data + Type: SHT_PROGBITS + - Name: .crel.data + Type: SHT_CREL + Flags: [ SHF_INFO_LINK ] + Link: .symtab + Info: .data + Content: 187f030a82017787feffffffffffffff077f0a +Symbols: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: l1 + Section: .text + - Name: g1 + Section: .text + Binding: STB_GLOBAL diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test index 89702b963c111..1e5b9e2e3c210 100644 --- a/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test +++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-reloc.test @@ -32,12 +32,17 @@ FileHeader: # RUN: --match-full-lines --check-prefixes=GNU-RELOCS,GNU-PLTRELA # LLVM-RELOCS: Dynamic Relocations { +# LLVM-RELOCS-NEXT: 0x8 R_X86_64_64 foo 0x0 # LLVM-RELOCS-NEXT: 0x1 R_X86_64_NONE foo 0x0 # LLVM-RELOCS-NEXT: 0x2 R_X86_64_NONE foo -# LLVM-RELOCS-NEXT: 0x4 R_X86_64_RELATIVE +# LLVM-RELOCS-NEXT: 0x4 R_X86_64_RELATIVE - # LLVM-RELOCS-NEXT: 0x8 R_X86_64_NONE foo # LLVM-RELOCS-NEXT: } +# GNU-RELOCS:'CREL' relocation section at offset 0xa8: +# GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name +# GNU-RELOCS-NEXT:0000000000000008 0000000100000001 R_X86_64_64 0000000000000000 foo + 0 +# GNU-RELOCS-EMPTY: # GNU-RELOCS:'RELA' relocation section at offset 0x78 contains 24 bytes: # GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-RELOCS-NEXT:0000000000000001 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 @@ -50,10 +55,10 @@ FileHeader: # GNU-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name # GNU-RELOCS-NEXT:0000000000000004 0000000000000008 R_X86_64_RELATIVE {{$}} # GNU-RELOCS-EMPTY: -# GNU-PLTREL-NEXT:'PLT' relocation section at offset 0xa8 contains 16 bytes: +# GNU-PLTREL-NEXT:'PLT' relocation section at offset 0xac contains 16 bytes: # GNU-PLTREL-NEXT: Offset Info Type Symbol's Value Symbol's Name # GNU-PLTREL-NEXT:0000000000000008 0000000100000000 R_X86_64_NONE 0000000000000000 foo -# GNU-PLTRELA-NEXT:'PLT' relocation section at offset 0xa8 contains 24 bytes: +# GNU-PLTRELA-NEXT:'PLT' relocation section at offset 0xac contains 24 bytes: # GNU-PLTRELA-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-PLTRELA-NEXT:0000000000000008 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 # GNU-RELOCS-EMPTY: @@ -82,6 +87,12 @@ Sections: Type: SHT_RELR Flags: [ SHF_ALLOC ] Entries: [ 0x0000000000000004 ] + - Name: .crel.dyn + Type: SHT_CREL + Relocations: + - Type: R_X86_64_64 + Offset: 0x8 + Symbol: foo - Name: .plt Type: [[PLTTYPE=SHT_REL]] Relocations: @@ -111,9 +122,12 @@ Sections: Value: 0x8 - Tag: DT_RELRENT Value: 0x8 -## 0x30 == offset of .plt section in the segment. - - Tag: DT_JMPREL +## 0x30 == offset of .crel.dyn section in the segment. + - Tag: DT_CREL Value: 0x30 +## 0x34 == offset of .plt section in the segment. + - Tag: DT_JMPREL + Value: 0x34 - Tag: DT_PLTREL Value: [[DTPLTREL=17]] ## 17 == DT_REL - Tag: DT_PLTRELSZ @@ -140,6 +154,7 @@ ProgramHeaders: # PLTRELUNKNOWN-LLVM: warning: '[[FILE]]': unknown DT_PLTREL value of 255 # PLTRELUNKNOWN-LLVM: Dynamic Relocations { +# PLTRELUNKNOWN-LLVM-NEXT: 0x8 R_X86_64_64 foo 0x0 # PLTRELUNKNOWN-LLVM-NEXT: 0x1 R_X86_64_NONE foo 0x0 # PLTRELUNKNOWN-LLVM-NEXT: 0x2 R_X86_64_NONE foo{{$}} # PLTRELUNKNOWN-LLVM-NEXT: 0x4 R_X86_64_RELATIVE -{{$}} @@ -148,6 +163,10 @@ ProgramHeaders: # PLTRELUNKNOWN-GNU: warning: '[[FILE]]': unknown DT_PLTREL value of 255 # PLTRELUNKNOWN-GNU-EMPTY: +# PLTRELUNKNOWN-GNU-NEXT: 'CREL' relocation section at offset 0xa8: +# PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name +# PLTRELUNKNOWN-GNU-NEXT: 0000000000000008 0000000100000001 R_X86_64_64 0000000000000000 foo + 0 +# PLTRELUNKNOWN-GNU-EMPTY: # PLTRELUNKNOWN-GNU-NEXT: 'RELA' relocation section at offset 0x78 contains 24 bytes: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # PLTRELUNKNOWN-GNU-NEXT: 0000000000000001 0000000100000000 R_X86_64_NONE 0000000000000000 foo + 0 @@ -160,6 +179,6 @@ ProgramHeaders: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name # PLTRELUNKNOWN-GNU-NEXT: 0000000000000004 0000000000000008 R_X86_64_RELATIVE # PLTRELUNKNOWN-GNU-EMPTY: -# PLTRELUNKNOWN-GNU-NEXT: 'PLT' relocation section at offset 0xa8 contains 16 bytes: +# PLTRELUNKNOWN-GNU-NEXT: 'PLT' relocation section at offset 0xac contains 16 bytes: # PLTRELUNKNOWN-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name # PLTRELUNKNOWN-GNU-NEXT: warning: '[[FILE]]': invalid DT_PLTRELSZ value (0x10) or PLTREL entry size (0x0) diff --git a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test index 22d1855c01163..87aab76de4c29 100644 --- a/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test +++ b/llvm/test/tools/llvm-readobj/ELF/relocation-errors.test @@ -37,6 +37,23 @@ # GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend # GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_RELA section with index 4: invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM +# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t64.crel +# RUN: llvm-readelf --relocations %t64.crel 2>&1 | FileCheck %s -DFILE=%t64.crel --check-prefix=CREL-GNU + +# CREL-GNU: Relocation section '.rel.text' at offset 0x41 contains 7 entries: +# CREL-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 1 in SHT_CREL section with index 3: unable to read an entry with index 4278124286 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: 0000000000000002 0000000000000000 R_X86_64_NONE 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 3 in SHT_CREL section with index 3: unable to read an entry with index 2 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 4 in SHT_CREL section with index 3: unable to read an entry with index 4 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 5 in SHT_CREL section with index 3: unable to read an entry with index 3 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 6 in SHT_CREL section with index 3: unable to read an entry with index 5 from SHT_NULL section with index 0: section [index 0] has invalid sh_entsize: expected 24, but got 0 +# CREL-GNU-EMPTY: +# CREL-GNU-NEXT: Relocation section '.rela.text' at offset 0x5a contains 1 entries: +# CREL-GNU-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CREL-GNU-NEXT: warning: '[[FILE]]': unable to print relocation 0 in SHT_RELA section with index 4: invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM + --- !ELF FileHeader: Class: ELFCLASS64 @@ -51,7 +68,7 @@ Sections: Type: SHT_PROGBITS ShName: 0xFEFEFEFE - Name: .rel.text - Type: SHT_REL + Type: [[TYPE=SHT_REL]] Info: .text Relocations: ## Case 1: There is no symbol with index 0xFEFEFEFE. diff --git a/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml b/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml index 8964877467f4a..c788a40e67788 100644 --- a/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml +++ b/llvm/test/tools/yaml2obj/ELF/dynamic-relocations.yaml @@ -4,6 +4,9 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-readelf -r %t | FileCheck %s +# RUN: yaml2obj -DTYPE=SHT_CREL %s -o %t.crel +# RUN: llvm-readelf -r %t.crel | FileCheck %s + # CHECK: Relocation section '.rela.dyn' at offset {{.*}} contains 2 entries: # CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name # CHECK-NEXT: 0000000000000000 0000000100000000 R_X86_64_NONE 0000000012345678 dynamic @@ -24,7 +27,7 @@ Sections: - Name: .data Type: SHT_PROGBITS - Name: .rela.dyn - Type: SHT_REL + Type: [[TYPE=SHT_REL]] Link: .dynsym Info: .data Relocations: diff --git a/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml b/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml index 43f6465c0a823..42621fa41d461 100644 --- a/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml +++ b/llvm/test/tools/yaml2obj/ELF/reloc-sec-entry-size.yaml @@ -12,6 +12,7 @@ # ELF64: .relr.default RELR 0000000000000000 000040 000000 08 # ELF64: .rela.custom RELA 0000000000000000 000040 000000 ff # ELF64: .rel.custom REL 0000000000000000 000040 000000 ff +# ELF64: .crel.custom CREL 0000000000000000 000040 000000 ff # ELF64: .relr.custom RELR 0000000000000000 000040 000000 ff # ELF32: Name Type Address Off Size ES @@ -20,6 +21,7 @@ # ELF32: .relr.default RELR 00000000 000034 000000 04 # ELF32: .rela.custom RELA 00000000 000034 000000 ff # ELF32: .rel.custom REL 00000000 000034 000000 ff +# ELF32: .crel.custom CREL 00000000 000034 000000 ff # ELF32: .relr.custom RELR 00000000 000034 000000 ff --- !ELF @@ -42,6 +44,9 @@ Sections: - Name: .rel.custom Type: SHT_REL EntSize: 0xFF + - Name: .crel.custom + Type: SHT_CREL + EntSize: 0xFF - Name: .relr.custom Type: SHT_RELR EntSize: 0xFF diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml new file mode 100644 index 0000000000000..c6006754614bb --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/relocation-crel.yaml @@ -0,0 +1,63 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf -r %t | FileCheck %s + +# CHECK: Relocation section '.crel.text' at offset {{.*}} contains 7 entries: +# CHECK-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# CHECK-NEXT: 0000000000000001 0000000100000004 R_X86_64_PLT32 0000000000000000 a0 - 4 +# CHECK-NEXT: 0000000000000005 0000000200000004 R_X86_64_PLT32 0000000000000000 a1 - 4 +# CHECK-NEXT: 000000000000000a 0000000300000004 R_X86_64_PLT32 0000000000000000 a2 + 0 +# CHECK-NEXT: 0000000000000010 0000000200000001 R_X86_64_64 0000000000000000 a1 - 4 +# CHECK-NEXT: 0000000000000018 0000000100000001 R_X86_64_64 0000000000000000 a0 + 80 +# CHECK-NEXT: 0000000000000020 0000000000000008 R_X86_64_RELATIVE 8000000000000000 +# CHECK-NEXT: 0000000000000028 0000000400000001 R_X86_64_64 0000000000000000 a3 + 7fffffffffffffff + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + - Name: .crel.text + Type: SHT_CREL + Info: .text + Link: .symtab + Relocations: + - Offset: 1 + Type: R_X86_64_PLT32 + Symbol: a0 + Addend: -4 + - Offset: 5 + Type: R_X86_64_PLT32 + Symbol: a1 + Addend: -4 + - Offset: 10 + Type: R_X86_64_PLT32 + Symbol: a2 + Addend: 0 + - Offset: 16 + Type: R_X86_64_64 + Symbol: a1 + Addend: -4 + - Offset: 24 + Type: R_X86_64_64 + Symbol: a0 + Addend: 128 + - Offset: 32 + Type: R_X86_64_RELATIVE + Addend: 0x8000000000000000 + - Offset: 40 + Type: R_X86_64_64 + Symbol: a3 + Addend: 0x7fffffffffffffff +Symbols: + - Name: a0 + Binding: STB_GLOBAL + - Name: a1 + Binding: STB_GLOBAL + - Name: a2 + Binding: STB_GLOBAL + - Name: a3 + Binding: STB_GLOBAL diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml index 2f8d98dee18a8..1eb376fb5c1ab 100644 --- a/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml +++ b/llvm/test/tools/yaml2obj/ELF/relocation-missing-symbol.yaml @@ -2,6 +2,7 @@ ## does not exist. # RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s +# RUN: not yaml2obj -DTYPE=SHT_CREL %s -o %t 2>&1 | FileCheck %s ## Check we are able to report multiple errors. @@ -18,7 +19,7 @@ Sections: - Name: .text Type: SHT_PROGBITS - Name: .rela.text - Type: SHT_RELA + Type: [[TYPE=SHT_RELA]] Info: .text Link: .symtab Relocations: diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml index 67d451df2f7ff..0aabde4ce1994 100644 --- a/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml +++ b/llvm/test/tools/yaml2obj/ELF/relocation-type.yaml @@ -3,6 +3,8 @@ ## Show that yaml2obj is able to produce relocations for an unknown e_machine kind properly. # RUN: yaml2obj %s -o %t1 -DMACHINE=0x1234 # RUN: llvm-readelf %t1 --relocations | FileCheck %s -DFIRST=Unknown -DSECOND=Unknown +# RUN: yaml2obj %s -o %t1 -DMACHINE=0x1234 -DTYPE=SHT_CREL +# RUN: llvm-readelf %t1 --relocations | FileCheck %s -DFIRST=Unknown -DSECOND=Unknown # CHECK: Relocation section '.rela.text' at offset 0x40 contains 4 entries: # CHECK: Offset Info Type @@ -23,7 +25,7 @@ FileHeader: Machine: [[MACHINE]] Sections: - Name: .rela.text - Type: SHT_RELA + Type: [[TYPE=SHT_RELA]] Relocations: ## Test a few noticeable possible values: 0, 1, max(int8_t)=127, max(uint8_t)=0xFF=-1 - Offset: 0x9 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index a752cc4015293..662bacf54a4ef 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -378,6 +378,7 @@ template <typename ELFT> class ELFDumper : public ObjDumper { DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; + DynRegionInfo DynCrelRegion; DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; std::optional<DynRegionInfo> DynSymRegion; @@ -1903,7 +1904,7 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O, ScopedPrinter &Writer) : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), FileName(O.getFileName()), DynRelRegion(O, *this), - DynRelaRegion(O, *this), DynRelrRegion(O, *this), + DynRelaRegion(O, *this), DynCrelRegion(O, *this), DynRelrRegion(O, *this), DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), DynamicTable(O, *this) { if (!O.IsContentValid()) @@ -2062,6 +2063,9 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { DynRelaRegion.EntSize = Dyn.getVal(); DynRelaRegion.EntSizePrintName = "DT_RELAENT value"; break; + case ELF::DT_CREL: + DynCrelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); + break; case ELF::DT_SONAME: SONameOffset = Dyn.getVal(); break; @@ -2102,6 +2106,8 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { DynPLTRelRegion.EntSize = sizeof(Elf_Rel); else if (Dyn.getVal() == DT_RELA) DynPLTRelRegion.EntSize = sizeof(Elf_Rela); + else if (Dyn.getVal() == DT_CREL) + DynPLTRelRegion.EntSize = 1; else reportUniqueWarning(Twine("unknown DT_PLTREL value of ") + Twine((uint64_t)Dyn.getVal())); @@ -2421,6 +2427,8 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, return "REL"; if (Value == DT_RELA) return "RELA"; + if (Value == DT_CREL) + return "CREL"; [[fallthrough]]; case DT_PLTGOT: case DT_HASH: @@ -2435,6 +2443,7 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_CREL: case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: @@ -3840,14 +3849,15 @@ void GNUELFDumper<ELFT>::printRelRelaReloc(const Relocation<ELFT> &R, template <class ELFT> static void printRelocHeaderFields(formatted_raw_ostream &OS, unsigned SType, - const typename ELFT::Ehdr &EHeader) { + const typename ELFT::Ehdr &EHeader, + uint64_t CrelHdr = 0) { bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA; if (ELFT::Is64Bits) OS << " Offset Info Type Symbol's " "Value Symbol's Name"; else OS << " Offset Info Type Sym. Value Symbol's Name"; - if (IsRela) + if (IsRela || (SType == ELF::SHT_CREL && (CrelHdr & 4))) OS << " + Addend"; OS << "\n"; } @@ -3857,7 +3867,10 @@ void GNUELFDumper<ELFT>::printDynamicRelocHeader(unsigned Type, StringRef Name, const DynRegionInfo &Reg) { uint64_t Offset = Reg.Addr - this->Obj.base(); OS << "\n'" << Name.str().c_str() << "' relocation section at offset 0x" - << utohexstr(Offset, /*LowerCase=*/true) << " contains " << Reg.Size << " bytes:\n"; + << utohexstr(Offset, /*LowerCase=*/true); + if (Type != ELF::SHT_CREL) + OS << " contains " << Reg.Size << " bytes"; + OS << ":\n"; printRelocHeaderFields<ELFT>(OS, Type, this->Obj.getHeader()); } @@ -3865,7 +3878,8 @@ template <class ELFT> static bool isRelocationSec(const typename ELFT::Shdr &Sec, const typename ELFT::Ehdr &EHeader) { return Sec.sh_type == ELF::SHT_REL || Sec.sh_type == ELF::SHT_RELA || - Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_ANDROID_REL || + Sec.sh_type == ELF::SHT_RELR || Sec.sh_type == ELF::SHT_CREL || + Sec.sh_type == ELF::SHT_ANDROID_REL || Sec.sh_type == ELF::SHT_ANDROID_RELA || Sec.sh_type == ELF::SHT_ANDROID_RELR || (EHeader.e_machine == EM_AARCH64 && @@ -3891,6 +3905,14 @@ template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() { return RelasOrErr->size(); } + if (Sec.sh_type == ELF::SHT_CREL) { + Expected<ArrayRef<uint8_t>> ContentsOrErr = + this->Obj.getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + return this->Obj.crelHeader(*ContentsOrErr) / 8; + } + if (PrintAsRelr(Sec)) { Expected<Elf_Relr_Range> RelrsOrErr = this->Obj.relrs(Sec); if (!RelrsOrErr) @@ -3924,7 +3946,13 @@ template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() { if (PrintAsRelr(Sec)) { printRelr(Sec); } else { - printRelocHeaderFields<ELFT>(OS, Sec.sh_type, this->Obj.getHeader()); + uint64_t CrelHdr = 0; + if (auto ContentsOrErr = this->Obj.getSectionContents(Sec)) + CrelHdr = this->Obj.crelHeader(*ContentsOrErr); + else + consumeError(ContentsOrErr.takeError()); + printRelocHeaderFields<ELFT>(OS, Sec.sh_type, this->Obj.getHeader(), + CrelHdr); this->printRelocationsHelper(Sec); } } @@ -4888,6 +4916,34 @@ void ELFDumper<ELFT>::printRelocationsHelper(const Elf_Shdr &Sec) { template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocationsHelper() { const bool IsMips64EL = this->Obj.isMips64EL(); + auto DumpCrelRegion = [&](DynRegionInfo &Region) { + // While the size is unknown, a valid CREL has at least one byte. We can + // check whether Addr is in bounds, and then decode CREL until the file + // end. + Region.Size = Region.EntSize = 1; + if (!Region.template getAsArrayRef<uint8_t>().empty()) { + const uint64_t Offset = + Region.Addr - + (const uint8_t *)ObjF.getMemoryBufferRef().getBufferStart(); + const uint64_t ObjSize = ObjF.getMemoryBufferRef().getBufferSize(); + auto RelsOrRelas = + Obj.decodeCrel(ArrayRef<uint8_t>(Region.Addr, ObjSize - Offset)); + if (!RelsOrRelas) { + reportUniqueWarning(toString(RelsOrRelas.takeError())); + } else { + for (const Elf_Rel &R : RelsOrRelas->first) + printDynamicReloc(Relocation<ELFT>(R, false)); + for (const Elf_Rela &R : RelsOrRelas->second) + printDynamicReloc(Relocation<ELFT>(R, false)); + } + } + }; + + if (this->DynCrelRegion.Addr) { + printDynamicRelocHeader(ELF::SHT_CREL, "CREL", this->DynCrelRegion); + DumpCrelRegion(this->DynCrelRegion); + } + if (this->DynRelaRegion.Size > 0) { printDynamicRelocHeader(ELF::SHT_RELA, "RELA", this->DynRelaRegion); for (const Elf_Rela &Rela : @@ -4916,6 +4972,8 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocationsHelper() { for (const Elf_Rela &Rela : this->DynPLTRelRegion.template getAsArrayRef<Elf_Rela>()) printDynamicReloc(Relocation<ELFT>(Rela, IsMips64EL)); + } else if (this->DynPLTRelRegion.EntSize == 1) { + DumpCrelRegion(this->DynPLTRelRegion); } else { printDynamicRelocHeader(ELF::SHT_REL, "PLT", this->DynPLTRelRegion); for (const Elf_Rel &Rel : @@ -6410,6 +6468,17 @@ void ELFDumper<ELFT>::forEachRelocationDo( /*SymTab=*/nullptr); break; } + case ELF::SHT_CREL: { + if (auto RelsOrRelas = Obj.crels(Sec)) { + for (const Elf_Rel &R : RelsOrRelas->first) + RelRelaFn(Relocation<ELFT>(R, false), RelNdx++, Sec, SymTab); + for (const Elf_Rela &R : RelsOrRelas->second) + RelRelaFn(Relocation<ELFT>(R, false), RelNdx++, Sec, SymTab); + } else { + Warn(RelsOrRelas.takeError()); + } + break; + } case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: if (Expected<std::vector<Elf_Rela>> RelasOrErr = Obj.android_relas(Sec)) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits