xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/simple-object-elf.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
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