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