1 /*
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
17 #define COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
18
19 #include <elf.h>
20 #include <vector>
21 #include <string>
22 #include <tuple>
23 #include <fstream>
24 #include <functional>
25 #ifdef PANDA_COMPILER_DEBUG_INFO
26 #include <libdwarf/libdwarf.h>
27 #include <libdwarf/dwarf.h>
28 #endif
29
30 #include "include/class.h"
31
32 namespace ark::compiler {
33
34 class ElfSectionDataProvider {
35 public:
36 using DataCallback = void (*)(Span<const uint8_t>);
37
38 virtual void FillData(Span<uint8_t> os, size_t pos) const = 0;
39 virtual size_t GetDataSize() const = 0;
40
41 ElfSectionDataProvider() = default;
42 NO_COPY_SEMANTIC(ElfSectionDataProvider);
43 NO_MOVE_SEMANTIC(ElfSectionDataProvider);
44 virtual ~ElfSectionDataProvider() = default;
45 };
46
47 #ifdef PANDA_COMPILER_DEBUG_INFO
48 class DwarfSectionData {
49 public:
50 using FdeInst = std::tuple<Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned>;
51 DwarfSectionData() = default;
52
AddFdeInst(Dwarf_Small op,Dwarf_Unsigned val1,Dwarf_Unsigned val2)53 void AddFdeInst(Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2)
54 {
55 fde_.emplace_back(op, val1, val2);
56 }
57
AddFdeInst(const FdeInst & fde)58 void AddFdeInst(const FdeInst &fde)
59 {
60 fde_.push_back(fde);
61 }
62
SetOffset(Dwarf_Unsigned offset)63 void SetOffset(Dwarf_Unsigned offset)
64 {
65 offset_ = offset;
66 }
67
SetSize(Dwarf_Unsigned size)68 void SetSize(Dwarf_Unsigned size)
69 {
70 size_ = size;
71 }
72
GetFde()73 const auto &GetFde() const
74 {
75 return fde_;
76 }
77
GetOffset()78 auto GetOffset() const
79 {
80 return offset_;
81 }
82
GetSize()83 auto GetSize() const
84 {
85 return size_;
86 }
87
88 private:
89 std::vector<FdeInst> fde_;
90 Dwarf_Unsigned offset_ {0};
91 Dwarf_Unsigned size_ {0};
92 };
93 #endif // PANDA_COMPILER_DEBUG_INFO
94
95 template <Arch ARCH, bool IS_JIT_MODE = false>
96 class ElfBuilder { // NOLINT(cppcoreguidelines-special-member-functions)
97 static constexpr size_t PAGE_SIZE_VALUE = 0x1000;
98 using ElfAddr = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Addr, Elf32_Addr>;
99 using ElfOff = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Off, Elf32_Off>;
100 using ElfHalf = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Half, Elf32_Half>;
101 using ElfWord = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Word, Elf32_Word>;
102 using ElfSword = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Sword, Elf32_Sword>;
103 using ElfXword = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Xword, Elf32_Xword>;
104 using ElfSxword = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Sxword, Elf32_Sxword>;
105 using ElfEhdr = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Ehdr, Elf32_Ehdr>;
106 using ElfShdr = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Shdr, Elf32_Shdr>;
107 using ElfSym = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Sym, Elf32_Sym>;
108 using ElfRel = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Rel, Elf32_Rel>;
109 using ElfRela = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Rela, Elf32_Rela>;
110 using ElfPhdr = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Phdr, Elf32_Phdr>;
111 using ElfDyn = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Dyn, Elf32_Dyn>;
112 using ElfSection = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, Elf64_Section, Elf32_Section>;
113
114 public:
115 class Section {
116 public:
117 using ElfShdrParams = std::array<ElfWord, 5U>;
118
119 // NOLINTNEXTLINE(modernize-pass-by-value)
Section(ElfBuilder & builder,const std::string & name,Section * link,const ElfShdrParams & params)120 Section(ElfBuilder &builder, const std::string &name, Section *link, const ElfShdrParams ¶ms)
121 : builder_(builder), name_(name), link_(link)
122 {
123 header_.sh_type = params[0U];
124 header_.sh_flags = params[1U];
125 header_.sh_info = params[2U];
126 header_.sh_addralign = params[3U];
127 header_.sh_entsize = params[4U];
128 }
129 virtual ~Section() = default;
130 NO_MOVE_SEMANTIC(Section);
131 NO_COPY_SEMANTIC(Section);
132
GetData()133 virtual void *GetData()
134 {
135 UNREACHABLE();
136 }
GetDataSize()137 virtual size_t GetDataSize() const
138 {
139 return header_.sh_size;
140 }
141
GetName()142 const std::string &GetName() const
143 {
144 return name_;
145 }
146
GetIndex()147 size_t GetIndex() const
148 {
149 return index_;
150 }
151
GetAddress()152 auto GetAddress() const
153 {
154 return header_.sh_addr;
155 }
156
GetOffset()157 auto GetOffset() const
158 {
159 return header_.sh_offset;
160 }
161
SetSize(size_t size)162 void SetSize(size_t size)
163 {
164 header_.sh_size = size;
165 }
166
SetDataProvider(std::unique_ptr<ElfSectionDataProvider> dataProvider)167 void SetDataProvider(std::unique_ptr<ElfSectionDataProvider> dataProvider)
168 {
169 dataProvider_ = std::move(dataProvider);
170 }
171
GetDataProvider()172 ElfSectionDataProvider *GetDataProvider() const
173 {
174 return dataProvider_.get();
175 }
176
177 private:
178 ElfBuilder &builder_;
179 std::string name_;
180 size_t index_ {std::numeric_limits<size_t>::max()};
181 ElfShdr header_ {};
182 Section *link_ {};
183 std::unique_ptr<ElfSectionDataProvider> dataProvider_ {nullptr};
184
185 friend class ElfBuilder;
186 };
187
188 class DataSection : public Section {
189 public:
190 using Section::Section;
191
192 DataSection() = default;
193 NO_COPY_SEMANTIC(DataSection);
194 NO_MOVE_SEMANTIC(DataSection);
195 ~DataSection() override = default; // NOLINT(hicpp-use-override, modernize-use-override)
196
AppendData(const void * data,size_t size)197 void AppendData(const void *data, size_t size)
198 {
199 auto pdata = reinterpret_cast<const uint8_t *>(data);
200 data_.insert(data_.end(), pdata, pdata + size); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
201 }
202
GetData()203 void *GetData() override
204 {
205 return data_.data();
206 }
207
GetVector()208 auto &GetVector()
209 {
210 return data_;
211 }
212
GetDataSize()213 size_t GetDataSize() const override
214 {
215 return this->dataProvider_ != nullptr ? this->dataProvider_->GetDataSize() : data_.size();
216 }
217
218 private:
219 std::vector<uint8_t> data_;
220 };
221
222 class SymbolSection : public Section {
223 public:
224 using ThunkFunc = std::function<ElfAddr(void)>;
225 using typename Section::ElfShdrParams;
226
227 using Section::Section;
SymbolSection(ElfBuilder & builder,const std::string & name,Section * link,const ElfShdrParams & params)228 SymbolSection(ElfBuilder &builder, const std::string &name, Section *link, const ElfShdrParams ¶ms)
229 : Section(builder, name, link, params)
230 {
231 symbols_.emplace_back(ElfSym {});
232 thunks_.emplace_back();
233 }
234
GetData()235 void *GetData() override
236 {
237 return symbols_.data();
238 }
239
GetDataSize()240 size_t GetDataSize() const override
241 {
242 return symbols_.size() * sizeof(ElfSym);
243 }
244
245 void Resolve();
246
247 private:
248 std::vector<ElfSym> symbols_;
249 std::vector<ThunkFunc> thunks_;
250
251 friend class ElfBuilder;
252 };
253
254 class StringSection : public DataSection {
255 public:
StringSection(ElfBuilder & builder,const std::string & name,ElfWord flags,ElfWord align)256 StringSection(ElfBuilder &builder, const std::string &name, ElfWord flags, ElfWord align)
257 : DataSection(builder, name, nullptr, {SHT_STRTAB, flags, 0, align, 0})
258 {
259 AddString("\0"); // NOLINT(bugprone-string-literal-with-embedded-nul)
260 }
261
AddString(const std::string & str)262 ElfWord AddString(const std::string &str)
263 {
264 auto pos = DataSection::GetDataSize();
265 DataSection::AppendData(str.data(), str.size() + 1);
266 return pos;
267 }
268 };
269
270 public:
~ElfBuilder()271 ~ElfBuilder()
272 {
273 for (auto roDataSection : roDataSections_) {
274 delete roDataSection;
275 }
276 for (auto segment : segments_) {
277 delete segment;
278 }
279 }
280
ElfBuilder()281 ElfBuilder()
282 {
283 AddSection(&hashSection_);
284 AddSection(&textSection_);
285 AddSection(&shstrtabSection_);
286 AddSection(&dynstrSection_);
287 AddSection(&dynsymSection_);
288 if constexpr (!IS_JIT_MODE) { // NOLINT
289 AddSection(&aotSection_);
290 AddSection(&gotSection_);
291 AddSection(&dynamicSection_);
292 }
293 #ifdef PANDA_COMPILER_DEBUG_INFO
294 AddSection(&frameSection_);
295 #endif
296 }
297
298 NO_MOVE_SEMANTIC(ElfBuilder);
299 NO_COPY_SEMANTIC(ElfBuilder);
300
AddSectionName(const std::string & name)301 ElfWord AddSectionName(const std::string &name)
302 {
303 return name.empty() ? 0 : shstrtabSection_.AddString(name);
304 }
305
AddSection(Section * section)306 void AddSection(Section *section)
307 {
308 sections_.push_back(section);
309 section->index_ = sections_.size() - 1;
310 }
311
312 template <bool IS_FUNCTION = false>
313 void AddSymbol(const std::string &name, ElfWord size, const Section §ion,
314 typename SymbolSection::ThunkFunc thunk);
315
GetTextSection()316 auto GetTextSection()
317 {
318 return &textSection_;
319 }
320
GetAotSection()321 auto GetAotSection()
322 {
323 return &aotSection_;
324 }
325
326 #ifdef PANDA_COMPILER_DEBUG_INFO
GetFrameSection()327 auto GetFrameSection()
328 {
329 return &frameSection_;
330 }
331
SetFrameData(std::vector<DwarfSectionData> * frameData)332 void SetFrameData(std::vector<DwarfSectionData> *frameData)
333 {
334 frameData_ = frameData;
335 }
336 void FillFrameSection();
337
SetCodeName(const std::string & methodName)338 void SetCodeName(const std::string &methodName)
339 {
340 methodName_ = methodName;
341 }
342 #endif
343
GetGotSection()344 auto GetGotSection()
345 {
346 return &gotSection_;
347 }
348
PreSizeRoDataSections(size_t newSize)349 void PreSizeRoDataSections(size_t newSize)
350 {
351 roDataSections_.reserve(newSize);
352 }
353
AddRoDataSection(const std::string & name,size_t alignment)354 void AddRoDataSection(const std::string &name, size_t alignment)
355 {
356 ASSERT(!name.empty());
357 auto section = new DataSection(*this, name, nullptr,
358 // CC-OFFNXT(G.FMT.03) project code style
359 {SHT_PROGBITS, SHF_ALLOC | SHF_MERGE, // NOLINT(hicpp-signed-bitwise)
360 0, static_cast<ElfWord>(alignment), 0});
361 AddSection(section);
362 roDataSections_.push_back(section);
363 }
364
GetRoDataSections()365 std::vector<DataSection *> *GetRoDataSections()
366 {
367 return &roDataSections_;
368 }
369
370 void Build(const std::string &fileName);
371
372 void SettleSection(Section *section);
373
374 void Write(const std::string &fileName);
375 void Write(Span<uint8_t> stream);
376
UpdateOffset(ElfWord align)377 ElfOff UpdateOffset(ElfWord align)
378 {
379 currentOffset_ = RoundUp(currentOffset_, align);
380 return currentOffset_;
381 }
382
UpdateAddress(ElfWord align)383 ElfOff UpdateAddress(ElfWord align)
384 {
385 currentAddress_ = RoundUp(currentAddress_, align);
386 return currentAddress_;
387 }
388
GetFileSize()389 size_t GetFileSize() const
390 {
391 return currentOffset_;
392 }
393
394 #ifdef PANDA_COMPILER_DEBUG_INFO
GetFrameData()395 std::vector<DwarfSectionData> *GetFrameData()
396 {
397 return frameData_;
398 }
399
GetTextSectionData()400 Span<uint8_t> GetTextSectionData() const
401 {
402 static_assert(IS_JIT_MODE);
403 return {reinterpret_cast<uint8_t *>(textSection_.header_.sh_addr), textSection_.header_.sh_size};
404 }
405
HackAddressesForJit(const uint8_t * elfData)406 void HackAddressesForJit(const uint8_t *elfData)
407 {
408 static_assert(IS_JIT_MODE);
409 ASSERT(frameData_->size() == 1U);
410 ASSERT(segments_.empty());
411 ASSERT(dynsymSection_.symbols_.size() == 2U);
412
413 for (auto section : sections_) {
414 if ((section->header_.sh_flags & SHF_ALLOC) != 0) { // NOLINT(hicpp-signed-bitwise)
415 section->header_.sh_addr += down_cast<typename ElfBuilder<ARCH, IS_JIT_MODE>::ElfAddr>(elfData);
416 }
417 }
418
419 ASSERT(dynsymSection_.symbols_[0].st_value == 0);
420 dynsymSection_.symbols_[1U].st_value +=
421 down_cast<typename ElfBuilder<ARCH, IS_JIT_MODE>::ElfAddr>(elfData) + CodeInfo::GetCodeOffset(ARCH);
422
423 // Some dark magic there. Here we patch the address of JIT code in frame debug info entry.
424 // NOTE (asidorov): rework to more readable code
425 uint8_t *cieAddr8 {static_cast<uint8_t *>(frameSection_.GetData())};
426 uint32_t *cieAddr32 {reinterpret_cast<uint32_t *>(cieAddr8)};
427 uint32_t cieLength {*cieAddr32 + static_cast<uint32_t>(sizeof(uint32_t))};
428 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
429 uint8_t *fdeInitialPcAddr8 {cieAddr8 + cieLength + 2U * sizeof(uint32_t)};
430 uintptr_t *fdeInitialPcAddrPtr {reinterpret_cast<uintptr_t *>(fdeInitialPcAddr8)};
431 *fdeInitialPcAddrPtr += down_cast<typename ElfBuilder<ARCH, IS_JIT_MODE>::ElfAddr>(elfData);
432 }
433 #endif
434
435 private:
436 void MakeHeader();
437 void AddSymbols();
438 void SettleSectionsForAot();
439 void SettleSectionsForJit();
440 void ConstructHashSection();
441 void ConstructDynamicSection(const std::string &fileName);
442
443 struct Segment {
SegmentSegment444 Segment(ElfAddr addr, ElfOff offset, ElfWord type, ElfWord flags, ElfWord align)
445 {
446 header.p_type = type;
447 header.p_flags = flags;
448 header.p_vaddr = header.p_paddr = addr;
449 header.p_align = align;
450 header.p_offset = offset;
451 }
452
453 ElfPhdr header {}; // NOLINT(misc-non-private-member-variables-in-classes)
454 };
455
456 class SegmentScope {
457 public:
458 template <typename... Args>
459 SegmentScope(ElfBuilder &builder, ElfWord type, ElfWord flags, bool first = false)
builder_(builder)460 : builder_(builder),
461 startAddress_(first ? 0 : RoundUp(builder.currentAddress_, PAGE_SIZE_VALUE)),
462 startOffset_(first ? 0 : RoundUp(builder.currentOffset_, PAGE_SIZE_VALUE))
463 {
464 auto *segment = new Segment(startAddress_, startOffset_, type, flags, PAGE_SIZE_VALUE);
465 builder_.segments_.push_back(segment);
466 builder_.currentSegment_ = segment;
467 }
~SegmentScope()468 ~SegmentScope()
469 {
470 builder_.currentSegment_->header.p_filesz = builder_.currentOffset_ - startOffset_;
471 builder_.currentSegment_->header.p_memsz = builder_.currentAddress_ - startAddress_;
472 builder_.currentSegment_ = nullptr;
473 }
474
475 NO_MOVE_SEMANTIC(SegmentScope);
476 NO_COPY_SEMANTIC(SegmentScope);
477
478 private:
479 ElfBuilder &builder_;
480 ElfAddr startAddress_;
481 ElfAddr startOffset_;
482 };
483
484 class AddrPatch {
485 using PatchFunc = std::function<ElfAddr(void)>;
486
487 public:
AddrPatch(ElfAddr * addr,PatchFunc func)488 AddrPatch(ElfAddr *addr, PatchFunc func) : address_(addr), patchFunc_(std::move(func)) {}
Patch()489 void Patch()
490 {
491 *address_ = patchFunc_();
492 }
493
494 private:
495 ElfAddr *address_;
496 PatchFunc patchFunc_;
497 };
498
499 private:
500 static constexpr size_t MAX_SEGMENTS_COUNT = 10;
501 static constexpr size_t DYNSTR_SECTION_ALIGN = 8;
502 static constexpr size_t JIT_TEXT_ALIGNMENT = ArchTraits<ARCH>::CODE_ALIGNMENT;
503 static constexpr size_t JIT_DATA_ALIGNMENT = ArchTraits<ARCH>::POINTER_SIZE;
504 static constexpr size_t JIT_DYNSTR_ALIGNMENT = 1U;
505 ElfEhdr header_ {};
506 std::vector<Section *> sections_;
507 std::vector<Segment *> segments_;
508 std::vector<AddrPatch> patches_;
509 ElfAddr currentAddress_ {0};
510 ElfOff currentOffset_ {0};
511 Segment *currentSegment_ {nullptr};
512
513 std::vector<DataSection *> roDataSections_;
514 DataSection hashSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
515 DataSection(*this, ".hash", &dynsymSection_, {SHT_HASH, SHF_ALLOC, 0, sizeof(ElfWord), sizeof(ElfWord)});
516 DataSection textSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
517 DataSection(
518 *this, ".text", nullptr,
519 {SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, IS_JIT_MODE ? JIT_TEXT_ALIGNMENT : PAGE_SIZE_VALUE, 0});
520 StringSection shstrtabSection_ = StringSection(*this, ".shstrtab", 0, 1);
521 StringSection dynstrSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
522 StringSection(*this, ".dynstr", SHF_ALLOC, IS_JIT_MODE ? JIT_DYNSTR_ALIGNMENT : DYNSTR_SECTION_ALIGN);
523 SymbolSection dynsymSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
524 SymbolSection(*this, ".dynsym", &dynstrSection_, {SHT_DYNSYM, SHF_ALLOC, 1, sizeof(ElfOff), sizeof(ElfSym)});
525 // NOLINTNEXTLINE(hicpp-signed-bitwise)
526 DataSection aotSection_ = DataSection(*this, ".aot", nullptr, {SHT_PROGBITS, SHF_ALLOC, 0, sizeof(ElfWord), 0});
527 // NOLINTNEXTLINE(hicpp-signed-bitwise)
528 DataSection gotSection_ = DataSection(*this, ".aot_got", nullptr, {SHT_PROGBITS, SHF_ALLOC, 0, PAGE_SIZE_VALUE, 0});
529 DataSection dynamicSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
530 DataSection(*this, ".dynamic", &dynstrSection_, {SHT_DYNAMIC, SHF_ALLOC, 0, PAGE_SIZE_VALUE, sizeof(ElfDyn)});
531 #ifdef PANDA_COMPILER_DEBUG_INFO
532 DataSection frameSection_ = // NOLINTNEXTLINE(hicpp-signed-bitwise)
533 DataSection(*this, ".eh_frame", nullptr,
534 {SHT_PROGBITS, SHF_ALLOC, 0, IS_JIT_MODE ? JIT_DATA_ALIGNMENT : PAGE_SIZE_VALUE, 0});
535
536 std::vector<DwarfSectionData> *frameData_ {nullptr};
537 #endif
538 std::string methodName_ = std::string("code");
539
540 friend SegmentScope;
541 };
542
543 template <Arch ARCH, bool IS_JIT_MODE>
544 template <bool IS_FUNCTION>
AddSymbol(const std::string & name,ElfWord size,const Section & section,typename SymbolSection::ThunkFunc thunk)545 void ElfBuilder<ARCH, IS_JIT_MODE>::AddSymbol(const std::string &name, ElfWord size, const Section §ion,
546 typename SymbolSection::ThunkFunc thunk)
547 {
548 uint8_t symbolType = IS_FUNCTION ? STT_FUNC : STT_OBJECT;
549 auto nameIdx = dynstrSection_.AddString(name);
550 constexpr uint8_t LOW_BITS_MASK = 0b1111;
551 auto stInfo =
552 // NOLINTNEXTLINE(hicpp-signed-bitwise)
553 static_cast<uint8_t>((STB_GLOBAL << 4U) + (symbolType & LOW_BITS_MASK));
554
555 // NOLINTNEXTLINE(readability-braces-around-statements)
556 if constexpr (ArchTraits<ARCH>::IS_64_BITS) {
557 dynsymSection_.symbols_.push_back({nameIdx, // st_name
558 stInfo, // st_info
559 0, // st_other
560 static_cast<ElfSection>(section.GetIndex()), // st_shndx
561 0, // st_value
562 size}); // st_size
563 // NOLINTNEXTLINE(readability-misleading-indentation)
564 } else {
565 dynsymSection_.symbols_.push_back({nameIdx, // st_name
566 0, // st_value
567 size, // st_size
568 stInfo, // st_info
569 0, // st_other
570 static_cast<ElfSection>(section.GetIndex())}); // st_shndx
571 }
572 dynsymSection_.thunks_.push_back(thunk);
573 }
574
575 template <Arch ARCH, bool IS_JIT_MODE>
Resolve()576 void ElfBuilder<ARCH, IS_JIT_MODE>::SymbolSection::Resolve()
577 {
578 for (auto i = 0U; i < thunks_.size(); i++) {
579 if (thunks_[i]) {
580 symbols_[i].st_value = thunks_[i]();
581 }
582 }
583 }
584
585 template <Arch ARCH, bool IS_JIT_MODE>
ConstructDynamicSection(const std::string & fileName)586 void ElfBuilder<ARCH, IS_JIT_MODE>::ConstructDynamicSection(const std::string &fileName)
587 {
588 using ElfDynDValType = decltype(ElfDyn::d_un.d_val); // NOLINT(cppcoreguidelines-pro-type-union-access)
589 auto soname = dynstrSection_.AddString(fileName);
590 auto dynstrSectionSize = dynstrSection_.GetDataSize();
591 // Make sure widening is zero-extension, if any
592 static_assert(std::is_unsigned<decltype(soname)>::value && std::is_unsigned<decltype(dynstrSectionSize)>::value);
593
594 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
595 ElfDyn dyns[] = {
596 {DT_HASH, {0}}, // will be patched
597 {DT_STRTAB, {0}}, // will be patched
598 {DT_SYMTAB, {0}}, // will be patched
599 {DT_SYMENT, {sizeof(ElfSym)}},
600 {DT_STRSZ, {static_cast<ElfDynDValType>(dynstrSectionSize)}},
601 {DT_SONAME, {static_cast<ElfDynDValType>(soname)}},
602 {DT_NULL, {0}},
603 };
604 dynamicSection_.AppendData(&dyns, sizeof(dyns));
605
606 auto firstPatchArgument = // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
607 reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamicSection_.GetData()) +
608 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
609 2U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
610 patches_.emplace_back(firstPatchArgument, [this]() { return dynsymSection_.GetAddress(); });
611
612 auto secondPatchArgument = // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
613 reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamicSection_.GetData()) +
614 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
615 1U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
616 patches_.emplace_back(secondPatchArgument, [this]() { return dynstrSection_.GetAddress(); });
617
618 auto thirdPatchArgument = // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
619 reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamicSection_.GetData()) +
620 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
621 0U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
622 patches_.emplace_back(thirdPatchArgument, [this]() { return hashSection_.GetAddress(); });
623 }
624
625 template <Arch ARCH, bool IS_JIT_MODE>
Build(const std::string & fileName)626 void ElfBuilder<ARCH, IS_JIT_MODE>::Build(const std::string &fileName)
627 {
628 shstrtabSection_.header_.sh_name = AddSectionName(shstrtabSection_.GetName());
629 for (auto section : sections_) {
630 section->header_.sh_name = AddSectionName(section->GetName());
631 if (section->link_) {
632 section->header_.sh_link = section->link_->GetIndex();
633 }
634 }
635
636 AddSymbols();
637
638 ConstructHashSection();
639
640 if constexpr (!IS_JIT_MODE) { // NOLINT
641 ConstructDynamicSection(fileName);
642 }
643
644 if constexpr (IS_JIT_MODE) { // NOLINT
645 SettleSectionsForJit();
646 } else { // NOLINT
647 SettleSectionsForAot();
648 }
649
650 MakeHeader();
651
652 dynsymSection_.Resolve();
653 std::for_each(patches_.begin(), patches_.end(), [](auto &patch) { patch.Patch(); });
654 }
655
656 template <Arch ARCH, bool IS_JIT_MODE>
ConstructHashSection()657 void ElfBuilder<ARCH, IS_JIT_MODE>::ConstructHashSection()
658 {
659 ElfWord value = 1;
660 auto symCount = dynsymSection_.GetDataSize() / sizeof(ElfSym);
661 hashSection_.AppendData(&value, sizeof(value));
662 hashSection_.AppendData(&symCount, sizeof(value));
663 hashSection_.AppendData(&value, sizeof(value));
664 value = 0;
665 hashSection_.AppendData(&value, sizeof(value));
666 for (auto i = 2U; i < symCount; i++) {
667 hashSection_.AppendData(&i, sizeof(value));
668 }
669 value = 0;
670 hashSection_.AppendData(&value, sizeof(value));
671 }
672
673 template <Arch ARCH, bool IS_JIT_MODE>
MakeHeader()674 void ElfBuilder<ARCH, IS_JIT_MODE>::MakeHeader()
675 {
676 header_.e_ident[EI_MAG0] = ELFMAG0;
677 header_.e_ident[EI_MAG1] = ELFMAG1;
678 header_.e_ident[EI_MAG2] = ELFMAG2;
679 header_.e_ident[EI_MAG3] = ELFMAG3;
680 header_.e_ident[EI_CLASS] = ArchTraits<ARCH>::IS_64_BITS ? ELFCLASS64 : ELFCLASS32;
681 header_.e_ident[EI_DATA] = ELFDATA2LSB;
682 header_.e_ident[EI_VERSION] = EV_CURRENT;
683 header_.e_ident[EI_OSABI] = ELFOSABI_LINUX;
684 header_.e_ident[EI_ABIVERSION] = 0;
685 std::fill_n(&header_.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
686 header_.e_type = ET_DYN;
687 header_.e_version = 1;
688 switch (ARCH) {
689 case Arch::AARCH32:
690 header_.e_machine = EM_ARM;
691 header_.e_flags = EF_ARM_EABI_VER5;
692 break;
693 case Arch::AARCH64:
694 header_.e_machine = EM_AARCH64;
695 header_.e_flags = 0;
696 break;
697 case Arch::X86:
698 header_.e_machine = EM_386;
699 header_.e_flags = 0;
700 break;
701 case Arch::X86_64:
702 header_.e_machine = EM_X86_64;
703 header_.e_flags = 0;
704 break;
705 default:
706 UNREACHABLE();
707 }
708 header_.e_entry = 0;
709 header_.e_ehsize = sizeof(ElfEhdr);
710 header_.e_phentsize = sizeof(ElfPhdr);
711 header_.e_shentsize = sizeof(ElfShdr);
712 header_.e_shstrndx = shstrtabSection_.GetIndex();
713 currentOffset_ = RoundUp(currentOffset_, alignof(ElfShdr));
714 header_.e_shoff = UpdateOffset(alignof(ElfShdr));
715 currentOffset_ += sections_.size() * sizeof(ElfShdr);
716 header_.e_phoff = IS_JIT_MODE ? 0U : sizeof(ElfEhdr);
717 header_.e_shnum = sections_.size();
718 header_.e_phnum = IS_JIT_MODE ? 0U : segments_.size();
719 }
720
721 template <Arch ARCH, bool IS_JIT_MODE>
AddSymbols()722 void ElfBuilder<ARCH, IS_JIT_MODE>::AddSymbols()
723 {
724 AddSymbol(methodName_, textSection_.GetDataSize(), textSection_, [this]() { return textSection_.GetAddress(); });
725 if constexpr (!IS_JIT_MODE) { // NOLINT
726 AddSymbol("code_end", textSection_.GetDataSize(), textSection_,
727 [this]() { return textSection_.GetAddress() + textSection_.GetDataSize(); });
728 AddSymbol("aot", aotSection_.GetDataSize(), aotSection_, [this]() { return aotSection_.GetAddress(); });
729 AddSymbol("aot_end", aotSection_.GetDataSize(), aotSection_,
730 [this]() { return aotSection_.GetAddress() + aotSection_.GetDataSize(); });
731 }
732 }
733
734 template <Arch ARCH, bool IS_JIT_MODE>
SettleSectionsForAot()735 void ElfBuilder<ARCH, IS_JIT_MODE>::SettleSectionsForAot()
736 {
737 static_assert(!IS_JIT_MODE);
738
739 // NOLINTNEXTLINE(hicpp-signed-bitwise)
740 auto phdrSegment = new Segment(sizeof(ElfEhdr), sizeof(ElfEhdr), PT_PHDR, PF_R, sizeof(ElfOff));
741 segments_.push_back(phdrSegment);
742
743 {
744 SegmentScope segmentScope(*this, PT_LOAD, PF_R, true); // NOLINT(hicpp-signed-bitwise)
745 currentAddress_ = sizeof(ElfEhdr) + sizeof(ElfPhdr) * MAX_SEGMENTS_COUNT;
746 currentOffset_ = sizeof(ElfEhdr) + sizeof(ElfPhdr) * MAX_SEGMENTS_COUNT;
747 SettleSection(&dynstrSection_);
748 SettleSection(&dynsymSection_);
749 SettleSection(&hashSection_);
750 SettleSection(&aotSection_);
751 for (auto roDataSection : roDataSections_) {
752 ASSERT(roDataSection->GetDataSize() > 0);
753 SettleSection(roDataSection);
754 }
755 }
756
757 {
758 SegmentScope segmentScope(*this, PT_LOAD, PF_R | PF_W); // NOLINT(hicpp-signed-bitwise)
759 SettleSection(&gotSection_);
760 }
761
762 {
763 SegmentScope segmentScope(*this, PT_LOAD, PF_R | PF_X); // NOLINT(hicpp-signed-bitwise)
764 SettleSection(&textSection_);
765 }
766
767 #ifdef PANDA_COMPILER_DEBUG_INFO
768 if (!frameData_->empty()) {
769 SegmentScope segmentScope(*this, PT_LOAD, PF_R); // NOLINT(hicpp-signed-bitwise)
770 FillFrameSection();
771 SettleSection(&frameSection_);
772 }
773 #endif
774
775 {
776 SegmentScope segmentScope(*this, PT_DYNAMIC, PF_R | PF_W); // NOLINT(hicpp-signed-bitwise)
777 SettleSection(&dynamicSection_);
778 }
779
780 SettleSection(&shstrtabSection_);
781
782 auto lodDynamicSegment = new Segment(*segments_.back());
783 ASSERT(lodDynamicSegment->header.p_type == PT_DYNAMIC);
784 lodDynamicSegment->header.p_type = PT_LOAD;
785 segments_.insert(segments_.end() - 1, lodDynamicSegment);
786
787 ASSERT(segments_.size() <= MAX_SEGMENTS_COUNT);
788 phdrSegment->header.p_filesz = phdrSegment->header.p_memsz = segments_.size() * sizeof(ElfPhdr);
789 }
790
791 template <Arch ARCH, bool IS_JIT_MODE>
SettleSectionsForJit()792 void ElfBuilder<ARCH, IS_JIT_MODE>::SettleSectionsForJit()
793 {
794 static_assert(IS_JIT_MODE);
795
796 currentAddress_ = sizeof(ElfEhdr);
797 currentOffset_ = sizeof(ElfEhdr);
798
799 SettleSection(&textSection_);
800 #ifdef PANDA_COMPILER_DEBUG_INFO
801 if (!frameData_->empty()) {
802 FillFrameSection();
803 SettleSection(&frameSection_);
804 }
805 #endif
806 SettleSection(&dynsymSection_);
807 SettleSection(&hashSection_);
808 SettleSection(&dynstrSection_);
809 SettleSection(&shstrtabSection_);
810 }
811
812 template <Arch ARCH, bool IS_JIT_MODE>
SettleSection(Section * section)813 void ElfBuilder<ARCH, IS_JIT_MODE>::SettleSection(Section *section)
814 {
815 bool isSectionAlloc {(section->header_.sh_flags & SHF_ALLOC) != 0}; // NOLINT(hicpp-signed-bitwise)
816 if (IS_JIT_MODE || !isSectionAlloc) {
817 ASSERT(currentSegment_ == nullptr);
818 } else {
819 ASSERT(currentSegment_ != nullptr && currentSegment_->header.p_type != PT_NULL);
820 }
821
822 section->header_.sh_size = section->GetDataSize();
823 if (isSectionAlloc) {
824 section->header_.sh_addr = UpdateAddress(section->header_.sh_addralign);
825 if (section->header_.sh_type != SHT_NOBITS) {
826 ASSERT(section->GetDataSize() != 0 || section->header_.sh_type == SHT_PROGBITS);
827 section->header_.sh_offset = UpdateOffset(section->header_.sh_addralign);
828 currentOffset_ += section->header_.sh_size;
829 } else {
830 section->header_.sh_offset = 0;
831 }
832 currentAddress_ += section->header_.sh_size;
833 } else {
834 section->header_.sh_offset = RoundUp(currentOffset_, section->header_.sh_addralign);
835 currentOffset_ += section->header_.sh_size;
836 }
837 }
838
839 template <Arch ARCH, bool IS_JIT_MODE>
Write(const std::string & fileName)840 void ElfBuilder<ARCH, IS_JIT_MODE>::Write(const std::string &fileName)
841 {
842 std::vector<uint8_t> data(GetFileSize());
843 auto dataSpan {Span(data)};
844 Write(dataSpan);
845
846 std::ofstream elfFile(fileName, std::ios::binary);
847 elfFile.write(reinterpret_cast<char *>(dataSpan.Data()), dataSpan.Size());
848 }
849
CopyToSpan(Span<uint8_t> to,const char * from,size_t size,size_t beginIndex)850 inline void CopyToSpan(Span<uint8_t> to, const char *from, size_t size, size_t beginIndex)
851 {
852 ASSERT(beginIndex < to.Size());
853 auto maxSize {to.Size() - beginIndex};
854 errno_t res = memcpy_s(&to[beginIndex], maxSize, from, size);
855 if (res != 0) {
856 UNREACHABLE();
857 }
858 }
859
860 template <Arch ARCH, bool IS_JIT_MODE>
Write(Span<uint8_t> stream)861 void ElfBuilder<ARCH, IS_JIT_MODE>::Write(Span<uint8_t> stream)
862 {
863 ASSERT(!stream.Empty());
864 char *header = reinterpret_cast<char *>(&header_);
865 CopyToSpan(stream, header, sizeof(header_), 0);
866 for (auto section : sections_) {
867 if (auto dataProvider = section->GetDataProvider(); dataProvider != nullptr) {
868 auto i = section->header_.sh_offset;
869 dataProvider->FillData(stream, i);
870 } else if (section->GetDataSize() && section->header_.sh_type != SHT_NOBITS) {
871 auto i = section->header_.sh_offset;
872 const char *data = reinterpret_cast<const char *>(section->GetData());
873 CopyToSpan(stream, data, section->GetDataSize(), i);
874 }
875 }
876
877 auto i = header_.e_shoff;
878 for (auto section : sections_) {
879 const char *data = reinterpret_cast<const char *>(§ion->header_);
880 CopyToSpan(stream, data, sizeof(section->header_), i);
881 i += sizeof(section->header_);
882 }
883
884 i = header_.e_phoff;
885 for (auto segment : segments_) {
886 const char *data = reinterpret_cast<const char *>(&segment->header);
887 CopyToSpan(stream, data, sizeof(segment->header), i);
888 i += sizeof(segment->header);
889 }
890 }
891
892 #ifdef PANDA_COMPILER_DEBUG_INFO
893 template <Arch ARCH>
894 class CfiGenerator {
895 public:
CfiGenerator(Span<DwarfSectionData> frameData)896 explicit CfiGenerator(Span<DwarfSectionData> frameData) : frameData_(frameData) {}
897
GenerateDebugInfo()898 void GenerateDebugInfo()
899 {
900 if (!debugInfo_.empty() || frameData_.empty()) {
901 return;
902 }
903
904 auto dw {Initialize()};
905 auto cie {CreateCie(dw)};
906
907 for (const auto &data : frameData_) {
908 AddFde(dw, cie, data);
909 }
910
911 Finalize(dw);
912 }
913
GetDebugInfo()914 Span<const uint8_t> GetDebugInfo() const
915 {
916 return Span(debugInfo_);
917 }
918
919 private:
920 enum DwarfSection {
921 REL_DEBUG_FRAME = 0,
922 DEBUG_FRAME = 1,
923 };
924
CreateSectionCallback(char * name,int size,Dwarf_Unsigned type,Dwarf_Unsigned flags,Dwarf_Unsigned link,Dwarf_Unsigned info,Dwarf_Unsigned * sectNameIndex,void * userData,int * error)925 static inline int CreateSectionCallback(char *name, [[maybe_unused]] int size, [[maybe_unused]] Dwarf_Unsigned type,
926 [[maybe_unused]] Dwarf_Unsigned flags, [[maybe_unused]] Dwarf_Unsigned link,
927 [[maybe_unused]] Dwarf_Unsigned info,
928 [[maybe_unused]] Dwarf_Unsigned *sectNameIndex,
929 [[maybe_unused]] void *userData, [[maybe_unused]] int *error)
930 {
931 if (strcmp(name, ".rel.debug_frame") == 0) {
932 return DwarfSection::REL_DEBUG_FRAME;
933 }
934 if (strcmp(name, ".debug_frame") == 0) {
935 return DwarfSection::DEBUG_FRAME;
936 }
937 UNREACHABLE();
938 }
939
Initialize()940 Dwarf_P_Debug Initialize() const
941 {
942 Dwarf_P_Debug dw {nullptr};
943 Dwarf_Error error {nullptr};
944 [[maybe_unused]] auto ret = // NOLINTNEXTLINE(hicpp-signed-bitwise)
945 dwarf_producer_init(DW_DLC_WRITE | DW_DLC_SIZE_64 | DW_DLC_SYMBOLIC_RELOCATIONS,
946 reinterpret_cast<Dwarf_Callback_Func>(CreateSectionCallback), nullptr, nullptr, nullptr,
947 GetIsaName(ARCH), "V2", nullptr, &dw, &error);
948
949 ASSERT(error == DW_DLV_OK);
950 return dw;
951 }
952
GetCieInitInstructions()953 Span<Dwarf_Small> GetCieInitInstructions() const
954 {
955 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
956 static Dwarf_Small cieInitInstructionsArm[] = {
957 DW_CFA_def_cfa,
958 GetDwarfSP(ARCH),
959 0U,
960 };
961
962 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
963 static Dwarf_Small cieInitInstructionsAmd64[] = {
964 // NOLINTNEXTLINE(hicpp-signed-bitwise)
965 DW_CFA_def_cfa, GetDwarfSP(ARCH), PointerSize(ARCH), DW_CFA_offset | GetDwarfRIP(ARCH), 1U,
966 };
967
968 if (ARCH == Arch::AARCH32 || ARCH == Arch::AARCH64) {
969 return Span(cieInitInstructionsArm, std::size(cieInitInstructionsArm));
970 }
971 if (ARCH == Arch::X86_64) {
972 return Span(cieInitInstructionsAmd64, std::size(cieInitInstructionsAmd64));
973 }
974 UNREACHABLE();
975 }
976
CreateCie(Dwarf_P_Debug dw)977 Dwarf_Unsigned CreateCie(Dwarf_P_Debug dw) const
978 {
979 Dwarf_Error error {nullptr};
980 auto cieInitInstructions {GetCieInitInstructions()};
981 Dwarf_Unsigned cie =
982 dwarf_add_frame_cie(dw, const_cast<char *>(""), static_cast<Dwarf_Small>(GetInstructionAlignment(ARCH)),
983 static_cast<Dwarf_Small>(-PointerSize(ARCH)), GetDwarfRIP(ARCH),
984 cieInitInstructions.data(), cieInitInstructions.SizeBytes(), &error);
985 ASSERT(error == DW_DLV_OK);
986 return cie;
987 }
988
AddFde(Dwarf_P_Debug dw,Dwarf_Unsigned cie,const DwarfSectionData & data)989 void AddFde(Dwarf_P_Debug dw, Dwarf_Unsigned cie, const DwarfSectionData &data) const
990 {
991 Dwarf_Error error {nullptr};
992 Dwarf_P_Fde fde = dwarf_new_fde(dw, &error);
993 ASSERT(error == DW_DLV_OK);
994 for (const auto &inst : data.GetFde()) {
995 auto [op, par1, par2] = inst;
996 dwarf_add_fde_inst(fde, op, par1, par2, &error);
997 ASSERT(error == DW_DLV_OK);
998 }
999
1000 dwarf_add_frame_fde(dw, fde, nullptr, cie, data.GetOffset(), data.GetSize(), DwarfSection::DEBUG_FRAME, &error);
1001 ASSERT(error == DW_DLV_OK);
1002 }
1003
Finalize(Dwarf_P_Debug dw)1004 void Finalize(Dwarf_P_Debug dw)
1005 {
1006 Dwarf_Error error {nullptr};
1007 auto sections = dwarf_transform_to_disk_form(dw, &error);
1008 ASSERT(error == DW_DLV_OK);
1009
1010 ASSERT(debugInfo_.empty());
1011 for (decltype(sections) i {0}; i < sections; ++i) {
1012 Dwarf_Unsigned len = 0;
1013 Dwarf_Signed elfIdx = 0;
1014 auto bytes = reinterpret_cast<const uint8_t *>(
1015 dwarf_get_section_bytes(dw, DwarfSection::DEBUG_FRAME, &elfIdx, &len, &error));
1016 ASSERT(error == DW_DLV_OK);
1017
1018 std::copy_n(bytes, len, std::back_inserter(debugInfo_));
1019 }
1020
1021 constexpr size_t TERMINATOR_SIZE {4U};
1022 constexpr uint8_t TERMINATOR_VALUE {0U};
1023 std::fill_n(std::back_inserter(debugInfo_), TERMINATOR_SIZE, TERMINATOR_VALUE);
1024
1025 dwarf_producer_finish(dw, &error);
1026 ASSERT(error == DW_DLV_OK);
1027
1028 constexpr size_t CIE_ID_OFFSET {4U};
1029 // zero out CIE ID field
1030 *reinterpret_cast<uint32_t *>(&debugInfo_[CIE_ID_OFFSET]) = 0;
1031
1032 constexpr size_t FDE_CIE_DISTANCE_OFFSET {4U};
1033 constexpr size_t FDE_LENGTH_SIZE {4U};
1034 size_t base {0};
1035 for (size_t i {0}; i < frameData_.size(); ++i) {
1036 // read FDE length field + 4 bytes (size of length field), get next FDE
1037 size_t fdeOffset {base + *reinterpret_cast<uint32_t *>(&debugInfo_[base]) + FDE_LENGTH_SIZE};
1038 // set distance to the parent CIE in FDE
1039 ASSERT(debugInfo_.size() > fdeOffset + FDE_CIE_DISTANCE_OFFSET + 3U);
1040 *reinterpret_cast<uint32_t *>(&debugInfo_[fdeOffset + FDE_CIE_DISTANCE_OFFSET]) =
1041 fdeOffset + FDE_CIE_DISTANCE_OFFSET;
1042 base = fdeOffset;
1043 ASSERT(debugInfo_.size() > base);
1044 }
1045 }
1046
1047 Span<DwarfSectionData> frameData_;
1048 std::vector<uint8_t> debugInfo_;
1049 };
1050
1051 template <Arch ARCH, bool IS_JIT_MODE>
FillFrameSection()1052 void ElfBuilder<ARCH, IS_JIT_MODE>::FillFrameSection()
1053 {
1054 // compute code offset for method
1055 for (auto &data : *frameData_) {
1056 data.SetOffset(textSection_.header_.sh_offset + data.GetOffset() + CodeInfo::GetCodeOffset(ARCH));
1057 }
1058
1059 CfiGenerator<ARCH> cfiGen {Span(*frameData_)};
1060 cfiGen.GenerateDebugInfo();
1061 auto debugInfo {cfiGen.GetDebugInfo()};
1062
1063 // Generate frame data
1064 GetFrameSection()->AppendData(debugInfo.data(), debugInfo.size());
1065 }
1066 #endif // #ifdef PANDA_COMPILER_DEBUG_INFO
1067
1068 class ElfWriter {
1069 public:
SetArch(Arch arch)1070 void SetArch(Arch arch)
1071 {
1072 arch_ = arch;
1073 }
GetArch()1074 Arch GetArch() const
1075 {
1076 return arch_;
1077 }
1078
SetRuntime(RuntimeInterface * runtime)1079 void SetRuntime(RuntimeInterface *runtime)
1080 {
1081 runtime_ = runtime;
1082 }
1083
GetRuntime()1084 RuntimeInterface *GetRuntime()
1085 {
1086 return runtime_;
1087 }
1088
GetCurrentCodeAddress()1089 uintptr_t GetCurrentCodeAddress() const
1090 {
1091 return currentCodeSize_;
1092 }
1093
StartClass(const Class & klass)1094 void StartClass(const Class &klass)
1095 {
1096 ClassHeader *classHeader = &classHeaders_.emplace_back();
1097 currentBitmap_ = &classMethodsBitmaps_.emplace_back();
1098 classHeader->classId = klass.GetFileId().GetOffset();
1099 classHeader->methodsOffset = methodHeaders_.size();
1100 currentBitmap_->resize(klass.GetMethods().size());
1101 }
1102
EndClass()1103 void EndClass()
1104 {
1105 ASSERT(!classHeaders_.empty());
1106 auto &classHeader = classHeaders_.back();
1107 classHeader.methodsCount = methodHeaders_.size() - classHeader.methodsOffset;
1108 if (classHeader.methodsCount != 0) {
1109 ASSERT(IsAligned<sizeof(uint32_t)>(currentBitmap_->GetContainerSizeInBytes()));
1110 classHeader.methodsBitmapOffset = bitmapSize_;
1111 classHeader.methodsBitmapSize = currentBitmap_->size();
1112 bitmapSize_ += currentBitmap_->GetContainerSize();
1113 } else {
1114 CHECK_EQ(classMethodsBitmaps_.size(), classHeaders_.size());
1115 classHeaders_.pop_back();
1116 classMethodsBitmaps_.pop_back();
1117 }
1118 }
1119
AddMethod(const CompiledMethod & method)1120 void AddMethod(const CompiledMethod &method)
1121 {
1122 if (method.GetMethod() == nullptr || method.GetCode().Empty()) {
1123 return;
1124 }
1125 methods_.push_back(method);
1126 auto &methodHeader = methodHeaders_.emplace_back();
1127 methodHeader.methodId = method.GetMethod()->GetFileId().GetOffset();
1128 methodHeader.codeOffset = currentCodeSize_;
1129 methodHeader.codeSize = method.GetOverallSize();
1130 currentCodeSize_ += methodHeader.codeSize;
1131 currentCodeSize_ = RoundUp(currentCodeSize_, GetCodeAlignment(arch_));
1132 currentBitmap_->SetBit(method.GetIndex());
1133
1134 #ifdef PANDA_COMPILER_DEBUG_INFO
1135 if (GetEmitDebugInfo()) {
1136 FillDebugInfo(method.GetCfiInfo(), methodHeader);
1137 }
1138 #endif
1139 }
1140
SetClassContext(const std::string & ctx)1141 void SetClassContext(const std::string &ctx)
1142 {
1143 classCtx_ = ctx;
1144 }
1145
1146 #ifdef PANDA_COMPILER_DEBUG_INFO
SetEmitDebugInfo(bool emitDebugInfo)1147 void SetEmitDebugInfo([[maybe_unused]] bool emitDebugInfo)
1148 {
1149 emitDebugInfo_ = emitDebugInfo;
1150 }
1151
GetEmitDebugInfo()1152 bool GetEmitDebugInfo() const
1153 {
1154 return emitDebugInfo_;
1155 }
1156 #endif
1157
AddString(const std::string & str)1158 size_t AddString(const std::string &str)
1159 {
1160 auto pos = stringTable_.size();
1161 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1162 stringTable_.insert(stringTable_.end(), str.data(), str.data() + str.size() + 1);
1163 return pos;
1164 }
1165
1166 template <Arch ARCH, bool IS_JIT_MODE>
1167 void GenerateSymbols(ElfBuilder<ARCH, IS_JIT_MODE> &builder);
1168
1169 #ifdef PANDA_COMPILER_DEBUG_INFO
1170 inline void PrepareOffsetsForDwarf(CfiOffsets *offsets) const;
1171
1172 inline void FillPrologueInfo(DwarfSectionData *sectData, const CfiOffsets &cfiOffsets) const;
1173
1174 inline void FillCalleesInfo(DwarfSectionData *sectData, const CfiInfo &cfiInfo) const;
1175
1176 inline void FillEpilogInfo(DwarfSectionData *sectData, const CfiOffsets &cfiOffsets) const;
1177
1178 inline void FillDebugInfo(CfiInfo cfiInfo, const compiler::MethodHeader &methodHeader);
1179
AddFrameData(const DwarfSectionData & data)1180 void AddFrameData(const DwarfSectionData &data)
1181 {
1182 frameData_.push_back(data);
1183 }
1184
GetFrameData()1185 std::vector<DwarfSectionData> *GetFrameData()
1186 {
1187 return &frameData_;
1188 }
1189
1190 #endif
1191 protected:
1192 std::vector<CompiledMethod> methods_; // NOLINT(misc-non-private-member-variables-in-classes)
1193 std::vector<compiler::MethodHeader> methodHeaders_; // NOLINT(misc-non-private-member-variables-in-classes)
1194 Arch arch_ {Arch::NONE}; // NOLINT(misc-non-private-member-variables-in-classes)
1195 std::vector<char> stringTable_; // NOLINT(misc-non-private-member-variables-in-classes)
1196 BitVector<> *currentBitmap_ {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes)
1197 size_t currentCodeSize_ {0}; // NOLINT(misc-non-private-member-variables-in-classes)
1198
1199 private:
1200 std::string classCtx_;
1201
1202 std::vector<compiler::PandaFileHeader> fileHeaders_;
1203 std::vector<compiler::ClassHeader> classHeaders_;
1204
1205 uint32_t gcType_ {static_cast<uint32_t>(mem::GCType::INVALID_GC)};
1206
1207 std::vector<BitVector<>> classMethodsBitmaps_;
1208 static_assert(sizeof(BitVector<>::container_value_type) == sizeof(uint32_t));
1209 uint32_t bitmapSize_ {0};
1210
1211 RuntimeInterface *runtime_ {nullptr};
1212 #ifdef PANDA_COMPILER_DEBUG_INFO
1213 std::vector<DwarfSectionData> frameData_;
1214 bool emitDebugInfo_ {false};
1215 #endif
1216
1217 friend class CodeDataProvider;
1218 friend class JitCodeDataProvider;
1219 friend class AotBuilder;
1220 friend class JitDebugWriter;
1221 };
1222
1223 #ifdef PANDA_COMPILER_DEBUG_INFO
1224 static constexpr size_t LR_CFA_OFFSET {1U};
1225 static constexpr size_t FP_CFA_OFFSET {2U};
1226 static constexpr size_t DWARF_ARM_FP_REGS_START {64U};
1227
PrepareOffsetsForDwarf(CfiOffsets * offsets)1228 void ElfWriter::PrepareOffsetsForDwarf(CfiOffsets *offsets) const
1229 {
1230 // Make relative offsets
1231 offsets->popFplr -= offsets->popCallees;
1232 offsets->popCallees -= offsets->pushCallees;
1233 offsets->pushCallees -= offsets->setFp;
1234 offsets->setFp -= offsets->pushFplr;
1235
1236 // Make offsets in alignment units
1237 auto instAlignment {GetInstructionAlignment(arch_)};
1238
1239 offsets->pushFplr /= instAlignment;
1240 offsets->setFp /= instAlignment;
1241 offsets->pushCallees /= instAlignment;
1242 offsets->popCallees /= instAlignment;
1243 offsets->popFplr /= instAlignment;
1244 }
1245
FillPrologueInfo(DwarfSectionData * sectData,const CfiOffsets & cfiOffsets)1246 void ElfWriter::FillPrologueInfo(DwarfSectionData *sectData, const CfiOffsets &cfiOffsets) const
1247 {
1248 sectData->AddFdeInst(DW_CFA_advance_loc, cfiOffsets.pushFplr, 0);
1249 sectData->AddFdeInst(DW_CFA_def_cfa_offset, FP_CFA_OFFSET * PointerSize(arch_), 0);
1250 if (arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64) {
1251 sectData->AddFdeInst(DW_CFA_offset, GetDwarfLR(arch_), LR_CFA_OFFSET);
1252 }
1253 sectData->AddFdeInst(DW_CFA_offset, GetDwarfFP(arch_), FP_CFA_OFFSET);
1254
1255 sectData->AddFdeInst(DW_CFA_advance_loc, cfiOffsets.setFp, 0);
1256 sectData->AddFdeInst(DW_CFA_def_cfa_register, GetDwarfFP(arch_), 0);
1257 }
1258
FillCalleesInfo(DwarfSectionData * sectData,const CfiInfo & cfiInfo)1259 void ElfWriter::FillCalleesInfo(DwarfSectionData *sectData, const CfiInfo &cfiInfo) const
1260 {
1261 const auto &cfiOffsets {cfiInfo.offsets};
1262
1263 sectData->AddFdeInst(DW_CFA_advance_loc, cfiOffsets.pushCallees, 0);
1264
1265 const auto &callees {cfiInfo.calleeRegs};
1266 size_t calleeSlot {0};
1267 for (size_t i {0}; i < callees.size(); ++i) {
1268 auto reg {(callees.size() - 1U) - i};
1269 if (callees.test(reg)) {
1270 #ifdef PANDA_COMPILER_TARGET_X86_64
1271 if (arch_ == Arch::X86_64) {
1272 reg = amd64::ConvertRegNumber(reg);
1273 }
1274 #endif
1275 sectData->AddFdeInst(DW_CFA_offset, reg,
1276 FP_CFA_OFFSET + CFrameLayout::CALLEE_REGS_START_SLOT + calleeSlot++);
1277 }
1278 }
1279
1280 const auto &vcallees {cfiInfo.calleeVregs};
1281 for (size_t i {0}; i < vcallees.size(); ++i) {
1282 auto vreg {(vcallees.size() - 1) - i};
1283 if (vcallees.test(vreg)) {
1284 ASSERT(arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64);
1285 sectData->AddFdeInst(DW_CFA_offset, DWARF_ARM_FP_REGS_START + vreg,
1286 FP_CFA_OFFSET + CFrameLayout::CALLEE_REGS_START_SLOT + calleeSlot++);
1287 }
1288 }
1289
1290 sectData->AddFdeInst(DW_CFA_advance_loc, cfiOffsets.popCallees, 0);
1291 for (size_t i {0}; i < callees.size(); ++i) {
1292 auto reg {(callees.size() - 1U) - i};
1293 if (callees.test(reg)) {
1294 #ifdef PANDA_COMPILER_TARGET_X86_64
1295 if (arch_ == Arch::X86_64) {
1296 reg = amd64::ConvertRegNumber(reg);
1297 }
1298 #endif
1299 sectData->AddFdeInst(DW_CFA_same_value, reg, 0);
1300 }
1301 }
1302
1303 for (size_t i {0}; i < vcallees.size(); ++i) {
1304 auto vreg {(vcallees.size() - 1) - i};
1305 if (vcallees.test(vreg)) {
1306 ASSERT(arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64);
1307 sectData->AddFdeInst(DW_CFA_same_value, DWARF_ARM_FP_REGS_START + vreg, 0);
1308 }
1309 }
1310 }
1311
FillEpilogInfo(DwarfSectionData * sectData,const CfiOffsets & cfiOffsets)1312 void ElfWriter::FillEpilogInfo(DwarfSectionData *sectData, const CfiOffsets &cfiOffsets) const
1313 {
1314 sectData->AddFdeInst(DW_CFA_advance_loc, cfiOffsets.popFplr, 0);
1315 sectData->AddFdeInst(DW_CFA_same_value, GetDwarfFP(arch_), 0);
1316 if (arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64) {
1317 sectData->AddFdeInst(DW_CFA_same_value, GetDwarfLR(arch_), 0);
1318 sectData->AddFdeInst(DW_CFA_def_cfa, GetDwarfSP(arch_), 0);
1319 } else if (arch_ == Arch::X86_64) {
1320 sectData->AddFdeInst(DW_CFA_def_cfa, GetDwarfSP(arch_), 1U * PointerSize(arch_));
1321 } else {
1322 UNREACHABLE();
1323 }
1324 }
1325
FillDebugInfo(CfiInfo cfiInfo,const compiler::MethodHeader & methodHeader)1326 void ElfWriter::FillDebugInfo(CfiInfo cfiInfo, const compiler::MethodHeader &methodHeader)
1327 {
1328 DwarfSectionData sectData;
1329 // Will be patched later
1330 sectData.SetOffset(methodHeader.codeOffset);
1331 sectData.SetSize(methodHeader.codeSize);
1332
1333 auto &cfiOffsets {cfiInfo.offsets};
1334 PrepareOffsetsForDwarf(&cfiOffsets);
1335
1336 FillPrologueInfo(§Data, cfiOffsets);
1337 FillCalleesInfo(§Data, cfiInfo);
1338 FillEpilogInfo(§Data, cfiOffsets);
1339
1340 AddFrameData(sectData);
1341 }
1342 #endif
1343
1344 } // namespace ark::compiler
1345
1346 #endif // COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
1347