1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2020-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #include <ZEELFObjectBuilder.hpp>
10 #include <ZEInfo.hpp>
11 #include <ZEInfoYAML.hpp>
12
13 #ifndef ZEBinStandAloneBuild
14 #include "common/LLVMWarningsPush.hpp"
15 #endif
16
17 #include "llvm/MC/StringTableBuilder.h"
18 #include "llvm/Support/EndianStream.h"
19 #include "llvm/Support/MathExtras.h"
20 #include "llvm/Support/raw_ostream.h"
21
22 #ifndef ZEBinStandAloneBuild
23 #include "common/LLVMWarningsPop.hpp"
24 #endif
25
26 #include <iostream>
27 #include <tuple>
28 #include "Probe/Assertion.h"
29
30 namespace zebin {
31
32 /// ELFWriter - A helper class to write ELF contents into given raw_pwrite_stream,
33 /// according to the given ZEELFObjectBuilder. This object should
34 /// only be used by ZEELFObjectBuilder
35 class ELFWriter {
36 public:
37 ELFWriter(llvm::raw_pwrite_stream& OS,
38 ZEELFObjectBuilder& objBuilder);
39
40 // write the ELF file into OS, return the number of written bytes
41 uint64_t write();
42
43 private:
44 typedef ZEELFObjectBuilder::Section Section;
45 typedef ZEELFObjectBuilder::StandardSection StandardSection;
46 typedef ZEELFObjectBuilder::RelocSection RelocSection;
47 typedef ZEELFObjectBuilder::ZEInfoSection ZEInfoSection;
48 typedef ZEELFObjectBuilder::RelocationListTy RelocationListTy;
49 typedef std::map<ZEELFObjectBuilder::SectionID, uint32_t> SectionIndexMapTy;
50 typedef std::map<std::string, uint64_t> SymNameIndexMapTy;
51
52 struct SectionHdrEntry {
53 uint32_t name = 0;
54 unsigned type = 0;
55 uint64_t offset = 0;
56 uint64_t size = 0;
57 uint32_t link = 0;
58 uint32_t info = 0;
59 uint32_t entsize = 0;
60
61 const Section* section = nullptr;
62 };
63 typedef std::vector<SectionHdrEntry> SectionHdrListTy;
64
65 private:
66 // set m_SectionHdrEntries and adjust the section index, also create
67 // strings for sections' name in StringTableBuilder
68 void createSectionHdrEntries();
69 // write elf header
70 void writeHeader();
71 // write sections and set the attributes in SectionHdrEntry
72 void writeSections();
73 // write a raw section
74 uint64_t writeSectionData(const uint8_t* data, uint64_t size, uint32_t padding);
75 // write symbol table section, return section size
76 uint64_t writeSymTab();
77 // write rel or rela relocation table section
78 uint64_t writeRelocTab(const RelocationListTy& relocs, bool isRelFormat);
79 // write ze info section
80 uint64_t writeZEInfo();
81 // write .note.intelgt.compat section
82 std::pair<uint64_t, uint64_t> writeCompatibilityNote();
83 // write string table
84 uint64_t writeStrTab();
85 // write section header
86 void writeSectionHeader();
87 // write the section header's offset into ELF header
88 void writeSectionHdrOffset(uint64_t offset);
89 // write number of zero bytes
90 void writePadding(uint32_t size);
91
92 // The name writeWord seems confusing. Both ELF32 and ELF64 words are
93 // uint32_t.
writeWord(uint64_t Word)94 void writeWord(uint64_t Word) {
95 if (is64Bit())
96 m_W.write<uint64_t>(Word);
97 else
98 m_W.write<uint32_t>(static_cast<uint32_t>(Word));
99 }
100
is64Bit()101 bool is64Bit() { return m_ObjBuilder.m_is64Bit; }
102
103 uint16_t numOfSections();
104
105 // name is the string table index of the section name
106 SectionHdrEntry& createSectionHdrEntry(
107 const std::string& name, unsigned type, const Section* sect = nullptr);
108 SectionHdrEntry& createNullSectionHdrEntry();
109
110 uint32_t getSymTabEntSize();
111 uint32_t getRelocTabEntSize(bool isRelFormat);
112
113 // name is the string table index of the symbol name
114 void writeSymbol(uint32_t name, uint64_t value, uint64_t size,
115 uint8_t binding, uint8_t type, uint8_t other, uint16_t shndx);
116
117 void writeRelRelocation(uint64_t offset, uint64_t type, uint64_t symIdx);
118 void writeRelaRelocation(uint64_t offset, uint64_t type, uint64_t symIdx, uint64_t addend);
119
120 void writeSecHdrEntry(uint32_t name, uint32_t type, uint64_t flags,
121 uint64_t address, uint64_t offset,
122 uint64_t size, uint32_t link, uint32_t info,
123 uint64_t addralign, uint64_t entsize);
124
125 private:
126 llvm::support::endian::Writer m_W;
127 llvm::StringTableBuilder m_StrTabBuilder{llvm::StringTableBuilder::ELF};
128 ZEELFObjectBuilder& m_ObjBuilder;
129
130 // Map Section::m_id to ELF section index, used for creating symbol table
131 SectionIndexMapTy m_SectionIndex;
132 uint32_t m_SymTabIndex = 0;
133 // string table index, it'll be the last section in this ELF file
134 uint32_t m_StringTableIndex = 0;
135
136 // symbol name to symbol index mapping, for creating relocations
137 SymNameIndexMapTy m_SymNameIdxMap;
138
139 // section information for constructing section header
140 SectionHdrListTy m_SectionHdrEntries;
141
142 };
143
144 } // namespace zebin
145
146 using namespace zebin;
147 using namespace llvm;
148
149 ZEELFObjectBuilder::Section&
addStandardSection(std::string sectName,const uint8_t * data,uint64_t size,unsigned type,uint32_t padding,uint32_t align,StandardSectionListTy & sections)150 ZEELFObjectBuilder::addStandardSection(
151 std::string sectName, const uint8_t* data, uint64_t size,
152 unsigned type, uint32_t padding, uint32_t align, StandardSectionListTy& sections)
153 {
154 IGC_ASSERT(type != ELF::SHT_NULL);
155 // calculate the required padding to satisfy alignment requirement
156 // The original data size is (size + padding)
157 uint32_t need_padding_for_align = (align == 0) ?
158 0 : align - ((size + padding) % align);
159 if (need_padding_for_align == align)
160 need_padding_for_align = 0;
161
162 // total required padding is (padding + need_padding_for_align)
163 sections.emplace_back(
164 ZEELFObjectBuilder::StandardSection(sectName, data, size, type,
165 (need_padding_for_align + padding), m_sectionIdCount));
166 ++m_sectionIdCount;
167 return sections.back();
168 }
169
170 ZEELFObjectBuilder::SectionID
addSectionText(std::string name,const uint8_t * data,uint64_t size,uint32_t padding,uint32_t align)171 ZEELFObjectBuilder::addSectionText(
172 std::string name, const uint8_t* data, uint64_t size, uint32_t padding,
173 uint32_t align)
174 {
175 // adjust the section name to be .text.givenSectName
176 std::string sectName;
177 if (name != "")
178 sectName = m_TextName + "." + name;
179 else
180 sectName = m_TextName;
181
182 Section& sect = addStandardSection(sectName, data, size, ELF::SHT_PROGBITS,
183 padding, align, m_textSections);
184
185 return sect.id();
186 }
187
188 ZEELFObjectBuilder::SectionID
addSectionData(std::string name,const uint8_t * data,uint64_t size,uint32_t padding,uint32_t align)189 ZEELFObjectBuilder::addSectionData(
190 std::string name, const uint8_t* data, uint64_t size, uint32_t padding, uint32_t align)
191 {
192 // adjust the section name to be .data.givenSectName
193 std::string sectName;
194 if (name != "")
195 sectName = m_DataName + "." + name;
196 else
197 sectName = m_DataName;
198
199 Section& sect = addStandardSection(sectName, data, size, ELF::SHT_PROGBITS,
200 padding, align, m_dataAndbssSections);
201 return sect.id();
202 }
203
204 ZEELFObjectBuilder::SectionID
addSectionBss(std::string name,uint64_t size,uint32_t padding,uint32_t align)205 ZEELFObjectBuilder::addSectionBss(
206 std::string name, uint64_t size, uint32_t padding, uint32_t align)
207 {
208 // adjust the section name to be .bss.givenSectName
209 std::string sectName;
210 if (name != "")
211 sectName = m_BssName + "." + name;
212 else
213 sectName = m_BssName;
214
215 Section& sect = addStandardSection(sectName, nullptr, size, ELF::SHT_NOBITS,
216 padding, align, m_dataAndbssSections);
217 return sect.id();
218 }
219
220 void
addSectionGTPinInfo(std::string name,const uint8_t * data,uint64_t size)221 ZEELFObjectBuilder::addSectionGTPinInfo(std::string name, const uint8_t* data, uint64_t size)
222 {
223 // adjust the section name
224 std::string sectName;
225 if (name != "")
226 sectName = m_GTPinInfoName + "." + name;
227 else
228 sectName = m_GTPinInfoName;
229
230 addStandardSection(sectName,
231 data, size, SHT_ZEBIN_GTPIN_INFO, 0, 0, m_otherStdSections);
232 }
233
234 void
addSectionVISAAsm(std::string name,const uint8_t * data,uint64_t size)235 ZEELFObjectBuilder::addSectionVISAAsm(std::string name, const uint8_t* data, uint64_t size)
236 {
237 // adjust the section name
238 std::string sectName;
239 if (name != "")
240 sectName = m_VISAAsmName + "." + name;
241 else
242 sectName = m_VISAAsmName;
243
244 addStandardSection(sectName,
245 data, size, SHT_ZEBIN_VISAASM, 0, 0, m_otherStdSections);
246 }
247
248 void
addSectionMisc(std::string name,const uint8_t * data,uint64_t size)249 ZEELFObjectBuilder::addSectionMisc(std::string name, const uint8_t* data, uint64_t size)
250 {
251 // adjust the section name
252 std::string sectName;
253 if (name != "")
254 sectName = m_MiscName + "." + name;
255 else
256 sectName = m_MiscName;
257
258 addStandardSection(sectName,
259 data, size, SHT_ZEBIN_MISC, 0, 0, m_otherStdSections);
260 }
261
262 void
addSectionSpirv(std::string name,const uint8_t * data,uint64_t size)263 ZEELFObjectBuilder::addSectionSpirv(std::string name, const uint8_t* data, uint64_t size)
264 {
265 if (name.empty())
266 name = m_SpvName;
267 addStandardSection(name, data, size, SHT_ZEBIN_SPIRV, 0, 0, m_otherStdSections);
268 }
269
270 ZEELFObjectBuilder::SectionID
addSectionDebug(std::string name,const uint8_t * data,uint64_t size)271 ZEELFObjectBuilder::addSectionDebug(std::string name, const uint8_t* data, uint64_t size)
272 {
273 if (name.empty())
274 name = m_DebugName;
275 Section& sect =
276 addStandardSection(name, data, size, ELF::SHT_PROGBITS, 0, 0, m_otherStdSections);
277 return sect.id();
278 }
279
280 void
addSectionZEInfo(zeInfoContainer & zeInfo)281 ZEELFObjectBuilder::addSectionZEInfo(zeInfoContainer& zeInfo)
282 {
283 // every object should have at most one ze_info section
284 IGC_ASSERT(!m_zeInfoSection);
285 m_zeInfoSection.reset(new ZEInfoSection(zeInfo, m_sectionIdCount));
286 ++m_sectionIdCount;
287 }
288
addSymbol(std::string name,uint64_t addr,uint64_t size,uint8_t binding,uint8_t type,ZEELFObjectBuilder::SectionID sectionId)289 void ZEELFObjectBuilder::addSymbol(
290 std::string name, uint64_t addr, uint64_t size, uint8_t binding,
291 uint8_t type, ZEELFObjectBuilder::SectionID sectionId)
292 {
293 if (binding == llvm::ELF::STB_LOCAL)
294 m_localSymbols.emplace_back(
295 ZEELFObjectBuilder::Symbol(name, addr, size, binding, type, sectionId));
296 else
297 m_globalSymbols.emplace_back(
298 ZEELFObjectBuilder::Symbol(name, addr, size, binding, type, sectionId));
299 }
300
301 ZEELFObjectBuilder::RelocSection&
getOrCreateRelocSection(SectionID targetSectId,bool isRelFormat)302 ZEELFObjectBuilder::getOrCreateRelocSection(SectionID targetSectId, bool isRelFormat)
303 {
304 // linear search to see if there's existed reloc section with given target id and rel format
305 // reversely iterate that the latest added might hit first
306 for (RelocSectionListTy::reverse_iterator it = m_relocSections.rbegin();
307 it != m_relocSections.rend(); ++it) {
308 if ((*it).m_TargetID == targetSectId && (*it).isRelFormat() == isRelFormat)
309 return *it;
310 }
311 // if not found, create one
312 // adjust the section name to be .rel.applyTargetName or .rela.applyTargetName
313 // If the targt name is empty, we use the defualt name .rel/.rela as the section name
314 // though in our case this should not happen
315 std::string sectName;
316 std::string targetName = getSectionNameBySectionID(targetSectId);
317 if (!targetName.empty())
318 sectName = (isRelFormat? m_RelName : m_RelaName) + targetName;
319 else
320 sectName = isRelFormat? m_RelName : m_RelaName;
321
322 m_relocSections.emplace_back(RelocSection(m_sectionIdCount, targetSectId, sectName, isRelFormat));
323 ++m_sectionIdCount;
324 return m_relocSections.back();
325 }
326
addRelRelocation(uint64_t offset,std::string symName,R_TYPE_ZEBIN type,SectionID sectionId)327 void ZEELFObjectBuilder::addRelRelocation(
328 uint64_t offset, std::string symName, R_TYPE_ZEBIN type, SectionID sectionId)
329 {
330 RelocSection& reloc_sect = getOrCreateRelocSection(sectionId, true);
331 // create the relocation
332 reloc_sect.m_Relocations.emplace_back(
333 ZEELFObjectBuilder::Relocation(offset, symName, type));
334 }
335
addRelaRelocation(uint64_t offset,std::string symName,R_TYPE_ZEBIN type,uint64_t addend,SectionID sectionId)336 void ZEELFObjectBuilder::addRelaRelocation(
337 uint64_t offset, std::string symName, R_TYPE_ZEBIN type, uint64_t addend, SectionID sectionId)
338 {
339 RelocSection& reloc_sect = getOrCreateRelocSection(sectionId, false);
340 // create the relocation
341 reloc_sect.m_Relocations.emplace_back(
342 ZEELFObjectBuilder::Relocation(offset, symName, type, addend));
343 }
344
finalize(llvm::raw_pwrite_stream & os)345 uint64_t ZEELFObjectBuilder::finalize(llvm::raw_pwrite_stream& os)
346 {
347 ELFWriter w(os, *this);
348 return w.write();
349 }
350
351 ZEELFObjectBuilder::SectionID
getSectionIDBySectionName(const char * name)352 ZEELFObjectBuilder::getSectionIDBySectionName(const char* name)
353 {
354 for (StandardSection& sect : m_textSections) {
355 if (strcmp(name, sect.m_sectName.c_str()) == 0)
356 return sect.id();
357 }
358 for (StandardSection& sect : m_dataAndbssSections) {
359 if (strcmp(name, sect.m_sectName.c_str()) == 0)
360 return sect.id();
361 }
362 for (StandardSection& sect : m_otherStdSections) {
363 if (strcmp(name, sect.m_sectName.c_str()) == 0)
364 return sect.id();
365 }
366
367 IGC_ASSERT_MESSAGE(0, "getSectionIDBySectionName: section not found");
368 return 0;
369 }
370
getSectionNameBySectionID(SectionID id)371 std::string ZEELFObjectBuilder::getSectionNameBySectionID(SectionID id)
372 {
373 // do linear search that we assume there won't be too many sections
374 for (StandardSection& sect : m_textSections) {
375 if (sect.id() == id)
376 return sect.m_sectName;
377 }
378 for (StandardSection& sect : m_dataAndbssSections) {
379 if (sect.id() == id)
380 return sect.m_sectName;
381 }
382 for (StandardSection& sect : m_otherStdSections) {
383 if (sect.id() == id)
384 return sect.m_sectName;
385 }
386 IGC_ASSERT_MESSAGE(0, "getSectionNameBySectionID: invalid SectionID");
387 return "";
388 }
389
writeSectionData(const uint8_t * data,uint64_t size,uint32_t padding)390 uint64_t ELFWriter::writeSectionData(const uint8_t* data, uint64_t size, uint32_t padding)
391 {
392 uint64_t start_off = m_W.OS.tell();
393
394 // it's possible that a section has only pading but no data
395 if (data != nullptr)
396 m_W.OS.write((const char*)data, size);
397
398 writePadding(padding);
399
400 IGC_ASSERT((m_W.OS.tell() - start_off) == (size + padding));
401 return m_W.OS.tell() - start_off;
402 }
403
writePadding(uint32_t size)404 void ELFWriter::writePadding(uint32_t size)
405 {
406 for (uint32_t i = 0; i < size; ++i)
407 m_W.write<uint8_t>(0x0);
408 }
409
getSymTabEntSize()410 uint32_t ELFWriter::getSymTabEntSize()
411 {
412 if (is64Bit())
413 return sizeof(ELF::Elf64_Sym);
414 else
415 return sizeof(ELF::Elf32_Sym);
416 }
417
getRelocTabEntSize(bool isRelFormat)418 uint32_t ELFWriter::getRelocTabEntSize(bool isRelFormat)
419 {
420 if (is64Bit())
421 return isRelFormat ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf64_Rela);
422 else
423 return isRelFormat ? sizeof(ELF::Elf32_Rel) : sizeof(ELF::Elf32_Rela);
424 }
425
writeSymbol(uint32_t name,uint64_t value,uint64_t size,uint8_t binding,uint8_t type,uint8_t other,uint16_t shndx)426 void ELFWriter::writeSymbol(uint32_t name, uint64_t value, uint64_t size,
427 uint8_t binding, uint8_t type, uint8_t other, uint16_t shndx)
428 {
429 uint8_t info = (binding << 4) | (type & 0xf);
430 if (is64Bit()) {
431 m_W.write(name); // st_name
432 m_W.write(info); // st_info
433 m_W.write(other); // st_other
434 m_W.write(shndx); // st_shndx
435 writeWord(value); // st_value
436 writeWord(size); // st_size
437 } else {
438 m_W.write(name); // st_name
439 writeWord(value); // st_value
440 writeWord(size); // st_size
441 m_W.write(info); // st_info
442 m_W.write(other); // st_other
443 m_W.write(shndx); // st_shndx
444 }
445 }
446
writeRelRelocation(uint64_t offset,uint64_t type,uint64_t symIdx)447 void ELFWriter::writeRelRelocation(uint64_t offset, uint64_t type, uint64_t symIdx)
448 {
449 if (is64Bit()) {
450 uint64_t info = (symIdx << 32) | (type & 0xffffffffL);
451 m_W.write(offset);
452 m_W.write(info);
453 } else {
454 uint32_t info = ((uint32_t)symIdx << 8) | ((unsigned char)type);
455 m_W.write(uint32_t(offset));
456 m_W.write(info);
457 }
458 }
459
writeRelaRelocation(uint64_t offset,uint64_t type,uint64_t symIdx,uint64_t addend)460 void ELFWriter::writeRelaRelocation(uint64_t offset, uint64_t type, uint64_t symIdx, uint64_t addend)
461 {
462 writeRelRelocation(offset, type, symIdx);
463 if (is64Bit()) {
464 m_W.write(addend);
465 } else {
466 m_W.write(uint32_t(addend));
467 }
468 }
469
writeRelocTab(const RelocationListTy & relocs,bool isRelFormat)470 uint64_t ELFWriter::writeRelocTab(const RelocationListTy& relocs, bool isRelFormat)
471 {
472 uint64_t start_off = m_W.OS.tell();
473
474 for (const ZEELFObjectBuilder::Relocation& reloc : relocs) {
475 // the target symbol's name must have been added into symbol table
476 IGC_ASSERT(m_SymNameIdxMap.find(reloc.symName()) != m_SymNameIdxMap.end());
477
478 if (isRelFormat)
479 writeRelRelocation(
480 reloc.offset(), reloc.type(), m_SymNameIdxMap[reloc.symName()]);
481 else
482 writeRelaRelocation(
483 reloc.offset(), reloc.type(), m_SymNameIdxMap[reloc.symName()], reloc.addend());
484 }
485
486 return m_W.OS.tell() - start_off;
487 }
488
writeSymTab()489 uint64_t ELFWriter::writeSymTab()
490 {
491 uint64_t start_off = m_W.OS.tell();
492
493 uint64_t symidx = 0;
494
495 // index 0 is the null symbol
496 writeSymbol(0, 0, 0, 0, 0, 0, ELF::SHN_UNDEF);
497 ++symidx;
498
499 auto writeOneSym = [&](ZEELFObjectBuilder::Symbol& sym) {
500 // create symbol name entry in str table
501 uint32_t nameoff = m_StrTabBuilder.add(StringRef(sym.name()));
502
503 uint16_t sect_idx = 0;
504 if (sym.sectionId() >= 0) {
505 // the given section's index must have been adjusted in
506 // createSectionHdrEntries
507 IGC_ASSERT(m_SectionIndex.find(sym.sectionId()) != m_SectionIndex.end());
508 sect_idx = m_SectionIndex.at(sym.sectionId());
509 }
510 else {
511 sect_idx = ELF::SHN_UNDEF;
512 }
513
514 writeSymbol(nameoff, sym.addr(), sym.size(), sym.binding(), sym.type(),
515 0, sect_idx);
516 // global symbol name must be unique
517 IGC_ASSERT(sym.binding() != llvm::ELF::STB_GLOBAL || m_SymNameIdxMap.find(sym.name()) == m_SymNameIdxMap.end());
518 m_SymNameIdxMap.insert(std::make_pair(sym.name(), symidx));
519 ++symidx;
520 };
521
522 // Write the local symbols first
523 for (ZEELFObjectBuilder::Symbol& sym : m_ObjBuilder.m_localSymbols) {
524 writeOneSym(sym);
525 }
526
527 // And then global symbols
528 for (ZEELFObjectBuilder::Symbol& sym : m_ObjBuilder.m_globalSymbols) {
529 writeOneSym(sym);
530 }
531
532 return m_W.OS.tell() - start_off;
533 }
534
writeZEInfo()535 uint64_t ELFWriter::writeZEInfo()
536 {
537 uint64_t start_off = m_W.OS.tell();
538 // serialize ze_info contents
539 llvm::yaml::Output yout(m_W.OS);
540 IGC_ASSERT(m_ObjBuilder.m_zeInfoSection);
541 yout << m_ObjBuilder.m_zeInfoSection->getZeInfo();
542
543 return m_W.OS.tell() - start_off;
544 }
545
writeCompatibilityNote()546 std::pair<uint64_t, uint64_t> ELFWriter::writeCompatibilityNote() {
547 auto padToRequiredAlign = [&]() {
548 // The alignment of the Elf word, name and descriptor is 4.
549 // Implementations differ from the specification here: in practice all
550 // variants align both the name and descriptor to 4-bytes.
551 uint64_t cur = m_W.OS.tell();
552 uint64_t next = llvm::alignTo(cur, 4);
553 writePadding(next - cur);
554 };
555
556 auto writeOneNote = [&](StringRef owner, auto desc, uint32_t type) {
557 // It's easier to use uint32_t directly now because both Elf32_Word and
558 // Elf64_Word are uint32_t.
559 // TODO: Use template implementation to handle ELF32 and ELF64 cases.
560 m_W.write<uint32_t>(owner.size() + 1);
561 m_W.write<uint32_t>(sizeof(desc));
562 m_W.write<uint32_t>(type);
563 m_W.OS << owner << '\0';
564 padToRequiredAlign();
565 m_W.write(desc);
566 padToRequiredAlign();
567 };
568
569 // Align the section offset to the required alignment first.
570 // TODO: Handle the section alignment in a more generic place..
571 padToRequiredAlign();
572 uint64_t start_off = m_W.OS.tell();
573 // write NT_INTELGT_PRODUCT_FAMILY
574 writeOneNote("IntelGT",
575 static_cast<uint32_t>(m_ObjBuilder.m_productFamily),
576 NT_INTELGT_PRODUCT_FAMILY);
577
578 // write NT_INTELGT_GFXCORE_FAMILY_
579 writeOneNote("IntelGT",
580 static_cast<uint32_t>(m_ObjBuilder.m_gfxCoreFamily),
581 NT_INTELGT_GFXCORE_FAMILY);
582
583 // write NT_INTELGT_TARGET_METADATA
584 writeOneNote("IntelGT",
585 m_ObjBuilder.m_metadata.packed,
586 NT_INTELGT_TARGET_METADATA);
587 return std::make_pair(start_off, m_W.OS.tell() - start_off);
588 }
589
writeStrTab()590 uint64_t ELFWriter::writeStrTab()
591 {
592 uint64_t start_off = m_W.OS.tell();
593
594 // at this point, all strings should be added. Finalized the string table
595 // and write it to OS
596 // must finalize it in order, that we take the offset of
597 // section and symbols' name when added
598 m_StrTabBuilder.finalizeInOrder();
599 m_StrTabBuilder.write(m_W.OS);
600
601 return m_W.OS.tell() - start_off;
602 }
603
writeSecHdrEntry(uint32_t name,uint32_t type,uint64_t flags,uint64_t address,uint64_t offset,uint64_t size,uint32_t link,uint32_t info,uint64_t addralign,uint64_t entsize)604 void ELFWriter::writeSecHdrEntry(uint32_t name, uint32_t type, uint64_t flags,
605 uint64_t address, uint64_t offset,
606 uint64_t size, uint32_t link, uint32_t info,
607 uint64_t addralign, uint64_t entsize)
608 {
609 m_W.write(name); // sh_name
610 m_W.write(type); // sh_type
611 writeWord(flags); // sh_flags
612 writeWord(address); // sh_addr
613 writeWord(offset); // sh_offset
614 writeWord(size); // sh_size
615 m_W.write(link); // sh_link
616 m_W.write(info); // sh_info
617 writeWord(addralign); // sh_addralign
618 writeWord(entsize); // sh_entsize
619 }
620
writeSectionHeader()621 void ELFWriter::writeSectionHeader()
622 {
623 // all SectionHdrEntry fields should be fill-up in either
624 // createSectionHdrEntries or writeSections
625 for (SectionHdrEntry& entry : m_SectionHdrEntries) {
626 writeSecHdrEntry(
627 entry.name, entry.type, 0, 0, entry.offset, entry.size, entry.link,
628 entry.info, 0, entry.entsize);
629 }
630 }
631
writeSections()632 void ELFWriter::writeSections()
633 {
634 for (SectionHdrEntry& entry : m_SectionHdrEntries) {
635 entry.offset = m_W.OS.tell();
636
637 switch(entry.type) {
638 case ELF::SHT_PROGBITS:
639 case SHT_ZEBIN_VISAASM:
640 case SHT_ZEBIN_SPIRV:
641 case SHT_ZEBIN_GTPIN_INFO: {
642 IGC_ASSERT(nullptr != entry.section);
643 IGC_ASSERT(entry.section->getKind() == Section::STANDARD);
644 const StandardSection* const stdsect =
645 static_cast<const StandardSection*>(entry.section);
646 IGC_ASSERT(nullptr != stdsect);
647 IGC_ASSERT(stdsect->m_size + stdsect->m_padding);
648 entry.size = writeSectionData(
649 stdsect->m_data, stdsect->m_size, stdsect->m_padding);
650 break;
651 }
652 case ELF::SHT_NOBITS: {
653 const StandardSection* const stdsect =
654 static_cast<const StandardSection*>(entry.section);
655 IGC_ASSERT(nullptr != stdsect);
656 entry.size = stdsect->m_size;
657 break;
658 }
659 case ELF::SHT_SYMTAB:
660 entry.size = writeSymTab();
661 entry.entsize = getSymTabEntSize();
662 entry.link = m_StringTableIndex;
663 // one greater than the last local symbol index, including the
664 // first null symbol
665 entry.info = m_ObjBuilder.m_localSymbols.size() + 1;
666 break;
667
668 case ELF::SHT_REL:
669 case ELF::SHT_RELA: {
670 IGC_ASSERT(nullptr != entry.section);
671 IGC_ASSERT(entry.section->getKind() == Section::RELOC);
672 const RelocSection* const relocSec =
673 static_cast<const RelocSection*>(entry.section);
674 IGC_ASSERT(nullptr != relocSec);
675 entry.size = writeRelocTab(relocSec->m_Relocations, relocSec->isRelFormat());
676 entry.entsize = getRelocTabEntSize(relocSec->isRelFormat());
677 break;
678 }
679 case SHT_ZEBIN_ZEINFO:
680 entry.size = writeZEInfo();
681 break;
682
683 case ELF::SHT_STRTAB:
684 entry.size = writeStrTab();
685 break;
686
687 case ELF::SHT_NULL:
688 // the first entry
689 entry.size =
690 (m_SectionHdrEntries.size() + 1) >= ELF::SHN_LORESERVE ?
691 (m_SectionHdrEntries.size() + 1) : 0;
692 break;
693
694 case ELF::SHT_NOTE: {
695 // Currently we don't seem to reorder strings in the .strtab, and
696 // the offset returned by LLVM StringTableBuilder::add() will still
697 // be valid, so the section name can be checked in this way. Other
698 // possibilities are creating a new section kind and set the
699 // appropriate section pointer, or emitting .strtab before the note
700 // section.
701 auto strtabSize = m_StrTabBuilder.getSize();
702 if (entry.name == m_StrTabBuilder.add(m_ObjBuilder.m_CompatNoteName)) {
703 IGC_ASSERT(entry.name < strtabSize);
704 std::tie(entry.offset, entry.size) = writeCompatibilityNote();
705 break;
706 }
707 }
708
709 default:
710 IGC_ASSERT(0);
711 break;
712 }
713 }
714 }
715
writeSectionHdrOffset(uint64_t offset)716 void ELFWriter::writeSectionHdrOffset(uint64_t offset)
717 {
718 auto &stream = static_cast<raw_pwrite_stream &>(m_W.OS);
719
720 if (is64Bit()) {
721 uint64_t Val =
722 support::endian::byte_swap<uint64_t>(offset, m_W.Endian);
723 stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
724 offsetof(ELF::Elf64_Ehdr, e_shoff));
725
726 } else {
727 uint32_t Val =
728 support::endian::byte_swap<uint32_t>(
729 static_cast<uint32_t>(offset), m_W.Endian);
730 stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
731 offsetof(ELF::Elf32_Ehdr, e_shoff));
732 }
733 }
734
writeHeader()735 void ELFWriter::writeHeader()
736 {
737 // e_ident[EI_MAG0] to e_ident[EI_MAG3]
738 m_W.OS << ELF::ElfMagic;
739
740 // e_ident[EI_CLASS]
741 m_W.OS << char(m_ObjBuilder.m_is64Bit ? ELF::ELFCLASS64 : ELF::ELFCLASS32);
742
743 // e_ident[EI_DATA]
744 m_W.OS << char(ELF::ELFDATA2LSB);
745
746 // e_ident[EI_VERSION]
747 m_W.OS << char(ELF::EV_CURRENT);
748
749 // e_ident padding
750 m_W.OS.write_zeros(ELF::EI_NIDENT - ELF::EI_OSABI);
751
752 // e_type: Currently IGC always emits a relocatable file
753 m_W.write<uint16_t>(ELF::ET_REL);
754
755 // e_machine
756 m_W.write<uint16_t>(EM_INTELGT);
757
758 // e_version
759 m_W.write<uint32_t>(ELF::EV_CURRENT);
760
761 // e_entry, no entry point
762 writeWord(0);
763
764 // e_phoff, no program header
765 writeWord(0);
766
767 // e_shoff, will write it later
768 writeWord(0);
769
770 // e_flags
771 m_W.write<uint32_t>(0);
772
773 // e_ehsize = ELF header size
774 m_W.write<uint16_t>(is64Bit() ?
775 sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr));
776
777 m_W.write<uint16_t>(0); // e_phentsize = prog header entry size
778 m_W.write<uint16_t>(0); // e_phnum = # prog header entries = 0
779
780 // e_shentsize
781 m_W.write<uint16_t>(is64Bit() ?
782 sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr));
783
784 // e_shnum
785 m_W.write<uint16_t>(numOfSections());
786
787 // e_shstrndx = .strtab index
788 m_W.write<uint16_t>(m_StringTableIndex);
789 }
790
numOfSections()791 uint16_t ELFWriter::numOfSections()
792 {
793 // string table is the last section in this file
794 return m_StringTableIndex + 1;
795 }
796
ELFWriter(llvm::raw_pwrite_stream & OS,ZEELFObjectBuilder & objBuilder)797 ELFWriter::ELFWriter(llvm::raw_pwrite_stream& OS,
798 ZEELFObjectBuilder& objBuilder)
799 : m_W(OS, llvm::support::little), m_ObjBuilder(objBuilder)
800 {
801 }
802
write()803 uint64_t ELFWriter::write()
804 {
805 uint64_t start = m_W.OS.tell();
806 createSectionHdrEntries();
807 writeHeader();
808 writeSections();
809 uint64_t sectHdrOff = m_W.OS.tell();
810 writeSectionHeader();
811 writeSectionHdrOffset(sectHdrOff);
812 return m_W.OS.tell() - start;
813 }
814
createNullSectionHdrEntry()815 ELFWriter::SectionHdrEntry& ELFWriter::createNullSectionHdrEntry()
816 {
817 m_SectionHdrEntries.emplace_back(SectionHdrEntry());
818 SectionHdrEntry& entry = m_SectionHdrEntries.back();
819 entry.type = ELF::SHT_NULL;
820 entry.name = 0;
821 return entry;
822 }
823
createSectionHdrEntry(const std::string & name,unsigned type,const Section * sect)824 ELFWriter::SectionHdrEntry& ELFWriter::createSectionHdrEntry(
825 const std::string& name, unsigned type, const Section* sect)
826 {
827 m_SectionHdrEntries.emplace_back(SectionHdrEntry());
828 SectionHdrEntry& entry = m_SectionHdrEntries.back();
829 entry.type = type;
830 entry.section = sect;
831 uint32_t nameoff = m_StrTabBuilder.add(StringRef(name));
832 entry.name = nameoff;
833 return entry;
834 }
835
createSectionHdrEntries()836 void ELFWriter::createSectionHdrEntries()
837 {
838 // adjust the sections' order in ELF and set m_SectionIndex, m_SymTabIndex,
839 // m_RelTabIndex and m_StringTableIndex
840 // Sections will be layout as
841 // .text
842 // .data
843 // .symtab
844 // all other standard sections follow the order of being added (spv, debug)
845 // .rel and .rela
846 // .ze_info
847 // .strtab
848
849 // first entry is NULL section
850 createNullSectionHdrEntry();
851
852 uint32_t index = 1;
853 // .text
854 for (StandardSection& sect : m_ObjBuilder.m_textSections) {
855 m_SectionIndex.insert(std::make_pair(sect.id(), index));
856 ++index;
857 createSectionHdrEntry(sect.m_sectName, sect.m_type, §);
858 }
859
860 // .data
861 for (StandardSection& sect : m_ObjBuilder.m_dataAndbssSections) {
862 m_SectionIndex.insert(std::make_pair(sect.id(), index));
863 ++index;
864 createSectionHdrEntry(sect.m_sectName, sect.m_type, §);
865 }
866
867 // .symtab
868 if (!m_ObjBuilder.m_localSymbols.empty() ||
869 !m_ObjBuilder.m_globalSymbols.empty()) {
870 m_SymTabIndex = index;
871 ++index;
872 createSectionHdrEntry(m_ObjBuilder.m_SymTabName, ELF::SHT_SYMTAB);
873 }
874
875 // other sections
876 for (StandardSection& sect : m_ObjBuilder.m_otherStdSections) {
877 m_SectionIndex.insert(std::make_pair(sect.id(), index));
878 ++index;
879 createSectionHdrEntry(sect.m_sectName, sect.m_type, §);
880 }
881
882 // .rel and .rela
883 if (!m_ObjBuilder.m_relocSections.empty()) {
884 // go through relocation sections
885 for (RelocSection& sect : m_ObjBuilder.m_relocSections) {
886 SectionHdrEntry& entry =
887 sect.isRelFormat() ?
888 createSectionHdrEntry(sect.m_sectName, ELF::SHT_REL, §) :
889 createSectionHdrEntry(sect.m_sectName, ELF::SHT_RELA, §);
890 // set apply target's section index
891 // relocations could only apply to standard sections. At this point,
892 // all standard section's section index should be adjusted
893 IGC_ASSERT(m_SectionIndex.find(sect.m_TargetID) != m_SectionIndex.end());
894 entry.info = m_SectionIndex.at(sect.m_TargetID);
895 entry.link = m_SymTabIndex;
896 ++index;
897 }
898 }
899
900 // .ze_info
901 if (m_ObjBuilder.m_zeInfoSection) {
902 createSectionHdrEntry(m_ObjBuilder.m_ZEInfoName, SHT_ZEBIN_ZEINFO,
903 m_ObjBuilder.m_zeInfoSection.get());
904 ++index;
905 }
906
907 // .note.intelgt.compat
908 // Create the compatibility note section
909 createSectionHdrEntry(m_ObjBuilder.m_CompatNoteName, ELF::SHT_NOTE);
910 ++index;
911
912 // .strtab
913 m_StringTableIndex = index;
914 createSectionHdrEntry(m_ObjBuilder.m_StrTabName, ELF::SHT_STRTAB);
915 }
916
917 // createKernel - create a zeInfoKernel and add it into zeInfoContainer
createKernel(const std::string & name)918 zeInfoKernel& ZEInfoBuilder::createKernel(const std::string& name)
919 {
920 mContainer.kernels.emplace_back();
921 zeInfoKernel& k = mContainer.kernels.back();
922 k.name = name;
923 return k;
924 }
925
empty() const926 bool ZEInfoBuilder::empty() const
927 {
928 return mContainer.kernels.empty();
929 }
930
931 // addPayloadArgumentByPointer - add explicit kernel argument with pointer
932 // type into given arg_list
addPayloadArgumentByPointer(PayloadArgumentsTy & arg_list,int32_t offset,int32_t size,int32_t arg_index,PreDefinedAttrGetter::ArgAddrMode addrmode,PreDefinedAttrGetter::ArgAddrSpace addrspace,PreDefinedAttrGetter::ArgAccessType access_type)933 zeInfoPayloadArgument& ZEInfoBuilder::addPayloadArgumentByPointer(
934 PayloadArgumentsTy& arg_list,
935 int32_t offset,
936 int32_t size,
937 int32_t arg_index,
938 PreDefinedAttrGetter::ArgAddrMode addrmode,
939 PreDefinedAttrGetter::ArgAddrSpace addrspace,
940 PreDefinedAttrGetter::ArgAccessType access_type)
941 {
942 arg_list.emplace_back();
943 zeInfoPayloadArgument& arg = arg_list.back();
944 arg.arg_type = PreDefinedAttrGetter::get(PreDefinedAttrGetter::ArgType::arg_bypointer);
945 arg.offset = offset;
946 arg.size = size;
947 arg.arg_index = arg_index;
948 arg.addrmode = PreDefinedAttrGetter::get(addrmode);
949 arg.addrspace = PreDefinedAttrGetter::get(addrspace);
950 arg.access_type = PreDefinedAttrGetter::get(access_type);
951 return arg;
952 }
953
954 // addPayloadArgumentSampler - add explicit kernel argument for sampler
955 // into given arg_list
956 // The argument type will be set to by_pointer, and addr_space will be set to sampler
addPayloadArgumentSampler(PayloadArgumentsTy & arg_list,int32_t offset,int32_t size,int32_t arg_index,int32_t sampler_index,PreDefinedAttrGetter::ArgAddrMode addrmode,PreDefinedAttrGetter::ArgAccessType access_type)957 zeInfoPayloadArgument& ZEInfoBuilder::addPayloadArgumentSampler(
958 PayloadArgumentsTy& arg_list,
959 int32_t offset,
960 int32_t size,
961 int32_t arg_index,
962 int32_t sampler_index,
963 PreDefinedAttrGetter::ArgAddrMode addrmode,
964 PreDefinedAttrGetter::ArgAccessType access_type)
965 {
966 zeInfoPayloadArgument& arg = addPayloadArgumentByPointer(arg_list, offset, size, arg_index, addrmode,
967 PreDefinedAttrGetter::ArgAddrSpace::sampler, access_type);
968 arg.sampler_index = sampler_index;
969 return arg;
970 }
971
972 // addPayloadArgumentByValue - add explicit kernel argument with pass by
973 // value type into given arg_list
addPayloadArgumentByValue(PayloadArgumentsTy & arg_list,int32_t offset,int32_t size,int32_t arg_index)974 zeInfoPayloadArgument& ZEInfoBuilder::addPayloadArgumentByValue(
975 PayloadArgumentsTy& arg_list,
976 int32_t offset,
977 int32_t size,
978 int32_t arg_index)
979 {
980 arg_list.emplace_back();
981 zeInfoPayloadArgument& arg = arg_list.back();
982 arg.arg_type = PreDefinedAttrGetter::get(PreDefinedAttrGetter::ArgType::arg_byvalue);
983 arg.offset = offset;
984 arg.size = size;
985 arg.arg_index = arg_index;
986 return arg;
987 }
988
989 // addPayloadArgumentImplicit - add non-user argument (implicit argument)
990 // into given zeKernel. The type must be local_size, group_size,
991 // global_id_offset or private_base_stateless
addPayloadArgumentImplicit(PayloadArgumentsTy & arg_list,PreDefinedAttrGetter::ArgType type,int32_t offset,int32_t size)992 zeInfoPayloadArgument& ZEInfoBuilder::addPayloadArgumentImplicit(
993 PayloadArgumentsTy& arg_list,
994 PreDefinedAttrGetter::ArgType type,
995 int32_t offset,
996 int32_t size)
997 {
998 arg_list.emplace_back();
999 zeInfoPayloadArgument& arg = arg_list.back();
1000 arg.arg_type = PreDefinedAttrGetter::get(type);
1001 arg.offset = offset;
1002 arg.size = size;
1003 return arg;
1004 }
1005
1006 // addPerThreadPayloadArgument - add a per-thread payload argument into
1007 // given kernel. Currently we only support local id as per-thread argument.
1008 // The given type must be packed_local_ids or local_id
addPerThreadPayloadArgument(PerThreadPayloadArgumentsTy & arg_list,PreDefinedAttrGetter::ArgType type,int32_t offset,int32_t size)1009 zeInfoPerThreadPayloadArgument& ZEInfoBuilder::addPerThreadPayloadArgument(
1010 PerThreadPayloadArgumentsTy& arg_list,
1011 PreDefinedAttrGetter::ArgType type,
1012 int32_t offset,
1013 int32_t size)
1014 {
1015 arg_list.emplace_back();
1016 zeInfoPerThreadPayloadArgument& arg = arg_list.back();
1017 arg.arg_type = PreDefinedAttrGetter::get(type);
1018 arg.offset = offset;
1019 arg.size = size;
1020 return arg;
1021 }
1022
1023 // addBindingTableIndex - add a binding table index into kernel, with
1024 // corresponding kernel argument index
addBindingTableIndex(BindingTableIndicesTy & bti_list,int32_t bti_value,int32_t arg_index)1025 zeInfoBindingTableIndex& ZEInfoBuilder::addBindingTableIndex(
1026 BindingTableIndicesTy& bti_list,
1027 int32_t bti_value,
1028 int32_t arg_index)
1029 {
1030 bti_list.emplace_back();
1031 zeInfoBindingTableIndex& bti = bti_list.back();
1032 bti.bti_value = bti_value;
1033 bti.arg_index = arg_index;
1034 return bti;
1035 }
1036
addPerThreadMemoryBuffer(PerThreadMemoryBuffersTy & mem_buff_list,PreDefinedAttrGetter::MemBufferType type,PreDefinedAttrGetter::MemBufferUsage usage,int32_t size)1037 zeInfoPerThreadMemoryBuffer& ZEInfoBuilder::addPerThreadMemoryBuffer(
1038 PerThreadMemoryBuffersTy& mem_buff_list,
1039 PreDefinedAttrGetter::MemBufferType type,
1040 PreDefinedAttrGetter::MemBufferUsage usage,
1041 int32_t size)
1042 {
1043 // use addScratchPerThreadMemoryBuffer API to add scratch buffer
1044 IGC_ASSERT(type != PreDefinedAttrGetter::MemBufferType::scratch);
1045 mem_buff_list.emplace_back();
1046 zeInfoPerThreadMemoryBuffer& info = mem_buff_list.back();
1047 info.type = PreDefinedAttrGetter::get(type);
1048 info.usage = PreDefinedAttrGetter::get(usage);
1049 info.size = size;
1050 return info;
1051 }
1052
addScratchPerThreadMemoryBuffer(PerThreadMemoryBuffersTy & mem_buff_list,PreDefinedAttrGetter::MemBufferUsage usage,int32_t slot_id,int32_t size)1053 zeInfoPerThreadMemoryBuffer& ZEInfoBuilder::addScratchPerThreadMemoryBuffer(
1054 PerThreadMemoryBuffersTy& mem_buff_list,
1055 PreDefinedAttrGetter::MemBufferUsage usage,
1056 int32_t slot_id,
1057 int32_t size)
1058 {
1059 mem_buff_list.emplace_back();
1060 zeInfoPerThreadMemoryBuffer& info = mem_buff_list.back();
1061 info.type = PreDefinedAttrGetter::get(PreDefinedAttrGetter::MemBufferType::scratch);
1062 info.usage = PreDefinedAttrGetter::get(usage);
1063 info.size = size;
1064 info.slot = slot_id;
1065 return info;
1066 }
1067
addPerSIMTThreadGlobalMemoryBuffer(PerThreadMemoryBuffersTy & mem_buff_list,PreDefinedAttrGetter::MemBufferUsage usage,int32_t size)1068 zeInfoPerThreadMemoryBuffer& ZEInfoBuilder::addPerSIMTThreadGlobalMemoryBuffer(
1069 PerThreadMemoryBuffersTy& mem_buff_list,
1070 PreDefinedAttrGetter::MemBufferUsage usage,
1071 int32_t size)
1072 {
1073 mem_buff_list.emplace_back();
1074 zeInfoPerThreadMemoryBuffer& info = mem_buff_list.back();
1075 info.type = PreDefinedAttrGetter::get(PreDefinedAttrGetter::MemBufferType::global);
1076 info.usage = PreDefinedAttrGetter::get(usage);
1077 info.size = size;
1078 info.is_simt_thread = true;
1079 return info;
1080 }
1081
addExpPropertiesHasNonKernelArgLdSt(zeInfoKernel & zekernel,bool hasNonKernelArgLoad,bool hasNonKernelArgStore,bool hasNonKernelArgAtomic)1082 void ZEInfoBuilder::addExpPropertiesHasNonKernelArgLdSt(zeInfoKernel& zekernel,
1083 bool hasNonKernelArgLoad, bool hasNonKernelArgStore, bool hasNonKernelArgAtomic)
1084 {
1085 zeInfoExperimentalProperties& ep = zekernel.experimental_properties;
1086 ep.has_non_kernel_arg_load = hasNonKernelArgLoad;
1087 ep.has_non_kernel_arg_store = hasNonKernelArgStore;
1088 ep.has_non_kernel_arg_atomic = hasNonKernelArgAtomic;
1089 }
1090