aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/ELF.cpp
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2024-07-01 10:32:02 -0700
committerGitHub <noreply@github.com>2024-07-01 10:32:02 -0700
commit1b704e889f09b5dfc0549786542bc6d2cd54e85b (patch)
tree30121301b878a128b496dcd600dedff1e366a107 /llvm/lib/Object/ELF.cpp
parent7926c0b594203ca1efe3d2a73a3f4066363bac5a (diff)
downloadllvm-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.cpp68
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,