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() noexcept override;
55
56private:
57 void init_sections() noexcept;
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,
64 std::string_view name) noexcept;
65
66public:
67 SecRef create_structor_section(bool init, SecRef group = SecRef()) noexcept;
68
69 void rename_section(SecRef, std::string_view) noexcept override;
70
71 SymRef section_symbol(SecRef) noexcept override;
72
73 /// Create a new group section.
74 [[nodiscard]] SecRef create_group_section(SymRef signature_sym,
75 bool is_comdat) noexcept;
76
77 /// Add a section to a section group.
78 void add_to_group(SecRef group_ref, SecRef sec_ref) noexcept;
79
80 const char *sec_name(SecRef ref) const noexcept;
81
82private:
83 bool sec_is_xindex(SecRef ref) const noexcept {
84 return ref.id() >= SHN_LORESERVE;
85 }
86
87public:
88 // Symbols
89
90 void sym_copy(SymRef dst, SymRef src) noexcept;
91
92private:
93 [[nodiscard]] SymRef
94 sym_add(std::string_view name, SymBinding binding, u32 type) noexcept;
95
96public:
97 [[nodiscard]] SymRef sym_add_undef(std::string_view name,
98 SymBinding binding) noexcept override {
99 return sym_add(name, binding, STT_NOTYPE);
100 }
101
102 [[nodiscard]] SymRef sym_predef_func(std::string_view name,
103 SymBinding binding) noexcept override {
104 return sym_add(name, binding, STT_FUNC);
105 }
106
107 [[nodiscard]] SymRef sym_predef_data(std::string_view name,
108 SymBinding binding) noexcept override {
109 return sym_add(name, binding, STT_OBJECT);
110 }
111
112 [[nodiscard]] SymRef sym_predef_tls(std::string_view name,
113 SymBinding binding) noexcept override {
114 return sym_add(name, binding, STT_TLS);
115 }
116
117private:
118 /// Set symbol sections for SHN_XINDEX.
119 void sym_def_xindex(SymRef sym_ref, SecRef sec_ref) noexcept;
120
121public:
122 void sym_def(SymRef sym_ref,
123 SecRef sec_ref,
124 u64 pos,
125 u64 size) noexcept override {
126 Elf64_Sym *sym = sym_ptr(sym_ref);
127 assert(sym->st_shndx == SHN_UNDEF && "cannot redefined symbol");
128 sym->st_value = pos;
129 sym->st_size = size;
130 if (!sec_is_xindex(sec_ref)) [[likely]] {
131 sym->st_shndx = sec_ref.id();
132 } else {
133 sym->st_shndx = SHN_XINDEX;
134 sym_def_xindex(sym_ref, sec_ref);
135 }
136 // TODO: handle fixups?
137 }
138
139 void sym_set_visibility(SymRef sym, SymVisibility visibility) noexcept {
140 sym_ptr(sym)->st_other = static_cast<u8>(visibility);
141 }
142
143 const char *sym_name(SymRef sym) const noexcept {
144 return strtab.data() + sym_ptr(sym)->st_name;
145 }
146
147 SecRef sym_section(SymRef sym) const noexcept {
148 auto shndx = sym_ptr(sym)->st_shndx;
149 if (shndx < SHN_LORESERVE && shndx != SHN_UNDEF) [[likely]] {
150 return SecRef(shndx);
151 }
152 assert(shndx == SHN_XINDEX);
153 const auto &shndx_tab = sym_is_local(sym) ? local_shndx : global_shndx;
154 return SecRef(shndx_tab[sym_idx(sym)]);
155 }
156
157private:
158 [[nodiscard]] static bool sym_is_local(const SymRef sym) noexcept {
159 return (sym.id() & 0x8000'0000) == 0;
160 }
161
162 [[nodiscard]] static u32 sym_idx(const SymRef sym) noexcept {
163 return sym.id() & ~0x8000'0000;
164 }
165
166 [[nodiscard]] Elf64_Sym *sym_ptr(const SymRef sym) noexcept {
167 if (sym_is_local(sym)) {
168 return &local_symbols[sym_idx(sym)];
169 } else {
170 return &global_symbols[sym_idx(sym)];
171 }
172 }
173
174 [[nodiscard]] const Elf64_Sym *sym_ptr(const SymRef sym) const noexcept {
175 if (sym_is_local(sym)) {
176 return &local_symbols[sym_idx(sym)];
177 } else {
178 return &global_symbols[sym_idx(sym)];
179 }
180 }
181
182public:
183 // Output file generation
184
185 std::vector<u8> build_object_file() noexcept override;
186};
187
188// TODO: Remove these types, instead find a good way to specify architecture as
189// enum parameter (probably contained in Assembler?) to constructor.
190
191class AssemblerElfA64 final : public AssemblerElf {
192 static const TargetInfoElf TARGET_INFO;
193
194public:
195 explicit AssemblerElfA64() noexcept : AssemblerElf(TARGET_INFO) {}
196};
197
198class AssemblerElfX64 final : public AssemblerElf {
199 static const TargetInfoElf TARGET_INFO;
200
201public:
202 explicit AssemblerElfX64() noexcept : AssemblerElf(TARGET_INFO) {}
203};
204
205} // namespace tpde::elf