• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- subzero/src/IceELFObjectWriter.cpp - ELF object file writer --------===//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Defines the writer for ELF relocatable object files.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "IceELFObjectWriter.h"
16 
17 #include "IceAssembler.h"
18 #include "IceDefs.h"
19 #include "IceELFSection.h"
20 #include "IceELFStreamer.h"
21 #include "IceGlobalContext.h"
22 #include "IceGlobalInits.h"
23 #include "IceInst.h"
24 #include "IceOperand.h"
25 
26 #include "llvm/Support/ELF.h"
27 #include "llvm/Support/MathExtras.h"
28 
29 namespace Ice {
30 
31 namespace {
32 
33 constexpr struct {
34   bool IsELF64;
35   uint16_t ELFMachine;
36   uint32_t ELFFlags;
37 } ELFTargetInfo[TargetArch_NUM] = {
38 #define X(tag, str, is_elf64, e_machine, e_flags)                              \
39   {is_elf64, e_machine, e_flags},
40     TARGETARCH_TABLE
41 #undef X
42 };
43 
isELF64(const ClFlags & Flags)44 bool isELF64(const ClFlags &Flags) {
45   const TargetArch Arch = Flags.getTargetArch();
46   if (Arch >= TargetArch_NUM) {
47     llvm_unreachable("Invalid target arch for isELF64");
48     return false;
49   }
50 
51   return ELFTargetInfo[Arch].IsELF64;
52 }
53 
getELFMachine(TargetArch Arch)54 uint16_t getELFMachine(TargetArch Arch) {
55   if (Arch < TargetArch_NUM)
56     return ELFTargetInfo[Arch].ELFMachine;
57   llvm_unreachable("Invalid target arch for getELFMachine");
58   return EM_NONE;
59 }
60 
getELFFlags(TargetArch Arch)61 uint32_t getELFFlags(TargetArch Arch) {
62   if (Arch < TargetArch_NUM)
63     return ELFTargetInfo[Arch].ELFFlags;
64   llvm_unreachable("Invalid target arch for getELFFlags");
65   return 0;
66 }
67 
68 } // end of anonymous namespace
69 
ELFObjectWriter(GlobalContext & Ctx,ELFStreamer & Out)70 ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out)
71     : Ctx(Ctx), Str(Out), ELF64(isELF64(getFlags())) {
72   // Create the special bookkeeping sections now.
73   constexpr char NullSectionName[] = "";
74   NullSection = new (Ctx.allocate<ELFSection>())
75       ELFSection(NullSectionName, SHT_NULL, 0, 0, 0);
76 
77   constexpr char ShStrTabName[] = ".shstrtab";
78   ShStrTab = new (Ctx.allocate<ELFStringTableSection>())
79       ELFStringTableSection(ShStrTabName, SHT_STRTAB, 0, 1, 0);
80   ShStrTab->add(ShStrTabName);
81 
82   constexpr char SymTabName[] = ".symtab";
83   const Elf64_Xword SymTabAlign = ELF64 ? 8 : 4;
84   const Elf64_Xword SymTabEntSize =
85       ELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
86   static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16,
87                 "Elf_Sym sizes cannot be derived from sizeof");
88   SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0,
89                                                 SymTabAlign, SymTabEntSize);
90   SymTab->createNullSymbol(NullSection, &Ctx);
91 
92   constexpr char StrTabName[] = ".strtab";
93   StrTab =
94       createSection<ELFStringTableSection>(StrTabName, SHT_STRTAB, 0, 1, 0);
95 }
96 
97 template <typename T>
createSection(const std::string & Name,Elf64_Word ShType,Elf64_Xword ShFlags,Elf64_Xword ShAddralign,Elf64_Xword ShEntsize)98 T *ELFObjectWriter::createSection(const std::string &Name, Elf64_Word ShType,
99                                   Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
100                                   Elf64_Xword ShEntsize) {
101   assert(!SectionNumbersAssigned);
102   T *NewSection =
103       new (Ctx.allocate<T>()) T(Name, ShType, ShFlags, ShAddralign, ShEntsize);
104   ShStrTab->add(Name);
105   return NewSection;
106 }
107 
108 ELFRelocationSection *
createRelocationSection(const ELFSection * RelatedSection)109 ELFObjectWriter::createRelocationSection(const ELFSection *RelatedSection) {
110   // Choice of RELA vs REL is actually separate from elf64 vs elf32, but in
111   // practice we've only had .rela for elf64 (x86-64). In the future, the two
112   // properties may need to be decoupled and the ShEntSize can vary more.
113   const Elf64_Word ShType = ELF64 ? SHT_RELA : SHT_REL;
114   const std::string RelPrefix = ELF64 ? ".rela" : ".rel";
115   const std::string RelSectionName = RelPrefix + RelatedSection->getName();
116   const Elf64_Xword ShAlign = ELF64 ? 8 : 4;
117   const Elf64_Xword ShEntSize = ELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
118   static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
119                 "Elf_Rel/Rela sizes cannot be derived from sizeof");
120   constexpr Elf64_Xword ShFlags = 0;
121   ELFRelocationSection *RelSection = createSection<ELFRelocationSection>(
122       RelSectionName, ShType, ShFlags, ShAlign, ShEntSize);
123   RelSection->setRelatedSection(RelatedSection);
124   return RelSection;
125 }
126 
127 template <typename UserSectionList>
assignRelSectionNumInPairs(SizeT & CurSectionNumber,UserSectionList & UserSections,RelSectionList & RelSections,SectionList & AllSections)128 void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber,
129                                                  UserSectionList &UserSections,
130                                                  RelSectionList &RelSections,
131                                                  SectionList &AllSections) {
132   RelSectionList::iterator RelIt = RelSections.begin();
133   RelSectionList::iterator RelE = RelSections.end();
134   for (ELFSection *UserSection : UserSections) {
135     UserSection->setNumber(CurSectionNumber++);
136     UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName()));
137     AllSections.push_back(UserSection);
138     if (RelIt != RelE) {
139       ELFRelocationSection *RelSection = *RelIt;
140       if (RelSection->getRelatedSection() == UserSection) {
141         RelSection->setInfoNum(UserSection->getNumber());
142         RelSection->setNumber(CurSectionNumber++);
143         RelSection->setNameStrIndex(ShStrTab->getIndex(RelSection->getName()));
144         AllSections.push_back(RelSection);
145         ++RelIt;
146       }
147     }
148   }
149   // Should finish with UserIt at the same time as RelIt.
150   assert(RelIt == RelE);
151   return;
152 }
153 
assignRelLinkNum(SizeT SymTabNumber,RelSectionList & RelSections)154 void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber,
155                                        RelSectionList &RelSections) {
156   for (ELFRelocationSection *S : RelSections) {
157     S->setLinkNum(SymTabNumber);
158   }
159 }
160 
assignSectionNumbersInfo(SectionList & AllSections)161 void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) {
162   // Go through each section, assigning them section numbers and and fill in
163   // the size for sections that aren't incrementally updated.
164   assert(!SectionNumbersAssigned);
165   SizeT CurSectionNumber = 0;
166   NullSection->setNumber(CurSectionNumber++);
167   // The rest of the fields are initialized to 0, and stay that way.
168   AllSections.push_back(NullSection);
169 
170   assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections,
171                                               RelTextSections, AllSections);
172   assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections,
173                                               RelDataSections, AllSections);
174   for (ELFSection *BSSSection : BSSSections) {
175     BSSSection->setNumber(CurSectionNumber++);
176     BSSSection->setNameStrIndex(ShStrTab->getIndex(BSSSection->getName()));
177     AllSections.push_back(BSSSection);
178   }
179   assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RODataSections,
180                                               RelRODataSections, AllSections);
181 
182   ShStrTab->setNumber(CurSectionNumber++);
183   ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName()));
184   AllSections.push_back(ShStrTab);
185 
186   SymTab->setNumber(CurSectionNumber++);
187   SymTab->setNameStrIndex(ShStrTab->getIndex(SymTab->getName()));
188   AllSections.push_back(SymTab);
189 
190   StrTab->setNumber(CurSectionNumber++);
191   StrTab->setNameStrIndex(ShStrTab->getIndex(StrTab->getName()));
192   AllSections.push_back(StrTab);
193 
194   SymTab->setLinkNum(StrTab->getNumber());
195   SymTab->setInfoNum(SymTab->getNumLocals());
196 
197   assignRelLinkNum(SymTab->getNumber(), RelTextSections);
198   assignRelLinkNum(SymTab->getNumber(), RelDataSections);
199   assignRelLinkNum(SymTab->getNumber(), RelRODataSections);
200   SectionNumbersAssigned = true;
201 }
202 
alignFileOffset(Elf64_Xword Align)203 Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) {
204   Elf64_Off OffsetInFile = Str.tell();
205   Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align);
206   if (AlignDiff == 0)
207     return OffsetInFile;
208   Str.writeZeroPadding(AlignDiff);
209   OffsetInFile += AlignDiff;
210   return OffsetInFile;
211 }
212 
writeFunctionCode(GlobalString FuncName,bool IsInternal,Assembler * Asm)213 void ELFObjectWriter::writeFunctionCode(GlobalString FuncName, bool IsInternal,
214                                         Assembler *Asm) {
215   assert(!SectionNumbersAssigned);
216   TimerMarker T_func(&Ctx, FuncName.toStringOrEmpty());
217   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
218   ELFTextSection *Section = nullptr;
219   ELFRelocationSection *RelSection = nullptr;
220   const bool FunctionSections = getFlags().getFunctionSections();
221   if (TextSections.empty() || FunctionSections) {
222     std::string SectionName = ".text";
223     if (FunctionSections)
224       SectionName += "." + FuncName;
225     constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
226     const Elf64_Xword ShAlign = 1 << Asm->getBundleAlignLog2Bytes();
227     Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags,
228                                             ShAlign, 0);
229     Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
230     Section->setFileOffset(OffsetInFile);
231     TextSections.push_back(Section);
232     RelSection = createRelocationSection(Section);
233     RelTextSections.push_back(RelSection);
234   } else {
235     Section = TextSections[0];
236     RelSection = RelTextSections[0];
237   }
238   const RelocOffsetT OffsetInSection = Section->getCurrentSize();
239   // Function symbols are set to 0 size in the symbol table, in contrast to
240   // data symbols which have a proper size.
241   constexpr SizeT SymbolSize = 0;
242   uint8_t SymbolType;
243   uint8_t SymbolBinding;
244   if (IsInternal && !getFlags().getDisableInternal()) {
245     SymbolType = STT_NOTYPE;
246     SymbolBinding = STB_LOCAL;
247   } else {
248     SymbolType = STT_FUNC;
249     SymbolBinding = STB_GLOBAL;
250   }
251   SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section,
252                            OffsetInSection, SymbolSize);
253   StrTab->add(FuncName);
254 
255   // Copy the fixup information from per-function Assembler memory to the
256   // object writer's memory, for writing later.
257   const auto &Fixups = Asm->fixups();
258   if (!Fixups.empty()) {
259     if (!RelSection->isRela()) {
260       // This is a non-rela section, so we need to update the instruction stream
261       // with the relocation addends.
262       for (const auto *Fixup : Fixups) {
263         Fixup->emitOffset(Asm);
264       }
265     }
266     RelSection->addRelocations(OffsetInSection, Asm->fixups(), SymTab);
267   }
268   Section->appendData(Str, Asm->getBufferView());
269 }
270 
271 namespace {
272 
273 ELFObjectWriter::SectionType
classifyGlobalSection(const VariableDeclaration * Var)274 classifyGlobalSection(const VariableDeclaration *Var) {
275   if (Var->getIsConstant())
276     return ELFObjectWriter::ROData;
277   if (Var->hasNonzeroInitializer())
278     return ELFObjectWriter::Data;
279   return ELFObjectWriter::BSS;
280 }
281 
282 // Partition the Vars list by SectionType into VarsBySection. If TranslateOnly
283 // is non-empty, then only the TranslateOnly variable is kept for emission.
partitionGlobalsBySection(const VariableDeclarationList & Vars,VariableDeclarationPartition VarsBySection[])284 void partitionGlobalsBySection(const VariableDeclarationList &Vars,
285                                VariableDeclarationPartition VarsBySection[]) {
286   for (VariableDeclaration *Var : Vars) {
287     if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
288       size_t Section = classifyGlobalSection(Var);
289       assert(Section < ELFObjectWriter::NumSectionTypes);
290       VarsBySection[Section].push_back(Var);
291     }
292   }
293 }
294 
295 } // end of anonymous namespace
296 
writeTargetRODataSection(const std::string & Name,Elf64_Word ShType,Elf64_Xword ShFlags,Elf64_Xword ShAddralign,Elf64_Xword ShEntsize,const llvm::StringRef & SecData)297 void ELFObjectWriter::writeTargetRODataSection(const std::string &Name,
298                                                Elf64_Word ShType,
299                                                Elf64_Xword ShFlags,
300                                                Elf64_Xword ShAddralign,
301                                                Elf64_Xword ShEntsize,
302                                                const llvm::StringRef &SecData) {
303   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
304   assert(!SectionNumbersAssigned);
305   ELFDataSection *Section = createSection<ELFDataSection>(
306       Name, ShType, ShFlags, ShAddralign, ShEntsize);
307   Section->setFileOffset(alignFileOffset(ShAddralign));
308   Section->appendData(Str, llvm::StringRef(SecData.data(), SecData.size()));
309   RODataSections.push_back(Section);
310 }
311 
writeDataSection(const VariableDeclarationList & Vars,FixupKind RelocationKind,const std::string & SectionSuffix,bool IsPIC)312 void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
313                                        FixupKind RelocationKind,
314                                        const std::string &SectionSuffix,
315                                        bool IsPIC) {
316   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
317   assert(!SectionNumbersAssigned);
318   VariableDeclarationPartition VarsBySection[ELFObjectWriter::NumSectionTypes];
319   for (auto &SectionList : VarsBySection)
320     SectionList.reserve(Vars.size());
321   partitionGlobalsBySection(Vars, VarsBySection);
322   size_t I = 0;
323   for (auto &SectionList : VarsBySection) {
324     writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
325                     SectionSuffix, IsPIC);
326   }
327 }
328 
329 namespace {
MangleSectionName(const char Base[],const std::string & Suffix)330 std::string MangleSectionName(const char Base[], const std::string &Suffix) {
331   if (Suffix.empty())
332     return Base;
333   return Base + ("." + Suffix);
334 }
335 } // end of anonymous namespace
336 
337 // TODO(jvoung): Handle fdata-sections.
writeDataOfType(SectionType ST,const VariableDeclarationPartition & Vars,FixupKind RelocationKind,const std::string & SectionSuffix,bool IsPIC)338 void ELFObjectWriter::writeDataOfType(SectionType ST,
339                                       const VariableDeclarationPartition &Vars,
340                                       FixupKind RelocationKind,
341                                       const std::string &SectionSuffix,
342                                       bool IsPIC) {
343   if (Vars.empty())
344     return;
345   ELFDataSection *Section;
346   ELFRelocationSection *RelSection;
347   Elf64_Xword ShAddralign = 1;
348   for (VariableDeclaration *Var : Vars) {
349     Elf64_Xword Align = Var->getAlignment();
350     ShAddralign = std::max(ShAddralign, Align);
351   }
352   constexpr Elf64_Xword ShEntsize = 0; // non-uniform data element size.
353   // Lift this out, so it can be re-used if we do fdata-sections?
354   switch (ST) {
355   case ROData: {
356     const std::string SectionName =
357         MangleSectionName(IsPIC ? ".data.rel.ro" : ".rodata", SectionSuffix);
358     const Elf64_Xword ShFlags = IsPIC ? (SHF_ALLOC | SHF_WRITE) : SHF_ALLOC;
359     Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
360                                             ShAddralign, ShEntsize);
361     Section->setFileOffset(alignFileOffset(ShAddralign));
362     RODataSections.push_back(Section);
363     RelSection = createRelocationSection(Section);
364     RelRODataSections.push_back(RelSection);
365     break;
366   }
367   case Data: {
368     const std::string SectionName = MangleSectionName(".data", SectionSuffix);
369     constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
370     Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
371                                             ShAddralign, ShEntsize);
372     Section->setFileOffset(alignFileOffset(ShAddralign));
373     DataSections.push_back(Section);
374     RelSection = createRelocationSection(Section);
375     RelDataSections.push_back(RelSection);
376     break;
377   }
378   case BSS: {
379     const std::string SectionName = MangleSectionName(".bss", SectionSuffix);
380     constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
381     Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
382                                             ShAddralign, ShEntsize);
383     Section->setFileOffset(alignFileOffset(ShAddralign));
384     BSSSections.push_back(Section);
385     break;
386   }
387   case NumSectionTypes:
388     llvm::report_fatal_error("Unknown SectionType");
389     break;
390   }
391 
392   constexpr uint8_t SymbolType = STT_OBJECT;
393   for (VariableDeclaration *Var : Vars) {
394     // If the variable declaration does not have an initializer, its symtab
395     // entry will be created separately.
396     if (!Var->hasInitializer())
397       continue;
398     constexpr Elf64_Xword MinAlign = 1;
399     const auto Align = std::max<Elf64_Xword>(MinAlign, Var->getAlignment());
400     Section->padToAlignment(Str, Align);
401     SizeT SymbolSize = Var->getNumBytes();
402     bool IsExternal = Var->isExternal() || getFlags().getDisableInternal();
403     const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
404     GlobalString Name = Var->getName();
405     SymTab->createDefinedSym(Name, SymbolType, SymbolBinding, Section,
406                              Section->getCurrentSize(), SymbolSize);
407     StrTab->add(Name);
408     if (!Var->hasNonzeroInitializer()) {
409       assert(ST == BSS || ST == ROData);
410       if (ST == ROData)
411         Section->appendZeros(Str, SymbolSize);
412       else
413         Section->setSize(Section->getCurrentSize() + SymbolSize);
414     } else {
415       assert(ST != BSS);
416       for (const auto *Init : Var->getInitializers()) {
417         switch (Init->getKind()) {
418         case VariableDeclaration::Initializer::DataInitializerKind: {
419           const auto &Data =
420               llvm::cast<VariableDeclaration::DataInitializer>(Init)
421                   ->getContents();
422           Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
423           break;
424         }
425         case VariableDeclaration::Initializer::ZeroInitializerKind:
426           Section->appendZeros(Str, Init->getNumBytes());
427           break;
428         case VariableDeclaration::Initializer::RelocInitializerKind: {
429           const auto *Reloc =
430               llvm::cast<VariableDeclaration::RelocInitializer>(Init);
431           AssemblerFixup NewFixup;
432           NewFixup.set_position(Section->getCurrentSize());
433           NewFixup.set_kind(Reloc->hasFixup() ? Reloc->getFixup()
434                                               : RelocationKind);
435           assert(NewFixup.kind() != llvm::ELF::R_ARM_NONE);
436           NewFixup.set_value(Ctx.getConstantSym(
437               Reloc->getOffset(), Reloc->getDeclaration()->getName()));
438           RelSection->addRelocation(NewFixup);
439           Section->appendRelocationOffset(Str, RelSection->isRela(),
440                                           Reloc->getOffset());
441           break;
442         }
443         }
444       }
445     }
446   }
447 }
448 
writeInitialELFHeader()449 void ELFObjectWriter::writeInitialELFHeader() {
450   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
451   assert(!SectionNumbersAssigned);
452   constexpr Elf64_Off DummySHOffset = 0;
453   constexpr SizeT DummySHStrIndex = 0;
454   constexpr SizeT DummyNumSections = 0;
455   if (ELF64) {
456     writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex,
457                                  DummyNumSections);
458   } else {
459     writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex,
460                                   DummyNumSections);
461   }
462 }
463 
464 template <bool IsELF64>
writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,SizeT SectHeaderStrIndex,SizeT NumSections)465 void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
466                                              SizeT SectHeaderStrIndex,
467                                              SizeT NumSections) {
468   // Write the e_ident: magic number, class, etc. The e_ident is byte order and
469   // ELF class independent.
470   Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic)));
471   Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32);
472   Str.write8(ELFDATA2LSB);
473   Str.write8(EV_CURRENT);
474   Str.write8(ELFOSABI_NONE);
475   constexpr uint8_t ELF_ABIVersion = 0;
476   Str.write8(ELF_ABIVersion);
477   Str.writeZeroPadding(EI_NIDENT - EI_PAD);
478 
479   // TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc:
480   // https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html e_shnum should
481   // be 0 and then actual number of sections is stored in the sh_size member of
482   // the 0th section.
483   assert(NumSections < SHN_LORESERVE);
484   assert(SectHeaderStrIndex < SHN_LORESERVE);
485 
486   const TargetArch Arch = getFlags().getTargetArch();
487   // Write the rest of the file header, which does depend on byte order and ELF
488   // class.
489   Str.writeLE16(ET_REL);                                    // e_type
490   Str.writeLE16(getELFMachine(getFlags().getTargetArch())); // e_machine
491   Str.writeELFWord<IsELF64>(1);                             // e_version
492   // Since this is for a relocatable object, there is no entry point, and no
493   // program headers.
494   Str.writeAddrOrOffset<IsELF64>(0);                                // e_entry
495   Str.writeAddrOrOffset<IsELF64>(0);                                // e_phoff
496   Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset);              // e_shoff
497   Str.writeELFWord<IsELF64>(getELFFlags(Arch));                     // e_flags
498   Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize
499   static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52,
500                 "Elf_Ehdr sizes cannot be derived from sizeof");
501   Str.writeLE16(0); // e_phentsize
502   Str.writeLE16(0); // e_phnum
503   Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr)
504                         : sizeof(Elf32_Shdr)); // e_shentsize
505   static_assert(sizeof(Elf64_Shdr) == 64 && sizeof(Elf32_Shdr) == 40,
506                 "Elf_Shdr sizes cannot be derived from sizeof");
507   Str.writeLE16(static_cast<Elf64_Half>(NumSections));        // e_shnum
508   Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx
509 }
510 
writeConstantPool(Type Ty)511 template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) {
512   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
513   ConstantList Pool = Ctx.getConstantPool(Ty);
514   if (Pool.empty()) {
515     return;
516   }
517   SizeT Align = typeAlignInBytes(Ty);
518   size_t EntSize = typeWidthInBytes(Ty);
519   char Buf[20];
520   SizeT WriteAmt = std::min(EntSize, llvm::array_lengthof(Buf));
521   // Check that we write the full PrimType.
522   assert(WriteAmt == EntSize);
523   // Assume that writing WriteAmt bytes at a time allows us to avoid aligning
524   // between entries.
525   assert(WriteAmt % Align == 0);
526   constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_MERGE;
527   std::string SecBuffer;
528   llvm::raw_string_ostream SecStrBuf(SecBuffer);
529   SecStrBuf << ".rodata.cst" << WriteAmt;
530   ELFDataSection *Section = createSection<ELFDataSection>(
531       SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt);
532   RODataSections.push_back(Section);
533   SizeT OffsetInSection = 0;
534   // The symbol table entry doesn't need to know the defined symbol's size
535   // since this is in a section with a fixed Entry Size.
536   constexpr SizeT SymbolSize = 0;
537   Section->setFileOffset(alignFileOffset(Align));
538 
539   // Write the data.
540   for (Constant *C : Pool) {
541     if (!C->getShouldBePooled())
542       continue;
543     auto *Const = llvm::cast<ConstType>(C);
544     GlobalString SymName = Const->getLabelName();
545     SymTab->createDefinedSym(SymName, STT_NOTYPE, STB_LOCAL, Section,
546                              OffsetInSection, SymbolSize);
547     StrTab->add(SymName);
548     typename ConstType::PrimType Value = Const->getValue();
549     memcpy(Buf, &Value, WriteAmt);
550     Str.writeBytes(llvm::StringRef(Buf, WriteAmt));
551     OffsetInSection += WriteAmt;
552   }
553   Section->setSize(OffsetInSection);
554 }
555 
556 // Instantiate known needed versions of the template, since we are defining the
557 // function in the .cpp file instead of the .h file. We may need to instantiate
558 // constant pools for integers as well if we do constant-pooling of large
559 // integers to remove them from the instruction stream (fewer bytes controlled
560 // by an attacker).
561 template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
562 
563 template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
564 
565 template void ELFObjectWriter::writeConstantPool<ConstantInteger32>(Type Ty);
566 
writeAllRelocationSections()567 void ELFObjectWriter::writeAllRelocationSections() {
568   writeRelocationSections(RelTextSections);
569   writeRelocationSections(RelDataSections);
570   writeRelocationSections(RelRODataSections);
571 }
572 
writeJumpTable(const JumpTableData & JT,FixupKind RelocationKind,bool IsPIC)573 void ELFObjectWriter::writeJumpTable(const JumpTableData &JT,
574                                      FixupKind RelocationKind, bool IsPIC) {
575   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
576   ELFDataSection *Section;
577   ELFRelocationSection *RelSection;
578   const Elf64_Xword PointerSize = typeWidthInBytes(getPointerType());
579   const Elf64_Xword ShAddralign = PointerSize;
580   const Elf64_Xword ShEntsize = PointerSize;
581   const std::string SectionName = MangleSectionName(
582       IsPIC ? ".data.rel.ro" : ".rodata", JT.getSectionName());
583   Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, SHF_ALLOC,
584                                           ShAddralign, ShEntsize);
585   Section->setFileOffset(alignFileOffset(ShAddralign));
586   RODataSections.push_back(Section);
587   RelSection = createRelocationSection(Section);
588   RelRODataSections.push_back(RelSection);
589 
590   constexpr uint8_t SymbolType = STT_OBJECT;
591   Section->padToAlignment(Str, PointerSize);
592   const bool IsExternal = getFlags().getDisableInternal();
593   const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
594   const auto JumpTableName = JT.getName();
595   SymTab->createDefinedSym(JumpTableName, SymbolType, SymbolBinding, Section,
596                            Section->getCurrentSize(), PointerSize);
597   StrTab->add(JumpTableName);
598 
599   for (intptr_t TargetOffset : JT.getTargetOffsets()) {
600     AssemblerFixup NewFixup;
601     NewFixup.set_position(Section->getCurrentSize());
602     NewFixup.set_kind(RelocationKind);
603     NewFixup.set_value(Ctx.getConstantSym(TargetOffset, JT.getFunctionName()));
604     RelSection->addRelocation(NewFixup);
605     Section->appendRelocationOffset(Str, RelSection->isRela(), TargetOffset);
606   }
607 }
608 
setUndefinedSyms(const ConstantList & UndefSyms)609 void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
610   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
611   for (const Constant *S : UndefSyms) {
612     const auto *Sym = llvm::cast<ConstantRelocatable>(S);
613     GlobalString Name = Sym->getName();
614     assert(Name.hasStdString());
615     assert(Sym->getOffset() == 0);
616     SymTab->noteUndefinedSym(Name, NullSection);
617     StrTab->add(Name);
618   }
619 }
620 
writeRelocationSections(RelSectionList & RelSections)621 void ELFObjectWriter::writeRelocationSections(RelSectionList &RelSections) {
622   for (ELFRelocationSection *RelSec : RelSections) {
623     Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
624     RelSec->setFileOffset(Offset);
625     RelSec->setSize(RelSec->getSectionDataSize());
626     if (ELF64) {
627       RelSec->writeData<true>(Str, SymTab);
628     } else {
629       RelSec->writeData<false>(Str, SymTab);
630     }
631   }
632 }
633 
writeNonUserSections()634 void ELFObjectWriter::writeNonUserSections() {
635   TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
636 
637   // Write out the shstrtab now that all sections are known.
638   ShStrTab->doLayout();
639   ShStrTab->setSize(ShStrTab->getSectionDataSize());
640   Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign());
641   ShStrTab->setFileOffset(ShStrTabOffset);
642   Str.writeBytes(ShStrTab->getSectionData());
643 
644   SectionList AllSections;
645   assignSectionNumbersInfo(AllSections);
646 
647   // Finalize the regular StrTab and fix up references in the SymTab.
648   StrTab->doLayout();
649   StrTab->setSize(StrTab->getSectionDataSize());
650 
651   SymTab->updateIndices(StrTab);
652 
653   Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign());
654   SymTab->setFileOffset(SymTabOffset);
655   SymTab->setSize(SymTab->getSectionDataSize());
656   SymTab->writeData(Str, ELF64);
657 
658   Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign());
659   StrTab->setFileOffset(StrTabOffset);
660   Str.writeBytes(StrTab->getSectionData());
661 
662   writeAllRelocationSections();
663 
664   // Write out the section headers.
665   const size_t ShdrAlign = ELF64 ? 8 : 4;
666   Elf64_Off ShOffset = alignFileOffset(ShdrAlign);
667   for (const auto S : AllSections) {
668     if (ELF64)
669       S->writeHeader<true>(Str);
670     else
671       S->writeHeader<false>(Str);
672   }
673 
674   // Finally write the updated ELF header w/ the correct number of sections.
675   Str.seek(0);
676   if (ELF64) {
677     writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(),
678                                  AllSections.size());
679   } else {
680     writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(),
681                                   AllSections.size());
682   }
683 }
684 
685 } // end of namespace Ice
686