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