diff options
author | Fangrui Song <i@maskray.me> | 2024-07-01 10:32:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-01 10:32:02 -0700 |
commit | 1b704e889f09b5dfc0549786542bc6d2cd54e85b (patch) | |
tree | 30121301b878a128b496dcd600dedff1e366a107 /llvm/lib/Object/ELF.cpp | |
parent | 7926c0b594203ca1efe3d2a73a3f4066363bac5a (diff) | |
download | llvm-1b704e889f09b5dfc0549786542bc6d2cd54e85b.zip llvm-1b704e889f09b5dfc0549786542bc6d2cd54e85b.tar.gz llvm-1b704e889f09b5dfc0549786542bc6d2cd54e85b.tar.bz2 |
[MC,llvm-readobj,yaml2obj] Support CREL relocation format
CREL is a compact relocation format for the ELF object file format.
This patch adds integrated assembler support (using the RELA form)
available with `llvm-mc -filetype=obj -crel a.s -o a.o`.
A dependent patch will add `clang -c -Wa,--crel,--allow-experimental-crel`.
Also add llvm-readobj support (for both REL and RELA forms) to
facilitate testing the assembler. Additionally, yaml2obj gains support
for the RELA form to aid testing with llvm-readobj.
We temporarily assign the section type code 0x40000020 from the generic
range to `SHT_CREL`. We avoided using `SHT_LLVM_` or `SHT_GNU_` to
avoid code churn and maintain broader applicability for interested psABIs.
Similarly, `DT_CREL` is temporarily 0x40000026.
LLVM will change the code and break compatibility. This is not an issue
if all relocatable files using CREL are regenerated (aka no prebuilt
relocatable files).
Link: https://discourse.llvm.org/t/rfc-crel-a-compact-relocation-format-for-elf/77600
Pull Request: https://github.com/llvm/llvm-project/pull/91280
Diffstat (limited to 'llvm/lib/Object/ELF.cpp')
-rw-r--r-- | llvm/lib/Object/ELF.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 0ac4e7a..18a1167 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); @@ -393,6 +394,73 @@ ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const { } template <class ELFT> +Expected<uint64_t> +ELFFile<ELFT>::getCrelHeader(ArrayRef<uint8_t> Content) const { + DataExtractor Data(Content, isLE(), sizeof(typename ELFT::Addr)); + Error Err = Error::success(); + uint64_t Hdr = 0; + Hdr = Data.getULEB128(&Hdr, &Err); + if (Err) + return Err; + return Hdr; +} + +template <class ELFT> +Expected<typename ELFFile<ELFT>::RelsOrRelas> +ELFFile<ELFT>::decodeCrel(ArrayRef<uint8_t> Content) const { + DataExtractor Data(Content, isLE(), sizeof(typename ELFT::Addr)); + DataExtractor::Cursor Cur(0); + const uint64_t Hdr = Data.getULEB128(Cur); + const size_t Count = Hdr / 8; + const size_t FlagBits = Hdr & ELF::CREL_HDR_ADDEND ? 3 : 2; + const size_t Shift = Hdr % ELF::CREL_HDR_ADDEND; + std::vector<Elf_Rel> Rels; + std::vector<Elf_Rela> Relas; + if (Hdr & ELF::CREL_HDR_ADDEND) + 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) { + // The delta offset and flags member may be larger than uint64_t. Special + // case the first byte (2 or 3 flag bits; the rest are offset bits). Other + // ULEB128 bytes encode the remaining delta offset bits. + const uint8_t B = Data.getU8(Cur); + Offset += B >> FlagBits; + if (B >= 0x80) + Offset += (Data.getULEB128(Cur) << (7 - FlagBits)) - (0x80 >> FlagBits); + // Delta symidx/type/addend members (SLEB128). + if (B & 1) + SymIdx += Data.getSLEB128(Cur); + if (B & 2) + Type += Data.getSLEB128(Cur); + if (B & 4 & Hdr) + Addend += Data.getSLEB128(Cur); + if (Hdr & ELF::CREL_HDR_ADDEND) { + 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 { // This function reads relocations in Android's packed relocation format, |