From 484a3db8119a8102379851d670e195eca1b88612 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Sun, 30 Jul 2017 19:33:58 +0100 Subject: [PATCH 1/4] This changes the procedure for retrieving bundled code objects to follow the one developed for HC2. The symbols which point into the .kernel section are internalised so as to not be affected by interposition. At runtime, alongside the local .kernel section, all other such sections present in linked in shared objects are obtained via ELF introspection. This removes the need for using the Bsymbolic hack. Unit tests are corrected to reflect this. The ELFIO library is used for the introspection, and it is added into the folder which is to host HC2 in the near future. --- benchmarks/benchEmptyKernel/nullkernel.cpp | 2 +- hc2/external/elfio/elf_types.hpp | 749 ++++++++++++++ hc2/external/elfio/elfio.hpp | 848 ++++++++++++++++ hc2/external/elfio/elfio_dump.hpp | 972 +++++++++++++++++++ hc2/external/elfio/elfio_dynamic.hpp | 253 +++++ hc2/external/elfio/elfio_header.hpp | 146 +++ hc2/external/elfio/elfio_note.hpp | 166 ++++ hc2/external/elfio/elfio_relocation.hpp | 369 +++++++ hc2/external/elfio/elfio_section.hpp | 296 ++++++ hc2/external/elfio/elfio_segment.hpp | 220 +++++ hc2/external/elfio/elfio_strings.hpp | 96 ++ hc2/external/elfio/elfio_symbols.hpp | 278 ++++++ hc2/external/elfio/elfio_utils.hpp | 209 ++++ hcc_config/hcc_config.cpp | 2 +- include/hc_rt_debug.h | 5 +- lib/CMakeLists.txt | 2 +- lib/mcwamp.cpp | 110 ++- tests/Unit/FilePath/file_path_test4.cpp | 2 +- tests/Unit/SharedLibrary/shared_library1.cpp | 2 +- tests/Unit/SharedLibrary/shared_library2.cpp | 4 +- tests/Unit/SharedLibrary/shared_library3.cpp | 4 +- tests/Unit/SharedLibrary/shared_library4.cpp | 2 +- tests/Unit/SharedLibrary/shared_library5.cpp | 2 +- 23 files changed, 4701 insertions(+), 38 deletions(-) create mode 100644 hc2/external/elfio/elf_types.hpp create mode 100644 hc2/external/elfio/elfio.hpp create mode 100644 hc2/external/elfio/elfio_dump.hpp create mode 100644 hc2/external/elfio/elfio_dynamic.hpp create mode 100644 hc2/external/elfio/elfio_header.hpp create mode 100644 hc2/external/elfio/elfio_note.hpp create mode 100644 hc2/external/elfio/elfio_relocation.hpp create mode 100644 hc2/external/elfio/elfio_section.hpp create mode 100644 hc2/external/elfio/elfio_segment.hpp create mode 100644 hc2/external/elfio/elfio_strings.hpp create mode 100644 hc2/external/elfio/elfio_symbols.hpp create mode 100644 hc2/external/elfio/elfio_utils.hpp diff --git a/benchmarks/benchEmptyKernel/nullkernel.cpp b/benchmarks/benchEmptyKernel/nullkernel.cpp index f7b8b86ee0c..f1ec520cfd4 100644 --- a/benchmarks/benchEmptyKernel/nullkernel.cpp +++ b/benchmarks/benchEmptyKernel/nullkernel.cpp @@ -1,4 +1,4 @@ -// RUN: %hc --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 -fPIC -Wl,-Bsymbolic -shared %S/nullkernel.cpp -o %T/nullkernel +// RUN: %hc --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 -fPIC -shared %S/nullkernel.cpp -o %T/nullkernel // RUN: HCC_HOME=%llvm_libs_dir/../../ %extractkernel -i %T/nullkernel #include "hc.hpp" diff --git a/hc2/external/elfio/elf_types.hpp b/hc2/external/elfio/elf_types.hpp new file mode 100644 index 00000000000..1b90c4c57dd --- /dev/null +++ b/hc2/external/elfio/elf_types.hpp @@ -0,0 +1,749 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#ifndef ELFIO_NO_OWN_TYPES + #if !defined(ELFIO_NO_CSTDINT) && !defined(ELFIO_NO_INTTYPES) + #include + #else + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + #ifdef _MSC_VER + typedef unsigned __int32 uint32_t; + typedef signed __int32 int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; + #else + typedef unsigned int uint32_t; + typedef signed int int32_t; + typedef unsigned long long uint64_t; + typedef signed long long int64_t; + #endif // _MSC_VER + #endif // ELFIO_NO_CSTDINT +#endif // ELFIO_NO_OWN_TYPES + +namespace ELFIO { + +// Attention! Platform depended definitions. +typedef uint16_t Elf_Half; +typedef uint32_t Elf_Word; +typedef int32_t Elf_Sword; +typedef uint64_t Elf_Xword; +typedef int64_t Elf_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; + +#define Elf32_Half Elf_Half +#define Elf64_Half Elf_Half +#define Elf32_Word Elf_Word +#define Elf64_Word Elf_Word +#define Elf32_Sword Elf_Sword +#define Elf64_Sword Elf_Sword + +/////////////////////// +// ELF Header Constants + +// File type +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xFE00 +#define ET_HIOS 0xFEFF +#define ET_LOPROC 0xFF00 +#define ET_HIPROC 0xFFFF + + +#define EM_NONE 0 // No machine +#define EM_M32 1 // AT&T WE 32100 +#define EM_SPARC 2 // SUN SPARC +#define EM_386 3 // Intel 80386 +#define EM_68K 4 // Motorola m68k family +#define EM_88K 5 // Motorola m88k family +#define EM_486 6 // Intel 80486// Reserved for future use +#define EM_860 7 // Intel 80860 +#define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) +#define EM_S370 9 // IBM System/370 +#define EM_MIPS_RS3_LE 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated +#define EM_res011 11 // Reserved +#define EM_res012 12 // Reserved +#define EM_res013 13 // Reserved +#define EM_res014 14 // Reserved +#define EM_PARISC 15 // HPPA +#define EM_res016 16 // Reserved +#define EM_VPP550 17 // Fujitsu VPP500 +#define EM_SPARC32PLUS 18 // Sun's "v8plus" +#define EM_960 19 // Intel 80960 +#define EM_PPC 20 // PowerPC +#define EM_PPC64 21 // 64-bit PowerPC +#define EM_S390 22 // IBM S/390 +#define EM_SPU 23 // Sony/Toshiba/IBM SPU +#define EM_res024 24 // Reserved +#define EM_res025 25 // Reserved +#define EM_res026 26 // Reserved +#define EM_res027 27 // Reserved +#define EM_res028 28 // Reserved +#define EM_res029 29 // Reserved +#define EM_res030 30 // Reserved +#define EM_res031 31 // Reserved +#define EM_res032 32 // Reserved +#define EM_res033 33 // Reserved +#define EM_res034 34 // Reserved +#define EM_res035 35 // Reserved +#define EM_V800 36 // NEC V800 series +#define EM_FR20 37 // Fujitsu FR20 +#define EM_RH32 38 // TRW RH32 +#define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA +#define EM_RCE 39 // Old name for MCore +#define EM_ARM 40 // ARM +#define EM_OLD_ALPHA 41 // Digital Alpha +#define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH +#define EM_SPARCV9 43 // SPARC v9 64-bit +#define EM_TRICORE 44 // Siemens Tricore embedded processor +#define EM_ARC 45 // ARC Cores +#define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 +#define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H +#define EM_H8S 48 // Renesas (formerly Hitachi) H8S +#define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 +#define EM_IA_64 50 // Intel IA-64 Processor +#define EM_MIPS_X 51 // Stanford MIPS-X +#define EM_COLDFIRE 52 // Motorola Coldfire +#define EM_68HC12 53 // Motorola M68HC12 +#define EM_MMA 54 // Fujitsu Multimedia Accelerator +#define EM_PCP 55 // Siemens PCP +#define EM_NCPU 56 // Sony nCPU embedded RISC processor +#define EM_NDR1 57 // Denso NDR1 microprocesspr +#define EM_STARCORE 58 // Motorola Star*Core processor +#define EM_ME16 59 // Toyota ME16 processor +#define EM_ST100 60 // STMicroelectronics ST100 processor +#define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor +#define EM_X86_64 62 // Advanced Micro Devices X86-64 processor +#define EM_PDSP 63 // Sony DSP Processor +#define EM_PDP10 64 // Digital Equipment Corp. PDP-10 +#define EM_PDP11 65 // Digital Equipment Corp. PDP-11 +#define EM_FX66 66 // Siemens FX66 microcontroller +#define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller +#define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller +#define EM_68HC16 69 // Motorola MC68HC16 Microcontroller +#define EM_68HC11 70 // Motorola MC68HC11 Microcontroller +#define EM_68HC08 71 // Motorola MC68HC08 Microcontroller +#define EM_68HC05 72 // Motorola MC68HC05 Microcontroller +#define EM_SVX 73 // Silicon Graphics SVx +#define EM_ST19 74 // STMicroelectronics ST19 8-bit cpu +#define EM_VAX 75 // Digital VAX +#define EM_CRIS 76 // Axis Communications 32-bit embedded processor +#define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded cpu +#define EM_FIREPATH 78 // Element 14 64-bit DSP processor +#define EM_ZSP 79 // LSI Logic's 16-bit DSP processor +#define EM_MMIX 80 // Donald Knuth's educational 64-bit processor +#define EM_HUANY 81 // Harvard's machine-independent format +#define EM_PRISM 82 // SiTera Prism +#define EM_AVR 83 // Atmel AVR 8-bit microcontroller +#define EM_FR30 84 // Fujitsu FR30 +#define EM_D10V 85 // Mitsubishi D10V +#define EM_D30V 86 // Mitsubishi D30V +#define EM_V850 87 // NEC v850 +#define EM_M32R 88 // Renesas M32R (formerly Mitsubishi M32R) +#define EM_MN10300 89 // Matsushita MN10300 +#define EM_MN10200 90 // Matsushita MN10200 +#define EM_PJ 91 // picoJava +#define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor +#define EM_ARC_A5 93 // ARC Cores Tangent-A5 +#define EM_XTENSA 94 // Tensilica Xtensa Architecture +#define EM_VIDEOCORE 95 // Alphamosaic VideoCore processor +#define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor +#define EM_NS32K 97 // National Semiconductor 32000 series +#define EM_TPC 98 // Tenor Network TPC processor +#define EM_SNP1K 99 // Trebia SNP 1000 processor +#define EM_ST200 100 // STMicroelectronics ST200 microcontroller +#define EM_IP2K 101 // Ubicom IP2022 micro controller +#define EM_MAX 102 // MAX Processor +#define EM_CR 103 // National Semiconductor CompactRISC +#define EM_F2MC16 104 // Fujitsu F2MC16 +#define EM_MSP430 105 // TI msp430 micro controller +#define EM_BLACKFIN 106 // ADI Blackfin +#define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors +#define EM_SEP 108 // Sharp embedded microprocessor +#define EM_ARCA 109 // Arca RISC Microprocessor +#define EM_UNICORE 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University +#define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU +#define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor +#define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor +#define EM_CRX 114 // National Semiconductor CRX +#define EM_XGATE 115 // Motorola XGATE embedded processor +#define EM_C166 116 // Infineon C16x/XC16x processor +#define EM_M16C 117 // Renesas M16C series microprocessors +#define EM_DSPIC30F 118 // Microchip Technology dsPIC30F Digital Signal Controller +#define EM_CE 119 // Freescale Communication Engine RISC core +#define EM_M32C 120 // Renesas M32C series microprocessors +#define EM_res121 121 // Reserved +#define EM_res122 122 // Reserved +#define EM_res123 123 // Reserved +#define EM_res124 124 // Reserved +#define EM_res125 125 // Reserved +#define EM_res126 126 // Reserved +#define EM_res127 127 // Reserved +#define EM_res128 128 // Reserved +#define EM_res129 129 // Reserved +#define EM_res130 130 // Reserved +#define EM_TSK3000 131 // Altium TSK3000 core +#define EM_RS08 132 // Freescale RS08 embedded processor +#define EM_res133 133 // Reserved +#define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor +#define EM_SCORE 135 // Sunplus Score +#define EM_SCORE7 135 // Sunplus S+core7 RISC processor +#define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor +#define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor +#define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture +#define EM_SE_C17 139 // Seiko Epson C17 family +#define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family +#define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family +#define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family +#define EM_res143 143 // Reserved +#define EM_res144 144 // Reserved +#define EM_res145 145 // Reserved +#define EM_res146 146 // Reserved +#define EM_res147 147 // Reserved +#define EM_res148 148 // Reserved +#define EM_res149 149 // Reserved +#define EM_res150 150 // Reserved +#define EM_res151 151 // Reserved +#define EM_res152 152 // Reserved +#define EM_res153 153 // Reserved +#define EM_res154 154 // Reserved +#define EM_res155 155 // Reserved +#define EM_res156 156 // Reserved +#define EM_res157 157 // Reserved +#define EM_res158 158 // Reserved +#define EM_res159 159 // Reserved +#define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor +#define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor +#define EM_R32C 162 // Renesas R32C series microprocessors +#define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family +#define EM_QDSP6 164 // QUALCOMM DSP6 Processor +#define EM_8051 165 // Intel 8051 and variants +#define EM_STXP7X 166 // STMicroelectronics STxP7x family +#define EM_NDS32 167 // Andes Technology compact code size embedded RISC processor family +#define EM_ECOG1 168 // Cyan Technology eCOG1X family +#define EM_ECOG1X 168 // Cyan Technology eCOG1X family +#define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers +#define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor +#define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor +#define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture +#define EM_RX 173 // Renesas RX family +#define EM_METAG 174 // Imagination Technologies META processor architecture +#define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture +#define EM_ECOG16 176 // Cyan Technology eCOG16 family +#define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor +#define EM_ETPU 178 // Freescale Extended Time Processing Unit +#define EM_SLE9X 179 // Infineon Technologies SLE9X core +#define EM_L1OM 180 // Intel L1OM +#define EM_INTEL181 181 // Reserved by Intel +#define EM_INTEL182 182 // Reserved by Intel +#define EM_res183 183 // Reserved by ARM +#define EM_res184 184 // Reserved by ARM +#define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family +#define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller +#define EM_TILE64 187 // Tilera TILE64 multicore architecture family +#define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family +#define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core +#define EM_CUDA 190 // NVIDIA CUDA architecture +#define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family +#define EM_CLOUDSHIELD 192 // CloudShield architecture family +#define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family +#define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family +#define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 +#define EM_OPEN8 196 // Open8 8-bit RISC soft processor core +#define EM_RL78 197 // Renesas RL78 family +#define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor +#define EM_78KOR 199 // Renesas 78KOR family +#define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) +#define EM_BA1 201 // Beyond BA1 CPU architecture +#define EM_BA2 202 // Beyond BA2 CPU architecture +#define EM_XCORE 203 // XMOS xCORE processor family +#define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family +#define EM_INTEL205 205 // Reserved by Intel +#define EM_INTEL206 206 // Reserved by Intel +#define EM_INTEL207 207 // Reserved by Intel +#define EM_INTEL208 208 // Reserved by Intel +#define EM_INTEL209 209 // Reserved by Intel +#define EM_KM32 210 // KM211 KM32 32-bit processor +#define EM_KMX32 211 // KM211 KMX32 32-bit processor +#define EM_KMX16 212 // KM211 KMX16 16-bit processor +#define EM_KMX8 213 // KM211 KMX8 8-bit processor +#define EM_KVARC 214 // KM211 KVARC processor +#define EM_CDP 215 // Paneve CDP architecture family +#define EM_COGE 216 // Cognitive Smart Memory Processor +#define EM_COOL 217 // iCelero CoolEngine +#define EM_NORC 218 // Nanoradio Optimized RISC +#define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family +#define EM_Z80 220 // Zilog Z80 +#define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor +#define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture +#define EM_MOXIE 223 // Moxie processor family +#define EM_AMDGPU 224 // AMD GPU architecture +#define EM_RISCV 243 // RISC-V +#define EM_LANAI 244 // Lanai processor +#define EM_CEVA 245 // CEVA Processor Architecture Family +#define EM_CEVA_X2 246 // CEVA X2 Processor Family +#define EM_BPF 247 // Linux BPF – in-kernel virtual machine + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// OS extensions +#define ELFOSABI_NONE 0 // No extensions or unspecified +#define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX +#define ELFOSABI_NETBSD 2 // NetBSD +#define ELFOSABI_LINUX 3 // Linux +#define ELFOSABI_SOLARIS 6 // Sun Solaris +#define ELFOSABI_AIX 7 // AIX +#define ELFOSABI_IRIX 8 // IRIX +#define ELFOSABI_FREEBSD 9 // FreeBSD +#define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX +#define ELFOSABI_MODESTO 11 // Novell Modesto +#define ELFOSABI_OPENBSD 12 // Open BSD +#define ELFOSABI_OPENVMS 13 // Open VMS +#define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel +#define ELFOSABI_AROS 15 // Amiga Research OS +#define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS +// 64-255 Architecture-specific value range + + + +///////////////////// +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_LOOS 0xFF20 +#define SHN_HIOS 0xFF3F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_XINDEX 0xFFFF +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Section attribute flags +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MERGE 0x10 +#define SHF_STRINGS 0x20 +#define SHF_INFO_LINK 0x40 +#define SHF_LINK_ORDER 0x80 +#define SHF_OS_NONCONFORMING 0x100 +#define SHF_GROUP 0x200 +#define SHF_TLS 0x400 +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xF0000000 + +// Section group flags +#define GRP_COMDAT 0x1 +#define GRP_MASKOS 0x0ff00000 +#define GRP_MASKPROC 0xf0000000 + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOOS 10 +#define STB_HIOS 12 +#define STB_MULTIDEF 13 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_LOOS 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Symbol visibility +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_X86_64_NONE 0 +#define R_386_32 1 +#define R_X86_64_64 1 +#define R_386_PC32 2 +#define R_X86_64_PC32 2 +#define R_386_GOT32 3 +#define R_X86_64_GOT32 3 +#define R_386_PLT32 4 +#define R_X86_64_PLT32 4 +#define R_386_COPY 5 +#define R_X86_64_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_X86_64_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_X86_64_JUMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_X86_64_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_X86_64_GOTPCREL 9 +#define R_386_GOTPC 10 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DTPMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 +#define R_X86_64_TLSDESC 36 +#define R_X86_64_IRELATIVE 37 +#define R_X86_64_GNU_VTINHERIT 250 +#define R_X86_64_GNU_VTENTRY 251 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_LOOS 0x60000000 +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 // Execute +#define PF_W 2 // Write +#define PF_R 4 // Read +#define PF_MASKOS 0x0ff00000 // Unspecified +#define PF_MASKPROC 0xf0000000 // Unspecified + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_MAXPOSTAGS 34 +#define DT_LOOS 0x6000000D +#define DT_HIOS 0x6ffff000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +// DT_FLAGS values +#define DF_ORIGIN 0x1 +#define DF_SYMBOLIC 0x2 +#define DF_TEXTREL 0x4 +#define DF_BIND_NOW 0x8 +#define DF_STATIC_TLS 0x10 + + +// ELF file header +struct Elf32_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr { + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + + +// Section header +struct Elf32_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf_Word sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Word sh_addralign; + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr { + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf_Xword sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Xword sh_addralign; + Elf_Xword sh_entsize; +}; + + +// Segment header +struct Elf32_Phdr { + Elf_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf_Word p_filesz; + Elf_Word p_memsz; + Elf_Word p_flags; + Elf_Word p_align; +}; + +struct Elf64_Phdr { + Elf_Word p_type; + Elf_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf_Xword p_filesz; + Elf_Xword p_memsz; + Elf_Xword p_align; +}; + + +// Symbol table entry +struct Elf32_Sym { + Elf_Word st_name; + Elf32_Addr st_value; + Elf_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; +}; + +struct Elf64_Sym { + Elf_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; + Elf64_Addr st_value; + Elf_Xword st_size; +}; + + +#define ELF_ST_BIND(i) ((i)>>4) +#define ELF_ST_TYPE(i) ((i)&0xf) +#define ELF_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#define ELF_ST_VISIBILITY(o) ((o)&0x3) + + +// Relocation entries +struct Elf32_Rel { + Elf32_Addr r_offset; + Elf_Word r_info; +}; + +struct Elf32_Rela { + Elf32_Addr r_offset; + Elf_Word r_info; + Elf_Sword r_addend; +}; + +struct Elf64_Rel { + Elf64_Addr r_offset; + Elf_Xword r_info; +}; + +struct Elf64_Rela { + Elf64_Addr r_offset; + Elf_Xword r_info; + Elf_Sxword r_addend; +}; + + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + +#define ELF64_R_SYM(i) ((i)>>32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) +#define ELF64_R_INFO(s,t) ((((int64_t)s)<<32)+((t)&0xffffffffL)) + +// Dynamic structure +struct Elf32_Dyn { + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn { + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +} // namespace ELFIO + +#endif // ELFTYPES_H diff --git a/hc2/external/elfio/elfio.hpp b/hc2/external/elfio/elfio.hpp new file mode 100644 index 00000000000..46ce5704066 --- /dev/null +++ b/hc2/external/elfio/elfio.hpp @@ -0,0 +1,848 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#ifdef _MSC_VER +#pragma warning ( push ) +#pragma warning(disable:4996) +#pragma warning(disable:4355) +#pragma warning(disable:4244) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf_types.hpp" +#include "elfio_utils.hpp" +#include "elfio_header.hpp" +#include "elfio_section.hpp" +#include "elfio_segment.hpp" +#include "elfio_strings.hpp" + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header->get_##FNAME(); \ +} + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ +TYPE \ +get_##FNAME() const \ +{ \ + return header->get_##FNAME(); \ +} \ +void \ +set_##FNAME( TYPE val ) \ +{ \ + header->set_##FNAME( val ); \ +} \ + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: +//------------------------------------------------------------------------------ + elfio() : sections( this ), segments( this ) + { + header = 0; + current_file_pos = 0; + create( ELFCLASS32, ELFDATA2LSB ); + } + +//------------------------------------------------------------------------------ + ~elfio() + { + clean(); + } + +//------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + clean(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + +//------------------------------------------------------------------------------ + bool load( const std::string& file_name ) + { + std::ifstream stream; + stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !stream ) { + return false; + } + + return load(stream); + } + +//------------------------------------------------------------------------------ + bool load( std::istream &stream ) + { + clean(); + + unsigned char e_ident[EI_NIDENT]; + + // Read ELF file signature + stream.seekg( 0 ); + stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || + e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || + e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 )) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( 0 == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream ); + load_segments( stream ); + + return true; + } + +//------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream f( file_name.c_str(), std::ios::out | std::ios::binary ); + + if ( !f ) { + return false; + } + + bool is_still_good = true; + + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = header->get_header_size() + + header->get_segment_entry_size() * header->get_segments_num(); + + is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( f ); + is_still_good = is_still_good && save_sections( f ); + is_still_good = is_still_good && save_segments( f ); + + f.close(); + + return is_still_good; + } + +//------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + +//------------------------------------------------------------------------------ + const endianess_convertor& get_convertor() const + { + return convertor; + } + +//------------------------------------------------------------------------------ + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void clean() + { + delete header; + header = 0; + + std::vector::const_iterator it; + for ( it = sections_.begin(); it != sections_.end(); ++it ) { + delete *it; + } + sections_.clear(); + + std::vector::const_iterator it1; + for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { + delete *it1; + } + segments_.clear(); + } + +//------------------------------------------------------------------------------ + elf_header* create_header( unsigned char file_class, unsigned char encoding ) + { + elf_header* new_header = 0; + + if ( file_class == ELFCLASS64 ) { + new_header = new elf_header_impl< Elf64_Ehdr >( &convertor, + encoding ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = new elf_header_impl< Elf32_Ehdr >( &convertor, + encoding ); + } + else { + return 0; + } + + return new_header; + } + +//------------------------------------------------------------------------------ + section* create_section() + { + section* new_section; + unsigned char file_class = get_class(); + + if ( file_class == ELFCLASS64 ) { + new_section = new section_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_section = new section_impl( &convertor ); + } + else { + return 0; + } + + new_section->set_index( (Elf_Half)sections_.size() ); + sections_.push_back( new_section ); + + return new_section; + } + + +//------------------------------------------------------------------------------ + segment* create_segment() + { + segment* new_segment; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + new_segment = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + new_segment = new segment_impl( &convertor ); + } + else { + return 0; + } + + new_segment->set_index( (Elf_Half)segments_.size() ); + segments_.push_back( new_segment ); + + return new_segment; + } + +//------------------------------------------------------------------------------ + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + +//------------------------------------------------------------------------------ + Elf_Half load_sections( std::istream& stream ) + { + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, (std::streamoff)offset + i * entry_size ); + sec->set_index( i ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + Elf_Half shstrndx = get_section_name_str_index(); + + if ( SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( offset ); + if ( p != 0 ) { + sections[i]->set_name( p ); + } + } + } + + return num; + } + +//------------------------------------------------------------------------------ + bool load_segments( std::istream& stream ) + { + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + segment* seg; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + seg = new segment_impl( &convertor ); + } + else if ( file_class == ELFCLASS32 ) { + seg = new segment_impl( &convertor ); + } + else { + return false; + } + + seg->load( stream, (std::streamoff)offset + i * entry_size ); + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for( Elf_Half j = 0; j < sections.size(); ++j ) { + const section* psec = sections[j]; + + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if( psec->get_flags() & SHF_ALLOC + ? (segVBaseAddr <= psec->get_address() + && psec->get_address() + psec->get_size() + <= segVEndAddr) + : (segBaseOffset <= psec->get_offset() + && psec->get_offset() + psec->get_size() + <= segEndOffset)) { + seg->add_section_index( psec->get_index(), + psec->get_addr_align() ); + } + } + + // Add section into the segments' container + segments_.push_back( seg ); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool save_header( std::ofstream& f ) + { + return header->save( f ); + } + +//------------------------------------------------------------------------------ + bool save_sections( std::ofstream& f ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + section *sec = sections_.at(i); + + std::streampos headerPosition = + (std::streamoff)header->get_sections_offset() + + header->get_section_entry_size() * sec->get_index(); + + sec->save(f,headerPosition,sec->get_offset()); + } + return true; + } + +//------------------------------------------------------------------------------ + bool save_segments( std::ofstream& f ) + { + for ( unsigned int i = 0; i < segments_.size(); ++i ) { + segment *seg = segments_.at(i); + + std::streampos headerPosition = header->get_segments_offset() + + header->get_segment_entry_size()*seg->get_index(); + + seg->save( f, headerPosition, seg->get_offset() ); + } + return true; + } + +//------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( unsigned int k = 0; + !found && ( k < segments[j]->get_sections_num() ); + ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + +//------------------------------------------------------------------------------ + bool is_subsequence_of( segment* seg1, segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + +//------------------------------------------------------------------------------ + std::vector get_ordered_segments( ) + { + std::vector res; + std::deque worklist; + + res.reserve(segments.size()); + std::copy( segments_.begin(), segments_.end(), + std::back_inserter( worklist )) ; + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for( size_t i = 0; i < worklist.size(); ++i ) { + if( i != nextSlot && worklist[i]->is_offset_initialized() + && worklist[i]->get_offset() == 0 ) { + std::swap(worklist[i],worklist[nextSlot]); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment *seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) + worklist.push_back(seg); + else + res.push_back(seg); + } + + return res; + } + + +//------------------------------------------------------------------------------ + bool layout_sections_without_segments( ) + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + section *sec = sections_[i]; + + Elf_Xword section_align = sec->get_addr_align(); + if ( section_align > 1 && current_file_pos % section_align != 0 ) { + current_file_pos += section_align - + current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + +//------------------------------------------------------------------------------ + bool layout_segments_and_their_sections( ) + { + std::vector worklist; + std::vector section_generated(sections.size(),false); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( unsigned int i = 0; i < worklist.size(); ++i ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + segment* seg = worklist[i]; + + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * header->get_segments_num(); + } + // Special case: + // Segments which start with the NULL section and have further sections + else if ( seg->get_sections_num() > 1 + && sections[seg->get_section_index_at( 0 )]->get_type() == SHT_NULL ) { + seg_start_pos = 0; + if ( seg->get_sections_num() ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() + && !section_generated[seg->get_section_index_at( 0 )] ) { + Elf64_Off cur_page_alignment = current_file_pos % seg->get_align(); + Elf64_Off req_page_alignment = seg->get_virtual_address() % seg->get_align(); + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % seg->get_align(); + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() ) { + seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[ index ]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type()) { + section_generated[index] = true; + continue; + } + + Elf_Xword secAlign = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() + && SHT_NOBITS != sec->get_type() + && SHT_NULL != sec->get_type() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + secAlign = req_offset - cur_offset; + } + else if (!section_generated[index]) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if (align == 0) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + secAlign = ( align - error ) % align; + } + else { + // Alignment for already generated sections + secAlign = sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( (sec->get_flags() & SHF_ALLOC) + && !( (sec->get_flags() & SHF_TLS) && (seg->get_type() != PT_TLS) + && ( SHT_NOBITS == sec->get_type())) ) + segment_memory += sec->get_size() + secAlign; + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + segment_filesize += sec->get_size() + secAlign; + + // Nothing to be done when generating nested segments + if(section_generated[index]) { + continue; + } + + current_file_pos += secAlign; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos); + + if ( 0 != sec->get_index() ) + sec->set_offset(current_file_pos); + + if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) + current_file_pos += sec->get_size(); + section_generated[index] = true; + } + + seg->set_file_size( segment_filesize ); + seg->set_memory_size( segment_memory ); + seg->set_offset(seg_start_pos); + } + + return true; + } + +//------------------------------------------------------------------------------ + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 4; + current_file_pos += ( 4 - alignmentError ) % 4; + header->set_sections_offset(current_file_pos); + return true; + } + + +//------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections { + public: +//------------------------------------------------------------------------------ + Sections( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->sections_.size(); + } + +//------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = 0; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index]; + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* operator[]( const std::string& name ) const + { + section* sec = 0; + + std::vector::const_iterator it; + for ( it = parent->sections_.begin(); + it != parent->sections_.end(); + ++it ) { + if ( (*it)->get_name() == name ) { + sec = *it; + break; + } + } + + return sec; + } + +//------------------------------------------------------------------------------ + section* add( const std::string& name ) + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index] ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->sections_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->sections_.end(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } sections; + +//------------------------------------------------------------------------------ + public: + friend class Segments; + class Segments { + public: +//------------------------------------------------------------------------------ + Segments( elfio* parent_ ) : + parent( parent_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Half size() const + { + return (Elf_Half)parent->segments_.size(); + } + +//------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index]; + } + + +//------------------------------------------------------------------------------ + segment* add() + { + return parent->create_segment(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator begin() { + return parent->segments_.begin(); + } + +//------------------------------------------------------------------------------ + std::vector::iterator end() { + return parent->segments_.end(); + } + +//------------------------------------------------------------------------------ + private: + elfio* parent; + } segments; + +//------------------------------------------------------------------------------ + private: + elf_header* header; + std::vector sections_; + std::vector segments_; + endianess_convertor convertor; + + Elf_Xword current_file_pos; +}; + +} // namespace ELFIO + +#include "elfio_symbols.hpp" +#include "elfio_note.hpp" +#include "elfio_relocation.hpp" +#include "elfio_dynamic.hpp" + +#ifdef _MSC_VER +#pragma warning ( pop ) +#endif + +#endif // ELFIO_HPP diff --git a/hc2/external/elfio/elfio_dump.hpp b/hc2/external/elfio/elfio_dump.hpp new file mode 100644 index 00000000000..04948529603 --- /dev/null +++ b/hc2/external/elfio/elfio_dump.hpp @@ -0,0 +1,972 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include "elfio.hpp" + +namespace ELFIO { + + +static struct class_table_t { + const char key; + const char* str; +} class_table [] = +{ + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + + +static struct endian_table_t { + const char key; + const char* str; +} endian_table [] = +{ + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + + +static struct version_table_t { + const Elf64_Word key; + const char* str; +} version_table [] = +{ + { EV_NONE , "None" }, + { EV_CURRENT, "Current" }, +}; + + +static struct type_table_t { + const Elf32_Half key; + const char* str; +} type_table [] = +{ + { ET_NONE, "No file type" }, + { ET_REL , "Relocatable file" }, + { ET_EXEC, "Executable file" }, + { ET_DYN , "Shared object file" }, + { ET_CORE, "Core file" }, +}; + + +static struct machine_table_t { + const Elf64_Half key; + const char* str; +} machine_table [] = +{ + { EM_NONE , "No machine" }, + { EM_M32 , "AT&T WE 32100" }, + { EM_SPARC , "SUN SPARC" }, + { EM_386 , "Intel 80386" }, + { EM_68K , "Motorola m68k family" }, + { EM_88K , "Motorola m88k family" }, + { EM_486 , "Intel 80486// Reserved for future use" }, + { EM_860 , "Intel 80860" }, + { EM_MIPS , "MIPS R3000 (officially, big-endian only)" }, + { EM_S370 , "IBM System/370" }, + { EM_MIPS_RS3_LE , "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011 , "Reserved" }, + { EM_res012 , "Reserved" }, + { EM_res013 , "Reserved" }, + { EM_res014 , "Reserved" }, + { EM_PARISC , "HPPA" }, + { EM_res016 , "Reserved" }, + { EM_VPP550 , "Fujitsu VPP500" }, + { EM_SPARC32PLUS , "Sun's v8plus" }, + { EM_960 , "Intel 80960" }, + { EM_PPC , "PowerPC" }, + { EM_PPC64 , "64-bit PowerPC" }, + { EM_S390 , "IBM S/390" }, + { EM_SPU , "Sony/Toshiba/IBM SPU" }, + { EM_res024 , "Reserved" }, + { EM_res025 , "Reserved" }, + { EM_res026 , "Reserved" }, + { EM_res027 , "Reserved" }, + { EM_res028 , "Reserved" }, + { EM_res029 , "Reserved" }, + { EM_res030 , "Reserved" }, + { EM_res031 , "Reserved" }, + { EM_res032 , "Reserved" }, + { EM_res033 , "Reserved" }, + { EM_res034 , "Reserved" }, + { EM_res035 , "Reserved" }, + { EM_V800 , "NEC V800 series" }, + { EM_FR20 , "Fujitsu FR20" }, + { EM_RH32 , "TRW RH32" }, + { EM_MCORE , "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE , "Old name for MCore" }, + { EM_ARM , "ARM" }, + { EM_OLD_ALPHA , "Digital Alpha" }, + { EM_SH , "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9 , "SPARC v9 64-bit" }, + { EM_TRICORE , "Siemens Tricore embedded processor" }, + { EM_ARC , "ARC Cores" }, + { EM_H8_300 , "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H , "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S , "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500 , "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64 , "Intel IA-64 Processor" }, + { EM_MIPS_X , "Stanford MIPS-X" }, + { EM_COLDFIRE , "Motorola Coldfire" }, + { EM_68HC12 , "Motorola M68HC12" }, + { EM_MMA , "Fujitsu Multimedia Accelerator" }, + { EM_PCP , "Siemens PCP" }, + { EM_NCPU , "Sony nCPU embedded RISC processor" }, + { EM_NDR1 , "Denso NDR1 microprocesspr" }, + { EM_STARCORE , "Motorola Star*Core processor" }, + { EM_ME16 , "Toyota ME16 processor" }, + { EM_ST100 , "STMicroelectronics ST100 processor" }, + { EM_TINYJ , "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64 , "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP , "Sony DSP Processor" }, + { EM_PDP10 , "Digital Equipment Corp. PDP-10" }, + { EM_PDP11 , "Digital Equipment Corp. PDP-11" }, + { EM_FX66 , "Siemens FX66 microcontroller" }, + { EM_ST9PLUS , "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7 , "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16 , "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11 , "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08 , "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05 , "Motorola MC68HC05 Microcontroller" }, + { EM_SVX , "Silicon Graphics SVx" }, + { EM_ST19 , "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX , "Digital VAX" }, + { EM_CRIS , "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN , "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH , "Element 14 64-bit DSP processor" }, + { EM_ZSP , "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX , "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY , "Harvard's machine-independent format" }, + { EM_PRISM , "SiTera Prism" }, + { EM_AVR , "Atmel AVR 8-bit microcontroller" }, + { EM_FR30 , "Fujitsu FR30" }, + { EM_D10V , "Mitsubishi D10V" }, + { EM_D30V , "Mitsubishi D30V" }, + { EM_V850 , "NEC v850" }, + { EM_M32R , "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300 , "Matsushita MN10300" }, + { EM_MN10200 , "Matsushita MN10200" }, + { EM_PJ , "picoJava" }, + { EM_OPENRISC , "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5 , "ARC Cores Tangent-A5" }, + { EM_XTENSA , "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE , "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP , "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K , "National Semiconductor 32000 series" }, + { EM_TPC , "Tenor Network TPC processor" }, + { EM_SNP1K , "Trebia SNP 1000 processor" }, + { EM_ST200 , "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K , "Ubicom IP2022 micro controller" }, + { EM_MAX , "MAX Processor" }, + { EM_CR , "National Semiconductor CompactRISC" }, + { EM_F2MC16 , "Fujitsu F2MC16" }, + { EM_MSP430 , "TI msp430 micro controller" }, + { EM_BLACKFIN , "ADI Blackfin" }, + { EM_SE_C33 , "S1C33 Family of Seiko Epson processors" }, + { EM_SEP , "Sharp embedded microprocessor" }, + { EM_ARCA , "Arca RISC Microprocessor" }, + { EM_UNICORE , "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University" }, + { EM_EXCESS , "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP , "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2 , "Altera Nios II soft-core processor" }, + { EM_CRX , "National Semiconductor CRX" }, + { EM_XGATE , "Motorola XGATE embedded processor" }, + { EM_C166 , "Infineon C16x/XC16x processor" }, + { EM_M16C , "Renesas M16C series microprocessors" }, + { EM_DSPIC30F , "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE , "Freescale Communication Engine RISC core" }, + { EM_M32C , "Renesas M32C series microprocessors" }, + { EM_res121 , "Reserved" }, + { EM_res122 , "Reserved" }, + { EM_res123 , "Reserved" }, + { EM_res124 , "Reserved" }, + { EM_res125 , "Reserved" }, + { EM_res126 , "Reserved" }, + { EM_res127 , "Reserved" }, + { EM_res128 , "Reserved" }, + { EM_res129 , "Reserved" }, + { EM_res130 , "Reserved" }, + { EM_TSK3000 , "Altium TSK3000 core" }, + { EM_RS08 , "Freescale RS08 embedded processor" }, + { EM_res133 , "Reserved" }, + { EM_ECOG2 , "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE , "Sunplus Score" }, + { EM_SCORE7 , "Sunplus S+core7 RISC processor" }, + { EM_DSP24 , "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3 , "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17 , "Seiko Epson C17 family" }, + { EM_TI_C6000 , "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000 , "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500 , "Texas Instruments TMS320C55x DSP family" }, + { EM_res143 , "Reserved" }, + { EM_res144 , "Reserved" }, + { EM_res145 , "Reserved" }, + { EM_res146 , "Reserved" }, + { EM_res147 , "Reserved" }, + { EM_res148 , "Reserved" }, + { EM_res149 , "Reserved" }, + { EM_res150 , "Reserved" }, + { EM_res151 , "Reserved" }, + { EM_res152 , "Reserved" }, + { EM_res153 , "Reserved" }, + { EM_res154 , "Reserved" }, + { EM_res155 , "Reserved" }, + { EM_res156 , "Reserved" }, + { EM_res157 , "Reserved" }, + { EM_res158 , "Reserved" }, + { EM_res159 , "Reserved" }, + { EM_MMDSP_PLUS , "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C , "Cypress M8C microprocessor" }, + { EM_R32C , "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA , "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6 , "QUALCOMM DSP6 Processor" }, + { EM_8051 , "Intel 8051 and variants" }, + { EM_STXP7X , "STMicroelectronics STxP7x family" }, + { EM_NDS32 , "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1 , "Cyan Technology eCOG1X family" }, + { EM_ECOG1X , "Cyan Technology eCOG1X family" }, + { EM_MAXQ30 , "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16 , "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK , "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2 , "Cray Inc. NV2 vector architecture" }, + { EM_RX , "Renesas RX family" }, + { EM_METAG , "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS , "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16 , "Cyan Technology eCOG16 family" }, + { EM_CR16 , "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU , "Freescale Extended Time Processing Unit" }, + { EM_SLE9X , "Infineon Technologies SLE9X core" }, + { EM_L1OM , "Intel L1OM" }, + { EM_INTEL181 , "Reserved by Intel" }, + { EM_INTEL182 , "Reserved by Intel" }, + { EM_res183 , "Reserved by ARM" }, + { EM_res184 , "Reserved by ARM" }, + { EM_AVR32 , "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8 , "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64 , "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO , "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE , "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA , "NVIDIA CUDA architecture " }, +}; + + +static struct section_type_table_t { + const Elf64_Half key; + const char* str; +} section_type_table [] = +{ + { SHT_NULL , "NULL" }, + { SHT_PROGBITS , "PROGBITS" }, + { SHT_SYMTAB , "SYMTAB" }, + { SHT_STRTAB , "STRTAB" }, + { SHT_RELA , "RELA" }, + { SHT_HASH , "HASH" }, + { SHT_DYNAMIC , "DYNAMIC" }, + { SHT_NOTE , "NOTE" }, + { SHT_NOBITS , "NOBITS" }, + { SHT_REL , "REL" }, + { SHT_SHLIB , "SHLIB" }, + { SHT_DYNSYM , "DYNSYM" }, + { SHT_INIT_ARRAY , "INIT_ARRAY" }, + { SHT_FINI_ARRAY , "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP , "GROUP" }, + { SHT_SYMTAB_SHNDX , "SYMTAB_SHNDX " }, +}; + + +static struct segment_type_table_t { + const Elf_Word key; + const char* str; +} segment_type_table [] = +{ + { PT_NULL , "NULL" }, + { PT_LOAD , "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP , "INTERP" }, + { PT_NOTE , "NOTE" }, + { PT_SHLIB , "SHLIB" }, + { PT_PHDR , "PHDR" }, + { PT_TLS , "TLS" }, +}; + + +static struct segment_flag_table_t { + const Elf_Word key; + const char* str; +} segment_flag_table [] = +{ + { 0, "" }, + { 1, "X" }, + { 2, "W" }, + { 3, "WX" }, + { 4, "R" }, + { 5, "RX" }, + { 6, "RW" }, + { 7, "RWX" }, +}; + + +static struct symbol_bind_t { + const Elf_Word key; + const char* str; +} symbol_bind_table [] = +{ + { STB_LOCAL , "LOCAL" }, + { STB_GLOBAL , "GLOBAL" }, + { STB_WEAK , "WEAK" }, + { STB_LOOS , "LOOS" }, + { STB_HIOS , "HIOS" }, + { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC , "LOPROC" }, + { STB_HIPROC , "HIPROC" }, +}; + + +static struct symbol_type_t { + const Elf_Word key; + const char* str; +} symbol_type_table [] = +{ + { STT_NOTYPE , "NOTYPE" }, + { STT_OBJECT , "OBJECT" }, + { STT_FUNC , "FUNC" }, + { STT_SECTION, "SECTION" }, + { STT_FILE , "FILE" }, + { STT_COMMON , "COMMON" }, + { STT_TLS , "TLS" }, + { STT_LOOS , "LOOS" }, + { STT_HIOS , "HIOS" }, + { STT_LOPROC , "LOPROC" }, + { STT_HIPROC , "HIPROC" }, +}; + + +static struct dynamic_tag_t { + const Elf_Word key; + const char* str; +} dynamic_tag_table [] = +{ + { DT_NULL , "NULL" }, + { DT_NEEDED , "NEEDED" }, + { DT_PLTRELSZ , "PLTRELSZ" }, + { DT_PLTGOT , "PLTGOT" }, + { DT_HASH , "HASH" }, + { DT_STRTAB , "STRTAB" }, + { DT_SYMTAB , "SYMTAB" }, + { DT_RELA , "RELA" }, + { DT_RELASZ , "RELASZ" }, + { DT_RELAENT , "RELAENT" }, + { DT_STRSZ , "STRSZ" }, + { DT_SYMENT , "SYMENT" }, + { DT_INIT , "INIT" }, + { DT_FINI , "FINI" }, + { DT_SONAME , "SONAME" }, + { DT_RPATH , "RPATH" }, + { DT_SYMBOLIC , "SYMBOLIC" }, + { DT_REL , "REL" }, + { DT_RELSZ , "RELSZ" }, + { DT_RELENT , "RELENT" }, + { DT_PLTREL , "PLTREL" }, + { DT_DEBUG , "DEBUG" }, + { DT_TEXTREL , "TEXTREL" }, + { DT_JMPREL , "JMPREL" }, + { DT_BIND_NOW , "BIND_NOW" }, + { DT_INIT_ARRAY , "INIT_ARRAY" }, + { DT_FINI_ARRAY , "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ , "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ , "FINI_ARRAYSZ" }, + { DT_RUNPATH , "RUNPATH" }, + { DT_FLAGS , "FLAGS" }, + { DT_ENCODING , "ENCODING" }, + { DT_PREINIT_ARRAY , "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS , "MAXPOSTAGS" }, +}; + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +class dump +{ +#define DUMP_DEC_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::dec << std::right +#define DUMP_HEX_FORMAT( width ) std::setw(width) << std::setfill( '0' ) << \ + std::hex << std::right +#define DUMP_STR_FORMAT( width ) std::setw(width) << std::setfill( ' ' ) << \ + std::hex << std::left + + public: +//------------------------------------------------------------------------------ + static void + header( std::ostream& out, const elfio& reader ) + { + out << "ELF Header" << std::endl << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) << std::endl + << " Version: " << str_version( reader.get_version() ) << std::endl + << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl + << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg Lk Inf Al Name" << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size ES Flg" << std::endl + << " Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_header( std::ostream& out, Elf_Half no, const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " + << std::endl; + } + + out.flags(original_flags); + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Segment headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type VirtAddr PhysAddr Flags" << std::endl + << " FileSize Mem.Size Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_header( std::ostream& out, Elf_Half no, const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " + << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " + << std::endl + << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + symbol_tables( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { + symbol_section_accessor symbols( reader, sec ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) { + out << "Symbol table (" << sec->get_name() << ")" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size Type Bind Sect" << std::endl + << " Name" + << std::endl; + } + for ( Elf_Half i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, section, other ); + symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + symbol_table( std::ostream& out, + Elf_Half no, + std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << value << " " + << DUMP_HEX_FORMAT( 8 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_HEX_FORMAT( 16 ) << value << " " + << DUMP_HEX_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " + << std::endl + << " " + << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags(original_flags); + } + +//------------------------------------------------------------------------------ + static void + notes( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec ); + int no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Type Name" + << std::endl; + for ( int j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note(j, type, name, desc, descsz) ) { + // 'name' usually contains \0 at the end. Try to fix it + name = name.c_str(); + note( out, j, type, name ); + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name ) + { + out << " [" + << DUMP_DEC_FORMAT( 2 ) << no + << "] " + << DUMP_HEX_FORMAT( 8 ) << type << " " + << DUMP_STR_FORMAT( 1 ) << name + << std::endl; + } + +//------------------------------------------------------------------------------ + static void + dynamic_tags( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no > 0 ) { + out << "Dynamic section (" << sec->get_name() << ")" << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( int i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, reader.get_class() ); + if ( DT_NULL == tag ) { + break; + } + } + + out << std::endl; + } + } + } + } + +//------------------------------------------------------------------------------ + static void + dynamic_tag( std::ostream& out, + int no, + Elf_Xword tag, + Elf_Xword value, + std::string str, + unsigned int /*elf_class*/ ) + { + out << "[" + << DUMP_DEC_FORMAT( 5 ) << no + << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ){ + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags(original_flags); + } + + return; + } + +//------------------------------------------------------------------------------ + static void + segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + + private: +//------------------------------------------------------------------------------ + template< typename T, typename K > + std::string + static + find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table )/sizeof( table[0] ); ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + +//------------------------------------------------------------------------------ + template< typename T, typename K > + static + std::string + format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + +//------------------------------------------------------------------------------ + template< typename T > + static + std::string + format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + +//------------------------------------------------------------------------------ + static + std::string + section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + + return ret; + } + + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template< typename T > \ + static \ + std::string \ + str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump + + +}; // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/hc2/external/elfio/elfio_dynamic.hpp b/hc2/external/elfio/elfio_dynamic.hpp new file mode 100644 index 00000000000..6f2d041e0fc --- /dev/null +++ b/hc2/external/elfio/elfio_dynamic.hpp @@ -0,0 +1,253 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class dynamic_section_accessor +{ + public: +//------------------------------------------------------------------------------ + dynamic_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), + dynamic_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != dynamic_section->get_entry_size() ) { + nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn< Elf32_Dyn >( index, tag, value ); + } + else { + generic_get_entry_dyn< Elf64_Dyn >( index, tag, value ); + } + + // If the tag may have a string table reference, prepare the string + if ( tag == DT_NEEDED || + tag == DT_SONAME || + tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + const char* result = strsec.get_string( value ); + if ( 0 == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword& tag, + Elf_Xword& value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Dyn >( tag, value ); + } + else { + generic_add_entry< Elf64_Dyn >( tag, value ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf_Xword& tag, + std::string& str ) + { + string_section_accessor strsec = + elf_file.sections[ get_string_table_index() ]; + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if( dynamic_section->get_data() == 0 || + ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = reinterpret_cast( + dynamic_section->get_data() + + index * dynamic_section->get_entry_size() ); + tag = convertor( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = convertor( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = convertor( pEntry->d_un.d_ptr ); + break; + } + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf_Xword tag, Elf_Xword value ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = convertor( value ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = convertor( value ); + break; + } + + entry.d_tag = convertor( tag ); + + dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* dynamic_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/hc2/external/elfio/elfio_header.hpp b/hc2/external/elfio/elfio_header.hpp new file mode 100644 index 00000000000..d689a8899f7 --- /dev/null +++ b/hc2/external/elfio/elfio_header.hpp @@ -0,0 +1,146 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +class elf_header +{ + public: + virtual ~elf_header() {}; + virtual bool load( std::istream& stream ) = 0; + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + + +template< class T > struct elf_header_impl_types; +template<> struct elf_header_impl_types { + typedef Elf32_Phdr Phdr_type; + typedef Elf32_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS32; +}; +template<> struct elf_header_impl_types { + typedef Elf64_Phdr Phdr_type; + typedef Elf64_Shdr Shdr_type; + static const unsigned char file_class = ELFCLASS64; +}; + +template< class T > class elf_header_impl : public elf_header +{ + public: + elf_header_impl( endianess_convertor* convertor_, + unsigned char encoding ) + { + convertor = convertor_; + + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = EV_CURRENT; + header.e_version = (*convertor)( header.e_version ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = (*convertor)( header.e_ehsize ); + header.e_shstrndx = (*convertor)( (Elf_Half)1 ); + header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = (*convertor)( header.e_phentsize ); + header.e_shentsize = (*convertor)( header.e_shentsize ); + } + + bool + load( std::istream& stream ) + { + stream.seekg( 0 ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return (stream.gcount() == sizeof( header ) ); + } + + bool + save( std::ostream& stream ) const + { + stream.seekp( 0 ); + stream.write( reinterpret_cast( &header ), sizeof( header ) ); + + return stream.good(); + } + + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Word, version, header.e_version ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header; + endianess_convertor* convertor; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/hc2/external/elfio/elfio_note.hpp b/hc2/external/elfio/elfio_note.hpp new file mode 100644 index 00000000000..35c6fe344cc --- /dev/null +++ b/hc2/external/elfio/elfio_note.hpp @@ -0,0 +1,166 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +class note_section_accessor +{ + public: +//------------------------------------------------------------------------------ + note_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), note_section( section_ ) + { + process_section(); + } + +//------------------------------------------------------------------------------ + Elf_Word + get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + +//------------------------------------------------------------------------------ + bool + get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + void*& desc, + Elf_Word& descSize ) const + { + if ( index >= note_section->get_size() ) { + return false; + } + + const char* pData = note_section->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(Elf_Word*)( pData + 2*align ) ); + Elf_Word namesz = convertor( *(Elf_Word*)( pData ) ); + descSize = convertor( *(Elf_Word*)( pData + sizeof( namesz ) ) ); + Elf_Word max_name_size = note_section->get_size() - note_start_positions[index]; + if ( namesz > max_name_size || + namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3*align, namesz - 1); + if ( 0 == descSize ) { + desc = 0; + } + else { + desc = const_cast ( pData + 3*align + + ( ( namesz + align - 1 )/align )*align ); + } + + return true; + } + +//------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const void* desc, + Elf_Word descSize ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = convertor( descSize ); + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = convertor( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, align - nameLen % align ); + } + if ( desc != 0 && descSize != 0 ) { + buffer.append( reinterpret_cast( desc ), descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, align - descSize % align ); + } + } + + note_start_positions.push_back( note_section->get_size() ); + note_section->append_data( buffer ); + } + + private: +//------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = note_section->get_data(); + Elf_Xword size = note_section->get_size(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( 0 == data || 0 == size ) { + return; + } + + int align = sizeof( Elf_Word ); + while ( current + 3*align <= size ) { + note_start_positions.push_back( current ); + Elf_Word namesz = convertor( + *(Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(Elf_Word*)( data + current + sizeof( namesz ) ) ); + + current += 3*sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * align + + ( ( descsz + align - 1 ) / align ) * align; + } + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* note_section; + std::vector note_start_positions; +}; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/hc2/external/elfio/elfio_relocation.hpp b/hc2/external/elfio/elfio_relocation.hpp new file mode 100644 index 00000000000..d13d8b23c7f --- /dev/null +++ b/hc2/external/elfio/elfio_relocation.hpp @@ -0,0 +1,369 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template<> struct get_sym_and_type< Elf32_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf32_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rel > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; +template<> struct get_sym_and_type< Elf64_Rela > +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF64_R_SYM( info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF64_R_TYPE( info ); + } +}; + + +//------------------------------------------------------------------------------ +class relocation_section_accessor +{ + public: +//------------------------------------------------------------------------------ + relocation_section_accessor( const elfio& elf_file_, section* section_ ) : + elf_file( elf_file_ ), + relocation_section( section_ ) + { + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / relocation_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf32_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf32_Rela >( index, offset, symbol, + type, addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel< Elf64_Rel >( index, offset, symbol, + type, addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela< Elf64_Rela >( index, offset, symbol, + type, addend ); + } + } + + return true; + } + +//------------------------------------------------------------------------------ + bool + get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + Elf_Word& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, + size, bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rel >( offset, info ); + } + else { + generic_add_entry< Elf64_Rel >( offset, info ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO((Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry< Elf32_Rela >( offset, info, addend ); + } + else { + generic_add_entry< Elf64_Rela >( offset, info, addend ); + } + } + +//------------------------------------------------------------------------------ + void + add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + +//------------------------------------------------------------------------------ + void + add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned char type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + Elf_Half + get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + Elf_Word& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = convertor( pEntry->r_addend ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + template< class T > + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + entry.r_addend = convertor( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* relocation_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/hc2/external/elfio/elfio_section.hpp b/hc2/external/elfio/elfio_section.hpp new file mode 100644 index 00000000000..b2c9b456b55 --- /dev/null +++ b/hc2/external/elfio/elfio_section.hpp @@ -0,0 +1,296 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + public: + virtual ~section() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + + virtual const char* get_data() const = 0; + virtual void set_data( const char* pData, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* pData, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + + protected: + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual void load( std::istream& f, + std::streampos header_offset ) = 0; + virtual void save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + + +template< class T > +class section_impl : public section +{ + public: +//------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + is_address_set = false; + data = 0; + data_size = 0; + } + +//------------------------------------------------------------------------------ + ~section_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS ( Elf64_Addr, address, header.sh_addr ); + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + + +//------------------------------------------------------------------------------ + std::string + get_name() const + { + return name; + } + +//------------------------------------------------------------------------------ + void + set_name( std::string name_ ) + { + name = name_; + } + +//------------------------------------------------------------------------------ + void + set_address( Elf64_Addr value ) + { + header.sh_addr = value; + header.sh_addr = (*convertor)( header.sh_addr ); + is_address_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_address_initialized() const + { + return is_address_set; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + void + set_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + delete [] data; + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + size = 0; + } + if ( 0 != data && 0 != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data ); + } + } + + set_size( size ); + } + +//------------------------------------------------------------------------------ + void + set_data( const std::string& str_data ) + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + void + append_data( const char* raw_data, Elf_Word size ) + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + std::copy( raw_data, raw_data + size, data + get_size() ); + } + else { + data_size = 2*( data_size + size); + char* new_data; + try { + new_data = new char[data_size]; + } catch (const std::bad_alloc&) { + new_data = 0; + size = 0; + } + if ( 0 != new_data ) { + std::copy( data, data + get_size(), new_data ); + std::copy( raw_data, raw_data + size, new_data + get_size() ); + delete [] data; + data = new_data; + } + } + set_size( get_size() + size ); + } + } + +//------------------------------------------------------------------------------ + void + append_data( const std::string& str_data ) + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + Elf_Xword size = get_size(); + if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() ) { + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + data_size = 0; + } + if ( 0 != size ) { + stream.seekg( (*convertor)( header.sh_offset ) ); + stream.read( data, size ); + data_size = size; + } + } + } + +//------------------------------------------------------------------------------ + void + save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) + { + if ( 0 != get_index() ) { + header.sh_offset = data_offset; + header.sh_offset = (*convertor)( header.sh_offset ); + } + + save_header( f, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != 0 ) { + save_data( f, data_offset ); + } + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + save_header( std::ostream& f, + std::streampos header_offset ) const + { + f.seekp( header_offset ); + f.write( reinterpret_cast( &header ), sizeof( header ) ); + } + +//------------------------------------------------------------------------------ + void + save_data( std::ostream& f, + std::streampos data_offset ) const + { + f.seekp( data_offset ); + f.write( get_data(), get_size() ); + } + +//------------------------------------------------------------------------------ + private: + T header; + Elf_Half index; + std::string name; + char* data; + Elf_Word data_size; + const endianess_convertor* convertor; + bool is_address_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/hc2/external/elfio/elfio_segment.hpp b/hc2/external/elfio/elfio_segment.hpp new file mode 100644 index 00000000000..35f17e939bc --- /dev/null +++ b/hc2/external/elfio/elfio_segment.hpp @@ -0,0 +1,220 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + public: + virtual ~segment() {}; + + ELFIO_GET_ACCESS_DECL ( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + + virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; + virtual Elf_Half get_sections_num() const = 0; + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + virtual bool is_offset_initialized() const = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual const std::vector& get_sections() const = 0; + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& f, std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + + +//------------------------------------------------------------------------------ +template< class T > +class segment_impl : public segment +{ + public: +//------------------------------------------------------------------------------ + segment_impl( endianess_convertor* convertor_ ) : + convertor( convertor_ ) + { + is_offset_set = false; + std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); + data = 0; + } + +//------------------------------------------------------------------------------ + virtual ~segment_impl() + { + delete [] data; + } + +//------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + +//------------------------------------------------------------------------------ + Elf_Half + get_index() const + { + return index; + } + +//------------------------------------------------------------------------------ + const char* + get_data() const + { + return data; + } + +//------------------------------------------------------------------------------ + Elf_Half + add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) + { + sections.push_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_sections_num() const + { + return (Elf_Half)sections.size(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_section_index_at( Elf_Half num ) const + { + if ( num < sections.size() ) { + return sections[num]; + } + + return -1; + } + +//------------------------------------------------------------------------------ + protected: +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ + void + set_offset( Elf64_Off value ) + { + ph.p_offset = value; + ph.p_offset = (*convertor)( ph.p_offset ); + is_offset_set = true; + } + +//------------------------------------------------------------------------------ + bool + is_offset_initialized() const + { + return is_offset_set; + } + +//------------------------------------------------------------------------------ + const std::vector& + get_sections() const + { + return sections; + } + +//------------------------------------------------------------------------------ + void + set_index( Elf_Half value ) + { + index = value; + } + +//------------------------------------------------------------------------------ + void + load( std::istream& stream, + std::streampos header_offset ) + { + stream.seekg( header_offset ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( PT_NULL != get_type() && 0 != get_file_size() ) { + stream.seekg( (*convertor)( ph.p_offset ) ); + Elf_Xword size = get_file_size(); + try { + data = new char[size]; + } catch (const std::bad_alloc&) { + data = 0; + } + if ( 0 != data ) { + stream.read( data, size ); + } + } + } + +//------------------------------------------------------------------------------ + void save( std::ostream& f, + std::streampos header_offset, + std::streampos data_offset ) + { + ph.p_offset = data_offset; + ph.p_offset = (*convertor)(ph.p_offset); + f.seekp( header_offset ); + f.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + +//------------------------------------------------------------------------------ + private: + T ph; + Elf_Half index; + char* data; + std::vector sections; + endianess_convertor* convertor; + bool is_offset_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/hc2/external/elfio/elfio_strings.hpp b/hc2/external/elfio/elfio_strings.hpp new file mode 100644 index 00000000000..df952a2145d --- /dev/null +++ b/hc2/external/elfio/elfio_strings.hpp @@ -0,0 +1,96 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class string_section_accessor +{ + public: +//------------------------------------------------------------------------------ + string_section_accessor( section* section_ ) : + string_section( section_ ) + { + } + + +//------------------------------------------------------------------------------ + const char* + get_string( Elf_Word index ) const + { + if ( string_section ) { + if ( index < string_section->get_size() ) { + const char* data = string_section->get_data(); + if ( 0 != data ) { + return data + index; + } + } + } + + return 0; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const char* str ) + { + Elf_Word current_position = 0; + + if (string_section) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)string_section->get_size(); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); + } + + return current_position; + } + + +//------------------------------------------------------------------------------ + Elf_Word + add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + +//------------------------------------------------------------------------------ + private: + section* string_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/hc2/external/elfio/elfio_symbols.hpp b/hc2/external/elfio/elfio_symbols.hpp new file mode 100644 index 00000000000..80e498d8d59 --- /dev/null +++ b/hc2/external/elfio/elfio_symbols.hpp @@ -0,0 +1,278 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class symbol_section_accessor +{ + public: +//------------------------------------------------------------------------------ + symbol_section_accessor( const elfio& elf_file_, section* symbol_section_ ) : + elf_file( elf_file_ ), + symbol_section( symbol_section_ ) + { + find_hash_section(); + } + +//------------------------------------------------------------------------------ + Elf_Xword + get_symbols_num() const + { + Elf_Xword nRet = 0; + if ( 0 != symbol_section->get_entry_size() ) { + nRet = symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + +//------------------------------------------------------------------------------ + bool + get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + Elf_Word nbucket = *(Elf_Word*)hash_section->get_data(); + Elf_Word nchain = *(Elf_Word*)( hash_section->get_data() + + sizeof( Elf_Word ) ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + + Elf_Word y = *(Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + if ( str == name ) { + ret = true; + } + } + + return ret; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, other, + shndx ); + } + + return nRet; + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + +//------------------------------------------------------------------------------ + Elf_Word + add_symbol( string_section_accessor& pStrWriter, const char* str, + Elf64_Addr value, Elf_Xword size, + unsigned char bind, unsigned char type, unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + void + find_hash_section() + { + hash_section = 0; + hash_section_index = 0; + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() ) { + hash_section = sec; + hash_section_index = i; + } + } + } + +//------------------------------------------------------------------------------ + Elf_Half + get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + +//------------------------------------------------------------------------------ + Elf_Half + get_hash_table_index() const + { + return hash_section_index; + } + +//------------------------------------------------------------------------------ + template< class T > + bool + generic_get_symbol( Elf_Xword index, + std::string& name, Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + + section* string_section = elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); + if ( 0 != pStr ) { + name = pStr; + } + value = convertor( pSym->st_value ); + size = convertor( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = convertor( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + +//------------------------------------------------------------------------------ + template< class T > + Elf_Word + generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, + unsigned char info, unsigned char other, + Elf_Half shndx ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = convertor( name ); + entry.st_value = value; + entry.st_value = convertor( entry.st_value ); + entry.st_size = size; + entry.st_size = convertor( entry.st_size ); + entry.st_info = convertor( info ); + entry.st_other = convertor( other ); + entry.st_shndx = convertor( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; + + return nRet; + } + +//------------------------------------------------------------------------------ + private: + const elfio& elf_file; + section* symbol_section; + Elf_Half hash_section_index; + const section* hash_section; +}; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/hc2/external/elfio/elfio_utils.hpp b/hc2/external/elfio/elfio_utils.hpp new file mode 100644 index 00000000000..f8423bd1475 --- /dev/null +++ b/hc2/external/elfio/elfio_utils.hpp @@ -0,0 +1,209 @@ +/* +Copyright (C) 2001-2015 by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const \ + { \ + return (*convertor)( FIELD ); \ + } \ + void set_##NAME( TYPE value ) \ + { \ + FIELD = value; \ + FIELD = (*convertor)( FIELD ); \ + } + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( TYPE value ) = 0 + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor { + public: +//------------------------------------------------------------------------------ + endianess_convertor() + { + need_conversion = false; + } + +//------------------------------------------------------------------------------ + void + setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + +//------------------------------------------------------------------------------ + uint64_t + operator()( uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00000000000000FFull ) << 56 ) | + ( ( value & 0x000000000000FF00ull ) << 40 ) | + ( ( value & 0x0000000000FF0000ull ) << 24 ) | + ( ( value & 0x00000000FF000000ull ) << 8 ) | + ( ( value & 0x000000FF00000000ull ) >> 8 ) | + ( ( value & 0x0000FF0000000000ull ) >> 24 ) | + ( ( value & 0x00FF000000000000ull ) >> 40 ) | + ( ( value & 0xFF00000000000000ull ) >> 56 ); + + return value; + } + +//------------------------------------------------------------------------------ + int64_t + operator()( int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int64_t)(*this)( (uint64_t)value ); + } + +//------------------------------------------------------------------------------ + uint32_t + operator()( uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | + ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | + ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + +//------------------------------------------------------------------------------ + int32_t + operator()( int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int32_t)(*this)( (uint32_t)value ); + } + +//------------------------------------------------------------------------------ + uint16_t + operator()( uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x00FF ) << 8 ) | + ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + +//------------------------------------------------------------------------------ + int16_t + operator()( int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int16_t)(*this)( (uint16_t)value ); + } + +//------------------------------------------------------------------------------ + int8_t + operator()( int8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + uint8_t + operator()( uint8_t value ) const + { + return value; + } + +//------------------------------------------------------------------------------ + private: +//------------------------------------------------------------------------------ + unsigned char + get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *(char*)&tmp ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + +//------------------------------------------------------------------------------ + private: + bool need_conversion; +}; + + +//------------------------------------------------------------------------------ +inline +uint32_t +elf_hash( const unsigned char *name ) +{ + uint32_t h = 0, g; + while ( *name ) { + h = (h << 4) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/hcc_config/hcc_config.cpp b/hcc_config/hcc_config.cpp index a64a2780d10..e75bea44109 100644 --- a/hcc_config/hcc_config.cpp +++ b/hcc_config/hcc_config.cpp @@ -199,7 +199,7 @@ void gtest(void) { // Compiling as a shared library void shared(void) { - std::cout << " -shared -fPIC -Wl,-Bsymbolic "; + std::cout << " -shared -fPIC "; } // print command line usage diff --git a/include/hc_rt_debug.h b/include/hc_rt_debug.h index ea0221ded74..bb3dbf99bfe 100644 --- a/include/hc_rt_debug.h +++ b/include/hc_rt_debug.h @@ -7,10 +7,11 @@ #ifndef USE_LIBCXX #include #endif +#include #include -#include #include -#include +#include +#include #define DB_API 0 /* 0x0001 HCC runtime API calls */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 816c34b9ca9..a48e8fbf9a5 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -34,7 +34,7 @@ endif (USE_LIBCXX) # Library interface for building shared libraries add_library(hccshared INTERFACE) -target_link_libraries(hccshared INTERFACE -fPIC -Wl,-Bsymbolic) +target_link_libraries(hccshared INTERFACE -fPIC) #################### # C++AMP tools diff --git a/lib/mcwamp.cpp b/lib/mcwamp.cpp index 032cf055fa1..923234cc14c 100644 --- a/lib/mcwamp.cpp +++ b/lib/mcwamp.cpp @@ -4,20 +4,23 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +#include "mcwamp_impl.hpp" +#include "hc_rt_debug.h" -#include -#include -#include -#include -#include +#include "../hc2/external/elfio/elfio.hpp" #include -#include - -#include "mcwamp_impl.hpp" -#include "hc_rt_debug.h" #include +#include + +#include +#include +#include +#include +#include +#include +#include namespace Concurrency { @@ -29,8 +32,8 @@ const wchar_t accelerator::default_accelerator[] = L"default"; // weak symbols of kernel codes // Kernel bundle -extern "C" char * kernel_bundle_source[] asm ("_binary_kernel_bundle_start") __attribute__((weak)); -extern "C" char * kernel_bundle_end[] asm ("_binary_kernel_bundle_end") __attribute__((weak)); +extern "C" char * kernel_bundle_source[] asm ("_binary_kernel_bundle_start") __attribute__((visibility("hidden"))); +extern "C" char * kernel_bundle_end[] asm ("_binary_kernel_bundle_end") __attribute__((visibility("hidden"))); // interface of HCC runtime implementation struct RuntimeImpl { @@ -268,18 +271,24 @@ static inline uint64_t Read8byteIntegerFromBuffer(const char *data, size_t pos) #define HCC_TRIPLE_PREFIX "hcc-amdgcn--amdhsa-" #define HCC_TRIPLE_PREFIX_LENGTH (19) -inline void DetermineAndGetProgram(KalmarQueue* pQueue, size_t* kernel_size, void** kernel_source) { - +inline +void DetermineAndGetProgram( + const void* kernel_bundle_f, + const void* kernel_bundle_l, + KalmarQueue* pQueue, + size_t* kernel_size, + void** kernel_source) +{ bool FoundCompatibleKernel = false; // walk through bundle header // get bundle file size - size_t bundle_size = - (std::ptrdiff_t)((void *)kernel_bundle_end) - - (std::ptrdiff_t)((void *)kernel_bundle_source); + size_t bundle_size = + static_cast(kernel_bundle_l) - + static_cast(kernel_bundle_f); // point to bundle file data - const char *data = (const char *)kernel_bundle_source; + const char *data = static_cast(kernel_bundle_f); // skip OFFLOAD_BUNDLER_MAGIC_STR size_t pos = 0; @@ -287,8 +296,9 @@ inline void DetermineAndGetProgram(KalmarQueue* pQueue, size_t* kernel_size, voi RUNTIME_ERROR(1, "Bundle size too small", __LINE__) } std::string MagicStr(data + pos, OFFLOAD_BUNDLER_MAGIC_STR_LENGTH); + //std::cerr << MagicStr << std::endl; if (MagicStr.compare(OFFLOAD_BUNDLER_MAGIC_STR) != 0) { - RUNTIME_ERROR(1, "Incorrect magic string", __LINE__) + return; //RUNTIME_ERROR(1, "Incorrect magic string", __LINE__) } pos += OFFLOAD_BUNDLER_MAGIC_STR_LENGTH; @@ -346,13 +356,63 @@ inline void DetermineAndGetProgram(KalmarQueue* pQueue, size_t* kernel_size, voi RUNTIME_ERROR(1, "Fail to find compatible kernel", __LINE__) } } + +namespace +{ + template>> + int copy_kernel_sections(dl_phdr_info* x, size_t, void* kernels) + { + static constexpr const char kernel[] = ".kernel"; + + auto out = static_cast(kernels); + + ELFIO::elfio tmp; + if (tmp.load(x->dlpi_name)) { + for (auto&& y : tmp.sections) { + if (y->get_name() == kernel) { + out->emplace_back( + y->get_data(), y->get_data() + y->get_size()); + } + } + } -void BuildProgram(KalmarQueue* pQueue) { - size_t kernel_size = 0; - void* kernel_source = nullptr; + return 0; + } + + static + const std::vector>& shared_object_kernel_sections() + { + static std::vector> r; - DetermineAndGetProgram(pQueue, &kernel_size, &kernel_source); - pQueue->getDev()->BuildProgram((void*)kernel_size, kernel_source); + static std::once_flag f; + std::call_once(f, []() { dl_iterate_phdr(copy_kernel_sections, &r); }); + + return r; + } +} +void BuildProgram(KalmarQueue* pQueue) { + std::vector> bundles{ + {reinterpret_cast(&kernel_bundle_source), + reinterpret_cast(&kernel_bundle_end)}}; + bundles.insert( + bundles.end(), + shared_object_kernel_sections().cbegin(), + shared_object_kernel_sections().cend()); + + for (auto&& x : bundles) { + size_t kernel_size = 0; + void* kernel_source = nullptr; + + DetermineAndGetProgram( + x.data(), + x.data() + x.size(), + pQueue, + &kernel_size, + &kernel_source); + if (kernel_source) { + pQueue->getDev()->BuildProgram((void*)kernel_size, kernel_source); + } + } } // used in parallel_for_each.h @@ -424,7 +484,7 @@ static inline std::uint32_t f32_as_u32(float f) { union { float f; std::uint32_t static inline float u32_as_f32(std::uint32_t u) { union { float f; std::uint32_t u; } v; v.u = u; return v.f; } static inline int clamp_int(int i, int l, int h) { return std::min(std::max(i, l), h); } -// half à float, the f16 is in the low 16 bits of the input argument ¿a¿ +// half � float, the f16 is in the low 16 bits of the input argument �a� static inline float __convert_half_to_float(std::uint32_t a) noexcept { std::uint32_t u = ((a << 13) + 0x70000000U) & 0x8fffe000U; std::uint32_t v = f32_as_u32(u32_as_f32(u) * 0x1.0p+112f) + 0x38000000U; @@ -432,7 +492,7 @@ static inline float __convert_half_to_float(std::uint32_t a) noexcept { return u32_as_f32(u) * 0x1.0p-112f; } -// float à half with nearest even rounding +// float � half with nearest even rounding // The lower 16 bits of the result is the bit pattern for the f16 static inline std::uint32_t __convert_float_to_half(float a) noexcept { std::uint32_t u = f32_as_u32(a); diff --git a/tests/Unit/FilePath/file_path_test4.cpp b/tests/Unit/FilePath/file_path_test4.cpp index 106b020b218..0f7ff33ea9d 100644 --- a/tests/Unit/FilePath/file_path_test4.cpp +++ b/tests/Unit/FilePath/file_path_test4.cpp @@ -1,6 +1,6 @@ // RUN: mkdir -p "%T/foo bar" // RUN: cp "%s" "%T/foo bar" -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY "%T/foo bar/`basename "%s"`" -o "%T/foo bar/libfile_path_test4.so" +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY "%T/foo bar/`basename "%s"`" -o "%T/foo bar/libfile_path_test4.so" // RUN: %clang %s -L"%T/foo bar/" -lfile_path_test4 -o %t.out && LD_LIBRARY_PATH="%T/foo bar/" %t.out // kernels built as one single shared libary diff --git a/tests/Unit/SharedLibrary/shared_library1.cpp b/tests/Unit/SharedLibrary/shared_library1.cpp index 500c1d77cfd..821765ecc13 100644 --- a/tests/Unit/SharedLibrary/shared_library1.cpp +++ b/tests/Unit/SharedLibrary/shared_library1.cpp @@ -1,5 +1,5 @@ -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY %s -o %T/libtest1.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY %s -o %T/libtest1.so // RUN: %clang %s -L%T -ltest1 -o %t.out && LD_LIBRARY_PATH=%T %t.out // kernels built as one single shared libary diff --git a/tests/Unit/SharedLibrary/shared_library2.cpp b/tests/Unit/SharedLibrary/shared_library2.cpp index d4176bd2760..ce13fc43ba3 100644 --- a/tests/Unit/SharedLibrary/shared_library2.cpp +++ b/tests/Unit/SharedLibrary/shared_library2.cpp @@ -1,6 +1,6 @@ -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY_1 %s -o %T/libtest2_foo.so -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY_2 %s -o %T/libtest2_bar.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY_1 %s -o %T/libtest2_foo.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY_2 %s -o %T/libtest2_bar.so // RUN: %clang -std=c++11 -ldl -lpthread %s -o %t.out -ldl && LD_LIBRARY_PATH=%T %t.out // kernels built as multiple shared libraries diff --git a/tests/Unit/SharedLibrary/shared_library3.cpp b/tests/Unit/SharedLibrary/shared_library3.cpp index 536a9ed342a..7b37a29e9d5 100644 --- a/tests/Unit/SharedLibrary/shared_library3.cpp +++ b/tests/Unit/SharedLibrary/shared_library3.cpp @@ -1,6 +1,6 @@ -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY_1 %s -o %T/libtest3_foo.so -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY_2 %s -o %T/libtest3_bar.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY_1 %s -o %T/libtest3_foo.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY_2 %s -o %T/libtest3_bar.so // RUN: %clang -std=c++11 %s -L%T -ltest3_foo -ltest3_bar -o %t.out && LD_LIBRARY_PATH=%T %t.out // kernels built as multiple shared libraries diff --git a/tests/Unit/SharedLibrary/shared_library4.cpp b/tests/Unit/SharedLibrary/shared_library4.cpp index e64b13e845e..79a9b7a5247 100644 --- a/tests/Unit/SharedLibrary/shared_library4.cpp +++ b/tests/Unit/SharedLibrary/shared_library4.cpp @@ -1,5 +1,5 @@ -// RUN: %hc -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY %s -o %T/libtest4.so +// RUN: %hc -fPIC -shared -DSHARED_LIBRARY %s -o %T/libtest4.so // RUN: %hc %s -L%T -ltest4 -o %t.out && LD_LIBRARY_PATH=%T %t.out // kernels built as one single shared libary diff --git a/tests/Unit/SharedLibrary/shared_library5.cpp b/tests/Unit/SharedLibrary/shared_library5.cpp index 7320dfce04e..2eb92aca071 100644 --- a/tests/Unit/SharedLibrary/shared_library5.cpp +++ b/tests/Unit/SharedLibrary/shared_library5.cpp @@ -1,5 +1,5 @@ -// RUN: %hc --amdgpu-target=gfx701 --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 -fPIC -Wl,-Bsymbolic -shared -DSHARED_LIBRARY %s -o %T/libtest5.so +// RUN: %hc --amdgpu-target=gfx701 --amdgpu-target=gfx801 --amdgpu-target=gfx802 --amdgpu-target=gfx803 -fPIC -shared -DSHARED_LIBRARY %s -o %T/libtest5.so // RUN: %clang %s -L%T -ltest5 -o %t.out && LD_LIBRARY_PATH=%T %t.out // kernels built as one single shared libary From 45d7c1789bcdc6b777bcec19052356834a729ea9 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Mon, 7 Aug 2017 03:58:44 +0100 Subject: [PATCH 2/4] This builds upon the prior change and corrects it to make it invariant by rapport with ordering of library initialisation. At the same time, a reduction in overhauled capability is introduced, with new HC2 functionality being used only for obtaining the .kernel sections from shared objects. The shared object iteration is moved to execute within HSADevice::CreateKernel, which holds all of the HCC changes. A one-time cost is incurred for the runtime initialisation of the static structures underpinning the implementation. The spurious HSAKernel::executable_ data member is removed, since it was not used anywhere and it made it difficult to construct values of type HSAKernel. This has been verified to work with some of the trickier cases we are dealing with, on top of the SharedLibrary unit-tests. --- hc2/headers/functions/hsa_interfaces.hpp | 299 ++++++++++++++++++ .../functions/integer_computational_basis.hpp | 22 ++ hc2/headers/types/code_object_bundle.hpp | 160 ++++++++++ hc2/headers/types/program_state.hpp | 276 ++++++++++++++++ hc2/headers/types/raii_handle.hpp | 126 ++++++++ hc2/headers/types/type_support.hpp | 20 ++ lib/hsa/mcwamp_hsa.cpp | 236 +++++++------- lib/mcwamp.cpp | 104 ++---- 8 files changed, 1053 insertions(+), 190 deletions(-) create mode 100644 hc2/headers/functions/hsa_interfaces.hpp create mode 100644 hc2/headers/functions/integer_computational_basis.hpp create mode 100644 hc2/headers/types/code_object_bundle.hpp create mode 100644 hc2/headers/types/program_state.hpp create mode 100644 hc2/headers/types/raii_handle.hpp create mode 100644 hc2/headers/types/type_support.hpp diff --git a/hc2/headers/functions/hsa_interfaces.hpp b/hc2/headers/functions/hsa_interfaces.hpp new file mode 100644 index 00000000000..bcc4b71081e --- /dev/null +++ b/hc2/headers/functions/hsa_interfaces.hpp @@ -0,0 +1,299 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#include "../types/raii_handle.hpp" + +#include + +#include + +#include +#include +#include +#include +#include + +inline +bool operator==(const hsa_agent_t& x, const hsa_agent_t& y) +{ + return x.handle == y.handle; +} + +inline +bool operator==(const hsa_isa_t& x, const hsa_isa_t& y) +{ + return x.handle == y.handle; +} + +inline +bool operator==( + const hsa_executable_symbol_t& x, const hsa_executable_symbol_t& y) +{ + return x.handle == y.handle; +} + +namespace std +{ + template<> + struct hash { + using argument_type = hsa_agent_t; + using result_type = std::size_t; + + result_type operator()(const argument_type& x) const + { + return std::hash{}(x.handle); + } + }; + + template<> + struct hash { + using argument_type = hsa_isa_t; + using result_type = std::size_t; + + result_type operator()(const argument_type& x) const + { + return std::hash{}(x.handle); + } + }; + + template<> + struct hash { + using argument_type = hsa_executable_symbol_t; + using result_type = std::size_t; + + result_type operator()(const argument_type& x) const + { + return std::hash{}(x.handle); + } + }; +} + +namespace hc2 +{ + inline + std::string to_string(const hsa_isa_t& x) + { + std::size_t sz = 0u; + hsa_isa_get_info(x, HSA_ISA_INFO_NAME_LENGTH, 0u, &sz); + + std::string r(sz, '\0'); + hsa_isa_get_info(x, HSA_ISA_INFO_NAME, 0u, &r.front()); + + return r; + } + + inline + std::string to_string(hsa_status_t err) + { + const char* s = nullptr; + if (hsa_status_string(err, &s) != HSA_STATUS_SUCCESS) { + return "Unknown."; + } + + return s; + } + + inline + void throwing_hsa_result_check( + hsa_status_t res, + const std::string& file, + const std::string& fn, + int line) + { + if (res != HSA_STATUS_SUCCESS) { + throw std::runtime_error{ + "Failed in file " + file + ", in function \"" + fn + + "\", on line " + std::to_string(line) + ", with error: " + + to_string(res)}; + } + } + + inline + hsa_agent_t hsa_agent(const hc::accelerator_view& av) + { + assert( + const_cast(av).get_hsa_agent() != nullptr); + + return *static_cast( + const_cast(av).get_hsa_agent()); + } + + inline + hsa_agent_t hsa_agent(const hc::accelerator& acc) + { + return hsa_agent(acc.get_default_view()); + } + + inline + hsa_isa_t hsa_agent_isa(const hc::accelerator_view& av) + { + hsa_isa_t r; + throwing_hsa_result_check( + hsa_agent_get_info(hsa_agent(av), HSA_AGENT_INFO_ISA, &r), + __FILE__, + __func__, + __LINE__); + + return r; + } + + inline + hsa_isa_t hsa_agent_isa(const hc::accelerator& acc) + { + return hsa_agent_isa(acc.get_default_view()); + } + + inline + std::string hsa_agent_name(hsa_agent_t x) + { + static constexpr std::size_t max_name_length = 63; + static std::array n = {{}}; + + throwing_hsa_result_check( + hsa_agent_get_info(x, HSA_AGENT_INFO_NAME, n.data()), + __FILE__, + __func__, + __LINE__); + + return std::string{n.cbegin(), n.cend()}; + } + + inline + std::string hsa_agent_name(const hc::accelerator_view& av) + { + return hsa_agent_name(hsa_agent(av)); + } + + inline + std::string hsa_agent_name(const hc::accelerator& acc) + { + return hsa_agent_name(acc.get_default_view()); + } + + inline + decltype(HSA_PROFILE_FULL) hsa_agent_profile(const hc::accelerator_view& av) + { + decltype(HSA_PROFILE_FULL) r; + throwing_hsa_result_check( + hsa_agent_get_info(hsa_agent(av), HSA_AGENT_INFO_PROFILE, &r), + __FILE__, + __func__, + __LINE__); + + return r; + } + + inline + decltype(HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT) hsa_agent_float_rounding_mode(hsa_agent_t a) + { + decltype(HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT) r; + throwing_hsa_result_check( + hsa_agent_get_info( + a, HSA_AGENT_INFO_DEFAULT_FLOAT_ROUNDING_MODE, &r), + __FILE__, + __func__, + __LINE__); + + return r; + } + + inline + decltype(HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT) hsa_agent_float_rounding_mode(const hc::accelerator_view& av) + { + return hsa_agent_float_rounding_mode(hsa_agent(av)); + } + + namespace + { + using Executable_symbol_info_t = + decltype(HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT); + } + + struct Symbol_kind_tag { + using value_type = hsa_symbol_kind_t; + + constexpr + operator Executable_symbol_info_t() const + { + return HSA_EXECUTABLE_SYMBOL_INFO_TYPE; + } + }; + + struct Symbol_name_size_tag { + using value_type = std::uint32_t; + + constexpr + operator Executable_symbol_info_t() const + { + return HSA_EXECUTABLE_SYMBOL_INFO_NAME_LENGTH; + } + }; + + struct Private_size_tag { + using value_type = std::uint32_t; + + constexpr + operator Executable_symbol_info_t() const + { + return HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE; + } + }; + + struct Lds_size_tag { + using value_type = std::uint32_t; + + constexpr + operator Executable_symbol_info_t() const + { + return HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_GROUP_SEGMENT_SIZE; + } + + }; + + struct Kernel_handle_tag { + using value_type = std::uint64_t; + + constexpr + operator Executable_symbol_info_t() const + { + return HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT; + } + }; + + template + typename T::value_type hsa_kernel_info(hsa_executable_symbol_t x, T info) + { + typename T::value_type r = {}; + throwing_hsa_result_check( + hsa_executable_symbol_get_info(x, info, &r), + __FILE__, + __func__, + __LINE__); + + return r; + } + + inline + bool is_kernel(hsa_executable_symbol_t x) + { + return hsa_kernel_info(x, Symbol_kind_tag{}) == + hsa_symbol_kind_t::HSA_SYMBOL_KIND_KERNEL; + } + + inline + std::string hsa_symbol_name(hsa_executable_symbol_t x) + { + const auto sz = hsa_kernel_info(x, Symbol_name_size_tag{}); + + std::string r(sz, '\0'); + hsa_executable_symbol_get_info( + x, HSA_EXECUTABLE_SYMBOL_INFO_NAME, &r.front()); + + return r; + } +} \ No newline at end of file diff --git a/hc2/headers/functions/integer_computational_basis.hpp b/hc2/headers/functions/integer_computational_basis.hpp new file mode 100644 index 00000000000..3fa8616cba1 --- /dev/null +++ b/hc2/headers/functions/integer_computational_basis.hpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#include + +namespace hc2 +{ + template< + typename T, + typename std::enable_if{}>::type* = nullptr> + inline + constexpr + bool positive(T x) + { + return x > T{0}; + } +} \ No newline at end of file diff --git a/hc2/headers/types/code_object_bundle.hpp b/hc2/headers/types/code_object_bundle.hpp new file mode 100644 index 00000000000..4046046c645 --- /dev/null +++ b/hc2/headers/types/code_object_bundle.hpp @@ -0,0 +1,160 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#include "../functions/hsa_interfaces.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace hc2 +{ + struct Bundled_code { + union { + struct { + std::uint64_t offset; + std::uint64_t bundle_sz; + std::uint64_t triple_sz; + }; + char cbuf[ + sizeof(offset) + sizeof(bundle_sz) + sizeof(triple_sz)]; + }; + std::string triple; + std::vector blob; + }; + + class Bundled_code_header { + friend + inline + bool valid(const Bundled_code_header& x) + { + return std::equal( + x.bundler_magic_string, + x.bundler_magic_string + x.magic_string_sz, + x.magic_string); + } + + friend + inline + const std::vector& bundles(const Bundled_code_header& x) + { + return x.bundles; + } + + template + friend + inline + bool read( + RandomAccessIterator f, + RandomAccessIterator l, + Bundled_code_header& x) + { + std::copy_n(f, sizeof(x.cbuf), x.cbuf); + + if (valid(x)) { + x.bundles.resize(x.bundle_cnt); + + auto it = f + sizeof(x.cbuf); + for (auto&& y : x.bundles) { + std::copy_n(it, sizeof(y.cbuf), y.cbuf); + it += sizeof(y.cbuf); + + y.triple.insert(y.triple.cend(), it, it + y.triple_sz); + + std::copy_n( + f + y.offset, y.bundle_sz, std::back_inserter(y.blob)); + + it += y.triple_sz; + } + + return true; + } + + return false; + } + + friend + inline + bool read(const std::vector& blob, Bundled_code_header& x) + { + return read(blob.cbegin(), blob.cend(), x); + } + + friend + inline + bool read(std::istream& is, Bundled_code_header& x) + { + return read(std::vector{ + std::istreambuf_iterator{is}, + std::istreambuf_iterator{}}, + x); + } + + static constexpr const char magic_string[] = "__CLANG_OFFLOAD_BUNDLE__"; + static constexpr std::size_t magic_string_sz = sizeof(magic_string) - 1; + + union { + struct { + char bundler_magic_string[magic_string_sz]; + std::uint64_t bundle_cnt; + }; + char cbuf[sizeof(bundler_magic_string) + sizeof(bundle_cnt)]; + }; + std::vector bundles; + public: + Bundled_code_header() = default; + Bundled_code_header(const Bundled_code_header&) = default; + Bundled_code_header(Bundled_code_header&&) = default; + + template + Bundled_code_header(RandomAccessIterator f, RandomAccessIterator l) + : Bundled_code_header{} + { + read(f, l, *this); + } + + explicit + Bundled_code_header(const std::vector& blob) + : Bundled_code_header{blob.cbegin(), blob.cend()} + {} + }; + constexpr const char Bundled_code_header::magic_string[]; + + inline + hsa_isa_t triple_to_hsa_isa(const std::string& triple) + { + static constexpr const char gfxip[] = "hcc-amdgcn--amdhsa-gfx"; + + hsa_isa_t r = {}; + + auto it = std::find_if( + triple.cbegin(), + triple.cend(), + [](char x) { return std::isdigit(x); }); + if (std::equal(triple.cbegin(), it, gfxip)) { + std::string tmp = "AMD:AMDGPU"; + while (it != triple.cend()) { + tmp.push_back(':'); + tmp.push_back(*it++); + } + + throwing_hsa_result_check( + hsa_isa_from_name(tmp.c_str(), &r), + __FILE__, + __func__, + __LINE__); + } + + return r; + } +} diff --git a/hc2/headers/types/program_state.hpp b/hc2/headers/types/program_state.hpp new file mode 100644 index 00000000000..ed3faffb000 --- /dev/null +++ b/hc2/headers/types/program_state.hpp @@ -0,0 +1,276 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#include "raii_handle.hpp" +#include "../functions/integer_computational_basis.hpp" +#include "../functions/hsa_interfaces.hpp" +#include "../types/code_object_bundle.hpp" + +#include + +#include + +#include "../../external/elfio/elfio.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace hc2 +{ + namespace + { + using RAII_code_object_reader = + RAII_move_only_handle< + hsa_code_object_reader_t, + decltype(hsa_code_object_reader_destroy)*>; + using RAII_executable = RAII_move_only_handle< + hsa_executable_t, decltype(hsa_executable_destroy)*>; + + inline + RAII_code_object_reader make_code_object_reader( + const char* f, std::size_t n) + { + RAII_code_object_reader r{{}, hsa_code_object_reader_destroy}; + + if (positive(n)) { + throwing_hsa_result_check( + hsa_code_object_reader_create_from_memory(f, n, &handle(r)), + __FILE__, + __func__, + __LINE__); + } + + return r; + } + + inline + RAII_code_object_reader make_code_object_reader( + const std::vector& x) + { + return make_code_object_reader(x.data(), x.size()); + } + + inline + RAII_executable executable( + const RAII_code_object_reader& x, hsa_agent_t a) + { + RAII_executable r{{}, hsa_executable_destroy}; + + throwing_hsa_result_check( + hsa_executable_create_alt( + HSA_PROFILE_FULL,//hsa_agent_profile(av) - TODO: this is a bug. + hsa_agent_float_rounding_mode(a), + nullptr, + &handle(r)), + __FILE__, + __func__, + __LINE__); + + throwing_hsa_result_check( + hsa_executable_load_agent_code_object( + handle(r), a, handle(x), nullptr, nullptr), + __FILE__, + __func__, + __LINE__); + + // TODO: temporary. + std::uint32_t v = UINT32_MAX; + throwing_hsa_result_check( + hsa_executable_validate_alt(handle(r), nullptr, &v), + __FILE__, + __func__, + __LINE__); + + assert(zero(v)); + + throwing_hsa_result_check( + hsa_executable_freeze(handle(r), nullptr), + __FILE__, + __func__, + __LINE__); + + return r; + } + } + + class Program_state { + using Code_object_table = std::unordered_map< + hsa_isa_t, std::vector>; + using Executable_table = std::unordered_map< + hsa_agent_t, std::vector>; + using Kernel_table = std::unordered_map< + hsa_agent_t, std::vector>; + + friend const Program_state& program_state(); + + friend + inline + const Kernel_table& shared_object_kernels(const Program_state& x) + { + return x.shared_object_kernel_table_(); + } + + std::vector acc_; + + template>> + static + int copy_kernel_sections_(dl_phdr_info* x, size_t, void* kernels) + { + static constexpr const char kernel[] = ".kernel"; + + auto out = static_cast(kernels); + + ELFIO::elfio tmp; + if (tmp.load(x->dlpi_name)) { + for (auto&& y : tmp.sections) { + if (y->get_name() == kernel) { + out->emplace_back( + y->get_data(), y->get_data() + y->get_size()); + } + } + } + + return 0; + } + + static + const std::vector& shared_object_kernel_sections_() + { + static std::vector r; + + static std::once_flag f; + std::call_once(f, []() { + std::vector> ks; + dl_iterate_phdr(copy_kernel_sections_<>, &ks); + + for (auto&& x : ks) { + Bundled_code_header tmp{x}; + if (valid(tmp)) r.push_back(std::move(tmp)); + } + }); + + return r; + } + + static + void make_code_object_table_( + const Bundled_code_header& x, Code_object_table& y) + { + for (auto&& z : bundles(x)) { + y[triple_to_hsa_isa(z.triple)].push_back( + make_code_object_reader(z.blob)); + } + y.erase(hsa_isa_t{0}); + } + + static + const Code_object_table& shared_object_code_object_table_() + { + static Code_object_table r; + + static std::once_flag f; + std::call_once(f, []() { + for (auto&& x : shared_object_kernel_sections_()) { + make_code_object_table_(x, r); + } + }); + + return r; + } + + void make_executable_table_( + const Code_object_table& x, Executable_table& y) const + { + for (auto&& a : acc_) { + const auto it = x.find(hsa_agent_isa(a)); + if (it != x.cend()) { + for (auto&& z : it->second) { + y[hsa_agent(a)].push_back(executable(z, hsa_agent(a))); + } + } + } + } + + const Executable_table& shared_object_executable_table_() const + { + static Executable_table r; + + static std::once_flag f; + std::call_once(f, [this]() { + make_executable_table_(shared_object_code_object_table_(), r); + }); + return r; + } + + static + decltype(HSA_STATUS_SUCCESS) copy_kernel_symbols( + hsa_executable_t, hsa_agent_t x, hsa_executable_symbol_t y, void* z) + { + auto p = static_cast(z); + + if (is_kernel(y)) p->push_back(y); + + return HSA_STATUS_SUCCESS; + } + + void make_kernel_table_( + const Executable_table& x, Kernel_table& y) const + { + for (auto&& e : x) { + for (auto&& ex : e.second) { + hsa_executable_iterate_agent_symbols( + handle(ex), e.first, copy_kernel_symbols, &y[e.first]); + } + } + } + + const Kernel_table& shared_object_kernel_table_() const + { + static Kernel_table r; + + static std::once_flag f; + std::call_once(f, [this]() { + make_kernel_table_(shared_object_executable_table_(), r); + }); + + return r; + } + + Program_state() : acc_{hc::accelerator::get_all()} + { + acc_.erase( + std::remove_if( + acc_.begin(), + acc_.end(), + [](const hc::accelerator& x) { return !x.is_hsa_accelerator(); }), + acc_.end()); + } + public: + Program_state(const Program_state&) = default; + Program_state(Program_state&&) = default; + + Program_state& operator=(const Program_state&) = default; + Program_state& operator=(Program_state&&) = default; + + ~Program_state() = default; + }; + + inline + const Program_state& program_state() + { + static const Program_state r; + + return r; + } +} \ No newline at end of file diff --git a/hc2/headers/types/raii_handle.hpp b/hc2/headers/types/raii_handle.hpp new file mode 100644 index 00000000000..436cad109b5 --- /dev/null +++ b/hc2/headers/types/raii_handle.hpp @@ -0,0 +1,126 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#include "type_support.hpp" + +#include +#include + +namespace hc2 +{ + template + class RAII_handle { + friend + inline + const T& handle(const RAII_handle& x) { return x.h_; } + + friend + inline + T& handle(RAII_handle& x) { return x.h_; } + + T h_; + D d_; + public: + RAII_handle() = default; + RAII_handle(const RAII_handle&) = default; + RAII_handle(RAII_handle&&) = default; + + RAII_handle(T h, D d) : h_{std::move(h)}, d_{std::move(d)} {} + + template< + typename E, + typename std::enable_if{}>::type* = nullptr> + RAII_handle(T h, E d) : RAII_handle{std::move(h), std::move(d)} {} + + RAII_handle& operator=(const RAII_handle&) = default; + RAII_handle& operator=(RAII_handle&&) = default; + + operator T() const { return h_; } + + ~RAII_handle() { d_(h_); } + }; + + template + class RAII_move_only_handle : + public Swappable> { + friend class Swappable; + + friend + inline + const T& handle(const RAII_move_only_handle& x) { return x.h_; } + + friend + inline + T& handle(RAII_move_only_handle& x) { return x.h_; } + + T h_; + D d_; + bool v_ = false; + + void swp_(RAII_move_only_handle& x) + { + using std::swap; + + swap(h_, x.h_); + swap(d_, x.d_); + swap(v_, x.v_); + } + public: + RAII_move_only_handle() = default; + RAII_move_only_handle(const RAII_move_only_handle&) = delete; + RAII_move_only_handle(RAII_move_only_handle&& x) + : RAII_move_only_handle{std::move(x.h_), std::move(x.d_)} + { + x.h_ = T{}; + x.v_ = false; + } + + RAII_move_only_handle(T h, D d) + : h_{std::move(h)}, d_{std::move(d)}, v_{true} + {} + + template< + typename E, + typename std::enable_if{}>::type* = nullptr> + RAII_move_only_handle(T h, E d) + : RAII_move_only_handle{std::move(h), std::move(d)} + {} + + RAII_move_only_handle& operator=(RAII_move_only_handle x) + { + using std::swap; + + swap(*this, x); + + return *this; + } + + ~RAII_move_only_handle() { if (v_) d_(h_); v_ = false; } + }; + + template + class RAII_stateless_handle { + D d_; + public: + RAII_stateless_handle() = default; + RAII_stateless_handle(const RAII_stateless_handle&) = default; + RAII_stateless_handle(RAII_stateless_handle&&) = default; + + template + RAII_stateless_handle(const C& ctor, D dtor) : d_{std::move(dtor)} + { + ctor(); + } + + RAII_stateless_handle& operator=( + const RAII_stateless_handle&) = default; + RAII_stateless_handle& operator=(RAII_stateless_handle&&) = default; + + ~RAII_stateless_handle() { d_(); } + }; +} \ No newline at end of file diff --git a/hc2/headers/types/type_support.hpp b/hc2/headers/types/type_support.hpp new file mode 100644 index 00000000000..edd68263999 --- /dev/null +++ b/hc2/headers/types/type_support.hpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +namespace hc2 +{ + template + class Swappable { + friend + inline + void swap(T& x, T& y) { Swappable::swap_(x, y); } + public: + static + void swap_(T& x, T& y) { x.swp_(y); } + }; +} \ No newline at end of file diff --git a/lib/hsa/mcwamp_hsa.cpp b/lib/hsa/mcwamp_hsa.cpp index e3e2d157263..bba0276f532 100644 --- a/lib/hsa/mcwamp_hsa.cpp +++ b/lib/hsa/mcwamp_hsa.cpp @@ -6,6 +6,8 @@ // Kalmar Runtime implementation (HSA version) +#include "../hc2/headers/types/program_state.hpp" + #include #include #include @@ -365,7 +367,6 @@ class HSAKernel { private: std::string kernelName; std::string shortKernelName; - HSAExecutable* executable; uint64_t kernelCodeHandle; hsa_executable_symbol_t hsaExecutableSymbol; uint32_t static_group_segment_size; @@ -374,12 +375,11 @@ class HSAKernel { friend class HSADispatch; public: - HSAKernel(std::string &_kernelName, const std::string &x_shortKernelName, HSAExecutable* _executable, + HSAKernel(std::string &_kernelName, const std::string &x_shortKernelName, hsa_executable_symbol_t _hsaExecutableSymbol, uint64_t _kernelCodeHandle) : kernelName(_kernelName), shortKernelName(x_shortKernelName), - executable(_executable), hsaExecutableSymbol(_hsaExecutableSymbol), kernelCodeHandle(_kernelCodeHandle) { @@ -483,16 +483,16 @@ class HSACopy : public Kalmar::KalmarAsyncOp { std::string s; switch (getCommandKind()) { - case hcMemcpyHostToHost: + case hcMemcpyHostToHost: s += "HostToHost"; break; - case hcMemcpyHostToDevice: + case hcMemcpyHostToDevice: s += "HostToDevice"; break; - case hcMemcpyDeviceToHost: + case hcMemcpyDeviceToHost: s += "DeviceToHost"; break; - case hcMemcpyDeviceToDevice: + case hcMemcpyDeviceToDevice: if (isPeerToPeer) { s += "PeerToPeer"; } else { @@ -515,7 +515,7 @@ class HSACopy : public Kalmar::KalmarAsyncOp { // HSA signals would be waited in HSA_WAIT_STATE_ACTIVE by default for HSACopy instances HSACopy(Kalmar::KalmarQueue *queue, const void* src_, void* dst_, size_t sizeBytes_); - + ~HSACopy() { @@ -553,7 +553,7 @@ class HSACopy : public Kalmar::KalmarAsyncOp { private: - hsa_status_t hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, const Kalmar::HSADevice *copyDevice, + hsa_status_t hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, const Kalmar::HSADevice *copyDevice, const hc::AmPointerInfo &dstPtrInfo, const hc::AmPointerInfo &srcPtrInfo, size_t sizeBytes, int depSignalCnt, const hsa_signal_t *depSignals, hsa_signal_t completion_signal); @@ -624,7 +624,7 @@ class HSABarrier : public Kalmar::KalmarAsyncOp { if ((count >= 0) && (count <= 5)) { for (int i = 0; i < count; ++i) { if (dependent_op_array[i]) { - // squish null ops + // squish null ops depAsyncOps[depCount] = dependent_op_array[i]; depCount++; } @@ -671,7 +671,7 @@ class HSADispatch : public Kalmar::KalmarAsyncOp { Kalmar::HSADevice* device; hsa_agent_t agent; - const char *kernel_name; + const char *kernel_name; const HSAKernel* kernel; std::vector arg_vec; @@ -874,7 +874,7 @@ struct RocrQueue { STATUS_CHECK(status, __LINE__); } - RocrQueue(hsa_agent_t agent, size_t queue_size, HSAQueue *hccQueue) + RocrQueue(hsa_agent_t agent, size_t queue_size, HSAQueue *hccQueue) { assert(queue_size != 0); @@ -912,9 +912,9 @@ struct RocrQueue { HSAQueue *_hccQueue; // Pointe to the HCC "HSA" queue which is assigned to use the rocrQueue std::vector cu_arrays; - + // Track profiling enabled state here. - no need now since all hw queues have profiling enabled. - + // Priority could be tracked here: }; @@ -927,7 +927,7 @@ class HSAQueue final : public KalmarQueue friend class RocrQueue; friend std::ostream& operator<<(std::ostream& os, const HSAQueue & hav); - // ROCR queue associated with this HSAQueue instance. + // ROCR queue associated with this HSAQueue instance. RocrQueue *rocrQueue; std::mutex qmutex; // Protect structures for this KalmarQueue. Currently just the hsaQueue. @@ -945,8 +945,8 @@ class HSAQueue final : public KalmarQueue uint64_t opSeqNums; uint64_t queueSeqNum; // sequence-number of this queue. - // Valid is used to prevent the fields of the HSAQueue from being disposed - // multiple times. + // Valid is used to prevent the fields of the HSAQueue from being disposed + // multiple times. bool valid; @@ -955,8 +955,8 @@ class HSAQueue final : public KalmarQueue // host data is valid. bool _nextSyncNeedsSysRelease; - // Flag that is set after a copy command. - // The next kernel command issued needs to add a system-scope acquire to + // Flag that is set after a copy command. + // The next kernel command issued needs to add a system-scope acquire to // pick up any data that may have been written by the copy. bool _nextKernelNeedsSysAcquire; @@ -1092,7 +1092,7 @@ class HSAQueue final : public KalmarQueue - // Check upcoming command that will be sent to this queue against the youngest async op + // Check upcoming command that will be sent to this queue against the youngest async op // in the queue to detect if any command dependency is required. // // The function returns nullptr if no dependency is required. For example, back-to-back commands @@ -1155,7 +1155,7 @@ class HSAQueue final : public KalmarQueue int getPendingAsyncOps() override { int count = 0; for (int i = 0; i < asyncOps.size(); ++i) { - auto &asyncOp = asyncOps[i]; + auto &asyncOp = asyncOps[i]; if (asyncOp != nullptr) { hsa_signal_t signal = *(static_cast (asyncOp->getNativeHandle())); @@ -1197,14 +1197,14 @@ class HSAQueue final : public KalmarQueue // Ensures younger ops have chance to complete before older ops reclaim their resources // - + if (HCC_OPT_FLUSH && nextSyncNeedsSysRelease()) { // In the loop below, this will be the first op waited on auto marker = EnqueueMarker(hc::system_scope); DBOUT(DB_CMD, " Sys-release needed, enqueued marker to release written data " << marker<<"\n"); - + } DBOUT(DB_WAIT, *this << " wait, contents:\n"); @@ -1315,7 +1315,7 @@ class HSAQueue final : public KalmarQueue } - void releaseToSystemIfNeeded() + void releaseToSystemIfNeeded() { if (HCC_OPT_FLUSH && nextSyncNeedsSysRelease()) { // In the loop below, this will be the first op waited on @@ -1678,17 +1678,17 @@ class HSAQueue final : public KalmarQueue // enqueue a barrier packet with multiple prior dependencies - // The marker will wait for all specified input dependencies to resolve and + // The marker will wait for all specified input dependencies to resolve and // also for all older commands in the queue to execute, and then will // signal completion by decrementing the associated signal. // - // depOps specifies the other ops that this marker will depend on. These + // depOps specifies the other ops that this marker will depend on. These // can be in any queue on any GPU . - // + // // releaseScope specifies the scope of the release fence that will be // applied after the marker executes. See hc::memory_scope - std::shared_ptr EnqueueMarkerWithDependency(int count, - std::shared_ptr *depOps, + std::shared_ptr EnqueueMarkerWithDependency(int count, + std::shared_ptr *depOps, hc::memory_scope releaseScope) override { hsa_status_t status = HSA_STATUS_SUCCESS; @@ -1704,12 +1704,12 @@ class HSAQueue final : public KalmarQueue // Same accelerator: // Inherit system-acquire and system-release bits from the queue which contains the op we are dependent on. // - // _nextSyncNeedsSysRelease is set when a queue executes a kernel. + // _nextSyncNeedsSysRelease is set when a queue executes a kernel. // It indicates the queue needs to execute a release-to-system - // before host can see the data - this is important for kernels which write + // before host can see the data - this is important for kernels which write // non-coherent zero-copy host memory. - // If creating a dependency on a queue which needs_system_release, copy that - // state here. If the host then waits on the freshly created marker, + // If creating a dependency on a queue which needs_system_release, copy that + // state here. If the host then waits on the freshly created marker, // runtime will issue a system-release fence. if (depHSAQueue->nextKernelNeedsSysAcquire()) { setNextKernelNeedsSysAcquire(true); @@ -1720,11 +1720,11 @@ class HSAQueue final : public KalmarQueue if (depHSAQueue->getHSADev() != this->getHSADev()) { // Cross-accelerator dependency case. - // This requires system-scope acquire + // This requires system-scope acquire // TODO - only needed if these are peer GPUs, could optimize with an extra check DBOUT(DB_WAIT, " Adding cross-accelerator system-scope acquire\n"); barrier->acquire_scope (hc::system_scope); - } + } } else { break; @@ -1864,7 +1864,7 @@ class HSADevice final : public KalmarDevice uint16_t versionMajor; uint16_t versionMinor; - int accSeqNum; // unique accelerator seq num + int accSeqNum; // unique accelerator seq num uint64_t queueSeqNums; // used to assign queue seqnums. @@ -1876,7 +1876,7 @@ class HSADevice final : public KalmarDevice // Creates or steals a rocrQueue and returns it in theif->rocrQueue void createOrstealRocrQueue(Kalmar::HSAQueue *thief) { - + std::lock_guard (this->rocrQueuesMutex); if (rocrQueues.size() < HCC_MAX_QUEUES) { @@ -1899,7 +1899,7 @@ class HSADevice final : public KalmarDevice foundRQ = rq; break; } - } + } if (!foundRQ) { for (auto rq : rocrQueues) { if (rq->_hccQueue != thief) { @@ -1910,7 +1910,7 @@ class HSADevice final : public KalmarDevice DBOUT(DB_LOCK, " ptr:" << this << " lock_guard...\n"); assert (victimHccQueue->rocrQueue == rq); // ensure the link is consistent. - victimHccQueue->rocrQueue = nullptr; + victimHccQueue->rocrQueue = nullptr; foundRQ = rq; DBOUT(DB_QUEUE, "Stole existing rocrQueue=" << rq << " from victimHccQueue=" << victimHccQueue << " to hccQueue=" << thief << "\n") break; @@ -1919,7 +1919,7 @@ class HSADevice final : public KalmarDevice } } if (foundRQ) { - + // update the queue pointers to indicate the theft: foundRQ->assignHccQueue(thief); @@ -1939,17 +1939,17 @@ class HSADevice final : public KalmarDevice // queues already locked: size_t hccSize = queues.size(); - { + { std::lock_guard (this->rocrQueuesMutex); // a perf optimization to keep the HSA queue if we have more HCC queues that might want it. - // This defers expensive queue deallocation if an hccQueue that holds an hwQueue is destroyed - + // This defers expensive queue deallocation if an hccQueue that holds an hwQueue is destroyed - // keep the hwqueue around until the number of hccQueues drops below the number of hwQueues // we have already allocated. auto rqSize = rocrQueues.size(); if (hccSize < rqSize) { auto iter = std::find(rocrQueues.begin(), rocrQueues.end(), rocrQueue); - assert (iter != rocrQueues.end()); + assert (iter != rocrQueues.end()); // Remove the pointer from the list: rocrQueues.erase(iter); DBOUT(DB_QUEUE, "removeRocrQueue-hard: rocrQueue=" << rocrQueue << " hccQueues/rocrQueues=" << hccSize << "/" << rqSize << "\n") @@ -2336,7 +2336,7 @@ class HSADevice final : public KalmarDevice shortName = shortName.substr(begin); - + DBOUTL(DB_CODE, "shortKernel processing demangled. beginChar=" << begin << " endChar=" << end ); @@ -2362,7 +2362,7 @@ class HSADevice final : public KalmarDevice uint64_t kernelCodeHandle; status = hsa_executable_symbol_get_info(kernelSymbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &kernelCodeHandle); if (status == HSA_STATUS_SUCCESS) { - kernel = new HSAKernel(str, shortName, executable, kernelSymbol, kernelCodeHandle); + kernel = new HSAKernel(str, shortName, kernelSymbol, kernelCodeHandle); break; } } @@ -2370,15 +2370,35 @@ class HSADevice final : public KalmarDevice } if (!kernel) { - hc::print_backtrace(); - std::cerr << "HSADevice::CreateKernel(): Unable to create kernel " << shortName << " \n"; - std::cerr << " CreateKernel_raw= " << fun << "\n"; - std::cerr << " CreateKernel_demangled= " << demangled << "\n"; - - if (demangled) { - free((void*)demangled); // cxa_dmangle mallocs memory. + const auto it = + shared_object_kernels(hc2::program_state()).find(agent); + if (it != shared_object_kernels(hc2::program_state()).cend()) { + const auto k = std::find_if( + it->second.cbegin(), + it->second.cend(), + [&](hsa_executable_symbol_t x) { + return hc2::hsa_symbol_name(x) == str; + }); + if (k != it->second.cend()) { + uint64_t h = 0u; + if (hsa_executable_symbol_get_info( + *k, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &h) == + HSA_STATUS_SUCCESS) { + kernel = new HSAKernel(str, shortName, *k, h); + } + } + } + if (!kernel) { + hc::print_backtrace(); + std::cerr << "HSADevice::CreateKernel(): Unable to create kernel " << shortName << " \n"; + std::cerr << " CreateKernel_raw= " << fun << "\n"; + std::cerr << " CreateKernel_demangled= " << demangled << "\n"; + + if (demangled) { + free((void*)demangled); // cxa_dmangle mallocs memory. + } + abort(); } - abort(); } else { //std::cerr << "HSADevice::CreateKernel(): Created kernel\n"; } @@ -2891,7 +2911,7 @@ class HSAContext final : public KalmarContext ReadHccEnv(); // initialize HSA runtime - + DBOUT(DB_INIT,"HSAContext::HSAContext(): init HSA runtime"); hsa_status_t status; @@ -3116,14 +3136,14 @@ namespace Kalmar { // Global free function to read HCC_ENV vars. Really this should be called once per process not once-per-event. // Global so HCC clients or debuggers can force a re-read of the environment variables. -void HSAContext::ReadHccEnv() +void HSAContext::ReadHccEnv() { GET_ENV_INT(HCC_PRINT_ENV, "Print values of HCC environment variables"); // 0x1=pre-serialize, 0x2=post-serialize , 0x3= pre- and post- serialize. // HCC_SERIALIZE_KERNEL serializes PFE, GL, and dispatch_hsa_kernel calls. // HCC_SERIALIZE_COPY serializes av::copy_async operations. (array_view copies are not currently impacted)) - GET_ENV_INT(HCC_SERIALIZE_KERNEL, + GET_ENV_INT(HCC_SERIALIZE_KERNEL, "0x1=pre-serialize before each kernel launch, 0x2=post-serialize after each kernel launch, 0x3=both"); GET_ENV_INT(HCC_SERIALIZE_COPY, "0x1=pre-serialize before each data copy, 0x2=post-serialize after each data copy, 0x3=both"); @@ -3139,7 +3159,7 @@ void HSAContext::ReadHccEnv() GET_ENV_INT(HCC_CHECK_COPY, "Check dst == src after each copy operation. Only works on large-bar systems."); - + // Select thresholds to use for unpinned copies GET_ENV_INT (HCC_H2D_STAGING_THRESHOLD, "Min size (in KB) to use staging buffer algorithm for H2D copy if ChooseBest algorithm selected"); GET_ENV_INT (HCC_H2D_PININPLACE_THRESHOLD, "Min size (in KB) to use pin-in-place algorithm for H2D copy if ChooseBest algorithm selected"); @@ -3352,7 +3372,7 @@ HSADevice::HSADevice(hsa_agent_t a, hsa_agent_t host, int x_accSeqNum) : KalmarD throw Kalmar::runtime_exception("HCC_CHECK_COPY can only be used on machines where accelerator memory is visible to CPU (ie large-bar systems)", 0); } - + ctx.agentToDeviceMap_.insert(std::pair (agent.handle, this)); } @@ -3362,7 +3382,7 @@ HSADevice::getHSAAgent() override { return static_cast(&getAgent()); } -static int get_seqnum_from_agent(hsa_agent_t hsaAgent) +static int get_seqnum_from_agent(hsa_agent_t hsaAgent) { auto i = ctx.agentToDeviceMap_.find(hsaAgent.handle); if (i != ctx.agentToDeviceMap_.end()) { @@ -3379,8 +3399,8 @@ static int get_seqnum_from_agent(hsa_agent_t hsaAgent) // ---------------------------------------------------------------------- namespace Kalmar { - -std::ostream& operator<<(std::ostream& os, const HSAQueue & hav) + +std::ostream& operator<<(std::ostream& os, const HSAQueue & hav) { auto device = static_cast(hav.getDev()); os << "queue#" << device->accSeqNum << "." << hav.queueSeqNum; @@ -3393,19 +3413,19 @@ inline void printOp(std::ostream& os, const HSAQueue &hav, uint64_t opNum) os << "op\n" ; } -inline std::ostream& operator<<(std::ostream& os, const HSADispatch & op) +inline std::ostream& operator<<(std::ostream& os, const HSADispatch & op) { //printOp(os, *op.hsaQueue(), op.getSeqNum()); return os; } -HSAQueue::HSAQueue(KalmarDevice* pDev, hsa_agent_t agent, execute_order order) : - KalmarQueue(pDev, queuing_mode_automatic, order), +HSAQueue::HSAQueue(KalmarDevice* pDev, hsa_agent_t agent, execute_order order) : + KalmarQueue(pDev, queuing_mode_automatic, order), rocrQueue(nullptr), - asyncOps(), opSeqNums(0), valid(true), _nextSyncNeedsSysRelease(false), _nextKernelNeedsSysAcquire(false), bufferKernelMap(), kernelBufferMap() + asyncOps(), opSeqNums(0), valid(true), _nextSyncNeedsSysRelease(false), _nextKernelNeedsSysAcquire(false), bufferKernelMap(), kernelBufferMap() { - { + { // Protect the HSA queue we can steal it. DBOUT(DB_LOCK, " ptr:" << this << " create lock_guard...\n"); @@ -3452,7 +3472,7 @@ void HSAQueue::dispose() override { Kalmar::HSADevice* device = static_cast(getDev()); if (this->rocrQueue != nullptr) { - + device->removeRocrQueue(rocrQueue); rocrQueue = nullptr; } @@ -3465,8 +3485,8 @@ void HSAQueue::dispose() override { DBOUT(DB_INIT, "HSAQueue::dispose() out\n"); } -Kalmar::HSADevice * HSAQueue::getHSADev() const { - return static_cast(this->getDev()); +Kalmar::HSADevice * HSAQueue::getHSADev() const { + return static_cast(this->getDev()); }; hsa_queue_t *HSAQueue::acquireLockedRocrQueue() { @@ -3484,7 +3504,7 @@ hsa_queue_t *HSAQueue::acquireLockedRocrQueue() { void HSAQueue::releaseLockedRocrQueue() { - + DBOUT(DB_LOCK, " ptr:" << this << " unlock...\n"); this->qmutex.unlock(); } @@ -3721,8 +3741,8 @@ static std::ostream& operator<<(std::ostream& os, const hsa_kernel_dispatch_pack << " grid=[" << std::dec << aql.grid_size_x << "." << aql.grid_size_y << "." << aql.grid_size_z << "]" << " group=[" << std::dec << aql.workgroup_size_x << "." << aql.workgroup_size_y << "." << aql.workgroup_size_z << "]" << " private_seg_size=" << aql.private_segment_size - << " group_seg_size=" << aql.group_segment_size - << " kernel_object=0x" << std::hex << aql.kernel_object + << " group_seg_size=" << aql.group_segment_size + << " kernel_object=0x" << std::hex << aql.kernel_object << " kernarg_address=0x" << aql.kernarg_address << " completion_signal=0x" << aql.completion_signal.handle << std::dec; @@ -3735,7 +3755,7 @@ static std::string rawAql(const hsa_kernel_dispatch_packet_t &aql) { std::stringstream ss; const unsigned *aqlBytes = (unsigned*)&aql; - ss << " raw_aql=[" << std::hex << std::setfill('0'); + ss << " raw_aql=[" << std::hex << std::setfill('0'); for (int i=0; i (kernarg_address); @@ -3782,8 +3802,8 @@ static void printKernarg(const void *kernarg_address, int bytesToPrint) ks << "kernarg_address: 0x" << kernarg_address << ", first " << bytesToPrint << " bytes:"; for (int i=0; ibase_address))[index & queueMask]); // Copy mostly-finished AQL packet into the queue @@ -3883,7 +3903,7 @@ HSADispatch::dispatchKernel(hsa_queue_t* lockedHsaQueue, const void *hostKernarg DBOUTL(DB_AQL, " dispatch_aql into " << *hsaQueue() << "(" << lockedHsaQueue << ") " << *q_aql ); DBOUTL(DB_AQL2, rawAql(*q_aql)); - if (DBFLAG(DB_KERNARG)) { + if (DBFLAG(DB_KERNARG)) { // TODO, perhaps someday we could determine size of kernarg block here: printKernarg(q_aql->kernarg_address, 128); } @@ -3951,7 +3971,7 @@ HSADispatch::dispatchKernelWaitComplete() { // WaitComplete dispatches need to ensure all data is released to system scope // This ensures the op is trule "complete" before continuing. // This WaitComplete path is used for AMP-style dispatches and may merit future review&optimization. - aql.header = + aql.header = ((HSA_FENCE_SCOPE_SYSTEM) << HSA_PACKET_HEADER_ACQUIRE_FENCE_SCOPE) | ((HSA_FENCE_SCOPE_SYSTEM) << HSA_PACKET_HEADER_RELEASE_FENCE_SCOPE); @@ -4123,8 +4143,8 @@ HSADispatch::setLaunchConfiguration(int dims, size_t *globalDims, size_t *localD size_t max_num_work_items_per_cu = (max_num_vgprs_per_work_item / workitem_vgpr_count) * num_work_items_per_simd * num_simds_per_cu; if (max_num_work_items_per_cu < workgroup_total_size) { std::string msg; - msg = "The number of VGPRs (" + std::to_string(kernel->workitem_vgpr_count) + ") needed by this launch (" + - (kernel->getKernelName()) + ") exceeds HW limit due to big work group size (" + + msg = "The number of VGPRs (" + std::to_string(kernel->workitem_vgpr_count) + ") needed by this launch (" + + (kernel->getKernelName()) + ") exceeds HW limit due to big work group size (" + std::to_string(workgroup_total_size) + ") workitems!"; throw Kalmar::runtime_exception(msg.c_str(), 0); } @@ -4146,7 +4166,7 @@ HSADispatch::setLaunchConfiguration(int dims, size_t *globalDims, size_t *localD aql.header |= ((HSA_FENCE_SCOPE_AGENT) << HSA_PACKET_HEADER_ACQUIRE_FENCE_SCOPE); } aql.header |= ((HSA_FENCE_SCOPE_AGENT) << HSA_PACKET_HEADER_RELEASE_FENCE_SCOPE); - } else { + } else { aql.header = ((HSA_FENCE_SCOPE_SYSTEM) << HSA_PACKET_HEADER_ACQUIRE_FENCE_SCOPE) | ((HSA_FENCE_SCOPE_SYSTEM) << HSA_PACKET_HEADER_RELEASE_FENCE_SCOPE); } @@ -4194,8 +4214,8 @@ HSABarrier::enqueueAsync(hc::memory_scope releaseScope) { // extract hsa_queue_t from HSAQueue // - - if (releaseScope == hc::system_scope) { + + if (releaseScope == hc::system_scope) { hsaQueue()->setNextSyncNeedsSysRelease(false); }; @@ -4410,7 +4430,7 @@ void checkCopy(const void *s1, const void *s2, size_t sizeBytes) // Small wrapper that calls hsa_amd_memory_async_copy. // HCC knows exactly which copy-engine it wants to perfom the copy and has already made. -hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, const Kalmar::HSADevice *copyDeviceArg, +hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, const Kalmar::HSADevice *copyDeviceArg, const hc::AmPointerInfo &dstPtrInfo, const hc::AmPointerInfo &srcPtrInfo, size_t sizeBytes, int depSignalCnt, const hsa_signal_t *depSignals, hsa_signal_t completion_signal) @@ -4437,23 +4457,23 @@ hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, cons hsa_agent_t srcAgent, dstAgent; switch (copyKind) { - case Kalmar::hcMemcpyHostToHost: + case Kalmar::hcMemcpyHostToHost: srcAgent=hostAgent; dstAgent=hostAgent; // Use host pointers since this copy will be performed with CPU. // If pointers are registered, then devicePointer may not match host pointer. dstPtr = dstPtrInfo._hostPointer; srcPtr = srcPtrInfo._hostPointer; - + //throw Kalmar::runtime_exception("HCC should not use hsa_memory_async_copy for host-to-host copy"); break; - case Kalmar::hcMemcpyHostToDevice: + case Kalmar::hcMemcpyHostToDevice: srcAgent=hostAgent; dstAgent=copyAgent; break; - case Kalmar::hcMemcpyDeviceToHost: + case Kalmar::hcMemcpyDeviceToHost: srcAgent=copyAgent; dstAgent=hostAgent; break; - case Kalmar::hcMemcpyDeviceToDevice: + case Kalmar::hcMemcpyDeviceToDevice: this->isPeerToPeer = (dstPtrInfo._acc != srcPtrInfo._acc); srcAgent=copyAgent; dstAgent=copyAgent; break; @@ -4463,24 +4483,24 @@ hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, cons /* ROCR logic to select the copy agent: - * - * Decide which copy agent to use : - * + * + * Decide which copy agent to use : + * * 1. Pick source agent if src agent is a GPU (regardless of the dst agent). - * 2. Pick destination agent if src argent is not a GPU, and the dst agent is a GPU. + * 2. Pick destination agent if src argent is not a GPU, and the dst agent is a GPU. * 3. If both src and dst agents are CPUs, launch a CPU thread to perform memcpy. Will wait on host for dependent signals to resolve. - * + * * Decide which DMA engine on the copy agent to use : - * + * * 1. Use SDMA, if the src agent is a CPU AND dst agent is a GPU. - * 2. Use SDMA, if the src agent is a GPU AND dst agent is a CPU. + * 2. Use SDMA, if the src agent is a GPU AND dst agent is a CPU. * 3. Launch a Blit kernel if the src agent is a GPU AND dst agent is a GPU. */ - DBOUT(DB_AQL, "hsa_amd_memory_async_copy(" + DBOUT(DB_AQL, "hsa_amd_memory_async_copy(" << "dstPtr=" << dstPtr << ",0x" << std::hex << dstAgent.handle << ",srcPtr=" << srcPtr << ",0x" << std::hex << srcAgent.handle - << ",sizeBytes=" << std::dec << sizeBytes + << ",sizeBytes=" << std::dec << sizeBytes << ",depSignalCnt=" << depSignalCnt << "," << depSignals << "," << std::hex << completion_signal.handle << "\n" << std::dec); @@ -4489,7 +4509,7 @@ hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, cons throw Kalmar::runtime_exception("hsa_amd_memory_async_copy error", status); } - + if (HCC_CHECK_COPY) { hsa_signal_wait_acquire(completion_signal, HSA_SIGNAL_CONDITION_EQ, 0, UINT64_MAX, HSA_WAIT_STATE_BLOCKED); @@ -4497,7 +4517,7 @@ hsa_status_t HSACopy::hcc_memory_async_copy(Kalmar::hcCommandKind copyKind, cons } // Next kernel needs to acquire the result of the copy. - // This holds true for any copy direction, since host memory can also be cached on this GPU. + // This holds true for any copy direction, since host memory can also be cached on this GPU. DBOUT( DB_CMD, " H2D copy setNextKernelNeedsSysAcquire(true)\n"); // HSA memory copy requires a system-scope acquire before the next kernel command - set flag here so we remember: hsaQueue()->setNextKernelNeedsSysAcquire(true); @@ -4557,13 +4577,13 @@ HSACopy::enqueueAsyncCopyCommand(const Kalmar::HSADevice *copyDevice, const hc:: // We need to ensure the copy waits for preceding commands the HCC queue to complete, if those commands exist. // The copy has to be set so that it depends on the completion_signal of the youngest command in the queue. - if (depAsyncOp) { + if (depAsyncOp) { depSignal = * (static_cast (depAsyncOp->getNativeHandle())); // Normally we can use the input signal to hsa_amd_memory_async_copy to ensure the copy waits for youngest op. // However, two cases require special handling: // - the youngest op may not have a completion signal - this is optional for kernel launch commands. - // - we may need a system-scope fence. This is true if any kernels have been executed in this queue, or + // - we may need a system-scope fence. This is true if any kernels have been executed in this queue, or // in streams that we depend on. // For both of these cases, we create an additional barrier packet in the source, and attach the desired fence. // Then we make the copy depend on the signal written by this command. @@ -4818,9 +4838,9 @@ HSACopy::syncCopy() { } // Else - dstNotMapped=dstInDeviceMem=false - DBOUTL(DB_COPY, " srcInTracker: " << srcInTracker - << " srcInDeviceMem: " << srcInDeviceMem - << " dstInTracker: " << dstInTracker + DBOUTL(DB_COPY, " srcInTracker: " << srcInTracker + << " srcInDeviceMem: " << srcInDeviceMem + << " dstInTracker: " << dstInTracker << " dstInDeviceMem: " << dstInDeviceMem); // Resolve default to a specific Kind so we know which algorithm to use: diff --git a/lib/mcwamp.cpp b/lib/mcwamp.cpp index 923234cc14c..c8439624bd7 100644 --- a/lib/mcwamp.cpp +++ b/lib/mcwamp.cpp @@ -4,23 +4,20 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#include "mcwamp_impl.hpp" + #include "hc_rt_debug.h" +#include "mcwamp_impl.hpp" -#include "../hc2/external/elfio/elfio.hpp" +#include +#include +#include +#include +#include #include +#include #include -#include - -#include -#include -#include -#include -#include -#include -#include namespace Concurrency { @@ -271,24 +268,18 @@ static inline uint64_t Read8byteIntegerFromBuffer(const char *data, size_t pos) #define HCC_TRIPLE_PREFIX "hcc-amdgcn--amdhsa-" #define HCC_TRIPLE_PREFIX_LENGTH (19) -inline -void DetermineAndGetProgram( - const void* kernel_bundle_f, - const void* kernel_bundle_l, - KalmarQueue* pQueue, - size_t* kernel_size, - void** kernel_source) -{ +inline void DetermineAndGetProgram(KalmarQueue* pQueue, size_t* kernel_size, void** kernel_source) { + bool FoundCompatibleKernel = false; // walk through bundle header // get bundle file size - size_t bundle_size = - static_cast(kernel_bundle_l) - - static_cast(kernel_bundle_f); + size_t bundle_size = + (std::ptrdiff_t)((void *)kernel_bundle_end) - + (std::ptrdiff_t)((void *)kernel_bundle_source); // point to bundle file data - const char *data = static_cast(kernel_bundle_f); + const char *data = (const char *)kernel_bundle_source; // skip OFFLOAD_BUNDLER_MAGIC_STR size_t pos = 0; @@ -296,9 +287,8 @@ void DetermineAndGetProgram( RUNTIME_ERROR(1, "Bundle size too small", __LINE__) } std::string MagicStr(data + pos, OFFLOAD_BUNDLER_MAGIC_STR_LENGTH); - //std::cerr << MagicStr << std::endl; if (MagicStr.compare(OFFLOAD_BUNDLER_MAGIC_STR) != 0) { - return; //RUNTIME_ERROR(1, "Incorrect magic string", __LINE__) + RUNTIME_ERROR(1, "Incorrect magic string", __LINE__) } pos += OFFLOAD_BUNDLER_MAGIC_STR_LENGTH; @@ -356,63 +346,13 @@ void DetermineAndGetProgram( RUNTIME_ERROR(1, "Fail to find compatible kernel", __LINE__) } } - -namespace -{ - template>> - int copy_kernel_sections(dl_phdr_info* x, size_t, void* kernels) - { - static constexpr const char kernel[] = ".kernel"; - - auto out = static_cast(kernels); - - ELFIO::elfio tmp; - if (tmp.load(x->dlpi_name)) { - for (auto&& y : tmp.sections) { - if (y->get_name() == kernel) { - out->emplace_back( - y->get_data(), y->get_data() + y->get_size()); - } - } - } - - return 0; - } - - static - const std::vector>& shared_object_kernel_sections() - { - static std::vector> r; - - static std::once_flag f; - std::call_once(f, []() { dl_iterate_phdr(copy_kernel_sections, &r); }); - return r; - } -} void BuildProgram(KalmarQueue* pQueue) { - std::vector> bundles{ - {reinterpret_cast(&kernel_bundle_source), - reinterpret_cast(&kernel_bundle_end)}}; - bundles.insert( - bundles.end(), - shared_object_kernel_sections().cbegin(), - shared_object_kernel_sections().cend()); - - for (auto&& x : bundles) { - size_t kernel_size = 0; - void* kernel_source = nullptr; - - DetermineAndGetProgram( - x.data(), - x.data() + x.size(), - pQueue, - &kernel_size, - &kernel_source); - if (kernel_source) { - pQueue->getDev()->BuildProgram((void*)kernel_size, kernel_source); - } - } + size_t kernel_size = 0; + void* kernel_source = nullptr; + + DetermineAndGetProgram(pQueue, &kernel_size, &kernel_source); + pQueue->getDev()->BuildProgram((void*)kernel_size, kernel_source); } // used in parallel_for_each.h @@ -454,14 +394,14 @@ class KalmarBootstrap { // get context KalmarContext* context = static_cast(runtime->m_GetContextImpl()); - + const std::vector devices = context->getDevices(); for (auto dev = devices.begin(); dev != devices.end(); dev++) { // get default queue on the default device std::shared_ptr queue = (*dev)->get_default_queue(); - + // build kernels on the default queue on the default device CLAMP::BuildProgram(queue.get()); } From f7a4301d5299aa5b1143b7c06fc443b250a02b04 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Thu, 14 Sep 2017 20:33:01 +0100 Subject: [PATCH 3/4] Adopt interface chance in HSAKernel. Note that nullptr is passed as the owning HSAExecutable for the shared-object case - if at some point HSAKernel will start using its _executable member this will create issues. --- hc2/headers/functions/integer_computational_basis.hpp | 11 +++++++++++ lib/hsa/mcwamp_hsa.cpp | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hc2/headers/functions/integer_computational_basis.hpp b/hc2/headers/functions/integer_computational_basis.hpp index 3fa8616cba1..f23a74a2af5 100644 --- a/hc2/headers/functions/integer_computational_basis.hpp +++ b/hc2/headers/functions/integer_computational_basis.hpp @@ -19,4 +19,15 @@ namespace hc2 { return x > T{0}; } + + template< + typename T, + typename std::enable_if{}>::type* = nullptr> + inline + constexpr + bool zero(T x) + { + return x == T{0}; + } + } \ No newline at end of file diff --git a/lib/hsa/mcwamp_hsa.cpp b/lib/hsa/mcwamp_hsa.cpp index 3858634fcfe..865aa8c1d79 100644 --- a/lib/hsa/mcwamp_hsa.cpp +++ b/lib/hsa/mcwamp_hsa.cpp @@ -2518,7 +2518,8 @@ class HSADevice final : public KalmarDevice if (hsa_executable_symbol_get_info( *k, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &h) == HSA_STATUS_SUCCESS) { - kernel = new HSAKernel(str, shortName, *k, h); + + kernel = new HSAKernel(str, shortName, nullptr, *k, h); } } } From e695e33e8709489e9c1f3331e39c53e0b587ba80 Mon Sep 17 00:00:00 2001 From: Alex Voicu Date: Wed, 20 Sep 2017 18:07:51 +0100 Subject: [PATCH 4/4] Mark global scope inline functions as static. Take arguments by value, and not by reference, since they are essentially a single std::uint64_t wrapped in a struct. --- hc2/headers/functions/hsa_interfaces.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hc2/headers/functions/hsa_interfaces.hpp b/hc2/headers/functions/hsa_interfaces.hpp index bcc4b71081e..9eef5f6ee91 100644 --- a/hc2/headers/functions/hsa_interfaces.hpp +++ b/hc2/headers/functions/hsa_interfaces.hpp @@ -18,21 +18,23 @@ #include #include +static inline -bool operator==(const hsa_agent_t& x, const hsa_agent_t& y) +bool operator==(hsa_agent_t x, hsa_agent_t y) { return x.handle == y.handle; } +static inline -bool operator==(const hsa_isa_t& x, const hsa_isa_t& y) +bool operator==(hsa_isa_t x, hsa_isa_t y) { return x.handle == y.handle; } +static inline -bool operator==( - const hsa_executable_symbol_t& x, const hsa_executable_symbol_t& y) +bool operator==(hsa_executable_symbol_t x, hsa_executable_symbol_t y) { return x.handle == y.handle; }