Skip to content

Commit 1952dba

Browse files
committed
[MC,ELF] Extract CREL encoder code
The extracted ELFObjectWriter.cpp code will be reused by llvm-objcopy support (#97521).
1 parent 0387a86 commit 1952dba

File tree

3 files changed

+82
-39
lines changed

3 files changed

+82
-39
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ADT/StringRef.h"
2323
#include <cstdint>
2424
#include <cstring>
25+
#include <type_traits>
2526

2627
namespace llvm {
2728
namespace ELF {
@@ -1430,6 +1431,14 @@ struct Elf64_Rela {
14301431
}
14311432
};
14321433

1434+
// In-memory representation of CREL. The serialized representation uses LEB128.
1435+
template <bool Is64> struct Elf_Crel {
1436+
std::conditional_t<Is64, uint64_t, uint32_t> r_offset;
1437+
uint32_t r_symidx;
1438+
uint32_t r_type;
1439+
std::conditional_t<Is64, int64_t, int32_t> r_addend;
1440+
};
1441+
14331442
// Relocation entry without explicit addend or info (relative relocations only).
14341443
typedef Elf64_Xword Elf64_Relr; // offset/bitmap for relative relocations
14351444

llvm/include/llvm/MC/MCELFExtras.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===- MCELFExtras.h - Extra functions for ELF ------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_MC_MCELFEXTRAS_H
10+
#define LLVM_MC_MCELFEXTRAS_H
11+
12+
#include "llvm/ADT/STLExtras.h"
13+
#include "llvm/ADT/bit.h"
14+
#include "llvm/BinaryFormat/ELF.h"
15+
#include "llvm/Support/LEB128.h"
16+
#include "llvm/Support/raw_ostream.h"
17+
18+
#include <cstdint>
19+
#include <type_traits>
20+
21+
namespace llvm::ELF {
22+
// Encode relocations as CREL to OS. ToCrel is responsible for converting a
23+
// const RelocsTy & to an Elf_Crel.
24+
template <bool Is64, class RelocsTy, class F>
25+
void encodeCrel(raw_ostream &OS, RelocsTy Relocs, F ToCrel) {
26+
using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
27+
uint OffsetMask = 8, Offset = 0, Addend = 0;
28+
uint32_t SymIdx = 0, Type = 0;
29+
for (const auto &R : Relocs)
30+
OffsetMask |= ToCrel(R).r_offset;
31+
const int Shift = llvm::countr_zero(OffsetMask);
32+
encodeULEB128(Relocs.size() * 8 + ELF::CREL_HDR_ADDEND + Shift, OS);
33+
for (const auto &R : Relocs) {
34+
auto CR = ToCrel(R);
35+
auto DeltaOffset = static_cast<uint>((CR.r_offset - Offset) >> Shift);
36+
Offset = CR.r_offset;
37+
uint8_t B = (DeltaOffset << 3) + (SymIdx != CR.r_symidx) +
38+
(Type != CR.r_type ? 2 : 0) +
39+
(Addend != uint(CR.r_addend) ? 4 : 0);
40+
if (DeltaOffset < 0x10) {
41+
OS << char(B);
42+
} else {
43+
OS << char(B | 0x80);
44+
encodeULEB128(DeltaOffset >> 4, OS);
45+
}
46+
// Delta symidx/type/addend members (SLEB128).
47+
if (B & 1) {
48+
encodeSLEB128(static_cast<int32_t>(CR.r_symidx - SymIdx), OS);
49+
SymIdx = CR.r_symidx;
50+
}
51+
if (B & 2) {
52+
encodeSLEB128(static_cast<int32_t>(CR.r_type - Type), OS);
53+
Type = CR.r_type;
54+
}
55+
if (B & 4) {
56+
encodeSLEB128(std::make_signed_t<uint>(CR.r_addend - Addend), OS);
57+
Addend = CR.r_addend;
58+
}
59+
}
60+
}
61+
} // namespace llvm::ELF
62+
63+
#endif

llvm/lib/MC/ELFObjectWriter.cpp

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/MC/MCAsmInfo.h"
2424
#include "llvm/MC/MCAssembler.h"
2525
#include "llvm/MC/MCContext.h"
26+
#include "llvm/MC/MCELFExtras.h"
2627
#include "llvm/MC/MCELFObjectWriter.h"
2728
#include "llvm/MC/MCExpr.h"
2829
#include "llvm/MC/MCFixup.h"
@@ -903,44 +904,14 @@ void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
903904
WriteWord(EntrySize); // sh_entsize
904905
}
905906

906-
template <class uint>
907+
template <bool Is64>
907908
static void encodeCrel(ArrayRef<ELFRelocationEntry> Relocs, raw_ostream &OS) {
908-
uint OffsetMask = 8, Offset = 0, Addend = 0;
909-
uint32_t SymIdx = 0, Type = 0;
910-
// hdr & 4 indicates 3 flag bits in delta offset and flags members.
911-
for (const ELFRelocationEntry &Entry : Relocs)
912-
OffsetMask |= Entry.Offset;
913-
const int Shift = llvm::countr_zero(OffsetMask);
914-
encodeULEB128(Relocs.size() * 8 + ELF::CREL_HDR_ADDEND + Shift, OS);
915-
for (const ELFRelocationEntry &Entry : Relocs) {
916-
// The delta offset and flags member may be larger than uint64_t. Special
917-
// case the first byte (3 flag bits and 4 offset bits). Other ULEB128 bytes
918-
// encode the remaining delta offset bits.
919-
auto DeltaOffset = static_cast<uint>((Entry.Offset - Offset) >> Shift);
920-
Offset = Entry.Offset;
921-
uint32_t CurSymIdx = Entry.Symbol ? Entry.Symbol->getIndex() : 0;
922-
uint8_t B = (DeltaOffset << 3) + (SymIdx != CurSymIdx) +
923-
(Type != Entry.Type ? 2 : 0) + (Addend != Entry.Addend ? 4 : 0);
924-
if (DeltaOffset < 0x10) {
925-
OS << char(B);
926-
} else {
927-
OS << char(B | 0x80);
928-
encodeULEB128(DeltaOffset >> 4, OS);
929-
}
930-
// Delta symidx/type/addend members (SLEB128).
931-
if (B & 1) {
932-
encodeSLEB128(static_cast<int32_t>(CurSymIdx - SymIdx), OS);
933-
SymIdx = CurSymIdx;
934-
}
935-
if (B & 2) {
936-
encodeSLEB128(static_cast<int32_t>(Entry.Type - Type), OS);
937-
Type = Entry.Type;
938-
}
939-
if (B & 4) {
940-
encodeSLEB128(std::make_signed_t<uint>(Entry.Addend - Addend), OS);
941-
Addend = Entry.Addend;
942-
}
943-
}
909+
using uint = std::conditional_t<Is64, uint64_t, uint32_t>;
910+
ELF::encodeCrel<Is64>(OS, Relocs, [&](const ELFRelocationEntry &R) {
911+
uint32_t SymIdx = R.Symbol ? R.Symbol->getIndex() : 0;
912+
return ELF::Elf_Crel<Is64>{static_cast<uint>(R.Offset), SymIdx, R.Type,
913+
std::make_signed_t<uint>(R.Addend)};
914+
});
944915
}
945916

946917
void ELFWriter::writeRelocations(const MCAssembler &Asm,
@@ -989,9 +960,9 @@ void ELFWriter::writeRelocations(const MCAssembler &Asm,
989960
}
990961
} else if (TO && TO->Crel) {
991962
if (is64Bit())
992-
encodeCrel<uint64_t>(Relocs, W.OS);
963+
encodeCrel<true>(Relocs, W.OS);
993964
else
994-
encodeCrel<uint32_t>(Relocs, W.OS);
965+
encodeCrel<false>(Relocs, W.OS);
995966
} else {
996967
for (const ELFRelocationEntry &Entry : Relocs) {
997968
uint32_t Symidx = Entry.Symbol ? Entry.Symbol->getIndex() : 0;

0 commit comments

Comments
 (0)