• 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     struct symInfo {
473         size_t addr_;
474         size_t size_;
475     };
476     std::map<std::string, symInfo> asmStubToAddr;
477     for (auto &des : des_) {
478         if (!des.HasAsmStubStrTab()) {
479             continue;
480         }
481 
482         const std::vector<std::pair<std::string, uint32_t>> &asmStubELFInfo = des.GetAsmStubELFInfo();
483 
484         auto end = asmStubELFInfo.cend();
485         for (auto iter = asmStubELFInfo.cbegin(); iter != end; ++iter) {
486             auto& [name, offset] = *iter;
487             auto nextIt = std::next(iter);
488             size_t symAddr = asmStubOffset + offset;
489             size_t symSize = 0;
490             if (nextIt != end) {
491                 symSize = nextIt->second - offset;
492             } else {
493                 symSize = des.GetSecSize(ElfSecName::ARK_ASMSTUB) - offset;
494             }
495             if (auto [result, inserted] = asmStubToAddr.try_emplace(name, symInfo{symAddr, symSize}); !inserted) {
496                 LOG_COMPILER(FATAL) << "Duplicate asm symbol: " << name << std::endl;
497             }
498             if (nameToSym.find(name) != nameToSym.end()) {
499                 LOG_COMPILER(FATAL) << "Duplicate asm symbol with ir symbol: " << name << std::endl;
500             }
501         }
502     }
503     uint32_t asmSecIndex = GetShIndex(ElfSecName::ARK_ASMSTUB);
504     for (auto &[name, undefSymVec] : undefSyms) {
505         auto targetSymIter = nameToSym.find(name);
506         if (targetSymIter != nameToSym.end()) {
507             for (auto undefSym : undefSymVec) {
508                 // preempt with defined symbol.
509                 *undefSym = *targetSymIter->second;
510             }
511             continue;
512         }
513         auto asmTargetSymIter = asmStubToAddr.find(std::string(name));
514         if (asmTargetSymIter != asmStubToAddr.end()) {
515             for (auto undefSym : undefSymVec) {
516                 // preempt with defined symbol.
517                 undefSym->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_FUNC);
518                 undefSym->st_shndx = static_cast<uint16_t>(asmSecIndex);
519                 undefSym->st_value = asmTargetSymIter->second.addr_;
520                 undefSym->st_size = asmTargetSymIter->second.size_;
521                 undefSym->st_other = llvm::ELF::STV_DEFAULT;
522             }
523             continue;
524         }
525         LOG_COMPILER(FATAL) << "Undefined symbol: " << name << std::endl;
526     }
527 }
528 
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)529 void ElfBuilder::CollectUndefSyms(std::map<std::string_view, llvm::ELF::Elf64_Sym *> &nameToSym,
530                                   std::map<std::string_view, std::vector<llvm::ELF::Elf64_Sym *>> &undefSyms,
531                                   llvm::ELF::Elf64_Sym *sy, std::string_view symName)
532 {
533     if (!enableOptDirectCall_) {
534         return;
535     }
536     if (sy->getBinding() == llvm::ELF::STB_LOCAL) {
537         // local symbol should be relocated when compiling, so skip them.
538         return;
539     }
540     if (sy->st_shndx != llvm::ELF::SHN_UNDEF) {
541         if (auto [iter, inserted] = nameToSym.try_emplace(symName, sy); !inserted) {
542             LOG_COMPILER(FATAL) << "Duplicate symbol: " << symName << std::endl;
543         }
544     } else {
545         auto [iter, inserted] = undefSyms.try_emplace(symName);
546         iter->second.push_back(sy);
547     }
548 }
549 
FixSymtab(llvm::ELF::Elf64_Shdr * shdr,llvm::ELF::Elf64_Off asmStubOffset)550 void ElfBuilder::FixSymtab(llvm::ELF::Elf64_Shdr* shdr, llvm::ELF::Elf64_Off asmStubOffset)
551 {
552     using Elf64_Sym = llvm::ELF::Elf64_Sym;
553     ASSERT(stubTextOffset_.size() == des_.size());
554     std::map<std::string_view, llvm::ELF::Elf64_Sym*> nameToSym;
555     std::map<std::string_view, std::vector<llvm::ELF::Elf64_Sym*>> undefSyms;
556     uint32_t secNum = static_cast<uint32_t>(GetSecNum());
557     uint32_t shStrTabIndex = GetShIndex(ElfSecName::SHSTRTAB);
558     uint32_t strTabIndex = GetShIndex(ElfSecName::STRTAB);
559     uint32_t textSecIndex = GetShIndex(ElfSecName::TEXT);
560 
561     uint32_t strTabSize = 0;
562     int firstGlobal = -1;
563     uint32_t count = 0;
564     for (size_t idx = 0; idx < des_.size(); ++idx) {
565         uint64_t strTabAddr = des_[idx].GetSecAddr(ElfSecName::STRTAB);
566         uint32_t secSize = des_[idx].GetSecSize(ElfSecName::SYMTAB);
567         uint64_t secAddr = des_[idx].GetSecAddr(ElfSecName::SYMTAB);
568         Elf64_Sym *syms = reinterpret_cast<Elf64_Sym*>(secAddr);
569         size_t n = secSize / sizeof(Elf64_Sym);
570         for (size_t i = 0; i < n; ++i) {
571             Elf64_Sym* sy = &syms[i];
572             std::string_view symName(reinterpret_cast<char *>(strTabAddr + sy->st_name));
573             if (sy->getBinding() == llvm::ELF::STB_GLOBAL && firstGlobal == -1) {
574                 firstGlobal = static_cast<int>(count);
575             }
576             if (sy->getType() == llvm::ELF::STT_SECTION) {
577                 sy->st_shndx = static_cast<uint16_t>(shStrTabIndex);
578             } else if (sy->getType() == llvm::ELF::STT_FUNC) {
579                 sy->st_shndx = static_cast<uint16_t>(textSecIndex);
580                 sy->st_value += stubTextOffset_[idx];
581             }
582             if (sy->st_shndx > secNum) {
583                 sy->st_shndx = 0;
584             }
585             sy->st_name += strTabSize;
586             count++;
587             CollectUndefSyms(nameToSym, undefSyms, sy, symName);
588         }
589         strTabSize += des_[idx].GetSecSize(ElfSecName::STRTAB);
590     }
591     shdr->sh_info = static_cast<uint32_t>(firstGlobal);
592     shdr->sh_link = strTabIndex;
593     FixUndefinedSymbols(nameToSym, undefSyms, asmStubOffset);
594 }
595 
596 /*
597 
598 section of aot.an layout as follows:
599 There are 7 section headers, starting at offset 0x40:
600 
601 Section Headers:
602   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
603   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
604   [ 1] .text             PROGBITS         0000000000001000  00001000  0000000000000f61  0000000000000000  AX       0     0     16
605   [ 2] .strtab           STRTAB           0000000000002000  00002000  0000000000000187  0000000000000000   A       0     0     1
606   [ 3] .symtab           SYMTAB           0000000000002188  00002188  00000000000001c8  0000000000000018   A       1     0     8
607   [ 4] .shstrtab         STRTAB           0000000000002350  00002350  000000000000003f  0000000000000000   A       0     0     8
608   [ 5] .ark_funcentry    PROGBITS         0000000000002390  00002390  00000000000006c0  0000000000000000   A       0     0     8
609   [ 6] .ark_stackmaps    PROGBITS         0000000000002a50  00002a50  000000000000070e  0000000000000000   A       0     0     8
610   [ 7] .ark_checksuminfo PROGBITS         000000000000315e  0000315e  0000000000000028  0000000000000000   A       0     0     8
611 
612 section of stub.an layout as follows:
613 There are 7 section headers, starting at offset 0x40:
614 
615   [Nr] Name              Type             Address           Offset    Size              EntSize          Flags  Link  Info  Align
616   [ 0]                   NULL             0000000000000000  00000000  0000000000000000  0000000000000000           0     0     0
617   [ 1] .text             PROGBITS         0000000000001000  00001000  000000000008225e  0000000000000000  AX       0     0     16
618   [ 2] .ark_asmstub      PROGBITS         0000000000083260  00083260  0000000000002dc0  0000000000000000  AX       0     0     8
619   [ 3] .shstrtab         STRTAB           0000000000087000  00087000  000000000000004c  0000000000000000   A       0     0     8
620   [ 4] .ark_funcentry    PROGBITS         0000000000087050  00087050  0000000000023ca0  0000000000000000   A       0     0     8
621   [ 5] .ark_stackmaps    PROGBITS         00000000000aacf0  000aacf0  0000000000011e90  0000000000000000   A       0     0     8
622   [ 6] .ark_moduleinfo   PROGBITS         00000000000bcb80  000bcb80  000000000000003c  0000000000000000   A       0     0     8
623 
624 Key to Flags:
625   W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
626   L (link order), O (extra OS processing required), G (group), T (TLS),
627   C (compressed), x (unknown), o (OS specific), E (exclude),
628   D (mbind), l (large), p (processor specific)
629 */
PackELFSections(std::fstream & file)630 void ElfBuilder::PackELFSections(std::fstream &file)
631 {
632     uint32_t moduleNum = des_.size();
633     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
634     uint32_t secNum = sections.size() + 1; // 1 : section id = 0 is null section
635     std::unique_ptr<llvm::ELF::Elf64_Shdr []> shdr;
636     AllocateShdr(shdr, secNum);
637     std::vector<ModuleSectionDes::ModuleRegionInfo> moduleInfo(moduleNum);
638     llvm::ELF::Elf64_Off curSecOffset = ComputeEndAddrOfShdr(secNum);
639     file.seekp(curSecOffset);
640 
641     int i = static_cast<int>(GetShIndex(ElfSecName::TEXT));
642     auto shStrTab = FindShStrTab();
643 
644     for (auto const &[secName, secInfo] : sections) {
645         auto &curShdr = shdr[i];
646         ElfSection section = ElfSection(secName);
647         if (!section.ShouldDumpToAOTFile()) {
648             continue;
649         }
650         curShdr.sh_addralign = sectionToAlign_[secName];
651         curSecOffset = AlignUp(curSecOffset, curShdr.sh_addralign);
652         file.seekp(curSecOffset);
653         ElfSecName segName = GetSegmentName(secName);
654         segments_.insert(segName);
655         std::string secNameStr = ModuleSectionDes::GetSecName(secName);
656         // text section address needs 16 bytes alignment
657         if (secName == ElfSecName::TEXT) {
658             curSecOffset = AlignUp(curSecOffset, AOTFileInfo::PAGE_ALIGN);
659             file.seekp(curSecOffset);
660         }
661         llvm::ELF::Elf64_Word shName = FindShName(secNameStr, shStrTab.first, shStrTab.second);
662         ASSERT(shName != static_cast<llvm::ELF::Elf64_Word>(-1));
663         curShdr.sh_name = shName;
664         curShdr.sh_type = section.Type();
665         curShdr.sh_flags = section.Flag();
666         curShdr.sh_addr = curSecOffset;
667         curShdr.sh_offset = static_cast<uint64_t>(curSecOffset);
668         curShdr.sh_info = 0;
669         curShdr.sh_link = static_cast<uint32_t>(section.Link());
670         sectionToFileOffset_[secName] = static_cast<uintptr_t>(file.tellp());
671         switch (secName) {
672             case ElfSecName::ARK_MODULEINFO: {
673                 uint32_t curSecSize = sizeof(ModuleSectionDes::ModuleRegionInfo) * moduleInfo.size();
674                 file.write(reinterpret_cast<char *>(moduleInfo.data()), curSecSize);
675                 curSecOffset += curSecSize;
676                 curShdr.sh_size = curSecSize;
677                 break;
678             }
679             case ElfSecName::TEXT: {
680                 uint32_t curSize = curSecOffset;
681                 MergeTextSections(file, moduleInfo, curSecOffset);
682                 curShdr.sh_size = curSecOffset - curSize;
683                 break;
684             }
685             case ElfSecName::ARK_STACKMAP: {
686                 uint32_t curSize = curSecOffset;
687                 MergeArkStackMapSections(file, moduleInfo, curSecOffset);
688                 curShdr.sh_size = curSecOffset - curSize;
689                 break;
690             }
691             case ElfSecName::STRTAB: {
692                 uint32_t curSize = curSecOffset;
693                 MergeStrtabSections(file, moduleInfo, curSecOffset);
694                 curShdr.sh_size = curSecOffset - curSize;
695                 break;
696             }
697             case ElfSecName::SYMTAB: {
698                 uint32_t curSize = curSecOffset;
699                 uint32_t asmSecIndex = GetShIndex(ElfSecName::ARK_ASMSTUB);
700                 uint64_t asmStubOffset = shdr[asmSecIndex].sh_offset;
701                 FixSymtab(&curShdr, asmStubOffset);
702                 MergeSymtabSections(file, moduleInfo, curSecOffset, asmStubOffset);
703                 curShdr.sh_size = curSecOffset - curSize;
704                 break;
705             }
706             case ElfSecName::SHSTRTAB:
707             case ElfSecName::ARK_FUNCENTRY:
708             case ElfSecName::ARK_ASMSTUB:
709             case ElfSecName::ARK_CHECKSUMINFO: {
710                 uint32_t curSecSize = des_[FullSecIndex].GetSecSize(secName);
711                 uint64_t curSecAddr = des_[FullSecIndex].GetSecAddr(secName);
712                 file.write(reinterpret_cast<char *>(curSecAddr), curSecSize);
713                 curSecOffset += curSecSize;
714                 curShdr.sh_size = curSecSize;
715                 break;
716             }
717             default: {
718                 LOG_ECMA(FATAL) << "this section should not dump to an file";
719                 break;
720             }
721         }
722         if (secName == lastDataSection || secName == lastCodeSection) {
723             curSecOffset = AlignUp(curSecOffset, PageSize());
724             file.seekp(curSecOffset);
725         }
726         curShdr.sh_entsize = static_cast<uint64_t>(section.Entsize());
727         sectionToShdr_[secName] = curShdr;
728         LOG_COMPILER(DEBUG) << "  shdr[i].sh_entsize " << std::hex << curShdr.sh_entsize << std::endl;
729         ++i;
730     }
731     uint32_t secEnd = static_cast<uint32_t>(file.tellp());
732     ResolveRelocate(file);
733     file.seekp(sizeof(llvm::ELF::Elf64_Ehdr));
734     file.write(reinterpret_cast<char *>(shdr.get()), secNum * sizeof(llvm::ELF::Elf64_Shdr));
735     file.seekp(secEnd);
736 }
737 
ResolveAArch64Relocate(std::fstream & elfFile,Span<llvm::ELF::Elf64_Rela> relas,Span<llvm::ELF::Elf64_Sym> syms,const uint32_t textOff)738 void ElfBuilder::ResolveAArch64Relocate(std::fstream &elfFile, Span<llvm::ELF::Elf64_Rela> relas,
739                                         Span<llvm::ELF::Elf64_Sym> syms, const uint32_t textOff)
740 {
741     using Elf64_Rela = llvm::ELF::Elf64_Rela;
742     for (Elf64_Rela &rela : relas) {
743         switch (rela.getType()) {
744             case llvm::ELF::R_AARCH64_JUMP26:
745             case llvm::ELF::R_AARCH64_CALL26: {
746                 // the reloc symbol is also in stub.an, calculate the relative offset.
747                 auto symIdx = rela.getSymbol();
748                 llvm::ELF::Elf64_Sym sym = syms[symIdx];
749                 if (sym.getBinding() == llvm::ELF::STB_LOCAL) {
750                     break;
751                 }
752                 uint32_t relocOff = textOff + rela.r_offset;
753                 uint32_t value = sym.st_value + rela.r_addend - relocOff;
754                 // Target = Symbol Value + Addend − Relocation Address
755                 if (!(IMM28_MIN <= static_cast<int32_t>(value) && static_cast<int32_t>(value) < IMM28_MAX)) {
756                     LOG_ECMA(FATAL) << "relocate target out of imm28 range: " << value << std::endl;
757                 }
758                 elfFile.seekg(relocOff);
759                 uint32_t oldVal = 0;
760                 elfFile.read(reinterpret_cast<char *>(&oldVal), sizeof(uint32_t));
761                 value = (oldVal & 0xFC000000) | ((value & 0x0FFFFFFC) >> DIV4_BITS);
762                 // 0xFC000000: 11111100 00000000 00000000 00000000, get the high 6 bit as the opcode.
763                 // 0x0FFFFFFC: 00001111 11111111 11111111 11111100, use this mask to get imm26 from the value.
764                 // the instructions must be bl or b, they accept a 26-bits imm int, so clear the low 26-bits in the old
765                 // instruction(it maybe wrong because llvm backend may fill some JITEngine reloc data in it). And fill
766                 // it with the calculated target.
767                 elfFile.seekp(relocOff);
768                 elfFile.write(reinterpret_cast<char *>(&value), sizeof(value));
769                 break;
770             }
771             case llvm::ELF::R_AARCH64_ADR_PREL_PG_HI21:
772             case llvm::ELF::R_AARCH64_ADD_ABS_LO12_NC:
773                 // data relocation, already handled by llvm backend, ignore it.
774                 break;
775             default:
776                 LOG_ECMA(FATAL) << "Unhandled relocate type: " << rela.getType() << std::endl;
777         }
778     }
779 }
780 
ResolveAmd64Relocate(std::fstream & elfFile,Span<llvm::ELF::Elf64_Rela> relas,Span<llvm::ELF::Elf64_Sym> syms,const uint32_t textOff)781 void ElfBuilder::ResolveAmd64Relocate(std::fstream &elfFile, Span<llvm::ELF::Elf64_Rela> relas,
782                                       Span<llvm::ELF::Elf64_Sym> syms, const uint32_t textOff)
783 {
784     using Elf64_Rela = llvm::ELF::Elf64_Rela;
785     for (Elf64_Rela &rela : relas) {
786         switch (rela.getType()) {
787             case llvm::ELF::R_X86_64_PLT32: {
788                 // the reloc symbol is also in stub.an, so fallback to R_X86_64_PC32
789                 uint32_t relocOff = textOff + rela.r_offset;
790                 auto symIdx = rela.getSymbol();
791                 uint32_t value = syms[symIdx].st_value + rela.r_addend - relocOff;
792                 // Target = Symbol Value + Addend − Relocation Address
793                 elfFile.seekp(relocOff);
794                 elfFile.write(reinterpret_cast<char *>(&value), sizeof(value));
795                 break;
796             }
797             case llvm::ELF::R_X86_64_PC32: {
798 #ifndef NDEBUG
799                 // already handled by llvm backend, just need verify it for debug.
800                 auto symIdx = rela.getSymbol();
801                 llvm::ELF::Elf64_Sym sym = syms[symIdx];
802                 if (sym.getBinding() == llvm::ELF::STB_LOCAL) {
803                     break;
804                 }
805                 uint32_t relocOff = textOff + rela.r_offset;
806                 uint32_t value = sym.st_value + rela.r_addend - relocOff;
807                 elfFile.seekg(relocOff);
808                 uint32_t oldValue = 0;
809                 elfFile.read(reinterpret_cast<char *>(&oldValue), sizeof(oldValue));
810                 if (oldValue != value) {
811                     LOG_ECMA(FATAL) << "Maybe incorrect relocate result, expect: " << value << ", but got: " << oldValue
812                         << " binding: " << static_cast<uint32_t>(sym.getBinding()) << std::endl;
813                 }
814 #endif
815                 break;
816             }
817             default:
818                 LOG_ECMA(FATAL) << "Unhandled relocate type: " << rela.getType() << std::endl;
819         }
820     }
821 }
822 
ResolveRelocate(std::fstream & elfFile)823 void ElfBuilder::ResolveRelocate(std::fstream &elfFile)
824 {
825     if (!enableOptDirectCall_) {
826         return;
827     }
828     elfFile.flush();
829     using Elf64_Sym = llvm::ELF::Elf64_Sym;
830     using Elf64_Rela = llvm::ELF::Elf64_Rela;
831     ASSERT(stubTextOffset_.size() == des_.size());
832 
833     for (size_t idx = 0; idx < des_.size(); ++idx) {
834         uint32_t relaSecSize = des_[idx].GetSecSize(ElfSecName::RELATEXT);
835         uint64_t relaSecAddr = des_[idx].GetSecAddr(ElfSecName::RELATEXT);
836         Elf64_Rela *relas = reinterpret_cast<Elf64_Rela *>(relaSecAddr);
837         size_t relas_num = relaSecSize / sizeof(Elf64_Rela);
838 
839         uint32_t symSecSize = des_[idx].GetSecSize(ElfSecName::SYMTAB);
840         uint64_t symSecAddr = des_[idx].GetSecAddr(ElfSecName::SYMTAB);
841         Elf64_Sym *syms = reinterpret_cast<Elf64_Sym *>(symSecAddr);
842         size_t syms_num = symSecSize / sizeof(Elf64_Sym);
843         const uint32_t textOff = stubTextOffset_[idx];
844         switch (triple_) {
845             case Triple::TRIPLE_AMD64:
846                 ResolveAmd64Relocate(elfFile, Span(relas, relas_num), Span(syms, syms_num), textOff);
847                 break;
848             case Triple::TRIPLE_AARCH64:
849                 ResolveAArch64Relocate(elfFile, Span(relas, relas_num), Span(syms, syms_num), textOff);
850                 break;
851             default:
852                 LOG_ECMA(FATAL) << "Unsupported triple when resolving relocate: " << static_cast<uint32_t>(triple_) <<
853                     std::endl;
854         }
855     }
856 }
857 
GetPFlag(ElfSecName segment) const858 unsigned ElfBuilder::GetPFlag(ElfSecName segment) const
859 {
860     return segmentToFlag_.at(segment);
861 }
862 
863 /*
864 segment layout as follows:
865 An Elf file
866 Entry point 0x0
867 There are 2 program headers, starting at offset 16384
868 
869 Program Headers:
870   Type    Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
871   LOAD    0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000f61 0x0000000000001000  R E    0x1000
872   LOAD    0x0000000000002000 0x0000000000002000 0x0000000000002000 0x000000000000115e 0x0000000000002000  R      0x1000
873 
874  Section to Segment mapping:
875   Segment Sections...
876    00     .text
877    01     .strtab .symtab .shstrtab .ark_funcentry .ark_stackmaps .ark_checksuminfo
878 ------------------------------------------------------------------------------------------------------------------------------
879 Stub Elf file
880 Entry point 0x0
881 There are 2 program headers, starting at offset 770048
882 
883 Program Headers:
884   Type     Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
885   LOAD     0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000085020 0x0000000000086000  R E    0x1000
886   LOAD     0x0000000000087000 0x0000000000087000 0x0000000000087000 0x0000000000035bbc 0x0000000000036000  R      0x1000
887 
888  Section to Segment mapping:
889   Segment Sections...
890    00     .text .ark_asmstub
891    01     .shstrtab .ark_funcentry .ark_stackmaps .ark_moduleinfo
892 */
PackELFSegment(std::fstream & file)893 void ElfBuilder::PackELFSegment(std::fstream &file)
894 {
895     llvm::ELF::Elf64_Off e_phoff = static_cast<uint64_t>(file.tellp());
896     long phoff = (long)offsetof(struct llvm::ELF::Elf64_Ehdr, e_phoff);
897     // write Elf32_Off e_phoff
898     file.seekp(phoff);
899     file.write(reinterpret_cast<char *>(&e_phoff), sizeof(e_phoff));
900     file.seekp(static_cast<long>(e_phoff));
901 
902     size_t segNum = GetSegmentNum();
903     auto phdrs = std::make_unique<llvm::ELF::Elf64_Phdr []>(segNum);
904     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxOffset;
905     std::map<ElfSecName, llvm::ELF::Elf64_Off> segmentToMaxAddress;
906     std::set<ElfSecName> segments;
907     // SecName -> addr & size
908     const std::map<ElfSecName, std::pair<uint64_t, uint32_t>> &sections = GetFullSecInfo();
909     llvm::ELF::Elf64_Off offset = e_phoff;
910     for (auto &s: sections) {
911         ElfSection section = ElfSection(s.first);
912         if (!section.ShouldDumpToAOTFile()) {
913             continue;
914         }
915         auto it = sectionToSegment_.find(s.first);
916         ASSERT(it != sectionToSegment_.end());
917         ElfSecName segName = it->second;
918         segments.insert(segName);
919         if (segmentToMaxOffset.find(segName) == segmentToMaxOffset.end()) {
920             segmentToMaxOffset[segName] = 0;
921         }
922         segmentToMaxOffset[segName] =
923             std::max(segmentToMaxOffset[segName], sectionToShdr_[s.first].sh_offset + sectionToShdr_[s.first].sh_size);
924         segmentToMaxAddress[segName] =
925             std::max(segmentToMaxAddress[segName], sectionToShdr_[s.first].sh_addr + sectionToShdr_[s.first].sh_size);
926         offset = std::min(offset, sectionToShdr_[s.first].sh_offset);
927     }
928     int phdrIndex = 0;
929     llvm::ELF::Elf64_Addr addr = offset;
930     for (auto &it: segments) {
931         ElfSecName name = it;
932         phdrs[phdrIndex].p_align = PageSize();
933         phdrs[phdrIndex].p_type = llvm::ELF::PT_LOAD;
934         phdrs[phdrIndex].p_flags = GetPFlag(name);
935         offset = AlignUp(offset, PageSize());
936         phdrs[phdrIndex].p_offset = offset;
937         phdrs[phdrIndex].p_vaddr = addr % phdrs[phdrIndex].p_align == 0 ?
938             addr : (addr / phdrs[phdrIndex].p_align + 1) * phdrs[phdrIndex].p_align;
939         phdrs[phdrIndex].p_paddr = phdrs[phdrIndex].p_vaddr;
940 
941         phdrs[phdrIndex].p_filesz = segmentToMaxOffset[name] - phdrs[phdrIndex].p_offset;
942         phdrs[phdrIndex].p_memsz = segmentToMaxAddress[name] - phdrs[phdrIndex].p_vaddr;
943         phdrs[phdrIndex].p_memsz = AlignUp(phdrs[phdrIndex].p_memsz, PageSize());
944         addr = phdrs[phdrIndex].p_vaddr + phdrs[phdrIndex].p_memsz;
945         offset += phdrs[phdrIndex].p_filesz;
946         ++phdrIndex;
947     }
948     file.write(reinterpret_cast<char *>(phdrs.get()), sizeof(llvm::ELF::Elf64_Phdr) * segNum);
949 }
950 
CalculateTotalFileSize()951 size_t ElfBuilder::CalculateTotalFileSize()
952 {
953     uint32_t moduleNum = des_.size();
954     const auto &sections = GetFullSecInfo();
955     uint32_t secNum = sections.size() + 1;  // +1 for null section
956     llvm::ELF::Elf64_Off curOffset = ComputeEndAddrOfShdr(secNum);
957 
958     for (auto const &[secName, secInfo] : sections) {
959         ElfSection section = ElfSection(secName);
960         if (!section.ShouldDumpToAOTFile()) {
961             continue;
962         }
963         auto align = sectionToAlign_[secName];
964         curOffset = AlignUp(curOffset, align);
965 
966         switch (secName) {
967             case ElfSecName::ARK_MODULEINFO: {
968                 uint32_t curSecSize = sizeof(ModuleSectionDes::ModuleRegionInfo) * moduleNum;
969                 curOffset = AlignUp(curOffset, align);
970                 curOffset += curSecSize;
971                 break;
972             }
973             case ElfSecName::TEXT: {
974                 CalculateTextSectionSize(curOffset);
975                 break;
976             }
977             case ElfSecName::ARK_STACKMAP: {
978                 for (auto &des : des_) {
979                     curOffset += des.GetSecSize(ElfSecName::ARK_STACKMAP);
980                 }
981                 break;
982             }
983             case ElfSecName::STRTAB: {
984                 CalculateStrTabSectionSize(curOffset);
985                 break;
986             }
987             case ElfSecName::SYMTAB: {
988                 CalculateSymTabSectionSize(curOffset);
989                 break;
990             }
991             case ElfSecName::SHSTRTAB:
992             case ElfSecName::ARK_FUNCENTRY:
993             case ElfSecName::ARK_ASMSTUB:
994             case ElfSecName::ARK_CHECKSUMINFO: {
995                 uint32_t curSecSize = des_[FullSecIndex].GetSecSize(secName);
996                 curOffset = AlignUp(curOffset, align);
997                 curOffset += curSecSize;
998                 break;
999             }
1000             default: {
1001                 LOG_COMPILER(FATAL) << "this section should not be included in file size calculation";
1002                 break;
1003             }
1004         }
1005 
1006         if (secName == lastDataSection || secName == lastCodeSection) {
1007             curOffset = AlignUp(curOffset, PageSize());
1008         }
1009     }
1010     // calcutelate segment
1011     curOffset += GetSegmentNum() * sizeof(llvm::ELF::Elf64_Phdr);
1012     return curOffset;
1013 }
1014 
CalculateTextSectionSize(llvm::ELF::Elf64_Off & curOffset)1015 void ElfBuilder::CalculateTextSectionSize(llvm::ELF::Elf64_Off &curOffset)
1016 {
1017     for (ModuleSectionDes &des : des_) {
1018         curOffset = AlignUp(curOffset, AOTFileInfo::PAGE_ALIGN);
1019         uint32_t textSize = des.GetSecSize(ElfSecName::TEXT);
1020         uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
1021         uint64_t rodataAddrBeforeText = 0;
1022         uint32_t rodataSizeBeforeText = 0;
1023         uint64_t rodataAddrAfterText = 0;
1024         uint32_t rodataSizeAfterText = 0;
1025         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
1026             des.GetMergedRODataAddrAndSize(textAddr);
1027 
1028         if (rodataSizeBeforeText != 0) {
1029             curOffset += rodataSizeBeforeText;
1030             curOffset = AlignUp(curOffset, AOTFileInfo::TEXT_SEC_ALIGN);
1031         }
1032         curOffset += textSize;
1033         if (rodataSizeAfterText != 0) {
1034             curOffset = AlignUp(curOffset, AOTFileInfo::RODATA_SEC_ALIGN);
1035             curOffset += rodataSizeAfterText;
1036         }
1037     }
1038 }
1039 
CalculateStrTabSectionSize(llvm::ELF::Elf64_Off & curOffset)1040 void ElfBuilder::CalculateStrTabSectionSize(llvm::ELF::Elf64_Off &curOffset)
1041 {
1042     for (auto &des : des_) {
1043         uint32_t curSecSize = des.GetSecSize(ElfSecName::STRTAB);
1044         curOffset += curSecSize;
1045         if (des.HasAsmStubStrTab()) {
1046             const auto &asmStubInfo = des.GetAsmStubELFInfo();
1047             uint32_t asmStubStrSize = 1;  // 1 for null string
1048             uint32_t asmStubSymTabNum = asmStubInfo.size() - 1;
1049             for (size_t idx = 0; idx < asmStubSymTabNum; ++idx) {
1050                 asmStubStrSize += asmStubInfo[idx].first.size() + 1;  // +1 for null terminator
1051             }
1052             curOffset += asmStubStrSize;
1053         }
1054     }
1055 }
1056 
CalculateSymTabSectionSize(llvm::ELF::Elf64_Off & curOffset)1057 void ElfBuilder::CalculateSymTabSectionSize(llvm::ELF::Elf64_Off &curOffset)
1058 {
1059     for (auto &des : des_) {
1060         curOffset += des.GetSecSize(ElfSecName::SYMTAB);
1061         if (des.HasAsmStubStrTab()) {
1062             const auto &asmStubInfo = des.GetAsmStubELFInfo();
1063             uint32_t asmStubSymTabNum = asmStubInfo.size() - 1;
1064             curOffset += asmStubSymTabNum * sizeof(llvm::ELF::Elf64_Sym);
1065         }
1066     }
1067 }
1068 }  // namespace panda::ecmascript
1069