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