15#include "tpde/util/BumpAllocator.hpp"
16#include "tpde/util/VectorWriter.hpp"
17#include "util/SmallVector.hpp"
18#include "util/misc.hpp"
24constexpr u8 DW_CFA_nop = 0;
25constexpr u8 DW_EH_PE_uleb128 = 0x01;
26constexpr u8 DW_EH_PE_pcrel = 0x10;
27constexpr u8 DW_EH_PE_indirect = 0x80;
28constexpr u8 DW_EH_PE_sdata4 = 0x0b;
29constexpr u8 DW_EH_PE_omit = 0xff;
31constexpr u8 DW_CFA_offset_extended = 0x05;
32constexpr u8 DW_CFA_def_cfa = 0x0c;
33constexpr u8 DW_CFA_def_cfa_register = 0x0d;
34constexpr u8 DW_CFA_def_cfa_offset = 0x0e;
35constexpr u8 DW_CFA_offset = 0x80;
36constexpr u8 DW_CFA_advance_loc = 0x40;
37constexpr u8 DW_CFA_advance_loc4 = 0x04;
39constexpr u8 DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
41constexpr u32 EH_FDE_FUNC_START_OFF = 0x8;
44constexpr u8 DW_reg_rax = 0;
45constexpr u8 DW_reg_rdx = 1;
46constexpr u8 DW_reg_rcx = 2;
47constexpr u8 DW_reg_rbx = 3;
48constexpr u8 DW_reg_rsi = 4;
49constexpr u8 DW_reg_rdi = 5;
50constexpr u8 DW_reg_rbp = 6;
51constexpr u8 DW_reg_rsp = 7;
52constexpr u8 DW_reg_r8 = 8;
53constexpr u8 DW_reg_r9 = 9;
54constexpr u8 DW_reg_r10 = 10;
55constexpr u8 DW_reg_r11 = 11;
56constexpr u8 DW_reg_r12 = 12;
57constexpr u8 DW_reg_r13 = 13;
58constexpr u8 DW_reg_r14 = 14;
59constexpr u8 DW_reg_r15 = 15;
60constexpr u8 DW_reg_ra = 16;
64constexpr u8 DW_reg_x0 = 0;
65constexpr u8 DW_reg_x1 = 1;
66constexpr u8 DW_reg_x2 = 2;
67constexpr u8 DW_reg_x3 = 3;
68constexpr u8 DW_reg_x4 = 4;
69constexpr u8 DW_reg_x5 = 5;
70constexpr u8 DW_reg_x6 = 6;
71constexpr u8 DW_reg_x7 = 7;
72constexpr u8 DW_reg_x8 = 8;
73constexpr u8 DW_reg_x9 = 9;
74constexpr u8 DW_reg_x10 = 10;
75constexpr u8 DW_reg_x11 = 11;
76constexpr u8 DW_reg_x12 = 12;
77constexpr u8 DW_reg_x13 = 13;
78constexpr u8 DW_reg_x14 = 14;
79constexpr u8 DW_reg_x15 = 15;
80constexpr u8 DW_reg_x16 = 16;
81constexpr u8 DW_reg_x17 = 17;
82constexpr u8 DW_reg_x18 = 18;
83constexpr u8 DW_reg_x19 = 19;
84constexpr u8 DW_reg_x20 = 20;
85constexpr u8 DW_reg_x21 = 21;
86constexpr u8 DW_reg_x22 = 22;
87constexpr u8 DW_reg_x23 = 23;
88constexpr u8 DW_reg_x24 = 24;
89constexpr u8 DW_reg_x25 = 25;
90constexpr u8 DW_reg_x26 = 26;
91constexpr u8 DW_reg_x27 = 27;
92constexpr u8 DW_reg_x28 = 28;
93constexpr u8 DW_reg_x29 = 29;
94constexpr u8 DW_reg_x30 = 30;
96constexpr u8 DW_reg_fp = 29;
97constexpr u8 DW_reg_lr = 30;
99constexpr u8 DW_reg_v0 = 64;
100constexpr u8 DW_reg_v1 = 65;
101constexpr u8 DW_reg_v2 = 66;
102constexpr u8 DW_reg_v3 = 67;
103constexpr u8 DW_reg_v4 = 68;
104constexpr u8 DW_reg_v5 = 69;
105constexpr u8 DW_reg_v6 = 70;
106constexpr u8 DW_reg_v7 = 71;
107constexpr u8 DW_reg_v8 = 72;
108constexpr u8 DW_reg_v9 = 73;
109constexpr u8 DW_reg_v10 = 74;
110constexpr u8 DW_reg_v11 = 75;
111constexpr u8 DW_reg_v12 = 76;
112constexpr u8 DW_reg_v13 = 77;
113constexpr u8 DW_reg_v14 = 78;
114constexpr u8 DW_reg_v15 = 79;
115constexpr u8 DW_reg_v16 = 80;
116constexpr u8 DW_reg_v17 = 81;
117constexpr u8 DW_reg_v18 = 82;
118constexpr u8 DW_reg_v19 = 83;
119constexpr u8 DW_reg_v20 = 84;
120constexpr u8 DW_reg_v21 = 85;
121constexpr u8 DW_reg_v22 = 86;
122constexpr u8 DW_reg_v23 = 87;
123constexpr u8 DW_reg_v24 = 88;
124constexpr u8 DW_reg_v25 = 89;
125constexpr u8 DW_reg_v26 = 90;
126constexpr u8 DW_reg_v27 = 91;
127constexpr u8 DW_reg_v28 = 92;
128constexpr u8 DW_reg_v29 = 93;
129constexpr u8 DW_reg_v30 = 94;
131constexpr u8 DW_reg_sp = 31;
132constexpr u8 DW_reg_pc = 32;
137struct AssemblerElfBase {
138 template <
class Derived>
139 friend struct AssemblerElf;
140 friend class ElfMapper;
149 u8 cie_return_addr_register;
151 std::span<const u8> cie_instrs;
153 u8 cie_code_alignment_factor;
155 u8 cie_data_alignment_factor;
163 enum class SymBinding : u8 {
172 enum class SymVisibility : u8 {
173 DEFAULT = STV_DEFAULT,
174 INTERNAL = STV_INTERNAL,
176 PROTECTED = STV_PROTECTED,
185 constexpr SymRef() : val(0) {}
187 explicit constexpr SymRef(u32
id) : val(id) {}
189 u32 id()
const {
return val; }
190 bool valid()
const {
return val != 0; }
192 bool operator==(
const SymRef &other)
const {
return other.val == val; }
195 enum class SecRef : u32 {
197 static constexpr SecRef INVALID_SEC_REF =
static_cast<SecRef
>(0u);
200 enum class Label : u32 {
208 using StorageTy = util::SmallVector<u8, 256>;
222 void *target_info =
nullptr;
230 DataSection(SecRef ref,
unsigned type,
unsigned flags,
unsigned name_off)
231 : hdr{.sh_name = name_off, .sh_type = type, .sh_flags = flags},
234 SecRef get_ref() const noexcept {
return sec_ref; }
236 size_t size()
const {
237 return (hdr.sh_type == SHT_NOBITS) ? hdr.sh_size : data.size();
240 template <
typename T>
241 void write(
const T &t)
noexcept {
243 assert(hdr.sh_type != SHT_NOBITS);
244 size_t off = data.size();
245 data.resize_uninitialized(data.size() +
sizeof(T));
246 memcpy(data.data() + off, &t,
sizeof(T));
250 template <
typename Derived>
251 class SectionWriterBase {
253 DataSection *section =
nullptr;
254 u8 *data_begin =
nullptr;
255 u8 *data_cur =
nullptr;
256 u8 *data_reserve_end =
nullptr;
260 u32 growth_size = 0x10000;
262 SectionWriterBase() noexcept = default;
264 ~SectionWriterBase() {
265 assert(data_cur == data_reserve_end &&
266 "must flush section writer before destructing");
270 Derived *derived() noexcept {
return static_cast<Derived *
>(
this); }
274 SecRef get_sec_ref() const noexcept {
return get_section().get_ref(); }
277 DataSection &get_section() const noexcept {
278 assert(section !=
nullptr);
283 void switch_section(DataSection &new_section)
noexcept {
284 assert(data_cur == data_reserve_end &&
285 "must flush section writer before switching sections");
286 section = &new_section;
287 data_begin = section->data.data();
288 data_cur = data_begin + section->data.size();
289 data_reserve_end = data_cur;
293 size_t offset() const noexcept {
return data_cur - data_begin; }
296 size_t allocated_size() const noexcept {
297 return data_reserve_end - data_begin;
301 u8 *begin_ptr() noexcept {
return data_begin; }
305 u8 *&cur_ptr() noexcept {
return data_cur; }
307 void ensure_space(
size_t size)
noexcept {
308 assert(data_reserve_end >= data_cur);
309 if (
size_t(data_reserve_end - data_cur) < size) [[unlikely]] {
310 derived()->more_space(size);
314 void more_space(
size_t size)
noexcept;
316 template <std::
integral T>
317 void write_unchecked(T t)
noexcept {
318 assert(
size_t(data_reserve_end - data_cur) >=
sizeof(T));
319 std::memcpy(data_cur, &t,
sizeof(T));
320 data_cur +=
sizeof(T);
323 template <std::
integral T>
324 void write(T t)
noexcept {
325 ensure_space(
sizeof(T));
326 write_unchecked<T>(t);
329 void flush() noexcept {
330 if (data_cur != data_reserve_end) {
331 section->data.resize(offset());
332 data_reserve_end = data_cur;
334 section->locked =
false;
339 void align(
size_t align)
noexcept {
340 assert(align > 0 && (align & (align - 1)) == 0);
343 std::memset(cur_ptr(), 0, align);
344 data_cur = data_begin + util::align_up(offset(), align);
345 section->hdr.sh_addralign = std::max(section->hdr.sh_addralign, align);
350 const TargetInfo &target_info;
352 util::BumpAllocator<> section_allocator;
353 util::SmallVector<util::BumpAllocUniquePtr<DataSection>, 16> sections;
355 std::vector<Elf64_Sym> global_symbols, local_symbols;
357 util::SmallVector<u32, 0> global_shndx, local_shndx;
360 struct TempSymbolInfo {
370 struct TempSymbolFixup {
378 std::vector<TempSymbolInfo> temp_symbols;
379 std::vector<TempSymbolFixup> temp_symbol_fixups;
380 u32 next_free_tsfixup = ~0u;
382 std::vector<char> strtab;
384 std::string shstrtab_extra;
387 SecRef secref_text = INVALID_SEC_REF;
388 SecRef secref_rodata = INVALID_SEC_REF;
389 SecRef secref_relro = INVALID_SEC_REF;
390 SecRef secref_data = INVALID_SEC_REF;
391 SecRef secref_bss = INVALID_SEC_REF;
392 SecRef secref_tdata = INVALID_SEC_REF;
393 SecRef secref_tbss = INVALID_SEC_REF;
396 SecRef secref_eh_frame = INVALID_SEC_REF;
397 SecRef secref_except_table = INVALID_SEC_REF;
400 util::VectorWriter<DataSection::StorageTy> eh_writer;
403 struct ExceptCallSiteInfo {
413 std::vector<ExceptCallSiteInfo> except_call_site_table;
416 std::vector<u8> except_encoded_call_sites;
418 std::vector<u8> except_action_table;
421 std::vector<SymRef> except_type_info_table;
423 std::vector<u8> except_spec_table;
425 SymRef cur_personality_func_addr;
426 u32 eh_cur_cie_off = 0u;
427 u32 eh_first_fde_off = 0;
433 explicit AssemblerElfBase(
const TargetInfo &target_info)
434 : target_info(target_info) {
435 strtab.push_back(
'\0');
437 local_symbols.resize(1);
442 void reset() noexcept;
446 DataSection &get_section(SecRef ref) noexcept {
447 assert(ref != INVALID_SEC_REF);
448 return *sections[
static_cast<u32
>(ref)];
451 const DataSection &get_section(SecRef ref)
const noexcept {
452 assert(ref != INVALID_SEC_REF);
453 return *sections[
static_cast<u32
>(ref)];
457 void init_sections() noexcept;
459 bool has_reloc_section(SecRef ref) const noexcept {
460 assert(ref != INVALID_SEC_REF);
461 if (
static_cast<u32
>(ref) + 1 < sections.size()) {
462 return sections[
static_cast<u32
>(ref) + 1]->hdr.sh_type == SHT_RELA;
467 DataSection &get_reloc_section(SecRef ref)
noexcept {
468 assert(has_reloc_section(ref));
469 DataSection &reloc_sec = *sections[
static_cast<u32
>(ref) + 1];
473 std::span<Elf64_Rela> get_relocs(SecRef ref) {
474 if (!has_reloc_section(ref)) {
477 DataSection &rela_sec = get_reloc_section(ref);
478 size_t count = rela_sec.size() /
sizeof(Elf64_Rela);
479 return {
reinterpret_cast<Elf64_Rela *
>(rela_sec.data.data()), count};
484 create_section(
unsigned type,
unsigned flags,
unsigned name)
noexcept;
487 [[nodiscard]] SecRef create_rela_section(SecRef ref,
489 unsigned rela_name)
noexcept;
491 [[nodiscard]] SymRef create_section_symbol(SecRef ref,
492 std::string_view name)
noexcept;
494 DataSection &get_or_create_section(SecRef &ref,
499 bool with_rela =
true) noexcept;
502 SecRef get_text_section() noexcept {
return secref_text; }
503 SecRef get_data_section(
bool rodata,
bool relro =
false) noexcept;
504 SecRef get_bss_section() noexcept;
505 SecRef get_tdata_section() noexcept;
506 SecRef get_tbss_section() noexcept;
507 SecRef create_structor_section(
bool init,
508 SecRef group = INVALID_SEC_REF) noexcept;
513 [[nodiscard]] SecRef create_section(std::string_view name,
517 SecRef group = INVALID_SEC_REF) noexcept;
520 [[nodiscard]] SecRef create_group_section(SymRef signature_sym,
521 bool is_comdat) noexcept;
523 const
char *sec_name(SecRef ref) const noexcept;
526 bool sec_is_xindex(SecRef ref) const noexcept {
527 return static_cast<u32
>(ref) >= SHN_LORESERVE;
533 void sym_copy(SymRef dst, SymRef src)
noexcept;
537 sym_add(std::string_view name, SymBinding binding, u32 type)
noexcept;
540 [[nodiscard]] SymRef sym_add_undef(std::string_view name,
541 SymBinding binding)
noexcept {
542 return sym_add(name, binding, STT_NOTYPE);
545 [[nodiscard]] SymRef sym_predef_func(std::string_view name,
546 SymBinding binding)
noexcept {
547 return sym_add(name, binding, STT_FUNC);
550 [[nodiscard]] SymRef sym_predef_data(std::string_view name,
551 SymBinding binding)
noexcept {
552 return sym_add(name, binding, STT_OBJECT);
555 [[nodiscard]] SymRef sym_predef_tls(std::string_view name,
556 SymBinding binding)
noexcept {
557 return sym_add(name, binding, STT_TLS);
560 void sym_def_predef_data(SecRef sec,
562 std::span<const u8> data,
566 [[nodiscard]] SymRef sym_def_data(SecRef sec,
567 std::string_view name,
568 std::span<const u8> data,
571 u32 *off =
nullptr) {
572 SymRef sym = sym_predef_data(name, binding);
573 sym_def_predef_data(sec, sym, data, align, off);
577 void sym_def_predef_zero(SecRef sec_ref,
581 u32 *off =
nullptr) noexcept;
585 void sym_def_xindex(SymRef sym_ref, SecRef sec_ref) noexcept;
588 void sym_def(SymRef sym_ref, SecRef sec_ref, u64 pos, u64 size) noexcept {
589 Elf64_Sym *sym = sym_ptr(sym_ref);
590 assert(sym->st_shndx == SHN_UNDEF &&
"cannot redefined symbol");
593 if (!sec_is_xindex(sec_ref)) [[likely]] {
594 sym->st_shndx =
static_cast<Elf64_Section
>(sec_ref);
596 sym->st_shndx = SHN_XINDEX;
597 sym_def_xindex(sym_ref, sec_ref);
602 void sym_set_visibility(SymRef sym, SymVisibility visibility)
noexcept {
603 sym_ptr(sym)->st_other =
static_cast<u8
>(visibility);
607 void sym_set_value(SymRef sym, u64 value)
noexcept {
608 sym_ptr(sym)->st_value = value;
611 const char *sym_name(SymRef sym)
const noexcept {
612 return strtab.data() + sym_ptr(sym)->st_name;
615 SecRef sym_section(SymRef sym)
const noexcept {
616 Elf64_Section shndx = sym_ptr(sym)->st_shndx;
617 if (shndx < SHN_LORESERVE && shndx != SHN_UNDEF) [[likely]] {
618 return SecRef(shndx);
620 assert(shndx == SHN_XINDEX);
621 const auto &shndx_tab = sym_is_local(sym) ? local_shndx : global_shndx;
622 return SecRef(shndx_tab[sym_idx(sym)]);
625 Label label_create() noexcept {
626 const Label label =
static_cast<Label
>(temp_symbols.size());
627 temp_symbols.push_back(TempSymbolInfo{INVALID_SEC_REF, {.fixup_idx = ~0u}});
632 u32 label_is_pending(Label label)
const noexcept {
633 const auto &info = temp_symbols[
static_cast<u32
>(label)];
634 return info.section == INVALID_SEC_REF;
638 u32 label_offset(Label label)
const noexcept {
639 assert(!label_is_pending(label));
640 const auto &info = temp_symbols[
static_cast<u32
>(label)];
645 [[nodiscard]]
static bool sym_is_local(
const SymRef sym)
noexcept {
646 return (sym.id() & 0x8000'0000) == 0;
649 [[nodiscard]]
static u32 sym_idx(
const SymRef sym)
noexcept {
650 return sym.id() & ~0x8000'0000;
653 [[nodiscard]] Elf64_Sym *sym_ptr(
const SymRef sym)
noexcept {
654 if (sym_is_local(sym)) {
655 return &local_symbols[sym_idx(sym)];
657 return &global_symbols[sym_idx(sym)];
661 [[nodiscard]]
const Elf64_Sym *sym_ptr(
const SymRef sym)
const noexcept {
662 if (sym_is_local(sym)) {
663 return &local_symbols[sym_idx(sym)];
665 return &global_symbols[sym_idx(sym)];
673 SecRef sec, SymRef sym, u32 type, u64 offset, i64 addend)
noexcept;
675 void reloc_pc32(SecRef sec, SymRef sym, u64 offset, i64 addend)
noexcept {
676 reloc_sec(sec, sym, target_info.reloc_pc32, offset, addend);
679 void reloc_abs(SecRef sec, SymRef sym, u64 offset, i64 addend)
noexcept {
680 reloc_sec(sec, sym, target_info.reloc_abs64, offset, addend);
683 void reloc_sec(SecRef sec, Label label, u8 kind, u32 offset)
noexcept;
687 static constexpr u32 write_eh_inst(u8 *dst, u8 opcode, u64 arg)
noexcept {
688 if (opcode & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) {
689 assert((arg & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) == 0);
694 return 1 + util::uleb_write(dst, arg);
698 write_eh_inst(u8 *dst, u8 opcode, u64 arg1, u64 arg2)
noexcept {
700 dst += write_eh_inst(dst, opcode, arg1);
701 dst += util::uleb_write(dst, arg2);
705 void eh_align_frame() noexcept;
706 void eh_write_inst(u8 opcode, u64 arg) noexcept;
707 void eh_write_inst(u8 opcode, u64 first_arg, u64 second_arg) noexcept;
708 void eh_write_uleb(u64 value) noexcept;
711 void eh_init_cie(SymRef personality_func_addr = SymRef()) noexcept;
714 u32 eh_begin_fde(SymRef personality_func_addr = SymRef()) noexcept;
715 void eh_end_fde(u32 fde_start, SymRef func) noexcept;
717 void except_begin_func() noexcept;
719 void except_encode_func(SymRef func_sym) noexcept;
723 void except_add_call_site(u32 text_off,
726 bool is_cleanup) noexcept;
730 void except_add_cleanup_action() noexcept;
734 void except_add_action(
bool first_action, SymRef type_sym) noexcept;
736 void except_add_empty_spec_action(
bool first_action) noexcept;
738 u32 except_type_idx_for_sym(SymRef sym) noexcept;
740 void finalize() noexcept;
744 std::vector<u8> build_object_file() noexcept;
747template <typename Derived>
748void AssemblerElfBase::SectionWriterBase<Derived>::more_space(
749 size_t size) noexcept {
750 size_t cur_size = section->data.size();
752 if (cur_size + size <= section->data.capacity()) {
753 new_size = section->data.capacity();
755 new_size = cur_size + (size <= growth_size ? growth_size : size);
758 growth_size = growth_size + (growth_size >> 1);
760 growth_size = growth_size < 0x1000000 ? growth_size : 0x1000000;
763 const size_t off = offset();
764 section->data.resize_uninitialized(new_size);
766 thread_local uint8_t rand = 1;
767 std::memset(section->data.data() + off, rand += 2, new_size - off);
768 section->locked =
true;
771 data_begin = section->data.data();
772 data_cur = data_begin + off;
773 data_reserve_end = data_begin + section->data.size();
779template <
typename Derived>
783 static_assert(std::is_base_of_v<AssemblerElf, Derived>);
786 Derived *derived() noexcept {
return static_cast<Derived *
>(
this); }
788 void label_place(Label label, SecRef sec, u32 off)
noexcept;
791template <
typename Derived>
792void AssemblerElf<Derived>::label_place(Label label,
794 u32 offset)
noexcept {
795 assert(label_is_pending(label));
796 TempSymbolInfo &info = temp_symbols[
static_cast<u32
>(label)];
797 u32 fixup_idx = info.fixup_idx;
801 while (fixup_idx != ~0u) {
802 TempSymbolFixup &fixup = temp_symbol_fixups[fixup_idx];
803 derived()->handle_fixup(info, fixup);
804 auto next = fixup.next_list_entry;
805 fixup.next_list_entry = next_free_tsfixup;
806 next_free_tsfixup = fixup_idx;
AssemblerElf contains the architecture-independent logic to emit ELF object files (currently linux-sp...
AssemblerElf()
The current write pointer for the text section.