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