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