15#include "tpde/StringTable.hpp"
16#include "tpde/util/BumpAllocator.hpp"
17#include "tpde/util/VectorWriter.hpp"
18#include "util/SmallVector.hpp"
19#include "util/misc.hpp"
25constexpr u8 DW_CFA_nop = 0;
26constexpr u8 DW_EH_PE_uleb128 = 0x01;
27constexpr u8 DW_EH_PE_pcrel = 0x10;
28constexpr u8 DW_EH_PE_indirect = 0x80;
29constexpr u8 DW_EH_PE_sdata4 = 0x0b;
30constexpr u8 DW_EH_PE_omit = 0xff;
32constexpr u8 DW_CFA_offset_extended = 0x05;
33constexpr u8 DW_CFA_def_cfa = 0x0c;
34constexpr u8 DW_CFA_def_cfa_register = 0x0d;
35constexpr u8 DW_CFA_def_cfa_offset = 0x0e;
36constexpr u8 DW_CFA_offset = 0x80;
37constexpr u8 DW_CFA_advance_loc = 0x40;
38constexpr u8 DW_CFA_advance_loc4 = 0x04;
40constexpr u8 DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
42constexpr u32 EH_FDE_FUNC_START_OFF = 0x8;
45constexpr u8 DW_reg_rax = 0;
46constexpr u8 DW_reg_rdx = 1;
47constexpr u8 DW_reg_rcx = 2;
48constexpr u8 DW_reg_rbx = 3;
49constexpr u8 DW_reg_rsi = 4;
50constexpr u8 DW_reg_rdi = 5;
51constexpr u8 DW_reg_rbp = 6;
52constexpr u8 DW_reg_rsp = 7;
53constexpr u8 DW_reg_r8 = 8;
54constexpr u8 DW_reg_r9 = 9;
55constexpr u8 DW_reg_r10 = 10;
56constexpr u8 DW_reg_r11 = 11;
57constexpr u8 DW_reg_r12 = 12;
58constexpr u8 DW_reg_r13 = 13;
59constexpr u8 DW_reg_r14 = 14;
60constexpr u8 DW_reg_r15 = 15;
61constexpr u8 DW_reg_ra = 16;
65constexpr u8 DW_reg_x0 = 0;
66constexpr u8 DW_reg_x1 = 1;
67constexpr u8 DW_reg_x2 = 2;
68constexpr u8 DW_reg_x3 = 3;
69constexpr u8 DW_reg_x4 = 4;
70constexpr u8 DW_reg_x5 = 5;
71constexpr u8 DW_reg_x6 = 6;
72constexpr u8 DW_reg_x7 = 7;
73constexpr u8 DW_reg_x8 = 8;
74constexpr u8 DW_reg_x9 = 9;
75constexpr u8 DW_reg_x10 = 10;
76constexpr u8 DW_reg_x11 = 11;
77constexpr u8 DW_reg_x12 = 12;
78constexpr u8 DW_reg_x13 = 13;
79constexpr u8 DW_reg_x14 = 14;
80constexpr u8 DW_reg_x15 = 15;
81constexpr u8 DW_reg_x16 = 16;
82constexpr u8 DW_reg_x17 = 17;
83constexpr u8 DW_reg_x18 = 18;
84constexpr u8 DW_reg_x19 = 19;
85constexpr u8 DW_reg_x20 = 20;
86constexpr u8 DW_reg_x21 = 21;
87constexpr u8 DW_reg_x22 = 22;
88constexpr u8 DW_reg_x23 = 23;
89constexpr u8 DW_reg_x24 = 24;
90constexpr u8 DW_reg_x25 = 25;
91constexpr u8 DW_reg_x26 = 26;
92constexpr u8 DW_reg_x27 = 27;
93constexpr u8 DW_reg_x28 = 28;
94constexpr u8 DW_reg_x29 = 29;
95constexpr u8 DW_reg_x30 = 30;
97constexpr u8 DW_reg_fp = 29;
98constexpr u8 DW_reg_lr = 30;
100constexpr u8 DW_reg_v0 = 64;
101constexpr u8 DW_reg_v1 = 65;
102constexpr u8 DW_reg_v2 = 66;
103constexpr u8 DW_reg_v3 = 67;
104constexpr u8 DW_reg_v4 = 68;
105constexpr u8 DW_reg_v5 = 69;
106constexpr u8 DW_reg_v6 = 70;
107constexpr u8 DW_reg_v7 = 71;
108constexpr u8 DW_reg_v8 = 72;
109constexpr u8 DW_reg_v9 = 73;
110constexpr u8 DW_reg_v10 = 74;
111constexpr u8 DW_reg_v11 = 75;
112constexpr u8 DW_reg_v12 = 76;
113constexpr u8 DW_reg_v13 = 77;
114constexpr u8 DW_reg_v14 = 78;
115constexpr u8 DW_reg_v15 = 79;
116constexpr u8 DW_reg_v16 = 80;
117constexpr u8 DW_reg_v17 = 81;
118constexpr u8 DW_reg_v18 = 82;
119constexpr u8 DW_reg_v19 = 83;
120constexpr u8 DW_reg_v20 = 84;
121constexpr u8 DW_reg_v21 = 85;
122constexpr u8 DW_reg_v22 = 86;
123constexpr u8 DW_reg_v23 = 87;
124constexpr u8 DW_reg_v24 = 88;
125constexpr u8 DW_reg_v25 = 89;
126constexpr u8 DW_reg_v26 = 90;
127constexpr u8 DW_reg_v27 = 91;
128constexpr u8 DW_reg_v28 = 92;
129constexpr u8 DW_reg_v29 = 93;
130constexpr u8 DW_reg_v30 = 94;
132constexpr u8 DW_reg_sp = 31;
133constexpr u8 DW_reg_pc = 32;
138struct AssemblerElfBase {
139 template <
class Derived>
140 friend struct AssemblerElf;
141 friend class ElfMapper;
150 u8 cie_return_addr_register;
152 std::span<const u8> cie_instrs;
154 u8 cie_code_alignment_factor;
156 u8 cie_data_alignment_factor;
164 enum class SymBinding : u8 {
173 enum class SymVisibility : u8 {
174 DEFAULT = STV_DEFAULT,
175 INTERNAL = STV_INTERNAL,
177 PROTECTED = STV_PROTECTED,
186 constexpr SymRef() : val(0) {}
188 explicit constexpr SymRef(u32
id) : val(id) {}
190 u32 id()
const {
return val; }
191 bool valid()
const {
return val != 0; }
193 bool operator==(
const SymRef &other)
const {
return other.val == val; }
196 enum class SecRef : u32 {
198 static constexpr SecRef INVALID_SEC_REF =
static_cast<SecRef
>(0u);
201 enum class Label : u32 {
209 using StorageTy = util::SmallVector<u8, 256>;
223 void *target_info =
nullptr;
231 DataSection(SecRef ref,
unsigned type,
unsigned flags,
unsigned name_off)
232 : hdr{.sh_name = name_off, .sh_type = type, .sh_flags = flags},
235 SecRef get_ref() const noexcept {
return sec_ref; }
237 size_t size()
const {
238 return (hdr.sh_type == SHT_NOBITS) ? hdr.sh_size : data.size();
241 template <
typename T>
242 void write(
const T &t)
noexcept {
244 assert(hdr.sh_type != SHT_NOBITS);
245 size_t off = data.size();
246 data.resize_uninitialized(data.size() +
sizeof(T));
247 memcpy(data.data() + off, &t,
sizeof(T));
251 template <
typename Derived>
252 class SectionWriterBase {
254 DataSection *section =
nullptr;
255 u8 *data_begin =
nullptr;
256 u8 *data_cur =
nullptr;
257 u8 *data_reserve_end =
nullptr;
261 u32 growth_size = 0x10000;
263 SectionWriterBase() noexcept = default;
265 ~SectionWriterBase() {
266 assert(data_cur == data_reserve_end &&
267 "must flush section writer before destructing");
271 Derived *derived() noexcept {
return static_cast<Derived *
>(
this); }
275 SecRef get_sec_ref() const noexcept {
return get_section().get_ref(); }
278 DataSection &get_section() const noexcept {
279 assert(section !=
nullptr);
284 void switch_section(DataSection &new_section)
noexcept {
285 assert(data_cur == data_reserve_end &&
286 "must flush section writer before switching sections");
287 section = &new_section;
288 data_begin = section->data.data();
289 data_cur = data_begin + section->data.size();
290 data_reserve_end = data_cur;
294 size_t offset() const noexcept {
return data_cur - data_begin; }
297 size_t allocated_size() const noexcept {
298 return data_reserve_end - data_begin;
302 u8 *begin_ptr() noexcept {
return data_begin; }
306 u8 *&cur_ptr() noexcept {
return data_cur; }
308 void ensure_space(
size_t size)
noexcept {
309 assert(data_reserve_end >= data_cur);
310 if (
size_t(data_reserve_end - data_cur) < size) [[unlikely]] {
311 derived()->more_space(size);
315 void more_space(
size_t size)
noexcept;
317 template <std::
integral T>
318 void write_unchecked(T t)
noexcept {
319 assert(
size_t(data_reserve_end - data_cur) >=
sizeof(T));
320 std::memcpy(data_cur, &t,
sizeof(T));
321 data_cur +=
sizeof(T);
324 template <std::
integral T>
325 void write(T t)
noexcept {
326 ensure_space(
sizeof(T));
327 write_unchecked<T>(t);
330 void flush() noexcept {
331 if (data_cur != data_reserve_end) {
332 section->data.resize(offset());
333 data_reserve_end = data_cur;
335 section->locked =
false;
340 void align(
size_t align)
noexcept {
341 assert(align > 0 && (align & (align - 1)) == 0);
344 std::memset(cur_ptr(), 0, align);
345 data_cur = data_begin + util::align_up(offset(), align);
346 section->hdr.sh_addralign = std::max(section->hdr.sh_addralign, align);
351 const TargetInfo &target_info;
353 util::BumpAllocator<> section_allocator;
354 util::SmallVector<util::BumpAllocUniquePtr<DataSection>, 16> sections;
356 std::vector<Elf64_Sym> global_symbols, local_symbols;
358 util::SmallVector<u32, 0> global_shndx, local_shndx;
361 struct TempSymbolInfo {
371 struct TempSymbolFixup {
379 std::vector<TempSymbolInfo> temp_symbols;
380 std::vector<TempSymbolFixup> temp_symbol_fixups;
381 u32 next_free_tsfixup = ~0u;
385 StringTable shstrtab_extra;
388 SecRef secref_text = INVALID_SEC_REF;
389 SecRef secref_rodata = INVALID_SEC_REF;
390 SecRef secref_relro = INVALID_SEC_REF;
391 SecRef secref_data = INVALID_SEC_REF;
392 SecRef secref_bss = INVALID_SEC_REF;
393 SecRef secref_tdata = INVALID_SEC_REF;
394 SecRef secref_tbss = INVALID_SEC_REF;
397 SecRef secref_eh_frame = INVALID_SEC_REF;
398 SecRef secref_except_table = INVALID_SEC_REF;
401 util::VectorWriter eh_writer;
404 struct ExceptCallSiteInfo {
414 std::vector<ExceptCallSiteInfo> except_call_site_table;
417 util::SmallVector<u8> except_encoded_call_sites;
419 util::SmallVector<u8> except_action_table;
422 std::vector<SymRef> except_type_info_table;
424 std::vector<u8> except_spec_table;
426 SymRef cur_personality_func_addr;
427 u32 eh_cur_cie_off = 0u;
428 u32 eh_first_fde_off = 0;
434 explicit AssemblerElfBase(
const TargetInfo &target_info)
435 : target_info(target_info) {
436 local_symbols.resize(1);
441 void reset() noexcept;
445 DataSection &get_section(SecRef ref) noexcept {
446 assert(ref != INVALID_SEC_REF);
447 return *sections[
static_cast<u32
>(ref)];
450 const DataSection &get_section(SecRef ref)
const noexcept {
451 assert(ref != INVALID_SEC_REF);
452 return *sections[
static_cast<u32
>(ref)];
456 void init_sections() noexcept;
458 bool has_reloc_section(SecRef ref) const noexcept {
459 assert(ref != INVALID_SEC_REF);
460 if (
static_cast<u32
>(ref) + 1 < sections.size()) {
461 return sections[
static_cast<u32
>(ref) + 1]->hdr.sh_type == SHT_RELA;
466 DataSection &get_reloc_section(SecRef ref)
noexcept {
467 assert(has_reloc_section(ref));
468 DataSection &reloc_sec = *sections[
static_cast<u32
>(ref) + 1];
472 std::span<Elf64_Rela> get_relocs(SecRef ref) {
473 if (!has_reloc_section(ref)) {
476 DataSection &rela_sec = get_reloc_section(ref);
477 size_t count = rela_sec.size() /
sizeof(Elf64_Rela);
478 return {
reinterpret_cast<Elf64_Rela *
>(rela_sec.data.data()), count};
483 create_section(
unsigned type,
unsigned flags,
unsigned name)
noexcept;
486 [[nodiscard]] SecRef create_rela_section(SecRef ref,
488 unsigned rela_name)
noexcept;
490 [[nodiscard]] SymRef create_section_symbol(SecRef ref,
491 std::string_view name)
noexcept;
493 DataSection &get_or_create_section(SecRef &ref,
498 bool with_rela =
true) noexcept;
501 SecRef get_text_section() noexcept {
return secref_text; }
502 SecRef get_data_section(
bool rodata,
bool relro =
false) noexcept;
503 SecRef get_bss_section() noexcept;
504 SecRef get_tdata_section() noexcept;
505 SecRef get_tbss_section() noexcept;
506 SecRef create_structor_section(
bool init,
507 SecRef group = INVALID_SEC_REF) noexcept;
512 [[nodiscard]] SecRef create_section(std::string_view name,
516 SecRef group = INVALID_SEC_REF) noexcept;
519 [[nodiscard]] SecRef create_group_section(SymRef signature_sym,
520 bool is_comdat) noexcept;
522 const
char *sec_name(SecRef ref) const noexcept;
525 bool sec_is_xindex(SecRef ref) const noexcept {
526 return static_cast<u32
>(ref) >= SHN_LORESERVE;
532 void sym_copy(SymRef dst, SymRef src)
noexcept;
536 sym_add(std::string_view name, SymBinding binding, u32 type)
noexcept;
539 [[nodiscard]] SymRef sym_add_undef(std::string_view name,
540 SymBinding binding)
noexcept {
541 return sym_add(name, binding, STT_NOTYPE);
544 [[nodiscard]] SymRef sym_predef_func(std::string_view name,
545 SymBinding binding)
noexcept {
546 return sym_add(name, binding, STT_FUNC);
549 [[nodiscard]] SymRef sym_predef_data(std::string_view name,
550 SymBinding binding)
noexcept {
551 return sym_add(name, binding, STT_OBJECT);
554 [[nodiscard]] SymRef sym_predef_tls(std::string_view name,
555 SymBinding binding)
noexcept {
556 return sym_add(name, binding, STT_TLS);
559 void sym_def_predef_data(SecRef sec,
561 std::span<const u8> data,
565 [[nodiscard]] SymRef sym_def_data(SecRef sec,
566 std::string_view name,
567 std::span<const u8> data,
570 u32 *off =
nullptr) {
571 SymRef sym = sym_predef_data(name, binding);
572 sym_def_predef_data(sec, sym, data, align, off);
576 void sym_def_predef_zero(SecRef sec_ref,
580 u32 *off =
nullptr) noexcept;
584 void sym_def_xindex(SymRef sym_ref, SecRef sec_ref) noexcept;
587 void sym_def(SymRef sym_ref, SecRef sec_ref, u64 pos, u64 size) noexcept {
588 Elf64_Sym *sym = sym_ptr(sym_ref);
589 assert(sym->st_shndx == SHN_UNDEF &&
"cannot redefined symbol");
592 if (!sec_is_xindex(sec_ref)) [[likely]] {
593 sym->st_shndx =
static_cast<Elf64_Section
>(sec_ref);
595 sym->st_shndx = SHN_XINDEX;
596 sym_def_xindex(sym_ref, sec_ref);
601 void sym_set_visibility(SymRef sym, SymVisibility visibility)
noexcept {
602 sym_ptr(sym)->st_other =
static_cast<u8
>(visibility);
606 void sym_set_value(SymRef sym, u64 value)
noexcept {
607 sym_ptr(sym)->st_value = value;
610 const char *sym_name(SymRef sym)
const noexcept {
611 return strtab.data() + sym_ptr(sym)->st_name;
614 SecRef sym_section(SymRef sym)
const noexcept {
615 Elf64_Section shndx = sym_ptr(sym)->st_shndx;
616 if (shndx < SHN_LORESERVE && shndx != SHN_UNDEF) [[likely]] {
617 return SecRef(shndx);
619 assert(shndx == SHN_XINDEX);
620 const auto &shndx_tab = sym_is_local(sym) ? local_shndx : global_shndx;
621 return SecRef(shndx_tab[sym_idx(sym)]);
624 Label label_create() noexcept {
625 const Label label =
static_cast<Label
>(temp_symbols.size());
626 temp_symbols.push_back(TempSymbolInfo{INVALID_SEC_REF, {.fixup_idx = ~0u}});
631 u32 label_is_pending(Label label)
const noexcept {
632 const auto &info = temp_symbols[
static_cast<u32
>(label)];
633 return info.section == INVALID_SEC_REF;
637 u32 label_offset(Label label)
const noexcept {
638 assert(!label_is_pending(label));
639 const auto &info = temp_symbols[
static_cast<u32
>(label)];
644 [[nodiscard]]
static bool sym_is_local(
const SymRef sym)
noexcept {
645 return (sym.id() & 0x8000'0000) == 0;
648 [[nodiscard]]
static u32 sym_idx(
const SymRef sym)
noexcept {
649 return sym.id() & ~0x8000'0000;
652 [[nodiscard]] Elf64_Sym *sym_ptr(
const SymRef sym)
noexcept {
653 if (sym_is_local(sym)) {
654 return &local_symbols[sym_idx(sym)];
656 return &global_symbols[sym_idx(sym)];
660 [[nodiscard]]
const Elf64_Sym *sym_ptr(
const SymRef sym)
const noexcept {
661 if (sym_is_local(sym)) {
662 return &local_symbols[sym_idx(sym)];
664 return &global_symbols[sym_idx(sym)];
672 SecRef sec, SymRef sym, u32 type, u64 offset, i64 addend)
noexcept;
674 void reloc_pc32(SecRef sec, SymRef sym, u64 offset, i64 addend)
noexcept {
675 reloc_sec(sec, sym, target_info.reloc_pc32, offset, addend);
678 void reloc_abs(SecRef sec, SymRef sym, u64 offset, i64 addend)
noexcept {
679 reloc_sec(sec, sym, target_info.reloc_abs64, offset, addend);
682 void reloc_sec(SecRef sec, Label label, u8 kind, u32 offset)
noexcept;
686 static constexpr u32 write_eh_inst(u8 *dst, u8 opcode, u64 arg)
noexcept {
687 if (opcode & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) {
688 assert((arg & dwarf::DWARF_CFI_PRIMARY_OPCODE_MASK) == 0);
693 return 1 + util::uleb_write(dst, arg);
697 write_eh_inst(u8 *dst, u8 opcode, u64 arg1, u64 arg2)
noexcept {
699 dst += write_eh_inst(dst, opcode, arg1);
700 dst += util::uleb_write(dst, arg2);
704 void eh_align_frame() noexcept;
705 void eh_write_inst(u8 opcode, u64 arg) noexcept;
706 void eh_write_inst(u8 opcode, u64 first_arg, u64 second_arg) noexcept;
709 void eh_init_cie(SymRef personality_func_addr = SymRef()) noexcept;
712 u32 eh_begin_fde(SymRef personality_func_addr = SymRef()) noexcept;
713 void eh_end_fde(u32 fde_start, SymRef func) noexcept;
715 void except_begin_func() noexcept;
717 void except_encode_func(SymRef func_sym) noexcept;
721 void except_add_call_site(u32 text_off,
724 bool is_cleanup) noexcept;
728 void except_add_cleanup_action() noexcept;
732 void except_add_action(
bool first_action, SymRef type_sym) noexcept;
734 void except_add_empty_spec_action(
bool first_action) noexcept;
736 u32 except_type_idx_for_sym(SymRef sym) noexcept;
738 void finalize() noexcept;
742 std::vector<u8> build_object_file() noexcept;
745template <typename Derived>
746void AssemblerElfBase::SectionWriterBase<Derived>::more_space(
747 size_t size) noexcept {
748 size_t cur_size = section->data.size();
750 if (cur_size + size <= section->data.capacity()) {
751 new_size = section->data.capacity();
753 new_size = cur_size + (size <= growth_size ? growth_size : size);
756 growth_size = growth_size + (growth_size >> 1);
758 growth_size = growth_size < 0x1000000 ? growth_size : 0x1000000;
761 const size_t off = offset();
762 section->data.resize_uninitialized(new_size);
764 thread_local uint8_t rand = 1;
765 std::memset(section->data.data() + off, rand += 2, new_size - off);
766 section->locked =
true;
769 data_begin = section->data.data();
770 data_cur = data_begin + off;
771 data_reserve_end = data_begin + section->data.size();
777template <
typename Derived>
781 static_assert(std::is_base_of_v<AssemblerElf, Derived>);
784 Derived *derived() noexcept {
return static_cast<Derived *
>(
this); }
786 void label_place(Label label, SecRef sec, u32 off)
noexcept;
789template <
typename Derived>
790void AssemblerElf<Derived>::label_place(Label label,
792 u32 offset)
noexcept {
793 assert(label_is_pending(label));
794 TempSymbolInfo &info = temp_symbols[
static_cast<u32
>(label)];
795 u32 fixup_idx = info.fixup_idx;
799 while (fixup_idx != ~0u) {
800 TempSymbolFixup &fixup = temp_symbol_fixups[fixup_idx];
801 derived()->handle_fixup(info, fixup);
802 auto next = fixup.next_list_entry;
803 fixup.next_list_entry = next_free_tsfixup;
804 next_free_tsfixup = fixup_idx;
AssemblerElf()
The current write pointer for the text section.