31class FunctionWriterBase {
33 struct TargetCIEInfo {
35 std::span<const u8> instrs;
37 u8 return_addr_register;
39 u8 code_alignment_factor;
41 u8 data_alignment_factor;
45 const TargetCIEInfo &cie_info;
47 DataSection *section =
nullptr;
48 u8 *data_begin =
nullptr;
49 u8 *data_cur =
nullptr;
50 u8 *data_reserve_end =
nullptr;
81 std::span<Label> labels() {
82 return {
reinterpret_cast<Label *
>(
this + 1), size};
86 static_assert(std::is_trivially_destructible_v<JumpTable>);
89 util::BumpAllocator<> jump_table_alloc;
92 util::SmallVector<JumpTable *> jump_tables;
95 DataSection *eh_frame_section;
98 util::VectorWriter eh_writer;
102 SymRef cur_personality_func_addr;
103 u32 eh_cur_cie_off = 0u;
106 struct ExceptCallSiteInfo {
115 util::SmallVector<ExceptCallSiteInfo, 0> except_call_site_table;
118 util::SmallVector<u8, 0> except_encoded_call_sites;
120 util::SmallVector<u8, 0> except_action_table;
123 util::SmallVector<SymRef, 0> except_type_info_table;
125 util::SmallVector<u8, 0> except_spec_table;
128 FunctionWriterBase(
const TargetCIEInfo &cie_info) : cie_info(cie_info) {}
136 assert(section !=
nullptr);
142 assert(data_cur == data_reserve_end &&
143 "must flush section writer before switching sections");
144 section = &new_section;
145 data_begin = section->data.data();
146 data_cur = data_begin + section->data.size();
147 data_reserve_end = data_cur;
157 size_t offset()
const {
return data_cur - data_begin; }
170 void more_space(
size_t size);
174 void reloc(SymRef sym, u32 type, u64 off, i64 addend = 0) {
175 assembler->reloc_sec(
get_sec_ref(), sym, type, off, addend);
184 if (data_cur != data_reserve_end) {
185 section->data.resize(
offset());
186 data_reserve_end = data_cur;
188 section->locked =
false;
203 bool label_is_pending(Label label)
const {
207 u32 label_offset(Label label)
const {
208 assert(!label_is_pending(label));
214 assert(
label_skew == 0 &&
"label_place called after prologue truncation");
215 assert(label_is_pending(label));
220 void label_ref(Label label, u32 off, LabelFixupKind kind) {
224 label_fixups.emplace_back(LabelFixup{label, off, kind});
233 SecRef get_jump_table_section() {
236 return assembler->get_default_section(SectionKind::ReadOnly);
243 static constexpr u32 write_eh_inst(u8 *dst, u8 opcode, u64 arg) {
244 if (opcode & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) {
245 assert((arg & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) == 0);
250 return 1 + util::uleb_write(dst, arg);
253 static constexpr u32 write_eh_inst(u8 *dst, u8 opcode, u64 arg1, u64 arg2) {
255 dst += write_eh_inst(dst, opcode, arg1);
256 dst += util::uleb_write(dst, arg2);
260 void eh_align_frame();
261 void eh_write_inst(u8 opcode) { this->eh_writer.write<u8>(opcode); }
262 void eh_write_inst(u8 opcode, u64 arg);
263 void eh_write_inst(u8 opcode, u64 first_arg, u64 second_arg);
270 void eh_init_cie(SymRef personality_func_addr = SymRef());
273 void eh_begin_fde(SymRef personality_func_addr = SymRef());
281 void except_encode_func();
298 void except_add_empty_spec_action(
bool first_action);
300 u32 except_type_idx_for_sym(SymRef sym);
307class FunctionWriter :
public FunctionWriterBase {
309 FunctionWriter(
const TargetCIEInfo &cie_info)
310 : FunctionWriterBase(cie_info) {}
312 Derived *derived() {
return static_cast<Derived *
>(
this); }
315 void begin_func(u32 align, u32 expected_size) {
318 derived()->align(align);
319 FunctionWriterBase::begin_func();
322 void finish_func() { derived()->handle_fixups(); }
329 assert(data_reserve_end >= data_cur);
330 if (
size_t(data_reserve_end - data_cur) < size) [[unlikely]] {
331 derived()->more_space(size);
335 template <std::
integral T>
336 void write_unchecked(T t) {
337 assert(
size_t(data_reserve_end - data_cur) >=
sizeof(T));
338 std::memcpy(data_cur, &t,
sizeof(T));
339 data_cur +=
sizeof(T);
342 template <std::
integral T>
345 write_unchecked<T>(t);
348 void align(
size_t align) {
349 assert(align > 0 && (align & (align - 1)) == 0);
352 std::memset(
cur_ptr(), 0, align);
353 data_cur = data_begin + util::align_up(
offset(), align);
354 section->align = std::max(section->align, u32(align));