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