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 //===- ZEELFObjectBuilder.hpp -----------------------------------*- C++ -*-===//
10 // ZE Binary Utilities
11 //
12 // \file
13 // This file declares ZEELFObjectBuilder for building an ZE Binary object
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef ZE_ELF_OBJECT_BUILDER_HPP
17 #define ZE_ELF_OBJECT_BUILDER_HPP
18 
19 #include <ZEELF.h>
20 #include <ZEInfo.hpp>
21 #include "inc/common/igfxfmid.h"
22 
23 #ifndef ZEBinStandAloneBuild
24 #include "common/LLVMWarningsPush.hpp"
25 #endif
26 
27 #include "llvm/BinaryFormat/ELF.h"
28 
29 #ifndef ZEBinStandAloneBuild
30 #include "common/LLVMWarningsPop.hpp"
31 #endif
32 
33 #include <map>
34 #include <memory>
35 #include <string>
36 #include <vector>
37 
38 namespace llvm {
39     class raw_pwrite_stream;
40 }
41 
42 namespace zebin {
43 
44 /// ZEELFObjectBuilder - Build an ELF Object for ZE binary format
45 class ZEELFObjectBuilder {
46     friend class ELFWriter;
47 public:
48     // The valid SectionID must be 0 or positive value
49     typedef int32_t SectionID;
50 
51 public:
ZEELFObjectBuilder(bool is64Bit)52     ZEELFObjectBuilder(bool is64Bit) : m_is64Bit(is64Bit)
53     {
54         m_metadata.packed = 0;
55     }
56 
~ZEELFObjectBuilder()57     ~ZEELFObjectBuilder() {}
58 
setProductFamily(PRODUCT_FAMILY family)59     void setProductFamily(PRODUCT_FAMILY family) { m_productFamily = family; }
getProductFamily() const60     PRODUCT_FAMILY getProductFamily() const { return m_productFamily; }
61 
setGfxCoreFamily(GFXCORE_FAMILY family)62     void setGfxCoreFamily(GFXCORE_FAMILY family) { m_gfxCoreFamily = family; }
getGfxCoreFamily() const63     GFXCORE_FAMILY getGfxCoreFamily() const { return m_gfxCoreFamily; }
64 
setTargetMetadata(TargetMetadata metadata)65     void setTargetMetadata(TargetMetadata metadata) { m_metadata = metadata; }
getTargetMetadata() const66     TargetMetadata getTargetMetadata() const { return m_metadata; }
67 
68     // add a text section contains gen binary
69     // - name: section name. This is usually the kernel or function name of
70     //         this text section. Do not includes leading .text in given
71     //         name. For example, giving "kernel", the section name will be
72     //         .text.kernel
73     // - data: memory buffer of the section contents. This buffer must be live
74     //         through this ZEELFObjectBuilder
75     // - size: input buffer size in byte
76     // - padding: required padding at the end
77     // - align: alignment requirement in byte
78     // - return a unique id for referencing in addSymbol
79     // Currently we assume there is only one text section that'll be added
80     SectionID addSectionText(
81         std::string name, const uint8_t* data, uint64_t size, uint32_t padding, uint32_t align);
82 
83     // add a data section contains raw data, such as constant or global buffer.
84     // - name: section name. Do not includes leading .data in given
85     //         name. For example, giving "const", the section name will be
86     //         .data.const
87     // - data: memory buffer of the section contents. This buffer must be live through
88     //         this ZEELFObjectBuilder
89     // - size: input buffer size in byte
90     // - padding: required padding at the end
91     // - align: alignment requirement in byte
92     // - return a unique id for referencing in addSymbol
93     SectionID addSectionData(
94         std::string name, const uint8_t* data, uint64_t size, uint32_t padding = 0, uint32_t align = 0);
95 
96     // add a bss section which occupies no space in the ELF, but with size and other section information
97     // The bss sections could be used for zero-initialized variables.
98     // - name: section name. Do not includes leading .bss in given name.
99     //         For example, giving "const", the section name will be .bss.const
100     // - size: input buffer size in byte
101     // - padding: required padding at the end
102     // - align: alignment requirement in byte
103     // - return a unique id for referencing in addSymbol
104     SectionID addSectionBss(
105         std::string name, uint64_t size, uint32_t padding = 0, uint32_t align = 0);
106 
107     // add a spv section contains the spv source. This section will be set to SHT_ZEBIN_SPIRV type
108     // - name: section name. The default name is .spv
109     // - size in byte
110     // - Note that the alignment requirement of the section should be satisfied
111     //   by the given data and size
112     // - Note that the given data buffer have to be alive through
113     //   ZEELFObjectBuilder
114     void addSectionSpirv(std::string name, const uint8_t* data, uint64_t size);
115 
116     // add .gtpin_info section
117     // - name: section name. Do not includes leading .gtpin_info in the given
118     //         name. For example, giving "func", the section name will be
119     //         ".gtpin_info.func". The default name is .gtpin_fino. It'll be apply
120     //         if the given name is empty.
121     // - size in byte
122     // - Note that the alignment requirement of the section should be satisfied
123     //   by the given data and size
124     // - Note that the given data buffer have to be alive through
125     //   ZEELFObjectBuilder
126     void addSectionGTPinInfo(std::string name, const uint8_t* data, uint64_t size);
127 
128     // add .visaasm section
129     // - name: section name. Do not includes leading .visaasm in the given
130     //         name. For example, giving "func", the section name will be
131     //         ".visaasm.func". The default name is .visaasm. It'll be apply
132     //         if the given name is empty.
133     // - size in byte
134     // - Note that the alignment requirement of the section should be satisfied
135     //   by the given data and size
136     // - Note that the given data buffer have to be alive through ZEELFObjectBuilder
137     void addSectionVISAAsm(std::string name, const uint8_t* data, uint64_t size);
138 
139     // add .misc section
140     // - name: section name. Do not includes leading .misc in the given
141     //         name. For example, giving "func", the section name will be
142     //         ".misc.func". The default name is .misc. It'll be apply
143     //         if the given name is empty.
144     // - size in byte
145     // - Note that the alignment requirement of the section should be satisfied
146     //   by the given data and size
147     // - Note that the given data buffer have to be alive through ZEELFObjectBuilder
148     void addSectionMisc(std::string name, const uint8_t* data, uint64_t size);
149 
150     // .debug_info section in DWARF format
151     // - name: section name. The default name is .debug_info
152     // - size in byte
153     // - Note that the alignment requirement of the section should be satisfied
154     //   by the given data and size
155     // - Note that the given data buffer have to be alive through
156     //   ZEELFObjectBuilder
157     // - return a unique id for referencing in addSymbol
158     SectionID addSectionDebug(std::string name, const uint8_t* data, uint64_t size);
159 
160     // add ze_info section
161     void addSectionZEInfo(zeInfoContainer& zeInfo);
162 
163     // add a symbol
164     // - name    : symbol's name
165     // - addr    : symbol's address. The binary offset of where this symbol is
166     //             defined in the section
167     // - size    : symbol size
168     // - binding : symbol binding. The value is defined in ELF standard ST_BIND
169     // - type    : symbol type. The value is defined in ELF standard ST_TYPE
170     // - sectionId : the section id of which this symbol is defined in. Giving
171     //               -1 if this is an UNDEFINED symbol
172     void addSymbol(std::string name, uint64_t addr, uint64_t size,
173         uint8_t binding, uint8_t type, SectionID sectionId);
174 
175     // add a relocation with rel format
176     // This function will create a corresponding .rel.{targetSectionName} section if
177     // not exist
178     // - offset    : the binary offset of the section where the relocation
179     //               will apply to. The section is denoted by sectionId
180     // - symName   : the target symbol's name
181     // - type      : the relocation name
182     // - sectionId : the section id where the relocation is apply to
183     void addRelRelocation(
184         uint64_t offset, std::string symName, R_TYPE_ZEBIN type, SectionID sectionId);
185 
186     // add a relocation with rela format
187     // This function will create a corresponding .rela.{targetSectionName} section if
188     // not exist
189     // - offset    : the binary offset of the section where the relocation
190     //               will apply to. The section is denoted by sectionId
191     // - symName   : the target symbol's name
192     // - type      : the relocation name
193     // - addend    : the addend value
194     // - sectionId : the section id where the relocation is apply to
195     void addRelaRelocation(
196         uint64_t offset, std::string symName, R_TYPE_ZEBIN type, uint64_t addend, SectionID sectionId);
197 
198     // finalize - Finalize the ELF Object, write ELF file into given os
199     // return number of written bytes
200     uint64_t finalize(llvm::raw_pwrite_stream& os);
201 
202     // get an ID of a section
203     // - name  : section name
204     SectionID getSectionIDBySectionName(const char* name);
205 
206 private:
207     class Section {
208     public:
209         enum Kind {STANDARD, RELOC, ZEINFO};
210         virtual Kind getKind() const = 0;
211 
id() const212         SectionID id() const { return m_id; }
213 
214     protected:
Section(uint32_t id)215         Section(uint32_t id) : m_id(id) {}
~Section()216         virtual ~Section() {}
217         Section(const Section&) = default;
218         Section& operator=(const Section&) = default;
219 
220     protected:
221         SectionID m_id;
222     };
223 
224     class StandardSection : public Section {
225     public:
StandardSection(std::string sectName,const uint8_t * data,uint64_t size,unsigned type,uint32_t padding,uint32_t id)226         StandardSection(std::string sectName, const uint8_t* data, uint64_t size,
227             unsigned type, uint32_t padding, uint32_t id)
228             : Section(id), m_sectName(sectName), m_data(data), m_size(size), m_type(type),
229               m_padding(padding)
230         {}
231 
getKind() const232         Kind getKind() const { return STANDARD; }
233 
234         // m_sectName - the final name presented in ELF section header
235         // This field is required as the place holder for StringTable construction
236         std::string m_sectName;
237         const uint8_t* m_data;
238         uint64_t m_size;
239         // section type
240         unsigned m_type;
241         uint32_t m_padding;
242     };
243 
244     class ZEInfoSection : public Section {
245     public:
ZEInfoSection(zeInfoContainer & zeinfo,uint32_t id)246         ZEInfoSection(zeInfoContainer& zeinfo, uint32_t id)
247             : Section(id), m_zeinfo(zeinfo)
248         {}
249 
getKind() const250         Kind getKind() const { return ZEINFO; }
251 
getZeInfo()252         zeInfoContainer& getZeInfo()
253         { return m_zeinfo; }
254 
255     private:
256         zeInfoContainer& m_zeinfo;
257     };
258 
259     class Symbol {
260     public:
Symbol(std::string name,uint64_t addr,uint64_t size,uint8_t binding,uint8_t type,SectionID sectionId)261         Symbol(std::string name, uint64_t addr, uint64_t size, uint8_t binding,
262             uint8_t type, SectionID sectionId)
263             : m_name(name), m_addr(addr), m_size(size), m_binding(binding),
264             m_type(type), m_sectionId(sectionId)
265         {}
266 
name()267         std::string& name()            { return m_name;      }
addr() const268         uint64_t     addr()      const { return m_addr;      }
size() const269         uint64_t     size()      const { return m_size;      }
binding() const270         uint8_t      binding()   const { return m_binding;   }
type() const271         uint8_t      type()      const { return m_type;      }
sectionId() const272         SectionID    sectionId() const { return m_sectionId; }
273 
274     private:
275         std::string m_name;
276         uint64_t m_addr;
277         uint64_t m_size;
278         uint8_t m_binding;
279         uint8_t m_type;
280         SectionID m_sectionId;
281     };
282 
283     /// Relocation - present the relocation information of each entry.
284     /// The relocation itself doesn't know if it's in rel or rela format.
285     /// It's rel or rela depends on it's in RelocSection or RelaRelocSection
286     class Relocation {
287     public:
Relocation(uint64_t offset,std::string symName,R_TYPE_ZEBIN type,uint64_t addend=0)288         Relocation(uint64_t offset, std::string symName, R_TYPE_ZEBIN type, uint64_t addend = 0)
289             : m_offset(offset), m_symName(symName), m_type(type), m_addend(addend)
290         {}
291 
offset() const292         uint64_t            offset()  const { return m_offset;  }
symName() const293         const std::string&  symName() const { return m_symName; }
type() const294         R_TYPE_ZEBIN        type()    const { return m_type;    }
addend() const295         uint64_t            addend()  const { return m_addend;  }
296 
297     private:
298         uint64_t m_offset;
299         std::string m_symName;
300         R_TYPE_ZEBIN m_type;
301         uint64_t m_addend;
302     };
303 
304     typedef std::vector<StandardSection> StandardSectionListTy;
305     typedef std::vector<Symbol> SymbolListTy;
306     typedef std::vector<Relocation> RelocationListTy;
307 
308     class RelocSection : public Section {
309     public:
RelocSection(SectionID myID,SectionID targetID,std::string sectName,bool isRelFormat)310         RelocSection(SectionID myID, SectionID targetID, std::string sectName, bool isRelFormat) :
311             Section(myID), m_TargetID(targetID), m_sectName(sectName), m_isRelFormat (isRelFormat)
312         {}
313 
getKind() const314         Kind getKind() const { return RELOC; }
isRelFormat() const315         bool isRelFormat() const { return m_isRelFormat; }
316 
317     public:
318         // target section's id that this relocation section apply to
319         SectionID m_TargetID;
320         std::string m_sectName;
321         RelocationListTy m_Relocations;
322 
323         // This is a rel or rela relocation format
324         bool m_isRelFormat;
325     };
326     typedef std::vector<RelocSection> RelocSectionListTy;
327 
328 private:
329     Section& addStandardSection(
330         std::string sectName, const uint8_t* data, uint64_t size,
331         unsigned type, uint32_t padding, uint32_t align, StandardSectionListTy& sections);
332 
333     // isRelFormat - rel or rela relocation format
334     RelocSection& getOrCreateRelocSection(SectionID targetSectId, bool isRelFormat);
335 
336     std::string getSectionNameBySectionID(SectionID id);
337 
338 private:
339     // place holder for section default name
340     const std::string m_TextName       = ".text";
341     const std::string m_DataName       = ".data";
342     const std::string m_BssName        = ".bss";
343     const std::string m_SymTabName     = ".symtab";
344     const std::string m_RelName        = ".rel";
345     const std::string m_RelaName       = ".rela";
346     const std::string m_SpvName        = ".spv";
347     const std::string m_VISAAsmName    = ".visaasm";
348     const std::string m_DebugName      = ".debug_info";
349     const std::string m_ZEInfoName     = ".ze_info";
350     const std::string m_GTPinInfoName  = ".gtpin_info";
351     const std::string m_MiscName       = ".misc";
352     const std::string m_CompatNoteName = ".note.intelgt.compat";
353     const std::string m_StrTabName     = ".strtab";
354 
355 private:
356     // 32 or 64 bit object
357     bool m_is64Bit;
358 
359     // information used to generate .note.intelgt.compat
360     PRODUCT_FAMILY m_productFamily = IGFX_UNKNOWN;
361     GFXCORE_FAMILY m_gfxCoreFamily = IGFX_UNKNOWN_CORE;
362     TargetMetadata m_metadata;
363 
364     StandardSectionListTy m_textSections;
365     StandardSectionListTy m_dataAndbssSections; // data and bss sections
366     StandardSectionListTy m_otherStdSections;
367     RelocSectionListTy    m_relocSections; // rel and rela reloc sections
368 
369     // current section id
370     SectionID m_sectionIdCount = 0;
371 
372     // every ze object contains at most one ze_info section
373     std::unique_ptr<ZEInfoSection> m_zeInfoSection;
374     SymbolListTy m_localSymbols;
375     SymbolListTy m_globalSymbols;
376 
377 };
378 
379 /// ZEInfoBuilder - Build a zeInfoContainer for .ze_info section
380 class ZEInfoBuilder {
381 public:
ZEInfoBuilder()382     ZEInfoBuilder()
383     {
384         mContainer.version = PreDefinedAttrGetter::getVersionNumber();
385     }
386 
getZEInfoContainer()387     zeInfoContainer& getZEInfoContainer()             { return mContainer; }
getZEInfoContainer() const388     const zeInfoContainer& getZEInfoContainer() const { return mContainer; }
389 
390     // empty - return true if there is no kernel/function info in it
391     bool empty() const;
392 
393     /// --------- Helper functions for setup zeinfo contents -------------- ///
394     // createKernel - create a zeInfoKernel and add it into zeInfoContainer
395     zeInfoKernel& createKernel(const std::string& name);
396 
397     // addPayloadArgumentByPointer - add explicit kernel argument with pointer
398     // type into given arg_list
399     static zeInfoPayloadArgument& addPayloadArgumentByPointer(
400         PayloadArgumentsTy& arg_list,
401         int32_t offset,
402         int32_t size,
403         int32_t arg_index,
404         PreDefinedAttrGetter::ArgAddrMode addrmode,
405         PreDefinedAttrGetter::ArgAddrSpace addrspace,
406         PreDefinedAttrGetter::ArgAccessType access_type);
407 
408     // addPayloadArgumentByValue - add explicit kernel argument with pass by
409     // value type into given arg_list
410     static zeInfoPayloadArgument& addPayloadArgumentByValue(
411         PayloadArgumentsTy& arg_list,
412         int32_t offset,
413         int32_t size,
414         int32_t arg_index);
415 
416     // addPayloadArgumentSampler - add explicit kernel argument for sampler
417     // into given arg_list
418     // The argument type will be set to by_pointer, and addr_space will be set to sampler
419     static zeInfoPayloadArgument& addPayloadArgumentSampler(
420         PayloadArgumentsTy& arg_list,
421         int32_t offset,
422         int32_t size,
423         int32_t arg_index,
424         int32_t sampler_index,
425         PreDefinedAttrGetter::ArgAddrMode addrmode,
426         PreDefinedAttrGetter::ArgAccessType access_type);
427 
428     // addPayloadArgumentImplicit - add non-user argument (implicit argument)
429     // into given arg_list. The type must be local_size, group_size,
430     // global_id_offset or private_base_stateless
431     static zeInfoPayloadArgument& addPayloadArgumentImplicit(
432         PayloadArgumentsTy& arg_list,
433         PreDefinedAttrGetter::ArgType type,
434         int32_t offset,
435         int32_t size);
436 
437     // addPerThreadPayloadArgument - add a per-thread payload argument into
438     // arg_list. Currently we only support local id as per-thread argument.
439     // The given type must be packed_local_ids or local_id
440     static zeInfoPerThreadPayloadArgument& addPerThreadPayloadArgument(
441         PerThreadPayloadArgumentsTy& arg_list,
442         PreDefinedAttrGetter::ArgType type,
443         int32_t offset,
444         int32_t size);
445 
446     // addBindingTableIndex - add a binding table index into given bti_list, with
447     // corresponding kernel argument index
448     static zeInfoBindingTableIndex& addBindingTableIndex(
449         BindingTableIndicesTy& bti_list,
450         int32_t bti_value,
451         int32_t arg_index);
452 
453     // addPerThreadMemoryBuffer - add a memory buffer info with global or slm type
454     // If adding buffer with "global" type, this API assume it is allocated per-hardware-thread
455     // Use below addPerSIMTThreadGlobalMemoryBuffer API if attempting to add per-simt-thread global buffer
456     static zeInfoPerThreadMemoryBuffer& addPerThreadMemoryBuffer(
457         PerThreadMemoryBuffersTy& mem_buff_list,
458         PreDefinedAttrGetter::MemBufferType type,
459         PreDefinedAttrGetter::MemBufferUsage usage,
460         int32_t size);
461 
462     // addScratchPerThreadMemoryBuffer - add a memory buffer info for scratch buffer
463     // per_thread_memory_buffers::type set to scratch
464     static zeInfoPerThreadMemoryBuffer& addScratchPerThreadMemoryBuffer(
465         PerThreadMemoryBuffersTy& mem_buff_list,
466         PreDefinedAttrGetter::MemBufferUsage usage,
467         int32_t slot_id,
468         int32_t size);
469 
470     // addPerSIMTThreadGlobalMemoryBuffer - add a memory buffer info
471     // for global memory buffer with
472     // per_thread_memory_buffers::type set to global
473     // per_thread_memory_buffers::is_simt_thread set to true
474     // Use addPerThreadMemoryBuffer if adding per-hardware-thread global memory buffer
475     static zeInfoPerThreadMemoryBuffer& addPerSIMTThreadGlobalMemoryBuffer(
476         PerThreadMemoryBuffersTy& mem_buff_list,
477         PreDefinedAttrGetter::MemBufferUsage usage,
478         int32_t size);
479 
480     // addExpPropertiesHasNonKernelArgLdSt - add experimental_properties for has-non-kernel-arg-load-store analysis
481     // add experimental_properties::has_non_kernel_arg_load, experimental_properties::has_non_kernel_arg_store
482     // and experimental_properties::has_non_kernel_arg_atomic
483     // Note that zeInfoExperimentalProperties is made as a vector under kernel in the spec, because we want it only
484     // present when needed. If it's not a vector, the attribute name will always present in final output even if
485     // all of its sub-attributes are default and are not shown.
486     static void addExpPropertiesHasNonKernelArgLdSt(zeInfoKernel& zekernel,
487         bool hasNonKernelArgLoad, bool hasNonKernelArgStore, bool hasNonKernelArgAtomic);
488 
489 private:
490     zeInfoContainer mContainer;
491 };
492 
493 } // end namespace zebin
494 
495 #endif // ZE_ELF_OBJECT_BUILDER_HPP
496