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