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