5#include "tpde/FunctionWriter.hpp"
14 util::SmallVector<u32, 16> veneers;
15 u32 unresolved_cond_brs, unresolved_test_brs;
18 void begin_func(u32 expected_size)
noexcept {
21 unresolved_cond_brs = unresolved_test_brs = 0;
22 FunctionWriter::begin_func(expected_size);
25 void more_space(u32 size)
noexcept;
27 bool try_write_inst(u32 inst)
noexcept {
35 void write_inst(u32 inst)
noexcept {
40 void write_inst_unchecked(u32 inst)
noexcept {
42 write_unchecked(inst);
45 void label_ref(Label label, u32 off, LabelFixupKind kind)
noexcept {
47 if (kind == LabelFixupKind::AARCH64_COND_BR) {
48 unresolved_cond_brs++;
49 }
else if (kind == LabelFixupKind::AARCH64_TEST_BR) {
50 unresolved_test_brs++;
55 void handle_fixups()
noexcept;
58inline void FunctionWriterA64::more_space(u32 size)
noexcept {
59 if (allocated_size() >= (128 * 1024 * 1024)) {
61 TPDE_FATAL(
"AArch64 doesn't support sections larger than 128 MiB");
66 u32 unresolved_count = unresolved_test_brs + unresolved_cond_brs;
67 u32 veneer_size =
sizeof(u32) * unresolved_count;
68 FunctionWriter::more_space(size + veneer_size + 4);
69 if (veneer_size == 0) {
74 u32 max_dist = unresolved_test_brs ? 4 << (14 - 1) : 4 << (19 - 1);
75 max_dist -= veneer_size;
78 u32 first_condbr = veneers.empty() ? 0 : veneers.back();
80 if (first_condbr + max_dist > allocated_size()) {
84 u32 cur_off = offset();
85 veneers.push_back(cur_off + 4);
86 unresolved_test_brs = unresolved_cond_brs = 0;
88 *
reinterpret_cast<u32 *
>(data_begin + cur_off) = de64_B(veneer_size / 4 + 1);
89 std::memset(data_begin + cur_off + 4, 0, veneer_size);
90 cur_ptr() += veneer_size + 4;
93inline void FunctionWriterA64::handle_fixups() noexcept {
95 u32 label_off = label_offset(fixup.label);
96 u32 *dst_ptr =
reinterpret_cast<u32 *
>(
begin_ptr() + fixup.off);
98 auto fix_condbr = [&](
unsigned nbits) {
99 i64 diff = i64(label_off) - i64(fixup.off);
100 assert(diff >= 0 && diff < 128 * 1024 * 1024);
102 if (diff >= (4 << (nbits - 1))) {
104 std::lower_bound(veneers.begin(), veneers.end(), fixup.off);
105 assert(veneer != veneers.end());
108 auto *br =
reinterpret_cast<u32 *
>(
begin_ptr() + *veneer);
109 assert(*br == 0 &&
"overwriting instructions with veneer branch");
110 *br = de64_B((label_off - *veneer) / 4);
111 diff = *veneer - fixup.off;
114 u32 off_mask = ((1 << nbits) - 1) << 5;
115 *dst_ptr = (*dst_ptr & ~off_mask) | ((diff / 4) << 5);
118 switch (fixup.kind) {
119 case LabelFixupKind::AARCH64_BR: {
121 i64 diff = i64(label_off) - i64(fixup.off);
122 assert(diff >= 0 && diff < 128 * 1024 * 1024);
123 *dst_ptr = de64_B(diff / 4);
126 case LabelFixupKind::AARCH64_COND_BR:
127 if (veneers.empty() || veneers.back() < fixup.off) {
128 assert(unresolved_cond_brs > 0);
129 unresolved_cond_brs -= 1;
133 case LabelFixupKind::AARCH64_TEST_BR:
134 if (veneers.empty() || veneers.back() < fixup.off) {
135 assert(unresolved_test_brs > 0);
136 unresolved_test_brs -= 1;
140 case LabelFixupKind::AARCH64_JUMP_TABLE: {
141 auto table_off = *dst_ptr;
142 *dst_ptr = (i32)label_off - (i32)table_off;
145 default: TPDE_UNREACHABLE(
"unexpected label fixup kind");
void label_ref(Label label, u32 off, LabelFixupKind kind) noexcept
Reference label at given offset inside the code section.
util::SmallVector< LabelFixup > label_fixups
u8 * begin_ptr() noexcept
Helper class to write function text for AArch64.