[llvm] 1952dba - [MC,ELF] Extract CREL encoder code

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 8 09:28:19 PDT 2024


Author: Fangrui Song
Date: 2024-07-08T09:28:09-07:00
New Revision: 1952dba49abdda848512d11fc68c031a0a21ec50

URL: https://github.com/llvm/llvm-project/commit/1952dba49abdda848512d11fc68c031a0a21ec50
DIFF: https://github.com/llvm/llvm-project/commit/1952dba49abdda848512d11fc68c031a0a21ec50.diff

LOG: [MC,ELF] Extract CREL encoder code

The extracted ELFObjectWriter.cpp code will be reused by llvm-objcopy
support (#97521).

Added: 
    llvm/include/llvm/MC/MCELFExtras.h

Modified: 
    llvm/include/llvm/BinaryFormat/ELF.h
    llvm/lib/MC/ELFObjectWriter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 32cc9ff8cbb78..456cffff6b4a7 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -22,6 +22,7 @@
 #include "llvm/ADT/StringRef.h"
 #include <cstdint>
 #include <cstring>
+#include <type_traits>
 
 namespace llvm {
 namespace ELF {
@@ -1430,6 +1431,14 @@ struct Elf64_Rela {
   }
 };
 
+// In-memory representation of CREL. The serialized representation uses LEB128.
+template <bool Is64> struct Elf_Crel {
+  std::conditional_t<Is64, uint64_t, uint32_t> r_offset;
+  uint32_t r_symidx;
+  uint32_t r_type;
+  std::conditional_t<Is64, int64_t, int32_t> r_addend;
+};
+
 // Relocation entry without explicit addend or info (relative relocations only).
 typedef Elf64_Xword Elf64_Relr; // offset/bitmap for relative relocations
 

diff  --git a/llvm/include/llvm/MC/MCELFExtras.h b/llvm/include/llvm/MC/MCELFExtras.h
new file mode 100644
index 0000000000000..2c0718886a11b
--- /dev/null
+++ b/llvm/include/llvm/MC/MCELFExtras.h
@@ -0,0 +1,63 @@
+//===- MCELFExtras.h - Extra functions for ELF ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCELFEXTRAS_H
+#define LLVM_MC_MCELFEXTRAS_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/bit.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdint>
+#include <type_traits>
+
+namespace llvm::ELF {
+// Encode relocations as CREL to OS. ToCrel is responsible for converting a
+// const RelocsTy & to an Elf_Crel.
+template <bool Is64, class RelocsTy, class F>
+void encodeCrel(raw_ostream &OS, RelocsTy Relocs, F ToCrel) {
+  using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
+  uint OffsetMask = 8, Offset = 0, Addend = 0;
+  uint32_t SymIdx = 0, Type = 0;
+  for (const auto &R : Relocs)
+    OffsetMask |= ToCrel(R).r_offset;
+  const int Shift = llvm::countr_zero(OffsetMask);
+  encodeULEB128(Relocs.size() * 8 + ELF::CREL_HDR_ADDEND + Shift, OS);
+  for (const auto &R : Relocs) {
+    auto CR = ToCrel(R);
+    auto DeltaOffset = static_cast<uint>((CR.r_offset - Offset) >> Shift);
+    Offset = CR.r_offset;
+    uint8_t B = (DeltaOffset << 3) + (SymIdx != CR.r_symidx) +
+                (Type != CR.r_type ? 2 : 0) +
+                (Addend != uint(CR.r_addend) ? 4 : 0);
+    if (DeltaOffset < 0x10) {
+      OS << char(B);
+    } else {
+      OS << char(B | 0x80);
+      encodeULEB128(DeltaOffset >> 4, OS);
+    }
+    // Delta symidx/type/addend members (SLEB128).
+    if (B & 1) {
+      encodeSLEB128(static_cast<int32_t>(CR.r_symidx - SymIdx), OS);
+      SymIdx = CR.r_symidx;
+    }
+    if (B & 2) {
+      encodeSLEB128(static_cast<int32_t>(CR.r_type - Type), OS);
+      Type = CR.r_type;
+    }
+    if (B & 4) {
+      encodeSLEB128(std::make_signed_t<uint>(CR.r_addend - Addend), OS);
+      Addend = CR.r_addend;
+    }
+  }
+}
+} // namespace llvm::ELF
+
+#endif

diff  --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
index 5cba6eb15b5c9..59d796b419b35 100644
--- a/llvm/lib/MC/ELFObjectWriter.cpp
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -23,6 +23,7 @@
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCELFExtras.h"
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCFixup.h"
@@ -903,44 +904,14 @@ void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
   WriteWord(EntrySize); // sh_entsize
 }
 
-template <class uint>
+template <bool Is64>
 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 (const ELFRelocationEntry &Entry : Relocs)
-    OffsetMask |= Entry.Offset;
-  const int Shift = llvm::countr_zero(OffsetMask);
-  encodeULEB128(Relocs.size() * 8 + ELF::CREL_HDR_ADDEND + 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);
-    }
-    // Delta symidx/type/addend members (SLEB128).
-    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;
-    }
-  }
+  using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
+  ELF::encodeCrel<Is64>(OS, Relocs, [&](const ELFRelocationEntry &R) {
+    uint32_t SymIdx = R.Symbol ? R.Symbol->getIndex() : 0;
+    return ELF::Elf_Crel<Is64>{static_cast<uint>(R.Offset), SymIdx, R.Type,
+                               std::make_signed_t<uint>(R.Addend)};
+  });
 }
 
 void ELFWriter::writeRelocations(const MCAssembler &Asm,
@@ -989,9 +960,9 @@ void ELFWriter::writeRelocations(const MCAssembler &Asm,
     }
   } else if (TO && TO->Crel) {
     if (is64Bit())
-      encodeCrel<uint64_t>(Relocs, W.OS);
+      encodeCrel<true>(Relocs, W.OS);
     else
-      encodeCrel<uint32_t>(Relocs, W.OS);
+      encodeCrel<false>(Relocs, W.OS);
   } else {
     for (const ELFRelocationEntry &Entry : Relocs) {
       uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0;


        


More information about the llvm-commits mailing list