TPDE
Loading...
Searching...
No Matches
AssemblerElf.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4#pragma once
5
6#include <cassert>
7#include <cstdlib>
8#include <elf.h>
9#include <span>
10#include <string_view>
11#include <type_traits>
12#include <vector>
13
14#include "base.hpp"
15#include "tpde/util/BumpAllocator.hpp"
16#include "tpde/util/VectorWriter.hpp"
17#include "util/SmallVector.hpp"
18#include "util/misc.hpp"
19
20namespace tpde {
21
22namespace dwarf {
23// DWARF constants
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;
30
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;
38
39constexpr u8 DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
40
41constexpr u32 EH_FDE_FUNC_START_OFF = 0x8;
42
43namespace x64 {
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;
61} // namespace x64
62
63namespace a64 {
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;
95
96constexpr u8 DW_reg_fp = 29;
97constexpr u8 DW_reg_lr = 30;
98
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;
130
131constexpr u8 DW_reg_sp = 31;
132constexpr u8 DW_reg_pc = 32;
133} // namespace a64
134
135} // namespace dwarf
136
137struct AssemblerElfBase {
138 template <class Derived>
139 friend struct AssemblerElf;
140 friend class ElfMapper;
141
142 struct TargetInfo {
143 /// The OS ABI for the ELF header.
144 u8 elf_osabi;
145 /// The machine for the ELF header.
146 u16 elf_machine;
147
148 /// The return address register for the CIE.
149 u8 cie_return_addr_register;
150 /// The initial instructions for the CIE.
151 std::span<const u8> cie_instrs;
152 /// Code alignment factor for the CIE, ULEB128, must be one byte.
153 u8 cie_code_alignment_factor;
154 /// Data alignment factor for the CIE, SLEB128, must be one byte.
155 u8 cie_data_alignment_factor;
156
157 /// The relocation type for 32-bit pc-relative offsets.
158 u32 reloc_pc32;
159 /// The relocation type for 64-bit absolute addresses.
160 u32 reloc_abs64;
161 };
162
163 enum class SymBinding : u8 {
164 /// Symbol with local linkage, must be defined
165 LOCAL,
166 /// Weak linkage
167 WEAK,
168 /// Global linkage
169 GLOBAL,
170 };
171
172 enum class SymVisibility : u8 {
173 DEFAULT = STV_DEFAULT,
174 INTERNAL = STV_INTERNAL,
175 HIDDEN = STV_HIDDEN,
176 PROTECTED = STV_PROTECTED,
177 };
178
179 struct SymRef {
180 private:
181 u32 val;
182
183 public:
184 /// Invalid symbol reference
185 constexpr SymRef() : val(0) {}
186
187 explicit constexpr SymRef(u32 id) : val(id) {}
188
189 u32 id() const { return val; }
190 bool valid() const { return val != 0; }
191
192 bool operator==(const SymRef &other) const { return other.val == val; }
193 };
194
195 enum class SecRef : u32 {
196 };
197 static constexpr SecRef INVALID_SEC_REF = static_cast<SecRef>(0u);
198
199 // TODO: merge Label with SymRef when adding private symbols
200 enum class Label : u32 {
201 };
202
203 // TODO(ts): 32 bit version?
204 struct DataSection {
205 /// 256 bytes inline storage is enough for 10 relocations, which is a
206 /// typical number for a single function (relevant for COMDAT sections with
207 /// one section per function).
208 using StorageTy = util::SmallVector<u8, 256>;
209
210 /// Section data.
211 StorageTy data;
212
213 Elf64_Shdr hdr;
214 /// Section symbol, or signature symbol for SHT_GROUP sections.
215 SymRef sym;
216
217 private:
218 SecRef sec_ref;
219
220 public:
221 /// Generic field for target-specific data.
222 void *target_info = nullptr;
223
224#ifndef NDEBUG
225 /// Whether the section is currently in use by a SectionWriter.
226 bool locked = false;
227#endif
228
229 // DataSection() = default;
230 DataSection(SecRef ref, unsigned type, unsigned flags, unsigned name_off)
231 : hdr{.sh_name = name_off, .sh_type = type, .sh_flags = flags},
232 sec_ref(ref) {}
233
234 SecRef get_ref() const noexcept { return sec_ref; }
235
236 size_t size() const {
237 return (hdr.sh_type == SHT_NOBITS) ? hdr.sh_size : data.size();
238 }
239
240 template <typename T>
241 void write(const T &t) noexcept {
242 assert(!locked);
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));
247 }
248 };
249
250 template <typename Derived>
251 class SectionWriterBase {
252 protected:
253 DataSection *section = nullptr;
254 u8 *data_begin = nullptr;
255 u8 *data_cur = nullptr;
256 u8 *data_reserve_end = nullptr;
257
258 public:
259 /// Growth size for more_space; adjusted exponentially after every grow.
260 u32 growth_size = 0x10000;
261
262 SectionWriterBase() noexcept = default;
263
264 ~SectionWriterBase() {
265 assert(data_cur == data_reserve_end &&
266 "must flush section writer before destructing");
267 }
268
269 protected:
270 Derived *derived() noexcept { return static_cast<Derived *>(this); }
271
272 public:
273 /// Get the SecRef of the current section.
274 SecRef get_sec_ref() const noexcept { return get_section().get_ref(); }
275
276 /// Get the current section.
277 DataSection &get_section() const noexcept {
278 assert(section != nullptr);
279 return *section;
280 }
281
282 /// Switch section writer to new section; must be flushed.
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;
290 }
291
292 /// Get the current offset into the section.
293 size_t offset() const noexcept { return data_cur - data_begin; }
294
295 /// Get the current allocated size of the section.
296 size_t allocated_size() const noexcept {
297 return data_reserve_end - data_begin;
298 }
299
300 /// Pointer to beginning of section data.
301 u8 *begin_ptr() noexcept { return data_begin; }
302
303 /// Modifiable pointer to current writing position of the section. Must not
304 /// be moved beyond the allocated region.
305 u8 *&cur_ptr() noexcept { return data_cur; }
306
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);
311 }
312 }
313
314 void more_space(size_t size) noexcept;
315
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);
321 }
322
323 template <std::integral T>
324 void write(T t) noexcept {
325 ensure_space(sizeof(T));
326 write_unchecked<T>(t);
327 }
328
329 void flush() noexcept {
330 if (data_cur != data_reserve_end) {
331 section->data.resize(offset());
332 data_reserve_end = data_cur;
333#ifndef NDEBUG
334 section->locked = false;
335#endif
336 }
337 }
338
339 void align(size_t align) noexcept {
340 assert(align > 0 && (align & (align - 1)) == 0);
341 ensure_space(align);
342 // permit optimization when align is a constant.
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);
346 }
347 };
348
349private:
350 const TargetInfo &target_info;
351
352 util::BumpAllocator<> section_allocator;
353 util::SmallVector<util::BumpAllocUniquePtr<DataSection>, 16> sections;
354
355 std::vector<Elf64_Sym> global_symbols, local_symbols;
356 /// Section indices for large section numbers
357 util::SmallVector<u32, 0> global_shndx, local_shndx;
358
359protected:
360 struct TempSymbolInfo {
361 /// Section, or INVALID_SEC_REF if pending
362 SecRef section;
363 /// Offset into section, or index into temp_symbol_fixups if pending
364 union {
365 u32 fixup_idx;
366 u32 off;
367 };
368 };
369
370 struct TempSymbolFixup {
371 SecRef section;
372 u32 next_list_entry;
373 u32 off;
374 u8 kind;
375 };
376
377private:
378 std::vector<TempSymbolInfo> temp_symbols;
379 std::vector<TempSymbolFixup> temp_symbol_fixups;
380 u32 next_free_tsfixup = ~0u;
381
382 std::vector<char> strtab;
383 /// Storage for extra user-provided section names.
384 std::string shstrtab_extra;
385
386protected:
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;
394
395 /// Unwind Info
396 SecRef secref_eh_frame = INVALID_SEC_REF;
397 SecRef secref_except_table = INVALID_SEC_REF;
398
399public:
400 util::VectorWriter<DataSection::StorageTy> eh_writer;
401
402private:
403 struct ExceptCallSiteInfo {
404 /// Start offset *in section* (not inside function)
405 u64 start;
406 u64 len;
407 Label landing_pad;
408 u32 action_entry;
409 };
410
411 /// Exception Handling temporary storage
412 /// Call Sites for current function
413 std::vector<ExceptCallSiteInfo> except_call_site_table;
414
415 /// Temporary storage for encoding call sites
416 std::vector<u8> except_encoded_call_sites;
417 /// Action Table for current function
418 std::vector<u8> except_action_table;
419 /// The type_info table (contains the symbols which contain the pointers to
420 /// the type_info)
421 std::vector<SymRef> except_type_info_table;
422 /// Table for exception specs
423 std::vector<u8> except_spec_table;
424 /// The current personality function (if any)
425 SymRef cur_personality_func_addr;
426 u32 eh_cur_cie_off = 0u;
427 u32 eh_first_fde_off = 0;
428
429 /// The current function
430 SymRef cur_func;
431
432public:
433 explicit AssemblerElfBase(const TargetInfo &target_info)
434 : target_info(target_info) {
435 strtab.push_back('\0');
436
437 local_symbols.resize(1); // First symbol must be null.
438 init_sections();
439 eh_init_cie();
440 }
441
442 void reset() noexcept;
443
444 // Sections
445
446 DataSection &get_section(SecRef ref) noexcept {
447 assert(ref != INVALID_SEC_REF);
448 return *sections[static_cast<u32>(ref)];
449 }
450
451 const DataSection &get_section(SecRef ref) const noexcept {
452 assert(ref != INVALID_SEC_REF);
453 return *sections[static_cast<u32>(ref)];
454 }
455
456private:
457 void init_sections() noexcept;
458
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;
463 }
464 return false;
465 }
466
467 DataSection &get_reloc_section(SecRef ref) noexcept {
468 assert(has_reloc_section(ref));
469 DataSection &reloc_sec = *sections[static_cast<u32>(ref) + 1];
470 return reloc_sec;
471 }
472
473 std::span<Elf64_Rela> get_relocs(SecRef ref) {
474 if (!has_reloc_section(ref)) {
475 return {};
476 }
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};
480 }
481
482 /// Allocate a new section.
483 [[nodiscard]] SecRef
484 create_section(unsigned type, unsigned flags, unsigned name) noexcept;
485
486 /// Allocate a new section for relocations.
487 [[nodiscard]] SecRef create_rela_section(SecRef ref,
488 unsigned flags,
489 unsigned rela_name) noexcept;
490
491 [[nodiscard]] SymRef create_section_symbol(SecRef ref,
492 std::string_view name) noexcept;
493
494 DataSection &get_or_create_section(SecRef &ref,
495 unsigned rela_name,
496 unsigned type,
497 unsigned flags,
498 unsigned align,
499 bool with_rela = true) noexcept;
500
501public:
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;
509
510 /// Create a new section with the given name, ELF section type, and flags.
511 /// Optionally, a corresponding relocation (.rela) section is also created,
512 /// otherwise, the section must not have relocations.
513 [[nodiscard]] SecRef create_section(std::string_view name,
514 unsigned type,
515 unsigned flags,
516 bool with_rela,
517 SecRef group = INVALID_SEC_REF) noexcept;
518
519 /// Create a new group section.
520 [[nodiscard]] SecRef create_group_section(SymRef signature_sym,
521 bool is_comdat) noexcept;
522
523 const char *sec_name(SecRef ref) const noexcept;
524
525private:
526 bool sec_is_xindex(SecRef ref) const noexcept {
527 return static_cast<u32>(ref) >= SHN_LORESERVE;
528 }
529
530public:
531 // Symbols
532
533 void sym_copy(SymRef dst, SymRef src) noexcept;
534
535private:
536 [[nodiscard]] SymRef
537 sym_add(std::string_view name, SymBinding binding, u32 type) noexcept;
538
539public:
540 [[nodiscard]] SymRef sym_add_undef(std::string_view name,
541 SymBinding binding) noexcept {
542 return sym_add(name, binding, STT_NOTYPE);
543 }
544
545 [[nodiscard]] SymRef sym_predef_func(std::string_view name,
546 SymBinding binding) noexcept {
547 return sym_add(name, binding, STT_FUNC);
548 }
549
550 [[nodiscard]] SymRef sym_predef_data(std::string_view name,
551 SymBinding binding) noexcept {
552 return sym_add(name, binding, STT_OBJECT);
553 }
554
555 [[nodiscard]] SymRef sym_predef_tls(std::string_view name,
556 SymBinding binding) noexcept {
557 return sym_add(name, binding, STT_TLS);
558 }
559
560 void sym_def_predef_data(SecRef sec,
561 SymRef sym,
562 std::span<const u8> data,
563 u32 align,
564 u32 *off) noexcept;
565
566 [[nodiscard]] SymRef sym_def_data(SecRef sec,
567 std::string_view name,
568 std::span<const u8> data,
569 u32 align,
570 SymBinding binding,
571 u32 *off = nullptr) {
572 SymRef sym = sym_predef_data(name, binding);
573 sym_def_predef_data(sec, sym, data, align, off);
574 return sym;
575 }
576
577 void sym_def_predef_zero(SecRef sec_ref,
578 SymRef sym_ref,
579 u32 size,
580 u32 align,
581 u32 *off = nullptr) noexcept;
582
583private:
584 /// Set symbol sections for SHN_XINDEX.
585 void sym_def_xindex(SymRef sym_ref, SecRef sec_ref) noexcept;
586
587public:
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");
591 sym->st_value = pos;
592 sym->st_size = size;
593 if (!sec_is_xindex(sec_ref)) [[likely]] {
594 sym->st_shndx = static_cast<Elf64_Section>(sec_ref);
595 } else {
596 sym->st_shndx = SHN_XINDEX;
597 sym_def_xindex(sym_ref, sec_ref);
598 }
599 // TODO: handle fixups?
600 }
601
602 void sym_set_visibility(SymRef sym, SymVisibility visibility) noexcept {
603 sym_ptr(sym)->st_other = static_cast<u8>(visibility);
604 }
605
606 /// Forcefully set value of symbol, doesn't change section.
607 void sym_set_value(SymRef sym, u64 value) noexcept {
608 sym_ptr(sym)->st_value = value;
609 }
610
611 const char *sym_name(SymRef sym) const noexcept {
612 return strtab.data() + sym_ptr(sym)->st_name;
613 }
614
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);
619 }
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)]);
623 }
624
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}});
628 return label;
629 }
630
631 // TODO: return pair of section, offset
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;
635 }
636
637 // TODO: return pair of section, offset
638 u32 label_offset(Label label) const noexcept {
639 assert(!label_is_pending(label));
640 const auto &info = temp_symbols[static_cast<u32>(label)];
641 return info.off;
642 }
643
644protected:
645 [[nodiscard]] static bool sym_is_local(const SymRef sym) noexcept {
646 return (sym.id() & 0x8000'0000) == 0;
647 }
648
649 [[nodiscard]] static u32 sym_idx(const SymRef sym) noexcept {
650 return sym.id() & ~0x8000'0000;
651 }
652
653 [[nodiscard]] Elf64_Sym *sym_ptr(const SymRef sym) noexcept {
654 if (sym_is_local(sym)) {
655 return &local_symbols[sym_idx(sym)];
656 } else {
657 return &global_symbols[sym_idx(sym)];
658 }
659 }
660
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)];
664 } else {
665 return &global_symbols[sym_idx(sym)];
666 }
667 }
668
669 // Relocations
670
671public:
672 void reloc_sec(
673 SecRef sec, SymRef sym, u32 type, u64 offset, i64 addend) noexcept;
674
675 void reloc_pc32(SecRef sec, SymRef sym, u64 offset, i64 addend) noexcept {
676 reloc_sec(sec, sym, target_info.reloc_pc32, offset, addend);
677 }
678
679 void reloc_abs(SecRef sec, SymRef sym, u64 offset, i64 addend) noexcept {
680 reloc_sec(sec, sym, target_info.reloc_abs64, offset, addend);
681 }
682
683 void reloc_sec(SecRef sec, Label label, u8 kind, u32 offset) noexcept;
684
685 // Unwind and exception info
686
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);
690 *dst = opcode | arg;
691 return 1;
692 }
693 *dst++ = opcode;
694 return 1 + util::uleb_write(dst, arg);
695 }
696
697 static constexpr u32
698 write_eh_inst(u8 *dst, u8 opcode, u64 arg1, u64 arg2) noexcept {
699 u8 *base = dst;
700 dst += write_eh_inst(dst, opcode, arg1);
701 dst += util::uleb_write(dst, arg2);
702 return dst - base;
703 }
704
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;
709
710private:
711 void eh_init_cie(SymRef personality_func_addr = SymRef()) noexcept;
712
713public:
714 u32 eh_begin_fde(SymRef personality_func_addr = SymRef()) noexcept;
715 void eh_end_fde(u32 fde_start, SymRef func) noexcept;
716
717 void except_begin_func() noexcept;
718
719 void except_encode_func(SymRef func_sym) noexcept;
720
721 /// add an entry to the call-site table
722 /// must be called in strictly increasing order wrt text_off
723 void except_add_call_site(u32 text_off,
724 u32 len,
725 Label landing_pad,
726 bool is_cleanup) noexcept;
727
728 /// Add a cleanup action to the action table
729 /// *MUST* be the last one
730 void except_add_cleanup_action() noexcept;
731
732 /// add an action to the action table
733 /// An invalid SymRef signals a catch(...)
734 void except_add_action(bool first_action, SymRef type_sym) noexcept;
735
736 void except_add_empty_spec_action(bool first_action) noexcept;
737
738 u32 except_type_idx_for_sym(SymRef sym) noexcept;
739
740 void finalize() noexcept;
741
742 // Output file generation
743
744 std::vector<u8> build_object_file() noexcept;
745};
746
747template <typename Derived>
748void AssemblerElfBase::SectionWriterBase<Derived>::more_space(
749 size_t size) noexcept {
750 size_t cur_size = section->data.size();
751 size_t new_size;
752 if (cur_size + size <= section->data.capacity()) {
753 new_size = section->data.capacity();
754 } else {
755 new_size = cur_size + (size <= growth_size ? growth_size : size);
756
757 // Grow by factor 1.5
758 growth_size = growth_size + (growth_size >> 1);
759 // Max 16 MiB per grow.
760 growth_size = growth_size < 0x1000000 ? growth_size : 0x1000000;
761 }
762
763 const size_t off = offset();
764 section->data.resize_uninitialized(new_size);
765#ifndef NDEBUG
766 thread_local uint8_t rand = 1;
767 std::memset(section->data.data() + off, rand += 2, new_size - off);
768 section->locked = true;
769#endif
770
771 data_begin = section->data.data();
772 data_cur = data_begin + off;
773 data_reserve_end = data_begin + section->data.size();
774}
775
776/// AssemblerElf contains the architecture-independent logic to emit
777/// ELF object files (currently linux-specific) which is then extended by
778/// AssemblerElfX64 or AssemblerElfA64
779template <typename Derived>
780struct AssemblerElf : public AssemblerElfBase {
781 /// The current write pointer for the text section
782 explicit AssemblerElf() : AssemblerElfBase(Derived::TARGET_INFO) {
783 static_assert(std::is_base_of_v<AssemblerElf, Derived>);
784 }
785
786 Derived *derived() noexcept { return static_cast<Derived *>(this); }
787
788 void label_place(Label label, SecRef sec, u32 off) noexcept;
789};
790
791template <typename Derived>
792void AssemblerElf<Derived>::label_place(Label label,
793 SecRef sec,
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;
798 info.section = sec;
799 info.off = offset;
800
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;
807 fixup_idx = next;
808 }
809}
810
811} // namespace tpde
AssemblerElf contains the architecture-independent logic to emit ELF object files (currently linux-sp...
AssemblerElf()
The current write pointer for the text section.