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, &sect);
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, &sect);
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, &sect);
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, &sect) :
889                   createSectionHdrEntry(sect.m_sectName, ELF::SHT_RELA, &sect);
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