1 //===- subzero/src/IceELFObjectWriter.cpp - ELF object file writer --------===//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the writer for ELF relocatable object files.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Support/MathExtras.h"
16 #include "assembler.h"
18 #include "IceELFObjectWriter.h"
19 #include "IceELFSection.h"
20 #include "IceELFStreamer.h"
21 #include "IceGlobalContext.h"
22 #include "IceGlobalInits.h"
23 #include "IceOperand.h"
25 using namespace llvm::ELF;
36 #define X(tag, str, is_elf64, e_machine, e_flags) \
37 { is_elf64, e_machine, e_flags } \
43 bool isELF64(TargetArch Arch) {
44 if (Arch < TargetArch_NUM)
45 return ELFTargetInfo[Arch].IsELF64;
46 llvm_unreachable("Invalid target arch for isELF64");
50 uint16_t getELFMachine(TargetArch Arch) {
51 if (Arch < TargetArch_NUM)
52 return ELFTargetInfo[Arch].ELFMachine;
53 llvm_unreachable("Invalid target arch for getELFMachine");
57 uint32_t getELFFlags(TargetArch Arch) {
58 if (Arch < TargetArch_NUM)
59 return ELFTargetInfo[Arch].ELFFlags;
60 llvm_unreachable("Invalid target arch for getELFFlags");
64 } // end of anonymous namespace
66 ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out)
67 : Ctx(Ctx), Str(Out), SectionNumbersAssigned(false) {
68 // Create the special bookkeeping sections now.
69 const IceString NullSectionName("");
70 NullSection = new (Ctx.allocate<ELFSection>())
71 ELFSection(NullSectionName, SHT_NULL, 0, 0, 0);
73 const IceString ShStrTabName(".shstrtab");
74 ShStrTab = new (Ctx.allocate<ELFStringTableSection>())
75 ELFStringTableSection(ShStrTabName, SHT_STRTAB, 0, 1, 0);
76 ShStrTab->add(ShStrTabName);
78 const IceString SymTabName(".symtab");
79 bool IsELF64 = isELF64(Ctx.getTargetArch());
80 const Elf64_Xword SymTabAlign = IsELF64 ? 8 : 4;
81 const Elf64_Xword SymTabEntSize =
82 IsELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
83 static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16,
84 "Elf_Sym sizes cannot be derived from sizeof");
85 SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0,
86 SymTabAlign, SymTabEntSize);
87 // The first entry in the symbol table should be a NULL entry.
88 const IceString NullSymName("");
89 SymTab->createDefinedSym(NullSymName, STT_NOTYPE, STB_LOCAL, NullSection, 0,
92 const IceString StrTabName(".strtab");
94 createSection<ELFStringTableSection>(StrTabName, SHT_STRTAB, 0, 1, 0);
98 T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType,
99 Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
100 Elf64_Xword ShEntsize) {
101 assert(!SectionNumbersAssigned);
103 new (Ctx.allocate<T>()) T(Name, ShType, ShFlags, ShAddralign, ShEntsize);
108 ELFRelocationSection *
109 ELFObjectWriter::createRelocationSection(bool IsELF64,
110 const ELFSection *RelatedSection) {
111 // Choice of RELA vs REL is actually separate from elf64 vs elf32,
112 // but in practice we've only had .rela for elf64 (x86-64).
113 // In the future, the two properties may need to be decoupled
114 // and the ShEntSize can vary more.
115 const Elf64_Word ShType = IsELF64 ? SHT_RELA : SHT_REL;
116 IceString RelPrefix = IsELF64 ? ".rela" : ".rel";
117 IceString RelSectionName = RelPrefix + RelatedSection->getName();
118 const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
119 const Elf64_Xword ShEntSize =
120 IsELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
121 static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
122 "Elf_Rel/Rela sizes cannot be derived from sizeof");
123 const Elf64_Xword ShFlags = 0;
124 ELFRelocationSection *RelSection = createSection<ELFRelocationSection>(
125 RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
126 RelSection->setRelatedSection(RelatedSection);
130 template <typename UserSectionList>
131 void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
132 UserSectionList &UserSections,
133 RelSectionList &RelSections,
134 SectionList &AllSections) {
135 RelSectionList::iterator RelIt = RelSections.begin();
136 RelSectionList::iterator RelE = RelSections.end();
137 for (ELFSection *UserSection : UserSections) {
138 UserSection->setNumber(CurSectionNumber++);
139 UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName()));
140 AllSections.push_back(UserSection);
142 ELFRelocationSection *RelSection = *RelIt;
143 if (RelSection->getRelatedSection() == UserSection) {
144 RelSection->setInfoNum(UserSection->getNumber());
145 RelSection->setNumber(CurSectionNumber++);
146 RelSection->setNameStrIndex(ShStrTab->getIndex(RelSection->getName()));
147 AllSections.push_back(RelSection);
152 // Should finish with UserIt at the same time as RelIt.
153 assert(RelIt == RelE);
157 void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber,
158 RelSectionList &RelSections) {
159 for (ELFRelocationSection *S : RelSections) {
160 S->setLinkNum(SymTabNumber);
164 void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
165 // Go through each section, assigning them section numbers and
166 // and fill in the size for sections that aren't incrementally updated.
167 assert(!SectionNumbersAssigned);
168 SizeT CurSectionNumber = 0;
169 NullSection->setNumber(CurSectionNumber++);
170 // The rest of the fields are initialized to 0, and stay that way.
171 AllSections.push_back(NullSection);
173 assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections,
174 RelTextSections, AllSections);
175 assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections,
176 RelDataSections, AllSections);
177 for (ELFSection *BSSSection : BSSSections) {
178 BSSSection->setNumber(CurSectionNumber++);
179 BSSSection->setNameStrIndex(ShStrTab->getIndex(BSSSection->getName()));
180 AllSections.push_back(BSSSection);
182 assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RODataSections,
183 RelRODataSections, AllSections);
185 ShStrTab->setNumber(CurSectionNumber++);
186 ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName()));
187 AllSections.push_back(ShStrTab);
189 SymTab->setNumber(CurSectionNumber++);
190 SymTab->setNameStrIndex(ShStrTab->getIndex(SymTab->getName()));
191 AllSections.push_back(SymTab);
193 StrTab->setNumber(CurSectionNumber++);
194 StrTab->setNameStrIndex(ShStrTab->getIndex(StrTab->getName()));
195 AllSections.push_back(StrTab);
197 SymTab->setLinkNum(StrTab->getNumber());
198 SymTab->setInfoNum(SymTab->getNumLocals());
200 assignRelLinkNum(SymTab->getNumber(), RelTextSections);
201 assignRelLinkNum(SymTab->getNumber(), RelDataSections);
202 assignRelLinkNum(SymTab->getNumber(), RelRODataSections);
203 SectionNumbersAssigned = true;
206 Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
207 Elf64_Off OffsetInFile = Str.tell();
208 Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align);
211 Str.writeZeroPadding(AlignDiff);
212 OffsetInFile += AlignDiff;
216 void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
217 bool IsInternal, const Assembler *Asm) {
218 assert(!SectionNumbersAssigned);
219 ELFTextSection *Section = nullptr;
220 ELFRelocationSection *RelSection = nullptr;
221 if (TextSections.empty()) {
222 // TODO(jvoung): handle ffunction-sections.
223 IceString SectionName = ".text";
224 bool IsELF64 = isELF64(Ctx.getTargetArch());
225 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
226 // TODO(jvoung): Should be bundle size. Grab it from that target?
227 const Elf64_Xword ShAlign = 32;
228 Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags,
230 Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
231 Section->setFileOffset(OffsetInFile);
232 TextSections.push_back(Section);
233 RelSection = createRelocationSection(IsELF64, Section);
234 RelTextSections.push_back(RelSection);
236 Section = TextSections[0];
237 RelSection = RelTextSections[0];
239 RelocOffsetT OffsetInSection = Section->getCurrentSize();
240 // Function symbols are set to 0 size in the symbol table,
241 // in contrast to data symbols which have a proper size.
242 SizeT SymbolSize = 0;
243 Section->appendData(Str, Asm->getBufferView());
245 uint8_t SymbolBinding;
247 SymbolType = STT_NOTYPE;
248 SymbolBinding = STB_LOCAL;
250 SymbolType = STT_FUNC;
251 SymbolBinding = STB_GLOBAL;
253 SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section,
254 OffsetInSection, SymbolSize);
255 StrTab->add(FuncName);
257 // Create a relocation section for the text section if needed, and copy the
258 // fixup information from per-function Assembler memory to the object
259 // writer's memory, for writing later.
260 if (!Asm->fixups().empty()) {
261 RelSection->addRelocations(OffsetInSection, Asm->fixups());
267 ELFObjectWriter::SectionType
268 classifyGlobalSection(const VariableDeclaration *Var) {
269 if (Var->getIsConstant())
270 return ELFObjectWriter::ROData;
271 if (Var->hasNonzeroInitializer())
272 return ELFObjectWriter::Data;
273 return ELFObjectWriter::BSS;
276 // Partition the Vars list by SectionType into VarsBySection.
277 // If TranslateOnly is non-empty, then only the TranslateOnly variable
278 // is kept for emission.
279 void partitionGlobalsBySection(const VariableDeclarationList &Vars,
280 VariableDeclarationList VarsBySection[],
281 const IceString &TranslateOnly) {
282 for (VariableDeclaration *Var : Vars) {
283 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
284 size_t Section = classifyGlobalSection(Var);
285 assert(Section < ELFObjectWriter::NumSectionTypes);
286 VarsBySection[Section].push_back(Var);
291 } // end of anonymous namespace
293 void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
294 FixupKind RelocationKind) {
295 assert(!SectionNumbersAssigned);
296 VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
297 for (auto &SectionList : VarsBySection)
298 SectionList.reserve(Vars.size());
299 partitionGlobalsBySection(Vars, VarsBySection, Ctx.getFlags().TranslateOnly);
300 bool IsELF64 = isELF64(Ctx.getTargetArch());
302 for (auto &SectionList : VarsBySection) {
303 writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
308 void ELFObjectWriter::writeDataOfType(SectionType ST,
309 const VariableDeclarationList &Vars,
310 FixupKind RelocationKind, bool IsELF64) {
313 ELFDataSection *Section;
314 ELFRelocationSection *RelSection;
315 // TODO(jvoung): Handle fdata-sections.
316 IceString SectionName;
317 Elf64_Xword ShAddralign = 1;
318 for (VariableDeclaration *Var : Vars) {
319 Elf64_Xword Align = Var->getAlignment();
320 ShAddralign = std::max(ShAddralign, Align);
322 const Elf64_Xword ShEntsize = 0; // non-uniform data element size.
323 // Lift this out, so it can be re-used if we do fdata-sections?
326 SectionName = ".rodata";
327 // Only expecting to write the data sections all in one shot for now.
328 assert(RODataSections.empty());
329 const Elf64_Xword ShFlags = SHF_ALLOC;
330 Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
331 ShAddralign, ShEntsize);
332 Section->setFileOffset(alignFileOffset(ShAddralign));
333 RODataSections.push_back(Section);
334 RelSection = createRelocationSection(IsELF64, Section);
335 RelRODataSections.push_back(RelSection);
339 SectionName = ".data";
340 assert(DataSections.empty());
341 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
342 Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
343 ShAddralign, ShEntsize);
344 Section->setFileOffset(alignFileOffset(ShAddralign));
345 DataSections.push_back(Section);
346 RelSection = createRelocationSection(IsELF64, Section);
347 RelDataSections.push_back(RelSection);
351 SectionName = ".bss";
352 assert(BSSSections.empty());
353 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
354 Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
355 ShAddralign, ShEntsize);
356 Section->setFileOffset(alignFileOffset(ShAddralign));
357 BSSSections.push_back(Section);
360 case NumSectionTypes:
361 llvm::report_fatal_error("Unknown SectionType");
365 const uint8_t SymbolType = STT_OBJECT;
366 for (VariableDeclaration *Var : Vars) {
367 // If the variable declaration does not have an initializer, its symtab
368 // entry will be created separately.
369 if (!Var->hasInitializer())
371 Elf64_Xword Align = Var->getAlignment();
372 Section->padToAlignment(Str, Align);
373 SizeT SymbolSize = Var->getNumBytes();
374 bool IsExternal = Var->isExternal() || Ctx.getFlags().DisableInternal;
375 const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
376 IceString MangledName = Var->mangleName(&Ctx);
377 SymTab->createDefinedSym(MangledName, SymbolType, SymbolBinding, Section,
378 Section->getCurrentSize(), SymbolSize);
379 StrTab->add(MangledName);
380 if (!Var->hasNonzeroInitializer()) {
381 assert(ST == BSS || ST == ROData);
383 Section->appendZeros(Str, SymbolSize);
385 Section->setSize(Section->getCurrentSize() + SymbolSize);
388 for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
389 switch (Init->getKind()) {
390 case VariableDeclaration::Initializer::DataInitializerKind: {
391 const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
392 Init)->getContents();
393 Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
396 case VariableDeclaration::Initializer::ZeroInitializerKind:
397 Section->appendZeros(Str, Init->getNumBytes());
399 case VariableDeclaration::Initializer::RelocInitializerKind: {
401 llvm::cast<VariableDeclaration::RelocInitializer>(Init);
402 AssemblerFixup NewFixup;
403 NewFixup.set_position(Section->getCurrentSize());
404 NewFixup.set_kind(RelocationKind);
405 const bool SuppressMangling = true;
406 NewFixup.set_value(Ctx.getConstantSym(
407 Reloc->getOffset(), Reloc->getDeclaration()->mangleName(&Ctx),
409 RelSection->addRelocation(NewFixup);
410 Section->appendRelocationOffset(Str, RelSection->isRela(),
420 void ELFObjectWriter::writeInitialELFHeader() {
421 assert(!SectionNumbersAssigned);
422 const Elf64_Off DummySHOffset = 0;
423 const SizeT DummySHStrIndex = 0;
424 const SizeT DummyNumSections = 0;
425 if (isELF64(Ctx.getTargetArch())) {
426 writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex,
429 writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex,
434 template <bool IsELF64>
435 void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
436 SizeT SectHeaderStrIndex,
438 // Write the e_ident: magic number, class, etc.
439 // The e_ident is byte order and ELF class independent.
440 Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic)));
441 Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32);
442 Str.write8(ELFDATA2LSB);
443 Str.write8(EV_CURRENT);
444 Str.write8(ELFOSABI_NONE);
445 const uint8_t ELF_ABIVersion = 0;
446 Str.write8(ELF_ABIVersion);
447 Str.writeZeroPadding(EI_NIDENT - EI_PAD);
449 // TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc:
450 // https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html
451 // e_shnum should be 0 and then actual number of sections is
452 // stored in the sh_size member of the 0th section.
453 assert(NumSections < SHN_LORESERVE);
454 assert(SectHeaderStrIndex < SHN_LORESERVE);
456 // Write the rest of the file header, which does depend on byte order
458 Str.writeLE16(ET_REL); // e_type
459 Str.writeLE16(getELFMachine(Ctx.getTargetArch())); // e_machine
460 Str.writeELFWord<IsELF64>(1); // e_version
461 // Since this is for a relocatable object, there is no entry point,
462 // and no program headers.
463 Str.writeAddrOrOffset<IsELF64>(0); // e_entry
464 Str.writeAddrOrOffset<IsELF64>(0); // e_phoff
465 Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff
466 Str.writeELFWord<IsELF64>(getELFFlags(Ctx.getTargetArch())); // e_flags
467 Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize
468 static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52,
469 "Elf_Ehdr sizes cannot be derived from sizeof");
470 Str.writeLE16(0); // e_phentsize
471 Str.writeLE16(0); // e_phnum
472 Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr)
473 : sizeof(Elf32_Shdr)); // e_shentsize
474 static_assert(sizeof(Elf64_Shdr) == 64 && sizeof(Elf32_Shdr) == 40,
475 "Elf_Shdr sizes cannot be derived from sizeof");
476 Str.writeLE16(static_cast<Elf64_Half>(NumSections)); // e_shnum
477 Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx
480 template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
481 ConstantList Pool = Ctx.getConstantPool(Ty);
485 SizeT Align = typeAlignInBytes(Ty);
486 size_t EntSize = typeWidthInBytes(Ty);
488 SizeT WriteAmt = std::min(EntSize, llvm::array_lengthof(Buf));
489 assert(WriteAmt == EntSize);
490 // Assume that writing WriteAmt bytes at a time allows us to avoid aligning
492 assert(WriteAmt % Align == 0);
493 // Check that we write the full PrimType.
494 assert(WriteAmt == sizeof(typename ConstType::PrimType));
495 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_MERGE;
496 std::string SecBuffer;
497 llvm::raw_string_ostream SecStrBuf(SecBuffer);
498 SecStrBuf << ".rodata.cst" << WriteAmt;
499 ELFDataSection *Section = createSection<ELFDataSection>(
500 SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
501 RODataSections.push_back(Section);
502 SizeT OffsetInSection = 0;
503 // The symbol table entry doesn't need to know the defined symbol's
504 // size since this is in a section with a fixed Entry Size.
505 const SizeT SymbolSize = 0;
506 Section->setFileOffset(alignFileOffset(Align));
509 for (Constant *C : Pool) {
510 auto Const = llvm::cast<ConstType>(C);
511 std::string SymBuffer;
512 llvm::raw_string_ostream SymStrBuf(SymBuffer);
513 Const->emitPoolLabel(SymStrBuf);
514 std::string &SymName = SymStrBuf.str();
515 SymTab->createDefinedSym(SymName, STT_NOTYPE, STB_LOCAL, Section,
516 OffsetInSection, SymbolSize);
517 StrTab->add(SymName);
518 typename ConstType::PrimType Value = Const->getValue();
519 memcpy(Buf, &Value, WriteAmt);
520 Str.writeBytes(llvm::StringRef(Buf, WriteAmt));
521 OffsetInSection += WriteAmt;
523 Section->setSize(OffsetInSection);
526 // Instantiate known needed versions of the template, since we are
527 // defining the function in the .cpp file instead of the .h file.
528 // We may need to instantiate constant pools for integers as well
529 // if we do constant-pooling of large integers to remove them
530 // from the instruction stream (fewer bytes controlled by an attacker).
531 template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
533 template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
535 void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) {
536 writeRelocationSections(IsELF64, RelTextSections);
537 writeRelocationSections(IsELF64, RelDataSections);
538 writeRelocationSections(IsELF64, RelRODataSections);
541 void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
542 for (const Constant *S : UndefSyms) {
543 const auto Sym = llvm::cast<ConstantRelocatable>(S);
544 const IceString &Name = Sym->getName();
545 assert(Sym->getOffset() == 0);
546 assert(Sym->getSuppressMangling());
547 SymTab->noteUndefinedSym(Name, NullSection);
552 void ELFObjectWriter::writeRelocationSections(bool IsELF64,
553 RelSectionList &RelSections) {
554 for (ELFRelocationSection *RelSec : RelSections) {
555 Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
556 RelSec->setFileOffset(Offset);
557 RelSec->setSize(RelSec->getSectionDataSize());
559 RelSec->writeData<true>(Ctx, Str, SymTab);
561 RelSec->writeData<false>(Ctx, Str, SymTab);
566 void ELFObjectWriter::writeNonUserSections() {
567 bool IsELF64 = isELF64(Ctx.getTargetArch());
569 // Write out the shstrtab now that all sections are known.
570 ShStrTab->doLayout();
571 ShStrTab->setSize(ShStrTab->getSectionDataSize());
572 Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign());
573 ShStrTab->setFileOffset(ShStrTabOffset);
574 Str.writeBytes(ShStrTab->getSectionData());
576 SectionList AllSections;
577 assignSectionNumbersInfo(AllSections);
579 // Finalize the regular StrTab and fix up references in the SymTab.
581 StrTab->setSize(StrTab->getSectionDataSize());
583 SymTab->updateIndices(StrTab);
585 Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign());
586 SymTab->setFileOffset(SymTabOffset);
587 SymTab->setSize(SymTab->getSectionDataSize());
588 SymTab->writeData(Str, IsELF64);
590 Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign());
591 StrTab->setFileOffset(StrTabOffset);
592 Str.writeBytes(StrTab->getSectionData());
594 writeAllRelocationSections(IsELF64);
596 // Write out the section headers.
597 const size_t ShdrAlign = IsELF64 ? 8 : 4;
598 Elf64_Off ShOffset = alignFileOffset(ShdrAlign);
599 for (const auto S : AllSections) {
601 S->writeHeader<true>(Str);
603 S->writeHeader<false>(Str);
606 // Finally write the updated ELF header w/ the correct number of sections.
609 writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(),
612 writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(),
617 } // end of namespace Ice