• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &section,
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 &section,
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 *>(&section->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(&sectData, cfiOffsets);
1334     FillCalleesInfo(&sectData, cfiInfo);
1335     FillEpilogInfo(&sectData, cfiOffsets);
1336 
1337     AddFrameData(sectData);
1338 }
1339 #endif
1340 
1341 }  // namespace ark::compiler
1342 
1343 #endif  // COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
1344