5#include "tpde/Assembler.hpp"
6#include "tpde/DWARF.hpp"
7#include "tpde/base.hpp"
8#include "tpde/util/SmallVector.hpp"
9#include "tpde/util/VectorWriter.hpp"
15enum class Label : u32 {
18enum class LabelFixupKind : u8 {
21 X64_JMP_OR_MEM_DISP = ArchKindBegin,
24 AARCH64_BR = ArchKindBegin,
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;
46 const TargetCIEInfo &cie_info;
49 DataSection *section =
nullptr;
50 u8 *data_begin =
nullptr;
51 u8 *data_cur =
nullptr;
52 u8 *data_reserve_end =
nullptr;
75 DataSection *eh_frame_section;
78 util::VectorWriter eh_writer;
82 SymRef cur_personality_func_addr;
83 u32 eh_cur_cie_off = 0u;
86 struct ExceptCallSiteInfo {
95 util::SmallVector<ExceptCallSiteInfo, 0> except_call_site_table;
98 util::SmallVector<u8, 0> except_encoded_call_sites;
100 util::SmallVector<u8, 0> except_action_table;
103 util::SmallVector<SymRef, 0> except_type_info_table;
105 util::SmallVector<u8, 0> except_spec_table;
109 : cie_info(cie_info) {}
111 ~FunctionWriterBase() {
112 assert(data_cur == data_reserve_end &&
113 "must flush section writer before destructing");
122 assert(section !=
nullptr);
128 assert(data_cur == data_reserve_end &&
129 "must flush section writer before switching sections");
130 section = &new_section;
131 data_begin = section->data.data();
132 data_cur = data_begin + section->data.size();
133 data_reserve_end = data_cur;
136 void begin_module(
Assembler &assembler)
noexcept;
138 void end_module() noexcept;
140 void begin_func() noexcept;
143 size_t offset() const noexcept {
return data_cur - data_begin; }
147 return data_reserve_end - data_begin;
157 void more_space(
size_t size)
noexcept;
164 void flush() noexcept {
165 if (data_cur != data_reserve_end) {
166 section->data.resize(
offset());
167 data_reserve_end = data_cur;
169 section->locked =
false;
184 bool label_is_pending(Label label)
const noexcept {
188 u32 label_offset(Label label)
const noexcept {
189 assert(!label_is_pending(label));
195 assert(
label_skew == 0 &&
"label_place called after prologue truncation");
196 assert(label_is_pending(label));
201 void label_ref(Label label, u32 off, LabelFixupKind kind)
noexcept {
205 label_fixups.emplace_back(LabelFixup{label, off, kind});
213 static constexpr u32 write_eh_inst(u8 *dst, u8 opcode, u64 arg)
noexcept {
214 if (opcode & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) {
215 assert((arg & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) == 0);
220 return 1 + util::uleb_write(dst, arg);
224 write_eh_inst(u8 *dst, u8 opcode, u64 arg1, u64 arg2)
noexcept {
226 dst += write_eh_inst(dst, opcode, arg1);
227 dst += util::uleb_write(dst, arg2);
231 void eh_align_frame() noexcept;
232 void eh_write_inst(u8 opcode) noexcept { this->eh_writer.write<u8>(opcode); }
233 void eh_write_inst(u8 opcode, u64 arg)
noexcept;
234 void eh_write_inst(u8 opcode, u64 first_arg, u64 second_arg)
noexcept;
241 void eh_init_cie(SymRef personality_func_addr = SymRef()) noexcept;
244 void eh_begin_fde(SymRef personality_func_addr = SymRef()) noexcept;
245 void eh_end_fde() noexcept;
252 void except_encode_func() noexcept;
259 bool is_cleanup) noexcept;
269 void except_add_empty_spec_action(
bool first_action) noexcept;
271 u32 except_type_idx_for_sym(SymRef sym) noexcept;
277template <typename Derived>
278class FunctionWriter : public FunctionWriterBase {
280 FunctionWriter(
const TargetCIEInfo &cie_info) noexcept
281 : FunctionWriterBase(cie_info) {}
283 Derived *derived()
noexcept {
return static_cast<Derived *
>(
this); }
286 void begin_func(u32 align, u32 expected_size)
noexcept {
289 derived()->align(align);
290 FunctionWriterBase::begin_func();
293 void finish_func()
noexcept { derived()->handle_fixups(); }
300 assert(data_reserve_end >= data_cur);
301 if (
size_t(data_reserve_end - data_cur) < size) [[unlikely]] {
302 derived()->more_space(size);
306 template <std::
integral T>
307 void write_unchecked(T t)
noexcept {
308 assert(
size_t(data_reserve_end - data_cur) >=
sizeof(T));
309 std::memcpy(data_cur, &t,
sizeof(T));
310 data_cur +=
sizeof(T);
313 template <std::
integral T>
314 void write(T t)
noexcept {
315 ensure_space(
sizeof(T));
316 write_unchecked<T>(t);
319 void align(
size_t align)
noexcept {
320 assert(align > 0 && (align & (align - 1)) == 0);
323 std::memset(
cur_ptr(), 0, align);
324 data_cur = data_begin + util::align_up(
offset(), align);
325 section->align = std::max(section->align, u32(align));
Architecture-independent base for helper class to write function text.
DataSection & get_section() const noexcept
Get the current section.
void except_add_cleanup_action() noexcept
Add a cleanup action to the action table MUST be the last one.
Label label_create() noexcept
Create a new unplaced label.
util::SmallVector< LabelFixup > label_fixups
Fixups for labels placed after their first use, processed at function end.
util::SmallVector< u32 > label_offsets
Label offsets into section, ~0u indicates unplaced label.
void switch_section(DataSection &new_section) noexcept
Switch section writer to new section; must be flushed.
void except_add_call_site(u32 text_off, u32 len, Label landing_pad, bool is_cleanup) noexcept
add an entry to the call-site table must be called in strictly increasing order wrt text_off
size_t allocated_size() const noexcept
Get the current allocated size of the section.
u8 *& cur_ptr() noexcept
Modifiable pointer to current writing position of the section.
u8 * begin_ptr() noexcept
Pointer to beginning of section data.
void eh_advance(u64 size) noexcept
Write CFA_advance_loc with code alignment factor 1.
u32 func_begin
Begin offset of the current function.
void eh_advance_raw(u64 size_units) noexcept
Write CFA_advance_loc; size must be scaled by code alignment factor.
void except_add_action(bool first_action, SymRef type_sym) noexcept
add an action to the action table An invalid SymRef signals a catch(...)
void label_ref(Label label, u32 off, LabelFixupKind kind) noexcept
Reference label at given offset inside the code section.
size_t offset() const noexcept
Get the current offset into the section.
u32 reloc_begin
Begin of relocations for current function.
u32 label_skew
Offset to subtract from all label offsets.
void label_place(Label label, u32 off) noexcept
Place unplaced label at the specified offset inside the section.
void remove_prologue_bytes(u32 start, u32 size) noexcept
Remove bytes and adjust labels/relocations accordingly.
u32 growth_size
Growth size for more_space; adjusted exponentially after every grow.
SecRef get_sec_ref() const noexcept
Get the SecRef of the current section.
void ensure_space(size_t size) noexcept
Ensure that at least size bytes are available.