diff --git a/CMakeLists.txt b/CMakeLists.txt index eac0f7f..d732f0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,8 @@ add_library(elna source/lexer.cpp include/elna/lexer.hpp source/result.cpp include/elna/result.hpp source/riscv.cpp include/elna/riscv.hpp + source/parser.cpp include/elna/parser.hpp source/ir.cpp include/elna/ir.hpp - include/elna/parser.hpp + source/cl.cpp include/elna/cl.hpp ) target_include_directories(elna PRIVATE include) diff --git a/include/elfio/elf_types.hpp b/include/elfio/elf_types.hpp new file mode 100644 index 0000000..c4f6b47 --- /dev/null +++ b/include/elfio/elf_types.hpp @@ -0,0 +1,1347 @@ +/* +Copyright (C) 2001-present 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 + +#ifdef __cplusplus +namespace ELFIO { +#endif + +using Elf_Half = uint16_t; +using Elf_Word = uint32_t; +using Elf_Sword = int32_t; +using Elf_Xword = uint64_t; +using Elf_Sxword = int64_t; + +using Elf32_Addr = uint32_t; +using Elf32_Off = uint32_t; +using Elf64_Addr = uint64_t; +using Elf64_Off = uint64_t; + +using Elf32_Half = Elf_Half; +using Elf64_Half = Elf_Half; +using Elf32_Word = Elf_Word; +using Elf64_Word = Elf_Word; +using Elf32_Sword = Elf_Sword; +using Elf64_Sword = Elf_Sword; + +/////////////////////// +// ELF Header Constants + +// File type +constexpr Elf_Half ET_NONE = 0; +constexpr Elf_Half ET_REL = 1; +constexpr Elf_Half ET_EXEC = 2; +constexpr Elf_Half ET_DYN = 3; +constexpr Elf_Half ET_CORE = 4; +constexpr Elf_Half ET_LOOS = 0xFE00; +constexpr Elf_Half ET_HIOS = 0xFEFF; +constexpr Elf_Half ET_LOPROC = 0xFF00; +constexpr Elf_Half ET_HIPROC = 0xFFFF; + +// clang-format off +// Machine number +constexpr Elf_Half EM_NONE = 0 ; // No machine +constexpr Elf_Half EM_M32 = 1 ; // AT&T WE 32100 +constexpr Elf_Half EM_SPARC = 2 ; // SUN SPARC +constexpr Elf_Half EM_386 = 3 ; // Intel 80386 +constexpr Elf_Half EM_68K = 4 ; // Motorola m68k family +constexpr Elf_Half EM_88K = 5 ; // Motorola m88k family +constexpr Elf_Half EM_486 = 6 ; // Intel 80486// Reserved for future use +constexpr Elf_Half EM_860 = 7 ; // Intel 80860 +constexpr Elf_Half EM_MIPS = 8 ; // MIPS R3000 (officially, big-endian only) +constexpr Elf_Half EM_S370 = 9 ; // IBM System/370 +constexpr Elf_Half EM_MIPS_RS3_LE = 10; // MIPS R3000 little-endian (Deprecated) +constexpr Elf_Half EM_res011 = 11; // Reserved +constexpr Elf_Half EM_res012 = 12; // Reserved +constexpr Elf_Half EM_res013 = 13; // Reserved +constexpr Elf_Half EM_res014 = 14; // Reserved +constexpr Elf_Half EM_PARISC = 15; // HPPA +constexpr Elf_Half EM_res016 = 16; // Reserved +constexpr Elf_Half EM_VPP550 = 17; // Fujitsu VPP500 +constexpr Elf_Half EM_SPARC32PLUS = 18; // Sun's "v8plus" +constexpr Elf_Half EM_960 = 19; // Intel 80960 +constexpr Elf_Half EM_PPC = 20; // PowerPC +constexpr Elf_Half EM_PPC64 = 21; // 64-bit PowerPC +constexpr Elf_Half EM_S390 = 22; // IBM S/390 +constexpr Elf_Half EM_SPU = 23; // Sony/Toshiba/IBM SPU +constexpr Elf_Half EM_res024 = 24; // Reserved +constexpr Elf_Half EM_res025 = 25; // Reserved +constexpr Elf_Half EM_res026 = 26; // Reserved +constexpr Elf_Half EM_res027 = 27; // Reserved +constexpr Elf_Half EM_res028 = 28; // Reserved +constexpr Elf_Half EM_res029 = 29; // Reserved +constexpr Elf_Half EM_res030 = 30; // Reserved +constexpr Elf_Half EM_res031 = 31; // Reserved +constexpr Elf_Half EM_res032 = 32; // Reserved +constexpr Elf_Half EM_res033 = 33; // Reserved +constexpr Elf_Half EM_res034 = 34; // Reserved +constexpr Elf_Half EM_res035 = 35; // Reserved +constexpr Elf_Half EM_V800 = 36; // NEC V800 series +constexpr Elf_Half EM_FR20 = 37; // Fujitsu FR20 +constexpr Elf_Half EM_RH32 = 38; // TRW RH32 +constexpr Elf_Half EM_MCORE = 39; // Motorola M*Core // May also be taken by Fujitsu MMA +constexpr Elf_Half EM_RCE = 39; // Old name for MCore +constexpr Elf_Half EM_ARM = 40; // ARM +constexpr Elf_Half EM_OLD_ALPHA = 41; // Digital Alpha +constexpr Elf_Half EM_SH = 42; // Renesas (formerly Hitachi) / SuperH SH +constexpr Elf_Half EM_SPARCV9 = 43; // SPARC v9 64-bit +constexpr Elf_Half EM_TRICORE = 44; // Siemens Tricore embedded processor +constexpr Elf_Half EM_ARC = 45; // ARC Cores +constexpr Elf_Half EM_H8_300 = 46; // Renesas (formerly Hitachi) H8/300 +constexpr Elf_Half EM_H8_300H = 47; // Renesas (formerly Hitachi) H8/300H +constexpr Elf_Half EM_H8S = 48; // Renesas (formerly Hitachi) H8S +constexpr Elf_Half EM_H8_500 = 49; // Renesas (formerly Hitachi) H8/500 +constexpr Elf_Half EM_IA_64 = 50; // Intel IA-64 Processor +constexpr Elf_Half EM_MIPS_X = 51; // Stanford MIPS-X +constexpr Elf_Half EM_COLDFIRE = 52; // Motorola Coldfire +constexpr Elf_Half EM_68HC12 = 53; // Motorola M68HC12 +constexpr Elf_Half EM_MMA = 54; // Fujitsu Multimedia Accelerator +constexpr Elf_Half EM_PCP = 55; // Siemens PCP +constexpr Elf_Half EM_NCPU = 56; // Sony nCPU embedded RISC processor +constexpr Elf_Half EM_NDR1 = 57; // Denso NDR1 microprocesspr +constexpr Elf_Half EM_STARCORE = 58; // Motorola Star*Core processor +constexpr Elf_Half EM_ME16 = 59; // Toyota ME16 processor +constexpr Elf_Half EM_ST100 = 60; // STMicroelectronics ST100 processor +constexpr Elf_Half EM_TINYJ = 61; // Advanced Logic Corp. TinyJ embedded processor +constexpr Elf_Half EM_X86_64 = 62; // Advanced Micro Devices X86-64 processor +constexpr Elf_Half EM_PDSP = 63; // Sony DSP Processor +constexpr Elf_Half EM_PDP10 = 64; // Digital Equipment Corp. PDP-10 +constexpr Elf_Half EM_PDP11 = 65; // Digital Equipment Corp. PDP-11 +constexpr Elf_Half EM_FX66 = 66; // Siemens FX66 microcontroller +constexpr Elf_Half EM_ST9PLUS = 67; // STMicroelectronics ST9+ 8/16 bit microcontroller +constexpr Elf_Half EM_ST7 = 68 ; // STMicroelectronics ST7 8-bit microcontroller +constexpr Elf_Half EM_68HC16 = 69 ; // Motorola MC68HC16 Microcontroller +constexpr Elf_Half EM_68HC11 = 70 ; // Motorola MC68HC11 Microcontroller +constexpr Elf_Half EM_68HC08 = 71 ; // Motorola MC68HC08 Microcontroller +constexpr Elf_Half EM_68HC05 = 72 ; // Motorola MC68HC05 Microcontroller +constexpr Elf_Half EM_SVX = 73 ; // Silicon Graphics SVx +constexpr Elf_Half EM_ST19 = 74 ; // STMicroelectronics ST19 8-bit cpu +constexpr Elf_Half EM_VAX = 75 ; // Digital VAX +constexpr Elf_Half EM_CRIS = 76 ; // Axis Communications 32-bit embedded processor +constexpr Elf_Half EM_JAVELIN = 77 ; // Infineon Technologies 32-bit embedded cpu +constexpr Elf_Half EM_FIREPATH = 78 ; // Element 14 64-bit DSP processor +constexpr Elf_Half EM_ZSP = 79 ; // LSI Logic's 16-bit DSP processor +constexpr Elf_Half EM_MMIX = 80 ; // Donald Knuth's educational 64-bit processor +constexpr Elf_Half EM_HUANY = 81 ; // Harvard's machine-independent format +constexpr Elf_Half EM_PRISM = 82 ; // SiTera Prism +constexpr Elf_Half EM_AVR = 83 ; // Atmel AVR 8-bit microcontroller +constexpr Elf_Half EM_FR30 = 84 ; // Fujitsu FR30 +constexpr Elf_Half EM_D10V = 85 ; // Mitsubishi D10V +constexpr Elf_Half EM_D30V = 86 ; // Mitsubishi D30V +constexpr Elf_Half EM_V850 = 87 ; // NEC v850 +constexpr Elf_Half EM_M32R = 88 ; // Renesas M32R (formerly Mitsubishi M32R) +constexpr Elf_Half EM_MN10300 = 89 ; // Matsushita MN10300 +constexpr Elf_Half EM_MN10200 = 90 ; // Matsushita MN10200 +constexpr Elf_Half EM_PJ = 91 ; // picoJava +constexpr Elf_Half EM_OPENRISC = 92 ; // OpenRISC 32-bit embedded processor +constexpr Elf_Half EM_ARC_A5 = 93 ; // ARC Cores Tangent-A5 +constexpr Elf_Half EM_XTENSA = 94 ; // Tensilica Xtensa Architecture +constexpr Elf_Half EM_VIDEOCORE = 95 ; // Alphamosaic VideoCore processor +constexpr Elf_Half EM_TMM_GPP = 96 ; // Thompson Multimedia General Purpose Processor +constexpr Elf_Half EM_NS32K = 97 ; // National Semiconductor 32000 series +constexpr Elf_Half EM_TPC = 98 ; // Tenor Network TPC processor +constexpr Elf_Half EM_SNP1K = 99 ; // Trebia SNP 1000 processor +constexpr Elf_Half EM_ST200 = 100; // STMicroelectronics ST200 microcontroller +constexpr Elf_Half EM_IP2K = 101; // Ubicom IP2022 micro controller +constexpr Elf_Half EM_MAX = 102; // MAX Processor +constexpr Elf_Half EM_CR = 103; // National Semiconductor CompactRISC +constexpr Elf_Half EM_F2MC16 = 104; // Fujitsu F2MC16 +constexpr Elf_Half EM_MSP430 = 105; // TI msp430 micro controller +constexpr Elf_Half EM_BLACKFIN = 106; // ADI Blackfin +constexpr Elf_Half EM_SE_C33 = 107; // S1C33 Family of Seiko Epson processors +constexpr Elf_Half EM_SEP = 108; // Sharp embedded microprocessor +constexpr Elf_Half EM_ARCA = 109; // Arca RISC Microprocessor +constexpr Elf_Half EM_UNICORE = 110; // Microprocessor series from PKU-Unity Ltd. +constexpr Elf_Half EM_EXCESS = 111; // eXcess: 16/32/64-bit configurable embedded CPU +constexpr Elf_Half EM_DXP = 112; // Icera Semiconductor Inc. Deep Execution Processor +constexpr Elf_Half EM_ALTERA_NIOS2 = 113; // Altera Nios II soft-core processor +constexpr Elf_Half EM_CRX = 114; // National Semiconductor CRX +constexpr Elf_Half EM_XGATE = 115; // Motorola XGATE embedded processor +constexpr Elf_Half EM_C166 = 116; // Infineon C16x/XC16x processor +constexpr Elf_Half EM_M16C = 117; // Renesas M16C series microprocessors +constexpr Elf_Half EM_DSPIC30F = 118; // Microchip Technology dsPIC30F DSignal Controller +constexpr Elf_Half EM_CE = 119; // Freescale Communication Engine RISC core +constexpr Elf_Half EM_M32C = 120; // Renesas M32C series microprocessors +constexpr Elf_Half EM_res121 = 121; // Reserved +constexpr Elf_Half EM_res122 = 122; // Reserved +constexpr Elf_Half EM_res123 = 123; // Reserved +constexpr Elf_Half EM_res124 = 124; // Reserved +constexpr Elf_Half EM_res125 = 125; // Reserved +constexpr Elf_Half EM_res126 = 126; // Reserved +constexpr Elf_Half EM_res127 = 127; // Reserved +constexpr Elf_Half EM_res128 = 128; // Reserved +constexpr Elf_Half EM_res129 = 129; // Reserved +constexpr Elf_Half EM_res130 = 130; // Reserved +constexpr Elf_Half EM_TSK3000 = 131; // Altium TSK3000 core +constexpr Elf_Half EM_RS08 = 132; // Freescale RS08 embedded processor +constexpr Elf_Half EM_res133 = 133; // Reserved +constexpr Elf_Half EM_ECOG2 = 134; // Cyan Technology eCOG2 microprocessor +constexpr Elf_Half EM_SCORE = 135; // Sunplus Score +constexpr Elf_Half EM_SCORE7 = 135; // Sunplus S+core7 RISC processor +constexpr Elf_Half EM_DSP24 = 136; // New Japan Radio (NJR) 24-bit DSP Processor +constexpr Elf_Half EM_VIDEOCORE3 = 137; // Broadcom VideoCore III processor +constexpr Elf_Half EM_LATTICEMICO32 = 138; // RISC processor for Lattice FPGA architecture +constexpr Elf_Half EM_SE_C17 = 139; // Seiko Epson C17 family +constexpr Elf_Half EM_TI_C6000 = 140; // Texas Instruments TMS320C6000 DSP family +constexpr Elf_Half EM_TI_C2000 = 141; // Texas Instruments TMS320C2000 DSP family +constexpr Elf_Half EM_TI_C5500 = 142; // Texas Instruments TMS320C55x DSP family +constexpr Elf_Half EM_res143 = 143; // Reserved +constexpr Elf_Half EM_res144 = 144; // Reserved +constexpr Elf_Half EM_res145 = 145; // Reserved +constexpr Elf_Half EM_res146 = 146; // Reserved +constexpr Elf_Half EM_res147 = 147; // Reserved +constexpr Elf_Half EM_res148 = 148; // Reserved +constexpr Elf_Half EM_res149 = 149; // Reserved +constexpr Elf_Half EM_res150 = 150; // Reserved +constexpr Elf_Half EM_res151 = 151; // Reserved +constexpr Elf_Half EM_res152 = 152; // Reserved +constexpr Elf_Half EM_res153 = 153; // Reserved +constexpr Elf_Half EM_res154 = 154; // Reserved +constexpr Elf_Half EM_res155 = 155; // Reserved +constexpr Elf_Half EM_res156 = 156; // Reserved +constexpr Elf_Half EM_res157 = 157; // Reserved +constexpr Elf_Half EM_res158 = 158; // Reserved +constexpr Elf_Half EM_res159 = 159; // Reserved +constexpr Elf_Half EM_MMDSP_PLUS = 160; // STMicroelectronics 64bit VLIW Data Signal Processor +constexpr Elf_Half EM_CYPRESS_M8C = 161; // Cypress M8C microprocessor +constexpr Elf_Half EM_R32C = 162; // Renesas R32C series microprocessors +constexpr Elf_Half EM_TRIMEDIA = 163; // NXP Semiconductors TriMedia architecture family +constexpr Elf_Half EM_QDSP6 = 164; // QUALCOMM DSP6 Processor +constexpr Elf_Half EM_8051 = 165; // Intel 8051 and variants +constexpr Elf_Half EM_STXP7X = 166; // STMicroelectronics STxP7x family +constexpr Elf_Half EM_NDS32 = 167; // Andes Technology embedded RISC processor family +constexpr Elf_Half EM_ECOG1 = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_ECOG1X = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_MAXQ30 = 169; // Dallas Semiconductor MAXQ30 Core Micro-controllers +constexpr Elf_Half EM_XIMO16 = 170; // New Japan Radio (NJR) 16-bit DSP Processor +constexpr Elf_Half EM_MANIK = 171; // M2000 Reconfigurable RISC Microprocessor +constexpr Elf_Half EM_CRAYNV2 = 172; // Cray Inc. NV2 vector architecture +constexpr Elf_Half EM_RX = 173; // Renesas RX family +constexpr Elf_Half EM_METAG = 174; // Imagination Technologies META processor architecture +constexpr Elf_Half EM_MCST_ELBRUS = 175; // MCST Elbrus general purpose hardware architecture +constexpr Elf_Half EM_ECOG16 = 176; // Cyan Technology eCOG16 family +constexpr Elf_Half EM_CR16 = 177; // National Semiconductor CompactRISC 16-bit processor +constexpr Elf_Half EM_ETPU = 178; // Freescale Extended Time Processing Unit +constexpr Elf_Half EM_SLE9X = 179; // Infineon Technologies SLE9X core +constexpr Elf_Half EM_L1OM = 180; // Intel L1OM +constexpr Elf_Half EM_INTEL181 = 181; // Reserved by Intel +constexpr Elf_Half EM_INTEL182 = 182; // Reserved by Intel +constexpr Elf_Half EM_AARCH64 = 183; // ARM AArch64 +constexpr Elf_Half EM_res184 = 184; // Reserved by ARM +constexpr Elf_Half EM_AVR32 = 185; // Atmel Corporation 32-bit microprocessor family +constexpr Elf_Half EM_STM8 = 186; // STMicroeletronics STM8 8-bit microcontroller +constexpr Elf_Half EM_TILE64 = 187; // Tilera TILE64 multicore architecture family +constexpr Elf_Half EM_TILEPRO = 188; // Tilera TILEPro multicore architecture family +constexpr Elf_Half EM_MICROBLAZE = 189; // Xilinx MicroBlaze 32-bit RISC soft processor core +constexpr Elf_Half EM_CUDA = 190; // NVIDIA CUDA architecture +constexpr Elf_Half EM_TILEGX = 191; // Tilera TILE-Gx multicore architecture family +constexpr Elf_Half EM_CLOUDSHIELD = 192; // CloudShield architecture family +constexpr Elf_Half EM_COREA_1ST = 193; // KIPO-KAIST Core-A 1st generation processor family +constexpr Elf_Half EM_COREA_2ND = 194; // KIPO-KAIST Core-A 2nd generation processor family +constexpr Elf_Half EM_ARC_COMPACT2 = 195; // Synopsys ARCompact V2 +constexpr Elf_Half EM_OPEN8 = 196; // Open8 8-bit RISC soft processor core +constexpr Elf_Half EM_RL78 = 197; // Renesas RL78 family +constexpr Elf_Half EM_VIDEOCORE5 = 198; // Broadcom VideoCore V processor +constexpr Elf_Half EM_78KOR = 199; // Renesas 78KOR family +constexpr Elf_Half EM_56800EX = 200; // Freescale 56800EX Digital Signal Controller (DSC) +constexpr Elf_Half EM_BA1 = 201; // Beyond BA1 CPU architecture +constexpr Elf_Half EM_BA2 = 202; // Beyond BA2 CPU architecture +constexpr Elf_Half EM_XCORE = 203; // XMOS xCORE processor family +constexpr Elf_Half EM_MCHP_PIC = 204; // Microchip 8-bit PIC(r) family +constexpr Elf_Half EM_INTEL205 = 205; // Reserved by Intel +constexpr Elf_Half EM_INTEL206 = 206; // Reserved by Intel +constexpr Elf_Half EM_INTEL207 = 207; // Reserved by Intel +constexpr Elf_Half EM_INTEL208 = 208; // Reserved by Intel +constexpr Elf_Half EM_INTEL209 = 209; // Reserved by Intel +constexpr Elf_Half EM_KM32 = 210; // KM211 KM32 32-bit processor +constexpr Elf_Half EM_KMX32 = 211; // KM211 KMX32 32-bit processor +constexpr Elf_Half EM_KMX16 = 212; // KM211 KMX16 16-bit processor +constexpr Elf_Half EM_KMX8 = 213; // KM211 KMX8 8-bit processor +constexpr Elf_Half EM_KVARC = 214; // KM211 KVARC processor +constexpr Elf_Half EM_CDP = 215; // Paneve CDP architecture family +constexpr Elf_Half EM_COGE = 216; // Cognitive Smart Memory Processor +constexpr Elf_Half EM_COOL = 217; // iCelero CoolEngine +constexpr Elf_Half EM_NORC = 218; // Nanoradio Optimized RISC +constexpr Elf_Half EM_CSR_KALIMBA = 219; // CSR Kalimba architecture family +constexpr Elf_Half EM_Z80 = 220; // Zilog Z80 +constexpr Elf_Half EM_VISIUM = 221; // Controls and Data Services VISIUMcore processor +constexpr Elf_Half EM_FT32 = 222; // FTDI Chip FT32 high performance 32-bit RISC architecture +constexpr Elf_Half EM_MOXIE = 223; // Moxie processor family +constexpr Elf_Half EM_AMDGPU = 224; // AMD GPU architecture +constexpr Elf_Half EM_RISCV = 243; // RISC-V +constexpr Elf_Half EM_LANAI = 244; // Lanai processor +constexpr Elf_Half EM_CEVA = 245; // CEVA Processor Architecture Family +constexpr Elf_Half EM_CEVA_X2 = 246; // CEVA X2 Processor Family +constexpr Elf_Half EM_BPF = 247; // Linux BPF – in-kernel virtual machine +constexpr Elf_Half EM_GRAPHCORE_IPU = 248; // Graphcore Intelligent Processing Unit +constexpr Elf_Half EM_IMG1 = 249; // Imagination Technologies +constexpr Elf_Half EM_NFP = 250; // Netronome Flow Processor (P) +constexpr Elf_Half EM_CSKY = 252; // C-SKY processor family +constexpr Elf_Half EM_ARC_COMPACT3_64 = 253; // Synopsys ARCv2.3 64-bit +constexpr Elf_Half EM_MCS6502 = 254; // MOS Technology MCS 6502 processor +constexpr Elf_Half EM_ARC_COMPACT3 = 255; // Synopsys ARCv2.3 32-bit +constexpr Elf_Half EM_KVX = 256; // Kalray VLIW core of the MPPA processor family +constexpr Elf_Half EM_65816 = 257; // WDC 65816/65C816 +constexpr Elf_Half EM_LOONGARCH = 258; // Loongson Loongarch +constexpr Elf_Half EM_KF32 = 259; // ChipON KungFu32 + +constexpr Elf_Half EM_MT = 0x2530; // Morpho Techologies MT processor +constexpr Elf_Half EM_ALPHA = 0x9026; // Alpha +constexpr Elf_Half EM_WEBASSEMBLY = 0x4157; // Web Assembly +constexpr Elf_Half EM_DLX = 0x5aa5; // OpenDLX +constexpr Elf_Half EM_XSTORMY16 = 0xad45; // Sanyo XStormy16 CPU core +constexpr Elf_Half EM_IQ2000 = 0xFEBA; // Vitesse IQ2000 +constexpr Elf_Half EM_M32C_OLD = 0xFEB; +constexpr Elf_Half EM_NIOS32 = 0xFEBB; // Altera Nios +constexpr Elf_Half EM_CYGNUS_MEP = 0xF00D; // Toshiba MeP Media Engine +constexpr Elf_Half EM_ADAPTEVA_EPIPHANY = 0x1223; // Adapteva EPIPHANY +constexpr Elf_Half EM_CYGNUS_FRV = 0x5441; // Fujitsu FR-V +constexpr Elf_Half EM_S12Z = 0x4DEF; // Freescale S12Z +// clang-format on + +// File version +constexpr unsigned char EV_NONE = 0; +constexpr unsigned char EV_CURRENT = 1; + +// Identification index +constexpr unsigned char EI_MAG0 = 0; +constexpr unsigned char EI_MAG1 = 1; +constexpr unsigned char EI_MAG2 = 2; +constexpr unsigned char EI_MAG3 = 3; +constexpr unsigned char EI_CLASS = 4; +constexpr unsigned char EI_DATA = 5; +constexpr unsigned char EI_VERSION = 6; +constexpr unsigned char EI_OSABI = 7; +constexpr unsigned char EI_ABIVERSION = 8; +constexpr unsigned char EI_PAD = 9; +constexpr unsigned char EI_NIDENT = 16; + +// Magic number +constexpr unsigned char ELFMAG0 = 0x7F; +constexpr unsigned char ELFMAG1 = 'E'; +constexpr unsigned char ELFMAG2 = 'L'; +constexpr unsigned char ELFMAG3 = 'F'; + +// File class +constexpr unsigned char ELFCLASSNONE = 0; +constexpr unsigned char ELFCLASS32 = 1; +constexpr unsigned char ELFCLASS64 = 2; + +// Encoding +constexpr unsigned char ELFDATANONE = 0; +constexpr unsigned char ELFDATA2LSB = 1; +constexpr unsigned char ELFDATA2MSB = 2; + +// clang-format off +// OS extensions +constexpr unsigned char ELFOSABI_NONE = 0; // No extensions or unspecified +constexpr unsigned char ELFOSABI_HPUX = 1; // Hewlett-Packard HP-UX +constexpr unsigned char ELFOSABI_NETBSD = 2; // NetBSD +constexpr unsigned char ELFOSABI_LINUX = 3; // Linux +constexpr unsigned char ELFOSABI_HURD = 4; // GNU Hurd +constexpr unsigned char ELFOSABI_SOLARIS = 6; // Sun Solaris +constexpr unsigned char ELFOSABI_AIX = 7; // AIX +constexpr unsigned char ELFOSABI_IRIX = 8; // IRIX +constexpr unsigned char ELFOSABI_FREEBSD = 9; // FreeBSD +constexpr unsigned char ELFOSABI_TRU64 = 10; // Compaq TRU64 UNIX +constexpr unsigned char ELFOSABI_MODESTO = 11; // Novell Modesto +constexpr unsigned char ELFOSABI_OPENBSD = 12; // Open BSD +constexpr unsigned char ELFOSABI_OPENVMS = 13; // Open VMS +constexpr unsigned char ELFOSABI_NSK = 14; // Hewlett-Packard Non-Stop Kernel +constexpr unsigned char ELFOSABI_AROS = 15; // Amiga Research OS +constexpr unsigned char ELFOSABI_FENIXOS = 16; // The FenixOS highly scalable multi-core OS +constexpr unsigned char ELFOSABI_NUXI = 17; // Nuxi CloudABI +constexpr unsigned char ELFOSABI_OPENVOS = 18; // Stratus Technologies OpenVOS +constexpr unsigned char ELFOSABI_ARM = 97; // ARM +constexpr unsigned char ELFOSABI_STANDALONE = 255; // Standalone (embedded) application + +// 64-255 Architecture-specific value range +// AMDGPU OS for HSA compatible compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_HSA = 64; +// AMDGPU OS for AMD PAL compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_PAL = 65; +// AMDGPU OS for Mesa3D compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_MESA3D = 66; +// clang-format on + +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V2 = 0; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V3 = 1; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V4 = 2; + +// AMDGPU specific e_flags +constexpr Elf_Word EF_AMDGPU_MACH = 0x0ff; // AMDGPU processor selection mask. +// Indicates if the XNACK target feature is +// enabled for all code contained in the ELF. +constexpr Elf_Word EF_AMDGPU_XNACK = 0x100; + +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V2 = 0x01; +constexpr Elf_Word EF_AMDGPU_FEATURE_TRAP_HANDLER_V2 = 0x02; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V3 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V3 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ANY_V4 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_OFF_V4 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ON_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V4 = 0xc00; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 = 0x400; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 = 0x800; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ON_V4 = 0xc00; + +// AMDGPU processors +constexpr Elf_Word EF_AMDGPU_MACH_NONE = 0x000; // Unspecified processor. +constexpr Elf_Word EF_AMDGPU_MACH_R600_R600 = 0x001; +constexpr Elf_Word EF_AMDGPU_MACH_R600_R630 = 0x002; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RS880 = 0x003; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV670 = 0x004; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV710 = 0x005; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV730 = 0x006; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV770 = 0x007; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CEDAR = 0x008; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CYPRESS = 0x009; +constexpr Elf_Word EF_AMDGPU_MACH_R600_JUNIPER = 0x00a; +constexpr Elf_Word EF_AMDGPU_MACH_R600_REDWOOD = 0x00b; +constexpr Elf_Word EF_AMDGPU_MACH_R600_SUMO = 0x00c; +constexpr Elf_Word EF_AMDGPU_MACH_R600_BARTS = 0x00d; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAICOS = 0x00e; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAYMAN = 0x00f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_TURKS = 0x010; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_FIRST = 0x011; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_LAST = 0x01f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_FIRST = EF_AMDGPU_MACH_R600_R600; +constexpr Elf_Word EF_AMDGPU_MACH_R600_LAST = EF_AMDGPU_MACH_R600_TURKS; + +// AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX600 = 0x020; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX601 = 0x021; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX700 = 0x022; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX701 = 0x023; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX702 = 0x024; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX703 = 0x025; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX704 = 0x026; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X27 = 0x027; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX802 = 0x029; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX803 = 0x02a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX810 = 0x02b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX908 = 0x030; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90C = 0x032; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1011 = 0x034; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1012 = 0x035; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1031 = 0x037; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1032 = 0x038; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1033 = 0x039; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX602 = 0x03a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX705 = 0x03b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX805 = 0x03c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X3D = 0x03d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1034 = 0x03e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90A = 0x03f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X40 = 0x040; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X41 = 0x041; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1013 = 0x042; +// First/last AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX1013; + +///////////////////// +// Sections constants + +// Section indexes +constexpr Elf_Word SHN_UNDEF = 0; +constexpr Elf_Word SHN_LORESERVE = 0xFF00; +constexpr Elf_Word SHN_LOPROC = 0xFF00; +constexpr Elf_Word SHN_HIPROC = 0xFF1F; +constexpr Elf_Word SHN_LOOS = 0xFF20; +constexpr Elf_Word SHN_HIOS = 0xFF3F; +constexpr Elf_Word SHN_ABS = 0xFFF1; +constexpr Elf_Word SHN_COMMON = 0xFFF2; +constexpr Elf_Word SHN_XINDEX = 0xFFFF; +constexpr Elf_Word SHN_HIRESERVE = 0xFFFF; + +// Section types +constexpr Elf_Word SHT_NULL = 0; +constexpr Elf_Word SHT_PROGBITS = 1; +constexpr Elf_Word SHT_SYMTAB = 2; +constexpr Elf_Word SHT_STRTAB = 3; +constexpr Elf_Word SHT_RELA = 4; +constexpr Elf_Word SHT_HASH = 5; +constexpr Elf_Word SHT_DYNAMIC = 6; +constexpr Elf_Word SHT_NOTE = 7; +constexpr Elf_Word SHT_NOBITS = 8; +constexpr Elf_Word SHT_REL = 9; +constexpr Elf_Word SHT_SHLIB = 10; +constexpr Elf_Word SHT_DYNSYM = 11; +constexpr Elf_Word SHT_INIT_ARRAY = 14; +constexpr Elf_Word SHT_FINI_ARRAY = 15; +constexpr Elf_Word SHT_PREINIT_ARRAY = 16; +constexpr Elf_Word SHT_GROUP = 17; +constexpr Elf_Word SHT_SYMTAB_SHNDX = 18; +constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5; +constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6; +constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7; +constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8; +constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb; +constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc; +constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd; +constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe; +constexpr Elf_Word SHT_GNU_versym = 0x6fffffff; +constexpr Elf_Word SHT_LOOS = 0x60000000; +constexpr Elf_Word SHT_HIOS = 0x6fffffff; +constexpr Elf_Word SHT_LOPROC = 0x70000000; +constexpr Elf_Word SHT_ARM_EXIDX = 0x70000001; +constexpr Elf_Word SHT_ARM_PREEMPTMAP = 0x70000002; +constexpr Elf_Word SHT_ARM_ATTRIBUTES = 0x70000003; +constexpr Elf_Word SHT_ARM_DEBUGOVERLAY = 0x70000004; +constexpr Elf_Word SHT_ARM_OVERLAYSECTION = 0x70000005; +constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF; +constexpr Elf_Word SHT_LOUSER = 0x80000000; +// Used by Nintendo Wii U +constexpr Elf_Word SHT_RPL_EXPORTS = 0x80000001; +constexpr Elf_Word SHT_RPL_IMPORTS = 0x80000002; +constexpr Elf_Word SHT_RPL_CRCS = 0x80000003; +constexpr Elf_Word SHT_RPL_FILEINFO = 0x80000004; +constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF; + +// Section attribute flags +constexpr Elf_Xword SHF_WRITE = 0x1; +constexpr Elf_Xword SHF_ALLOC = 0x2; +constexpr Elf_Xword SHF_EXECINSTR = 0x4; +constexpr Elf_Xword SHF_MERGE = 0x10; +constexpr Elf_Xword SHF_STRINGS = 0x20; +constexpr Elf_Xword SHF_INFO_LINK = 0x40; +constexpr Elf_Xword SHF_LINK_ORDER = 0x80; +constexpr Elf_Xword SHF_OS_NONCONFORMING = 0x100; +constexpr Elf_Xword SHF_GROUP = 0x200; +constexpr Elf_Xword SHF_TLS = 0x400; +constexpr Elf_Xword SHF_COMPRESSED = 0x800; +constexpr Elf_Xword SHF_GNU_RETAIN = 0x200000; +constexpr Elf_Xword SHF_GNU_MBIND = 0x01000000; +// flag used in Nintendo RPX/RPL to indicate section data is compressed +constexpr Elf_Xword SHF_RPX_DEFLATE = 0x08000000; +constexpr Elf_Xword SHF_MASKOS = 0x0FF00000; +constexpr Elf_Xword SHF_MIPS_GPREL = 0x10000000; +constexpr Elf_Xword SHF_ORDERED = 0x40000000; +constexpr Elf_Xword SHF_EXCLUDE = 0x80000000; +constexpr Elf_Xword SHF_MASKPROC = 0xF0000000; + +// Section group flags +constexpr Elf_Word GRP_COMDAT = 0x1; +constexpr Elf_Word GRP_MASKOS = 0x0ff00000; +constexpr Elf_Word GRP_MASKPROC = 0xf0000000; + +// Symbol binding +constexpr unsigned char STB_LOCAL = 0; +constexpr unsigned char STB_GLOBAL = 1; +constexpr unsigned char STB_WEAK = 2; +constexpr unsigned char STB_LOOS = 10; +constexpr unsigned char STB_HIOS = 12; +constexpr unsigned char STB_MULTIDEF = 13; +constexpr unsigned char STB_LOPROC = 13; +constexpr unsigned char STB_HIPROC = 15; + +// Values of note segment descriptor types for core files +constexpr Elf_Word NT_PRSTATUS = 1; // Contains copy of prstatus struct +constexpr Elf_Word NT_FPREGSET = 2; // Contains copy of fpregset struct +constexpr Elf_Word NT_PRPSINFO = 3; // Contains copy of prpsinfo struct +constexpr Elf_Word NT_TASKSTRUCT = 4; // Contains copy of task struct +constexpr Elf_Word NT_AUXV = 6; // Contains copy of Elfxx_auxv_t +constexpr Elf_Word NT_SIGINFO = 0x53494749; // Fields of siginfo_t. +constexpr Elf_Word NT_FILE = 0x46494c45; // Description of mapped files. + +// Note segments for core files on dir-style procfs systems. +constexpr Elf_Word NT_PSTATUS = 10; // Has a struct pstatus +constexpr Elf_Word NT_FPREGS = 12; // Has a struct fpregset +constexpr Elf_Word NT_PSINFO = 13; // Has a struct psinfo +constexpr Elf_Word NT_LWPSTATUS = 16; // Has a struct lwpstatus_t +constexpr Elf_Word NT_LWPSINFO = 17; // Has a struct lwpsinfo_t +constexpr Elf_Word NT_WIN32PSTATUS = 18; // Has a struct win32_pstatus + +// clang-format off + +// Note name must be "LINUX" +constexpr Elf_Word NT_PRXFPREG = 0x46e62b7f; // Contains a user_xfpregs_struct +constexpr Elf_Word NT_PPC_VMX = 0x100; // PowerPC Altivec/VMX registers +constexpr Elf_Word NT_PPC_VSX = 0x102; // PowerPC VSX registers +constexpr Elf_Word NT_PPC_TAR = 0x103; // PowerPC Target Address Register +constexpr Elf_Word NT_PPC_PPR = 0x104; // PowerPC Program Priority Register +constexpr Elf_Word NT_PPC_DSCR = 0x105; // PowerPC Data Stream Control Register +constexpr Elf_Word NT_PPC_EBB = 0x106; // PowerPC Event Based Branch Registers +constexpr Elf_Word NT_PPC_PMU = 0x107; // PowerPC Performance Monitor Registers +constexpr Elf_Word NT_PPC_TM_CGPR = 0x108; // PowerPC TM checkpointed GPR Registers +constexpr Elf_Word NT_PPC_TM_CFPR = 0x109; // PowerPC TM checkpointed FPR Registers +constexpr Elf_Word NT_PPC_TM_CVMX = 0x10a; // PowerPC TM checkpointed VMX Registers +constexpr Elf_Word NT_PPC_TM_CVSX = 0x10b; // PowerPC TM checkpointed VSX Registers +constexpr Elf_Word NT_PPC_TM_SPR = 0x10c; // PowerPC TM Special Purpose Registers +constexpr Elf_Word NT_PPC_TM_CTAR = 0x10d; // PowerPC TM checkpointed TAR +constexpr Elf_Word NT_PPC_TM_CPPR = 0x10e; // PowerPC TM checkpointed PPR +constexpr Elf_Word NT_PPC_TM_CDSCR = 0x10f; // PowerPC TM checkpointed Data SCR +constexpr Elf_Word NT_386_TLS = 0x200; // x86 TLS information +constexpr Elf_Word NT_386_IOPERM = 0x201; // x86 io permissions +constexpr Elf_Word NT_X86_XSTATE = 0x202; // x86 XSAVE extended state +constexpr Elf_Word NT_X86_CET = 0x203; // x86 CET state. +constexpr Elf_Word NT_S390_HIGH_GPRS = 0x300; // S/390 upper halves of GPRs +constexpr Elf_Word NT_S390_TIMER = 0x301; // S390 timer +constexpr Elf_Word NT_S390_TODCMP = 0x302; // S390 TOD clock comparator +constexpr Elf_Word NT_S390_TODPREG = 0x303; // S390 TOD programmable register +constexpr Elf_Word NT_S390_CTRS = 0x304; // S390 control registers +constexpr Elf_Word NT_S390_PREFIX = 0x305; // S390 prefix register +constexpr Elf_Word NT_S390_LAST_BREAK = 0x306; // S390 breaking event address +constexpr Elf_Word NT_S390_SYSTEM_CALL = 0x307; // S390 system call restart data +constexpr Elf_Word NT_S390_TDB = 0x308; // S390 transaction diagnostic block +constexpr Elf_Word NT_S390_VXRS_LOW = 0x309; // S390 vector registers 0-15 upper half +constexpr Elf_Word NT_S390_VXRS_HIGH = 0x30a; // S390 vector registers 16-31 +constexpr Elf_Word NT_S390_GS_CB = 0x30b; // s390 guarded storage registers +constexpr Elf_Word NT_S390_GS_BC = 0x30c; // s390 guarded storage broadcast control block +constexpr Elf_Word NT_ARM_VFP = 0x400; // ARM VFP registers +constexpr Elf_Word NT_ARM_TLS = 0x401; // AArch TLS registers +constexpr Elf_Word NT_ARM_HW_BREAK = 0x402; // AArch hardware breakpoint registers +constexpr Elf_Word NT_ARM_HW_WATCH = 0x403; // AArch hardware watchpoint registers +constexpr Elf_Word NT_ARM_SVE = 0x405; // AArch SVE registers. +constexpr Elf_Word NT_ARM_PAC_MASK = 0x406; // AArch pointer authentication code masks +constexpr Elf_Word NT_ARM_PACA_KEYS = 0x407; // ARM pointer authentication address keys +constexpr Elf_Word NT_ARM_PACG_KEYS = 0x408; // ARM pointer authentication generic keys +constexpr Elf_Word NT_ARM_TAGGED_ADDR_CTRL = 0x409; // AArch64 tagged address control (prctl()) +constexpr Elf_Word NT_ARM_PAC_ENABLED_KEYS = 0x40a; // AArch64 pointer authentication enabled keys (prctl()) +constexpr Elf_Word NT_ARC_V2 = 0x600; // ARC HS accumulator/extra registers. +constexpr Elf_Word NT_LARCH_CPUCFG = 0xa00; // LoongArch CPU config registers +constexpr Elf_Word NT_LARCH_CSR = 0xa01; // LoongArch Control State Registers +constexpr Elf_Word NT_LARCH_LSX = 0xa02; // LoongArch SIMD eXtension registers +constexpr Elf_Word NT_LARCH_LASX = 0xa03; // LoongArch Advanced SIMD eXtension registers +constexpr Elf_Word NT_RISCV_CSR = 0x900; // RISC-V Control and Status Registers + +// Note name must be "CORE" +constexpr Elf_Word NT_LARCH_LBT = 0xa04; // LoongArch Binary Translation registers + +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't + originate from any particular operating system. */ +constexpr Elf_Word NT_GDB_TDESC = 0xff000000; // Contains copy of GDB's target description XML. +constexpr Elf_Word NT_MEMTAG = 0xff000001; // Contains a copy of the memory tags. +/* ARM-specific NT_MEMTAG types. */ +constexpr Elf_Word NT_MEMTAG_TYPE_AARCH_MTE = 0x400; // MTE memory tags for AArch64. + +constexpr Elf_Word NT_STAPSDT = 3; // Note segment for SystemTap probes. + +// Note name is "FreeBSD" +constexpr Elf_Word NT_FREEBSD_THRMISC = 7; // Thread miscellaneous info. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PROC = 8; // Procstat proc data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_FILES = 9; // Procstat files data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_VMMAP = 10; // Procstat vmmap data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_GROUPS = 11; // Procstat groups data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_UMASK = 12; // Procstat umask data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_RLIMIT = 13; // Procstat rlimit data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_OSREL = 14; // Procstat osreldate data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PSSTRINGS = 15; // Procstat ps_strings data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_AUXV = 16; // Procstat auxv data. +constexpr Elf_Word NT_FREEBSD_PTLWPINFO = 17; // Thread ptrace miscellaneous info. + +// Note name must start with "NetBSD-CORE" +constexpr Elf_Word NT_NETBSDCORE_PROCINFO = 1; // Has a struct procinfo +constexpr Elf_Word NT_NETBSDCORE_AUXV = 2; // Has auxv data +constexpr Elf_Word NT_NETBSDCORE_LWPSTATUS = 24; // Has LWPSTATUS data +constexpr Elf_Word NT_NETBSDCORE_FIRSTMACH = 32; // start of machdep note types + +// Note name is "OpenBSD" +constexpr Elf_Word NT_OPENBSD_PROCINFO = 10; +constexpr Elf_Word NT_OPENBSD_AUXV = 11; +constexpr Elf_Word NT_OPENBSD_REGS = 20; +constexpr Elf_Word NT_OPENBSD_FPREGS = 21; +constexpr Elf_Word NT_OPENBSD_XFPREGS = 22; +constexpr Elf_Word NT_OPENBSD_WCOOKIE = 23; + +// Note name must start with "SPU" +constexpr Elf_Word NT_SPU = 1; + +// Values of note segment descriptor types for object files +constexpr Elf_Word NT_VERSION = 1; // Contains a version string. +constexpr Elf_Word NT_ARCH = 2; // Contains an architecture string. +constexpr Elf_Word NT_GO_BUILDID = 4; // Contains GO buildid data. + +// Values for notes in non-core files using name "GNU" +constexpr Elf_Word NT_GNU_ABI_TAG = 1; +constexpr Elf_Word NT_GNU_HWCAP = 2; // Used by ld.so and kernel vDSO. +constexpr Elf_Word NT_GNU_BUILD_ID = 3; // Generated by ld --build-id. +constexpr Elf_Word NT_GNU_GOLD_VERSION = 4; // Generated by gold. +constexpr Elf_Word NT_GNU_PROPERTY_TYPE_0 = 5; // Generated by gcc. +// clang-format on + +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_OPEN = 0x100; +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101; + +// Symbol types +constexpr Elf_Word STT_NOTYPE = 0; +constexpr Elf_Word STT_OBJECT = 1; +constexpr Elf_Word STT_FUNC = 2; +constexpr Elf_Word STT_SECTION = 3; +constexpr Elf_Word STT_FILE = 4; +constexpr Elf_Word STT_COMMON = 5; +constexpr Elf_Word STT_TLS = 6; +constexpr Elf_Word STT_LOOS = 10; +constexpr Elf_Word STT_AMDGPU_HSA_KERNEL = 10; +constexpr Elf_Word STT_HIOS = 12; +constexpr Elf_Word STT_LOPROC = 13; +constexpr Elf_Word STT_HIPROC = 15; + +// Symbol visibility +constexpr unsigned char STV_DEFAULT = 0; +constexpr unsigned char STV_INTERNAL = 1; +constexpr unsigned char STV_HIDDEN = 2; +constexpr unsigned char STV_PROTECTED = 3; + +// Undefined name +constexpr Elf_Word STN_UNDEF = 0; + +// Relocation types +// X86 +constexpr unsigned R_386_NONE = 0; +constexpr unsigned R_X86_64_NONE = 0; +constexpr unsigned R_AMDGPU_NONE = 0; +constexpr unsigned R_386_32 = 1; +constexpr unsigned R_X86_64_64 = 1; +constexpr unsigned R_AMDGPU_ABS32_LO = 1; +constexpr unsigned R_386_PC32 = 2; +constexpr unsigned R_X86_64_PC32 = 2; +constexpr unsigned R_AMDGPU_ABS32_HI = 2; +constexpr unsigned R_386_GOT32 = 3; +constexpr unsigned R_X86_64_GOT32 = 3; +constexpr unsigned R_AMDGPU_ABS64 = 3; +constexpr unsigned R_386_PLT32 = 4; +constexpr unsigned R_X86_64_PLT32 = 4; +constexpr unsigned R_AMDGPU_REL32 = 4; +constexpr unsigned R_386_COPY = 5; +constexpr unsigned R_X86_64_COPY = 5; +constexpr unsigned R_AMDGPU_REL64 = 5; +constexpr unsigned R_386_GLOB_DAT = 6; +constexpr unsigned R_X86_64_GLOB_DAT = 6; +constexpr unsigned R_AMDGPU_ABS32 = 6; +constexpr unsigned R_386_JMP_SLOT = 7; +constexpr unsigned R_X86_64_JUMP_SLOT = 7; +constexpr unsigned R_AMDGPU_GOTPCREL = 7; +constexpr unsigned R_386_RELATIVE = 8; +constexpr unsigned R_X86_64_RELATIVE = 8; +constexpr unsigned R_AMDGPU_GOTPCREL32_LO = 8; +constexpr unsigned R_386_GOTOFF = 9; +constexpr unsigned R_X86_64_GOTPCREL = 9; +constexpr unsigned R_AMDGPU_GOTPCREL32_HI = 9; +constexpr unsigned R_386_GOTPC = 10; +constexpr unsigned R_X86_64_32 = 10; +constexpr unsigned R_AMDGPU_REL32_LO = 10; +constexpr unsigned R_386_32PLT = 11; +constexpr unsigned R_X86_64_32S = 11; +constexpr unsigned R_AMDGPU_REL32_HI = 11; +constexpr unsigned R_X86_64_16 = 12; +constexpr unsigned R_X86_64_PC16 = 13; +constexpr unsigned R_AMDGPU_RELATIVE64 = 13; +constexpr unsigned R_386_TLS_TPOFF = 14; +constexpr unsigned R_X86_64_8 = 14; +constexpr unsigned R_386_TLS_IE = 15; +constexpr unsigned R_X86_64_PC8 = 15; +constexpr unsigned R_386_TLS_GOTIE = 16; +constexpr unsigned R_X86_64_DTPMOD64 = 16; +constexpr unsigned R_386_TLS_LE = 17; +constexpr unsigned R_X86_64_DTPOFF64 = 17; +constexpr unsigned R_386_TLS_GD = 18; +constexpr unsigned R_X86_64_TPOFF64 = 18; +constexpr unsigned R_386_TLS_LDM = 19; +constexpr unsigned R_X86_64_TLSGD = 19; +constexpr unsigned R_386_16 = 20; +constexpr unsigned R_X86_64_TLSLD = 20; +constexpr unsigned R_386_PC16 = 21; +constexpr unsigned R_X86_64_DTPOFF32 = 21; +constexpr unsigned R_386_8 = 22; +constexpr unsigned R_X86_64_GOTTPOFF = 22; +constexpr unsigned R_386_PC8 = 23; +constexpr unsigned R_X86_64_TPOFF32 = 23; +constexpr unsigned R_386_TLS_GD_32 = 24; +constexpr unsigned R_X86_64_PC64 = 24; +constexpr unsigned R_386_TLS_GD_PUSH = 25; +constexpr unsigned R_X86_64_GOTOFF64 = 25; +constexpr unsigned R_386_TLS_GD_CALL = 26; +constexpr unsigned R_X86_64_GOTPC32 = 26; +constexpr unsigned R_386_TLS_GD_POP = 27; +constexpr unsigned R_X86_64_GOT64 = 27; +constexpr unsigned R_386_TLS_LDM_32 = 28; +constexpr unsigned R_X86_64_GOTPCREL64 = 28; +constexpr unsigned R_386_TLS_LDM_PUSH = 29; +constexpr unsigned R_X86_64_GOTPC64 = 29; +constexpr unsigned R_386_TLS_LDM_CALL = 30; +constexpr unsigned R_X86_64_GOTPLT64 = 30; +constexpr unsigned R_386_TLS_LDM_POP = 31; +constexpr unsigned R_X86_64_PLTOFF64 = 31; +constexpr unsigned R_386_TLS_LDO_32 = 32; +constexpr unsigned R_386_TLS_IE_32 = 33; +constexpr unsigned R_386_TLS_LE_32 = 34; +constexpr unsigned R_X86_64_GOTPC32_TLSDESC = 34; +constexpr unsigned R_386_TLS_DTPMOD32 = 35; +constexpr unsigned R_X86_64_TLSDESC_CALL = 35; +constexpr unsigned R_386_TLS_DTPOFF32 = 36; +constexpr unsigned R_X86_64_TLSDESC = 36; +constexpr unsigned R_386_TLS_TPOFF32 = 37; +constexpr unsigned R_X86_64_IRELATIVE = 37; +constexpr unsigned R_386_SIZE32 = 38; +constexpr unsigned R_386_TLS_GOTDESC = 39; +constexpr unsigned R_386_TLS_DESC_CALL = 40; +constexpr unsigned R_386_TLS_DESC = 41; +constexpr unsigned R_386_IRELATIVE = 42; +constexpr unsigned R_386_GOT32X = 43; +constexpr unsigned R_X86_64_GNU_VTINHERIT = 250; +constexpr unsigned R_X86_64_GNU_VTENTRY = 251; +// AArch64 +constexpr unsigned R_AARCH64_NONE = 0; +constexpr unsigned R_AARCH64_P32_ABS32 = 1; +constexpr unsigned R_AARCH64_P32_COPY = 180; +constexpr unsigned R_AARCH64_P32_GLOB_DAT = 181; +constexpr unsigned R_AARCH64_P32_JUMP_SLOT = 182; +constexpr unsigned R_AARCH64_P32_RELATIVE = 183; +constexpr unsigned R_AARCH64_P32_TLS_DTPMOD = 184; +constexpr unsigned R_AARCH64_P32_TLS_DTPREL = 185; +constexpr unsigned R_AARCH64_P32_TLS_TPREL = 186; +constexpr unsigned R_AARCH64_P32_TLSDESC = 187; +constexpr unsigned R_AARCH64_P32_IRELATIVE = 188; +constexpr unsigned R_AARCH64_ABS64 = 257; +constexpr unsigned R_AARCH64_ABS32 = 258; +constexpr unsigned R_AARCH64_ABS16 = 259; +constexpr unsigned R_AARCH64_PREL64 = 260; +constexpr unsigned R_AARCH64_PREL32 = 261; +constexpr unsigned R_AARCH64_PREL16 = 262; +constexpr unsigned R_AARCH64_MOVW_UABS_G0 = 263; +constexpr unsigned R_AARCH64_MOVW_UABS_G0_NC = 264; +constexpr unsigned R_AARCH64_MOVW_UABS_G1 = 265; +constexpr unsigned R_AARCH64_MOVW_UABS_G1_NC = 266; +constexpr unsigned R_AARCH64_MOVW_UABS_G2 = 267; +constexpr unsigned R_AARCH64_MOVW_UABS_G2_NC = 268; +constexpr unsigned R_AARCH64_MOVW_UABS_G3 = 269; +constexpr unsigned R_AARCH64_MOVW_SABS_G0 = 270; +constexpr unsigned R_AARCH64_MOVW_SABS_G1 = 271; +constexpr unsigned R_AARCH64_MOVW_SABS_G2 = 272; +constexpr unsigned R_AARCH64_LD_PREL_LO19 = 273; +constexpr unsigned R_AARCH64_ADR_PREL_LO21 = 274; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21 = 275; +constexpr unsigned R_AARCH64_ADR_PREL_PG_HI21_NC = 276; +constexpr unsigned R_AARCH64_ADD_ABS_LO12_NC = 277; +constexpr unsigned R_AARCH64_LDST8_ABS_LO12_NC = 278; +constexpr unsigned R_AARCH64_TSTBR14 = 279; +constexpr unsigned R_AARCH64_CONDBR19 = 280; +constexpr unsigned R_AARCH64_JUMP26 = 282; +constexpr unsigned R_AARCH64_CALL26 = 283; +constexpr unsigned R_AARCH64_LDST16_ABS_LO12_NC = 284; +constexpr unsigned R_AARCH64_LDST32_ABS_LO12_NC = 285; +constexpr unsigned R_AARCH64_LDST64_ABS_LO12_NC = 286; +constexpr unsigned R_AARCH64_MOVW_PREL_G0 = 287; +constexpr unsigned R_AARCH64_MOVW_PREL_G0_NC = 288; +constexpr unsigned R_AARCH64_MOVW_PREL_G1 = 289; +constexpr unsigned R_AARCH64_MOVW_PREL_G1_NC = 290; +constexpr unsigned R_AARCH64_MOVW_PREL_G2 = 291; +constexpr unsigned R_AARCH64_MOVW_PREL_G2_NC = 292; +constexpr unsigned R_AARCH64_MOVW_PREL_G3 = 293; +constexpr unsigned R_AARCH64_LDST128_ABS_LO12_NC = 299; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0 = 300; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G0_NC = 301; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1 = 302; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G1_NC = 303; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2 = 304; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G2_NC = 305; +constexpr unsigned R_AARCH64_MOVW_GOTOFF_G3 = 306; +constexpr unsigned R_AARCH64_GOTREL64 = 307; +constexpr unsigned R_AARCH64_GOTREL32 = 308; +constexpr unsigned R_AARCH64_GOT_LD_PREL19 = 309; +constexpr unsigned R_AARCH64_LD64_GOTOFF_LO15 = 310; +constexpr unsigned R_AARCH64_ADR_GOT_PAGE = 311; +constexpr unsigned R_AARCH64_LD64_GOT_LO12_NC = 312; +constexpr unsigned R_AARCH64_LD64_GOTPAGE_LO15 = 313; +constexpr unsigned R_AARCH64_TLSGD_ADR_PREL21 = 512; +constexpr unsigned R_AARCH64_TLSGD_ADR_PAGE21 = 513; +constexpr unsigned R_AARCH64_TLSGD_ADD_LO12_NC = 514; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G1 = 515; +constexpr unsigned R_AARCH64_TLSGD_MOVW_G0_NC = 516; +constexpr unsigned R_AARCH64_TLSLD_ADR_PREL21 = 517; +constexpr unsigned R_AARCH64_TLSLD_ADR_PAGE21 = 518; +constexpr unsigned R_AARCH64_TLSLD_ADD_LO12_NC = 519; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G1 = 520; +constexpr unsigned R_AARCH64_TLSLD_MOVW_G0_NC = 521; +constexpr unsigned R_AARCH64_TLSLD_LD_PREL19 = 522; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 523; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 524; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 525; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 526; +constexpr unsigned R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 527; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 528; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 529; +constexpr unsigned R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 530; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 531; +constexpr unsigned R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 532; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 533; +constexpr unsigned R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 534; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 535; +constexpr unsigned R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 536; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 537; +constexpr unsigned R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 538; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 539; +constexpr unsigned R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 540; +constexpr unsigned R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 541; +constexpr unsigned R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542; +constexpr unsigned R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 543; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G2 = 544; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1 = 545; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 546; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0 = 547; +constexpr unsigned R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 548; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_HI12 = 549; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12 = 550; +constexpr unsigned R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 551; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 552; +constexpr unsigned R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 553; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 554; +constexpr unsigned R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 555; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 556; +constexpr unsigned R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 557; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 558; +constexpr unsigned R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 559; +constexpr unsigned R_AARCH64_TLSDESC_LD_PREL19 = 560; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PREL21 = 561; +constexpr unsigned R_AARCH64_TLSDESC_ADR_PAGE21 = 562; +constexpr unsigned R_AARCH64_TLSDESC_LD64_LO12 = 563; +constexpr unsigned R_AARCH64_TLSDESC_ADD_LO12 = 564; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G1 = 565; +constexpr unsigned R_AARCH64_TLSDESC_OFF_G0_NC = 566; +constexpr unsigned R_AARCH64_TLSDESC_LDR = 567; +constexpr unsigned R_AARCH64_TLSDESC_ADD = 568; +constexpr unsigned R_AARCH64_TLSDESC_CALL = 569; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 570; +constexpr unsigned R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 571; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12 = 572; +constexpr unsigned R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC = 573; +constexpr unsigned R_AARCH64_COPY = 1024; +constexpr unsigned R_AARCH64_GLOB_DAT = 1025; +constexpr unsigned R_AARCH64_JUMP_SLOT = 1026; +constexpr unsigned R_AARCH64_RELATIVE = 1027; +constexpr unsigned R_AARCH64_TLS_DTPMOD = 1028; +constexpr unsigned R_AARCH64_TLS_DTPMOD64 = 1028; +constexpr unsigned R_AARCH64_TLS_DTPREL = 1029; +constexpr unsigned R_AARCH64_TLS_DTPREL64 = 1029; +constexpr unsigned R_AARCH64_TLS_TPREL = 1030; +constexpr unsigned R_AARCH64_TLS_TPREL64 = 1030; +constexpr unsigned R_AARCH64_TLSDESC = 1031; + +// Segment types +constexpr Elf_Word PT_NULL = 0; +constexpr Elf_Word PT_LOAD = 1; +constexpr Elf_Word PT_DYNAMIC = 2; +constexpr Elf_Word PT_INTERP = 3; +constexpr Elf_Word PT_NOTE = 4; +constexpr Elf_Word PT_SHLIB = 5; +constexpr Elf_Word PT_PHDR = 6; +constexpr Elf_Word PT_TLS = 7; +constexpr Elf_Word PT_LOOS = 0X60000000; +constexpr Elf_Word PT_GNU_EH_FRAME = 0X6474E550; // Frame unwind information +constexpr Elf_Word PT_GNU_STACK = 0X6474E551; // Stack flags +constexpr Elf_Word PT_GNU_RELRO = 0X6474E552; // Read only after relocs +constexpr Elf_Word PT_GNU_PROPERTY = 0X6474E553; // GNU property +constexpr Elf_Word PT_GNU_MBIND_LO = 0X6474E555; // Mbind segments start +constexpr Elf_Word PT_GNU_MBIND_HI = 0X6474F554; // Mbind segments finish +constexpr Elf_Word PT_PAX_FLAGS = 0X65041580; +constexpr Elf_Word PT_OPENBSD_RANDOMIZE = 0X65A3DBE6; +constexpr Elf_Word PT_OPENBSD_WXNEEDED = 0X65A3DBE7; +constexpr Elf_Word PT_OPENBSD_BOOTDATA = 0X65A41BE6; +constexpr Elf_Word PT_SUNWBSS = 0X6FFFFFFA; +constexpr Elf_Word PT_SUNWSTACK = 0X6FFFFFFB; +constexpr Elf_Word PT_HIOS = 0X6FFFFFFF; +constexpr Elf_Word PT_LOPROC = 0X70000000; +constexpr Elf_Word PT_HIPROC = 0X7FFFFFFF; + +// Segment flags +constexpr Elf_Word PF_X = 1; // Execute +constexpr Elf_Word PF_W = 2; // Write +constexpr Elf_Word PF_R = 4; // Read +constexpr Elf_Word PF_MASKOS = 0x0ff00000; // Unspecified +constexpr Elf_Word PF_MASKPROC = 0xf0000000; // Unspecified + +// Dynamic Array Tags +constexpr Elf_Word DT_NULL = 0; +constexpr Elf_Word DT_NEEDED = 1; +constexpr Elf_Word DT_PLTRELSZ = 2; +constexpr Elf_Word DT_PLTGOT = 3; +constexpr Elf_Word DT_HASH = 4; +constexpr Elf_Word DT_STRTAB = 5; +constexpr Elf_Word DT_SYMTAB = 6; +constexpr Elf_Word DT_RELA = 7; +constexpr Elf_Word DT_RELASZ = 8; +constexpr Elf_Word DT_RELAENT = 9; +constexpr Elf_Word DT_STRSZ = 10; +constexpr Elf_Word DT_SYMENT = 11; +constexpr Elf_Word DT_INIT = 12; +constexpr Elf_Word DT_FINI = 13; +constexpr Elf_Word DT_SONAME = 14; +constexpr Elf_Word DT_RPATH = 15; +constexpr Elf_Word DT_SYMBOLIC = 16; +constexpr Elf_Word DT_REL = 17; +constexpr Elf_Word DT_RELSZ = 18; +constexpr Elf_Word DT_RELENT = 19; +constexpr Elf_Word DT_PLTREL = 20; +constexpr Elf_Word DT_DEBUG = 21; +constexpr Elf_Word DT_TEXTREL = 22; +constexpr Elf_Word DT_JMPREL = 23; +constexpr Elf_Word DT_BIND_NOW = 24; +constexpr Elf_Word DT_INIT_ARRAY = 25; +constexpr Elf_Word DT_FINI_ARRAY = 26; +constexpr Elf_Word DT_INIT_ARRAYSZ = 27; +constexpr Elf_Word DT_FINI_ARRAYSZ = 28; +constexpr Elf_Word DT_RUNPATH = 29; +constexpr Elf_Word DT_FLAGS = 30; +constexpr Elf_Word DT_ENCODING = 32; +constexpr Elf_Word DT_PREINIT_ARRAY = 32; +constexpr Elf_Word DT_PREINIT_ARRAYSZ = 33; +constexpr Elf_Word DT_MAXPOSTAGS = 34; +constexpr Elf_Word DT_LOOS = 0x6000000D; +constexpr Elf_Word DT_HIOS = 0x6ffff000; +constexpr Elf_Word DT_GNU_HASH = 0x6ffffef5; +constexpr Elf_Word DT_TLSDESC_PLT = 0x6ffffef6; +constexpr Elf_Word DT_TLSDESC_GOT = 0x6ffffef7; +constexpr Elf_Word DT_GNU_CONFLICT = 0x6ffffef8; +constexpr Elf_Word DT_GNU_LIBLIST = 0x6ffffef9; +constexpr Elf_Word DT_CONFIG = 0x6ffffefa; +constexpr Elf_Word DT_DEPAUDIT = 0x6ffffefb; +constexpr Elf_Word DT_AUDIT = 0x6ffffefc; +constexpr Elf_Word DT_PLTPAD = 0x6ffffefd; +constexpr Elf_Word DT_MOVETAB = 0x6ffffefe; +constexpr Elf_Word DT_SYMINFO = 0x6ffffeff; +constexpr Elf_Word DT_ADDRRNGHI = 0x6ffffeff; +constexpr Elf_Word DT_VERSYM = 0x6ffffff0; +constexpr Elf_Word DT_RELACOUNT = 0x6ffffff9; +constexpr Elf_Word DT_RELCOUNT = 0x6ffffffa; +constexpr Elf_Word DT_FLAGS_1 = 0x6ffffffb; +constexpr Elf_Word DT_VERDEF = 0x6ffffffc; +constexpr Elf_Word DT_VERDEFNUM = 0x6ffffffd; +constexpr Elf_Word DT_VERNEED = 0x6ffffffe; +constexpr Elf_Word DT_VERNEEDNUM = 0x6fffffff; +constexpr Elf_Word DT_LOPROC = 0x70000000; +constexpr Elf_Word DT_HIPROC = 0x7FFFFFFF; + +// DT_FLAGS values +constexpr Elf_Word DF_ORIGIN = 0x1; +constexpr Elf_Word DF_SYMBOLIC = 0x2; +constexpr Elf_Word DF_TEXTREL = 0x4; +constexpr Elf_Word DF_BIND_NOW = 0x8; +constexpr Elf_Word DF_STATIC_TLS = 0x10; + +// Legal values for d_tag (dynamic entry type). +constexpr Elf_Word AT_NULL = 0; // End of vector +constexpr Elf_Word AT_IGNORE = 1; // Entry should be ignored +constexpr Elf_Word AT_EXECFD = 2; // File descriptor of program +constexpr Elf_Word AT_PHDR = 3; // Program headers for program +constexpr Elf_Word AT_PHENT = 4; // Size of program header entry +constexpr Elf_Word AT_PHNUM = 5; // Number of program headers +constexpr Elf_Word AT_PAGESZ = 6; // System page size +constexpr Elf_Word AT_BASE = 7; // Base address of interpreter +constexpr Elf_Word AT_FLAGS = 8; // Flags +constexpr Elf_Word AT_ENTRY = 9; // Entry point of program +constexpr Elf_Word AT_NOTELF = 10; // Program is not ELF +constexpr Elf_Word AT_UID = 11; // Real uid +constexpr Elf_Word AT_EUID = 12; // Effective uid +constexpr Elf_Word AT_GID = 13; // Real gid +constexpr Elf_Word AT_EGID = 14; // Effective gid +constexpr Elf_Word AT_CLKTCK = 17; // Frequency of times() +constexpr Elf_Word AT_PLATFORM = 15; // String identifying platform. +constexpr Elf_Word AT_HWCAP = 16; // Hints about processor capabilities. +constexpr Elf_Word AT_FPUCW = 18; // Used FPU control word. +constexpr Elf_Word AT_DCACHEBSIZE = 19; // Data cache block size. +constexpr Elf_Word AT_ICACHEBSIZE = 20; // Instruction cache block size. +constexpr Elf_Word AT_UCACHEBSIZE = 21; // Unified cache block size. +constexpr Elf_Word AT_IGNOREPPC = 22; // Entry should be ignored. +constexpr Elf_Word AT_SECURE = 23; // Boolean, was exec setuid-like? +constexpr Elf_Word AT_BASE_PLATFORM = 24; // String identifying real platforms. +constexpr Elf_Word AT_RANDOM = 25; // Address of 16 random bytes. +constexpr Elf_Word AT_HWCAP2 = 26; // More hints about processor capabilities. +constexpr Elf_Word AT_EXECFN = 31; // Filename of executable. +constexpr Elf_Word AT_SYSINFO = 32; // EP to the system call in the vDSO. +constexpr Elf_Word AT_SYSINFO_EHDR = 33; // Start of the ELF header of the vDSO. +constexpr Elf_Word AT_L1I_CACHESHAPE = 34; +constexpr Elf_Word AT_L1D_CACHESHAPE = 35; +constexpr Elf_Word AT_L2_CACHESHAPE = 36; +constexpr Elf_Word AT_L3_CACHESHAPE = 37; +constexpr Elf_Word AT_L1I_CACHESIZE = 40; +constexpr Elf_Word AT_L1I_CACHEGEOMETRY = 41; +constexpr Elf_Word AT_L1D_CACHESIZE = 42; +constexpr Elf_Word AT_L1D_CACHEGEOMETRY = 43; +constexpr Elf_Word AT_L2_CACHESIZE = 44; +constexpr Elf_Word AT_L2_CACHEGEOMETRY = 45; +constexpr Elf_Word AT_L3_CACHESIZE = 46; + +// 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; +}; + +struct Elfxx_Verneed +{ + Elf_Half vn_version; + Elf_Half vn_cnt; + Elf_Word vn_file; + Elf_Word vn_aux; + Elf_Word vn_next; +}; + +struct Elfxx_Vernaux +{ + Elf_Word vna_hash; + Elf_Half vna_flags; + Elf_Half vna_other; + Elf_Word vna_name; + Elf_Word vna_next; +}; + +// ELF auxiliary vectors, they are usually run-time information +// being passed to program when the kernel is loading it. +// This is now required, +// because in order to initialize the stack cookie +// to protect against buffer overflows, +// most of libc ask us to have a valid pointer for the AT_RANDOM entry. +// glibc for example crashes if you don't. +// https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/libc-start.c;h=543560f36c33b07a1fbe1b7e4578374fe8007b1f;hb=HEAD#l308 +// This is also useful to be able to reconstruct at run-time +// the ELF headers, if ELF headers were erased after loading. +// Although this library is targeted to be parsing files only, +// I assume auxiliary vectors could be also used to get +// more information about the ELF binary at run-time in future. +// The main purpose is also for ELF injectors. +struct Elf32_auxv +{ + uint32_t a_type; // Entry type + + union { + uint32_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf64_auxv +{ + uint64_t a_type; // Entry type + + union { + uint64_t a_val; // Integer value, usually a pointer + } a_un; +}; + +struct Elf32_Chdr +{ + Elf32_Word ch_type; // The compression algorithm used + Elf32_Word ch_size; //The size, in bytes, of the uncompressed section data + Elf32_Word + ch_addralign; // The address alignment of the uncompressed section data +}; + +struct Elf64_Chdr +{ + Elf64_Word ch_type; //The compression algorithm used + Elf64_Word ch_reserved; // Reserved + Elf_Xword ch_size; //The size, in bytes, of the uncompressed section data + Elf_Xword + ch_addralign; //The address alignment of the uncompressed section data +}; + +#ifdef __cplusplus +} // namespace ELFIO +#endif + +#endif // ELFTYPES_H diff --git a/include/elfio/elfio.hpp b/include/elfio/elfio.hpp new file mode 100644 index 0000000..fc5995f --- /dev/null +++ b/include/elfio/elfio.hpp @@ -0,0 +1,1096 @@ +/* +Copyright (C) 2001-present 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ + TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ + TYPE get_##FNAME() const \ + { \ + return header ? ( header->get_##FNAME() ) : 0; \ + } \ + void set_##FNAME( TYPE val ) \ + { \ + if ( header ) { \ + header->set_##FNAME( val ); \ + } \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: + //------------------------------------------------------------------------------ + elfio() noexcept : sections( this ), segments( this ) + { + create( ELFCLASS32, ELFDATA2LSB ); + } + + explicit elfio( compression_interface* compression ) noexcept + : sections( this ), segments( this ), + compression( std::shared_ptr( compression ) ) + { + elfio(); + } + + elfio( elfio&& other ) noexcept + : sections( this ), segments( this ), + current_file_pos( other.current_file_pos ) + { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + compression = std::move( other.compression ); + + other.header = nullptr; + other.sections_.clear(); + other.segments_.clear(); + other.compression = nullptr; + } + + elfio& operator=( elfio&& other ) noexcept + { + if ( this != &other ) { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + current_file_pos = other.current_file_pos; + compression = std::move( other.compression ); + + other.current_file_pos = 0; + other.header = nullptr; + other.compression = nullptr; + other.sections_.clear(); + other.segments_.clear(); + } + return *this; + } + + //------------------------------------------------------------------------------ + // clang-format off + elfio( const elfio& ) = delete; + elfio& operator=( const elfio& ) = delete; + ~elfio() = default; + // clang-format on + + //------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + sections_.clear(); + segments_.clear(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + + void set_address_translation( std::vector& addr_trans ) + { + addr_translator.set_address_translation( addr_trans ); + } + + //------------------------------------------------------------------------------ + bool load( const std::string& file_name, bool is_lazy = false ) + { + pstream = std::make_unique(); + pstream->open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( pstream == nullptr || !*pstream ) { + return false; + } + + bool ret = load( *pstream, is_lazy ); + + if ( !is_lazy ) { + pstream.reset(); + } + + return ret; + } + + //------------------------------------------------------------------------------ + bool load( std::istream& stream, bool is_lazy = false ) + { + sections_.clear(); + segments_.clear(); + + std::array e_ident = { 0 }; + // Read ELF file signature + stream.seekg( addr_translator[0] ); + stream.read( e_ident.data(), 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; + } + + if ( ( e_ident[EI_DATA] != ELFDATA2LSB ) && + ( e_ident[EI_DATA] != ELFDATA2MSB ) ) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( nullptr == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream, is_lazy ); + bool is_still_good = load_segments( stream, is_lazy ); + return is_still_good; + } + + //------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save( stream ); + } + + //------------------------------------------------------------------------------ + bool save( std::ostream& stream ) + { + if ( !stream || header == nullptr ) { + return false; + } + + // 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() > 0 ? 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() * + static_cast( header->get_segments_num() ); + + calc_segment_alignment(); + + bool 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( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + 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; + } + } + + //------------------------------------------------------------------------------ + //! returns an empty string if no problems are detected, + //! or a string containing an error message if problems are found, + //! with one error per line. + std::string validate() const + { + // clang-format off + + std::string errors; + // Check for overlapping sections in the file + // This is explicitly forbidden by ELF specification + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( ( ( a->get_type() & SHT_NOBITS) == 0 ) + && ( ( b->get_type() & SHT_NOBITS) == 0 ) + && ( a->get_size() > 0 ) + && ( b->get_size() > 0 ) + && ( a->get_offset() > 0 ) + && ( b->get_offset() > 0 ) + && ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a ) ) ) { + errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; + } + } + } + // clang-format on + + // Check for conflicting section / program header tables, where + // the same offset has different vaddresses in section table and + // program header table. + // This doesn't seem to be explicitly forbidden by ELF specification, + // but: + // - it doesn't make any sense + // - ELFIO relies on this being consistent when writing ELF files, + // since offsets are re-calculated from vaddress + for ( int h = 0; h < segments.size(); ++h ) { + const segment* seg = segments[h]; + const section* sec = + find_prog_section_for_offset( seg->get_offset() ); + if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 && + sec != nullptr ) { + Elf64_Addr sec_addr = + get_virtual_addr( seg->get_offset(), sec ); + if ( sec_addr != seg->get_virtual_address() ) { + errors += "Virtual address of segment " + + std::to_string( h ) + " (" + + to_hex_string( seg->get_virtual_address() ) + + ")" + " conflicts with address of section " + + sec->get_name() + " (" + + to_hex_string( sec_addr ) + ")" + " at offset " + + to_hex_string( seg->get_offset() ) + "\n"; + } + } + } + + // more checks to be added here... + + return errors; + } + + private: + //------------------------------------------------------------------------------ + static bool is_offset_in_section( Elf64_Off offset, const section* sec ) + { + return ( offset >= sec->get_offset() ) && + ( offset < ( sec->get_offset() + sec->get_size() ) ); + } + + //------------------------------------------------------------------------------ + static Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) + { + return sec->get_address() + offset - sec->get_offset(); + } + + //------------------------------------------------------------------------------ + const section* find_prog_section_for_offset( Elf64_Off offset ) const + { + for ( const auto& sec : sections ) { + if ( sec->get_type() == SHT_PROGBITS && + is_offset_in_section( offset, sec.get() ) ) { + return sec.get(); + } + } + return nullptr; + } + + //------------------------------------------------------------------------------ + std::unique_ptr create_header( unsigned char file_class, + unsigned char encoding ) + { + std::unique_ptr new_header; + + if ( file_class == ELFCLASS64 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + &convertor, encoding, &addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = std::unique_ptr( + new ( std::nothrow ) elf_header_impl( + &convertor, encoding, &addr_translator ) ); + } + else { + return nullptr; + } + + return new_header; + } + + //------------------------------------------------------------------------------ + section* create_section() + { + if ( auto file_class = get_class(); file_class == ELFCLASS64 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + &convertor, &addr_translator, compression ) ); + } + else if ( file_class == ELFCLASS32 ) { + sections_.emplace_back( + new ( std::nothrow ) section_impl( + &convertor, &addr_translator, compression ) ); + } + else { + sections_.pop_back(); + return nullptr; + } + + section* new_section = sections_.back().get(); + new_section->set_index( static_cast( sections_.size() - 1 ) ); + + return new_section; + } + + //------------------------------------------------------------------------------ + segment* create_segment() + { + if ( auto file_class = header->get_class(); file_class == ELFCLASS64 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( &convertor, &addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( + new ( std::nothrow ) + segment_impl( &convertor, &addr_translator ) ); + } + else { + segments_.pop_back(); + return nullptr; + } + + segment* new_segment = segments_.back().get(); + new_segment->set_index( static_cast( segments_.size() - 1 ) ); + + 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 ); + } + + //------------------------------------------------------------------------------ + bool load_sections( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Shdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Shdr ) ) ) { + return false; + } + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + if ( Elf_Half shstrndx = get_section_name_str_index(); + SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != nullptr ) { + sections[i]->set_name( p ); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + //! Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + static bool is_sect_in_seg( Elf64_Off sect_begin, + Elf_Xword sect_size, + Elf64_Off seg_begin, + Elf64_Off seg_end ) + { + return ( seg_begin <= sect_begin ) && + ( sect_begin + sect_size <= seg_end ) && + ( sect_begin < + seg_end ); // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + + //------------------------------------------------------------------------------ + bool load_segments( std::istream& stream, bool is_lazy ) + { + unsigned char file_class = header->get_class(); + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + if ( ( num != 0 && file_class == ELFCLASS64 && + entry_size < sizeof( Elf64_Phdr ) ) || + ( num != 0 && file_class == ELFCLASS32 && + entry_size < sizeof( Elf32_Phdr ) ) ) { + return false; + } + + for ( Elf_Half i = 0; i < num; ++i ) { + if ( file_class == ELFCLASS64 ) { + segments_.emplace_back( + new ( std::nothrow ) segment_impl( + &convertor, &addr_translator ) ); + } + else if ( file_class == ELFCLASS32 ) { + segments_.emplace_back( + new ( std::nothrow ) segment_impl( + &convertor, &addr_translator ) ); + } + else { + segments_.pop_back(); + return false; + } + + segment* seg = segments_.back().get(); + + if ( !seg->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size, + is_lazy ) || + stream.fail() ) { + segments_.pop_back(); + return false; + } + + 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 ( const auto& psec : sections ) { + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) + ? is_sect_in_seg( psec->get_address(), + psec->get_size(), segVBaseAddr, + segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), + segBaseOffset, segEndOffset ) ) { + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + bool save_header( std::ostream& stream ) const + { + return header->save( stream ); + } + + //------------------------------------------------------------------------------ + bool save_sections( std::ostream& stream ) const + { + for ( const auto& sec : sections_ ) { + std::streampos headerPosition = + static_cast( header->get_sections_offset() ) + + static_cast( + header->get_section_entry_size() ) * + sec->get_index(); + + sec->save( stream, headerPosition, sec->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + bool save_segments( std::ostream& stream ) const + { + for ( const auto& seg : segments_ ) { + std::streampos headerPosition = + static_cast( header->get_segments_offset() ) + + static_cast( + header->get_segment_entry_size() ) * + seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) const + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( Elf_Half k = 0; + !found && ( k < segments[j]->get_sections_num() ); ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + + //------------------------------------------------------------------------------ + static bool is_subsequence_of( const segment* seg1, const 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() const + { + std::vector res; + std::deque worklist; + + res.reserve( segments.size() ); + for ( const auto& seg : segments ) { + worklist.emplace_back( seg.get() ); + } + + // 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 ) { + if ( worklist[nextSlot]->get_offset() == 0 ) { + ++nextSlot; + } + 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.emplace_back( seg ); + } + else { + res.emplace_back( seg ); + } + } + + return res; + } + + //------------------------------------------------------------------------------ + bool layout_sections_without_segments() + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + const auto& sec = sections_[i]; + + if ( Elf_Xword section_align = sec->get_addr_align(); + 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; + } + + //------------------------------------------------------------------------------ + void calc_segment_alignment() const + { + for ( const auto& seg : segments_ ) { + for ( Elf_Half i = 0; i < seg->get_sections_num(); ++i ) { + const auto& sect = sections_[seg->get_section_index_at( i )]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + + //------------------------------------------------------------------------------ + 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 ( auto* seg : worklist ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + // 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() * + static_cast( header->get_segments_num() ); + } + // Special case: + else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { + seg_start_pos = 0; + if ( seg->get_sections_num() > 0 ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() > 0 && + !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = + seg->get_virtual_address() % align; + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() > 0 ) { + seg_start_pos = + sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + if ( !write_segment_data( seg, section_generated, segment_memory, + segment_filesize, seg_start_pos ) ) { + return false; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + 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; + } + + //------------------------------------------------------------------------------ + bool write_segment_data( const segment* seg, + std::vector& section_generated, + Elf_Xword& segment_memory, + Elf_Xword& segment_filesize, + const Elf_Xword& seg_start_pos ) + { + for ( Elf_Half 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 section_align = 0; + // Fix up the alignment + if ( !section_generated[index] && sec->is_address_initialized() && + SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && + 0 != sec->get_size() ) { + // 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; + if ( req_offset < cur_offset ) { + // something has gone awfully wrong, abort! + // section_align would turn out negative, seeking backwards and overwriting previous data + return false; + } + section_align = req_offset - cur_offset; + } + else if ( !section_generated[index] && + !sec->is_address_initialized() ) { + // 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; + section_align = ( align - error ) % align; + } + else if ( section_generated[index] ) { + // Alignment for already generated sections + section_align = + 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 ) == SHF_ALLOC ) && + !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) && + ( SHT_NOBITS == sec->get_type() ) ) ) { + segment_memory += sec->get_size() + section_align; + } + + if ( SHT_NOBITS != sec->get_type() ) { + segment_filesize += sec->get_size() + section_align; + } + + // Nothing to be done when generating nested segments + if ( section_generated[index] ) { + continue; + } + + current_file_pos += section_align; + + // 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() ) { + current_file_pos += sec->get_size(); + } + + section_generated[index] = true; + } + + return true; + } + + //------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections + { + public: + //------------------------------------------------------------------------------ + explicit Sections( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + Elf_Half size() const + { + return static_cast( parent->sections_.size() ); + } + + //------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = nullptr; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index].get(); + } + + return sec; + } + + //------------------------------------------------------------------------------ + section* operator[]( const std::string_view& name ) const + { + section* sec = nullptr; + + for ( const auto& it : parent->sections_ ) { + if ( it->get_name() == name ) { + sec = it.get(); + break; + } + } + + return sec; + } + + //------------------------------------------------------------------------------ + section* add( const std::string& name ) const + { + 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].get() ); + 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(); + } + + //------------------------------------------------------------------------------ + std::vector>::const_iterator begin() const + { + return parent->sections_.cbegin(); + } + + //------------------------------------------------------------------------------ + std::vector>::const_iterator end() const + { + return parent->sections_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; + }; + Sections sections; + + //------------------------------------------------------------------------------ + friend class Segments; + class Segments + { + public: + //------------------------------------------------------------------------------ + explicit Segments( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + Elf_Half size() const + { + return static_cast( parent->segments_.size() ); + } + + //------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index].get(); + } + + //------------------------------------------------------------------------------ + segment* add() { return parent->create_segment(); } + + //------------------------------------------------------------------------------ + std::vector>::iterator begin() + { + return parent->segments_.begin(); + } + + //------------------------------------------------------------------------------ + std::vector>::iterator end() + { + return parent->segments_.end(); + } + + //------------------------------------------------------------------------------ + std::vector>::const_iterator begin() const + { + return parent->segments_.cbegin(); + } + + //------------------------------------------------------------------------------ + std::vector>::const_iterator end() const + { + return parent->segments_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; + }; + Segments segments; + + //------------------------------------------------------------------------------ + private: + std::unique_ptr pstream = nullptr; + std::unique_ptr header = nullptr; + std::vector> sections_; + std::vector> segments_; + endianess_convertor convertor; + address_translator addr_translator; + std::shared_ptr compression = nullptr; + + Elf_Xword current_file_pos = 0; +}; + +} // namespace ELFIO + +#include +#include +#include +#include +#include +#include +#include + +#endif // ELFIO_HPP diff --git a/include/elfio/elfio_array.hpp b/include/elfio/elfio_array.hpp new file mode 100644 index 0000000..190c075 --- /dev/null +++ b/include/elfio/elfio_array.hpp @@ -0,0 +1,88 @@ +/* +Copyright (C) 2001-present 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_ARRAY_HPP +#define ELFIO_ARRAY_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class array_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit array_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), array_section( section ) + { + } + + //------------------------------------------------------------------------------ + Elf_Xword get_entries_num() const + { + Elf_Xword entry_size = sizeof( T ); + return array_section->get_size() / entry_size; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, Elf64_Addr& address ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T temp = *reinterpret_cast( array_section->get_data() + + index * sizeof( T ) ); + address = convertor( temp ); + + return true; + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr address ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T temp = convertor( (T)address ); + array_section->append_data( reinterpret_cast( &temp ), + sizeof( temp ) ); + } + + private: + //------------------------------------------------------------------------------ + const elfio& elf_file; + S* array_section; +}; + +template +using array_section_accessor = array_section_accessor_template; +template +using const_array_section_accessor = + array_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_ARRAY_HPP diff --git a/include/elfio/elfio_dump.hpp b/include/elfio/elfio_dump.hpp new file mode 100644 index 0000000..3310511 --- /dev/null +++ b/include/elfio/elfio_dump.hpp @@ -0,0 +1,1346 @@ +/* +Copyright (C) 2001-present 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 + +namespace ELFIO { + +static const struct class_table_t +{ + const char key; + const char* str; +} class_table[] = { + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + +static const struct endian_table_t +{ + const char key; + const char* str; +} endian_table[] = { + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + +static const struct os_abi_table_t +{ + const unsigned char key; + const char* str; +} os_abi_table[] = { + { ELFOSABI_NONE, "UNIX System V" }, + { ELFOSABI_HPUX, "Hewlett-Packard HP-UX" }, + { ELFOSABI_NETBSD, "NetBSD" }, + { ELFOSABI_LINUX, "Linux" }, + { ELFOSABI_HURD, "GNU Hurd" }, + { ELFOSABI_SOLARIS, "Sun Solaris" }, + { ELFOSABI_AIX, "AIX" }, + { ELFOSABI_IRIX, "IRIX" }, + { ELFOSABI_FREEBSD, "FreeBSD" }, + { ELFOSABI_TRU64, "Compaq TRU64 UNIX" }, + { ELFOSABI_MODESTO, "Novell Modesto" }, + { ELFOSABI_OPENBSD, "Open BSD" }, + { ELFOSABI_OPENVMS, "Open VMS" }, + { ELFOSABI_NSK, "Hewlett-Packard Non-Stop Kernel" }, + { ELFOSABI_AROS, "Amiga Research OS" }, + { ELFOSABI_FENIXOS, "FenixOS" }, + { ELFOSABI_NUXI, "Nuxi CloudABI" }, + { ELFOSABI_OPENVOS, "OpenVOS" }, + { ELFOSABI_ARM, "ARM" }, + { ELFOSABI_STANDALONE, "Standalone (embedded)" }, +}; + +static const struct version_table_t +{ + const Elf64_Word key; + const char* str; +} version_table[] = { + { EV_NONE, "None" }, + { EV_CURRENT, "Current" }, +}; + +static const 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 const 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_AARCH64, "ARM AArch64" }, + { 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 " }, + { EM_TILEGX, "Tilera TILE-Gx multicore architecture family" }, + { EM_CLOUDSHIELD, "CloudShield architecture family" }, + { EM_COREA_1ST, "KIPO-KAIST Core-A 1st generation processor family" }, + { EM_COREA_2ND, "KIPO-KAIST Core-A 2nd generation processor family" }, + { EM_ARC_COMPACT2, "Synopsys ARCompact V2" }, + { EM_OPEN8, "Open8 8-bit RISC soft processor core" }, + { EM_RL78, "Renesas RL78 family" }, + { EM_VIDEOCORE5, "Broadcom VideoCore V processor" }, + { EM_78KOR, "Renesas 78KOR family" }, + { EM_56800EX, "Freescale 56800EX Digital Signal Controller (DSC)" }, + { EM_BA1, "Beyond BA1 CPU architecture" }, + { EM_BA2, "Beyond BA2 CPU architecture" }, + { EM_XCORE, "XMOS xCORE processor family" }, + { EM_MCHP_PIC, "Microchip 8-bit PIC(r) family" }, + { EM_INTEL205, "Reserved by Intel" }, + { EM_INTEL206, "Reserved by Intel" }, + { EM_INTEL207, "Reserved by Intel" }, + { EM_INTEL208, "Reserved by Intel" }, + { EM_INTEL209, "Reserved by Intel" }, + { EM_KM32, "KM211 KM32 32-bit processor" }, + { EM_KMX32, "KM211 KMX32 32-bit processor" }, + { EM_KMX16, "KM211 KMX16 16-bit processor" }, + { EM_KMX8, "KM211 KMX8 8-bit processor" }, + { EM_KVARC, "KM211 KVARC processor" }, + { EM_CDP, "Paneve CDP architecture family" }, + { EM_COGE, "Cognitive Smart Memory Processor" }, + { EM_COOL, "iCelero CoolEngine" }, + { EM_NORC, "Nanoradio Optimized RISC" }, + { EM_CSR_KALIMBA, "CSR Kalimba architecture family" }, + { EM_Z80, "Zilog Z80" }, + { EM_VISIUM, "Controls and Data Services VISIUMcore processor" }, + { EM_FT32, "FTDI Chip FT32 high performance 32-bit RISC architecture" }, + { EM_MOXIE, "Moxie processor family" }, + { EM_AMDGPU, "AMD GPU architecture" }, + { EM_RISCV, "RISC-V" }, + { EM_LANAI, "Lanai processor" }, + { EM_CEVA, "CEVA Processor Architecture Family" }, + { EM_CEVA_X2, "CEVA X2 Processor Family" }, + { EM_BPF, "Linux BPF – in-kernel virtual machine" }, + { EM_GRAPHCORE_IPU, "Graphcore Intelligent Processing Unit" }, + { EM_IMG1, "Imagination Technologies" }, + { EM_NFP, "Netronome Flow Processor (P)" }, + { EM_CSKY, "C-SKY processor family" }, + { EM_ARC_COMPACT3_64, "Synopsys ARCv2.3 64-bit" }, + { EM_MCS6502, "MOS Technology MCS 6502 processor" }, + { EM_ARC_COMPACT3, "Synopsys ARCv2.3 32-bit" }, + { EM_KVX, "Kalray VLIW core of the MPPA processor family" }, + { EM_65816, "WDC 65816/65C816" }, + { EM_LOONGARCH, "Loongson Loongarch" }, + { EM_KF32, "ChipON KungFu32" }, + { EM_MT, "Morpho Techologies MT processor" }, + { EM_ALPHA, "Alpha" }, + { EM_WEBASSEMBLY, "Web Assembly" }, + { EM_DLX, "OpenDLX" }, + { EM_XSTORMY16, "Sanyo XStormy16 CPU core" }, + { EM_IQ2000, "Vitesse IQ2000" }, + { EM_M32C_OLD, "M32C_OLD" }, + { EM_NIOS32, "Altera Nios" }, + { EM_CYGNUS_MEP, "Toshiba MeP Media Engine" }, + { EM_ADAPTEVA_EPIPHANY, "Adapteva EPIPHANY" }, + { EM_CYGNUS_FRV, "Fujitsu FR-V" }, + { EM_S12Z, "Freescale S12Z" }, +}; + +static const struct section_type_table_t +{ + const Elf64_Word 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" }, + { SHT_GNU_ATTRIBUTES, "GNU_ATTRIBUTES" }, + { SHT_GNU_HASH, "GNU_HASH" }, + { SHT_GNU_LIBLIST, "GNU_LIBLIST" }, + { SHT_CHECKSUM, "CHECKSUM" }, + { SHT_LOSUNW, "LOSUNW" }, + { SHT_SUNW_move, "SUNW_move" }, + { SHT_SUNW_COMDAT, "SUNW_COMDAT" }, + { SHT_SUNW_syminfo, "SUNW_syminfo" }, + { SHT_GNU_verdef, "GNU_verdef" }, + { SHT_GNU_verneed, "GNU_verneed" }, + { SHT_GNU_versym, "GNU_versym" }, + { SHT_ARM_EXIDX, "ARM_EXIDX" }, + { SHT_ARM_PREEMPTMAP, "ARM_PREEMPTMAP" }, + { SHT_ARM_ATTRIBUTES, "ARM_ATTRIBUTES" }, + { SHT_ARM_DEBUGOVERLAY, "ARM_DEBUGOVERLAY" }, + { SHT_ARM_OVERLAYSECTION, "ARM_OVERLAYSECTION" }, + +}; + +static const 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" }, + { PT_GNU_EH_FRAME, "GNU_EH_FRAME" }, + { PT_GNU_STACK, "GNU_STACK" }, + { PT_GNU_RELRO, "GNU_RELRO" }, + { PT_GNU_PROPERTY, "GNU_PROPERTY" }, + { PT_GNU_MBIND_LO, "GNU_MBIND_LO" }, + { PT_GNU_MBIND_HI, "GNU_MBIND_HI" }, + { PT_PAX_FLAGS, "PAX_FLAGS" }, + { PT_OPENBSD_RANDOMIZE, "OPENBSD_RANDOMIZE" }, + { PT_OPENBSD_WXNEEDED, "OPENBSD_WXNEEDED " }, + { PT_OPENBSD_BOOTDATA, "OPENBSD_BOOTDATA " }, + { PT_SUNWBSS, "PT_SUNWBSS" }, + { PT_SUNWSTACK, "SUNWSTACK" }, +}; + +static const struct segment_flag_table_t +{ + const Elf_Word key; + const char* str; +} segment_flag_table[] = { + { 0, " " }, { 1, " E" }, { 2, " W " }, { 3, " WE" }, + { 4, "R " }, { 5, "R E" }, { 6, "RW " }, { 7, "RWE" }, +}; + +static const 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 const 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 const 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" }, + { DT_GNU_HASH, "GNU_HASH" }, + { DT_TLSDESC_PLT, "TLSDESC_PLT" }, + { DT_TLSDESC_GOT, "TLSDESC_GOT" }, + { DT_GNU_CONFLICT, "GNU_CONFLICT" }, + { DT_GNU_LIBLIST, "GNU_LIBLIST" }, + { DT_CONFIG, "CONFIG" }, + { DT_DEPAUDIT, "DEPAUDIT" }, + { DT_AUDIT, "AUDIT" }, + { DT_PLTPAD, "PLTPAD" }, + { DT_MOVETAB, "MOVETAB" }, + { DT_SYMINFO, "SYMINFO" }, + { DT_ADDRRNGHI, "ADDRRNGHI" }, + { DT_VERSYM, "VERSYM" }, + { DT_RELACOUNT, "RELACOUNT" }, + { DT_RELCOUNT, "RELCOUNT" }, + { DT_FLAGS_1, "FLAGS_1" }, + { DT_VERDEF, "VERDEF" }, + { DT_VERDEFNUM, "VERDEFNUM" }, + { DT_VERNEED, "VERNEED" }, + { DT_VERNEEDNUM, "VERNEEDNUM" }, +}; + +// clang-format off +static const struct note_tag_t +{ + struct note_values_t + { + Elf64_Word type; + std::string type_str; + std::string description; + }; + std::string name; + std::vector values; +} note_tag_table[] = { + { "", + { { NT_PRSTATUS, "NT_PRSTATUS", "prstatus struct" }, + { NT_FPREGSET, "NT_FPREGSET", "fpregset struct" }, + { NT_PRPSINFO, "NT_PRPSINFO", "prpsinfo struct" }, + { NT_TASKSTRUCT, "NT_TASKSTRUCT", "task struct" }, + { NT_AUXV, "NT_AUXV", "Elfxx_auxv_t" }, + { NT_PSTATUS, "NT_PSTATUS", "pstatus struct" }, + { NT_FPREGS, "NT_FPREGS", "fpregset struct" }, + { NT_PSINFO, "NT_PSINFO", "psinfo struct" }, + { NT_LWPSTATUS, "NT_LWPSTATUS", "lwpstatus_t struct" }, + { NT_LWPSINFO, "NT_LWPSINFO", "lwpsinfo_t struct" }, + { NT_WIN32PSTATUS, "NT_WIN32PSTATUS", "win32_pstatus struct" }, + } }, + { "LINUX", + { { NT_PRXFPREG, "NT_PRXFPREG", "Contains a user_xfpregs_struct;" }, + { NT_PPC_VMX, "NT_PPC_VMX", "PowerPC Altivec/VMX registers" }, + { NT_PPC_VSX, "NT_PPC_VSX", "PowerPC VSX registers" }, + { NT_PPC_TAR, "NT_PPC_TAR", "PowerPC Target Address Register" }, + { NT_PPC_PPR, "NT_PPC_PPR", "PowerPC Program Priority Register" }, + { NT_PPC_DSCR, "NT_PPC_DSCR", "PowerPC Data Stream Control Register" }, + { NT_PPC_EBB, "NT_PPC_EBB", "PowerPC Event Based Branch Registers" }, + { NT_PPC_PMU, "NT_PPC_PMU", "PowerPC Performance Monitor Registers" }, + { NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR", "PowerPC TM checkpointed GPR Registers" }, + { NT_PPC_TM_CFPR, "NT_PPC_TM_CFPR", "PowerPC TM checkpointed FPR Registers" }, + { NT_PPC_TM_CVMX, "NT_PPC_TM_CVMX", "PowerPC TM checkpointed VMX Registers" }, + { NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX", "PowerPC TM checkpointed VSX Registers" }, + { NT_PPC_TM_SPR, "NT_PPC_TM_SPR", "PowerPC TM Special Purpose Registers" }, + { NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR", "PowerPC TM checkpointed TAR" }, + { NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR", "PowerPC TM checkpointed PPR" }, + { NT_PPC_TM_CDSCR, "NT_PPC_TM_CDSCR", "PowerPC TM checkpointed Data SCR" }, + { NT_386_TLS, "NT_386_TLS", "x86 TLS information" }, + { NT_386_IOPERM, "NT_386_IOPERM", "x86 io permissions" }, + { NT_X86_XSTATE, "NT_X86_XSTATE", "x86 XSAVE extended state" }, + { NT_X86_CET, "NT_X86_CET", "x86 CET state" }, + { NT_S390_HIGH_GPRS, "NT_S390_HIGH_GPRS", "S/390 upper halves of GPRs " }, + { NT_S390_TIMER, "NT_S390_TIMER", "S390 timer" }, + { NT_S390_TODCMP, "NT_S390_TODCMP", "S390 TOD clock comparator" }, + { NT_S390_TODPREG, "NT_S390_TODPREG", "S390 TOD programmable register" }, + { NT_S390_CTRS, "NT_S390_CTRS", "S390 control registers" }, + { NT_S390_PREFIX, "NT_S390_PREFIX", "S390 prefix register" }, + { NT_S390_LAST_BREAK, "NT_S390_LAST_BREAK", "S390 breaking event address" }, + { NT_S390_SYSTEM_CALL, "NT_S390_SYSTEM_CALL", "S390 system call restart data" }, + { NT_S390_TDB, "NT_S390_TDB", "S390 transaction diagnostic block" }, + { NT_S390_VXRS_LOW, "NT_S390_VXRS_LOW", "S390 vector registers 0-15 upper half" }, + { NT_S390_VXRS_HIGH, "NT_S390_VXRS_HIGH", "S390 vector registers 16-31" }, + { NT_S390_GS_CB, "NT_S390_GS_CB", "s390 guarded storage registers" }, + { NT_S390_GS_BC, "NT_S390_GS_BC", "s390 guarded storage broadcast control block" }, + { NT_ARM_VFP, "NT_ARM_VFP", "ARM VFP registers" }, + { NT_ARM_TLS, "NT_ARM_TLS", "AArch TLS registers" }, + { NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK", "AArch hardware breakpoint registers" }, + { NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH", "AArch hardware watchpoint registers" }, + { NT_ARM_SVE, "NT_ARM_SVE", "AArch SVE registers. " }, + { NT_ARM_PAC_MASK, "NT_ARM_PAC_MASK", "AArch pointer authentication code masks" }, + { NT_ARM_PACA_KEYS, "NT_ARM_PACA_KEYS", "ARM pointer authentication address keys" }, + { NT_ARM_PACG_KEYS, "NT_ARM_PACG_KEYS", "ARM pointer authentication generic keys" }, + { NT_ARM_TAGGED_ADDR_CTRL, "NT_ARM_TAGGED_ADDR_CTRL", "AArch64 tagged address control (prctl())" }, + { NT_ARM_PAC_ENABLED_KEYS, "NT_ARM_PAC_ENABLED_KEYS", "AArch64 pointer authentication enabled keys (prctl())" }, + { NT_ARC_V2, "NT_ARC_V2", "ARC HS accumulator/extra registers. " }, + { NT_LARCH_CPUCFG, "NT_LARCH_CPUCFG", "LoongArch CPU config registers" }, + { NT_LARCH_CSR, "NT_LARCH_CSR", "LoongArch Control State Registers" }, + { NT_LARCH_LSX, "NT_LARCH_LSX", "LoongArch SIMD eXtension registers" }, + { NT_LARCH_LASX, "NT_LARCH_LASX", "LoongArch Advanced SIMD eXtension registers" }, + { NT_RISCV_CSR, "NT_RISCV_CSR", "RISC-V Control and Status Registers" }, + } }, + { "CORE", + { { NT_LARCH_LBT, "NT_LARCH_LBT", "LoongArch Binary Translation registers" } + } }, + { "FreeBSD", + { { NT_FREEBSD_THRMISC, "NT_FREEBSD_THRMISC", "Thread miscellaneous info." }, + { NT_FREEBSD_PROCSTAT_PROC, "NT_FREEBSD_PROCSTAT_PROC", "Procstat proc data." }, + { NT_FREEBSD_PROCSTAT_FILES, "NT_FREEBSD_PROCSTAT_FILES", "Procstat files data." }, + { NT_FREEBSD_PROCSTAT_VMMAP, "NT_FREEBSD_PROCSTAT_VMMAP", "Procstat vmmap data." }, + { NT_FREEBSD_PROCSTAT_GROUPS, "NT_FREEBSD_PROCSTAT_GROUPS", "Procstat groups data." }, + { NT_FREEBSD_PROCSTAT_UMASK, "NT_FREEBSD_PROCSTAT_UMASK", "Procstat umask data." }, + { NT_FREEBSD_PROCSTAT_RLIMIT, "NT_FREEBSD_PROCSTAT_RLIMIT", "Procstat rlimit data." }, + { NT_FREEBSD_PROCSTAT_OSREL, "NT_FREEBSD_PROCSTAT_OSREL", "Procstat osreldate data." }, + { NT_FREEBSD_PROCSTAT_PSSTRINGS, "NT_FREEBSD_PROCSTAT_PSSTRINGS", "Procstat ps_strings data." }, + { NT_FREEBSD_PROCSTAT_AUXV, "NT_FREEBSD_PROCSTAT_AUXV", "Procstat auxv data." }, + { NT_FREEBSD_PTLWPINFO, "NT_FREEBSD_PTLWPINFO", "Thread ptrace miscellaneous info." }, + } }, + { "NetBSD-CORE", + { { NT_NETBSDCORE_PROCINFO, "NT_NETBSDCORE_PROCINFO", "Has a struct procinfo" }, + { NT_NETBSDCORE_AUXV, "NT_NETBSDCORE_AUXV", "Has auxv data" }, + { NT_NETBSDCORE_LWPSTATUS, "NT_NETBSDCORE_LWPSTATUS", "Has LWPSTATUS data" }, + { NT_NETBSDCORE_FIRSTMACH, "NT_NETBSDCORE_FIRSTMACH", "start of machdep note types" }, + } }, + { "OpenBSD", + { { NT_OPENBSD_PROCINFO, "NT_OPENBSD_PROCINFO", "" }, + { NT_OPENBSD_AUXV, "NT_OPENBSD_AUXV", "" }, + { NT_OPENBSD_REGS, "NT_OPENBSD_REGS", "" }, + { NT_OPENBSD_FPREGS, "NT_OPENBSD_FPREGS", "" }, + { NT_OPENBSD_XFPREGS, "NT_OPENBSD_XFPREGS", "" }, + { NT_OPENBSD_WCOOKIE, "NT_OPENBSD_WCOOKIE", "" }, + } }, + { "SPU", + { { NT_SPU, "NT_SPU", "" } + } }, + { "GNU", + { + { NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG", "GNU ABI tag" }, + { NT_GNU_HWCAP, "NT_GNU_HWCAP", "Used by ld.so and kernel vDSO" }, + { NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID", "Build ID of the binary" }, + { NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION", "Version of GNU gold used to link the binary" }, + { NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0", "Property type 0" }, + // { NT_GNU_PROPERTY_TYPE_1, "NT_GNU_PROPERTY_TYPE_1", "Property type 1" }, + // { NT_GNU_PROPERTY_TYPE_2, "NT_GNU_PROPERTY_TYPE_2", "Property type 2" }, + // { NT_GNU_PROPERTY_TYPE_3, "NT_GNU_PROPERTY_TYPE_3", "Property type 3" }, + // { NT_GNU_PROPERTY_TYPE_4, "NT_GNU_PROPERTY_TYPE_4", "Property type 4" }, + // { NT_GNU_PROPERTY_TYPE_5, "NT_GNU_PROPERTY_TYPE_5", "Property type 5" }, + // { NT_GNU_PROPERTY_TYPE_6, "NT_GNU_PROPERTY_TYPE_6", "Property type 6" }, + // { NT_GNU_PROPERTY_TYPE_7, "NT_GNU_PROPERTY_TYPE_7", "Property type 7" }, + // { NT_GNU_PROPERTY_TYPE_8, "NT_GNU_PROPERTY_TYPE_8", "Property type 8" }, + // { NT_GNU_PROPERTY_TYPE_9, "NT_GNU_PROPERTY_TYPE_9", "Property type 9" }, + // { NT_GNU_PROPERTY_TYPE_10, "NT_GNU_PROPERTY_TYPE_10", "Property type 10" }, + // { NT_GNU_PROPERTY_TYPE_11, "NT_GNU_PROPERTY_TYPE_11", "Property type 11" }, + // { NT_GNU_PROPERTY_TYPE_12, "NT_GNU_PROPERTY_TYPE_12", "Property type 12" }, + // { NT_GNU_PROPERTY_TYPE_13, "NT_GNU_PROPERTY_TYPE_13", "Property type 13" }, + // { NT_GNU_PROPERTY_TYPE_14, "NT_GNU_PROPERTY_TYPE_14", "Property type 14" }, + } }, + // { "SOLARIS", + // { { NT_SOLARIS_AUXV, "NT_SOLARIS_AUXV", "" } + // } }, + // { "AIX", + // { { NT_AIX_AUXV, "NT_AIX_AUXV", "" } + // } }, + // { "IRIX", + // { { NT_IRIX_FPREGS, "NT_IRIX_FPREGS", "" } + // } }, +}; +// clang-format on + +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_HEX0x_FORMAT( width ) \ + "0x" << std::setw( width ) << std::setfill( '0' ) << std::hex << 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 ) + { + if ( !reader.get_header_size() ) { + return; + } + 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 + << " OS/ABI: " << str_os_abi( reader.get_os_abi() ) + << std::endl + << " ABI Version:" << (int)reader.get_abi_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 " + " Offset Flg" + << std::endl + << " ES Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + const section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute), " << std::endl; + out << " M (merge), S (strings), I (info)," << std::endl; + out << " L (link order), O (extra OS processing required)," + << std::endl; + out << " G (group), T (TLS), C (compressed), E (exclude)" + << 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(); + + // clang-format off + 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_HEX0x_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX0x_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_HEX0x_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_offset() << " " + << DUMP_STR_FORMAT( 3) << section_flags( sec->get_flags() ) + << std::endl + << DUMP_STR_FORMAT( 8 ) << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() + << std::endl; + } + // clang-format on + + 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 << "Program 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 Offset VirtAddr " + " PhysAddr" + + << std::endl + << " FileSize MemSize " + " Flags Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + const 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(); + // clang-format off + 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_HEX0x_FORMAT( 8 ) << seg->get_virtual_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_physical_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) + << " " << DUMP_HEX0x_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_HEX0x_FORMAT( 16 ) << seg->get_offset() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_physical_address() + << std::endl + << DUMP_STR_FORMAT( 23 ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 3 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX0x_FORMAT( 1 ) << seg->get_align() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + static void symbol_tables( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_SYMTAB == sec->get_type() || + SHT_DYNSYM == sec->get_type() ) { + const_symbol_section_accessor symbols( reader, sec.get() ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no == 0 ) { + continue; + } + + 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_Xword 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_Xword no, + const 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_HEX0x_FORMAT( 8 ) << value << " " + << DUMP_HEX0x_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_HEX0x_FORMAT( 16 ) << value << " " + << DUMP_HEX0x_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 ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec.get() ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note section (" << sec->get_name() << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + + Elf_Half no = reader.segments.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all segments + segment* seg = reader.segments[i]; + if ( PT_NOTE == seg->get_type() ) { // Look at notes + note_segment_accessor notes( reader, seg ); + Elf_Word no_notes = notes.get_notes_num(); + + if ( no_notes == 0 ) + continue; + + out << "Note segment (" << i << ")" << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + char* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + } + + //------------------------------------------------------------------------------ + static void note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name, + void* desc, + Elf_Word descsz ) + { + out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] "; + + const auto name_group = std::find_if( + std::begin( note_tag_table ), std::end( note_tag_table ), + [&name]( const note_tag_t& entry ) { return entry.name == name; } ); + + std::vector::const_iterator type_value; + if ( name_group != std::end( note_tag_table ) ) { + type_value = std::find_if( + name_group->values.begin(), name_group->values.end(), + [&type]( const note_tag_t::note_values_t& e ) { + return e.type == type; + } ); + } + + if ( name_group != std::end( note_tag_table ) && + type_value != name_group->values.end() ) { + out << DUMP_STR_FORMAT( 12 ) << name_group->name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << type_value->type_str << " (" << type_value->description + << ")"; + } + else { + out << DUMP_STR_FORMAT( 12 ) << name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << DUMP_HEX0x_FORMAT( 8 ) << type; + } + + if ( descsz != 0 ) { + for ( Elf_Word i = 0; i < descsz; ++i ) { + if ( i % 16 == 0 ) { + out << std::endl << " "; + } + out << DUMP_HEX_FORMAT( 2 ) + << (uint32_t)( (uint8_t*)( desc ) )[i]; + } + } + } + + //------------------------------------------------------------------------------ + static void modinfo( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( ".modinfo" == sec->get_name() ) { // Look for the section + out << "Section .modinfo" << std::endl; + + const_modinfo_section_accessor modinfo( sec.get() ); + for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { + std::string field; + std::string value; + if ( modinfo.get_attribute( i, field, value ) ) { + out << " " << std::setw( 20 ) << field + << std::setw( 0 ) << " = " << value << std::endl; + } + } + + out << std::endl; + break; + } + } + } + + //------------------------------------------------------------------------------ + static void dynamic_tags( std::ostream& out, const elfio& reader ) + { + for ( const auto& sec : reader.sections ) { // For all sections + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec.get() ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no == 0 ) + continue; + + out << "Dynamic section (" << sec->get_name() << ")" + << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( Elf_Xword 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, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + const 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_HEX0x_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_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_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 + const 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_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_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 + const segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template 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( os_abi ) + 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 + + private: + //------------------------------------------------------------------------------ + template + 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 + 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 + 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"; + } + if ( flags & SHF_MERGE ) { + ret += "M"; + } + if ( flags & SHF_STRINGS ) { + ret += "S"; + } + if ( flags & SHF_INFO_LINK ) { + ret += "I"; + } + if ( flags & SHF_LINK_ORDER ) { + ret += "L"; + } + if ( flags & SHF_OS_NONCONFORMING ) { + ret += "O"; + } + if ( flags & SHF_GROUP ) { + ret += "G"; + } + if ( flags & SHF_TLS ) { + ret += "T"; + } + if ( flags & SHF_COMPRESSED ) { + ret += "C"; + } + if ( flags & SHF_EXCLUDE ) { + ret += "E"; + } + if ( flags & SHF_GNU_MBIND ) { + ret += "D"; + } + + return ret; + } + +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX0x_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump +} // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/include/elfio/elfio_dynamic.hpp b/include/elfio/elfio_dynamic.hpp new file mode 100644 index 0000000..035e67d --- /dev/null +++ b/include/elfio/elfio_dynamic.hpp @@ -0,0 +1,274 @@ +/* +Copyright (C) 2001-present 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 + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class dynamic_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit dynamic_section_accessor_template( const elfio& elf_file, + S* section ) + : elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) + { + } + + //------------------------------------------------------------------------------ + Elf_Xword get_entries_num() const + { + size_t needed_entry_size = -1; + if ( elf_file.get_class() == ELFCLASS32 ) { + needed_entry_size = sizeof( Elf32_Dyn ); + } + else { + needed_entry_size = sizeof( Elf64_Dyn ); + } + + if ( ( 0 == entries_num ) && + ( 0 != dynamic_section->get_entry_size() && + dynamic_section->get_entry_size() >= needed_entry_size ) ) { + entries_num = + dynamic_section->get_size() / dynamic_section->get_entry_size(); + Elf_Xword i; + Elf_Xword tag = DT_NULL; + Elf_Xword value = 0; + std::string str; + for ( i = 0; i < entries_num; i++ ) { + get_entry( i, tag, value, str ); + if ( tag == DT_NULL ) + break; + } + entries_num = std::min( entries_num, i + 1 ); + } + + return entries_num; + } + + //------------------------------------------------------------------------------ + 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( index, tag, value ); + } + else { + generic_get_entry_dyn( index, tag, value ); + } + + // If the tag has 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( (Elf_Word)value ); + if ( nullptr == 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_dyn( tag, value ); + } + else { + generic_add_entry_dyn( tag, value ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf_Xword tag, const 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 + 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() == nullptr || + ( index + 1 ) * dynamic_section->get_entry_size() > + dynamic_section->get_size() || + dynamic_section->get_entry_size() < sizeof( T ) ) { + 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 + void generic_add_entry_dyn( 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: + entry.d_un.d_val = convertor( decltype( entry.d_un.d_val )( 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: + entry.d_un.d_val = + convertor( decltype( entry.d_un.d_val )( 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( decltype( entry.d_un.d_val )( value ) ); + break; + } + + entry.d_tag = convertor( decltype( entry.d_tag )( tag ) ); + + dynamic_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* dynamic_section; + mutable Elf_Xword entries_num; +}; + +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = + dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/include/elfio/elfio_header.hpp b/include/elfio/elfio_header.hpp new file mode 100644 index 0000000..eccae13 --- /dev/null +++ b/include/elfio/elfio_header.hpp @@ -0,0 +1,153 @@ +/* +Copyright (C) 2001-present 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() = default; + + 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_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( Elf_Word, version ); + 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 struct elf_header_impl_types; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf32_Phdr; + using Shdr_type = Elf32_Shdr; + static const unsigned char file_class = ELFCLASS32; +}; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf64_Phdr; + using Shdr_type = Elf64_Shdr; + static const unsigned char file_class = ELFCLASS64; +}; + +template class elf_header_impl : public elf_header +{ + public: + //------------------------------------------------------------------------------ + elf_header_impl( endianess_convertor* convertor, + unsigned char encoding, + const address_translator* translator ) + : convertor( convertor ), translator( translator ) + { + 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 = ( *convertor )( (Elf_Word)EV_CURRENT ); + 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 ) override + { + stream.seekg( ( *translator )[0] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return ( stream.gcount() == sizeof( header ) ); + } + + //------------------------------------------------------------------------------ + bool save( std::ostream& stream ) const override + { + stream.seekp( ( *translator )[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_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( Elf_Word, version, header.e_version ); + 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 = nullptr; + const address_translator* translator = nullptr; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/include/elfio/elfio_modinfo.hpp b/include/elfio/elfio_modinfo.hpp new file mode 100644 index 0000000..2d42ba3 --- /dev/null +++ b/include/elfio/elfio_modinfo.hpp @@ -0,0 +1,124 @@ +/* +Copyright (C) 2001-present 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_MODINFO_HPP +#define ELFIO_MODINFO_HPP + +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class modinfo_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit modinfo_section_accessor_template( S* section ) + : modinfo_section( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } + + //------------------------------------------------------------------------------ + bool + get_attribute( Elf_Word no, std::string& field, std::string& value ) const + { + if ( no < content.size() ) { + field = content[no].first; + value = content[no].second; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool get_attribute( const std::string_view& field_name, + std::string& value ) const + { + for ( const auto [first, second] : content ) { + if ( field_name == first ) { + value = second; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + Elf_Word add_attribute( const std::string& field, const std::string& value ) + { + Elf_Word current_position = 0; + + if ( modinfo_section ) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)modinfo_section->get_size(); + + std::string attribute = field + "=" + value; + + modinfo_section->append_data( attribute + '\0' ); + content.emplace_back( field, value ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + private: + void process_section() + { + const char* pdata = modinfo_section->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i = 0; + while ( i < modinfo_section->get_size() ) { + while ( i < modinfo_section->get_size() && !pdata[i] ) + i++; + if ( i < modinfo_section->get_size() ) { + std::string info = pdata + i; + size_t loc = info.find( '=' ); + content.emplace_back( info.substr( 0, loc ), + info.substr( loc + 1 ) ); + + i += info.length(); + } + } + } + } + + //------------------------------------------------------------------------------ + private: + S* modinfo_section; + std::vector> content; +}; + +using modinfo_section_accessor = modinfo_section_accessor_template
; +using const_modinfo_section_accessor = + modinfo_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_MODINFO_HPP diff --git a/include/elfio/elfio_note.hpp b/include/elfio/elfio_note.hpp new file mode 100644 index 0000000..63ef102 --- /dev/null +++ b/include/elfio/elfio_note.hpp @@ -0,0 +1,184 @@ +/* +Copyright (C) 2001-present 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 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template +class note_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit note_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), notes( 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, + char*& desc, + Elf_Word& descSize ) const + { + if ( index >= ( notes->*F_get_size )() ) { + return false; + } + + const char* pData = notes->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); + Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); + descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + + Elf_Xword max_name_size = + ( notes->*F_get_size )() - note_start_positions[index]; + if ( namesz < 1 || namesz > max_name_size || + (Elf_Xword)namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3 * (size_t)align, namesz - 1 ); + if ( 0 == descSize ) { + desc = nullptr; + } + else { + desc = const_cast( pData + 3 * (size_t)align + + ( ( namesz + align - 1 ) / align ) * + (size_t)align ); + } + + return true; + } + + //------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const char* 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, (size_t)align - nameLen % align ); + } + if ( desc != nullptr && descSize != 0 ) { + buffer.append( desc, descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, (size_t)align - descSize % align ); + } + } + + note_start_positions.emplace_back( ( notes->*F_get_size )() ); + notes->append_data( buffer ); + } + + private: + //------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = notes->get_data(); + Elf_Xword size = ( notes->*F_get_size )(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( nullptr == data || 0 == size ) { + return; + } + + Elf_Word align = sizeof( Elf_Word ); + while ( current + (Elf_Xword)3 * align <= size ) { + Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + Elf_Word advance = + (Elf_Xword)3 * sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; + if ( namesz < size && descsz < size && current + advance <= size ) { + note_start_positions.emplace_back( current ); + } + else { + break; + } + + current += advance; + } + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* notes; + std::vector note_start_positions; +}; + +using note_section_accessor = + note_section_accessor_template; +using const_note_section_accessor = + note_section_accessor_template; +using note_segment_accessor = + note_section_accessor_template; +using const_note_segment_accessor = + note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/include/elfio/elfio_relocation.hpp b/include/elfio/elfio_relocation.hpp new file mode 100644 index 0000000..2f39a36 --- /dev/null +++ b/include/elfio/elfio_relocation.hpp @@ -0,0 +1,460 @@ +/* +Copyright (C) 2001-present 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 +{ + 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 +{ + 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 +{ + 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 +{ + 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 class relocation_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit relocation_section_accessor_template( const elfio& elf_file, + S* 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, + unsigned& 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( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + unsigned& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol = 0; + 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; + } + + //------------------------------------------------------------------------------ + bool set_entry( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info ); + } + else { + generic_add_entry( offset, info ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned 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( offset, info, addend ); + } + else { + generic_add_entry( offset, info, addend ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, + Elf_Word symbol, + unsigned 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 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 ); + } + + //------------------------------------------------------------------------------ + void swap_symbols( Elf_Xword first, Elf_Xword second ) + { + Elf64_Addr offset = 0; + Elf_Word symbol = 0; + unsigned rtype = 0; + Elf_Sxword addend = 0; + for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { + get_entry( i, offset, symbol, rtype, addend ); + if ( symbol == first ) { + set_entry( i, offset, (Elf_Word)second, rtype, addend ); + } + if ( symbol == second ) { + set_entry( i, offset, (Elf_Word)first, rtype, addend ); + } + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + Elf_Half get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + + //------------------------------------------------------------------------------ + template + void generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& 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 + void generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned& 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 + void generic_set_entry_rel( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_offset = convertor( pEntry->r_offset ); + pEntry->r_info = convertor( pEntry->r_info ); + } + + //------------------------------------------------------------------------------ + template + void generic_set_entry_rela( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned type, + Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = decltype( pEntry->r_offset )( offset ); + pEntry->r_addend = decltype( pEntry->r_addend )( addend ); + pEntry->r_offset = convertor( pEntry->r_offset ); + pEntry->r_info = convertor( pEntry->r_info ); + pEntry->r_addend = convertor( pEntry->r_addend ); + } + + //------------------------------------------------------------------------------ + template + void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = decltype( entry.r_offset )( offset ); + entry.r_info = decltype( 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 + 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; + S* relocation_section = nullptr; +}; + +using relocation_section_accessor = + relocation_section_accessor_template
; +using const_relocation_section_accessor = + relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/include/elfio/elfio_section.hpp b/include/elfio/elfio_section.hpp new file mode 100644 index 0000000..8c6aed4 --- /dev/null +++ b/include/elfio/elfio_section.hpp @@ -0,0 +1,367 @@ +/* +Copyright (C) 2001-present 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 +#include +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + + public: + virtual ~section() = default; + + 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 ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + virtual void set_data( const char* raw_data, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* raw_data, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + virtual void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) = 0; + virtual void insert_data( Elf_Xword pos, const std::string& data ) = 0; + virtual size_t get_stream_size() const = 0; + virtual void set_stream_size( size_t value ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + +template class section_impl : public section +{ + public: + //------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor, + const address_translator* translator, + const std::shared_ptr& compression ) + : convertor( convertor ), translator( translator ), + compression( compression ) + { + } + + //------------------------------------------------------------------------------ + // 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 override { return index; } + + //------------------------------------------------------------------------------ + std::string get_name() const override { return name; } + + //------------------------------------------------------------------------------ + void set_name( const std::string& name_prm ) override + { + this->name = name_prm; + } + + //------------------------------------------------------------------------------ + void set_address( const Elf64_Addr& value ) override + { + header.sh_addr = decltype( header.sh_addr )( value ); + header.sh_addr = ( *convertor )( header.sh_addr ); + is_address_set = true; + } + + //------------------------------------------------------------------------------ + bool is_address_initialized() const override { return is_address_set; } + + //------------------------------------------------------------------------------ + const char* get_data() const override + { + if ( is_lazy ) { + load_data(); + } + return data.get(); + } + + //------------------------------------------------------------------------------ + void set_data( const char* raw_data, Elf_Word size ) override + { + if ( get_type() != SHT_NOBITS ) { + data = std::unique_ptr( new ( std::nothrow ) char[size] ); + if ( nullptr != data.get() && nullptr != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data.get() ); + } + else { + data_size = 0; + } + } + + set_size( data_size ); + if ( translator->empty() ) { + set_stream_size( data_size ); + } + } + + //------------------------------------------------------------------------------ + void set_data( const std::string& str_data ) override + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + //------------------------------------------------------------------------------ + void append_data( const char* raw_data, Elf_Word size ) override + { + insert_data( get_size(), raw_data, size ); + } + + //------------------------------------------------------------------------------ + void append_data( const std::string& str_data ) override + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + //------------------------------------------------------------------------------ + void + insert_data( Elf_Xword pos, const char* raw_data, Elf_Word size ) override + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + char* d = data.get(); + std::copy_backward( d + pos, d + get_size(), + d + get_size() + size ); + std::copy( raw_data, raw_data + size, d + pos ); + } + else { + data_size = 2 * ( data_size + size ); + std::unique_ptr new_data( + new ( std::nothrow ) char[data_size] ); + + if ( nullptr != new_data ) { + char* d = data.get(); + std::copy( d, d + pos, new_data.get() ); + std::copy( raw_data, raw_data + size, + new_data.get() + pos ); + std::copy( d + pos, d + get_size(), + new_data.get() + pos + size ); + data = std::move( new_data ); + } + else { + size = 0; + } + } + set_size( get_size() + size ); + if ( translator->empty() ) { + set_stream_size( get_stream_size() + size ); + } + } + } + + //------------------------------------------------------------------------------ + void insert_data( Elf_Xword pos, const std::string& str_data ) override + { + return insert_data( pos, str_data.c_str(), (Elf_Word)str_data.size() ); + } + + size_t get_stream_size() const override { return stream_size; } + + //------------------------------------------------------------------------------ + void set_stream_size( size_t value ) override { stream_size = value; } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + + //------------------------------------------------------------------------------ + void set_index( const Elf_Half& value ) override { index = value; } + + bool is_compressed() const + { + return ( ( get_flags() & SHF_RPX_DEFLATE ) || + ( get_flags() & SHF_COMPRESSED ) ) && + compression != nullptr; + } + + //------------------------------------------------------------------------------ + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + if ( !is_lazy || is_compressed() ) { + + bool ret = load_data(); + + if ( is_compressed() ) { + Elf_Xword size = get_size(); + Elf_Xword uncompressed_size = 0; + auto decompressed_data = compression->inflate( + data.get(), convertor, size, uncompressed_size ); + if ( decompressed_data != nullptr ) { + set_size( uncompressed_size ); + data = std::move( decompressed_data ); + } + } + + return ret; + } + + return true; + } + + bool load_data() const + { + is_lazy = false; + Elf_Xword size = get_size(); + if ( nullptr == data && SHT_NULL != get_type() && + SHT_NOBITS != get_type() && size < get_stream_size() ) { + data.reset( new ( std::nothrow ) char[size_t( size ) + 1] ); + + if ( ( 0 != size ) && ( nullptr != data ) ) { + pstream->seekg( + ( *translator )[( *convertor )( header.sh_offset )] ); + pstream->read( data.get(), size ); + if ( static_cast( pstream->gcount() ) != size ) { + data = nullptr; + return false; + } + + // refresh size because it may have changed if we had to decompress data + size = get_size(); + data.get()[size] = + 0; // Ensure data is ended with 0 to avoid oob read + data_size = decltype( data_size )( size ); + } + else { + data_size = 0; + } + } + + return true; + } + + //------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + if ( 0 != get_index() ) { + header.sh_offset = decltype( header.sh_offset )( data_offset ); + header.sh_offset = ( *convertor )( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != nullptr ) { + save_data( stream, data_offset ); + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + void save_header( std::ostream& stream, std::streampos header_offset ) const + { + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + } + + //------------------------------------------------------------------------------ + void save_data( std::ostream& stream, std::streampos data_offset ) + { + adjust_stream_size( stream, data_offset ); + + if ( ( ( get_flags() & SHF_COMPRESSED ) || + ( get_flags() & SHF_RPX_DEFLATE ) ) && + compression != nullptr ) { + Elf_Xword decompressed_size = get_size(); + Elf_Xword compressed_size = 0; + auto compressed_ptr = compression->deflate( + data.get(), convertor, decompressed_size, compressed_size ); + stream.write( compressed_ptr.get(), compressed_size ); + } + else { + stream.write( get_data(), get_size() ); + } + } + + //------------------------------------------------------------------------------ + private: + mutable std::istream* pstream = nullptr; + T header = {}; + Elf_Half index = 0; + std::string name; + mutable std::unique_ptr data; + mutable Elf_Word data_size = 0; + const endianess_convertor* convertor = nullptr; + const address_translator* translator = nullptr; + const std::shared_ptr compression = nullptr; + bool is_address_set = false; + size_t stream_size = 0; + mutable bool is_lazy = false; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/include/elfio/elfio_segment.hpp b/include/elfio/elfio_segment.hpp new file mode 100644 index 0000000..6b0f81d --- /dev/null +++ b/include/elfio/elfio_segment.hpp @@ -0,0 +1,254 @@ +/* +Copyright (C) 2001-present 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 +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + + public: + virtual ~segment() = default; + + 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( section* psec, Elf_Xword addr_align ) = 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 bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + +//------------------------------------------------------------------------------ +template class segment_impl : public segment +{ + public: + //------------------------------------------------------------------------------ + segment_impl( const endianess_convertor* convertor, + const address_translator* translator ) + : convertor( convertor ), translator( translator ) + { + } + + //------------------------------------------------------------------------------ + // 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 override { return index; } + + //------------------------------------------------------------------------------ + const char* get_data() const override + { + if ( is_lazy ) { + load_data(); + } + return data.get(); + } + + //------------------------------------------------------------------------------ + Elf_Half add_section_index( Elf_Half sec_index, + Elf_Xword addr_align ) override + { + sections.emplace_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + Elf_Half add_section( section* psec, Elf_Xword addr_align ) override + { + return add_section_index( psec->get_index(), addr_align ); + } + + //------------------------------------------------------------------------------ + Elf_Half get_sections_num() const override + { + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + Elf_Half get_section_index_at( Elf_Half num ) const override + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half( -1 ); + } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + + //------------------------------------------------------------------------------ + void set_offset( const Elf64_Off& value ) override + { + ph.p_offset = decltype( ph.p_offset )( value ); + ph.p_offset = ( *convertor )( ph.p_offset ); + is_offset_set = true; + } + + //------------------------------------------------------------------------------ + bool is_offset_initialized() const override { return is_offset_set; } + + //------------------------------------------------------------------------------ + const std::vector& get_sections() const override + { + return sections; + } + + //------------------------------------------------------------------------------ + void set_index( const Elf_Half& value ) override { index = value; } + + //------------------------------------------------------------------------------ + bool load( std::istream& stream, + std::streampos header_offset, + bool is_lazy_ ) override + { + pstream = &stream; + is_lazy = is_lazy_; + + if ( translator->empty() ) { + stream.seekg( 0, std::istream::end ); + set_stream_size( size_t( stream.tellg() ) ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( !is_lazy ) { + return load_data(); + } + + return true; + } + + //------------------------------------------------------------------------------ + bool load_data() const + { + is_lazy = false; + if ( PT_NULL == get_type() || 0 == get_file_size() ) { + return true; + } + + pstream->seekg( ( *translator )[( *convertor )( ph.p_offset )] ); + Elf_Xword size = get_file_size(); + + if ( size > get_stream_size() ) { + data = nullptr; + } + else { + data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); + + if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { + data.get()[size] = 0; + } + else { + data = nullptr; + return false; + } + } + + return true; + } + + //------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + ph.p_offset = decltype( ph.p_offset )( data_offset ); + ph.p_offset = ( *convertor )( ph.p_offset ); + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + + //------------------------------------------------------------------------------ + size_t get_stream_size() const { return stream_size; } + + //------------------------------------------------------------------------------ + void set_stream_size( size_t value ) { stream_size = value; } + + //------------------------------------------------------------------------------ + private: + mutable std::istream* pstream = nullptr; + T ph = {}; + Elf_Half index = 0; + mutable std::unique_ptr data; + std::vector sections; + const endianess_convertor* convertor = nullptr; + const address_translator* translator = nullptr; + size_t stream_size = 0; + bool is_offset_set = false; + mutable bool is_lazy = false; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/include/elfio/elfio_strings.hpp b/include/elfio/elfio_strings.hpp new file mode 100644 index 0000000..09f5729 --- /dev/null +++ b/include/elfio/elfio_strings.hpp @@ -0,0 +1,97 @@ +/* +Copyright (C) 2001-present 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 { + +//------------------------------------------------------------------------------ +template class string_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit string_section_accessor_template( S* section ) + : string_section( section ) + { + } + + //------------------------------------------------------------------------------ + const char* get_string( Elf_Word index ) const + { + if ( string_section ) { + const char* data = string_section->get_data(); + if ( index < string_section->get_size() && nullptr != data ) { + size_t string_length = + strnlen( data + index, string_section->get_size() - index ); + if ( string_length < ( string_section->get_size() - index ) ) + return data + index; + } + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + 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 = + static_cast( 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, static_cast( std::strlen( str ) + 1 ) ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + Elf_Word add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + + //------------------------------------------------------------------------------ + private: + S* string_section; +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = + string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/include/elfio/elfio_symbols.hpp b/include/elfio/elfio_symbols.hpp new file mode 100644 index 0000000..d868500 --- /dev/null +++ b/include/elfio/elfio_symbols.hpp @@ -0,0 +1,562 @@ +/* +Copyright (C) 2001-present 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 { + +//------------------------------------------------------------------------------ +template class symbol_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit symbol_section_accessor_template( const elfio& elf_file, + S* symbol_section ) + : elf_file( elf_file ), symbol_section( symbol_section ) + { + find_hash_section(); + } + + //------------------------------------------------------------------------------ + Elf_Xword get_symbols_num() const + { + Elf_Xword nRet = 0; + + size_t minimum_symbol_size; + switch ( elf_file.get_class() ) { + case ELFCLASS32: + minimum_symbol_size = sizeof( Elf32_Sym ); + break; + case ELFCLASS64: + minimum_symbol_size = sizeof( Elf64_Sym ); + break; + default: + return nRet; + } + + if ( symbol_section->get_entry_size() >= minimum_symbol_size && + symbol_section->get_size() <= symbol_section->get_stream_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() ) { + if ( hash_section->get_type() == SHT_HASH ) { + ret = hash_lookup( name, value, size, bind, type, section_index, + other ); + } + if ( hash_section->get_type() == SHT_GNU_HASH || + hash_section->get_type() == DT_GNU_HASH ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + else { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + } + } + + if ( !ret ) { + for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { + std::string symbol_name; + if ( get_symbol( i, symbol_name, value, size, bind, type, + section_index, other ) ) { + if ( symbol_name == name ) { + ret = true; + } + } + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + bool get_symbol( const Elf64_Addr& value, + std::string& name, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Xword idx = 0; + bool match = false; + Elf64_Addr v = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + match = generic_search_symbols( + [&]( const Elf32_Sym* sym ) { + return convertor( sym->st_value ) == value; + }, + idx ); + } + else { + match = generic_search_symbols( + [&]( const Elf64_Sym* sym ) { + return convertor( sym->st_value ) == value; + }, + idx ); + } + + if ( match ) { + return get_symbol( idx, name, v, size, bind, type, section_index, + other ); + } + + return false; + } + + //------------------------------------------------------------------------------ + 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 ); + } + + //------------------------------------------------------------------------------ + Elf_Xword arrange_local_symbols( + std::function func = + nullptr ) + { + Elf_Xword nRet = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_arrange_local_symbols( func ); + } + else { + nRet = generic_arrange_local_symbols( func ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + void find_hash_section() + { + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() && + ( sec->get_type() == SHT_HASH || + sec->get_type() == SHT_GNU_HASH || + sec->get_type() == DT_GNU_HASH ) ) { + hash_section = sec; + hash_section_index = i; + break; + } + } + } + + //------------------------------------------------------------------------------ + 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; } + + //------------------------------------------------------------------------------ + bool hash_lookup( 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; + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + nbucket = convertor( nbucket ); + Elf_Word nchain = + *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); + nchain = convertor( nchain ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + Elf_Word y = + *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + y = convertor( y ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + y = convertor( y ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + + if ( str == name ) { + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + template + bool gnu_hash_lookup( 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; + const endianess_convertor& convertor = elf_file.get_convertor(); + + uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 ); + uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 ); + uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 ); + uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 ); + nbuckets = convertor( nbuckets ); + symoffset = convertor( symoffset ); + bloom_size = convertor( bloom_size ); + bloom_shift = convertor( bloom_shift ); + + T* bloom_filter = + (T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) ); + + uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); + uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; + T bloom_bits = + ( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | + ( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); + + if ( ( convertor( bloom_filter[bloom_index] ) & bloom_bits ) != + bloom_bits ) + return ret; + + uint32_t bucket = hash % nbuckets; + auto* buckets = + (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + + bloom_size * sizeof( T ) ); + auto* chains = + (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + + bloom_size * sizeof( T ) + + nbuckets * sizeof( uint32_t ) ); + + if ( convertor( buckets[bucket] ) >= symoffset ) { + uint32_t chain_index = convertor( buckets[bucket] ) - symoffset; + uint32_t chain_hash = convertor( chains[chain_index] ); + std::string symname; + + while ( true ) { + if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && + get_symbol( chain_index + symoffset, symname, value, size, + bind, type, section_index, other ) && + name == symname ) { + ret = true; + break; + } + + if ( chain_hash & 1 ) + break; + chain_hash = convertor( chains[++chain_index] ); + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + template const T* generic_get_symbol_ptr( Elf_Xword index ) const + { + if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + return pSym; + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + template + bool generic_search_symbols( std::function match, + Elf_Xword& idx ) const + { + for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { + const T* symPtr = generic_get_symbol_ptr( i ); + + if ( symPtr == nullptr ) + return false; + + if ( match( symPtr ) ) { + idx = i; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + template + 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 ( nullptr != symbol_section->get_data() && + 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 ( nullptr != 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 + 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 = decltype( entry.st_value )( value ); + entry.st_value = convertor( entry.st_value ); + entry.st_size = decltype( 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 = + Elf_Word( symbol_section->get_size() / sizeof( entry ) - 1 ); + + return nRet; + } + + //------------------------------------------------------------------------------ + template + Elf_Xword generic_arrange_local_symbols( + std::function func ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Word first_not_local = + 1; // Skip the first entry. It is always NOTYPE + Elf_Xword current = 0; + Elf_Xword count = get_symbols_num(); + + while ( true ) { + T* p1 = nullptr; + T* p2 = nullptr; + + while ( first_not_local < count ) { + p1 = const_cast( + generic_get_symbol_ptr( first_not_local ) ); + if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL ) + break; + ++first_not_local; + } + + current = first_not_local + 1; + while ( current < count ) { + p2 = const_cast( generic_get_symbol_ptr( current ) ); + if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL ) + break; + ++current; + } + + if ( first_not_local < count && current < count ) { + if ( func ) + func( first_not_local, current ); + + std::swap( *p1, *p2 ); + } + else { + // Update 'info' field of the section + symbol_section->set_info( first_not_local ); + break; + } + } + + return first_not_local; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* symbol_section; + Elf_Half hash_section_index{ 0 }; + const section* hash_section{ nullptr }; +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = + symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/include/elfio/elfio_utils.hpp b/include/elfio/elfio_utils.hpp new file mode 100644 index 0000000..ecb0961 --- /dev/null +++ b/include/elfio/elfio_utils.hpp @@ -0,0 +1,302 @@ +/* +Copyright (C) 2001-present 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 + +#include +#include + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( const TYPE& value ) = 0 + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } + +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \ + void set_##NAME( const TYPE& value ) override \ + { \ + FIELD = decltype( FIELD )( value ); \ + FIELD = ( *convertor )( FIELD ); \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor +{ + public: + //------------------------------------------------------------------------------ + 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 = + (uint16_t)( ( 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 == *reinterpret_cast( &tmp ) ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + + //------------------------------------------------------------------------------ + bool need_conversion = false; +}; + +//------------------------------------------------------------------------------ +struct address_translation +{ + address_translation( uint64_t start, uint64_t size, uint64_t mapped_to ) + : start( start ), size( size ), mapped_to( mapped_to ){}; + std::streampos start; + std::streampos size; + std::streampos mapped_to; +}; + +//------------------------------------------------------------------------------ +class address_translator +{ + public: + //------------------------------------------------------------------------------ + void set_address_translation( std::vector& addr_trans ) + { + addr_translations = addr_trans; + + std::sort( addr_translations.begin(), addr_translations.end(), + []( const address_translation& a, + const address_translation& b ) -> bool { + return a.start < b.start; + } ); + } + + //------------------------------------------------------------------------------ + std::streampos operator[]( std::streampos value ) const + { + if ( addr_translations.empty() ) { + return value; + } + + for ( auto& t : addr_translations ) { + if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) { + return value - t.start + t.mapped_to; + } + } + + return value; + } + + bool empty() const { return addr_translations.empty(); } + + private: + std::vector addr_translations; +}; + +//------------------------------------------------------------------------------ +inline uint32_t elf_hash( const unsigned char* name ) +{ + uint32_t h = 0; + uint32_t g = 0; + while ( *name != '\0' ) { + h = ( h << 4 ) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +//------------------------------------------------------------------------------ +inline uint32_t elf_gnu_hash( const unsigned char* s ) +{ + uint32_t h = 0x1505; + for ( unsigned char c = *s; c != '\0'; c = *++s ) + h = ( h << 5 ) + h + c; + return h; +} + +//------------------------------------------------------------------------------ +inline std::string to_hex_string( uint64_t value ) +{ + std::string str; + + while ( value ) { + if ( auto digit = value & 0xF; digit < 0xA ) { + str = char( '0' + digit ) + str; + } + else { + str = char( 'A' + digit - 0xA ) + str; + } + value >>= 4; + } + + return "0x" + str; +} + +//------------------------------------------------------------------------------ +inline void adjust_stream_size( std::ostream& stream, std::streamsize offset ) +{ + stream.seekp( 0, std::ios_base::end ); + if ( stream.tellp() < offset ) { + std::streamsize size = offset - stream.tellp(); + stream.write( std::string( size_t( size ), '\0' ).c_str(), size ); + } + stream.seekp( offset ); +} + +/** + * Consumers should write an implementation of this class and pass an instance of it to the ELFIO::elfio constructor. + */ +class compression_interface +{ + public: + virtual ~compression_interface() = default; + /** + * decompresses a compressed section + * + * @param data the buffer of compressed data + * @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness. + * @param compressed_size the size of the data buffer, in bytes + * @param decompressed_size a reference to a variable where the decompressed buffer size will be stored. + * @returns a smart pointer to the decompressed data. + */ + virtual std::unique_ptr + inflate( const char* data, + const endianess_convertor* convertor, + Elf_Xword compressed_size, + Elf_Xword& uncompressed_size ) const = 0; + + /** + * compresses a section + * + * @param data the buffer of uncompressed data + * @param endianness_convertor pointer to an endianness_convertor instance, used to convert numbers to/from the target endianness. + * @param decompressed_size the size of the data buffer, in bytes + * @param compressed_size a reference to a variable where the compressed buffer size will be stored. + * @returns a smart pointer to the compressed data. + */ + virtual std::unique_ptr + deflate( const char* data, + const endianess_convertor* convertor, + Elf_Xword decompressed_size, + Elf_Xword& compressed_size ) const = 0; +}; + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/include/elfio/elfio_version.hpp b/include/elfio/elfio_version.hpp new file mode 100644 index 0000000..5b62d0d --- /dev/null +++ b/include/elfio/elfio_version.hpp @@ -0,0 +1 @@ +#define ELFIO_VERSION "3.12" diff --git a/include/elfio/elfio_versym.hpp b/include/elfio/elfio_versym.hpp new file mode 100644 index 0000000..9971caf --- /dev/null +++ b/include/elfio/elfio_versym.hpp @@ -0,0 +1,179 @@ +/* +Copyright (C) 2001-present 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_VERSYM_HPP +#define ELFIO_VERSYM_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class versym_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit versym_section_accessor_template( S* section ) + : versym_section( section ) + { + if ( section != nullptr ) { + entries_num = decltype( entries_num )( section->get_size() / + sizeof( Elf_Half ) ); + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const + { + if ( versym_section ) { + return entries_num; + } + return 0; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, Elf_Half& value ) const + { + if ( versym_section && ( no < get_entries_num() ) ) { + value = ( (Elf_Half*)versym_section->get_data() )[no]; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool modify_entry( Elf_Word no, Elf_Half value ) + { + if ( versym_section && ( no < get_entries_num() ) ) { + ( (Elf_Half*)versym_section->get_data() )[no] = value; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool add_entry( Elf_Half value ) + { + if ( !versym_section ) { + return false; + } + + versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); + ++entries_num; + + return true; + } + + //------------------------------------------------------------------------------ + private: + S* versym_section = nullptr; + Elf_Word entries_num = 0; +}; + +using versym_section_accessor = versym_section_accessor_template
; +using const_versym_section_accessor = + versym_section_accessor_template; + +//------------------------------------------------------------------------------ +template class versym_r_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + versym_r_section_accessor_template( const elfio& elf_file, + S* versym_r_section ) + : elf_file( elf_file ), versym_r_section( versym_r_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERNEEDNUM ) { + entries_num = (Elf_Word)value; + break; + } + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, + Elf_Half& version, + std::string& file_name, + Elf_Word& hash, + Elf_Half& flags, + Elf_Half& other, + std::string& dep_name ) const + { + if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_r_section->get_link()] ); + + Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); + Elfxx_Vernaux* veraux = + (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); + veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + } + + version = verneed->vn_version; + file_name = string_section_acc.get_string( verneed->vn_file ); + hash = veraux->vna_hash; + flags = veraux->vna_flags; + other = veraux->vna_other; + dep_name = string_section_acc.get_string( veraux->vna_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_r_section = nullptr; + Elf_Word entries_num = 0; +}; + +using versym_r_section_accessor = versym_r_section_accessor_template
; +using const_versym_r_section_accessor = + versym_r_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_VERSYM_HPP diff --git a/include/elna/cl.hpp b/include/elna/cl.hpp new file mode 100644 index 0000000..36160b4 --- /dev/null +++ b/include/elna/cl.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace elna +{ + char *readSource(const char *source); + int compile(const char *inFile, const char *outputFilename); +} diff --git a/include/elna/ir.hpp b/include/elna/ir.hpp index d758a73..b92f2e0 100644 --- a/include/elna/ir.hpp +++ b/include/elna/ir.hpp @@ -1,95 +1,18 @@ #pragma once #include "elna/parser.hpp" -#include -#include -namespace elna::ir +namespace elna { - class Node; - class Definition; - class Operand; - class BinaryExpression; - class Variable; - class VariableDeclaration; - class Number; - - struct IRVisitor + class TransformVisitor final : public ParserVisitor { - virtual void visit(Node *) = 0; - virtual void visit(Definition *) = 0; - virtual void visit(Operand *) = 0; - virtual void visit(BinaryExpression *) = 0; - virtual void visit(Variable *) = 0; - virtual void visit(Number *) = 0; - }; - - /** - * AST node. - */ - class Node - { - public: - virtual void accept(IRVisitor *) = 0; - }; - - /** - * Definition. - */ - class Definition : public Node - { - public: - BinaryExpression **statements; - std::size_t statementsLength; - Operand *result; - - virtual void accept(IRVisitor *visitor) override; - }; - - class Statement : public Node - { - }; - - class Operand : public Node - { - public: - virtual void accept(IRVisitor *visitor) override; - }; - - class Number : public Operand - { - public: - std::int32_t value; - - virtual void accept(IRVisitor *visitor) override; - }; - - class Variable : public Operand - { - public: - std::size_t counter; - - virtual void accept(IRVisitor *visitor) override; - }; - - class BinaryExpression : public Statement - { - public: - Operand *lhs, *rhs; - BinaryOperator _operator; - - BinaryExpression(Operand *lhs, Operand *rhs, BinaryOperator _operator); - - virtual void accept(IRVisitor *visitor) override; - }; - - class BangExpression : public Statement - { - Operand *operand; - - public: - BangExpression(Operand *operand); - - virtual void accept(IRVisitor *visitor) override; + void visit(Node *node) override; + void visit(Definition *definition) override; + void visit(BangStatement *statement) override; + void visit(Block *block) override; + void visit(Expression *expression) override; + void visit(Number *number) override; + void visit(Variable *variable) override; + void visit(BinaryExpression *binaryExpression) override; }; } diff --git a/include/elna/parser.hpp b/include/elna/parser.hpp index 322277d..152aec8 100644 --- a/include/elna/parser.hpp +++ b/include/elna/parser.hpp @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + namespace elna { enum class BinaryOperator @@ -7,4 +11,113 @@ namespace elna sum, subtraction }; + + class Node; + class Definition; + class BangStatement; + class Block; + class Expression; + class BinaryExpression; + class Variable; + class Number; + + struct ParserVisitor + { + virtual void visit(Node *) = 0; + virtual void visit(Definition *) = 0; + virtual void visit(BangStatement *) = 0; + virtual void visit(Block *) = 0; + virtual void visit(Expression *) = 0; + virtual void visit(BinaryExpression *) = 0; + virtual void visit(Variable *) = 0; + virtual void visit(Number *) = 0; + }; + + /** + * AST node. + */ + class Node + { + public: + virtual void accept(ParserVisitor *) = 0; + }; + + class Statement : public Node + { + }; + + /** + * Constant definition. + */ + class Definition : public Node + { + public: + Number *number; + const char *identifier; + + virtual void accept(ParserVisitor *visitor) override; + }; + + class BangStatement : public Statement + { + public: + Expression *expression; + + virtual void accept(ParserVisitor *visitor) override; + }; + + /** + * Block. + */ + class Block : public Node + { + public: + Definition** definitions{ nullptr }; + size_t definitionsLength{ 0 }; + Statement *statement{ nullptr }; + + virtual void accept(ParserVisitor *visitor) override; + }; + + class Expression : public Node + { + public: + virtual void accept(ParserVisitor *visitor) override; + }; + + class Number : public Expression + { + public: + std::int32_t value; + + virtual void accept(ParserVisitor *visitor) override; + }; + + class Variable : public Expression + { + public: + const char *identifier; + + virtual void accept(ParserVisitor *visitor) override; + }; + + class BinaryExpression : public Expression + { + public: + Expression *lhs, *rhs; + BinaryOperator _operator; + + BinaryExpression(Expression *lhs, Expression *rhs, unsigned char); + + virtual void accept(ParserVisitor *visitor) override; + }; + + Expression *parseFactor(Token **tokens, std::size_t *length); + Expression *parseTerm(Token **tokens, std::size_t *length); + Expression *parseExpression(Token **tokens, std::size_t *length); + Definition *parseDefinition(Token **tokens, std::size_t *length); + Statement *parseStatement(Token **tokens, std::size_t *length); + Definition **parseDefinitions(Token **tokens, std::size_t *length, std::size_t *resultLength); + Block *parseBlock(Token **tokens, std::size_t *length); + Block *parse(Token *tokenStream, std::size_t length); } diff --git a/include/elna/result.hpp b/include/elna/result.hpp index 72dc647..5740b62 100644 --- a/include/elna/result.hpp +++ b/include/elna/result.hpp @@ -59,4 +59,13 @@ namespace elna size_t offset; Target target; }; + + struct Symbol + { + Symbol(const char *name); + const char *name; + unsigned char *text; + std::size_t length; + Reference symbols[3]; + }; } diff --git a/include/elna/riscv.hpp b/include/elna/riscv.hpp index 5a01bf9..3dba193 100644 --- a/include/elna/riscv.hpp +++ b/include/elna/riscv.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "elna/ir.hpp" +#include "elna/parser.hpp" #include "elna/result.hpp" namespace elna @@ -130,19 +130,27 @@ namespace elna std::uint32_t instruction{ 0 }; }; - class RiscVVisitor : public ir::IRVisitor + class RiscVVisitor : public ParserVisitor { + public: Instruction *instructions; std::size_t instructionsLength; - bool registerInUse; + bool registerInUse{ true }; std::uint32_t variableCounter = 1; Reference references[3]; + std::int32_t *constValues{ nullptr }; + const char **constNames{ nullptr }; + std::size_t constCount{ 0 }; - virtual void visit(ir::Node *) override; - virtual void visit(ir::Definition *definition) override; - virtual void visit(ir::Operand *operand) override; - virtual void visit(ir::Variable *variable) override; - virtual void visit(ir::Number *number) override; - virtual void visit(ir::BinaryExpression *expression) override; + virtual void visit(Node *) override; + virtual void visit(Definition *definition) override; + virtual void visit(BangStatement *statement) override; + virtual void visit(Block *block) override; + virtual void visit(Expression *operand) override; + virtual void visit(Variable *variable) override; + virtual void visit(Number *number) override; + virtual void visit(BinaryExpression *expression) override; }; + + Symbol writeNext(Block *ast); } diff --git a/source/cl.cpp b/source/cl.cpp new file mode 100644 index 0000000..fa27377 --- /dev/null +++ b/source/cl.cpp @@ -0,0 +1,136 @@ +#include "elna/cl.hpp" +#include "elna/result.hpp" +#include "elna/riscv.hpp" +#include +#include +#include +#include + +namespace elna +{ + char *readSource(const char *source) + { + const std::size_t bufferSize = 255; + + std::ifstream input_stream{ source }; + std::stringstream buffer; + buffer << input_stream.rdbuf(); + input_stream.close(); + std::string contents = buffer.str(); + char *result = reinterpret_cast(malloc(contents.size() + 1)); + std::copy(std::cbegin(contents), std::cend(contents), result); + result[contents.size()] = '\0'; + + return result; + } + + int compile(const char *inFile, const char *outputFilename) + { + ELFIO::elfio writer; + + // You can't proceed before this function call! + writer.create(ELFIO::ELFCLASS32, ELFIO::ELFDATA2LSB); + + writer.set_os_abi(ELFIO::ELFOSABI_NONE); + writer.set_type(ELFIO::ET_REL); + writer.set_machine(ELFIO::EM_RISCV); + + auto sourceText = readSource(inFile); + if (sourceText == nullptr) + { + return 3; + } + CompileError *compileError = nullptr; + size_t tokensCount{ 0 }; + auto tokens = lex(sourceText, compileError, &tokensCount); + free(sourceText); + if (tokens == nullptr) + { + printf("%lu:%lu: %s\n", compileError->line(), compileError->column(), compileError->what()); + return 1; + } + auto ast = parse(tokens, tokensCount); + if (ast == nullptr) + { + return 2; + } + auto program = writeNext(ast); + + // Create code section + ELFIO::section* text_sec = writer.sections.add(".text"); + text_sec->set_type(ELFIO::SHT_PROGBITS); + text_sec->set_flags(ELFIO::SHF_ALLOC | ELFIO::SHF_EXECINSTR); + text_sec->set_addr_align(0x1); + text_sec->set_data(reinterpret_cast(program.text), program.length); + + // Create string table section + ELFIO::section* str_sec = writer.sections.add(".strtab"); + str_sec->set_type(ELFIO::SHT_STRTAB); + + // Create string table writer + ELFIO::string_section_accessor stra(str_sec); + // Add label name + ELFIO::Elf32_Word str_index = stra.add_string("msg"); + + // Create read only data section + ELFIO::section* ro_sec = writer.sections.add(".rodata"); + ro_sec->set_type(ELFIO::SHT_PROGBITS); + ro_sec->set_flags(ELFIO::SHF_ALLOC); + ro_sec->set_addr_align(0x4); + ro_sec->set_data("%d\n"); + + // Create symbol table section + ELFIO::section* sym_sec = writer.sections.add(".symtab"); + sym_sec->set_type(ELFIO::SHT_SYMTAB); + sym_sec->set_info(2); + sym_sec->set_addr_align(0x4); + sym_sec->set_entry_size(writer.get_default_entry_size(ELFIO::SHT_SYMTAB)); + sym_sec->set_link(str_sec->get_index()); + + // Create symbol table writer + ELFIO::symbol_section_accessor syma(writer, sym_sec); + auto label_sym = syma.add_symbol(stra, ".CL0", 0x00000000, strlen("%d\n") + 1, + ELFIO::STB_LOCAL, ELFIO::STT_NOTYPE, 0, ro_sec->get_index()); + syma.add_symbol(stra, program.name, 0x00000000, program.length, + ELFIO::STB_GLOBAL, ELFIO::STT_FUNC, 0, text_sec->get_index()); + auto printf_sym = syma.add_symbol(stra, "printf", 0x00000000, 0, + ELFIO::STB_GLOBAL, ELFIO::STT_NOTYPE, 0, ELFIO::SHN_UNDEF); + + // Create relocation table section + ELFIO::section* rel_sec = writer.sections.add(".rel.text"); + rel_sec->set_type(ELFIO::SHT_REL); + rel_sec->set_info(text_sec->get_index()); + rel_sec->set_addr_align(0x4); + rel_sec->set_entry_size(writer.get_default_entry_size(ELFIO::SHT_REL)); + rel_sec->set_link(sym_sec->get_index()); + rel_sec->set_flags(ELFIO::SHF_ALLOC); + + // Create relocation table writer + ELFIO::relocation_section_accessor rela(writer, rel_sec); + // Add relocation entry (adjust address at offset 11) + rela.add_entry(program.symbols[0].offset, label_sym, 26 /* ELFIO::R_RISCV_HI20 */); + rela.add_entry(program.symbols[0].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); + rela.add_entry(program.symbols[1].offset, label_sym, 27 /* ELFIO::R_RISCV_LO12_I */); + rela.add_entry(program.symbols[1].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); + rela.add_entry(program.symbols[2].offset, printf_sym, 18 /* ELFIO::R_RISCV_CALL */); + rela.add_entry(program.symbols[2].offset, printf_sym, 51 /* ELFIO::R_RISCV_RELAX */); + + // Another method to add the same relocation entry at one step is: + // rela.add_entry( stra, "msg", + // syma, 29, 0, + // ELF_ST_INFO( STB_GLOBAL, STT_OBJECT ), 0, + // text_sec->get_index(), + // place_to_adjust, (unsigned char)R_386_RELATIVE ); + + /* We don't use local symbols here. There is no need to rearrange them. + // But, for the completeness, we do this just prior 'save' + syma.arrange_local_symbols([&](ELFIO::Elf_Xword first, ELFIO::Elf_Xword second) { + rela.swap_symbols( first, second ); + }); */ + + // Create ELF object file + writer.save(outputFilename); + + return 0; + } +} diff --git a/source/elna/arguments.d b/source/elna/arguments.d deleted file mode 100644 index 1ad928a..0000000 --- a/source/elna/arguments.d +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Argument parsing. - */ -module elna.arguments; - -import std.algorithm; -import std.range; -import std.sumtype; - -struct ArgumentError -{ - enum Type - { - expectedOutputFile, - noInput, - superfluousArguments, - } - - private Type type_; - private string argument_; - - @property Type type() const @nogc nothrow pure @safe - { - return this.type_; - } - - @property string argument() const @nogc nothrow pure @safe - { - return this.argument_; - } - - void toString(OR)(OR range) - if (isOutputRage!OR) - { - final switch (Type) - { - case Type.expectedOutputFile: - put(range, "Expected an output filename after -o"); - break; - case Type.noInput: - put(range, "No input files specified"); - break; - } - } -} - -/** - * Supported compiler arguments. - */ -struct Arguments -{ - private bool assembler_; - private string output_; - private string inFile_; - - @property string inFile() @nogc nothrow pure @safe - { - return this.inFile_; - } - - /** - * Returns: Whether to generate assembly instead of an object file. - */ - @property bool assembler() const @nogc nothrow pure @safe - { - return this.assembler_; - } - - /** - * Returns: Output file. - */ - @property string output() const @nogc nothrow pure @safe - { - return this.output_; - } - - /** - * Parse command line arguments. - * - * The first argument is expected to be the program name (and it is - * ignored). - * - * Params: - * arguments = Command line arguments. - * - * Returns: Parsed arguments or an error. - */ - static SumType!(ArgumentError, Arguments) parse(string[] arguments) - @nogc nothrow pure @safe - { - if (!arguments.empty) - { - arguments.popFront; - } - alias ReturnType = typeof(return); - - return parseArguments(arguments).match!( - (Arguments parsed) { - if (parsed.inFile is null) - { - return ReturnType(ArgumentError(ArgumentError.Type.noInput)); - } - else if (!arguments.empty) - { - return ReturnType(ArgumentError( - ArgumentError.Type.superfluousArguments, - arguments.front - )); - } - return ReturnType(parsed); - }, - (ArgumentError argumentError) => ReturnType(argumentError) - ); - } - - private static SumType!(ArgumentError, Arguments) parseArguments(ref string[] arguments) - @nogc nothrow pure @safe - { - Arguments parsed; - - while (!arguments.empty) - { - if (arguments.front == "-s") - { - parsed.assembler_ = true; - } - else if (arguments.front == "-o") - { - if (arguments.empty) - { - return typeof(return)(ArgumentError( - ArgumentError.Type.expectedOutputFile, - arguments.front - )); - } - arguments.popFront; - parsed.output_ = arguments.front; - } - else if (arguments.front == "--") - { - arguments.popFront; - parsed.inFile_ = arguments.front; - arguments.popFront; - break; - } - else if (!arguments.front.startsWith("-")) - { - parsed.inFile_ = arguments.front; - } - arguments.popFront; - } - return typeof(return)(parsed); - } -} diff --git a/source/elna/backend.d b/source/elna/backend.d index e2d67ac..50a7cf1 100644 --- a/source/elna/backend.d +++ b/source/elna/backend.d @@ -4,9 +4,7 @@ import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import elna.elf; -import elna.ir; import elna.extended; -import elna.riscv; import elna.lexer; import elna.parser; import elna.result; @@ -18,27 +16,16 @@ import tanya.container.array; import tanya.container.string; import tanya.memory.allocator; -private char* readSource(string source) @nogc -{ - enum size_t bufferSize = 255; - auto sourceFilename = String(source); +extern(C++, "elna") +Symbol writeNext(Block ast) @nogc; - return readFile(sourceFilename).match!( - (ErrorCode errorCode) { - perror(sourceFilename.toStringz); - return null; - }, - (Array!ubyte contents) { - char* cString = cast(char*) malloc(contents.length + 1); - memcpy(cString, contents.get.ptr, contents.length); - cString[contents.length] = '\0'; +extern(C++, "elna") +char* readSource(const(char)* source) @nogc; - return cString; - } - ); -} +extern(C++, "elna") +int compile(const(char)* inFile, const(char)* outputFilename) @nogc; -int generate(string inFile, ref String outputFilename) @nogc +int generate(const(char)* inFile, const(char)* outputFilename) @nogc { auto sourceText = readSource(inFile); if (sourceText is null) @@ -54,32 +41,24 @@ int generate(string inFile, ref String outputFilename) @nogc printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.what); return 1; } - auto ast = parse(tokens[0 .. tokensCount]); - if (!ast.valid) + auto ast = parse(tokens, tokensCount); + if (ast is null) { - compileError = ast.error.get; - printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.what); return 2; } - auto transformVisitor = cast(TransformVisitor) malloc(__traits(classInstanceSize, TransformVisitor)); - (cast(void*) transformVisitor)[0 .. __traits(classInstanceSize, TransformVisitor)] = __traits(initSymbol, TransformVisitor)[]; + auto handle = File.open(outputFilename, BitFlags!(File.Mode)(File.Mode.truncate)); - auto ir = transformVisitor.visit(ast.result); - - transformVisitor.__xdtor(); - free(cast(void*) transformVisitor); - - auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate)); if (!handle.valid) { return 1; } - auto program = writeNext(ir); + auto program = writeNext(ast); auto elf = Elf!ELFCLASS32(move(handle)); auto readOnlyData = Array!ubyte(cast(const(ubyte)[]) "%d\n".ptr[0 .. 4]); // With \0. + auto text = Array!ubyte(program.text[0 .. program.length]); elf.addReadOnlyData(String(".CL0"), readOnlyData); - elf.addCode(program.name, program.text); + elf.addCode(String(program.name[0 .. strlen(program.name)]), text); elf.addExternSymbol(String("printf")); foreach (ref reference; program.symbols) diff --git a/source/elna/extended.d b/source/elna/extended.d index ff06a0c..6baea71 100644 --- a/source/elna/extended.d +++ b/source/elna/extended.d @@ -297,10 +297,10 @@ struct File * * See_Also: $(D_PSYMBOL File.read) */ -SumType!(ErrorCode, Array!ubyte) readFile(String sourceFilename) @nogc +SumType!(ErrorCode, Array!ubyte) readFile(const(char)* sourceFilename) @nogc { enum size_t bufferSize = 255; - auto sourceFile = File.open(sourceFilename.toStringz, BitFlags!(File.Mode)(File.Mode.read)); + auto sourceFile = File.open(sourceFilename, BitFlags!(File.Mode)(File.Mode.read)); if (!sourceFile.valid) { diff --git a/source/elna/ir.d b/source/elna/ir.d deleted file mode 100644 index 4ff2288..0000000 --- a/source/elna/ir.d +++ /dev/null @@ -1,220 +0,0 @@ -module elna.ir; - -import core.stdc.stdlib; -import parser = elna.parser; -import tanya.container.array; -import tanya.container.hashtable; -import tanya.container.string; -import tanya.memory.allocator; -public import elna.parser : BinaryOperator; - -/** - * Mapping between the parser and IR AST. - */ -struct ASTMapping -{ - alias Node = .Node; - alias Definition = .Definition; - alias Statement = .Operand; - alias BangStatement = .Operand; - alias Block = .Definition; - alias Expression = .Operand; - alias Number = .Number; - alias Variable = .Number; - alias BinaryExpression = .Variable; - -} - -/** - * IR visitor. -*/ -extern(C++, "elna", "ir") -abstract class IRVisitor -{ - abstract void visit(Node) @nogc; - abstract void visit(Definition) @nogc; - abstract void visit(Operand) @nogc; - abstract void visit(BinaryExpression) @nogc; - abstract void visit(Variable) @nogc; - abstract void visit(Number) @nogc; -} - -/** - * AST node. - */ -extern(C++, "elna", "ir") -abstract class Node -{ - abstract void accept(IRVisitor) @nogc; -} - -/** - * Definition. - */ -extern(C++, "elna", "ir") -class Definition : Node -{ - BinaryExpression* statements; - size_t statementsLength; - Operand result; - - override void accept(IRVisitor visitor) @nogc; -} - -extern(C++, "elna", "ir") -abstract class Statement : Node -{ -} - -extern(C++, "elna", "ir") -abstract class Operand : Node -{ - override void accept(IRVisitor visitor) @nogc; -} - -extern(C++, "elna", "ir") -class Number : Operand -{ - int value; - - override void accept(IRVisitor visitor) @nogc; -} - -extern(C++, "elna", "ir") -class Variable : Operand -{ - size_t counter; - - override void accept(IRVisitor visitor) @nogc; -} - -extern(C++, "elna", "ir") -class BinaryExpression : Statement -{ - Operand lhs, rhs; - BinaryOperator operator; - - this(Operand lhs, Operand rhs, BinaryOperator operator) @nogc; - - override void accept(IRVisitor visitor) @nogc; -} - -extern(C++, "elna", "ir") -class BangExpression : Statement -{ - Operand operand; - - this(Operand operand); - - override void accept(IRVisitor visitor) @nogc; -} - -final class TransformVisitor : parser.ParserVisitor!ASTMapping -{ - private HashTable!(String, int) constants; - private BinaryExpression* statements; - private size_t statementsLength; - - ASTMapping.Node visit(parser.Node node) @nogc - { - assert(false, "Not implemented"); - } - - ASTMapping.Definition visit(parser.Definition definition) @nogc - { - assert(false, "Not implemented"); - } - - ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc - { - return statement.expression.accept(this); - } - - ASTMapping.Block visit(parser.Block block) @nogc - { - auto target = defaultAllocator.make!Definition; - this.constants = transformConstants(block.definitions); - - target.result = block.statement.accept(this); - target.statements = this.statements; - target.statementsLength = this.statementsLength; - - return target; - } - - ASTMapping.Expression visit(parser.Expression expression) @nogc - { - if ((cast(parser.Number) expression) !is null) - { - return (cast(parser.Number) expression).accept(this); - } - if ((cast(parser.Variable) expression) !is null) - { - return (cast(parser.Variable) expression).accept(this); - } - else if ((cast(parser.BinaryExpression) expression) !is null) - { - return (cast(parser.BinaryExpression) expression).accept(this); - } - assert(false, "Invalid expression type"); - } - - ASTMapping.Number visit(parser.Number number) @nogc - { - auto numberExpression = defaultAllocator.make!Number; - numberExpression.value = number.value; - - return numberExpression; - } - - ASTMapping.Variable visit(parser.Variable variable) @nogc - { - auto numberExpression = defaultAllocator.make!Number; - numberExpression.value = this.constants[variable.identifier]; - - return numberExpression; - } - - ASTMapping.BinaryExpression visit(parser.BinaryExpression binaryExpression) @nogc - { - auto target = defaultAllocator.make!BinaryExpression( - binaryExpression.lhs.accept(this), - binaryExpression.rhs.accept(this), - binaryExpression.operator - ); - this.statements = cast(BinaryExpression*) - realloc(this.statements, (this.statementsLength + 1) * BinaryExpression.sizeof); - this.statements[this.statementsLength++] = target; - - auto newVariable = defaultAllocator.make!Variable; - newVariable.counter = this.statementsLength; - - return newVariable; - } - - private Number transformNumber(parser.Number number) @nogc - { - return defaultAllocator.make!Number(number.value); - } - - override Operand visit(parser.Statement statement) @nogc - { - if ((cast(parser.BangStatement) statement) !is null) - { - return (cast(parser.BangStatement) statement).accept(this); - } - assert(false, "Invalid statement type"); - } - - private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc - { - typeof(return) constants; - - foreach (definition; definitions[]) - { - constants[definition.identifier] = definition.number.value; - } - - return constants; - } -} diff --git a/source/elna/lexer.d b/source/elna/lexer.d index 45a641c..eb0d6dd 100644 --- a/source/elna/lexer.d +++ b/source/elna/lexer.d @@ -1,12 +1,7 @@ module elna.lexer; -import core.stdc.stdlib; -import core.stdc.ctype; import core.stdc.string; import elna.result; -import std.range; -import tanya.container.array; -import tanya.container.string; extern(C++, "elna") struct Token @@ -56,62 +51,5 @@ struct Token @property const(Position) position() const @nogc nothrow pure @safe; } -/** - * Range over the source text that keeps track of the current position. - */ -struct Source -{ - const(char)* buffer; - Position position; - - this(const(char)* buffer) @nogc nothrow pure @safe - { - this.buffer = buffer; - } - - @disable this(); - - bool empty() @nogc nothrow pure @safe - { - return this.buffer is null || this.buffer[0] == '\0'; - } - - char front() @nogc nothrow pure @safe - in (!empty) - { - return this.buffer[0]; - } - - void popFront() @nogc nothrow pure - in (!empty) - { - ++this.buffer; - ++this.position.column; - } - - void breakLine() @nogc nothrow pure - in (!empty) - { - ++this.buffer; - ++this.position.line; - this.position.column = 1; - } - - @property size_t length() const @nogc nothrow pure - { - return strlen(this.buffer); - } - - char opIndex(size_t index) @nogc nothrow pure - { - return this.buffer[index]; - } - - const(char)[] opSlice(size_t i, size_t j) @nogc nothrow pure - { - return this.buffer[i .. j]; - } -} - extern(C++, "elna") Token* lex(const(char)* buffer, CompileError* compileError, size_t* length) @nogc; diff --git a/source/elna/parser.d b/source/elna/parser.d index 18e31bd..ca8064e 100644 --- a/source/elna/parser.d +++ b/source/elna/parser.d @@ -1,109 +1,92 @@ module elna.parser; import core.stdc.string; +import core.stdc.stdlib; import elna.lexer; import elna.result; -import tanya.container.array; -import tanya.container.string; import tanya.memory.allocator; import std.array; /** * Parser visitor. */ -interface ParserVisitor(Mapping) +extern(C++, "elna") +abstract class ParserVisitor { - Mapping.Node visit(Node) @nogc; - Mapping.Definition visit(Definition) @nogc; - Mapping.Statement visit(Statement) @nogc; - Mapping.BangStatement visit(BangStatement) @nogc; - Mapping.Block visit(Block) @nogc; - Mapping.Expression visit(Expression) @nogc; - Mapping.Number visit(Number) @nogc; - Mapping.Variable visit(Variable) @nogc; - Mapping.BinaryExpression visit(BinaryExpression) @nogc; + abstract void visit(Node) @nogc; + abstract void visit(Definition) @nogc; + abstract void visit(BangStatement) @nogc; + abstract void visit(Block) @nogc; + abstract void visit(Expression) @nogc; + abstract void visit(BinaryExpression) @nogc; + abstract void visit(Variable) @nogc; + abstract void visit(Number) @nogc; } /** * AST node. */ +extern(C++, "elna") abstract class Node { - Mapping.Node accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + abstract void accept(ParserVisitor visitor) @nogc; +} + +extern(C++, "elna") +abstract class Statement : Node +{ } /** * Constant definition. */ +extern(C++, "elna") class Definition : Node { Number number; - String identifier; + const(char)* identifier; - Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } -} - -abstract class Statement : Node -{ - Mapping.Statement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } +extern(C++, "elna") class BangStatement : Statement { Expression expression; - Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } +extern(C++, "elna") class Block : Node { - Array!Definition definitions; + Definition* definitions; + size_t definitionsLength; Statement statement; - Mapping.Block accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } +extern(C++, "elna") abstract class Expression : Node { - Mapping.Expression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } +extern(C++, "elna") class Number : Expression { int value; - Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } +extern(C++, "elna") class Variable : Expression { - String identifier; + const(char)* identifier; - Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + override void accept(ParserVisitor visitor) @nogc; } extern(C++, "elna") @@ -113,196 +96,15 @@ enum BinaryOperator subtraction } +extern(C++, "elna") class BinaryExpression : Expression { Expression lhs, rhs; BinaryOperator operator; - this(Expression lhs, Expression rhs, String operator) @nogc - { - this.lhs = lhs; - this.rhs = rhs; - if (operator == "+") - { - this.operator = BinaryOperator.sum; - } - else if (operator == "-") - { - this.operator = BinaryOperator.subtraction; - } - else - { - assert(false, "Invalid binary operator"); - } - } - - Mapping.BinaryExpression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc - { - return visitor.visit(this); - } + this(Expression lhs, Expression rhs, ubyte operator) @nogc; + override void accept(ParserVisitor visitor) @nogc; } -private Result!Expression parseFactor(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected factor, got end of stream") -{ - if (tokens.front.of() == Token.Type.identifier) - { - auto variable = defaultAllocator.make!Variable; - variable.identifier = tokens.front.identifier()[0 .. strlen(tokens.front.identifier())]; - tokens.popFront; - return Result!Expression(variable); - } - else if (tokens.front.of() == Token.Type.number) - { - auto number = defaultAllocator.make!Number; - number.value = tokens.front.number(); - tokens.popFront; - return Result!Expression(number); - } - else if (tokens.front.of() == Token.Type.leftParen) - { - tokens.popFront; - - auto expression = parseExpression(tokens); - - tokens.popFront; - return expression; - } - return Result!Expression("Expected a factor", tokens.front.position); -} - -private Result!Expression parseTerm(ref Token[] tokens) @nogc -{ - return parseFactor(tokens); -} - -private Result!Expression parseExpression(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected expression, got end of stream") -{ - auto term = parseTerm(tokens); - if (!term.valid || tokens.empty || tokens.front.of() != Token.Type.operator) - { - return term; - } - auto operator = String(tokens.front.identifier()[0 .. strlen(tokens.front.identifier())]); - tokens.popFront; - - auto expression = parseExpression(tokens); - - if (expression.valid) - { - auto binaryExpression = defaultAllocator - .make!BinaryExpression(term.result, expression.result, operator); - - return Result!Expression(binaryExpression); - } - else - { - return Result!Expression("Expected right-hand side to be an expression", tokens.front.position); - } -} - -private Result!Definition parseDefinition(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected definition, got end of stream") -{ - auto definition = defaultAllocator.make!Definition; - definition.identifier = tokens.front.identifier()[0 .. strlen(tokens.front.identifier())]; // Copy. - - tokens.popFront(); - tokens.popFront(); // Skip the equals sign. - - if (tokens.front.of() == Token.Type.number) - { - auto number = defaultAllocator.make!Number; - number.value = tokens.front.number(); - definition.number = number; - tokens.popFront; - return Result!Definition(definition); - } - return Result!Definition("Expected a number", tokens.front.position); -} - -private Result!Statement parseStatement(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected block, got end of stream") -{ - if (tokens.front.of() == Token.Type.bang) - { - tokens.popFront; - auto statement = defaultAllocator.make!BangStatement; - auto expression = parseExpression(tokens); - if (expression.valid) - { - statement.expression = expression.result; - } - else - { - return Result!Statement(expression.error.get); - } - return Result!Statement(statement); - } - return Result!Statement("Expected ! statement", tokens.front.position); -} - -private Result!(Array!Definition) parseDefinitions(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected definition, got end of stream") -{ - tokens.popFront; // Skip const. - - Array!Definition definitions; - - while (!tokens.empty) - { - auto definition = parseDefinition(tokens); - if (!definition.valid) - { - return typeof(return)(definition.error.get); - } - definitions.insertBack(definition.result); - if (tokens.front.of() == Token.Type.semicolon) - { - break; - } - if (tokens.front.of() == Token.Type.comma) - { - tokens.popFront; - } - } - - return typeof(return)(definitions); -} - -private Result!Block parseBlock(ref Token[] tokens) @nogc -in (!tokens.empty, "Expected block, got end of stream") -{ - auto block = defaultAllocator.make!Block; - if (tokens.front.of() == Token.Type.let) - { - auto constDefinitions = parseDefinitions(tokens); - if (constDefinitions.valid) - { - block.definitions = constDefinitions.result; - } - else - { - return Result!Block(constDefinitions.error.get); - } - tokens.popFront; - } - auto statement = parseStatement(tokens); - if (statement.valid) - { - block.statement = statement.result; - } - else - { - return Result!Block(statement.error.get); - } - - return Result!Block(block); -} - -Result!Block parse(Token[] tokenStream) @nogc -{ - auto tokens = tokenStream[]; - return parseBlock(tokens); -} +extern(C++, "elna") +Block parse(Token* tokenStream, size_t length) @nogc; diff --git a/source/elna/result.d b/source/elna/result.d index f35f68e..2b0a521 100644 --- a/source/elna/result.d +++ b/source/elna/result.d @@ -90,9 +90,12 @@ struct Reference Target target; } +extern(C++, "elna") struct Symbol { - String name; - Array!ubyte text; - Array!Reference symbols; + this(const(char)* name) @nogc; + const(char)* name; + ubyte* text; + size_t length; + Reference[3] symbols; } diff --git a/source/elna/riscv.d b/source/elna/riscv.d deleted file mode 100644 index 2719f48..0000000 --- a/source/elna/riscv.d +++ /dev/null @@ -1,183 +0,0 @@ -module elna.riscv; - -import core.stdc.stdlib; -import elna.ir; -import elna.result; -import tanya.container.array; -import tanya.container.string; - -extern(C++, "elna") -enum XRegister : ubyte -{ - zero = 0, - ra = 1, - sp = 2, - gp = 3, - tp = 4, - t0 = 5, - t1 = 6, - t2 = 7, - s0 = 8, - s1 = 9, - a0 = 10, - a1 = 11, - a2 = 12, - a3 = 13, - a4 = 14, - a5 = 15, - a6 = 16, - a7 = 17, - s2 = 18, - s3 = 19, - s4 = 20, - s5 = 21, - s6 = 22, - s7 = 23, - s8 = 24, - s9 = 25, - s10 = 26, - s11 = 27, - t3 = 28, - t4 = 29, - t5 = 30, - t6 = 31, -} - -extern(C++, "elna") -enum Funct3 : ubyte -{ - addi = 0b000, - slti = 0b001, - sltiu = 0b011, - andi = 0b111, - ori = 0b110, - xori = 0b100, - slli = 0b000, - srli = 0b101, - srai = 0b101, - add = 0b000, - slt = 0b010, - sltu = 0b011, - and = 0b111, - or = 0b110, - xor = 0b100, - sll = 0b001, - srl = 0b101, - sub = 0b000, - sra = 0b101, - beq = 0b000, - bne = 0b001, - blt = 0b100, - bltu = 0b110, - bge = 0b101, - bgeu = 0b111, - fence = 0b000, - fenceI = 0b001, - csrrw = 0b001, - csrrs = 0b010, - csrrc = 0b011, - csrrwi = 0b101, - csrrsi = 0b110, - csrrci = 0b111, - priv = 0b000, - sb = 0b000, - sh = 0b001, - sw = 0b010, - lb = 0b000, - lh = 0b001, - lw = 0b010, - lbu = 0b100, - lhu = 0b101, - jalr = 0b000, -} - -extern(C++, "elna") -enum Funct12 : ubyte -{ - ecall = 0b000000000000, - ebreak = 0b000000000001, -} - -extern(C++, "elna") -enum Funct7 : ubyte -{ - none = 0, - sub = 0b0100000 -} - -extern(C++, "elna") -enum BaseOpcode : ubyte -{ - opImm = 0b0010011, - lui = 0b0110111, - auipc = 0b0010111, - op = 0b0110011, - jal = 0b1101111, - jalr = 0b1100111, - branch = 0b1100011, - load = 0b0000011, - store = 0b0100011, - miscMem = 0b0001111, - system = 0b1110011, -} - -extern(C++, "elna") -struct Instruction -{ - private uint instruction; - - this(BaseOpcode opcode) @nogc; - @disable this(); - - ref Instruction i(XRegister rd, Funct3 funct3, XRegister rs1, uint immediate) - return scope @nogc; - - ref Instruction s(uint imm1, Funct3 funct3, XRegister rs1, XRegister rs2) - return scope @nogc; - - ref Instruction r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7.none) - return scope @nogc; - - ref Instruction u(XRegister rd, uint imm) - return scope @nogc; - - ubyte* encode() return scope @nogc; -} - -extern(C++, "elna") -class RiscVVisitor : IRVisitor -{ - Instruction *instructions; - size_t instructionsLength; - bool registerInUse; - uint variableCounter = 1; - Reference[3] references; - - override void visit(Node) @nogc; - override void visit(Definition definition) @nogc; - override void visit(Operand operand) @nogc; - override void visit(Variable variable) @nogc; - override void visit(Number number) @nogc; - override void visit(BinaryExpression expression) @nogc; -} - -Symbol writeNext(Definition ast) @nogc -{ - Array!Instruction instructions; - auto visitor = cast(RiscVVisitor) malloc(__traits(classInstanceSize, RiscVVisitor)); - (cast(void*) visitor)[0 .. __traits(classInstanceSize, RiscVVisitor)] = __traits(initSymbol, RiscVVisitor)[]; - scope (exit) - { - free(cast(void*) visitor); - } - visitor.visit(ast); - - auto program = Symbol(String("main")); - - program.symbols = Array!Reference(visitor.references[]); - foreach (ref instruction; visitor.instructions[0 .. visitor.instructionsLength]) - { - program.text.insertBack(instruction.encode[0 .. uint.sizeof]); - } - return program; -} diff --git a/source/ir.cpp b/source/ir.cpp index f7ae9ff..e209866 100644 --- a/source/ir.cpp +++ b/source/ir.cpp @@ -1,53 +1,46 @@ #include "elna/ir.hpp" -namespace elna::ir +#include + +namespace elna { - /** - * AST node. - */ - void Node::accept(IRVisitor *) + void TransformVisitor::visit(Node *node) { + assert(false); } - void Definition::accept(IRVisitor *visitor) + void TransformVisitor::visit(Definition *definition) { - visitor->visit(this); + assert(false); } - void Operand::accept(IRVisitor *visitor) + void TransformVisitor::visit(BangStatement *statement) { - visitor->visit(this); + assert(false); } - void Number::accept(IRVisitor *visitor) + void TransformVisitor::visit(Block *block) { - visitor->visit(this); + assert(false); } - void Variable::accept(IRVisitor *visitor) + void TransformVisitor::visit(Expression *expression) { - visitor->visit(this); + assert(false); } - BinaryExpression::BinaryExpression(Operand *lhs, Operand *rhs, BinaryOperator _operator) + void TransformVisitor::visit(Number *number) { - this->lhs = lhs; - this->rhs = rhs; - this->_operator = _operator; + assert(false); } - void BinaryExpression::accept(IRVisitor *visitor) + void TransformVisitor::visit(Variable *variable) { - visitor->visit(this); + assert(false); } - BangExpression::BangExpression(Operand *operand) + void TransformVisitor::visit(BinaryExpression *binaryExpression) { - this->operand = operand; - } - - void BangExpression::accept(IRVisitor *visitor) - { - visitor->visit(this); + assert(false); } } diff --git a/source/main.d b/source/main.d index dcb9fa0..3bd823b 100644 --- a/source/main.d +++ b/source/main.d @@ -1,33 +1,15 @@ import elna.backend; -import elna.ir; -import elna.arguments; import std.path; import std.sumtype; import tanya.container.string; import tanya.memory.allocator; import tanya.memory.mmappool; -int main(string[] args) +extern(C) +int main(int argc, char** args) { defaultAllocator = MmapPool.instance; - return Arguments.parse(args).match!( - (ArgumentError argumentError) => 4, - (Arguments arguments) { - String outputFilename; - if (arguments.output is null) - { - outputFilename = arguments - .inFile - .baseName - .withExtension("o"); - } - else - { - outputFilename = String(arguments.output); - } - - return generate(arguments.inFile, outputFilename); - } - ); + // return generate(args[3], args[2]); + return compile(args[3], args[2]); } diff --git a/source/parser.cpp b/source/parser.cpp new file mode 100644 index 0000000..699a9ee --- /dev/null +++ b/source/parser.cpp @@ -0,0 +1,240 @@ +#include "elna/parser.hpp" +#include + +namespace elna +{ + /** + * AST node. + */ + void Node::accept(ParserVisitor *) + { + } + + void Definition::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + void Block::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + void Expression::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + void Number::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + void Variable::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + BinaryExpression::BinaryExpression(Expression *lhs, Expression *rhs, unsigned char _operator) + { + this->lhs = lhs; + this->rhs = rhs; + + if (_operator == '+') + { + this->_operator = BinaryOperator::sum; + } + else if (_operator == '-') + { + this->_operator = BinaryOperator::subtraction; + } + else + { + throw std::logic_error("Invalid binary operator"); + } + } + + void BinaryExpression::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + void BangStatement::accept(ParserVisitor *visitor) + { + visitor->visit(this); + } + + Block *parse(Token *tokenStream, std::size_t length) + { + return parseBlock(&tokenStream, &length); + } + + Expression *parseFactor(Token **tokens, size_t *length) + { + if ((*tokens)[0].of() == Token::TOKEN_IDENTIFIER) + { + auto variable = new Variable(); + variable->identifier = (*tokens)[0].identifier(); + ++(*tokens); + --(*length); + return variable; + } + else if ((*tokens)[0].of() == Token::TOKEN_NUMBER) + { + auto number = new Number(); + number->value = (*tokens)[0].number(); + ++(*tokens); + --(*length); + return number; + } + else if ((*tokens)[0].of() == Token::TOKEN_LEFT_PAREN) + { + ++(*tokens); + --(*length); + + auto expression = parseExpression(tokens, length); + + ++(*tokens); + --(*length); + + return expression; + } + return nullptr; + } + + Expression *parseTerm(Token **tokens, size_t *length) + { + return parseFactor(tokens, length); + } + + Expression *parseExpression(Token **tokens, size_t *length) + { + auto term = parseTerm(tokens, length); + if (term == nullptr || *length == 0 || (*tokens)[0].of() != Token::TOKEN_OPERATOR) + { + return term; + } + auto _operator = (*tokens)[0].identifier()[0]; + ++(*tokens); + --(*length); + + auto expression = parseExpression(tokens, length); + + if (expression != nullptr) + { + auto binaryExpression = new BinaryExpression(term, expression, _operator); + + return binaryExpression; + } + else + { + return nullptr; + } + } + + Definition *parseDefinition(Token **tokens, size_t *length) + { + auto definition = new Definition(); + definition->identifier = (*tokens)[0].identifier(); // Copy. + + ++(*tokens); + ++(*tokens); // Skip the equals sign. + *length -= 2; + + if ((*tokens)[0].of() == Token::TOKEN_NUMBER) + { + auto number = new Number(); + number->value = (*tokens)[0].number(); + definition->number = number; + ++(*tokens); + --(*length); + return definition; + } + return nullptr; + } + + Statement *parseStatement(Token **tokens, std::size_t *length) + { + if ((*tokens)[0].of() == Token::TOKEN_BANG) + { + ++(*tokens); + --(*length); + auto statement = new BangStatement(); + auto expression = parseExpression(tokens, length); + if (expression != nullptr) + { + statement->expression = expression; + } + else + { + return nullptr; + } + return statement; + } + return nullptr; + } + + Definition **parseDefinitions(Token **tokens, size_t *length, size_t *resultLength) + { + ++(*tokens); // Skip const. + --(*length); + + Definition **definitions; + *resultLength = 0; + + while (*length != 0) + { + auto definition = parseDefinition(tokens, length); + if (definition == nullptr) + { + return nullptr; + } + definitions = reinterpret_cast( + realloc(definitions, (*resultLength + 1) * sizeof(Definition*))); + definitions[(*resultLength)++] = definition; + + if ((*tokens)[0].of() == Token::TOKEN_SEMICOLON) + { + break; + } + if ((*tokens)[0].of() == Token::TOKEN_COMMA) + { + ++(*tokens); + --(*length); + } + } + + return definitions; + } + + Block *parseBlock(Token **tokens, std::size_t *length) + { + auto block = new Block(); + if ((*tokens)[0].of() == Token::TOKEN_LET) + { + size_t length_ = 0; + auto constDefinitions = parseDefinitions(tokens, length, &length_); + if (constDefinitions != nullptr) + { + block->definitionsLength = length_; + block->definitions = constDefinitions; + } + else + { + return nullptr; + } + ++(*tokens); + --(*length); + } + auto statement = parseStatement(tokens, length); + if (statement != nullptr) + { + block->statement = statement; + } + else + { + return nullptr; + } + return block; + } +} diff --git a/source/result.cpp b/source/result.cpp index c027c70..a65e55f 100644 --- a/source/result.cpp +++ b/source/result.cpp @@ -22,4 +22,9 @@ namespace elna { return this->position.column; } + + Symbol::Symbol(const char *name) + { + this->name = name; + } } diff --git a/source/riscv.cpp b/source/riscv.cpp index c8d434f..ac1787a 100644 --- a/source/riscv.cpp +++ b/source/riscv.cpp @@ -1,5 +1,6 @@ #include "elna/parser.hpp" #include "elna/riscv.hpp" +#include #include namespace elna @@ -53,35 +54,43 @@ namespace elna return reinterpret_cast(&this->instruction); } - void RiscVVisitor::visit(ir::Node *) + void RiscVVisitor::visit(Node *) { } - void RiscVVisitor::visit(ir::Definition *definition) + void RiscVVisitor::visit(Definition *definition) { - const uint stackSize = static_cast(definition->statementsLength * 4 + 12); + ++constCount; + constNames = reinterpret_cast(realloc(constNames, sizeof(const char *) * constCount)); + constValues = reinterpret_cast(realloc(constValues, sizeof(std::int32_t) * constCount)); + constNames[constCount - 1] = definition->identifier; + constValues[constCount - 1] = definition->number->value; + } + + void RiscVVisitor::visit(Block *block) + { + for (std::size_t i = 0; i < block->definitionsLength; ++i) + { + block->definitions[i]->accept(this); + } this->instructionsLength += 4; this->instructions = reinterpret_cast( realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - // Prologue. - this->instructions[instructionsLength - 4] = Instruction(BaseOpcode::opImm) - .i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize); - this->instructions[instructionsLength - 3] = Instruction(BaseOpcode::store) - .s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0); - this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::store) - .s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra); - this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::opImm) - .i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize); + block->statement->accept(this); - for (std::size_t i = 0; i < definition->statementsLength; ++i) - { - definition->statements[i]->accept(this); - } - this->registerInUse = true; - definition->result->accept(this); - this->registerInUse = false; + // Prologue. + const uint stackSize = static_cast(variableCounter * 4 + 12); + + this->instructions[0] = Instruction(BaseOpcode::opImm) + .i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize); + this->instructions[1] = Instruction(BaseOpcode::store) + .s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0); + this->instructions[2] = Instruction(BaseOpcode::store) + .s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra); + this->instructions[3] = Instruction(BaseOpcode::opImm) + .i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize); this->instructions = reinterpret_cast( realloc(this->instructions, (this->instructionsLength + 10) * sizeof(Instruction))); @@ -123,32 +132,44 @@ namespace elna .i(XRegister::zero, Funct3::jalr, XRegister::ra, 0); } - void RiscVVisitor::visit(ir::Operand *operand) + void RiscVVisitor::visit(BangStatement *statement) { - if (dynamic_cast(operand) != nullptr) + statement->expression->accept(this); + } + + void RiscVVisitor::visit(Expression *operand) + { + if (dynamic_cast(operand) != nullptr) { - return dynamic_cast(operand)->accept(this); + return dynamic_cast(operand)->accept(this); } - if (dynamic_cast(operand) != nullptr) + if (dynamic_cast(operand) != nullptr) { - return dynamic_cast(operand)->accept(this); + return dynamic_cast(operand)->accept(this); } } - void RiscVVisitor::visit(ir::Variable *variable) + void RiscVVisitor::visit(Variable *variable) { + std::size_t i = 0; + for (; i < constCount; ++i) + { + if (strcmp(variable->identifier, constNames[i]) == 0) + { + break; + } + } const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0; ++this->instructionsLength; this->instructions = reinterpret_cast( realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - // movl -x(%rbp), %eax; where x is a number. - this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::load) - .i(freeRegister, Funct3::lw, XRegister::sp, - static_cast(variable->counter * 4)); + this->instructions[this->instructionsLength - 1] = + Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number. + .i(freeRegister, Funct3::addi, XRegister::zero, constValues[i]); } - void RiscVVisitor::visit(ir::Number *number) + void RiscVVisitor::visit(Number *number) { const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0; @@ -160,32 +181,63 @@ namespace elna .i(freeRegister, Funct3::addi, XRegister::zero, number->value); } - void RiscVVisitor::visit(ir::BinaryExpression *expression) + void RiscVVisitor::visit(BinaryExpression *expression) { + const auto lhs_register = this->registerInUse ? XRegister::a0 : XRegister::t0; + this->registerInUse = true; expression->lhs->accept(this); + + ++this->instructionsLength; + this->instructions = reinterpret_cast( + realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); + this->instructions[instructionsLength - 1] = // movl %eax, -x(%rbp); where x is a number. + Instruction(BaseOpcode::store) + .s(static_cast(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0); + auto lhs_stack_position = ++this->variableCounter; + this->registerInUse = false; expression->rhs->accept(this); this->instructionsLength += 2; this->instructions = reinterpret_cast( realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); + + this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::load) + .i(XRegister::a0, Funct3::lw, XRegister::sp, + static_cast((lhs_stack_position - 1) * 4)); + // Calculate the result and assign it to a variable on the stack. switch (expression->_operator) { case BinaryOperator::sum: - this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::op) - .r(XRegister::a0, Funct3::add, XRegister::a0, XRegister::t0); + this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op) + .r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0); break; case BinaryOperator::subtraction: - this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::op) - .r(XRegister::a0, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub); + this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op) + .r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub); break; } - this->instructions[instructionsLength - 1] = // movl %eax, -x(%rbp); where x is a number. - Instruction(BaseOpcode::store) - .s(static_cast(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0); + } - ++this->variableCounter; + Symbol writeNext(Block *ast) + { + auto visitor = std::make_unique(); + visitor->visit(ast); + + Symbol program{ "main" }; + + for (std::size_t i = 0; i < 3; ++i) + { + program.symbols[i] = visitor->references[i]; + } + program.text = reinterpret_cast(malloc(sizeof(std::uint32_t) * visitor->instructionsLength)); + for (std::size_t i = 0; i < visitor->instructionsLength; ++i) + { + memcpy(program.text + program.length, visitor->instructions[i].encode(), sizeof(std::uint32_t)); + program.length += sizeof(std::uint32_t); + } + return program; } }