198b9484cSchristos /* simple-object-elf.c -- routines to manipulate ELF object files. 2*5173eb0aSchristos Copyright (C) 2010-2024 Free Software Foundation, Inc. 398b9484cSchristos Written by Ian Lance Taylor, Google. 498b9484cSchristos 598b9484cSchristos This program is free software; you can redistribute it and/or modify it 698b9484cSchristos under the terms of the GNU General Public License as published by the 798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any 898b9484cSchristos later version. 998b9484cSchristos 1098b9484cSchristos This program is distributed in the hope that it will be useful, 1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1398b9484cSchristos GNU General Public License for more details. 1498b9484cSchristos 1598b9484cSchristos You should have received a copy of the GNU General Public License 1698b9484cSchristos along with this program; if not, write to the Free Software 1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor, 1898b9484cSchristos Boston, MA 02110-1301, USA. */ 1998b9484cSchristos 2098b9484cSchristos #include "config.h" 2198b9484cSchristos #include "libiberty.h" 2298b9484cSchristos #include "simple-object.h" 2398b9484cSchristos 2498b9484cSchristos #include <errno.h> 254559860eSchristos /* mingw.org's MinGW doesn't have ENOTSUP. */ 264559860eSchristos #ifndef ENOTSUP 274559860eSchristos # define ENOTSUP ENOSYS 284559860eSchristos #endif 2998b9484cSchristos #include <stddef.h> 3098b9484cSchristos 3198b9484cSchristos #ifdef HAVE_STDLIB_H 3298b9484cSchristos #include <stdlib.h> 3398b9484cSchristos #endif 3498b9484cSchristos 3598b9484cSchristos #ifdef HAVE_STDINT_H 3698b9484cSchristos #include <stdint.h> 3798b9484cSchristos #endif 3898b9484cSchristos 3998b9484cSchristos #ifdef HAVE_STRING_H 4098b9484cSchristos #include <string.h> 4198b9484cSchristos #endif 4298b9484cSchristos 4398b9484cSchristos #ifdef HAVE_INTTYPES_H 4498b9484cSchristos #include <inttypes.h> 4598b9484cSchristos #endif 4698b9484cSchristos 4798b9484cSchristos #include "simple-object-common.h" 4898b9484cSchristos 4998b9484cSchristos /* ELF structures and constants. */ 5098b9484cSchristos 5198b9484cSchristos /* 32-bit ELF file header. */ 5298b9484cSchristos 5398b9484cSchristos typedef struct { 5498b9484cSchristos unsigned char e_ident[16]; /* ELF "magic number" */ 5598b9484cSchristos unsigned char e_type[2]; /* Identifies object file type */ 5698b9484cSchristos unsigned char e_machine[2]; /* Specifies required architecture */ 5798b9484cSchristos unsigned char e_version[4]; /* Identifies object file version */ 5898b9484cSchristos unsigned char e_entry[4]; /* Entry point virtual address */ 5998b9484cSchristos unsigned char e_phoff[4]; /* Program header table file offset */ 6098b9484cSchristos unsigned char e_shoff[4]; /* Section header table file offset */ 6198b9484cSchristos unsigned char e_flags[4]; /* Processor-specific flags */ 6298b9484cSchristos unsigned char e_ehsize[2]; /* ELF header size in bytes */ 6398b9484cSchristos unsigned char e_phentsize[2]; /* Program header table entry size */ 6498b9484cSchristos unsigned char e_phnum[2]; /* Program header table entry count */ 6598b9484cSchristos unsigned char e_shentsize[2]; /* Section header table entry size */ 6698b9484cSchristos unsigned char e_shnum[2]; /* Section header table entry count */ 6798b9484cSchristos unsigned char e_shstrndx[2]; /* Section header string table index */ 6898b9484cSchristos } Elf32_External_Ehdr; 6998b9484cSchristos 7098b9484cSchristos /* 64-bit ELF file header. */ 7198b9484cSchristos 7298b9484cSchristos typedef struct { 7398b9484cSchristos unsigned char e_ident[16]; /* ELF "magic number" */ 7498b9484cSchristos unsigned char e_type[2]; /* Identifies object file type */ 7598b9484cSchristos unsigned char e_machine[2]; /* Specifies required architecture */ 7698b9484cSchristos unsigned char e_version[4]; /* Identifies object file version */ 7798b9484cSchristos unsigned char e_entry[8]; /* Entry point virtual address */ 7898b9484cSchristos unsigned char e_phoff[8]; /* Program header table file offset */ 7998b9484cSchristos unsigned char e_shoff[8]; /* Section header table file offset */ 8098b9484cSchristos unsigned char e_flags[4]; /* Processor-specific flags */ 8198b9484cSchristos unsigned char e_ehsize[2]; /* ELF header size in bytes */ 8298b9484cSchristos unsigned char e_phentsize[2]; /* Program header table entry size */ 8398b9484cSchristos unsigned char e_phnum[2]; /* Program header table entry count */ 8498b9484cSchristos unsigned char e_shentsize[2]; /* Section header table entry size */ 8598b9484cSchristos unsigned char e_shnum[2]; /* Section header table entry count */ 8698b9484cSchristos unsigned char e_shstrndx[2]; /* Section header string table index */ 8798b9484cSchristos } Elf64_External_Ehdr; 8898b9484cSchristos 8998b9484cSchristos /* Indexes and values in e_ident field of Ehdr. */ 9098b9484cSchristos 9198b9484cSchristos #define EI_MAG0 0 /* File identification byte 0 index */ 9298b9484cSchristos #define ELFMAG0 0x7F /* Magic number byte 0 */ 9398b9484cSchristos 9498b9484cSchristos #define EI_MAG1 1 /* File identification byte 1 index */ 9598b9484cSchristos #define ELFMAG1 'E' /* Magic number byte 1 */ 9698b9484cSchristos 9798b9484cSchristos #define EI_MAG2 2 /* File identification byte 2 index */ 9898b9484cSchristos #define ELFMAG2 'L' /* Magic number byte 2 */ 9998b9484cSchristos 10098b9484cSchristos #define EI_MAG3 3 /* File identification byte 3 index */ 10198b9484cSchristos #define ELFMAG3 'F' /* Magic number byte 3 */ 10298b9484cSchristos 10398b9484cSchristos #define EI_CLASS 4 /* File class */ 10498b9484cSchristos #define ELFCLASSNONE 0 /* Invalid class */ 10598b9484cSchristos #define ELFCLASS32 1 /* 32-bit objects */ 10698b9484cSchristos #define ELFCLASS64 2 /* 64-bit objects */ 10798b9484cSchristos 10898b9484cSchristos #define EI_DATA 5 /* Data encoding */ 10998b9484cSchristos #define ELFDATANONE 0 /* Invalid data encoding */ 11098b9484cSchristos #define ELFDATA2LSB 1 /* 2's complement, little endian */ 11198b9484cSchristos #define ELFDATA2MSB 2 /* 2's complement, big endian */ 11298b9484cSchristos 11398b9484cSchristos #define EI_VERSION 6 /* File version */ 11498b9484cSchristos #define EV_CURRENT 1 /* Current version */ 11598b9484cSchristos 11698b9484cSchristos #define EI_OSABI 7 /* Operating System/ABI indication */ 11798b9484cSchristos 11898b9484cSchristos /* Values for e_type field of Ehdr. */ 11998b9484cSchristos 12098b9484cSchristos #define ET_REL 1 /* Relocatable file */ 12198b9484cSchristos 12298b9484cSchristos /* Values for e_machine field of Ehdr. */ 12398b9484cSchristos 12498b9484cSchristos #define EM_SPARC 2 /* SUN SPARC */ 12598b9484cSchristos #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ 12698b9484cSchristos 12798b9484cSchristos /* Special section index values. */ 12898b9484cSchristos 1294559860eSchristos #define SHN_UNDEF 0 /* Undefined section */ 13098b9484cSchristos #define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ 1314559860eSchristos #define SHN_COMMON 0xFFF2 /* Associated symbol is in common */ 13298b9484cSchristos #define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ 1334559860eSchristos #define SHN_HIRESERVE 0xffff /* End of reserved indices */ 1344559860eSchristos 13598b9484cSchristos 13698b9484cSchristos /* 32-bit ELF program header. */ 13798b9484cSchristos 13898b9484cSchristos typedef struct { 13998b9484cSchristos unsigned char p_type[4]; /* Identifies program segment type */ 14098b9484cSchristos unsigned char p_offset[4]; /* Segment file offset */ 14198b9484cSchristos unsigned char p_vaddr[4]; /* Segment virtual address */ 14298b9484cSchristos unsigned char p_paddr[4]; /* Segment physical address */ 14398b9484cSchristos unsigned char p_filesz[4]; /* Segment size in file */ 14498b9484cSchristos unsigned char p_memsz[4]; /* Segment size in memory */ 14598b9484cSchristos unsigned char p_flags[4]; /* Segment flags */ 14698b9484cSchristos unsigned char p_align[4]; /* Segment alignment, file & memory */ 14798b9484cSchristos } Elf32_External_Phdr; 14898b9484cSchristos 14998b9484cSchristos /* 64-bit ELF program header. */ 15098b9484cSchristos 15198b9484cSchristos typedef struct { 15298b9484cSchristos unsigned char p_type[4]; /* Identifies program segment type */ 15398b9484cSchristos unsigned char p_flags[4]; /* Segment flags */ 15498b9484cSchristos unsigned char p_offset[8]; /* Segment file offset */ 15598b9484cSchristos unsigned char p_vaddr[8]; /* Segment virtual address */ 15698b9484cSchristos unsigned char p_paddr[8]; /* Segment physical address */ 15798b9484cSchristos unsigned char p_filesz[8]; /* Segment size in file */ 15898b9484cSchristos unsigned char p_memsz[8]; /* Segment size in memory */ 15998b9484cSchristos unsigned char p_align[8]; /* Segment alignment, file & memory */ 16098b9484cSchristos } Elf64_External_Phdr; 16198b9484cSchristos 16298b9484cSchristos /* 32-bit ELF section header */ 16398b9484cSchristos 16498b9484cSchristos typedef struct { 16598b9484cSchristos unsigned char sh_name[4]; /* Section name, index in string tbl */ 16698b9484cSchristos unsigned char sh_type[4]; /* Type of section */ 16798b9484cSchristos unsigned char sh_flags[4]; /* Miscellaneous section attributes */ 16898b9484cSchristos unsigned char sh_addr[4]; /* Section virtual addr at execution */ 16998b9484cSchristos unsigned char sh_offset[4]; /* Section file offset */ 17098b9484cSchristos unsigned char sh_size[4]; /* Size of section in bytes */ 17198b9484cSchristos unsigned char sh_link[4]; /* Index of another section */ 17298b9484cSchristos unsigned char sh_info[4]; /* Additional section information */ 17398b9484cSchristos unsigned char sh_addralign[4]; /* Section alignment */ 17498b9484cSchristos unsigned char sh_entsize[4]; /* Entry size if section holds table */ 17598b9484cSchristos } Elf32_External_Shdr; 17698b9484cSchristos 17798b9484cSchristos /* 64-bit ELF section header. */ 17898b9484cSchristos 17998b9484cSchristos typedef struct { 18098b9484cSchristos unsigned char sh_name[4]; /* Section name, index in string tbl */ 18198b9484cSchristos unsigned char sh_type[4]; /* Type of section */ 18298b9484cSchristos unsigned char sh_flags[8]; /* Miscellaneous section attributes */ 18398b9484cSchristos unsigned char sh_addr[8]; /* Section virtual addr at execution */ 18498b9484cSchristos unsigned char sh_offset[8]; /* Section file offset */ 18598b9484cSchristos unsigned char sh_size[8]; /* Size of section in bytes */ 18698b9484cSchristos unsigned char sh_link[4]; /* Index of another section */ 18798b9484cSchristos unsigned char sh_info[4]; /* Additional section information */ 18898b9484cSchristos unsigned char sh_addralign[8]; /* Section alignment */ 18998b9484cSchristos unsigned char sh_entsize[8]; /* Entry size if section holds table */ 19098b9484cSchristos } Elf64_External_Shdr; 19198b9484cSchristos 19298b9484cSchristos /* Values for sh_type field. */ 19398b9484cSchristos 1944559860eSchristos #define SHT_NULL 0 /* Section header table entry unused */ 19598b9484cSchristos #define SHT_PROGBITS 1 /* Program data */ 1964559860eSchristos #define SHT_SYMTAB 2 /* Link editing symbol table */ 19798b9484cSchristos #define SHT_STRTAB 3 /* A string table */ 1984559860eSchristos #define SHT_RELA 4 /* Relocation entries with addends */ 1994559860eSchristos #define SHT_REL 9 /* Relocation entries, no addends */ 2004559860eSchristos #define SHT_GROUP 17 /* Section contains a section group */ 2014559860eSchristos #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ 2024559860eSchristos 2034559860eSchristos /* Values for sh_flags field. */ 2044559860eSchristos 2054559860eSchristos #define SHF_INFO_LINK 0x00000040 /* `sh_info' contains SHT index */ 2064559860eSchristos #define SHF_EXECINSTR 0x00000004 /* Executable section. */ 2074559860eSchristos #define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude this 2084559860eSchristos section from executable and 2094559860eSchristos shared library that it builds 2104559860eSchristos when those objects are not to be 2114559860eSchristos further relocated. */ 2124559860eSchristos /* Symbol table entry. */ 2134559860eSchristos 2144559860eSchristos typedef struct 2154559860eSchristos { 2164559860eSchristos unsigned char st_name[4]; /* Symbol name (string tbl index) */ 2174559860eSchristos unsigned char st_value[4]; /* Symbol value */ 2184559860eSchristos unsigned char st_size[4]; /* Symbol size */ 2194559860eSchristos unsigned char st_info; /* Symbol type and binding */ 2204559860eSchristos unsigned char st_other; /* Symbol visibility */ 2214559860eSchristos unsigned char st_shndx[2]; /* Section index */ 2224559860eSchristos } Elf32_External_Sym; 2234559860eSchristos 2244559860eSchristos typedef struct 2254559860eSchristos { 2264559860eSchristos unsigned char st_name[4]; /* Symbol name (string tbl index) */ 2274559860eSchristos unsigned char st_info; /* Symbol type and binding */ 2284559860eSchristos unsigned char st_other; /* Symbol visibility */ 2294559860eSchristos unsigned char st_shndx[2]; /* Section index */ 2304559860eSchristos unsigned char st_value[8]; /* Symbol value */ 2314559860eSchristos unsigned char st_size[8]; /* Symbol size */ 2324559860eSchristos } Elf64_External_Sym; 2334559860eSchristos 2344559860eSchristos #define ELF_ST_BIND(val) (((unsigned char) (val)) >> 4) 2354559860eSchristos #define ELF_ST_TYPE(val) ((val) & 0xf) 2364559860eSchristos #define ELF_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) 2374559860eSchristos 2384559860eSchristos #define STT_NOTYPE 0 /* Symbol type is unspecified */ 2394559860eSchristos #define STT_OBJECT 1 /* Symbol is a data object */ 2404559860eSchristos #define STT_FUNC 2 /* Symbol is a code object */ 2414559860eSchristos #define STT_TLS 6 /* Thread local data object */ 2424559860eSchristos #define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */ 2434559860eSchristos 2444559860eSchristos #define STB_LOCAL 0 /* Local symbol */ 2454559860eSchristos #define STB_GLOBAL 1 /* Global symbol */ 2464559860eSchristos #define STB_WEAK 2 /* Weak global */ 2474559860eSchristos 2484559860eSchristos #define STV_DEFAULT 0 /* Visibility is specified by binding type */ 2494559860eSchristos #define STV_HIDDEN 2 /* Can only be seen inside currect component */ 25098b9484cSchristos 25198b9484cSchristos /* Functions to fetch and store different ELF types, depending on the 25298b9484cSchristos endianness and size. */ 25398b9484cSchristos 25498b9484cSchristos struct elf_type_functions 25598b9484cSchristos { 25698b9484cSchristos unsigned short (*fetch_Elf_Half) (const unsigned char *); 25798b9484cSchristos unsigned int (*fetch_Elf_Word) (const unsigned char *); 25898b9484cSchristos ulong_type (*fetch_Elf_Addr) (const unsigned char *); 25998b9484cSchristos void (*set_Elf_Half) (unsigned char *, unsigned short); 26098b9484cSchristos void (*set_Elf_Word) (unsigned char *, unsigned int); 26198b9484cSchristos void (*set_Elf_Addr) (unsigned char *, ulong_type); 26298b9484cSchristos }; 26398b9484cSchristos 26498b9484cSchristos static const struct elf_type_functions elf_big_32_functions = 26598b9484cSchristos { 26698b9484cSchristos simple_object_fetch_big_16, 26798b9484cSchristos simple_object_fetch_big_32, 26898b9484cSchristos simple_object_fetch_big_32_ulong, 26998b9484cSchristos simple_object_set_big_16, 27098b9484cSchristos simple_object_set_big_32, 27198b9484cSchristos simple_object_set_big_32_ulong 27298b9484cSchristos }; 27398b9484cSchristos 27498b9484cSchristos static const struct elf_type_functions elf_little_32_functions = 27598b9484cSchristos { 27698b9484cSchristos simple_object_fetch_little_16, 27798b9484cSchristos simple_object_fetch_little_32, 27898b9484cSchristos simple_object_fetch_little_32_ulong, 27998b9484cSchristos simple_object_set_little_16, 28098b9484cSchristos simple_object_set_little_32, 28198b9484cSchristos simple_object_set_little_32_ulong 28298b9484cSchristos }; 28398b9484cSchristos 28498b9484cSchristos #ifdef UNSIGNED_64BIT_TYPE 28598b9484cSchristos 28698b9484cSchristos static const struct elf_type_functions elf_big_64_functions = 28798b9484cSchristos { 28898b9484cSchristos simple_object_fetch_big_16, 28998b9484cSchristos simple_object_fetch_big_32, 29098b9484cSchristos simple_object_fetch_big_64, 29198b9484cSchristos simple_object_set_big_16, 29298b9484cSchristos simple_object_set_big_32, 29398b9484cSchristos simple_object_set_big_64 29498b9484cSchristos }; 29598b9484cSchristos 29698b9484cSchristos static const struct elf_type_functions elf_little_64_functions = 29798b9484cSchristos { 29898b9484cSchristos simple_object_fetch_little_16, 29998b9484cSchristos simple_object_fetch_little_32, 30098b9484cSchristos simple_object_fetch_little_64, 30198b9484cSchristos simple_object_set_little_16, 30298b9484cSchristos simple_object_set_little_32, 30398b9484cSchristos simple_object_set_little_64 30498b9484cSchristos }; 30598b9484cSchristos 30698b9484cSchristos #endif 30798b9484cSchristos 30898b9484cSchristos /* Hideous macro to fetch the value of a field from an external ELF 30998b9484cSchristos struct of some sort. TYPEFUNCS is the set of type functions. 31098b9484cSchristos BUFFER points to the external data. STRUCTTYPE is the appropriate 31198b9484cSchristos struct type. FIELD is a field within the struct. TYPE is the type 31298b9484cSchristos of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */ 31398b9484cSchristos 31498b9484cSchristos #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \ 31598b9484cSchristos ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD))) 31698b9484cSchristos 31798b9484cSchristos /* Even more hideous macro to fetch the value of FIELD from BUFFER. 31898b9484cSchristos SIZE is 32 or 64. STRUCTTYPE is the name of the struct from 31998b9484cSchristos elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in 32098b9484cSchristos the struct. TYPE is the type of the field in the struct: Elf_Half, 32198b9484cSchristos Elf_Word, or Elf_Addr. */ 32298b9484cSchristos 32398b9484cSchristos #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \ 32498b9484cSchristos FIELD, TYPE) \ 32598b9484cSchristos ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \ 32698b9484cSchristos Elf ## SIZE ## _External_ ## STRUCTTYPE, \ 32798b9484cSchristos FIELD, BUFFER, TYPE) 32898b9484cSchristos 32998b9484cSchristos /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */ 33098b9484cSchristos 33198b9484cSchristos #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \ 33298b9484cSchristos FIELD, TYPE) \ 33398b9484cSchristos ((CLASS) == ELFCLASS32 \ 33498b9484cSchristos ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ 33598b9484cSchristos TYPE) \ 33698b9484cSchristos : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ 33798b9484cSchristos TYPE)) 33898b9484cSchristos 33998b9484cSchristos /* Hideous macro to set the value of a field in an external ELF 34098b9484cSchristos structure to VAL. TYPEFUNCS is the set of type functions. BUFFER 34198b9484cSchristos points to the external data. STRUCTTYPE is the appropriate 34298b9484cSchristos structure type. FIELD is a field within the struct. TYPE is the 34398b9484cSchristos type of the field in the struct: Elf_Half, Elf_Word, or 34498b9484cSchristos Elf_Addr. */ 34598b9484cSchristos 34698b9484cSchristos #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \ 34798b9484cSchristos (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL)) 34898b9484cSchristos 34998b9484cSchristos /* Even more hideous macro to set the value of FIELD in BUFFER to VAL. 35098b9484cSchristos SIZE is 32 or 64. STRUCTTYPE is the name of the struct from 35198b9484cSchristos elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in 35298b9484cSchristos the struct. TYPE is the type of the field in the struct: Elf_Half, 35398b9484cSchristos Elf_Word, or Elf_Addr. */ 35498b9484cSchristos 35598b9484cSchristos #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \ 35698b9484cSchristos TYPE, VAL) \ 35798b9484cSchristos ELF_SET_STRUCT_FIELD (TYPEFUNCS, \ 35898b9484cSchristos Elf ## SIZE ## _External_ ## STRUCTTYPE, \ 35998b9484cSchristos FIELD, BUFFER, TYPE, VAL) 36098b9484cSchristos 36198b9484cSchristos /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */ 36298b9484cSchristos 36398b9484cSchristos #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \ 36498b9484cSchristos TYPE, VAL) \ 36598b9484cSchristos ((CLASS) == ELFCLASS32 \ 36698b9484cSchristos ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ 36798b9484cSchristos TYPE, VAL) \ 36898b9484cSchristos : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ 36998b9484cSchristos TYPE, VAL)) 37098b9484cSchristos 37198b9484cSchristos /* Private data for an simple_object_read. */ 37298b9484cSchristos 37398b9484cSchristos struct simple_object_elf_read 37498b9484cSchristos { 37598b9484cSchristos /* Type functions. */ 37698b9484cSchristos const struct elf_type_functions* type_functions; 37798b9484cSchristos /* Elf data. */ 37898b9484cSchristos unsigned char ei_data; 37998b9484cSchristos /* Elf class. */ 38098b9484cSchristos unsigned char ei_class; 38198b9484cSchristos /* ELF OS ABI. */ 38298b9484cSchristos unsigned char ei_osabi; 38398b9484cSchristos /* Elf machine number. */ 38498b9484cSchristos unsigned short machine; 38598b9484cSchristos /* Processor specific flags. */ 38698b9484cSchristos unsigned int flags; 38798b9484cSchristos /* File offset of section headers. */ 38898b9484cSchristos ulong_type shoff; 38998b9484cSchristos /* Number of sections. */ 39098b9484cSchristos unsigned int shnum; 39198b9484cSchristos /* Index of string table section header. */ 39298b9484cSchristos unsigned int shstrndx; 39398b9484cSchristos }; 39498b9484cSchristos 39598b9484cSchristos /* Private data for an simple_object_attributes. */ 39698b9484cSchristos 39798b9484cSchristos struct simple_object_elf_attributes 39898b9484cSchristos { 39998b9484cSchristos /* Type functions. */ 40098b9484cSchristos const struct elf_type_functions* type_functions; 40198b9484cSchristos /* Elf data. */ 40298b9484cSchristos unsigned char ei_data; 40398b9484cSchristos /* Elf class. */ 40498b9484cSchristos unsigned char ei_class; 40598b9484cSchristos /* ELF OS ABI. */ 40698b9484cSchristos unsigned char ei_osabi; 40798b9484cSchristos /* Elf machine number. */ 40898b9484cSchristos unsigned short machine; 40998b9484cSchristos /* Processor specific flags. */ 41098b9484cSchristos unsigned int flags; 41198b9484cSchristos }; 41298b9484cSchristos 4134559860eSchristos /* Private data for an simple_object_write. */ 4144559860eSchristos 4154559860eSchristos struct simple_object_elf_write 4164559860eSchristos { 4174559860eSchristos struct simple_object_elf_attributes attrs; 4184559860eSchristos unsigned char *shdrs; 4194559860eSchristos }; 4204559860eSchristos 42198b9484cSchristos /* See if we have an ELF file. */ 42298b9484cSchristos 42398b9484cSchristos static void * 42498b9484cSchristos simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 42598b9484cSchristos int descriptor, off_t offset, 42698b9484cSchristos const char *segment_name ATTRIBUTE_UNUSED, 42798b9484cSchristos const char **errmsg, int *err) 42898b9484cSchristos { 42998b9484cSchristos unsigned char ei_data; 43098b9484cSchristos unsigned char ei_class; 43198b9484cSchristos const struct elf_type_functions *type_functions; 43298b9484cSchristos unsigned char ehdr[sizeof (Elf64_External_Ehdr)]; 43398b9484cSchristos struct simple_object_elf_read *eor; 43498b9484cSchristos 43598b9484cSchristos if (header[EI_MAG0] != ELFMAG0 43698b9484cSchristos || header[EI_MAG1] != ELFMAG1 43798b9484cSchristos || header[EI_MAG2] != ELFMAG2 43898b9484cSchristos || header[EI_MAG3] != ELFMAG3 43998b9484cSchristos || header[EI_VERSION] != EV_CURRENT) 44098b9484cSchristos { 44198b9484cSchristos *errmsg = NULL; 44298b9484cSchristos *err = 0; 44398b9484cSchristos return NULL; 44498b9484cSchristos } 44598b9484cSchristos 44698b9484cSchristos ei_data = header[EI_DATA]; 44798b9484cSchristos if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB) 44898b9484cSchristos { 44998b9484cSchristos *errmsg = "unknown ELF endianness"; 45098b9484cSchristos *err = 0; 45198b9484cSchristos return NULL; 45298b9484cSchristos } 45398b9484cSchristos 45498b9484cSchristos ei_class = header[EI_CLASS]; 45598b9484cSchristos switch (ei_class) 45698b9484cSchristos { 45798b9484cSchristos case ELFCLASS32: 45898b9484cSchristos type_functions = (ei_data == ELFDATA2LSB 45998b9484cSchristos ? &elf_little_32_functions 46098b9484cSchristos : &elf_big_32_functions); 46198b9484cSchristos break; 46298b9484cSchristos 46398b9484cSchristos case ELFCLASS64: 46498b9484cSchristos #ifndef UNSIGNED_64BIT_TYPE 46598b9484cSchristos *errmsg = "64-bit ELF objects not supported"; 46698b9484cSchristos *err = 0; 46798b9484cSchristos return NULL; 46898b9484cSchristos #else 46998b9484cSchristos type_functions = (ei_data == ELFDATA2LSB 47098b9484cSchristos ? &elf_little_64_functions 47198b9484cSchristos : &elf_big_64_functions); 47298b9484cSchristos break; 47398b9484cSchristos #endif 47498b9484cSchristos 47598b9484cSchristos default: 47698b9484cSchristos *errmsg = "unrecognized ELF size"; 47798b9484cSchristos *err = 0; 47898b9484cSchristos return NULL; 47998b9484cSchristos } 48098b9484cSchristos 48198b9484cSchristos if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr, 48298b9484cSchristos errmsg, err)) 48398b9484cSchristos return NULL; 48498b9484cSchristos 48598b9484cSchristos eor = XNEW (struct simple_object_elf_read); 48698b9484cSchristos eor->type_functions = type_functions; 48798b9484cSchristos eor->ei_data = ei_data; 48898b9484cSchristos eor->ei_class = ei_class; 48998b9484cSchristos eor->ei_osabi = header[EI_OSABI]; 49098b9484cSchristos eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, 49198b9484cSchristos e_machine, Elf_Half); 49298b9484cSchristos eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, 49398b9484cSchristos e_flags, Elf_Word); 49498b9484cSchristos eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, 49598b9484cSchristos e_shoff, Elf_Addr); 49698b9484cSchristos eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, 49798b9484cSchristos e_shnum, Elf_Half); 49898b9484cSchristos eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, 49998b9484cSchristos e_shstrndx, Elf_Half); 50098b9484cSchristos 50198b9484cSchristos if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX) 50298b9484cSchristos && eor->shoff != 0) 50398b9484cSchristos { 50498b9484cSchristos unsigned char shdr[sizeof (Elf64_External_Shdr)]; 50598b9484cSchristos 50698b9484cSchristos /* Object file has more than 0xffff sections. */ 50798b9484cSchristos 50898b9484cSchristos if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr, 50998b9484cSchristos (ei_class == ELFCLASS32 51098b9484cSchristos ? sizeof (Elf32_External_Shdr) 51198b9484cSchristos : sizeof (Elf64_External_Shdr)), 51298b9484cSchristos errmsg, err)) 51398b9484cSchristos { 51498b9484cSchristos XDELETE (eor); 51598b9484cSchristos return NULL; 51698b9484cSchristos } 51798b9484cSchristos 51898b9484cSchristos if (eor->shnum == 0) 51998b9484cSchristos eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 52098b9484cSchristos shdr, sh_size, Elf_Addr); 52198b9484cSchristos 52298b9484cSchristos if (eor->shstrndx == SHN_XINDEX) 52398b9484cSchristos { 52498b9484cSchristos eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 52598b9484cSchristos shdr, sh_link, Elf_Word); 52698b9484cSchristos 52798b9484cSchristos /* Versions of the GNU binutils between 2.12 and 2.18 did 52898b9484cSchristos not handle objects with more than SHN_LORESERVE sections 52998b9484cSchristos correctly. All large section indexes were offset by 53098b9484cSchristos 0x100. There is more information at 5314b169a6bSchristos https://sourceware.org/PR5900 . 53298b9484cSchristos Fortunately these object files are easy to detect, as the 53398b9484cSchristos GNU binutils always put the section header string table 53498b9484cSchristos near the end of the list of sections. Thus if the 53598b9484cSchristos section header string table index is larger than the 53698b9484cSchristos number of sections, then we know we have to subtract 53798b9484cSchristos 0x100 to get the real section index. */ 53898b9484cSchristos if (eor->shstrndx >= eor->shnum 53998b9484cSchristos && eor->shstrndx >= SHN_LORESERVE + 0x100) 54098b9484cSchristos eor->shstrndx -= 0x100; 54198b9484cSchristos } 54298b9484cSchristos } 54398b9484cSchristos 54498b9484cSchristos if (eor->shstrndx >= eor->shnum) 54598b9484cSchristos { 54698b9484cSchristos *errmsg = "invalid ELF shstrndx >= shnum"; 54798b9484cSchristos *err = 0; 54898b9484cSchristos XDELETE (eor); 54998b9484cSchristos return NULL; 55098b9484cSchristos } 55198b9484cSchristos 5528dffb485Schristos if (eor->shstrndx == 0) 5538dffb485Schristos { 5548dffb485Schristos *errmsg = "invalid ELF shstrndx == 0"; 5558dffb485Schristos *err = 0; 5568dffb485Schristos XDELETE (eor); 5578dffb485Schristos return NULL; 5588dffb485Schristos } 5598dffb485Schristos 56098b9484cSchristos return (void *) eor; 56198b9484cSchristos } 56298b9484cSchristos 56398b9484cSchristos /* Find all sections in an ELF file. */ 56498b9484cSchristos 56598b9484cSchristos static const char * 56698b9484cSchristos simple_object_elf_find_sections (simple_object_read *sobj, 56798b9484cSchristos int (*pfn) (void *, const char *, 56898b9484cSchristos off_t offset, off_t length), 56998b9484cSchristos void *data, 57098b9484cSchristos int *err) 57198b9484cSchristos { 57298b9484cSchristos struct simple_object_elf_read *eor = 57398b9484cSchristos (struct simple_object_elf_read *) sobj->data; 57498b9484cSchristos const struct elf_type_functions *type_functions = eor->type_functions; 57598b9484cSchristos unsigned char ei_class = eor->ei_class; 57698b9484cSchristos size_t shdr_size; 57798b9484cSchristos unsigned int shnum; 57898b9484cSchristos unsigned char *shdrs; 57998b9484cSchristos const char *errmsg; 58098b9484cSchristos unsigned char *shstrhdr; 58198b9484cSchristos size_t name_size; 58298b9484cSchristos off_t shstroff; 58398b9484cSchristos unsigned char *names; 58498b9484cSchristos unsigned int i; 58598b9484cSchristos 58698b9484cSchristos shdr_size = (ei_class == ELFCLASS32 58798b9484cSchristos ? sizeof (Elf32_External_Shdr) 58898b9484cSchristos : sizeof (Elf64_External_Shdr)); 58998b9484cSchristos 59098b9484cSchristos /* Read the section headers. We skip section 0, which is not a 59198b9484cSchristos useful section. */ 59298b9484cSchristos 59398b9484cSchristos shnum = eor->shnum; 59498b9484cSchristos shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1)); 59598b9484cSchristos 59698b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, 59798b9484cSchristos sobj->offset + eor->shoff + shdr_size, 59898b9484cSchristos shdrs, 59998b9484cSchristos shdr_size * (shnum - 1), 60098b9484cSchristos &errmsg, err)) 60198b9484cSchristos { 60298b9484cSchristos XDELETEVEC (shdrs); 60398b9484cSchristos return errmsg; 60498b9484cSchristos } 60598b9484cSchristos 60698b9484cSchristos /* Read the section names. */ 60798b9484cSchristos 60898b9484cSchristos shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size; 60998b9484cSchristos name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 61098b9484cSchristos shstrhdr, sh_size, Elf_Addr); 61198b9484cSchristos shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 61298b9484cSchristos shstrhdr, sh_offset, Elf_Addr); 61398b9484cSchristos names = XNEWVEC (unsigned char, name_size); 61498b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, 61598b9484cSchristos sobj->offset + shstroff, 61698b9484cSchristos names, name_size, &errmsg, err)) 61798b9484cSchristos { 61898b9484cSchristos XDELETEVEC (names); 61998b9484cSchristos XDELETEVEC (shdrs); 62098b9484cSchristos return errmsg; 62198b9484cSchristos } 62298b9484cSchristos 62398b9484cSchristos for (i = 1; i < shnum; ++i) 62498b9484cSchristos { 62598b9484cSchristos unsigned char *shdr; 62698b9484cSchristos unsigned int sh_name; 62798b9484cSchristos const char *name; 62898b9484cSchristos off_t offset; 62998b9484cSchristos off_t length; 63098b9484cSchristos 63198b9484cSchristos shdr = shdrs + (i - 1) * shdr_size; 63298b9484cSchristos sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 63398b9484cSchristos shdr, sh_name, Elf_Word); 63498b9484cSchristos if (sh_name >= name_size) 63598b9484cSchristos { 63698b9484cSchristos *err = 0; 63798b9484cSchristos XDELETEVEC (names); 63898b9484cSchristos XDELETEVEC (shdrs); 63998b9484cSchristos return "ELF section name out of range"; 64098b9484cSchristos } 64198b9484cSchristos 64298b9484cSchristos name = (const char *) names + sh_name; 64398b9484cSchristos offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 64498b9484cSchristos shdr, sh_offset, Elf_Addr); 64598b9484cSchristos length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 64698b9484cSchristos shdr, sh_size, Elf_Addr); 64798b9484cSchristos 64898b9484cSchristos if (!(*pfn) (data, name, offset, length)) 64998b9484cSchristos break; 65098b9484cSchristos } 65198b9484cSchristos 65298b9484cSchristos XDELETEVEC (names); 65398b9484cSchristos XDELETEVEC (shdrs); 65498b9484cSchristos 65598b9484cSchristos return NULL; 65698b9484cSchristos } 65798b9484cSchristos 65898b9484cSchristos /* Fetch the attributes for an simple_object_read. */ 65998b9484cSchristos 66098b9484cSchristos static void * 66198b9484cSchristos simple_object_elf_fetch_attributes (simple_object_read *sobj, 66298b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 66398b9484cSchristos int *err ATTRIBUTE_UNUSED) 66498b9484cSchristos { 66598b9484cSchristos struct simple_object_elf_read *eor = 66698b9484cSchristos (struct simple_object_elf_read *) sobj->data; 66798b9484cSchristos struct simple_object_elf_attributes *ret; 66898b9484cSchristos 66998b9484cSchristos ret = XNEW (struct simple_object_elf_attributes); 67098b9484cSchristos ret->type_functions = eor->type_functions; 67198b9484cSchristos ret->ei_data = eor->ei_data; 67298b9484cSchristos ret->ei_class = eor->ei_class; 67398b9484cSchristos ret->ei_osabi = eor->ei_osabi; 67498b9484cSchristos ret->machine = eor->machine; 67598b9484cSchristos ret->flags = eor->flags; 67698b9484cSchristos return ret; 67798b9484cSchristos } 67898b9484cSchristos 67998b9484cSchristos /* Release the privata data for an simple_object_read. */ 68098b9484cSchristos 68198b9484cSchristos static void 68298b9484cSchristos simple_object_elf_release_read (void *data) 68398b9484cSchristos { 68498b9484cSchristos XDELETE (data); 68598b9484cSchristos } 68698b9484cSchristos 68798b9484cSchristos /* Compare two attributes structures. */ 68898b9484cSchristos 68998b9484cSchristos static const char * 69098b9484cSchristos simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err) 69198b9484cSchristos { 69298b9484cSchristos struct simple_object_elf_attributes *to = 69398b9484cSchristos (struct simple_object_elf_attributes *) todata; 69498b9484cSchristos struct simple_object_elf_attributes *from = 69598b9484cSchristos (struct simple_object_elf_attributes *) fromdata; 69698b9484cSchristos 69798b9484cSchristos if (to->ei_data != from->ei_data || to->ei_class != from->ei_class) 69898b9484cSchristos { 69998b9484cSchristos *err = 0; 70098b9484cSchristos return "ELF object format mismatch"; 70198b9484cSchristos } 70298b9484cSchristos 70398b9484cSchristos if (to->machine != from->machine) 70498b9484cSchristos { 70598b9484cSchristos int ok; 70698b9484cSchristos 70798b9484cSchristos /* EM_SPARC and EM_SPARC32PLUS are compatible and force an 70898b9484cSchristos output of EM_SPARC32PLUS. */ 70998b9484cSchristos ok = 0; 71098b9484cSchristos switch (to->machine) 71198b9484cSchristos { 71298b9484cSchristos case EM_SPARC: 71398b9484cSchristos if (from->machine == EM_SPARC32PLUS) 71498b9484cSchristos { 71598b9484cSchristos to->machine = from->machine; 71698b9484cSchristos ok = 1; 71798b9484cSchristos } 71898b9484cSchristos break; 71998b9484cSchristos 72098b9484cSchristos case EM_SPARC32PLUS: 72198b9484cSchristos if (from->machine == EM_SPARC) 72298b9484cSchristos ok = 1; 72398b9484cSchristos break; 72498b9484cSchristos 72598b9484cSchristos default: 72698b9484cSchristos break; 72798b9484cSchristos } 72898b9484cSchristos 72998b9484cSchristos if (!ok) 73098b9484cSchristos { 73198b9484cSchristos *err = 0; 73298b9484cSchristos return "ELF machine number mismatch"; 73398b9484cSchristos } 73498b9484cSchristos } 73598b9484cSchristos 73698b9484cSchristos return NULL; 73798b9484cSchristos } 73898b9484cSchristos 73998b9484cSchristos /* Release the private data for an attributes structure. */ 74098b9484cSchristos 74198b9484cSchristos static void 74298b9484cSchristos simple_object_elf_release_attributes (void *data) 74398b9484cSchristos { 74498b9484cSchristos XDELETE (data); 74598b9484cSchristos } 74698b9484cSchristos 74798b9484cSchristos /* Prepare to write out a file. */ 74898b9484cSchristos 74998b9484cSchristos static void * 75098b9484cSchristos simple_object_elf_start_write (void *attributes_data, 75198b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 75298b9484cSchristos int *err ATTRIBUTE_UNUSED) 75398b9484cSchristos { 75498b9484cSchristos struct simple_object_elf_attributes *attrs = 75598b9484cSchristos (struct simple_object_elf_attributes *) attributes_data; 7564559860eSchristos struct simple_object_elf_write *ret; 75798b9484cSchristos 75898b9484cSchristos /* We're just going to record the attributes, but we need to make a 75998b9484cSchristos copy because the user may delete them. */ 7604559860eSchristos ret = XNEW (struct simple_object_elf_write); 7614559860eSchristos ret->attrs = *attrs; 7624559860eSchristos ret->shdrs = NULL; 76398b9484cSchristos return ret; 76498b9484cSchristos } 76598b9484cSchristos 76698b9484cSchristos /* Write out an ELF ehdr. */ 76798b9484cSchristos 76898b9484cSchristos static int 76998b9484cSchristos simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, 77098b9484cSchristos const char **errmsg, int *err) 77198b9484cSchristos { 77298b9484cSchristos struct simple_object_elf_attributes *attrs = 77398b9484cSchristos (struct simple_object_elf_attributes *) sobj->data; 77498b9484cSchristos const struct elf_type_functions* fns; 77598b9484cSchristos unsigned char cl; 77698b9484cSchristos size_t ehdr_size; 77798b9484cSchristos unsigned char buf[sizeof (Elf64_External_Ehdr)]; 77898b9484cSchristos simple_object_write_section *section; 77998b9484cSchristos unsigned int shnum; 780837edd6bSchristos unsigned int shstrndx; 78198b9484cSchristos 78298b9484cSchristos fns = attrs->type_functions; 78398b9484cSchristos cl = attrs->ei_class; 78498b9484cSchristos 78598b9484cSchristos shnum = 0; 78698b9484cSchristos for (section = sobj->sections; section != NULL; section = section->next) 78798b9484cSchristos ++shnum; 78898b9484cSchristos if (shnum > 0) 78998b9484cSchristos { 79098b9484cSchristos /* Add a section header for the dummy section and one for 79198b9484cSchristos .shstrtab. */ 79298b9484cSchristos shnum += 2; 79398b9484cSchristos } 79498b9484cSchristos 79598b9484cSchristos ehdr_size = (cl == ELFCLASS32 79698b9484cSchristos ? sizeof (Elf32_External_Ehdr) 79798b9484cSchristos : sizeof (Elf64_External_Ehdr)); 79898b9484cSchristos memset (buf, 0, sizeof (Elf64_External_Ehdr)); 79998b9484cSchristos 80098b9484cSchristos buf[EI_MAG0] = ELFMAG0; 80198b9484cSchristos buf[EI_MAG1] = ELFMAG1; 80298b9484cSchristos buf[EI_MAG2] = ELFMAG2; 80398b9484cSchristos buf[EI_MAG3] = ELFMAG3; 80498b9484cSchristos buf[EI_CLASS] = cl; 80598b9484cSchristos buf[EI_DATA] = attrs->ei_data; 80698b9484cSchristos buf[EI_VERSION] = EV_CURRENT; 80798b9484cSchristos buf[EI_OSABI] = attrs->ei_osabi; 80898b9484cSchristos 80998b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL); 81098b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine); 81198b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT); 81298b9484cSchristos /* e_entry left as zero. */ 81398b9484cSchristos /* e_phoff left as zero. */ 81498b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size); 81598b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags); 81698b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size); 81798b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half, 81898b9484cSchristos (cl == ELFCLASS32 81998b9484cSchristos ? sizeof (Elf32_External_Phdr) 82098b9484cSchristos : sizeof (Elf64_External_Phdr))); 82198b9484cSchristos /* e_phnum left as zero. */ 82298b9484cSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half, 82398b9484cSchristos (cl == ELFCLASS32 82498b9484cSchristos ? sizeof (Elf32_External_Shdr) 82598b9484cSchristos : sizeof (Elf64_External_Shdr))); 826837edd6bSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, 827837edd6bSchristos shnum >= SHN_LORESERVE ? 0 : shnum); 828837edd6bSchristos if (shnum == 0) 829837edd6bSchristos shstrndx = 0; 830837edd6bSchristos else 831837edd6bSchristos { 832837edd6bSchristos shstrndx = shnum - 1; 833837edd6bSchristos if (shstrndx >= SHN_LORESERVE) 834837edd6bSchristos shstrndx = SHN_XINDEX; 835837edd6bSchristos } 836837edd6bSchristos ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx); 83798b9484cSchristos 83898b9484cSchristos return simple_object_internal_write (descriptor, 0, buf, ehdr_size, 83998b9484cSchristos errmsg, err); 84098b9484cSchristos } 84198b9484cSchristos 84298b9484cSchristos /* Write out an ELF shdr. */ 84398b9484cSchristos 84498b9484cSchristos static int 84598b9484cSchristos simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, 84698b9484cSchristos off_t offset, unsigned int sh_name, 84798b9484cSchristos unsigned int sh_type, unsigned int sh_flags, 8484559860eSchristos off_t sh_addr, 84998b9484cSchristos unsigned int sh_offset, unsigned int sh_size, 8504559860eSchristos unsigned int sh_link, unsigned int sh_info, 8514559860eSchristos size_t sh_addralign, 8524559860eSchristos size_t sh_entsize, 853837edd6bSchristos const char **errmsg, int *err) 85498b9484cSchristos { 85598b9484cSchristos struct simple_object_elf_attributes *attrs = 85698b9484cSchristos (struct simple_object_elf_attributes *) sobj->data; 85798b9484cSchristos const struct elf_type_functions* fns; 85898b9484cSchristos unsigned char cl; 85998b9484cSchristos size_t shdr_size; 86098b9484cSchristos unsigned char buf[sizeof (Elf64_External_Shdr)]; 86198b9484cSchristos 86298b9484cSchristos fns = attrs->type_functions; 86398b9484cSchristos cl = attrs->ei_class; 86498b9484cSchristos 86598b9484cSchristos shdr_size = (cl == ELFCLASS32 86698b9484cSchristos ? sizeof (Elf32_External_Shdr) 86798b9484cSchristos : sizeof (Elf64_External_Shdr)); 86898b9484cSchristos memset (buf, 0, sizeof (Elf64_External_Shdr)); 86998b9484cSchristos 87098b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name); 87198b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type); 87298b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags); 8734559860eSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr); 87498b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset); 87598b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size); 876837edd6bSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link); 8774559860eSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info); 87898b9484cSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign); 8794559860eSchristos ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize); 88098b9484cSchristos 88198b9484cSchristos return simple_object_internal_write (descriptor, offset, buf, shdr_size, 88298b9484cSchristos errmsg, err); 88398b9484cSchristos } 88498b9484cSchristos 88598b9484cSchristos /* Write out a complete ELF file. 88698b9484cSchristos Ehdr 88798b9484cSchristos initial dummy Shdr 88898b9484cSchristos user-created Shdrs 88998b9484cSchristos .shstrtab Shdr 89098b9484cSchristos user-created section data 89198b9484cSchristos .shstrtab data */ 89298b9484cSchristos 89398b9484cSchristos static const char * 89498b9484cSchristos simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, 89598b9484cSchristos int *err) 89698b9484cSchristos { 8974559860eSchristos struct simple_object_elf_write *eow = 8984559860eSchristos (struct simple_object_elf_write *) sobj->data; 8994559860eSchristos struct simple_object_elf_attributes *attrs = &eow->attrs; 90098b9484cSchristos unsigned char cl; 90198b9484cSchristos size_t ehdr_size; 90298b9484cSchristos size_t shdr_size; 90398b9484cSchristos const char *errmsg; 90498b9484cSchristos simple_object_write_section *section; 90598b9484cSchristos unsigned int shnum; 90698b9484cSchristos size_t shdr_offset; 90798b9484cSchristos size_t sh_offset; 908837edd6bSchristos unsigned int first_sh_size; 909837edd6bSchristos unsigned int first_sh_link; 91098b9484cSchristos size_t sh_name; 91198b9484cSchristos unsigned char zero; 9124559860eSchristos unsigned secnum; 91398b9484cSchristos 91498b9484cSchristos if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err)) 91598b9484cSchristos return errmsg; 91698b9484cSchristos 91798b9484cSchristos cl = attrs->ei_class; 91898b9484cSchristos if (cl == ELFCLASS32) 91998b9484cSchristos { 92098b9484cSchristos ehdr_size = sizeof (Elf32_External_Ehdr); 92198b9484cSchristos shdr_size = sizeof (Elf32_External_Shdr); 92298b9484cSchristos } 92398b9484cSchristos else 92498b9484cSchristos { 92598b9484cSchristos ehdr_size = sizeof (Elf64_External_Ehdr); 92698b9484cSchristos shdr_size = sizeof (Elf64_External_Shdr); 92798b9484cSchristos } 92898b9484cSchristos 92998b9484cSchristos shnum = 0; 93098b9484cSchristos for (section = sobj->sections; section != NULL; section = section->next) 93198b9484cSchristos ++shnum; 93298b9484cSchristos if (shnum == 0) 93398b9484cSchristos return NULL; 93498b9484cSchristos 93598b9484cSchristos /* Add initial dummy Shdr and .shstrtab. */ 93698b9484cSchristos shnum += 2; 93798b9484cSchristos 93898b9484cSchristos shdr_offset = ehdr_size; 93998b9484cSchristos sh_offset = shdr_offset + shnum * shdr_size; 94098b9484cSchristos 941837edd6bSchristos if (shnum < SHN_LORESERVE) 942837edd6bSchristos first_sh_size = 0; 943837edd6bSchristos else 944837edd6bSchristos first_sh_size = shnum; 945837edd6bSchristos if (shnum - 1 < SHN_LORESERVE) 946837edd6bSchristos first_sh_link = 0; 947837edd6bSchristos else 948837edd6bSchristos first_sh_link = shnum - 1; 94998b9484cSchristos if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, 9504559860eSchristos 0, 0, 0, 0, 0, first_sh_size, first_sh_link, 9514559860eSchristos 0, 0, 0, &errmsg, err)) 95298b9484cSchristos return errmsg; 95398b9484cSchristos 95498b9484cSchristos shdr_offset += shdr_size; 95598b9484cSchristos 95698b9484cSchristos sh_name = 1; 9574559860eSchristos secnum = 0; 95898b9484cSchristos for (section = sobj->sections; section != NULL; section = section->next) 95998b9484cSchristos { 96098b9484cSchristos size_t mask; 96198b9484cSchristos size_t new_sh_offset; 96298b9484cSchristos size_t sh_size; 96398b9484cSchristos struct simple_object_write_section_buffer *buffer; 9644559860eSchristos unsigned int sh_type = SHT_PROGBITS; 9654559860eSchristos unsigned int sh_flags = 0; 9664559860eSchristos off_t sh_addr = 0; 9674559860eSchristos unsigned int sh_link = 0; 9684559860eSchristos unsigned int sh_info = 0; 9694559860eSchristos size_t sh_addralign = 1U << section->align; 9704559860eSchristos size_t sh_entsize = 0; 9714559860eSchristos if (eow->shdrs) 9724559860eSchristos { 9734559860eSchristos sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9744559860eSchristos eow->shdrs + secnum * shdr_size, 9754559860eSchristos sh_type, Elf_Word); 9764559860eSchristos sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9774559860eSchristos eow->shdrs + secnum * shdr_size, 9784559860eSchristos sh_flags, Elf_Addr); 9794559860eSchristos sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9804559860eSchristos eow->shdrs + secnum * shdr_size, 9814559860eSchristos sh_addr, Elf_Addr); 9824559860eSchristos sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9834559860eSchristos eow->shdrs + secnum * shdr_size, 9844559860eSchristos sh_link, Elf_Word); 9854559860eSchristos sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9864559860eSchristos eow->shdrs + secnum * shdr_size, 9874559860eSchristos sh_info, Elf_Word); 9884559860eSchristos sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9894559860eSchristos eow->shdrs + secnum * shdr_size, 9904559860eSchristos sh_addralign, Elf_Addr); 9914559860eSchristos sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr, 9924559860eSchristos eow->shdrs + secnum * shdr_size, 9934559860eSchristos sh_entsize, Elf_Addr); 9944559860eSchristos secnum++; 9954559860eSchristos } 99698b9484cSchristos 9974559860eSchristos mask = sh_addralign - 1; 99898b9484cSchristos new_sh_offset = sh_offset + mask; 99998b9484cSchristos new_sh_offset &= ~ mask; 100098b9484cSchristos while (new_sh_offset > sh_offset) 100198b9484cSchristos { 100298b9484cSchristos unsigned char zeroes[16]; 100398b9484cSchristos size_t write; 100498b9484cSchristos 100598b9484cSchristos memset (zeroes, 0, sizeof zeroes); 100698b9484cSchristos write = new_sh_offset - sh_offset; 100798b9484cSchristos if (write > sizeof zeroes) 100898b9484cSchristos write = sizeof zeroes; 100998b9484cSchristos if (!simple_object_internal_write (descriptor, sh_offset, zeroes, 101098b9484cSchristos write, &errmsg, err)) 101198b9484cSchristos return errmsg; 101298b9484cSchristos sh_offset += write; 101398b9484cSchristos } 101498b9484cSchristos 101598b9484cSchristos sh_size = 0; 101698b9484cSchristos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 101798b9484cSchristos { 101898b9484cSchristos if (!simple_object_internal_write (descriptor, sh_offset + sh_size, 101998b9484cSchristos ((const unsigned char *) 102098b9484cSchristos buffer->buffer), 102198b9484cSchristos buffer->size, &errmsg, err)) 102298b9484cSchristos return errmsg; 102398b9484cSchristos sh_size += buffer->size; 102498b9484cSchristos } 102598b9484cSchristos 102698b9484cSchristos if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, 10274559860eSchristos sh_name, sh_type, sh_flags, 10284559860eSchristos sh_addr, sh_offset, 10294559860eSchristos sh_size, sh_link, sh_info, 10304559860eSchristos sh_addralign, sh_entsize, 103198b9484cSchristos &errmsg, err)) 103298b9484cSchristos return errmsg; 103398b9484cSchristos 103498b9484cSchristos shdr_offset += shdr_size; 103598b9484cSchristos sh_name += strlen (section->name) + 1; 103698b9484cSchristos sh_offset += sh_size; 103798b9484cSchristos } 103898b9484cSchristos 103998b9484cSchristos if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, 10404559860eSchristos sh_name, SHT_STRTAB, 0, 0, sh_offset, 10414559860eSchristos sh_name + strlen (".shstrtab") + 1, 0, 0, 10424559860eSchristos 1, 0, &errmsg, err)) 104398b9484cSchristos return errmsg; 104498b9484cSchristos 104598b9484cSchristos /* .shstrtab has a leading zero byte. */ 104698b9484cSchristos zero = 0; 104798b9484cSchristos if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1, 104898b9484cSchristos &errmsg, err)) 104998b9484cSchristos return errmsg; 105098b9484cSchristos ++sh_offset; 105198b9484cSchristos 105298b9484cSchristos for (section = sobj->sections; section != NULL; section = section->next) 105398b9484cSchristos { 105498b9484cSchristos size_t len; 105598b9484cSchristos 105698b9484cSchristos len = strlen (section->name) + 1; 105798b9484cSchristos if (!simple_object_internal_write (descriptor, sh_offset, 105898b9484cSchristos (const unsigned char *) section->name, 105998b9484cSchristos len, &errmsg, err)) 106098b9484cSchristos return errmsg; 106198b9484cSchristos sh_offset += len; 106298b9484cSchristos } 106398b9484cSchristos 106498b9484cSchristos if (!simple_object_internal_write (descriptor, sh_offset, 106598b9484cSchristos (const unsigned char *) ".shstrtab", 106698b9484cSchristos strlen (".shstrtab") + 1, &errmsg, err)) 106798b9484cSchristos return errmsg; 106898b9484cSchristos 106998b9484cSchristos return NULL; 107098b9484cSchristos } 107198b9484cSchristos 107298b9484cSchristos /* Release the private data for an simple_object_write structure. */ 107398b9484cSchristos 107498b9484cSchristos static void 107598b9484cSchristos simple_object_elf_release_write (void *data) 107698b9484cSchristos { 10774559860eSchristos struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data; 10784559860eSchristos if (eow->shdrs) 10794559860eSchristos XDELETE (eow->shdrs); 108098b9484cSchristos XDELETE (data); 108198b9484cSchristos } 108298b9484cSchristos 10834559860eSchristos /* Copy all sections in an ELF file. */ 10844559860eSchristos 10854559860eSchristos static const char * 10864559860eSchristos simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj, 10874559860eSchristos simple_object_write *dobj, 10884559860eSchristos char *(*pfn) (const char *), 10894559860eSchristos int *err) 10904559860eSchristos { 10914559860eSchristos struct simple_object_elf_read *eor = 10924559860eSchristos (struct simple_object_elf_read *) sobj->data; 10934559860eSchristos const struct elf_type_functions *type_functions = eor->type_functions; 10944559860eSchristos struct simple_object_elf_write *eow = 10954559860eSchristos (struct simple_object_elf_write *) dobj->data; 10964559860eSchristos unsigned char ei_class = eor->ei_class; 10974559860eSchristos size_t shdr_size; 10984559860eSchristos unsigned int shnum; 10994559860eSchristos unsigned char *shdrs; 11004559860eSchristos const char *errmsg; 11014559860eSchristos unsigned char *shstrhdr; 11024559860eSchristos size_t name_size; 11034559860eSchristos off_t shstroff; 11044559860eSchristos unsigned char *names; 11054559860eSchristos unsigned int i; 11064559860eSchristos int changed; 11074559860eSchristos int *pfnret; 11084559860eSchristos const char **pfnname; 11094559860eSchristos unsigned new_i; 11104559860eSchristos unsigned *sh_map; 11114559860eSchristos unsigned first_shndx = 0; 11124559860eSchristos unsigned int *symtab_indices_shndx; 11134559860eSchristos 11144559860eSchristos shdr_size = (ei_class == ELFCLASS32 11154559860eSchristos ? sizeof (Elf32_External_Shdr) 11164559860eSchristos : sizeof (Elf64_External_Shdr)); 11174559860eSchristos 11184559860eSchristos /* Read the section headers. We skip section 0, which is not a 11194559860eSchristos useful section. */ 11204559860eSchristos 11214559860eSchristos shnum = eor->shnum; 11224559860eSchristos shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1)); 11234559860eSchristos 11244559860eSchristos if (!simple_object_internal_read (sobj->descriptor, 11254559860eSchristos sobj->offset + eor->shoff + shdr_size, 11264559860eSchristos shdrs, 11274559860eSchristos shdr_size * (shnum - 1), 11284559860eSchristos &errmsg, err)) 11294559860eSchristos { 11304559860eSchristos XDELETEVEC (shdrs); 11314559860eSchristos return errmsg; 11324559860eSchristos } 11334559860eSchristos 11344559860eSchristos /* Read the section names. */ 11354559860eSchristos 11364559860eSchristos shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size; 11374559860eSchristos name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 11384559860eSchristos shstrhdr, sh_size, Elf_Addr); 11394559860eSchristos shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 11404559860eSchristos shstrhdr, sh_offset, Elf_Addr); 11414559860eSchristos names = XNEWVEC (unsigned char, name_size); 11424559860eSchristos if (!simple_object_internal_read (sobj->descriptor, 11434559860eSchristos sobj->offset + shstroff, 11444559860eSchristos names, name_size, &errmsg, err)) 11454559860eSchristos { 11464559860eSchristos XDELETEVEC (names); 11474559860eSchristos XDELETEVEC (shdrs); 11484559860eSchristos return errmsg; 11494559860eSchristos } 11504559860eSchristos 11514559860eSchristos pfnret = XNEWVEC (int, shnum); 11524559860eSchristos pfnname = XNEWVEC (const char *, shnum); 11534559860eSchristos 11544559860eSchristos /* Map of symtab to index section. */ 11554559860eSchristos symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1); 11564559860eSchristos 11574559860eSchristos /* First perform the callbacks to know which sections to preserve and 11584559860eSchristos what name to use for those. */ 11594559860eSchristos for (i = 1; i < shnum; ++i) 11604559860eSchristos { 11614559860eSchristos unsigned char *shdr; 11624559860eSchristos unsigned int sh_name, sh_type; 11634559860eSchristos const char *name; 11644559860eSchristos char *ret; 11654559860eSchristos 11664559860eSchristos shdr = shdrs + (i - 1) * shdr_size; 11674559860eSchristos sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 11684559860eSchristos shdr, sh_name, Elf_Word); 11694559860eSchristos if (sh_name >= name_size) 11704559860eSchristos { 11714559860eSchristos *err = 0; 11724559860eSchristos XDELETEVEC (names); 11734559860eSchristos XDELETEVEC (shdrs); 11744559860eSchristos return "ELF section name out of range"; 11754559860eSchristos } 11764559860eSchristos 11774559860eSchristos name = (const char *) names + sh_name; 11784559860eSchristos 11794559860eSchristos ret = (*pfn) (name); 11804559860eSchristos pfnret[i - 1] = ret == NULL ? -1 : 0; 11814559860eSchristos pfnname[i - 1] = ret == NULL ? name : ret; 11824559860eSchristos if (first_shndx == 0 11834559860eSchristos && pfnret[i - 1] == 0) 11844559860eSchristos first_shndx = i; 11854559860eSchristos 11864559860eSchristos /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections. */ 11874559860eSchristos sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 11884559860eSchristos shdr, sh_type, Elf_Word); 11894559860eSchristos if (sh_type == SHT_SYMTAB_SHNDX) 11904559860eSchristos { 11914559860eSchristos unsigned int sh_link; 11924559860eSchristos sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 11934559860eSchristos shdr, sh_link, Elf_Word); 11944b169a6bSchristos symtab_indices_shndx[sh_link - 1] = i - 1; 11954559860eSchristos /* Always discard the extended index sections, after 11964559860eSchristos copying it will not be needed. This way we don't need to 11974559860eSchristos update it and deal with the ordering constraints of 11984559860eSchristos processing the existing symtab and changing the index. */ 11994559860eSchristos pfnret[i - 1] = -1; 12004559860eSchristos } 12014559860eSchristos } 12024559860eSchristos 12034559860eSchristos /* Mark sections as preserved that are required by to be preserved 12044559860eSchristos sections. */ 12054559860eSchristos do 12064559860eSchristos { 12074559860eSchristos changed = 0; 12084559860eSchristos for (i = 1; i < shnum; ++i) 12094559860eSchristos { 12104559860eSchristos unsigned char *shdr; 12114559860eSchristos unsigned int sh_type, sh_info, sh_link; 12124559860eSchristos off_t offset; 12134559860eSchristos off_t length; 12144559860eSchristos 12154559860eSchristos shdr = shdrs + (i - 1) * shdr_size; 12164559860eSchristos sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 12174559860eSchristos shdr, sh_type, Elf_Word); 12184559860eSchristos sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 12194559860eSchristos shdr, sh_info, Elf_Word); 12204559860eSchristos sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 12214559860eSchristos shdr, sh_link, Elf_Word); 12224559860eSchristos if (sh_type == SHT_GROUP) 12234559860eSchristos { 12244559860eSchristos /* Mark groups containing copied sections. */ 12254559860eSchristos unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, 12264559860eSchristos Shdr, shdr, sh_entsize, 12274559860eSchristos Elf_Addr); 12284559860eSchristos unsigned char *ent, *buf; 12294559860eSchristos int keep = 0; 12304559860eSchristos offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 12314559860eSchristos shdr, sh_offset, Elf_Addr); 12324559860eSchristos length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 12334559860eSchristos shdr, sh_size, Elf_Addr); 12344559860eSchristos buf = XNEWVEC (unsigned char, length); 12354559860eSchristos if (!simple_object_internal_read (sobj->descriptor, 12364559860eSchristos sobj->offset + offset, buf, 12374559860eSchristos (size_t) length, &errmsg, err)) 12384559860eSchristos { 12394559860eSchristos XDELETEVEC (buf); 12404559860eSchristos XDELETEVEC (names); 12414559860eSchristos XDELETEVEC (shdrs); 12424559860eSchristos return errmsg; 12434559860eSchristos } 12444559860eSchristos for (ent = buf + entsize; ent < buf + length; ent += entsize) 12454559860eSchristos { 12464559860eSchristos unsigned sec = type_functions->fetch_Elf_Word (ent); 12474559860eSchristos if (pfnret[sec - 1] == 0) 12484559860eSchristos keep = 1; 12494559860eSchristos } 12504559860eSchristos if (keep) 12514559860eSchristos { 12524559860eSchristos changed |= (pfnret[sh_link - 1] == -1 12534559860eSchristos || pfnret[i - 1] == -1); 12544559860eSchristos pfnret[sh_link - 1] = 0; 12554559860eSchristos pfnret[i - 1] = 0; 12564559860eSchristos } 12574559860eSchristos } 12584559860eSchristos if (sh_type == SHT_RELA 12594559860eSchristos || sh_type == SHT_REL) 12604559860eSchristos { 12614559860eSchristos /* Mark relocation sections and symtab of copied sections. */ 12624559860eSchristos if (pfnret[sh_info - 1] == 0) 12634559860eSchristos { 12644559860eSchristos changed |= (pfnret[sh_link - 1] == -1 12654559860eSchristos || pfnret[i - 1] == -1); 12664559860eSchristos pfnret[sh_link - 1] = 0; 12674559860eSchristos pfnret[i - 1] = 0; 12684559860eSchristos } 12694559860eSchristos } 12704559860eSchristos if (sh_type == SHT_SYMTAB) 12714559860eSchristos { 12724559860eSchristos /* Mark strings sections of copied symtabs. */ 12734559860eSchristos if (pfnret[i - 1] == 0) 12744559860eSchristos { 12754559860eSchristos changed |= pfnret[sh_link - 1] == -1; 12764559860eSchristos pfnret[sh_link - 1] = 0; 12774559860eSchristos } 12784559860eSchristos } 12794559860eSchristos } 12804559860eSchristos } 12814559860eSchristos while (changed); 12824559860eSchristos 12834559860eSchristos /* Compute a mapping of old -> new section numbers. */ 12844559860eSchristos sh_map = XNEWVEC (unsigned, shnum); 12854559860eSchristos sh_map[0] = 0; 12864559860eSchristos new_i = 1; 12874559860eSchristos for (i = 1; i < shnum; ++i) 12884559860eSchristos { 12894559860eSchristos if (pfnret[i - 1] == -1) 12904559860eSchristos sh_map[i] = 0; 12914559860eSchristos else 12924559860eSchristos sh_map[i] = new_i++; 12934559860eSchristos } 12944559860eSchristos if (new_i - 1 >= SHN_LORESERVE) 12954559860eSchristos { 12964559860eSchristos *err = ENOTSUP; 12974559860eSchristos return "Too many copied sections"; 12984559860eSchristos } 12994559860eSchristos eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1)); 13004559860eSchristos 13014559860eSchristos /* Then perform the actual copying. */ 13024559860eSchristos new_i = 0; 13034559860eSchristos for (i = 1; i < shnum; ++i) 13044559860eSchristos { 13054559860eSchristos unsigned char *shdr; 13064559860eSchristos unsigned int sh_name, sh_type; 13074559860eSchristos const char *name; 13084559860eSchristos off_t offset; 13094559860eSchristos off_t length; 13104559860eSchristos simple_object_write_section *dest; 13114559860eSchristos off_t flags; 13124559860eSchristos unsigned char *buf; 13134559860eSchristos 13144559860eSchristos if (pfnret[i - 1]) 13154559860eSchristos continue; 13164559860eSchristos 13174559860eSchristos new_i++; 13184559860eSchristos shdr = shdrs + (i - 1) * shdr_size; 13194559860eSchristos sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13204559860eSchristos shdr, sh_name, Elf_Word); 13214559860eSchristos if (sh_name >= name_size) 13224559860eSchristos { 13234559860eSchristos *err = 0; 13244559860eSchristos XDELETEVEC (names); 13254559860eSchristos XDELETEVEC (shdrs); 13264559860eSchristos XDELETEVEC (symtab_indices_shndx); 13274559860eSchristos return "ELF section name out of range"; 13284559860eSchristos } 13294559860eSchristos 13304559860eSchristos name = pfnname[i - 1]; 13314559860eSchristos offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13324559860eSchristos shdr, sh_offset, Elf_Addr); 13334559860eSchristos length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13344559860eSchristos shdr, sh_size, Elf_Addr); 13354559860eSchristos sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13364559860eSchristos shdr, sh_type, Elf_Word); 13374559860eSchristos 13384559860eSchristos dest = simple_object_write_create_section (dobj, pfnname[i - 1], 13394559860eSchristos 0, &errmsg, err); 13404559860eSchristos if (dest == NULL) 13414559860eSchristos { 13424559860eSchristos XDELETEVEC (names); 13434559860eSchristos XDELETEVEC (shdrs); 13444559860eSchristos XDELETEVEC (symtab_indices_shndx); 13454559860eSchristos return errmsg; 13464559860eSchristos } 13474559860eSchristos 13484559860eSchristos /* Record the SHDR of the source. */ 13494559860eSchristos memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size); 13504559860eSchristos shdr = eow->shdrs + (new_i - 1) * shdr_size; 13514559860eSchristos 13524559860eSchristos /* Copy the data. 13534559860eSchristos ??? This is quite wasteful and ideally would be delayed until 13544559860eSchristos write_to_file (). Thus it questions the interfacing 13554559860eSchristos which eventually should contain destination creation plus 13564559860eSchristos writing. */ 13574559860eSchristos buf = XNEWVEC (unsigned char, length); 13584559860eSchristos if (!simple_object_internal_read (sobj->descriptor, 13594559860eSchristos sobj->offset + offset, buf, 13604559860eSchristos (size_t) length, &errmsg, err)) 13614559860eSchristos { 13624559860eSchristos XDELETEVEC (buf); 13634559860eSchristos XDELETEVEC (names); 13644559860eSchristos XDELETEVEC (shdrs); 13654559860eSchristos XDELETEVEC (symtab_indices_shndx); 13664559860eSchristos return errmsg; 13674559860eSchristos } 13684559860eSchristos 13698dffb485Schristos /* If we are processing .symtab purge any symbols 13708dffb485Schristos in discarded sections. */ 13714559860eSchristos if (sh_type == SHT_SYMTAB) 13724559860eSchristos { 13734559860eSchristos unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13744559860eSchristos shdr, sh_entsize, Elf_Addr); 13758dffb485Schristos size_t prevailing_name_idx = 0; 13764559860eSchristos unsigned char *ent; 13774559860eSchristos unsigned *shndx_table = NULL; 13784559860eSchristos /* Read the section index table if present. */ 13794559860eSchristos if (symtab_indices_shndx[i - 1] != 0) 13804559860eSchristos { 13814b169a6bSchristos unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size; 13824559860eSchristos off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13834559860eSchristos sidxhdr, sh_offset, Elf_Addr); 13844559860eSchristos size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13854559860eSchristos sidxhdr, sh_size, Elf_Addr); 13864b169a6bSchristos unsigned int shndx_type 13874b169a6bSchristos = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 13884b169a6bSchristos sidxhdr, sh_type, Elf_Word); 13894b169a6bSchristos if (shndx_type != SHT_SYMTAB_SHNDX) 13904b169a6bSchristos return "Wrong section type of a SYMTAB SECTION INDICES section"; 13914559860eSchristos shndx_table = (unsigned *)XNEWVEC (char, sidxsz); 13924559860eSchristos simple_object_internal_read (sobj->descriptor, 13934559860eSchristos sobj->offset + sidxoff, 13944559860eSchristos (unsigned char *)shndx_table, 13954559860eSchristos sidxsz, &errmsg, err); 13964559860eSchristos } 13978dffb485Schristos 13988dffb485Schristos /* Find a WEAK HIDDEN symbol which name we will use for removed 13998dffb485Schristos symbols. We know there's a prevailing weak hidden symbol 14008dffb485Schristos at the start of the .debug_info section. */ 14018dffb485Schristos for (ent = buf; ent < buf + length; ent += entsize) 14028dffb485Schristos { 14038dffb485Schristos unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class, 14048dffb485Schristos Sym, ent, 14058dffb485Schristos st_shndx, Elf_Half); 14068dffb485Schristos unsigned char *st_info; 14078dffb485Schristos unsigned char *st_other; 14088dffb485Schristos if (ei_class == ELFCLASS32) 14098dffb485Schristos { 14108dffb485Schristos st_info = &((Elf32_External_Sym *)ent)->st_info; 14118dffb485Schristos st_other = &((Elf32_External_Sym *)ent)->st_other; 14128dffb485Schristos } 14138dffb485Schristos else 14148dffb485Schristos { 14158dffb485Schristos st_info = &((Elf64_External_Sym *)ent)->st_info; 14168dffb485Schristos st_other = &((Elf64_External_Sym *)ent)->st_other; 14178dffb485Schristos } 14188dffb485Schristos if (st_shndx == SHN_XINDEX) 14198dffb485Schristos st_shndx = type_functions->fetch_Elf_Word 14208dffb485Schristos ((unsigned char *)(shndx_table + (ent - buf) / entsize)); 14218dffb485Schristos 14228dffb485Schristos if (st_shndx != SHN_COMMON 14238dffb485Schristos && !(st_shndx != SHN_UNDEF 14248dffb485Schristos && st_shndx < shnum 14258dffb485Schristos && pfnret[st_shndx - 1] == -1) 14268dffb485Schristos && ELF_ST_BIND (*st_info) == STB_WEAK 14278dffb485Schristos && *st_other == STV_HIDDEN) 14288dffb485Schristos { 14298dffb485Schristos prevailing_name_idx = ELF_FETCH_FIELD (type_functions, 14308dffb485Schristos ei_class, Sym, ent, 14318dffb485Schristos st_name, Elf_Word); 14328dffb485Schristos break; 14338dffb485Schristos } 14348dffb485Schristos } 14358dffb485Schristos 14364559860eSchristos for (ent = buf; ent < buf + length; ent += entsize) 14374559860eSchristos { 14384559860eSchristos unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class, 14394559860eSchristos Sym, ent, 14404559860eSchristos st_shndx, Elf_Half); 14414559860eSchristos unsigned raw_st_shndx = st_shndx; 14424559860eSchristos unsigned char *st_info; 14434559860eSchristos unsigned char *st_other; 14444559860eSchristos int discard = 0; 14454559860eSchristos if (ei_class == ELFCLASS32) 14464559860eSchristos { 14474559860eSchristos st_info = &((Elf32_External_Sym *)ent)->st_info; 14484559860eSchristos st_other = &((Elf32_External_Sym *)ent)->st_other; 14494559860eSchristos } 14504559860eSchristos else 14514559860eSchristos { 14524559860eSchristos st_info = &((Elf64_External_Sym *)ent)->st_info; 14534559860eSchristos st_other = &((Elf64_External_Sym *)ent)->st_other; 14544559860eSchristos } 14554559860eSchristos if (st_shndx == SHN_XINDEX) 14564559860eSchristos st_shndx = type_functions->fetch_Elf_Word 14574559860eSchristos ((unsigned char *)(shndx_table + (ent - buf) / entsize)); 14588dffb485Schristos /* Eliminate all COMMONs - this includes __gnu_lto_slim 14598dffb485Schristos which otherwise cause endless LTO plugin invocation. 14608dffb485Schristos FIXME: remove the condition once we remove emission 14618dffb485Schristos of __gnu_lto_slim symbol. */ 14624559860eSchristos if (st_shndx == SHN_COMMON) 14634559860eSchristos discard = 1; 14644559860eSchristos /* We also need to remove symbols refering to sections 14654559860eSchristos we'll eventually remove as with fat LTO objects 14664559860eSchristos we otherwise get duplicate symbols at final link 14674559860eSchristos (with GNU ld, gold is fine and ignores symbols in 14684559860eSchristos sections marked as EXCLUDE). ld/20513 */ 14694559860eSchristos else if (st_shndx != SHN_UNDEF 14704559860eSchristos && st_shndx < shnum 14714559860eSchristos && pfnret[st_shndx - 1] == -1) 14724559860eSchristos discard = 1; 14738dffb485Schristos /* We also need to remove global UNDEFs which can 14748dffb485Schristos cause link fails later. */ 14758dffb485Schristos else if (st_shndx == SHN_UNDEF 14768dffb485Schristos && ELF_ST_BIND (*st_info) == STB_GLOBAL) 14778dffb485Schristos discard = 1; 14784559860eSchristos 14794559860eSchristos if (discard) 14804559860eSchristos { 14814559860eSchristos /* Make discarded symbols undefined and unnamed 14824559860eSchristos in case it is local. */ 14834559860eSchristos int bind = ELF_ST_BIND (*st_info); 14844559860eSchristos int other = STV_DEFAULT; 14854559860eSchristos if (bind == STB_LOCAL) 14864559860eSchristos { 14874559860eSchristos /* Make discarded local symbols unnamed and 14884559860eSchristos defined in the first prevailing section. */ 14894559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 14904559860eSchristos ent, st_name, Elf_Word, 0); 14914559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 14924559860eSchristos ent, st_shndx, Elf_Half, 14934559860eSchristos sh_map[first_shndx]); 14944559860eSchristos } 14954559860eSchristos else 14964559860eSchristos { 14974559860eSchristos /* Make discarded global symbols hidden weak 14988dffb485Schristos undefined and sharing a name of a prevailing 14998dffb485Schristos symbol. */ 15004559860eSchristos bind = STB_WEAK; 15014559860eSchristos other = STV_HIDDEN; 15024559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 15034559860eSchristos ent, st_name, Elf_Word, 15048dffb485Schristos prevailing_name_idx); 15054559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 15064559860eSchristos ent, st_shndx, Elf_Half, SHN_UNDEF); 15074559860eSchristos } 15084559860eSchristos *st_other = other; 15094559860eSchristos *st_info = ELF_ST_INFO (bind, STT_NOTYPE); 15104559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 15114559860eSchristos ent, st_value, Elf_Addr, 0); 15124559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 15134559860eSchristos ent, st_size, Elf_Word, 0); 15144559860eSchristos } 15154559860eSchristos else if (raw_st_shndx < SHN_LORESERVE 15164559860eSchristos || raw_st_shndx == SHN_XINDEX) 15174559860eSchristos /* Remap the section reference. */ 15184559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Sym, 15194559860eSchristos ent, st_shndx, Elf_Half, sh_map[st_shndx]); 15204559860eSchristos } 15214559860eSchristos XDELETEVEC (shndx_table); 15224559860eSchristos } 15234559860eSchristos else if (sh_type == SHT_GROUP) 15244559860eSchristos { 15254559860eSchristos /* Remap section indices in groups and remove removed members. */ 15264559860eSchristos unsigned char *ent, *dst; 15274559860eSchristos for (dst = ent = buf + 4; ent < buf + length; ent += 4) 15284559860eSchristos { 15294559860eSchristos unsigned shndx = type_functions->fetch_Elf_Word (ent); 15304559860eSchristos if (pfnret[shndx - 1] == -1) 15314559860eSchristos ; 15324559860eSchristos else 15334559860eSchristos { 15344559860eSchristos type_functions->set_Elf_Word (dst, sh_map[shndx]); 15354559860eSchristos dst += 4; 15364559860eSchristos } 15374559860eSchristos } 15384559860eSchristos /* Adjust the length. */ 15394559860eSchristos length = dst - buf; 15404559860eSchristos } 15414559860eSchristos 15424559860eSchristos errmsg = simple_object_write_add_data (dobj, dest, 15434559860eSchristos buf, length, 1, err); 15444559860eSchristos XDELETEVEC (buf); 15454559860eSchristos if (errmsg) 15464559860eSchristos { 15474559860eSchristos XDELETEVEC (names); 15484559860eSchristos XDELETEVEC (shdrs); 15494559860eSchristos XDELETEVEC (symtab_indices_shndx); 15504559860eSchristos return errmsg; 15514559860eSchristos } 15524559860eSchristos 15534559860eSchristos flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 15544559860eSchristos shdr, sh_flags, Elf_Addr); 15554559860eSchristos /* Remap the section references. */ 15564559860eSchristos { 15574559860eSchristos unsigned int sh_info, sh_link; 15584559860eSchristos if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA) 15594559860eSchristos { 15604559860eSchristos sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 15614559860eSchristos shdr, sh_info, Elf_Word); 15624559860eSchristos sh_info = sh_map[sh_info]; 15634559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Shdr, 15644559860eSchristos shdr, sh_info, Elf_Word, sh_info); 15654559860eSchristos } 15664559860eSchristos sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, 15674559860eSchristos shdr, sh_link, Elf_Word); 15684559860eSchristos sh_link = sh_map[sh_link]; 15694559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Shdr, 15704559860eSchristos shdr, sh_link, Elf_Word, sh_link); 15714559860eSchristos } 15724559860eSchristos /* The debugobj doesn't contain any code, thus no trampolines. 15734559860eSchristos Even when the original object needs trampolines, debugobj 15744559860eSchristos doesn't. */ 15754559860eSchristos if (strcmp (name, ".note.GNU-stack") == 0) 15764559860eSchristos flags &= ~SHF_EXECINSTR; 15774559860eSchristos /* Clear SHF_EXCLUDE on to be preserved sections. */ 15784559860eSchristos flags &= ~SHF_EXCLUDE; 15794559860eSchristos ELF_SET_FIELD (type_functions, ei_class, Shdr, 15804559860eSchristos shdr, sh_flags, Elf_Addr, flags); 15814559860eSchristos } 15824559860eSchristos 15834559860eSchristos XDELETEVEC (names); 15844559860eSchristos XDELETEVEC (shdrs); 15854559860eSchristos XDELETEVEC (pfnret); 15864559860eSchristos XDELETEVEC (pfnname); 15874559860eSchristos XDELETEVEC (symtab_indices_shndx); 15884559860eSchristos XDELETEVEC (sh_map); 15894559860eSchristos 15904559860eSchristos return NULL; 15914559860eSchristos } 15924559860eSchristos 15934559860eSchristos 159498b9484cSchristos /* The ELF functions. */ 159598b9484cSchristos 159698b9484cSchristos const struct simple_object_functions simple_object_elf_functions = 159798b9484cSchristos { 159898b9484cSchristos simple_object_elf_match, 159998b9484cSchristos simple_object_elf_find_sections, 160098b9484cSchristos simple_object_elf_fetch_attributes, 160198b9484cSchristos simple_object_elf_release_read, 160298b9484cSchristos simple_object_elf_attributes_merge, 160398b9484cSchristos simple_object_elf_release_attributes, 160498b9484cSchristos simple_object_elf_start_write, 160598b9484cSchristos simple_object_elf_write_to_file, 16064559860eSchristos simple_object_elf_release_write, 16074559860eSchristos simple_object_elf_copy_lto_debug_sections 160898b9484cSchristos }; 1609