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