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 <span>
8#include <string_view>
9#include <vector>
10
11#include "base.hpp"
12#include "tpde/Assembler.hpp"
13#include "tpde/ELF.hpp"
14#include "tpde/StringTable.hpp"
15#include "util/SmallVector.hpp"
16
17namespace tpde::elf {
18
19class AssemblerElf : public Assembler {
20 friend class ElfMapper;
21
22protected:
23 struct TargetInfoElf : Assembler::TargetInfo {
24 /// The OS ABI for the ELF header.
25 u8 elf_osabi;
26 /// The machine for the ELF header.
27 u16 elf_machine;
28 };
29
30public:
31 enum class SymVisibility : u8 {
32 DEFAULT = STV_DEFAULT,
33 INTERNAL = STV_INTERNAL,
34 HIDDEN = STV_HIDDEN,
35 PROTECTED = STV_PROTECTED,
36 };
37
38private:
39 std::vector<Elf64_Sym> global_symbols, local_symbols;
40 /// Section indices for large section numbers
41 util::SmallVector<u32, 0> global_shndx, local_shndx;
42
43 StringTable strtab;
44 /// Storage for extra user-provided section names.
45 StringTable shstrtab_extra;
46
47public:
48 explicit AssemblerElf(const TargetInfoElf &target_info)
49 : Assembler(target_info) {
50 local_symbols.resize(1); // First symbol must be null.
51 init_sections();
52 }
53
54 void reset() override;
55
56private:
57 void init_sections();
58
59 std::span<Relocation> get_relocs(SecRef ref) {
60 return get_section(ref).relocs;
61 }
62
63 [[nodiscard]] SymRef create_section_symbol(SecRef ref, std::string_view name);
64
65public:
66 SecRef create_structor_section(bool init, SecRef group = SecRef());
67
68 void rename_section(SecRef, std::string_view) override;
69
70 SymRef section_symbol(SecRef) override;
71
72 /// Create a new group section.
73 [[nodiscard]] SecRef create_group_section(SymRef signature_sym,
74 bool is_comdat);
75
76 /// Add a section to a section group.
77 void add_to_group(SecRef group_ref, SecRef sec_ref);
78
79 const char *sec_name(SecRef ref) const;
80
81private:
82 bool sec_is_xindex(SecRef ref) const { return ref.id() >= SHN_LORESERVE; }
83
84public:
85 // Symbols
86
87 void sym_copy(SymRef dst, SymRef src);
88
89private:
90 [[nodiscard]] SymRef
91 sym_add(std::string_view name, SymBinding binding, u32 type);
92
93public:
94 [[nodiscard]] SymRef sym_add_undef(std::string_view name,
95 SymBinding binding) override {
96 return sym_add(name, binding, STT_NOTYPE);
97 }
98
99 [[nodiscard]] SymRef sym_predef_func(std::string_view name,
100 SymBinding binding) override {
101 return sym_add(name, binding, STT_FUNC);
102 }
103
104 [[nodiscard]] SymRef sym_predef_data(std::string_view name,
105 SymBinding binding) override {
106 return sym_add(name, binding, STT_OBJECT);
107 }
108
109 [[nodiscard]] SymRef sym_predef_tls(std::string_view name,
110 SymBinding binding) override {
111 return sym_add(name, binding, STT_TLS);
112 }
113
114private:
115 /// Set symbol sections for SHN_XINDEX.
116 void sym_def_xindex(SymRef sym_ref, SecRef sec_ref);
117
118public:
119 void sym_def(SymRef sym_ref, SecRef sec_ref, u64 pos, u64 size) override {
120 Elf64_Sym *sym = sym_ptr(sym_ref);
121 assert(sym->st_shndx == SHN_UNDEF && "cannot redefined symbol");
122 sym->st_value = pos;
123 sym->st_size = size;
124 if (!sec_is_xindex(sec_ref)) [[likely]] {
125 sym->st_shndx = sec_ref.id();
126 } else {
127 sym->st_shndx = SHN_XINDEX;
128 sym_def_xindex(sym_ref, sec_ref);
129 }
130 // TODO: handle fixups?
131 }
132
133 void sym_set_visibility(SymRef sym, SymVisibility visibility) {
134 sym_ptr(sym)->st_other = static_cast<u8>(visibility);
135 }
136
137 const char *sym_name(SymRef sym) const {
138 return strtab.data() + sym_ptr(sym)->st_name;
139 }
140
141 SecRef sym_section(SymRef sym) const {
142 auto shndx = sym_ptr(sym)->st_shndx;
143 if (shndx < SHN_LORESERVE && shndx != SHN_UNDEF) [[likely]] {
144 return SecRef(shndx);
145 }
146 assert(shndx == SHN_XINDEX);
147 const auto &shndx_tab = sym_is_local(sym) ? local_shndx : global_shndx;
148 return SecRef(shndx_tab[sym_idx(sym)]);
149 }
150
151private:
152 [[nodiscard]] static bool sym_is_local(const SymRef sym) {
153 return (sym.id() & 0x8000'0000) == 0;
154 }
155
156 [[nodiscard]] static u32 sym_idx(const SymRef sym) {
157 return sym.id() & ~0x8000'0000;
158 }
159
160 [[nodiscard]] Elf64_Sym *sym_ptr(const SymRef sym) {
161 if (sym_is_local(sym)) {
162 return &local_symbols[sym_idx(sym)];
163 } else {
164 return &global_symbols[sym_idx(sym)];
165 }
166 }
167
168 [[nodiscard]] const Elf64_Sym *sym_ptr(const SymRef sym) const {
169 if (sym_is_local(sym)) {
170 return &local_symbols[sym_idx(sym)];
171 } else {
172 return &global_symbols[sym_idx(sym)];
173 }
174 }
175
176public:
177 // Output file generation
178
179 std::vector<u8> build_object_file() override;
180};
181
182// TODO: Remove these types, instead find a good way to specify architecture as
183// enum parameter (probably contained in Assembler?) to constructor.
184
185class AssemblerElfA64 final : public AssemblerElf {
186 static const TargetInfoElf TARGET_INFO;
187
188public:
189 explicit AssemblerElfA64() : AssemblerElf(TARGET_INFO) {}
190};
191
192class AssemblerElfX64 final : public AssemblerElf {
193 static const TargetInfoElf TARGET_INFO;
194
195public:
196 explicit AssemblerElfX64() : AssemblerElf(TARGET_INFO) {}
197};
198
199} // namespace tpde::elf