TPDE
Loading...
Searching...
No Matches
FunctionWriterA64.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3#pragma once
4
5#include "tpde/FunctionWriter.hpp"
6
7namespace tpde::a64 {
8
9/// Helper class to write function text for AArch64.
10class FunctionWriterA64 : public FunctionWriter<FunctionWriterA64> {
11 friend class FunctionWriter<FunctionWriterA64>;
12
13 util::SmallVector<u32, 16> veneers;
14 u32 unresolved_cond_brs, unresolved_test_brs;
15
16 static const TargetCIEInfo CIEInfo;
17
18 // ADRP; ADD; LDR; ADR; ADD; BR.
19 static constexpr u32 JumpTableCodeSize = 24;
20
21public:
22 FunctionWriterA64() : FunctionWriter(CIEInfo) {}
23
24 void begin_func(u32 align, u32 expected_size) {
25 veneers.clear();
26 // Must clear unresolved count here, begin_func will call more_space.
27 unresolved_cond_brs = unresolved_test_brs = 0;
28 FunctionWriter::begin_func(align, expected_size);
29 }
30
31private:
32 void more_space(u32 size);
33
34public:
35 JumpTable &create_jump_table(u32 size, Reg idx, Reg tmp, bool is32) {
36 JumpTable &jt = alloc_jump_table(size, idx, tmp);
37 jt.misc = is32;
38 ensure_space(JumpTableCodeSize);
39 cur_ptr() += JumpTableCodeSize;
40 return jt;
41 }
42
43 void ensure_space(size_t size) {
44 // Advancing by more than 32kiB is problematic: when inserting a tbz,
45 // more_space might not be called within 32kiB, preventing the insertion of
46 // required veneer space. However, all veneers must be reachable from every
47 // instruction, therefore, reduce by factor 2.
48 assert(size <= (4 << (14 - 1 - 1)) && "cannot skip beyond tbz max dist");
50 }
51
52 bool try_write_inst(u32 inst) {
53 if (inst == 0) {
54 return false;
55 }
56 write(inst);
57 return true;
58 }
59
60 void write_inst(u32 inst) {
61 assert(inst != 0);
62 write(inst);
63 }
64
65 void write_inst_unchecked(u32 inst) {
66 assert(inst != 0);
67 write_unchecked(inst);
68 }
69
70 void label_ref(Label label, u32 off, LabelFixupKind kind) {
71 FunctionWriter::label_ref(label, off, kind);
72 if (kind == LabelFixupKind::AARCH64_COND_BR) {
73 unresolved_cond_brs++;
74 } else if (kind == LabelFixupKind::AARCH64_TEST_BR) {
75 unresolved_test_brs++;
76 }
77 }
78
79 void eh_advance(u64 size) { eh_advance_raw(size / 4); }
80
81private:
82 void handle_fixups();
83};
84
85} // namespace tpde::a64
u8 *& cur_ptr()
Modifiable pointer to current writing position of the section.
void label_ref(Label label, u32 off, LabelFixupKind kind)
Reference label at given offset inside the code section.
JumpTable & alloc_jump_table(u32 size, Reg idx, Reg tmp)
Allocate a jump table for the current location.
void eh_advance_raw(u64 size_units)
Write CFA_advance_loc; size must be scaled by code alignment factor.
void ensure_space(size_t size)
Ensure that at least size bytes are available.