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>> §ions =
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>> §ions = 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> §ions,
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>> §ions = 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>> §ions = 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>> §ions = 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>> §ions = 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>> §ions = 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>> §ions = 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 §ions = 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