• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "ecmascript/compiler/aot_file/elf_builder.h"
17 
18 #include "ecmascript/ecma_macros.h"
19 #include "securec.h"
20 
21 namespace panda::ecmascript {
AddShStrTabSection()22 void ElfBuilder::AddShStrTabSection()
23 {
24     std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections =
25         des_[ShStrTableModuleDesIndex].GetSectionsInfo();
26 
27     uint32_t size = 1;
28     for (auto &s : sections_) {
29         std::string str = ModuleSectionDes::GetSecName(s);
30         size = size + str.size() + 1;
31     }
32 
33     shStrTabPtr_ = std::make_unique<char []>(size);
34     char *dst = shStrTabPtr_.get();
35     dst[0] = 0x0;
36     uint32_t i = 1;
37     for (auto &s: sections_) {
38         std::string str = ModuleSectionDes::GetSecName(s);
39         uint32_t copySize = str.size();
40         if (copySize == 0) {
41             UNREACHABLE();
42         }
43         if ((copySize != 0) && ((memcpy_s(dst + i, size - i + 1, str.data(), copySize)) != EOK)) {
44             UNREACHABLE();
45         }
46         dst[i + copySize] = 0x0;
47         i = i + copySize + 1;
48     }
49     if (sections.find(ElfSecName::SHSTRTAB) != sections.end()) {
50         sections.erase(ElfSecName::SHSTRTAB);
51     }
52     sections[ElfSecName::SHSTRTAB] = std::make_pair(reinterpret_cast<uint64_t>(shStrTabPtr_.get()), size);
53     if (enableSecDump_) {
54         DumpSection();
55     }
56 }
57 
DumpSection() const58 void ElfBuilder::DumpSection() const
59 {
60     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
61     // dump
62     for (auto &s : sections) {
63         ElfSection section = ElfSection(s.first);
64         if (!section.ShouldDumpToAOTFile()) {
65             continue;
66         }
67         LOG_COMPILER(INFO) << "secname :" << std::dec << static_cast<int>(s.first)
68             << " addr:0x" << std::hex << s.second.first << " size:0x" << s.second.second << std::endl;
69     }
70 }
71 
ElfBuilder(const std::vector<ModuleSectionDes> & des,const std::vector<ElfSecName> & sections)72 ElfBuilder::ElfBuilder(const std::vector<ModuleSectionDes> &des,
73                        const std::vector<ElfSecName> &sections): des_(des), sections_(sections)
74 {
75     Initialize();
76     AddShStrTabSection();
77     RemoveNotNeedSection();
78 }
79 
Initialize()80 void ElfBuilder::Initialize()
81 {
82     for (size_t i = 0; i < des_.size(); i++) {
83         des_[i].AddArkStackMapSection();
84     }
85     sectionToAlign_ = {
86         {ElfSecName::TEXT, AOTFileInfo::PAGE_ALIGN},
87         {ElfSecName::STRTAB, 1},
88         {ElfSecName::SYMTAB, AOTFileInfo::DATA_SEC_ALIGN},
89         {ElfSecName::SHSTRTAB, AOTFileInfo::DATA_SEC_ALIGN},
90         {ElfSecName::ARK_STACKMAP, AOTFileInfo::DATA_SEC_ALIGN},
91         {ElfSecName::ARK_FUNCENTRY, AOTFileInfo::DATA_SEC_ALIGN},
92         {ElfSecName::ARK_ASMSTUB, AOTFileInfo::DATA_SEC_ALIGN},
93         {ElfSecName::ARK_MODULEINFO, AOTFileInfo::DATA_SEC_ALIGN},
94     };
95 
96     sectionToSegment_ = {
97         {ElfSecName::RODATA, ElfSecName::TEXT},
98         {ElfSecName::RODATA_CST4, ElfSecName::TEXT},
99         {ElfSecName::RODATA_CST8, ElfSecName::TEXT},
100         {ElfSecName::RODATA_CST16, ElfSecName::TEXT},
101         {ElfSecName::RODATA_CST32, ElfSecName::TEXT},
102         {ElfSecName::TEXT, ElfSecName::TEXT},
103         {ElfSecName::STRTAB, ElfSecName::DATA},
104         {ElfSecName::SYMTAB, ElfSecName::DATA},
105         {ElfSecName::SHSTRTAB, ElfSecName::DATA},
106         {ElfSecName::ARK_STACKMAP, ElfSecName::DATA},
107         {ElfSecName::ARK_FUNCENTRY, ElfSecName::DATA},
108         {ElfSecName::ARK_ASMSTUB, ElfSecName::TEXT},
109         {ElfSecName::ARK_MODULEINFO, ElfSecName::DATA},
110     };
111 
112     segmentToFlag_ = {
113         {ElfSecName::TEXT, llvm::ELF::PF_X | llvm::ELF::PF_R},
114         {ElfSecName::DATA, llvm::ELF::PF_R},
115     };
116 
117     SetLastSection();
118 }
119 
RemoveNotNeedSection()120 void ElfBuilder::RemoveNotNeedSection()
121 {
122     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
123     for (size_t i = 0; i < sections_.size();) {
124         if (sections.find(sections_[i]) == sections.end()) {
125             auto it = sections_.begin() + i;
126             sections_.erase(it);
127             continue;
128         }
129         i++;
130     }
131 }
132 
~ElfBuilder()133 ElfBuilder::~ElfBuilder()
134 {
135     shStrTabPtr_ = nullptr;
136 }
137 
GetShIndex(ElfSecName section) const138 uint32_t ElfBuilder::GetShIndex(ElfSecName section) const
139 {
140     std::set<ElfSecName> secSet(sections_.begin(), sections_.end());
141     uint32_t idx = 1;
142     for (ElfSecName sec : secSet) {
143         if (sec == section) {
144             return idx;
145         }
146         idx++;
147     }
148     return -1;
149 }
150 
GetSecNum() const151 int ElfBuilder::GetSecNum() const
152 {
153     return sections_.size() + 1; // add first empty section.
154 }
155 
156 /*
157 ELF Header as follow:
158 ELF Header:
159   Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
160   Class:                             ELF64
161   Data:                              2's complement, little endian
162   Version:                           1 (current)
163   OS/ABI:                            UNIX - System V
164   ABI Version:                       0
165   Type:                              DYN (Shared object file)
166   Machine:                           Advanced Micro Devices X86-64
167   Version:                           0x4000001
168   Entry point address:               0x0
169   Start of program headers:          16384 (bytes into file)
170   Start of section headers:          64 (bytes into file)
171   Flags:                             0x0
172   Size of this header:               64 (bytes)
173   Size of program headers:           56 (bytes)
174   Number of program headers:         2
175   Size of section headers:           64 (bytes)
176   Number of section headers:         7
177   Section header string table index: 3
178 */
PackELFHeader(llvm::ELF::Elf64_Ehdr & header,uint32_t version,Triple triple)179 void ElfBuilder::PackELFHeader(llvm::ELF::Elf64_Ehdr &header, uint32_t version, Triple triple)
180 {
181     if (memset_s(reinterpret_cast<void *>(&header), sizeof(llvm::ELF::Elf64_Ehdr), 0,
182                  sizeof(llvm::ELF::Elf64_Ehdr)) != EOK) {
183         UNREACHABLE();
184     }
185     header.e_ident[llvm::ELF::EI_MAG0] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG0];
186     header.e_ident[llvm::ELF::EI_MAG1] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG1];
187     header.e_ident[llvm::ELF::EI_MAG2] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG2];
188     header.e_ident[llvm::ELF::EI_MAG3] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG3];
189     header.e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
190     header.e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
191     header.e_ident[llvm::ELF::EI_VERSION] = 1;
192 
193     header.e_type = llvm::ELF::ET_DYN;
194     switch (triple) {
195         case Triple::TRIPLE_AMD64:
196             header.e_machine = llvm::ELF::EM_X86_64;
197             break;
198         case Triple::TRIPLE_ARM32:
199             header.e_machine = llvm::ELF::EM_ARM;
200             break;
201         case Triple::TRIPLE_AARCH64:
202             header.e_machine = llvm::ELF::EM_AARCH64;
203             break;
204         default:
205             UNREACHABLE();
206             break;
207     }
208     header.e_version = version;
209     // start of section headers
210     header.e_shoff = sizeof(llvm::ELF::Elf64_Ehdr);
211     // size of ehdr
212     header.e_ehsize = sizeof(llvm::ELF::Elf64_Ehdr);
213     // size of section headers
214     header.e_shentsize = sizeof(llvm::ELF::Elf64_Shdr);
215     // number of section headers
216     header.e_shnum = GetSecNum();
217     // section header string table index
218     header.e_shstrndx = static_cast<llvm::ELF::Elf64_Half>(GetShIndex(ElfSecName::SHSTRTAB));
219     // section header stub sec info index
220     header.e_flags = static_cast<llvm::ELF::Elf64_Word>(GetShIndex(ElfSecName::ARK_MODULEINFO));
221     // phr
222     header.e_phentsize = sizeof(llvm::ELF::Elf64_Phdr);
223     header.e_phnum = GetSegmentNum();
224 }
225 
GetSegmentNum() const226 int ElfBuilder::GetSegmentNum() const
227 {
228     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
229     std::set<ElfSecName> segments;
230     for (auto &s: sections) {
231         ElfSection section = ElfSection(s.first);
232         if (!section.ShouldDumpToAOTFile()) {
233             continue;
234         }
235         auto it = sectionToSegment_.find(s.first);
236         ASSERT(it != sectionToSegment_.end());
237         ElfSecName name = it->second;
238         segments.insert(name);
239     }
240     return segments.size();
241 }
242 
SetLastSection()243 void ElfBuilder::SetLastSection()
244 {
245     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
246     for (auto &s: sections) {
247         ElfSection section = ElfSection(s.first);
248         if (!section.ShouldDumpToAOTFile()) {
249             continue;
250         }
251         auto it = sectionToSegment_.find(s.first);
252         ASSERT(it != sectionToSegment_.end());
253         ElfSecName name = it->second;
254         if (name == ElfSecName::TEXT) {
255             lastCodeSection = std::max(lastCodeSection, s.first);
256         } else {
257             lastDataSection = std::max(lastDataSection, s.first);
258         }
259     }
260 }
261 
FindShName(std::string name,uintptr_t strTabPtr,int strTabSize)262 llvm::ELF::Elf64_Word ElfBuilder::FindShName(std::string name, uintptr_t strTabPtr, int strTabSize)
263 {
264     llvm::ELF::Elf64_Word ans = -1;
265     int len = static_cast<int>(name.size());
266     if (strTabSize < len + 1) {
267         return ans;
268     }
269     LOG_ECMA(DEBUG) << "  FindShName name:" << name.c_str() << std::endl;
270     for (int i = 0; i < strTabSize - len + 1; ++i) {
271         char *dst = reinterpret_cast<char *>(strTabPtr) + i;
272         if (name.compare(dst) == 0) {
273             return i;
274         }
275     }
276     return ans;
277 }
278 
FindShStrTab() const279 std::pair<uint64_t, uint32_t> ElfBuilder::FindShStrTab() const
280 {
281     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
282     uint64_t shStrTabAddr = 0;
283     uint32_t shStrTabSize = 0;
284     for (auto &s: sections) {
285         uint32_t curSecSize = des_[ShStrTableModuleDesIndex].GetSecSize(s.first);
286         uint64_t curSecAddr = des_[ShStrTableModuleDesIndex].GetSecAddr(s.first);
287         if (s.first == ElfSecName::SHSTRTAB) {
288             shStrTabSize = curSecSize;
289             shStrTabAddr = curSecAddr;
290             break;
291         }
292     }
293     return std::make_pair(shStrTabAddr, shStrTabSize);
294 }
295 
AllocateShdr(std::unique_ptr<llvm::ELF::Elf64_Shdr[]> & shdr,const uint32_t & secNum)296 void ElfBuilder::AllocateShdr(std::unique_ptr<llvm::ELF::Elf64_Shdr []> &shdr, const uint32_t &secNum)
297 {
298     shdr = std::make_unique<llvm::ELF::Elf64_Shdr []>(secNum);
299     if (memset_s(reinterpret_cast<void *>(&shdr[0]),
300                  sizeof(llvm::ELF::Elf64_Shdr),
301                  0,
302                  sizeof(llvm::ELF::Elf64_Shdr)) != EOK) {
303         UNREACHABLE();
304     }
305 }
306 
ComputeEndAddrOfShdr(const uint32_t & secNum) const307 llvm::ELF::Elf64_Off ElfBuilder::ComputeEndAddrOfShdr(const uint32_t &secNum) const
308 {
309     llvm::ELF::Elf64_Off curSecOffset = sizeof(llvm::ELF::Elf64_Ehdr) + secNum * sizeof(llvm::ELF::Elf64_Shdr);
310     curSecOffset = AlignUp(curSecOffset, PageSize()); // not pagesize align will cause performance degradation
311     return curSecOffset;
312 }
313 
GetSegmentName(const ElfSecName & secName) const314 ElfSecName ElfBuilder::GetSegmentName(const ElfSecName &secName) const
315 {
316     auto it = sectionToSegment_.find(secName);
317     ASSERT(it != sectionToSegment_.end());
318     ElfSecName segName = it->second;
319     return segName;
320 }
321 
MergeTextSections(std::ofstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)322 void ElfBuilder::MergeTextSections(std::ofstream &file,
323                                    std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
324                                    llvm::ELF::Elf64_Off &curSecOffset)
325 {
326     for (size_t i = 0; i < des_.size(); ++i) {
327         ModuleSectionDes &des = des_[i];
328         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
329         uint32_t curSecSize = des.GetSecSize(ElfSecName::TEXT);
330         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::TEXT);
331         curSecOffset = AlignUp(curSecOffset, AOTFileInfo::PAGE_ALIGN);
332         file.seekp(curSecOffset);
333         auto curModuleSec = des.GetSectionsInfo();
334         uint64_t rodataAddrBeforeText = 0;
335         uint32_t rodataSizeBeforeText = 0;
336         uint64_t rodataAddrAfterText = 0;
337         uint32_t rodataSizeAfterText = 0;
338         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
339             des.GetMergedRODataAddrAndSize(curSecAddr);
340         if (rodataSizeBeforeText != 0) {
341             file.write(reinterpret_cast<char *>(rodataAddrBeforeText), rodataSizeBeforeText);
342             curInfo.rodataSizeBeforeText = rodataSizeBeforeText;
343             curSecOffset += rodataSizeBeforeText;
344             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::TEXT_SEC_ALIGN);
345             file.seekp(curSecOffset);
346         }
347         stubTextOffset_.emplace_back(curSecOffset);
348         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
349         curInfo.textSize = curSecSize;
350         curSecOffset += curSecSize;
351         if (rodataSizeAfterText != 0) {
352             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::DATA_SEC_ALIGN);
353             file.seekp(curSecOffset);
354             file.write(reinterpret_cast<char *>(rodataAddrAfterText), rodataSizeAfterText);
355             curInfo.rodataSizeAfterText = rodataSizeAfterText;
356             curSecOffset += rodataSizeAfterText;
357         }
358     }
359 }
360 
MergeStrtabSections(std::ofstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)361 void ElfBuilder::MergeStrtabSections(std::ofstream &file,
362                                      std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
363                                      llvm::ELF::Elf64_Off &curSecOffset)
364 {
365     for (size_t i = 0; i < des_.size(); ++i) {
366         ModuleSectionDes &des = des_[i];
367         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
368         uint32_t curSecSize = des.GetSecSize(ElfSecName::STRTAB);
369         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::STRTAB);
370         curInfo.strtabSize = curSecSize;
371         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
372         curSecOffset += curSecSize;
373     }
374 }
375 
MergeSymtabSections(std::ofstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)376 void ElfBuilder::MergeSymtabSections(std::ofstream &file,
377                                      std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
378                                      llvm::ELF::Elf64_Off &curSecOffset)
379 {
380     for (size_t i = 0; i < des_.size(); ++i) {
381         ModuleSectionDes &des = des_[i];
382         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
383         uint32_t curSecSize = des.GetSecSize(ElfSecName::SYMTAB);
384         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::SYMTAB);
385         curInfo.symtabSize = curSecSize;
386         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
387         curSecOffset += curSecSize;
388     }
389 }
390 
MergeArkStackMapSections(std::ofstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)391 void ElfBuilder::MergeArkStackMapSections(std::ofstream &file,
392                                           std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
393                                           llvm::ELF::Elf64_Off &curSecOffset)
394 {
395     for (size_t i = 0; i < des_.size(); ++i) {
396         ModuleSectionDes &des = des_[i];
397         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
398         uint32_t curSecSize = des.GetSecSize(ElfSecName::ARK_STACKMAP);
399         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::ARK_STACKMAP);
400         uint32_t index = des.GetStartIndex();
401         uint32_t cnt = des.GetFuncCount();
402         curInfo.startIndex = index;
403         curInfo.funcCount = cnt;
404         curInfo.stackMapSize = curSecSize;
405         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
406         curSecOffset += curSecSize;
407     }
408 }
409 
FixSymtab(llvm::ELF::Elf64_Shdr * shdr)410 void ElfBuilder::FixSymtab(llvm::ELF::Elf64_Shdr* shdr)
411 {
412     using Elf64_Sym = llvm::ELF::Elf64_Sym;
413     ASSERT(stubTextOffset_.size() == des_.size());
414 
415     uint32_t secNum = static_cast<uint32_t>(GetSecNum());
416     uint32_t shStrTabIndex = GetShIndex(ElfSecName::SHSTRTAB);
417     uint32_t strTabIndex = GetShIndex(ElfSecName::STRTAB);
418     uint32_t textSecIndex = GetShIndex(ElfSecName::TEXT);
419 
420     uint32_t strTabSize = 0;
421     int firstGlobal = -1;
422     uint32_t count = 0;
423 
424     for (size_t idx = 0; idx < des_.size(); ++idx) {
425         uint32_t secSize = des_[idx].GetSecSize(ElfSecName::SYMTAB);
426         uint64_t secAddr = des_[idx].GetSecAddr(ElfSecName::SYMTAB);
427         Elf64_Sym *syms = reinterpret_cast<Elf64_Sym*>(secAddr);
428         size_t n = secSize / sizeof(Elf64_Sym);
429         for (size_t i = 0; i < n; ++i) {
430             Elf64_Sym* sy = &syms[i];
431             if (sy->getBinding() == llvm::ELF::STB_GLOBAL && firstGlobal == -1) {
432                 firstGlobal = static_cast<int>(count);
433             }
434             if (sy->getType() == llvm::ELF::STT_SECTION) {
435                 sy->st_shndx = static_cast<uint16_t>(shStrTabIndex);
436             } else if (sy->getType() == llvm::ELF::STT_FUNC) {
437                 sy->st_shndx = static_cast<uint16_t>(textSecIndex);
438                 sy->st_value += stubTextOffset_[idx];
439             }
440             if (sy->st_shndx > secNum) {
441                 sy->st_shndx = 0;
442             }
443             sy->st_name += strTabSize;
444             count++;
445         }
446         strTabSize += des_[idx].GetSecSize(ElfSecName::STRTAB);
447     }
448     shdr->sh_info = static_cast<uint32_t>(firstGlobal);
449     shdr->sh_link = strTabIndex;
450 }
451 
452 /*
453 
454 section of aot.an layout as follows:
455 There are 7 section headers, starting at offset 0x40:
456 
457 Section Headers:
458   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
459   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
460   [ 1] .text             PROGBITS         0000000000001000  00001000  0000000000000f61  0000000000000000  AX       0     0     16
461   [ 2] .strtab           STRTAB           0000000000002000  00002000  0000000000000187  0000000000000000   A       0     0     1
462   [ 3] .symtab           SYMTAB           0000000000002188  00002188  00000000000001c8  0000000000000018   A       1     0     8
463   [ 4] .shstrtab         STRTAB           0000000000002350  00002350  000000000000003f  0000000000000000   A       0     0     8
464   [ 5] .ark_funcentry    PROGBITS         0000000000002390  00002390  00000000000006c0  0000000000000000   A       0     0     8
465   [ 6] .ark_stackmaps    PROGBITS         0000000000002a50  00002a50  000000000000070e  0000000000000000   A       0     0     8
466 
467 section of stub.an layout as follows:
468 There are 7 section headers, starting at offset 0x40:
469 
470   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
471   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
472   [ 1] .text             PROGBITS         0000000000001000  00001000  000000000008225e  0000000000000000  AX       0     0     16
473   [ 2] .ark_asmstub      PROGBITS         0000000000083260  00083260  0000000000002dc0  0000000000000000  AX       0     0     8
474   [ 3] .shstrtab         STRTAB           0000000000087000  00087000  000000000000004c  0000000000000000   A       0     0     8
475   [ 4] .ark_funcentry    PROGBITS         0000000000087050  00087050  0000000000023ca0  0000000000000000   A       0     0     8
476   [ 5] .ark_stackmaps    PROGBITS         00000000000aacf0  000aacf0  0000000000011e90  0000000000000000   A       0     0     8
477   [ 6] .ark_moduleinfo   PROGBITS         00000000000bcb80  000bcb80  000000000000003c  0000000000000000   A       0     0     8
478 
479 Key to Flags:
480   W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
481   L (link order), O (extra OS processing required), G (group), T (TLS),
482   C (compressed), x (unknown), o (OS specific), E (exclude),
483   D (mbind), l (large), p (processor specific)
484 */
PackELFSections(std::ofstream & file)485 void ElfBuilder::PackELFSections(std::ofstream &file)
486 {
487     uint32_t moduleNum = des_.size();
488     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
489     uint32_t secNum = sections.size() + 1; // 1 : section id = 0 is null section
490     std::unique_ptr<llvm::ELF::Elf64_Shdr []> shdr;
491     AllocateShdr(shdr, secNum);
492     std::vector<ModuleSectionDes::ModuleRegionInfo> moduleInfo(moduleNum);
493     llvm::ELF::Elf64_Off curSecOffset = ComputeEndAddrOfShdr(secNum);
494     file.seekp(curSecOffset);
495 
496     int i = static_cast<int>(GetShIndex(ElfSecName::TEXT));
497     auto shStrTab = FindShStrTab();
498 
499     for (auto const &[secName, secInfo] : sections) {
500         auto &curShdr = shdr[i];
501         ElfSection section = ElfSection(secName);
502         if (!section.ShouldDumpToAOTFile()) {
503             continue;
504         }
505         curShdr.sh_addralign = sectionToAlign_[secName];
506         curSecOffset = AlignUp(curSecOffset, curShdr.sh_addralign);
507         file.seekp(curSecOffset);
508         ElfSecName segName = GetSegmentName(secName);
509         segments_.insert(segName);
510         std::string secNameStr = ModuleSectionDes::GetSecName(secName);
511         // text section address needs 16 bytes alignment
512         if (secName == ElfSecName::TEXT) {
513             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::PAGE_ALIGN);
514             file.seekp(curSecOffset);
515         }
516         llvm::ELF::Elf64_Word shName = FindShName(secNameStr, shStrTab.first, shStrTab.second);
517         ASSERT(shName != static_cast<llvm::ELF::Elf64_Word>(-1));
518         curShdr.sh_name = shName;
519         curShdr.sh_type = section.Type();
520         curShdr.sh_flags = section.Flag();
521         curShdr.sh_addr = curSecOffset;
522         curShdr.sh_offset = static_cast<uint64_t>(curSecOffset);
523         curShdr.sh_info = 0;
524         curShdr.sh_link = static_cast<uint32_t>(section.Link());
525         sectionToFileOffset_[secName] = static_cast<uintptr_t>(file.tellp());
526         switch (secName) {
527             case ElfSecName::ARK_MODULEINFO: {
528                 uint32_t curSecSize = sizeof(ModuleSectionDes::ModuleRegionInfo) * moduleInfo.size();
529                 file.write(reinterpret_cast<char *>(moduleInfo.data()), curSecSize);
530                 curSecOffset += curSecSize;
531                 curShdr.sh_size = curSecSize;
532                 break;
533             }
534             case ElfSecName::TEXT: {
535                 uint32_t curSize = curSecOffset;
536                 MergeTextSections(file, moduleInfo, curSecOffset);
537                 curShdr.sh_size = curSecOffset - curSize;
538                 break;
539             }
540             case ElfSecName::ARK_STACKMAP: {
541                 uint32_t curSize = curSecOffset;
542                 MergeArkStackMapSections(file, moduleInfo, curSecOffset);
543                 curShdr.sh_size = curSecOffset - curSize;
544                 break;
545             }
546             case ElfSecName::STRTAB: {
547                 uint32_t curSize = curSecOffset;
548                 MergeStrtabSections(file, moduleInfo, curSecOffset);
549                 curShdr.sh_size = curSecOffset - curSize;
550                 break;
551             }
552             case ElfSecName::SYMTAB: {
553                 FixSymtab(&curShdr);
554                 uint32_t curSize = curSecOffset;
555                 MergeSymtabSections(file, moduleInfo, curSecOffset);
556                 curShdr.sh_size = curSecOffset - curSize;
557                 break;
558             }
559             case ElfSecName::SHSTRTAB:
560             case ElfSecName::ARK_FUNCENTRY:
561             case ElfSecName::ARK_ASMSTUB: {
562                 uint32_t curSecSize = des_[FullSecIndex].GetSecSize(secName);
563                 uint64_t curSecAddr = des_[FullSecIndex].GetSecAddr(secName);
564                 file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
565                 curSecOffset += curSecSize;
566                 curShdr.sh_size = curSecSize;
567                 break;
568             }
569             default: {
570                 LOG_ECMA(FATAL) << "this section should not dump to an file";
571                 break;
572             }
573         }
574         if (secName == lastDataSection || secName == lastCodeSection) {
575             curSecOffset = AlignUp(curSecOffset, PageSize());
576             file.seekp(curSecOffset);
577         }
578         curShdr.sh_entsize = static_cast<uint64_t>(section.Entsize());
579         sectionToShdr_[secName] = curShdr;
580         LOG_COMPILER(DEBUG) << "  shdr[i].sh_entsize " << std::hex << curShdr.sh_entsize << std::endl;
581         ++i;
582     }
583     uint32_t secEnd = static_cast<uint32_t>(file.tellp());
584     file.seekp(sizeof(llvm::ELF::Elf64_Ehdr));
585     file.write(reinterpret_cast<char *>(shdr.get()), secNum * sizeof(llvm::ELF::Elf64_Shdr));
586     file.seekp(secEnd);
587 }
588 
GetPFlag(ElfSecName segment) const589 unsigned ElfBuilder::GetPFlag(ElfSecName segment) const
590 {
591     return segmentToFlag_.at(segment);
592 }
593 
594 /*
595 segment layout as follows:
596 An Elf file
597 Entry point 0x0
598 There are 2 program headers, starting at offset 16384
599 
600 Program Headers:
601   Type           Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
602   LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000f61 0x0000000000001000  R E    0x1000
603   LOAD           0x0000000000002000 0x0000000000002000 0x0000000000002000 0x000000000000115e 0x0000000000002000  R      0x1000
604 
605  Section to Segment mapping:
606   Segment Sections...
607    00     .text
608    01     .strtab .symtab .shstrtab .ark_funcentry .ark_stackmaps
609 ------------------------------------------------------------------------------------------------------------------------------
610 Stub Elf file
611 Entry point 0x0
612 There are 2 program headers, starting at offset 770048
613 
614 Program Headers:
615   Type           Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
616   LOAD           0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000085020 0x0000000000086000  R E    0x1000
617   LOAD           0x0000000000087000 0x0000000000087000 0x0000000000087000 0x0000000000035bbc 0x0000000000036000  R      0x1000
618 
619  Section to Segment mapping:
620   Segment Sections...
621    00     .text .ark_asmstub
622    01     .shstrtab .ark_funcentry .ark_stackmaps .ark_moduleinfo
623 */
PackELFSegment(std::ofstream & file)624 void ElfBuilder::PackELFSegment(std::ofstream &file)
625 {
626     llvm::ELF::Elf64_Off e_phoff = static_cast<uint64_t>(file.tellp());
627     long phoff = (long)offsetof(struct llvm::ELF::Elf64_Ehdr, e_phoff);
628     // write Elf32_Off e_phoff
629     file.seekp(phoff);
630     file.write(reinterpret_cast<char *>(&e_phoff), sizeof(e_phoff));
631     file.seekp(static_cast<long>(e_phoff));
632 
633     int segNum = GetSegmentNum();
634     auto phdrs = std::make_unique<llvm::ELF::Elf64_Phdr []>(segNum);
635     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxOffset;
636     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxAddress;
637     std::set<ElfSecName> segments;
638     // SecName -> addr & size
639     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
640     llvm::ELF::Elf64_Off offset = e_phoff;
641     for (auto &s: sections) {
642         ElfSection section = ElfSection(s.first);
643         if (!section.ShouldDumpToAOTFile()) {
644             continue;
645         }
646         auto it = sectionToSegment_.find(s.first);
647         ASSERT(it != sectionToSegment_.end());
648         ElfSecName segName = it->second;
649         segments.insert(segName);
650         if (segmentToMaxOffset.find(segName) == segmentToMaxOffset.end()) {
651             segmentToMaxOffset[segName] = 0;
652         }
653         segmentToMaxOffset[segName] =
654             std::max(segmentToMaxOffset[segName], sectionToShdr_[s.first].sh_offset + sectionToShdr_[s.first].sh_size);
655         segmentToMaxAddress[segName] =
656             std::max(segmentToMaxAddress[segName], sectionToShdr_[s.first].sh_addr + sectionToShdr_[s.first].sh_size);
657         offset = std::min(offset, sectionToShdr_[s.first].sh_offset);
658     }
659     int phdrIndex = 0;
660     llvm::ELF::Elf64_Addr addr = offset;
661     for (auto &it: segments) {
662         ElfSecName name = it;
663         phdrs[phdrIndex].p_align = PageSize();
664         phdrs[phdrIndex].p_type = llvm::ELF::PT_LOAD;
665         phdrs[phdrIndex].p_flags = GetPFlag(name);
666         offset = AlignUp(offset, PageSize());
667         phdrs[phdrIndex].p_offset = offset;
668         phdrs[phdrIndex].p_vaddr = addr % phdrs[phdrIndex].p_align == 0 ?
669             addr : (addr / phdrs[phdrIndex].p_align + 1) * phdrs[phdrIndex].p_align;
670         phdrs[phdrIndex].p_paddr = phdrs[phdrIndex].p_vaddr;
671 
672         phdrs[phdrIndex].p_filesz = segmentToMaxOffset[name] - phdrs[phdrIndex].p_offset;
673         phdrs[phdrIndex].p_memsz = segmentToMaxAddress[name] - phdrs[phdrIndex].p_vaddr;
674         phdrs[phdrIndex].p_memsz = AlignUp(phdrs[phdrIndex].p_memsz, PageSize());
675         addr = phdrs[phdrIndex].p_vaddr + phdrs[phdrIndex].p_memsz;
676         offset += phdrs[phdrIndex].p_filesz;
677         ++phdrIndex;
678     }
679     file.write(reinterpret_cast<char *>(phdrs.get()), sizeof(llvm::ELF::Elf64_Phdr) * segNum);
680 }
681 }  // namespace panda::ecmascript
682