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