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