• 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 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::fstream & elfFile,const std::vector<std::pair<std::string,uint32_t>> & asmStubELFInfo)56 uint32_t ElfBuilder::AddAsmStubStrTab(std::fstream &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,bool enableOptDirectCall,Triple triple)102 ElfBuilder::ElfBuilder(const std::vector<ModuleSectionDes> &des,
103     const std::vector<ElfSecName> &sections,
104     bool enableOptDirectCall,
105     Triple triple): des_(des), sections_(sections), enableOptDirectCall_(enableOptDirectCall), triple_(triple)
106 {
107     Initialize();
108     AddShStrTabSection();
109     RemoveNotNeedSection();
110 }
111 
Initialize()112 void ElfBuilder::Initialize()
113 {
114     for (size_t i = 0; i < des_.size(); i++) {
115         des_[i].AddArkStackMapSection();
116     }
117     sectionToAlign_ = {{ElfSecName::TEXT, AOTFileInfo::PAGE_ALIGN},
118                        {ElfSecName::STRTAB, 1},
119                        {ElfSecName::SYMTAB, AOTFileInfo::DATA_SEC_ALIGN},
120                        {ElfSecName::SHSTRTAB, AOTFileInfo::DATA_SEC_ALIGN},
121                        {ElfSecName::ARK_STACKMAP, AOTFileInfo::DATA_SEC_ALIGN},
122                        {ElfSecName::ARK_FUNCENTRY, AOTFileInfo::DATA_SEC_ALIGN},
123                        {ElfSecName::ARK_ASMSTUB, AOTFileInfo::DATA_SEC_ALIGN},
124                        {ElfSecName::ARK_MODULEINFO, AOTFileInfo::DATA_SEC_ALIGN},
125                        {ElfSecName::ARK_CHECKSUMINFO, AOTFileInfo::DATA_SEC_ALIGN}};
126 
127     sectionToSegment_ = {
128         {ElfSecName::RODATA, ElfSecName::TEXT},         {ElfSecName::RODATA_CST4, ElfSecName::TEXT},
129         {ElfSecName::RODATA_CST8, ElfSecName::TEXT},    {ElfSecName::RODATA_CST16, ElfSecName::TEXT},
130         {ElfSecName::RODATA_CST32, ElfSecName::TEXT},   {ElfSecName::TEXT, ElfSecName::TEXT},
131         {ElfSecName::STRTAB, ElfSecName::DATA},         {ElfSecName::SYMTAB, ElfSecName::DATA},
132         {ElfSecName::SHSTRTAB, ElfSecName::DATA},       {ElfSecName::ARK_STACKMAP, ElfSecName::DATA},
133         {ElfSecName::ARK_FUNCENTRY, ElfSecName::DATA},  {ElfSecName::ARK_ASMSTUB, ElfSecName::TEXT},
134         {ElfSecName::ARK_MODULEINFO, ElfSecName::DATA}, {ElfSecName::ARK_CHECKSUMINFO, ElfSecName::DATA}};
135 
136     segmentToFlag_ = {
137         {ElfSecName::TEXT, llvm::ELF::PF_X | llvm::ELF::PF_R},
138         {ElfSecName::DATA, llvm::ELF::PF_R},
139     };
140 
141     SetLastSection();
142 }
143 
RemoveNotNeedSection()144 void ElfBuilder::RemoveNotNeedSection()
145 {
146     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
147     for (size_t i = 0; i < sections_.size();) {
148         if (sections.find(sections_[i]) == sections.end()) {
149             auto it = sections_.begin() + i;
150             sections_.erase(it);
151             continue;
152         }
153         i++;
154     }
155 }
156 
~ElfBuilder()157 ElfBuilder::~ElfBuilder()
158 {
159     shStrTabPtr_ = nullptr;
160 }
161 
GetShIndex(ElfSecName section) const162 uint32_t ElfBuilder::GetShIndex(ElfSecName section) const
163 {
164     std::set<ElfSecName> secSet(sections_.begin(), sections_.end());
165     uint32_t idx = 1;
166     for (ElfSecName sec : secSet) {
167         if (sec == section) {
168             return idx;
169         }
170         idx++;
171     }
172     return 0;
173 }
174 
GetSecNum() const175 int ElfBuilder::GetSecNum() const
176 {
177     return sections_.size() + 1; // add first empty section.
178 }
179 
180 /*
181 ELF Header as follow:
182 ELF Header:
183   Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
184   Class:                             ELF64
185   Data:                              2's complement, little endian
186   Version:                           1 (current)
187   OS/ABI:                            UNIX - System V
188   ABI Version:                       0
189   Type:                              DYN (Shared object file)
190   Machine:                           Advanced Micro Devices X86-64
191   Version:                           0x4000001
192   Entry point address:               0x0
193   Start of program headers:          16384 (bytes into file)
194   Start of section headers:          64 (bytes into file)
195   Flags:                             0x0
196   Size of this header:               64 (bytes)
197   Size of program headers:           56 (bytes)
198   Number of program headers:         2
199   Size of section headers:           64 (bytes)
200   Number of section headers:         7
201   Section header string table index: 3
202 */
PackELFHeader(llvm::ELF::Elf64_Ehdr & header,uint32_t version,Triple triple)203 void ElfBuilder::PackELFHeader(llvm::ELF::Elf64_Ehdr &header, uint32_t version, Triple triple)
204 {
205     if (memset_s(reinterpret_cast<void *>(&header), sizeof(llvm::ELF::Elf64_Ehdr), 0,
206                  sizeof(llvm::ELF::Elf64_Ehdr)) != EOK) {
207         UNREACHABLE();
208     }
209     header.e_ident[llvm::ELF::EI_MAG0] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG0];
210     header.e_ident[llvm::ELF::EI_MAG1] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG1];
211     header.e_ident[llvm::ELF::EI_MAG2] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG2];
212     header.e_ident[llvm::ELF::EI_MAG3] = llvm::ELF::ElfMagic[llvm::ELF::EI_MAG3];
213     header.e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
214     header.e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
215     header.e_ident[llvm::ELF::EI_VERSION] = 1;
216 
217     header.e_type = llvm::ELF::ET_DYN;
218     switch (triple) {
219         case Triple::TRIPLE_AMD64:
220             header.e_machine = llvm::ELF::EM_X86_64;
221             break;
222         case Triple::TRIPLE_ARM32:
223             header.e_machine = llvm::ELF::EM_ARM;
224             break;
225         case Triple::TRIPLE_AARCH64:
226             header.e_machine = llvm::ELF::EM_AARCH64;
227             break;
228         default:
229             UNREACHABLE();
230             break;
231     }
232     header.e_version = version;
233     // start of section headers
234     header.e_shoff = sizeof(llvm::ELF::Elf64_Ehdr);
235     // size of ehdr
236     header.e_ehsize = sizeof(llvm::ELF::Elf64_Ehdr);
237     // size of section headers
238     header.e_shentsize = sizeof(llvm::ELF::Elf64_Shdr);
239     // number of section headers
240     header.e_shnum = GetSecNum();
241     // section header string table index
242     header.e_shstrndx = static_cast<llvm::ELF::Elf64_Half>(GetShIndex(ElfSecName::SHSTRTAB));
243     // section header stub sec info index
244     header.e_flags = static_cast<llvm::ELF::Elf64_Word>(GetShIndex(ElfSecName::ARK_MODULEINFO));
245     // phr
246     header.e_phentsize = sizeof(llvm::ELF::Elf64_Phdr);
247     header.e_phnum = GetSegmentNum();
248 }
249 
GetSegmentNum() const250 size_t ElfBuilder::GetSegmentNum() const
251 {
252     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
253     std::set<ElfSecName> segments;
254     for (auto &s: sections) {
255         ElfSection section = ElfSection(s.first);
256         if (!section.ShouldDumpToAOTFile()) {
257             continue;
258         }
259         auto it = sectionToSegment_.find(s.first);
260         ASSERT(it != sectionToSegment_.end());
261         ElfSecName name = it->second;
262         segments.insert(name);
263     }
264     return segments.size();
265 }
266 
SetLastSection()267 void ElfBuilder::SetLastSection()
268 {
269     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
270     for (auto &s: sections) {
271         ElfSection section = ElfSection(s.first);
272         if (!section.ShouldDumpToAOTFile()) {
273             continue;
274         }
275         auto it = sectionToSegment_.find(s.first);
276         ASSERT(it != sectionToSegment_.end());
277         ElfSecName name = it->second;
278         if (name == ElfSecName::TEXT) {
279             lastCodeSection = std::max(lastCodeSection, s.first);
280         } else {
281             lastDataSection = std::max(lastDataSection, s.first);
282         }
283     }
284 }
285 
FindShName(std::string name,uintptr_t strTabPtr,int strTabSize)286 llvm::ELF::Elf64_Word ElfBuilder::FindShName(std::string name, uintptr_t strTabPtr, int strTabSize)
287 {
288     llvm::ELF::Elf64_Word ans = -1;
289     int len = static_cast<int>(name.size());
290     if (strTabSize < len + 1) {
291         return ans;
292     }
293     LOG_ECMA(DEBUG) << "  FindShName name:" << name.c_str() << std::endl;
294     for (int i = 0; i < strTabSize - len + 1; ++i) {
295         char *dst = reinterpret_cast<char *>(strTabPtr) + i;
296         if (name.compare(dst) == 0) {
297             return i;
298         }
299     }
300     return ans;
301 }
302 
FindShStrTab() const303 std::pair<uint64_t, uint32_t> ElfBuilder::FindShStrTab() const
304 {
305     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
306     uint64_t shStrTabAddr = 0;
307     uint32_t shStrTabSize = 0;
308     for (auto &s: sections) {
309         uint32_t curSecSize = des_[ShStrTableModuleDesIndex].GetSecSize(s.first);
310         uint64_t curSecAddr = des_[ShStrTableModuleDesIndex].GetSecAddr(s.first);
311         if (s.first == ElfSecName::SHSTRTAB) {
312             shStrTabSize = curSecSize;
313             shStrTabAddr = curSecAddr;
314             break;
315         }
316     }
317     return std::make_pair(shStrTabAddr, shStrTabSize);
318 }
319 
AllocateShdr(std::unique_ptr<llvm::ELF::Elf64_Shdr[]> & shdr,const uint32_t & secNum)320 void ElfBuilder::AllocateShdr(std::unique_ptr<llvm::ELF::Elf64_Shdr []> &shdr, const uint32_t &secNum)
321 {
322     shdr = std::make_unique<llvm::ELF::Elf64_Shdr []>(secNum);
323     if (memset_s(reinterpret_cast<void *>(&shdr[0]),
324                  sizeof(llvm::ELF::Elf64_Shdr),
325                  0,
326                  sizeof(llvm::ELF::Elf64_Shdr)) != EOK) {
327         UNREACHABLE();
328     }
329 }
330 
ComputeEndAddrOfShdr(const uint32_t & secNum) const331 llvm::ELF::Elf64_Off ElfBuilder::ComputeEndAddrOfShdr(const uint32_t &secNum) const
332 {
333     llvm::ELF::Elf64_Off curSecOffset = sizeof(llvm::ELF::Elf64_Ehdr) + secNum * sizeof(llvm::ELF::Elf64_Shdr);
334     curSecOffset = AlignUp(curSecOffset, PageSize()); // not pagesize align will cause performance degradation
335     return curSecOffset;
336 }
337 
GetSegmentName(const ElfSecName & secName) const338 ElfSecName ElfBuilder::GetSegmentName(const ElfSecName &secName) const
339 {
340     auto it = sectionToSegment_.find(secName);
341     ASSERT(it != sectionToSegment_.end());
342     ElfSecName segName = it->second;
343     return segName;
344 }
345 
MergeTextSections(std::fstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)346 void ElfBuilder::MergeTextSections(std::fstream &file,
347                                    std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
348                                    llvm::ELF::Elf64_Off &curSecOffset)
349 {
350     for (size_t i = 0; i < des_.size(); ++i) {
351         ModuleSectionDes &des = des_[i];
352         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
353         uint32_t curSecSize = des.GetSecSize(ElfSecName::TEXT);
354         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::TEXT);
355         curSecOffset = AlignUp(curSecOffset, AOTFileInfo::PAGE_ALIGN);
356         file.seekp(curSecOffset);
357         auto curModuleSec = des.GetSectionsInfo();
358         uint64_t rodataAddrBeforeText = 0;
359         uint32_t rodataSizeBeforeText = 0;
360         uint64_t rodataAddrAfterText = 0;
361         uint32_t rodataSizeAfterText = 0;
362         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
363             des.GetMergedRODataAddrAndSize(curSecAddr);
364         if (rodataSizeBeforeText != 0) {
365             file.write(reinterpret_cast<char *>(rodataAddrBeforeText), rodataSizeBeforeText);
366             curInfo.rodataSizeBeforeText = rodataSizeBeforeText;
367             curSecOffset += rodataSizeBeforeText;
368             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::TEXT_SEC_ALIGN);
369             file.seekp(curSecOffset);
370         }
371         stubTextOffset_.emplace_back(curSecOffset);
372         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
373         curInfo.textSize = curSecSize;
374         curSecOffset += curSecSize;
375         if (rodataSizeAfterText != 0) {
376             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::RODATA_SEC_ALIGN);
377             file.seekp(curSecOffset);
378             file.write(reinterpret_cast<char *>(rodataAddrAfterText), rodataSizeAfterText);
379             curInfo.rodataSizeAfterText = rodataSizeAfterText;
380             curSecOffset += rodataSizeAfterText;
381         }
382     }
383 }
384 
MergeStrtabSections(std::fstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)385 void ElfBuilder::MergeStrtabSections(std::fstream &file,
386                                      std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
387                                      llvm::ELF::Elf64_Off &curSecOffset)
388 {
389     for (size_t i = 0; i < des_.size(); ++i) {
390         ModuleSectionDes &des = des_[i];
391         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
392         uint32_t curSecSize = des.GetSecSize(ElfSecName::STRTAB);
393         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::STRTAB);
394         curInfo.strtabSize = curSecSize;
395         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
396         curSecOffset += curSecSize;
397         if (des.HasAsmStubStrTab()) {
398             uint32_t asmStubStrTabSize = AddAsmStubStrTab(file, des.GetAsmStubELFInfo());
399             curSecOffset += asmStubStrTabSize;
400             curInfo.strtabSize += asmStubStrTabSize;
401         }
402     }
403 }
404 
MergeSymtabSections(std::fstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset,llvm::ELF::Elf64_Off & asmStubOffset)405 void ElfBuilder::MergeSymtabSections(std::fstream &file,
406                                      std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
407                                      llvm::ELF::Elf64_Off &curSecOffset,
408                                      llvm::ELF::Elf64_Off &asmStubOffset)
409 {
410     using Elf64_Sym = llvm::ELF::Elf64_Sym;
411     uint32_t strTabSize = 0;
412     uint32_t textSecIndex = GetShIndex(ElfSecName::ARK_ASMSTUB);
413     for (size_t i = 0; i < des_.size(); ++i) {
414         ModuleSectionDes &des = des_[i];
415         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
416         uint32_t curSecSize = des.GetSecSize(ElfSecName::SYMTAB);
417         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::SYMTAB);
418         curInfo.symtabSize = curSecSize;
419         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
420         curSecOffset += curSecSize;
421         strTabSize += des.GetSecSize(ElfSecName::STRTAB);
422         if (des.HasAsmStubStrTab()) {
423             const std::vector<std::pair<std::string, uint32_t>> &asmStubELFInfo = des.GetAsmStubELFInfo();
424             ASSERT(asmStubELFInfo.size() > 0);
425             uint32_t asmStubSymTabNum = asmStubELFInfo.size() - 1;
426             std::unique_ptr<Elf64_Sym []> syms = std::make_unique<Elf64_Sym []>(asmStubSymTabNum);
427             ASSERT(asmStubStrName_.size() == asmStubSymTabNum);
428             for (size_t idx = 0; idx < asmStubSymTabNum; ++idx) {
429                 Elf64_Sym &sym = syms[idx];
430                 sym.setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_FUNC);
431                 sym.st_shndx = static_cast<uint16_t>(textSecIndex);
432                 sym.st_value = asmStubELFInfo[idx].second + asmStubOffset;
433                 sym.st_name = asmStubStrName_[idx];
434                 sym.st_name += strTabSize;
435                 sym.st_other = llvm::ELF::STV_DEFAULT;
436                 sym.st_size = asmStubELFInfo[idx + 1].second - asmStubELFInfo[idx].second;
437             }
438             uint32_t asmStubSymTabSize = asmStubSymTabNum * sizeof(llvm::ELF::Elf64_Sym);
439             file.write(reinterpret_cast<char *>(syms.get()), asmStubSymTabSize);
440             curInfo.symtabSize += asmStubSymTabSize;
441             curSecOffset += asmStubSymTabSize;
442         }
443     }
444 }
445 
MergeArkStackMapSections(std::fstream & file,std::vector<ModuleSectionDes::ModuleRegionInfo> & moduleInfo,llvm::ELF::Elf64_Off & curSecOffset)446 void ElfBuilder::MergeArkStackMapSections(std::fstream &file,
447                                           std::vector<ModuleSectionDes::ModuleRegionInfo> &moduleInfo,
448                                           llvm::ELF::Elf64_Off &curSecOffset)
449 {
450     for (size_t i = 0; i < des_.size(); ++i) {
451         ModuleSectionDes &des = des_[i];
452         ModuleSectionDes::ModuleRegionInfo &curInfo = moduleInfo[i];
453         uint32_t curSecSize = des.GetSecSize(ElfSecName::ARK_STACKMAP);
454         uint64_t curSecAddr = des.GetSecAddr(ElfSecName::ARK_STACKMAP);
455         uint32_t index = des.GetStartIndex();
456         uint32_t cnt = des.GetFuncCount();
457         curInfo.startIndex = index;
458         curInfo.funcCount = cnt;
459         curInfo.stackMapSize = curSecSize;
460         file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
461         curSecOffset += curSecSize;
462     }
463 }
464 
FixUndefinedSymbols(const std::map<std::string_view,llvm::ELF::Elf64_Sym * > & nameToSym,const std::map<std::string_view,std::vector<llvm::ELF::Elf64_Sym * >> & undefSyms,llvm::ELF::Elf64_Off asmStubOffset)465 void ElfBuilder::FixUndefinedSymbols(const std::map<std::string_view, llvm::ELF::Elf64_Sym *> &nameToSym,
466                                      const std::map<std::string_view, std::vector<llvm::ELF::Elf64_Sym *>> &undefSyms,
467                                      llvm::ELF::Elf64_Off asmStubOffset)
468 {
469     if (!enableOptDirectCall_) {
470         return;
471     }
472     std::map<std::string, uint64_t> asmStubToAddr;
473     for (auto &des : des_) {
474         if (!des.HasAsmStubStrTab()) {
475             continue;
476         }
477 
478         const std::vector<std::pair<std::string, uint32_t>> &asmStubELFInfo = des.GetAsmStubELFInfo();
479         ASSERT(asmStubELFInfo.size() > 0);
480         for (auto &[name, offset] : asmStubELFInfo) {
481             if (auto [result, inserted] = asmStubToAddr.try_emplace(name, asmStubOffset + offset); !inserted) {
482                 LOG_COMPILER(FATAL) << "Duplicate asm symbol: " << name << std::endl;
483             }
484             if (nameToSym.find(name) != nameToSym.end()) {
485                 LOG_COMPILER(FATAL) << "Duplicate asm symbol with ir symbol: " << name << std::endl;
486             }
487         }
488     }
489     uint32_t asmSecIndex = GetShIndex(ElfSecName::ARK_ASMSTUB);
490     for (auto &[name, undefSymVec] : undefSyms) {
491         auto targetSymIter = nameToSym.find(name);
492         if (targetSymIter != nameToSym.end()) {
493             for (auto undefSym : undefSymVec) {
494                 // preempt with defined symbol.
495                 *undefSym = *targetSymIter->second;
496             }
497             continue;
498         }
499         auto asmTargetSymIter = asmStubToAddr.find(std::string(name));
500         if (asmTargetSymIter != asmStubToAddr.end()) {
501             for (auto undefSym : undefSymVec) {
502                 // preempt with defined symbol.
503                 undefSym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_FUNC);
504                 undefSym->st_shndx = static_cast<uint16_t>(asmSecIndex);
505                 undefSym->st_value = asmTargetSymIter->second;
506                 undefSym->st_other = llvm::ELF::STV_DEFAULT;
507             }
508             continue;
509         }
510         LOG_COMPILER(FATAL) << "Undefined symbol: " << name << std::endl;
511     }
512 }
513 
CollectUndefSyms(std::map<std::string_view,llvm::ELF::Elf64_Sym * > & nameToSym,std::map<std::string_view,std::vector<llvm::ELF::Elf64_Sym * >> & undefSyms,llvm::ELF::Elf64_Sym * sy,std::string_view symName)514 void ElfBuilder::CollectUndefSyms(std::map<std::string_view, llvm::ELF::Elf64_Sym *> &nameToSym,
515                                   std::map<std::string_view, std::vector<llvm::ELF::Elf64_Sym *>> &undefSyms,
516                                   llvm::ELF::Elf64_Sym *sy, std::string_view symName)
517 {
518     if (!enableOptDirectCall_) {
519         return;
520     }
521     if (sy->getBinding() == llvm::ELF::STB_LOCAL) {
522         // local symbol should be relocated when compiling, so skip them.
523         return;
524     }
525     if (sy->st_shndx != llvm::ELF::SHN_UNDEF) {
526         if (auto [iter, inserted] = nameToSym.try_emplace(symName, sy); !inserted) {
527             LOG_COMPILER(FATAL) << "Duplicate symbol: " << symName << std::endl;
528         }
529     } else {
530         auto [iter, inserted] = undefSyms.try_emplace(symName);
531         iter->second.push_back(sy);
532     }
533 }
534 
FixSymtab(llvm::ELF::Elf64_Shdr * shdr,llvm::ELF::Elf64_Off asmStubOffset)535 void ElfBuilder::FixSymtab(llvm::ELF::Elf64_Shdr* shdr, llvm::ELF::Elf64_Off asmStubOffset)
536 {
537     using Elf64_Sym = llvm::ELF::Elf64_Sym;
538     ASSERT(stubTextOffset_.size() == des_.size());
539     std::map<std::string_view, llvm::ELF::Elf64_Sym*> nameToSym;
540     std::map<std::string_view, std::vector<llvm::ELF::Elf64_Sym*>> undefSyms;
541     uint32_t secNum = static_cast<uint32_t>(GetSecNum());
542     uint32_t shStrTabIndex = GetShIndex(ElfSecName::SHSTRTAB);
543     uint32_t strTabIndex = GetShIndex(ElfSecName::STRTAB);
544     uint32_t textSecIndex = GetShIndex(ElfSecName::TEXT);
545 
546     uint32_t strTabSize = 0;
547     int firstGlobal = -1;
548     uint32_t count = 0;
549     for (size_t idx = 0; idx < des_.size(); ++idx) {
550         uint64_t strTabAddr = des_[idx].GetSecAddr(ElfSecName::STRTAB);
551         uint32_t secSize = des_[idx].GetSecSize(ElfSecName::SYMTAB);
552         uint64_t secAddr = des_[idx].GetSecAddr(ElfSecName::SYMTAB);
553         Elf64_Sym *syms = reinterpret_cast<Elf64_Sym*>(secAddr);
554         size_t n = secSize / sizeof(Elf64_Sym);
555         for (size_t i = 0; i < n; ++i) {
556             Elf64_Sym* sy = &syms[i];
557             std::string_view symName(reinterpret_cast<char *>(strTabAddr + sy->st_name));
558             if (sy->getBinding() == llvm::ELF::STB_GLOBAL && firstGlobal == -1) {
559                 firstGlobal = static_cast<int>(count);
560             }
561             if (sy->getType() == llvm::ELF::STT_SECTION) {
562                 sy->st_shndx = static_cast<uint16_t>(shStrTabIndex);
563             } else if (sy->getType() == llvm::ELF::STT_FUNC) {
564                 sy->st_shndx = static_cast<uint16_t>(textSecIndex);
565                 sy->st_value += stubTextOffset_[idx];
566             }
567             if (sy->st_shndx > secNum) {
568                 sy->st_shndx = 0;
569             }
570             sy->st_name += strTabSize;
571             count++;
572             CollectUndefSyms(nameToSym, undefSyms, sy, symName);
573         }
574         strTabSize += des_[idx].GetSecSize(ElfSecName::STRTAB);
575     }
576     shdr->sh_info = static_cast<uint32_t>(firstGlobal);
577     shdr->sh_link = strTabIndex;
578     FixUndefinedSymbols(nameToSym, undefSyms, asmStubOffset);
579 }
580 
581 /*
582 
583 section of aot.an layout as follows:
584 There are 7 section headers, starting at offset 0x40:
585 
586 Section Headers:
587   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
588   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
589   [ 1] .text             PROGBITS         0000000000001000  00001000  0000000000000f61  0000000000000000  AX       0     0     16
590   [ 2] .strtab           STRTAB           0000000000002000  00002000  0000000000000187  0000000000000000   A       0     0     1
591   [ 3] .symtab           SYMTAB           0000000000002188  00002188  00000000000001c8  0000000000000018   A       1     0     8
592   [ 4] .shstrtab         STRTAB           0000000000002350  00002350  000000000000003f  0000000000000000   A       0     0     8
593   [ 5] .ark_funcentry    PROGBITS         0000000000002390  00002390  00000000000006c0  0000000000000000   A       0     0     8
594   [ 6] .ark_stackmaps    PROGBITS         0000000000002a50  00002a50  000000000000070e  0000000000000000   A       0     0     8
595   [ 7] .ark_checksuminfo PROGBITS         000000000000315e  0000315e  0000000000000028  0000000000000000   A       0     0     8
596 
597 section of stub.an layout as follows:
598 There are 7 section headers, starting at offset 0x40:
599 
600   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
601   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
602   [ 1] .text             PROGBITS         0000000000001000  00001000  000000000008225e  0000000000000000  AX       0     0     16
603   [ 2] .ark_asmstub      PROGBITS         0000000000083260  00083260  0000000000002dc0  0000000000000000  AX       0     0     8
604   [ 3] .shstrtab         STRTAB           0000000000087000  00087000  000000000000004c  0000000000000000   A       0     0     8
605   [ 4] .ark_funcentry    PROGBITS         0000000000087050  00087050  0000000000023ca0  0000000000000000   A       0     0     8
606   [ 5] .ark_stackmaps    PROGBITS         00000000000aacf0  000aacf0  0000000000011e90  0000000000000000   A       0     0     8
607   [ 6] .ark_moduleinfo   PROGBITS         00000000000bcb80  000bcb80  000000000000003c  0000000000000000   A       0     0     8
608 
609 Key to Flags:
610   W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
611   L (link order), O (extra OS processing required), G (group), T (TLS),
612   C (compressed), x (unknown), o (OS specific), E (exclude),
613   D (mbind), l (large), p (processor specific)
614 */
PackELFSections(std::fstream & file)615 void ElfBuilder::PackELFSections(std::fstream &file)
616 {
617     uint32_t moduleNum = des_.size();
618     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
619     uint32_t secNum = sections.size() + 1; // 1 : section id = 0 is null section
620     std::unique_ptr<llvm::ELF::Elf64_Shdr []> shdr;
621     AllocateShdr(shdr, secNum);
622     std::vector<ModuleSectionDes::ModuleRegionInfo> moduleInfo(moduleNum);
623     llvm::ELF::Elf64_Off curSecOffset = ComputeEndAddrOfShdr(secNum);
624     file.seekp(curSecOffset);
625 
626     int i = static_cast<int>(GetShIndex(ElfSecName::TEXT));
627     auto shStrTab = FindShStrTab();
628 
629     for (auto const &[secName, secInfo] : sections) {
630         auto &curShdr = shdr[i];
631         ElfSection section = ElfSection(secName);
632         if (!section.ShouldDumpToAOTFile()) {
633             continue;
634         }
635         curShdr.sh_addralign = sectionToAlign_[secName];
636         curSecOffset = AlignUp(curSecOffset, curShdr.sh_addralign);
637         file.seekp(curSecOffset);
638         ElfSecName segName = GetSegmentName(secName);
639         segments_.insert(segName);
640         std::string secNameStr = ModuleSectionDes::GetSecName(secName);
641         // text section address needs 16 bytes alignment
642         if (secName == ElfSecName::TEXT) {
643             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::PAGE_ALIGN);
644             file.seekp(curSecOffset);
645         }
646         llvm::ELF::Elf64_Word shName = FindShName(secNameStr, shStrTab.first, shStrTab.second);
647         ASSERT(shName != static_cast<llvm::ELF::Elf64_Word>(-1));
648         curShdr.sh_name = shName;
649         curShdr.sh_type = section.Type();
650         curShdr.sh_flags = section.Flag();
651         curShdr.sh_addr = curSecOffset;
652         curShdr.sh_offset = static_cast<uint64_t>(curSecOffset);
653         curShdr.sh_info = 0;
654         curShdr.sh_link = static_cast<uint32_t>(section.Link());
655         sectionToFileOffset_[secName] = static_cast<uintptr_t>(file.tellp());
656         switch (secName) {
657             case ElfSecName::ARK_MODULEINFO: {
658                 uint32_t curSecSize = sizeof(ModuleSectionDes::ModuleRegionInfo) * moduleInfo.size();
659                 file.write(reinterpret_cast<char *>(moduleInfo.data()), curSecSize);
660                 curSecOffset += curSecSize;
661                 curShdr.sh_size = curSecSize;
662                 break;
663             }
664             case ElfSecName::TEXT: {
665                 uint32_t curSize = curSecOffset;
666                 MergeTextSections(file, moduleInfo, curSecOffset);
667                 curShdr.sh_size = curSecOffset - curSize;
668                 break;
669             }
670             case ElfSecName::ARK_STACKMAP: {
671                 uint32_t curSize = curSecOffset;
672                 MergeArkStackMapSections(file, moduleInfo, curSecOffset);
673                 curShdr.sh_size = curSecOffset - curSize;
674                 break;
675             }
676             case ElfSecName::STRTAB: {
677                 uint32_t curSize = curSecOffset;
678                 MergeStrtabSections(file, moduleInfo, curSecOffset);
679                 curShdr.sh_size = curSecOffset - curSize;
680                 break;
681             }
682             case ElfSecName::SYMTAB: {
683                 uint32_t curSize = curSecOffset;
684                 uint32_t asmSecIndex = GetShIndex(ElfSecName::ARK_ASMSTUB);
685                 uint64_t asmStubOffset = shdr[asmSecIndex].sh_offset;
686                 FixSymtab(&curShdr, asmStubOffset);
687                 MergeSymtabSections(file, moduleInfo, curSecOffset, asmStubOffset);
688                 curShdr.sh_size = curSecOffset - curSize;
689                 break;
690             }
691             case ElfSecName::SHSTRTAB:
692             case ElfSecName::ARK_FUNCENTRY:
693             case ElfSecName::ARK_ASMSTUB:
694             case ElfSecName::ARK_CHECKSUMINFO: {
695                 uint32_t curSecSize = des_[FullSecIndex].GetSecSize(secName);
696                 uint64_t curSecAddr = des_[FullSecIndex].GetSecAddr(secName);
697                 file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
698                 curSecOffset += curSecSize;
699                 curShdr.sh_size = curSecSize;
700                 break;
701             }
702             default: {
703                 LOG_ECMA(FATAL) << "this section should not dump to an file";
704                 break;
705             }
706         }
707         if (secName == lastDataSection || secName == lastCodeSection) {
708             curSecOffset = AlignUp(curSecOffset, PageSize());
709             file.seekp(curSecOffset);
710         }
711         curShdr.sh_entsize = static_cast<uint64_t>(section.Entsize());
712         sectionToShdr_[secName] = curShdr;
713         LOG_COMPILER(DEBUG) << "  shdr[i].sh_entsize " << std::hex << curShdr.sh_entsize << std::endl;
714         ++i;
715     }
716     ResolveRelocate(file);
717     uint32_t secEnd = static_cast<uint32_t>(file.tellp());
718     file.seekp(sizeof(llvm::ELF::Elf64_Ehdr));
719     file.write(reinterpret_cast<char *>(shdr.get()), secNum * sizeof(llvm::ELF::Elf64_Shdr));
720     file.seekp(secEnd);
721 }
722 
ResolveAArch64Relocate(std::fstream & elfFile,Span<llvm::ELF::Elf64_Rela> relas,Span<llvm::ELF::Elf64_Sym> syms,const uint32_t textOff)723 void ElfBuilder::ResolveAArch64Relocate(std::fstream &elfFile, Span<llvm::ELF::Elf64_Rela> relas,
724                                         Span<llvm::ELF::Elf64_Sym> syms, const uint32_t textOff)
725 {
726     using Elf64_Rela = llvm::ELF::Elf64_Rela;
727     for (Elf64_Rela &rela : relas) {
728         switch (rela.getType()) {
729             case llvm::ELF::R_AARCH64_JUMP26:
730             case llvm::ELF::R_AARCH64_CALL26: {
731                 // the reloc symbol is also in stub.an, calculate the relative offset.
732                 auto symIdx = rela.getSymbol();
733                 llvm::ELF::Elf64_Sym sym = syms[symIdx];
734                 if (sym.getBinding() == llvm::ELF::STB_LOCAL) {
735                     break;
736                 }
737                 uint32_t relocOff = textOff + rela.r_offset;
738                 uint32_t value = sym.st_value + rela.r_addend - relocOff;
739                 // Target = Symbol Value + Addend − Relocation Address
740                 if (!(IMM28_MIN <= static_cast<int32_t>(value) && static_cast<int32_t>(value) < IMM28_MAX)) {
741                     LOG_ECMA(FATAL) << "relocate target out of imm28 range: " << value << std::endl;
742                 }
743                 elfFile.seekg(relocOff);
744                 uint32_t oldVal = 0;
745                 elfFile.read(reinterpret_cast<char *>(&oldVal), sizeof(uint32_t));
746                 value = (oldVal & 0xFC000000) | ((value & 0x0FFFFFFC) >> DIV4_BITS);
747                 // 0xFC000000: 11111100 00000000 00000000 00000000, get the high 6 bit as the opcode.
748                 // 0x0FFFFFFC: 00001111 11111111 11111111 11111100, use this mask to get imm26 from the value.
749                 // the instructions must be bl or b, they accept a 26-bits imm int, so clear the low 26-bits in the old
750                 // instruction(it maybe wrong because llvm backend may fill some JITEngine reloc data in it). And fill
751                 // it with the calculated target.
752                 elfFile.seekp(relocOff);
753                 elfFile.write(reinterpret_cast<char *>(&value), sizeof(value));
754                 break;
755             }
756             case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
757             case llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC:
758                 // data relocation, already handled by llvm backend, ignore it.
759                 break;
760             default:
761                 LOG_ECMA(FATAL) << "Unhandled relocate type: " << rela.getType() << std::endl;
762         }
763     }
764 }
765 
ResolveAmd64Relocate(std::fstream & elfFile,Span<llvm::ELF::Elf64_Rela> relas,Span<llvm::ELF::Elf64_Sym> syms,const uint32_t textOff)766 void ElfBuilder::ResolveAmd64Relocate(std::fstream &elfFile, Span<llvm::ELF::Elf64_Rela> relas,
767                                       Span<llvm::ELF::Elf64_Sym> syms, const uint32_t textOff)
768 {
769     using Elf64_Rela = llvm::ELF::Elf64_Rela;
770     for (Elf64_Rela &rela : relas) {
771         switch (rela.getType()) {
772             case llvm::ELF::R_X86_64_PLT32: {
773                 // the reloc symbol is also in stub.an, so fallback to R_X86_64_PC32
774                 uint32_t relocOff = textOff + rela.r_offset;
775                 auto symIdx = rela.getSymbol();
776                 uint32_t value = syms[symIdx].st_value + rela.r_addend - relocOff;
777                 // Target = Symbol Value + Addend − Relocation Address
778                 elfFile.seekp(relocOff);
779                 elfFile.write(reinterpret_cast<char *>(&value), sizeof(value));
780                 break;
781             }
782             case llvm::ELF::R_X86_64_PC32: {
783 #ifndef NDEBUG
784                 // already handled by llvm backend, just need verify it for debug.
785                 auto symIdx = rela.getSymbol();
786                 llvm::ELF::Elf64_Sym sym = syms[symIdx];
787                 if (sym.getBinding() == llvm::ELF::STB_LOCAL) {
788                     break;
789                 }
790                 uint32_t relocOff = textOff + rela.r_offset;
791                 uint32_t value = sym.st_value + rela.r_addend - relocOff;
792                 elfFile.seekg(relocOff);
793                 uint32_t oldValue = 0;
794                 elfFile.read(reinterpret_cast<char *>(&oldValue), sizeof(oldValue));
795                 if (oldValue != value) {
796                     LOG_ECMA(FATAL) << "Maybe incorrect relocate result, expect: " << value << ", but got: " << oldValue
797                         << " binding: " << static_cast<uint32_t>(sym.getBinding()) << std::endl;
798                 }
799 #endif
800                 break;
801             }
802             default:
803                 LOG_ECMA(FATAL) << "Unhandled relocate type: " << rela.getType() << std::endl;
804         }
805     }
806 }
807 
ResolveRelocate(std::fstream & elfFile)808 void ElfBuilder::ResolveRelocate(std::fstream &elfFile)
809 {
810     if (!enableOptDirectCall_) {
811         return;
812     }
813     elfFile.flush();
814     using Elf64_Sym = llvm::ELF::Elf64_Sym;
815     using Elf64_Rela = llvm::ELF::Elf64_Rela;
816     ASSERT(stubTextOffset_.size() == des_.size());
817 
818     for (size_t idx = 0; idx < des_.size(); ++idx) {
819         uint32_t relaSecSize = des_[idx].GetSecSize(ElfSecName::RELATEXT);
820         uint64_t relaSecAddr = des_[idx].GetSecAddr(ElfSecName::RELATEXT);
821         Elf64_Rela *relas = reinterpret_cast<Elf64_Rela *>(relaSecAddr);
822         size_t relas_num = relaSecSize / sizeof(Elf64_Rela);
823 
824         uint32_t symSecSize = des_[idx].GetSecSize(ElfSecName::SYMTAB);
825         uint64_t symSecAddr = des_[idx].GetSecAddr(ElfSecName::SYMTAB);
826         Elf64_Sym *syms = reinterpret_cast<Elf64_Sym *>(symSecAddr);
827         size_t syms_num = symSecSize / sizeof(Elf64_Sym);
828         const uint32_t textOff = stubTextOffset_[idx];
829         switch (triple_) {
830             case Triple::TRIPLE_AMD64:
831                 ResolveAmd64Relocate(elfFile, Span(relas, relas_num), Span(syms, syms_num), textOff);
832                 break;
833             case Triple::TRIPLE_AARCH64:
834                 ResolveAArch64Relocate(elfFile, Span(relas, relas_num), Span(syms, syms_num), textOff);
835                 break;
836             default:
837                 LOG_ECMA(FATAL) << "Unsupported triple when resolving relocate: " << static_cast<uint32_t>(triple_) <<
838                     std::endl;
839         }
840     }
841 }
842 
GetPFlag(ElfSecName segment) const843 unsigned ElfBuilder::GetPFlag(ElfSecName segment) const
844 {
845     return segmentToFlag_.at(segment);
846 }
847 
848 /*
849 segment layout as follows:
850 An Elf file
851 Entry point 0x0
852 There are 2 program headers, starting at offset 16384
853 
854 Program Headers:
855   Type    Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
856   LOAD    0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000f61 0x0000000000001000  R E    0x1000
857   LOAD    0x0000000000002000 0x0000000000002000 0x0000000000002000 0x000000000000115e 0x0000000000002000  R      0x1000
858 
859  Section to Segment mapping:
860   Segment Sections...
861    00     .text
862    01     .strtab .symtab .shstrtab .ark_funcentry .ark_stackmaps .ark_checksuminfo
863 ------------------------------------------------------------------------------------------------------------------------------
864 Stub Elf file
865 Entry point 0x0
866 There are 2 program headers, starting at offset 770048
867 
868 Program Headers:
869   Type     Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
870   LOAD     0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000085020 0x0000000000086000  R E    0x1000
871   LOAD     0x0000000000087000 0x0000000000087000 0x0000000000087000 0x0000000000035bbc 0x0000000000036000  R      0x1000
872 
873  Section to Segment mapping:
874   Segment Sections...
875    00     .text .ark_asmstub
876    01     .shstrtab .ark_funcentry .ark_stackmaps .ark_moduleinfo
877 */
PackELFSegment(std::fstream & file)878 void ElfBuilder::PackELFSegment(std::fstream &file)
879 {
880     llvm::ELF::Elf64_Off e_phoff = static_cast<uint64_t>(file.tellp());
881     long phoff = (long)offsetof(struct llvm::ELF::Elf64_Ehdr, e_phoff);
882     // write Elf32_Off e_phoff
883     file.seekp(phoff);
884     file.write(reinterpret_cast<char *>(&e_phoff), sizeof(e_phoff));
885     file.seekp(static_cast<long>(e_phoff));
886 
887     size_t segNum = GetSegmentNum();
888     auto phdrs = std::make_unique<llvm::ELF::Elf64_Phdr []>(segNum);
889     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxOffset;
890     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxAddress;
891     std::set<ElfSecName> segments;
892     // SecName -> addr & size
893     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
894     llvm::ELF::Elf64_Off offset = e_phoff;
895     for (auto &s: sections) {
896         ElfSection section = ElfSection(s.first);
897         if (!section.ShouldDumpToAOTFile()) {
898             continue;
899         }
900         auto it = sectionToSegment_.find(s.first);
901         ASSERT(it != sectionToSegment_.end());
902         ElfSecName segName = it->second;
903         segments.insert(segName);
904         if (segmentToMaxOffset.find(segName) == segmentToMaxOffset.end()) {
905             segmentToMaxOffset[segName] = 0;
906         }
907         segmentToMaxOffset[segName] =
908             std::max(segmentToMaxOffset[segName], sectionToShdr_[s.first].sh_offset + sectionToShdr_[s.first].sh_size);
909         segmentToMaxAddress[segName] =
910             std::max(segmentToMaxAddress[segName], sectionToShdr_[s.first].sh_addr + sectionToShdr_[s.first].sh_size);
911         offset = std::min(offset, sectionToShdr_[s.first].sh_offset);
912     }
913     int phdrIndex = 0;
914     llvm::ELF::Elf64_Addr addr = offset;
915     for (auto &it: segments) {
916         ElfSecName name = it;
917         phdrs[phdrIndex].p_align = PageSize();
918         phdrs[phdrIndex].p_type = llvm::ELF::PT_LOAD;
919         phdrs[phdrIndex].p_flags = GetPFlag(name);
920         offset = AlignUp(offset, PageSize());
921         phdrs[phdrIndex].p_offset = offset;
922         phdrs[phdrIndex].p_vaddr = addr % phdrs[phdrIndex].p_align == 0 ?
923             addr : (addr / phdrs[phdrIndex].p_align + 1) * phdrs[phdrIndex].p_align;
924         phdrs[phdrIndex].p_paddr = phdrs[phdrIndex].p_vaddr;
925 
926         phdrs[phdrIndex].p_filesz = segmentToMaxOffset[name] - phdrs[phdrIndex].p_offset;
927         phdrs[phdrIndex].p_memsz = segmentToMaxAddress[name] - phdrs[phdrIndex].p_vaddr;
928         phdrs[phdrIndex].p_memsz = AlignUp(phdrs[phdrIndex].p_memsz, PageSize());
929         addr = phdrs[phdrIndex].p_vaddr + phdrs[phdrIndex].p_memsz;
930         offset += phdrs[phdrIndex].p_filesz;
931         ++phdrIndex;
932     }
933     file.write(reinterpret_cast<char *>(phdrs.get()), sizeof(llvm::ELF::Elf64_Phdr) * segNum);
934 }
935 
CalculateTotalFileSize()936 size_t ElfBuilder::CalculateTotalFileSize()
937 {
938     uint32_t moduleNum = des_.size();
939     const auto &sections = GetFullSecInfo();
940     uint32_t secNum = sections.size() + 1;  // +1 for null section
941     llvm::ELF::Elf64_Off curOffset = ComputeEndAddrOfShdr(secNum);
942 
943     for (auto const &[secName, secInfo] : sections) {
944         ElfSection section = ElfSection(secName);
945         if (!section.ShouldDumpToAOTFile()) {
946             continue;
947         }
948         auto align = sectionToAlign_[secName];
949         curOffset = AlignUp(curOffset, align);
950 
951         switch (secName) {
952             case ElfSecName::ARK_MODULEINFO: {
953                 uint32_t curSecSize = sizeof(ModuleSectionDes::ModuleRegionInfo) * moduleNum;
954                 curOffset = AlignUp(curOffset, align);
955                 curOffset += curSecSize;
956                 break;
957             }
958             case ElfSecName::TEXT: {
959                 CalculateTextSectionSize(curOffset);
960                 break;
961             }
962             case ElfSecName::ARK_STACKMAP: {
963                 for (auto &des : des_) {
964                     curOffset += des.GetSecSize(ElfSecName::ARK_STACKMAP);
965                 }
966                 break;
967             }
968             case ElfSecName::STRTAB: {
969                 CalculateStrTabSectionSize(curOffset);
970                 break;
971             }
972             case ElfSecName::SYMTAB: {
973                 CalculateSymTabSectionSize(curOffset);
974                 break;
975             }
976             case ElfSecName::SHSTRTAB:
977             case ElfSecName::ARK_FUNCENTRY:
978             case ElfSecName::ARK_ASMSTUB:
979             case ElfSecName::ARK_CHECKSUMINFO: {
980                 uint32_t curSecSize = des_[FullSecIndex].GetSecSize(secName);
981                 curOffset = AlignUp(curOffset, align);
982                 curOffset += curSecSize;
983                 break;
984             }
985             default: {
986                 LOG_COMPILER(FATAL) << "this section should not be included in file size calculation";
987                 break;
988             }
989         }
990 
991         if (secName == lastDataSection || secName == lastCodeSection) {
992             curOffset = AlignUp(curOffset, PageSize());
993         }
994     }
995     // calcutelate segment
996     curOffset += GetSegmentNum() * sizeof(llvm::ELF::Elf64_Phdr);
997     return curOffset;
998 }
999 
CalculateTextSectionSize(llvm::ELF::Elf64_Off & curOffset)1000 void ElfBuilder::CalculateTextSectionSize(llvm::ELF::Elf64_Off &curOffset)
1001 {
1002     for (ModuleSectionDes &des : des_) {
1003         curOffset = AlignUp(curOffset, AOTFileInfo::PAGE_ALIGN);
1004         uint32_t textSize = des.GetSecSize(ElfSecName::TEXT);
1005         uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
1006         uint64_t rodataAddrBeforeText = 0;
1007         uint32_t rodataSizeBeforeText = 0;
1008         uint64_t rodataAddrAfterText = 0;
1009         uint32_t rodataSizeAfterText = 0;
1010         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
1011             des.GetMergedRODataAddrAndSize(textAddr);
1012 
1013         if (rodataSizeBeforeText != 0) {
1014             curOffset += rodataSizeBeforeText;
1015             curOffset = AlignUp(curOffset, AOTFileInfo::TEXT_SEC_ALIGN);
1016         }
1017         curOffset += textSize;
1018         if (rodataSizeAfterText != 0) {
1019             curOffset = AlignUp(curOffset, AOTFileInfo::RODATA_SEC_ALIGN);
1020             curOffset += rodataSizeAfterText;
1021         }
1022     }
1023 }
1024 
CalculateStrTabSectionSize(llvm::ELF::Elf64_Off & curOffset)1025 void ElfBuilder::CalculateStrTabSectionSize(llvm::ELF::Elf64_Off &curOffset)
1026 {
1027     for (auto &des : des_) {
1028         uint32_t curSecSize = des.GetSecSize(ElfSecName::STRTAB);
1029         curOffset += curSecSize;
1030         if (des.HasAsmStubStrTab()) {
1031             const auto &asmStubInfo = des.GetAsmStubELFInfo();
1032             uint32_t asmStubStrSize = 1;  // 1 for null string
1033             uint32_t asmStubSymTabNum = asmStubInfo.size() - 1;
1034             for (size_t idx = 0; idx < asmStubSymTabNum; ++idx) {
1035                 asmStubStrSize += asmStubInfo[idx].first.size() + 1;  // +1 for null terminator
1036             }
1037             curOffset += asmStubStrSize;
1038         }
1039     }
1040 }
1041 
CalculateSymTabSectionSize(llvm::ELF::Elf64_Off & curOffset)1042 void ElfBuilder::CalculateSymTabSectionSize(llvm::ELF::Elf64_Off &curOffset)
1043 {
1044     for (auto &des : des_) {
1045         curOffset += des.GetSecSize(ElfSecName::SYMTAB);
1046         if (des.HasAsmStubStrTab()) {
1047             const auto &asmStubInfo = des.GetAsmStubELFInfo();
1048             uint32_t asmStubSymTabNum = asmStubInfo.size() - 1;
1049             curOffset += asmStubSymTabNum * sizeof(llvm::ELF::Elf64_Sym);
1050         }
1051     }
1052 }
1053 }  // namespace panda::ecmascript
1054