xref: /netbsd-src/external/gpl3/binutils/dist/libiberty/simple-object-elf.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1be9ac0eaSchristos /* simple-object-elf.c -- routines to manipulate ELF object files.
2*cb63e24eSchristos    Copyright (C) 2010-2024 Free Software Foundation, Inc.
3be9ac0eaSchristos    Written by Ian Lance Taylor, Google.
4be9ac0eaSchristos 
5be9ac0eaSchristos This program is free software; you can redistribute it and/or modify it
6be9ac0eaSchristos under the terms of the GNU General Public License as published by the
7be9ac0eaSchristos Free Software Foundation; either version 2, or (at your option) any
8be9ac0eaSchristos later version.
9be9ac0eaSchristos 
10be9ac0eaSchristos This program is distributed in the hope that it will be useful,
11be9ac0eaSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12be9ac0eaSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13be9ac0eaSchristos GNU General Public License for more details.
14be9ac0eaSchristos 
15be9ac0eaSchristos You should have received a copy of the GNU General Public License
16be9ac0eaSchristos along with this program; if not, write to the Free Software
17be9ac0eaSchristos Foundation, 51 Franklin Street - Fifth Floor,
18be9ac0eaSchristos Boston, MA 02110-1301, USA.  */
19be9ac0eaSchristos 
20be9ac0eaSchristos #include "config.h"
21be9ac0eaSchristos #include "libiberty.h"
22be9ac0eaSchristos #include "simple-object.h"
23be9ac0eaSchristos 
24be9ac0eaSchristos #include <errno.h>
256f4ced0bSchristos /* mingw.org's MinGW doesn't have ENOTSUP.  */
266f4ced0bSchristos #ifndef ENOTSUP
276f4ced0bSchristos # define ENOTSUP ENOSYS
286f4ced0bSchristos #endif
29be9ac0eaSchristos #include <stddef.h>
30be9ac0eaSchristos 
31be9ac0eaSchristos #ifdef HAVE_STDLIB_H
32be9ac0eaSchristos #include <stdlib.h>
33be9ac0eaSchristos #endif
34be9ac0eaSchristos 
35be9ac0eaSchristos #ifdef HAVE_STDINT_H
36be9ac0eaSchristos #include <stdint.h>
37be9ac0eaSchristos #endif
38be9ac0eaSchristos 
39be9ac0eaSchristos #ifdef HAVE_STRING_H
40be9ac0eaSchristos #include <string.h>
41be9ac0eaSchristos #endif
42be9ac0eaSchristos 
43be9ac0eaSchristos #ifdef HAVE_INTTYPES_H
44be9ac0eaSchristos #include <inttypes.h>
45be9ac0eaSchristos #endif
46be9ac0eaSchristos 
47be9ac0eaSchristos #include "simple-object-common.h"
48be9ac0eaSchristos 
49be9ac0eaSchristos /* ELF structures and constants.  */
50be9ac0eaSchristos 
51be9ac0eaSchristos /* 32-bit ELF file header.  */
52be9ac0eaSchristos 
53be9ac0eaSchristos typedef struct {
54be9ac0eaSchristos   unsigned char	e_ident[16];		/* ELF "magic number" */
55be9ac0eaSchristos   unsigned char	e_type[2];		/* Identifies object file type */
56be9ac0eaSchristos   unsigned char	e_machine[2];		/* Specifies required architecture */
57be9ac0eaSchristos   unsigned char	e_version[4];		/* Identifies object file version */
58be9ac0eaSchristos   unsigned char	e_entry[4];		/* Entry point virtual address */
59be9ac0eaSchristos   unsigned char	e_phoff[4];		/* Program header table file offset */
60be9ac0eaSchristos   unsigned char	e_shoff[4];		/* Section header table file offset */
61be9ac0eaSchristos   unsigned char	e_flags[4];		/* Processor-specific flags */
62be9ac0eaSchristos   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
63be9ac0eaSchristos   unsigned char	e_phentsize[2];		/* Program header table entry size */
64be9ac0eaSchristos   unsigned char	e_phnum[2];		/* Program header table entry count */
65be9ac0eaSchristos   unsigned char	e_shentsize[2];		/* Section header table entry size */
66be9ac0eaSchristos   unsigned char	e_shnum[2];		/* Section header table entry count */
67be9ac0eaSchristos   unsigned char	e_shstrndx[2];		/* Section header string table index */
68be9ac0eaSchristos } Elf32_External_Ehdr;
69be9ac0eaSchristos 
70be9ac0eaSchristos /* 64-bit ELF file header.  */
71be9ac0eaSchristos 
72be9ac0eaSchristos typedef struct {
73be9ac0eaSchristos   unsigned char	e_ident[16];		/* ELF "magic number" */
74be9ac0eaSchristos   unsigned char	e_type[2];		/* Identifies object file type */
75be9ac0eaSchristos   unsigned char	e_machine[2];		/* Specifies required architecture */
76be9ac0eaSchristos   unsigned char	e_version[4];		/* Identifies object file version */
77be9ac0eaSchristos   unsigned char	e_entry[8];		/* Entry point virtual address */
78be9ac0eaSchristos   unsigned char	e_phoff[8];		/* Program header table file offset */
79be9ac0eaSchristos   unsigned char	e_shoff[8];		/* Section header table file offset */
80be9ac0eaSchristos   unsigned char	e_flags[4];		/* Processor-specific flags */
81be9ac0eaSchristos   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
82be9ac0eaSchristos   unsigned char	e_phentsize[2];		/* Program header table entry size */
83be9ac0eaSchristos   unsigned char	e_phnum[2];		/* Program header table entry count */
84be9ac0eaSchristos   unsigned char	e_shentsize[2];		/* Section header table entry size */
85be9ac0eaSchristos   unsigned char	e_shnum[2];		/* Section header table entry count */
86be9ac0eaSchristos   unsigned char	e_shstrndx[2];		/* Section header string table index */
87be9ac0eaSchristos } Elf64_External_Ehdr;
88be9ac0eaSchristos 
89be9ac0eaSchristos /* Indexes and values in e_ident field of Ehdr.  */
90be9ac0eaSchristos 
91be9ac0eaSchristos #define EI_MAG0		0	/* File identification byte 0 index */
92be9ac0eaSchristos #define ELFMAG0		   0x7F	/* Magic number byte 0 */
93be9ac0eaSchristos 
94be9ac0eaSchristos #define EI_MAG1		1	/* File identification byte 1 index */
95be9ac0eaSchristos #define ELFMAG1		    'E'	/* Magic number byte 1 */
96be9ac0eaSchristos 
97be9ac0eaSchristos #define EI_MAG2		2	/* File identification byte 2 index */
98be9ac0eaSchristos #define ELFMAG2		    'L'	/* Magic number byte 2 */
99be9ac0eaSchristos 
100be9ac0eaSchristos #define EI_MAG3		3	/* File identification byte 3 index */
101be9ac0eaSchristos #define ELFMAG3		    'F'	/* Magic number byte 3 */
102be9ac0eaSchristos 
103be9ac0eaSchristos #define EI_CLASS	4	/* File class */
104be9ac0eaSchristos #define ELFCLASSNONE	      0	/* Invalid class */
105be9ac0eaSchristos #define ELFCLASS32	      1	/* 32-bit objects */
106be9ac0eaSchristos #define ELFCLASS64	      2	/* 64-bit objects */
107be9ac0eaSchristos 
108be9ac0eaSchristos #define EI_DATA		5	/* Data encoding */
109be9ac0eaSchristos #define ELFDATANONE	      0	/* Invalid data encoding */
110be9ac0eaSchristos #define ELFDATA2LSB	      1	/* 2's complement, little endian */
111be9ac0eaSchristos #define ELFDATA2MSB	      2	/* 2's complement, big endian */
112be9ac0eaSchristos 
113be9ac0eaSchristos #define EI_VERSION	6	/* File version */
114be9ac0eaSchristos #define EV_CURRENT	1		/* Current version */
115be9ac0eaSchristos 
116be9ac0eaSchristos #define EI_OSABI	7	/* Operating System/ABI indication */
117be9ac0eaSchristos 
118be9ac0eaSchristos /* Values for e_type field of Ehdr.  */
119be9ac0eaSchristos 
120be9ac0eaSchristos #define ET_REL		1	/* Relocatable file */
121be9ac0eaSchristos 
122883529b6Schristos /* Values for e_machine field of Ehdr.  */
123883529b6Schristos 
124883529b6Schristos #define EM_SPARC	  2	/* SUN SPARC */
125883529b6Schristos #define EM_SPARC32PLUS	 18	/* Sun's "v8plus" */
126883529b6Schristos 
127be9ac0eaSchristos /* Special section index values.  */
128be9ac0eaSchristos 
129fc4f4269Schristos #define SHN_UNDEF	0		/* Undefined section */
130be9ac0eaSchristos #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
131fc4f4269Schristos #define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
132be9ac0eaSchristos #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
133c1a20988Schristos #define SHN_HIRESERVE	0xffff		/* End of reserved indices */
134be9ac0eaSchristos 
135fc4f4269Schristos 
136be9ac0eaSchristos /* 32-bit ELF program header.  */
137be9ac0eaSchristos 
138be9ac0eaSchristos typedef struct {
139be9ac0eaSchristos   unsigned char	p_type[4];		/* Identifies program segment type */
140be9ac0eaSchristos   unsigned char	p_offset[4];		/* Segment file offset */
141be9ac0eaSchristos   unsigned char	p_vaddr[4];		/* Segment virtual address */
142be9ac0eaSchristos   unsigned char	p_paddr[4];		/* Segment physical address */
143be9ac0eaSchristos   unsigned char	p_filesz[4];		/* Segment size in file */
144be9ac0eaSchristos   unsigned char	p_memsz[4];		/* Segment size in memory */
145be9ac0eaSchristos   unsigned char	p_flags[4];		/* Segment flags */
146be9ac0eaSchristos   unsigned char	p_align[4];		/* Segment alignment, file & memory */
147be9ac0eaSchristos } Elf32_External_Phdr;
148be9ac0eaSchristos 
149be9ac0eaSchristos /* 64-bit ELF program header.  */
150be9ac0eaSchristos 
151be9ac0eaSchristos typedef struct {
152be9ac0eaSchristos   unsigned char	p_type[4];		/* Identifies program segment type */
153be9ac0eaSchristos   unsigned char	p_flags[4];		/* Segment flags */
154be9ac0eaSchristos   unsigned char	p_offset[8];		/* Segment file offset */
155be9ac0eaSchristos   unsigned char	p_vaddr[8];		/* Segment virtual address */
156be9ac0eaSchristos   unsigned char	p_paddr[8];		/* Segment physical address */
157be9ac0eaSchristos   unsigned char	p_filesz[8];		/* Segment size in file */
158be9ac0eaSchristos   unsigned char	p_memsz[8];		/* Segment size in memory */
159be9ac0eaSchristos   unsigned char	p_align[8];		/* Segment alignment, file & memory */
160be9ac0eaSchristos } Elf64_External_Phdr;
161be9ac0eaSchristos 
162be9ac0eaSchristos /* 32-bit ELF section header */
163be9ac0eaSchristos 
164be9ac0eaSchristos typedef struct {
165be9ac0eaSchristos   unsigned char	sh_name[4];		/* Section name, index in string tbl */
166be9ac0eaSchristos   unsigned char	sh_type[4];		/* Type of section */
167be9ac0eaSchristos   unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
168be9ac0eaSchristos   unsigned char	sh_addr[4];		/* Section virtual addr at execution */
169be9ac0eaSchristos   unsigned char	sh_offset[4];		/* Section file offset */
170be9ac0eaSchristos   unsigned char	sh_size[4];		/* Size of section in bytes */
171be9ac0eaSchristos   unsigned char	sh_link[4];		/* Index of another section */
172be9ac0eaSchristos   unsigned char	sh_info[4];		/* Additional section information */
173be9ac0eaSchristos   unsigned char	sh_addralign[4];	/* Section alignment */
174be9ac0eaSchristos   unsigned char	sh_entsize[4];		/* Entry size if section holds table */
175be9ac0eaSchristos } Elf32_External_Shdr;
176be9ac0eaSchristos 
177be9ac0eaSchristos /* 64-bit ELF section header.  */
178be9ac0eaSchristos 
179be9ac0eaSchristos typedef struct {
180be9ac0eaSchristos   unsigned char	sh_name[4];		/* Section name, index in string tbl */
181be9ac0eaSchristos   unsigned char	sh_type[4];		/* Type of section */
182be9ac0eaSchristos   unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
183be9ac0eaSchristos   unsigned char	sh_addr[8];		/* Section virtual addr at execution */
184be9ac0eaSchristos   unsigned char	sh_offset[8];		/* Section file offset */
185be9ac0eaSchristos   unsigned char	sh_size[8];		/* Size of section in bytes */
186be9ac0eaSchristos   unsigned char	sh_link[4];		/* Index of another section */
187be9ac0eaSchristos   unsigned char	sh_info[4];		/* Additional section information */
188be9ac0eaSchristos   unsigned char	sh_addralign[8];	/* Section alignment */
189be9ac0eaSchristos   unsigned char	sh_entsize[8];		/* Entry size if section holds table */
190be9ac0eaSchristos } Elf64_External_Shdr;
191be9ac0eaSchristos 
192be9ac0eaSchristos /* Values for sh_type field.  */
193be9ac0eaSchristos 
194fc4f4269Schristos #define SHT_NULL	0		/* Section header table entry unused */
195be9ac0eaSchristos #define SHT_PROGBITS	1		/* Program data */
196fc4f4269Schristos #define SHT_SYMTAB	2		/* Link editing symbol table */
197be9ac0eaSchristos #define SHT_STRTAB	3		/* A string table */
198fc4f4269Schristos #define SHT_RELA	4		/* Relocation entries with addends */
199fc4f4269Schristos #define SHT_REL		9		/* Relocation entries, no addends */
200fc4f4269Schristos #define SHT_GROUP	17		/* Section contains a section group */
201c1a20988Schristos #define SHT_SYMTAB_SHNDX 18		/* Extended section indeces */
202fc4f4269Schristos 
203fc4f4269Schristos /* Values for sh_flags field.  */
204fc4f4269Schristos 
205c1a20988Schristos #define SHF_INFO_LINK	0x00000040	/* `sh_info' contains SHT index */
206fc4f4269Schristos #define SHF_EXECINSTR	0x00000004	/* Executable section.  */
207fc4f4269Schristos #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
208fc4f4269Schristos 					   section from executable and
209fc4f4269Schristos 					   shared library that it builds
210fc4f4269Schristos 					   when those objects are not to be
211fc4f4269Schristos 					   further relocated.  */
212fc4f4269Schristos /* Symbol table entry.  */
213fc4f4269Schristos 
214fc4f4269Schristos typedef struct
215fc4f4269Schristos {
216fc4f4269Schristos   unsigned char st_name[4];                /* Symbol name (string tbl index) */
217fc4f4269Schristos   unsigned char st_value[4];               /* Symbol value */
218fc4f4269Schristos   unsigned char st_size[4];                /* Symbol size */
219fc4f4269Schristos   unsigned char st_info;                /* Symbol type and binding */
220fc4f4269Schristos   unsigned char st_other;               /* Symbol visibility */
221fc4f4269Schristos   unsigned char st_shndx[2];               /* Section index */
222fc4f4269Schristos } Elf32_External_Sym;
223fc4f4269Schristos 
224fc4f4269Schristos typedef struct
225fc4f4269Schristos {
226fc4f4269Schristos   unsigned char st_name[4];                /* Symbol name (string tbl index) */
227fc4f4269Schristos   unsigned char st_info;                /* Symbol type and binding */
228fc4f4269Schristos   unsigned char st_other;               /* Symbol visibility */
229fc4f4269Schristos   unsigned char st_shndx[2];               /* Section index */
230fc4f4269Schristos   unsigned char st_value[8];               /* Symbol value */
231fc4f4269Schristos   unsigned char st_size[8];                /* Symbol size */
232fc4f4269Schristos } Elf64_External_Sym;
233fc4f4269Schristos 
234fc4f4269Schristos #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
235fc4f4269Schristos #define ELF_ST_TYPE(val)              ((val) & 0xf)
236fc4f4269Schristos #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
237fc4f4269Schristos 
238fc4f4269Schristos #define STT_NOTYPE	0	/* Symbol type is unspecified */
239fc4f4269Schristos #define STT_OBJECT	1	/* Symbol is a data object */
240fc4f4269Schristos #define STT_FUNC	2	/* Symbol is a code object */
241fc4f4269Schristos #define STT_TLS		6	/* Thread local data object */
242fc4f4269Schristos #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
243fc4f4269Schristos 
244fc4f4269Schristos #define STB_LOCAL	0	/* Local symbol */
245fc4f4269Schristos #define STB_GLOBAL	1	/* Global symbol */
246fc4f4269Schristos #define STB_WEAK	2	/* Weak global */
247fc4f4269Schristos 
248fc4f4269Schristos #define STV_DEFAULT	0	/* Visibility is specified by binding type */
249fc4f4269Schristos #define STV_HIDDEN	2	/* Can only be seen inside currect component */
250be9ac0eaSchristos 
251be9ac0eaSchristos /* Functions to fetch and store different ELF types, depending on the
252be9ac0eaSchristos    endianness and size.  */
253be9ac0eaSchristos 
254be9ac0eaSchristos struct elf_type_functions
255be9ac0eaSchristos {
256be9ac0eaSchristos   unsigned short (*fetch_Elf_Half) (const unsigned char *);
257be9ac0eaSchristos   unsigned int (*fetch_Elf_Word) (const unsigned char *);
258be9ac0eaSchristos   ulong_type (*fetch_Elf_Addr) (const unsigned char *);
259be9ac0eaSchristos   void (*set_Elf_Half) (unsigned char *, unsigned short);
260be9ac0eaSchristos   void (*set_Elf_Word) (unsigned char *, unsigned int);
261be9ac0eaSchristos   void (*set_Elf_Addr) (unsigned char *, ulong_type);
262be9ac0eaSchristos };
263be9ac0eaSchristos 
264be9ac0eaSchristos static const struct elf_type_functions elf_big_32_functions =
265be9ac0eaSchristos {
266be9ac0eaSchristos   simple_object_fetch_big_16,
267be9ac0eaSchristos   simple_object_fetch_big_32,
268be9ac0eaSchristos   simple_object_fetch_big_32_ulong,
269be9ac0eaSchristos   simple_object_set_big_16,
270be9ac0eaSchristos   simple_object_set_big_32,
271be9ac0eaSchristos   simple_object_set_big_32_ulong
272be9ac0eaSchristos };
273be9ac0eaSchristos 
274be9ac0eaSchristos static const struct elf_type_functions elf_little_32_functions =
275be9ac0eaSchristos {
276be9ac0eaSchristos   simple_object_fetch_little_16,
277be9ac0eaSchristos   simple_object_fetch_little_32,
278be9ac0eaSchristos   simple_object_fetch_little_32_ulong,
279be9ac0eaSchristos   simple_object_set_little_16,
280be9ac0eaSchristos   simple_object_set_little_32,
281be9ac0eaSchristos   simple_object_set_little_32_ulong
282be9ac0eaSchristos };
283be9ac0eaSchristos 
284be9ac0eaSchristos #ifdef UNSIGNED_64BIT_TYPE
285be9ac0eaSchristos 
286be9ac0eaSchristos static const struct elf_type_functions elf_big_64_functions =
287be9ac0eaSchristos {
288be9ac0eaSchristos   simple_object_fetch_big_16,
289be9ac0eaSchristos   simple_object_fetch_big_32,
290be9ac0eaSchristos   simple_object_fetch_big_64,
291be9ac0eaSchristos   simple_object_set_big_16,
292be9ac0eaSchristos   simple_object_set_big_32,
293be9ac0eaSchristos   simple_object_set_big_64
294be9ac0eaSchristos };
295be9ac0eaSchristos 
296be9ac0eaSchristos static const struct elf_type_functions elf_little_64_functions =
297be9ac0eaSchristos {
298be9ac0eaSchristos   simple_object_fetch_little_16,
299be9ac0eaSchristos   simple_object_fetch_little_32,
300be9ac0eaSchristos   simple_object_fetch_little_64,
301be9ac0eaSchristos   simple_object_set_little_16,
302be9ac0eaSchristos   simple_object_set_little_32,
303be9ac0eaSchristos   simple_object_set_little_64
304be9ac0eaSchristos };
305be9ac0eaSchristos 
306be9ac0eaSchristos #endif
307be9ac0eaSchristos 
308be9ac0eaSchristos /* Hideous macro to fetch the value of a field from an external ELF
309be9ac0eaSchristos    struct of some sort.  TYPEFUNCS is the set of type functions.
310be9ac0eaSchristos    BUFFER points to the external data.  STRUCTTYPE is the appropriate
311be9ac0eaSchristos    struct type.  FIELD is a field within the struct.  TYPE is the type
312be9ac0eaSchristos    of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
313be9ac0eaSchristos 
314be9ac0eaSchristos #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
315be9ac0eaSchristos   ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
316be9ac0eaSchristos 
317be9ac0eaSchristos /* Even more hideous macro to fetch the value of FIELD from BUFFER.
318be9ac0eaSchristos    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
319be9ac0eaSchristos    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
320be9ac0eaSchristos    the struct.  TYPE is the type of the field in the struct: Elf_Half,
321be9ac0eaSchristos    Elf_Word, or Elf_Addr.  */
322be9ac0eaSchristos 
323be9ac0eaSchristos #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
324be9ac0eaSchristos 			      FIELD, TYPE)				\
325be9ac0eaSchristos   ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
326be9ac0eaSchristos 			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
327be9ac0eaSchristos 			  FIELD, BUFFER, TYPE)
328be9ac0eaSchristos 
329be9ac0eaSchristos /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
330be9ac0eaSchristos 
331be9ac0eaSchristos #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
332be9ac0eaSchristos 			FIELD, TYPE)					\
333be9ac0eaSchristos   ((CLASS) == ELFCLASS32						\
334be9ac0eaSchristos     ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
335be9ac0eaSchristos 			     TYPE)					\
336be9ac0eaSchristos     : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
337be9ac0eaSchristos 			     TYPE))
338be9ac0eaSchristos 
339be9ac0eaSchristos /* Hideous macro to set the value of a field in an external ELF
340be9ac0eaSchristos    structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
341be9ac0eaSchristos    points to the external data.  STRUCTTYPE is the appropriate
342be9ac0eaSchristos    structure type.  FIELD is a field within the struct.  TYPE is the
343be9ac0eaSchristos    type of the field in the struct: Elf_Half, Elf_Word, or
344be9ac0eaSchristos    Elf_Addr.  */
345be9ac0eaSchristos 
346be9ac0eaSchristos #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
347be9ac0eaSchristos   (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
348be9ac0eaSchristos 
349be9ac0eaSchristos /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
350be9ac0eaSchristos    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
351be9ac0eaSchristos    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
352be9ac0eaSchristos    the struct.  TYPE is the type of the field in the struct: Elf_Half,
353be9ac0eaSchristos    Elf_Word, or Elf_Addr.  */
354be9ac0eaSchristos 
355be9ac0eaSchristos #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
356be9ac0eaSchristos 			    TYPE, VAL)					\
357be9ac0eaSchristos   ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
358be9ac0eaSchristos 			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
359be9ac0eaSchristos 			FIELD, BUFFER, TYPE, VAL)
360be9ac0eaSchristos 
361be9ac0eaSchristos /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
362be9ac0eaSchristos 
363be9ac0eaSchristos #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
364be9ac0eaSchristos 		      TYPE, VAL)					\
365be9ac0eaSchristos   ((CLASS) == ELFCLASS32						\
366be9ac0eaSchristos     ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
367be9ac0eaSchristos 			   TYPE, VAL)					\
368be9ac0eaSchristos     : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
369be9ac0eaSchristos 			   TYPE, VAL))
370be9ac0eaSchristos 
371be9ac0eaSchristos /* Private data for an simple_object_read.  */
372be9ac0eaSchristos 
373be9ac0eaSchristos struct simple_object_elf_read
374be9ac0eaSchristos {
375be9ac0eaSchristos   /* Type functions.  */
376be9ac0eaSchristos   const struct elf_type_functions* type_functions;
377be9ac0eaSchristos   /* Elf data.  */
378be9ac0eaSchristos   unsigned char ei_data;
379be9ac0eaSchristos   /* Elf class.  */
380be9ac0eaSchristos   unsigned char ei_class;
381be9ac0eaSchristos   /* ELF OS ABI.  */
382be9ac0eaSchristos   unsigned char ei_osabi;
383be9ac0eaSchristos   /* Elf machine number.  */
384be9ac0eaSchristos   unsigned short machine;
385be9ac0eaSchristos   /* Processor specific flags.  */
386be9ac0eaSchristos   unsigned int flags;
387be9ac0eaSchristos   /* File offset of section headers.  */
388be9ac0eaSchristos   ulong_type shoff;
389be9ac0eaSchristos   /* Number of sections.  */
390be9ac0eaSchristos   unsigned int shnum;
391be9ac0eaSchristos   /* Index of string table section header.  */
392be9ac0eaSchristos   unsigned int shstrndx;
393be9ac0eaSchristos };
394be9ac0eaSchristos 
395be9ac0eaSchristos /* Private data for an simple_object_attributes.  */
396be9ac0eaSchristos 
397be9ac0eaSchristos struct simple_object_elf_attributes
398be9ac0eaSchristos {
399be9ac0eaSchristos   /* Type functions.  */
400be9ac0eaSchristos   const struct elf_type_functions* type_functions;
401be9ac0eaSchristos   /* Elf data.  */
402be9ac0eaSchristos   unsigned char ei_data;
403be9ac0eaSchristos   /* Elf class.  */
404be9ac0eaSchristos   unsigned char ei_class;
405be9ac0eaSchristos   /* ELF OS ABI.  */
406be9ac0eaSchristos   unsigned char ei_osabi;
407be9ac0eaSchristos   /* Elf machine number.  */
408be9ac0eaSchristos   unsigned short machine;
409be9ac0eaSchristos   /* Processor specific flags.  */
410be9ac0eaSchristos   unsigned int flags;
411be9ac0eaSchristos };
412be9ac0eaSchristos 
413fc4f4269Schristos /* Private data for an simple_object_write.  */
414fc4f4269Schristos 
415fc4f4269Schristos struct simple_object_elf_write
416fc4f4269Schristos {
417fc4f4269Schristos   struct simple_object_elf_attributes attrs;
418fc4f4269Schristos   unsigned char *shdrs;
419fc4f4269Schristos };
420fc4f4269Schristos 
421be9ac0eaSchristos /* See if we have an ELF file.  */
422be9ac0eaSchristos 
423be9ac0eaSchristos static void *
simple_object_elf_match(unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],int descriptor,off_t offset,const char * segment_name ATTRIBUTE_UNUSED,const char ** errmsg,int * err)424be9ac0eaSchristos simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
425be9ac0eaSchristos 			 int descriptor, off_t offset,
426be9ac0eaSchristos 			 const char *segment_name ATTRIBUTE_UNUSED,
427be9ac0eaSchristos 			 const char **errmsg, int *err)
428be9ac0eaSchristos {
429be9ac0eaSchristos   unsigned char ei_data;
430be9ac0eaSchristos   unsigned char ei_class;
431be9ac0eaSchristos   const struct elf_type_functions *type_functions;
432be9ac0eaSchristos   unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
433be9ac0eaSchristos   struct simple_object_elf_read *eor;
434be9ac0eaSchristos 
435be9ac0eaSchristos   if (header[EI_MAG0] != ELFMAG0
436be9ac0eaSchristos       || header[EI_MAG1] != ELFMAG1
437be9ac0eaSchristos       || header[EI_MAG2] != ELFMAG2
438be9ac0eaSchristos       || header[EI_MAG3] != ELFMAG3
439be9ac0eaSchristos       || header[EI_VERSION] != EV_CURRENT)
440be9ac0eaSchristos     {
441be9ac0eaSchristos       *errmsg = NULL;
442be9ac0eaSchristos       *err = 0;
443be9ac0eaSchristos       return NULL;
444be9ac0eaSchristos     }
445be9ac0eaSchristos 
446be9ac0eaSchristos   ei_data = header[EI_DATA];
447be9ac0eaSchristos   if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
448be9ac0eaSchristos     {
449be9ac0eaSchristos       *errmsg = "unknown ELF endianness";
450be9ac0eaSchristos       *err = 0;
451be9ac0eaSchristos       return NULL;
452be9ac0eaSchristos     }
453be9ac0eaSchristos 
454be9ac0eaSchristos   ei_class = header[EI_CLASS];
455be9ac0eaSchristos   switch (ei_class)
456be9ac0eaSchristos     {
457be9ac0eaSchristos     case ELFCLASS32:
458be9ac0eaSchristos       type_functions = (ei_data == ELFDATA2LSB
459be9ac0eaSchristos 			? &elf_little_32_functions
460be9ac0eaSchristos 			: &elf_big_32_functions);
461be9ac0eaSchristos       break;
462be9ac0eaSchristos 
463be9ac0eaSchristos     case ELFCLASS64:
464be9ac0eaSchristos #ifndef UNSIGNED_64BIT_TYPE
465be9ac0eaSchristos       *errmsg = "64-bit ELF objects not supported";
466be9ac0eaSchristos       *err = 0;
467be9ac0eaSchristos       return NULL;
468be9ac0eaSchristos #else
469be9ac0eaSchristos       type_functions = (ei_data == ELFDATA2LSB
470be9ac0eaSchristos 			? &elf_little_64_functions
471be9ac0eaSchristos 			: &elf_big_64_functions);
472be9ac0eaSchristos       break;
473be9ac0eaSchristos #endif
474be9ac0eaSchristos 
475be9ac0eaSchristos     default:
476be9ac0eaSchristos       *errmsg = "unrecognized ELF size";
477be9ac0eaSchristos       *err = 0;
478be9ac0eaSchristos       return NULL;
479be9ac0eaSchristos     }
480be9ac0eaSchristos 
481be9ac0eaSchristos   if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
482be9ac0eaSchristos 				    errmsg, err))
483be9ac0eaSchristos     return NULL;
484be9ac0eaSchristos 
485be9ac0eaSchristos   eor = XNEW (struct simple_object_elf_read);
486be9ac0eaSchristos   eor->type_functions = type_functions;
487be9ac0eaSchristos   eor->ei_data = ei_data;
488be9ac0eaSchristos   eor->ei_class = ei_class;
489be9ac0eaSchristos   eor->ei_osabi = header[EI_OSABI];
490be9ac0eaSchristos   eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
491be9ac0eaSchristos 				  e_machine, Elf_Half);
492be9ac0eaSchristos   eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
493be9ac0eaSchristos 				e_flags, Elf_Word);
494be9ac0eaSchristos   eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
495be9ac0eaSchristos 				e_shoff, Elf_Addr);
496be9ac0eaSchristos   eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
497be9ac0eaSchristos 				e_shnum, Elf_Half);
498be9ac0eaSchristos   eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
499be9ac0eaSchristos 				   e_shstrndx, Elf_Half);
500be9ac0eaSchristos 
501be9ac0eaSchristos   if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
502be9ac0eaSchristos       && eor->shoff != 0)
503be9ac0eaSchristos     {
504be9ac0eaSchristos       unsigned char shdr[sizeof (Elf64_External_Shdr)];
505be9ac0eaSchristos 
506be9ac0eaSchristos       /* Object file has more than 0xffff sections.  */
507be9ac0eaSchristos 
508be9ac0eaSchristos       if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
509be9ac0eaSchristos 					(ei_class == ELFCLASS32
510be9ac0eaSchristos 					 ? sizeof (Elf32_External_Shdr)
511be9ac0eaSchristos 					 : sizeof (Elf64_External_Shdr)),
512be9ac0eaSchristos 					errmsg, err))
513be9ac0eaSchristos 	{
514be9ac0eaSchristos 	  XDELETE (eor);
515be9ac0eaSchristos 	  return NULL;
516be9ac0eaSchristos 	}
517be9ac0eaSchristos 
518be9ac0eaSchristos       if (eor->shnum == 0)
519be9ac0eaSchristos 	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
520be9ac0eaSchristos 				      shdr, sh_size, Elf_Addr);
521be9ac0eaSchristos 
522be9ac0eaSchristos       if (eor->shstrndx == SHN_XINDEX)
523be9ac0eaSchristos 	{
524be9ac0eaSchristos 	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
525be9ac0eaSchristos 					   shdr, sh_link, Elf_Word);
526be9ac0eaSchristos 
527be9ac0eaSchristos 	  /* Versions of the GNU binutils between 2.12 and 2.18 did
528be9ac0eaSchristos 	     not handle objects with more than SHN_LORESERVE sections
529be9ac0eaSchristos 	     correctly.  All large section indexes were offset by
530be9ac0eaSchristos 	     0x100.  There is more information at
5314f645668Schristos 	     https://sourceware.org/PR5900 .
532be9ac0eaSchristos 	     Fortunately these object files are easy to detect, as the
533be9ac0eaSchristos 	     GNU binutils always put the section header string table
534be9ac0eaSchristos 	     near the end of the list of sections.  Thus if the
535be9ac0eaSchristos 	     section header string table index is larger than the
536be9ac0eaSchristos 	     number of sections, then we know we have to subtract
537be9ac0eaSchristos 	     0x100 to get the real section index.  */
538be9ac0eaSchristos 	  if (eor->shstrndx >= eor->shnum
539be9ac0eaSchristos 	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
540be9ac0eaSchristos 	    eor->shstrndx -= 0x100;
541be9ac0eaSchristos 	}
542be9ac0eaSchristos     }
543be9ac0eaSchristos 
544be9ac0eaSchristos   if (eor->shstrndx >= eor->shnum)
545be9ac0eaSchristos     {
546be9ac0eaSchristos       *errmsg = "invalid ELF shstrndx >= shnum";
547be9ac0eaSchristos       *err = 0;
548be9ac0eaSchristos       XDELETE (eor);
549be9ac0eaSchristos       return NULL;
550be9ac0eaSchristos     }
551be9ac0eaSchristos 
5526f4ced0bSchristos   if (eor->shstrndx == 0)
5536f4ced0bSchristos     {
5546f4ced0bSchristos       *errmsg = "invalid ELF shstrndx == 0";
5556f4ced0bSchristos       *err = 0;
5566f4ced0bSchristos       XDELETE (eor);
5576f4ced0bSchristos       return NULL;
5586f4ced0bSchristos     }
5596f4ced0bSchristos 
560be9ac0eaSchristos   return (void *) eor;
561be9ac0eaSchristos }
562be9ac0eaSchristos 
563be9ac0eaSchristos /* Find all sections in an ELF file.  */
564be9ac0eaSchristos 
565be9ac0eaSchristos static const char *
simple_object_elf_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,int * err)566be9ac0eaSchristos simple_object_elf_find_sections (simple_object_read *sobj,
567be9ac0eaSchristos 				 int (*pfn) (void *, const char *,
568be9ac0eaSchristos 					     off_t offset, off_t length),
569be9ac0eaSchristos 				 void *data,
570be9ac0eaSchristos 				 int *err)
571be9ac0eaSchristos {
572be9ac0eaSchristos   struct simple_object_elf_read *eor =
573be9ac0eaSchristos     (struct simple_object_elf_read *) sobj->data;
574be9ac0eaSchristos   const struct elf_type_functions *type_functions = eor->type_functions;
575be9ac0eaSchristos   unsigned char ei_class = eor->ei_class;
576be9ac0eaSchristos   size_t shdr_size;
577be9ac0eaSchristos   unsigned int shnum;
578be9ac0eaSchristos   unsigned char *shdrs;
579be9ac0eaSchristos   const char *errmsg;
580be9ac0eaSchristos   unsigned char *shstrhdr;
581be9ac0eaSchristos   size_t name_size;
582be9ac0eaSchristos   off_t shstroff;
583be9ac0eaSchristos   unsigned char *names;
584be9ac0eaSchristos   unsigned int i;
585be9ac0eaSchristos 
586be9ac0eaSchristos   shdr_size = (ei_class == ELFCLASS32
587be9ac0eaSchristos 	       ? sizeof (Elf32_External_Shdr)
588be9ac0eaSchristos 	       : sizeof (Elf64_External_Shdr));
589be9ac0eaSchristos 
590be9ac0eaSchristos   /* Read the section headers.  We skip section 0, which is not a
591be9ac0eaSchristos      useful section.  */
592be9ac0eaSchristos 
593be9ac0eaSchristos   shnum = eor->shnum;
594be9ac0eaSchristos   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
595be9ac0eaSchristos 
596be9ac0eaSchristos   if (!simple_object_internal_read (sobj->descriptor,
597be9ac0eaSchristos 				    sobj->offset + eor->shoff + shdr_size,
598be9ac0eaSchristos 				    shdrs,
599be9ac0eaSchristos 				    shdr_size * (shnum - 1),
600be9ac0eaSchristos 				    &errmsg, err))
601be9ac0eaSchristos     {
602be9ac0eaSchristos       XDELETEVEC (shdrs);
603be9ac0eaSchristos       return errmsg;
604be9ac0eaSchristos     }
605be9ac0eaSchristos 
606be9ac0eaSchristos   /* Read the section names.  */
607be9ac0eaSchristos 
608be9ac0eaSchristos   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
609be9ac0eaSchristos   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
610be9ac0eaSchristos 			       shstrhdr, sh_size, Elf_Addr);
611be9ac0eaSchristos   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
612be9ac0eaSchristos 			      shstrhdr, sh_offset, Elf_Addr);
613be9ac0eaSchristos   names = XNEWVEC (unsigned char, name_size);
614be9ac0eaSchristos   if (!simple_object_internal_read (sobj->descriptor,
615be9ac0eaSchristos 				    sobj->offset + shstroff,
616be9ac0eaSchristos 				    names, name_size, &errmsg, err))
617be9ac0eaSchristos     {
618be9ac0eaSchristos       XDELETEVEC (names);
619be9ac0eaSchristos       XDELETEVEC (shdrs);
620be9ac0eaSchristos       return errmsg;
621be9ac0eaSchristos     }
622be9ac0eaSchristos 
623be9ac0eaSchristos   for (i = 1; i < shnum; ++i)
624be9ac0eaSchristos     {
625be9ac0eaSchristos       unsigned char *shdr;
626be9ac0eaSchristos       unsigned int sh_name;
627be9ac0eaSchristos       const char *name;
628be9ac0eaSchristos       off_t offset;
629be9ac0eaSchristos       off_t length;
630be9ac0eaSchristos 
631be9ac0eaSchristos       shdr = shdrs + (i - 1) * shdr_size;
632be9ac0eaSchristos       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
633be9ac0eaSchristos 				 shdr, sh_name, Elf_Word);
634be9ac0eaSchristos       if (sh_name >= name_size)
635be9ac0eaSchristos 	{
636be9ac0eaSchristos 	  *err = 0;
637be9ac0eaSchristos 	  XDELETEVEC (names);
638be9ac0eaSchristos 	  XDELETEVEC (shdrs);
639be9ac0eaSchristos 	  return "ELF section name out of range";
640be9ac0eaSchristos 	}
641be9ac0eaSchristos 
642be9ac0eaSchristos       name = (const char *) names + sh_name;
643be9ac0eaSchristos       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
644be9ac0eaSchristos 				shdr, sh_offset, Elf_Addr);
645be9ac0eaSchristos       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
646be9ac0eaSchristos 				shdr, sh_size, Elf_Addr);
647be9ac0eaSchristos 
648be9ac0eaSchristos       if (!(*pfn) (data, name, offset, length))
649be9ac0eaSchristos 	break;
650be9ac0eaSchristos     }
651be9ac0eaSchristos 
652be9ac0eaSchristos   XDELETEVEC (names);
653be9ac0eaSchristos   XDELETEVEC (shdrs);
654be9ac0eaSchristos 
655be9ac0eaSchristos   return NULL;
656be9ac0eaSchristos }
657be9ac0eaSchristos 
658be9ac0eaSchristos /* Fetch the attributes for an simple_object_read.  */
659be9ac0eaSchristos 
660be9ac0eaSchristos static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)661be9ac0eaSchristos simple_object_elf_fetch_attributes (simple_object_read *sobj,
662be9ac0eaSchristos 				    const char **errmsg ATTRIBUTE_UNUSED,
663be9ac0eaSchristos 				    int *err ATTRIBUTE_UNUSED)
664be9ac0eaSchristos {
665be9ac0eaSchristos   struct simple_object_elf_read *eor =
666be9ac0eaSchristos     (struct simple_object_elf_read *) sobj->data;
667be9ac0eaSchristos   struct simple_object_elf_attributes *ret;
668be9ac0eaSchristos 
669be9ac0eaSchristos   ret = XNEW (struct simple_object_elf_attributes);
670be9ac0eaSchristos   ret->type_functions = eor->type_functions;
671be9ac0eaSchristos   ret->ei_data = eor->ei_data;
672be9ac0eaSchristos   ret->ei_class = eor->ei_class;
673be9ac0eaSchristos   ret->ei_osabi = eor->ei_osabi;
674be9ac0eaSchristos   ret->machine = eor->machine;
675be9ac0eaSchristos   ret->flags = eor->flags;
676be9ac0eaSchristos   return ret;
677be9ac0eaSchristos }
678be9ac0eaSchristos 
679be9ac0eaSchristos /* Release the privata data for an simple_object_read.  */
680be9ac0eaSchristos 
681be9ac0eaSchristos static void
simple_object_elf_release_read(void * data)682be9ac0eaSchristos simple_object_elf_release_read (void *data)
683be9ac0eaSchristos {
684be9ac0eaSchristos   XDELETE (data);
685be9ac0eaSchristos }
686be9ac0eaSchristos 
687be9ac0eaSchristos /* Compare two attributes structures.  */
688be9ac0eaSchristos 
689be9ac0eaSchristos static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)690883529b6Schristos simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
691be9ac0eaSchristos {
692883529b6Schristos   struct simple_object_elf_attributes *to =
693883529b6Schristos     (struct simple_object_elf_attributes *) todata;
694883529b6Schristos   struct simple_object_elf_attributes *from =
695883529b6Schristos     (struct simple_object_elf_attributes *) fromdata;
696be9ac0eaSchristos 
697883529b6Schristos   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
698be9ac0eaSchristos     {
699be9ac0eaSchristos       *err = 0;
700be9ac0eaSchristos       return "ELF object format mismatch";
701be9ac0eaSchristos     }
702883529b6Schristos 
703883529b6Schristos   if (to->machine != from->machine)
704883529b6Schristos     {
705883529b6Schristos       int ok;
706883529b6Schristos 
707883529b6Schristos       /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
708883529b6Schristos 	 output of EM_SPARC32PLUS.  */
709883529b6Schristos       ok = 0;
710883529b6Schristos       switch (to->machine)
711883529b6Schristos 	{
712883529b6Schristos 	case EM_SPARC:
713883529b6Schristos 	  if (from->machine == EM_SPARC32PLUS)
714883529b6Schristos 	    {
715883529b6Schristos 	      to->machine = from->machine;
716883529b6Schristos 	      ok = 1;
717883529b6Schristos 	    }
718883529b6Schristos 	  break;
719883529b6Schristos 
720883529b6Schristos 	case EM_SPARC32PLUS:
721883529b6Schristos 	  if (from->machine == EM_SPARC)
722883529b6Schristos 	    ok = 1;
723883529b6Schristos 	  break;
724883529b6Schristos 
725883529b6Schristos 	default:
726883529b6Schristos 	  break;
727883529b6Schristos 	}
728883529b6Schristos 
729883529b6Schristos       if (!ok)
730883529b6Schristos 	{
731883529b6Schristos 	  *err = 0;
732883529b6Schristos 	  return "ELF machine number mismatch";
733883529b6Schristos 	}
734883529b6Schristos     }
735883529b6Schristos 
736be9ac0eaSchristos   return NULL;
737be9ac0eaSchristos }
738be9ac0eaSchristos 
739be9ac0eaSchristos /* Release the private data for an attributes structure.  */
740be9ac0eaSchristos 
741be9ac0eaSchristos static void
simple_object_elf_release_attributes(void * data)742be9ac0eaSchristos simple_object_elf_release_attributes (void *data)
743be9ac0eaSchristos {
744be9ac0eaSchristos   XDELETE (data);
745be9ac0eaSchristos }
746be9ac0eaSchristos 
747be9ac0eaSchristos /* Prepare to write out a file.  */
748be9ac0eaSchristos 
749be9ac0eaSchristos static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)750be9ac0eaSchristos simple_object_elf_start_write (void *attributes_data,
751be9ac0eaSchristos 			       const char **errmsg ATTRIBUTE_UNUSED,
752be9ac0eaSchristos 			       int *err ATTRIBUTE_UNUSED)
753be9ac0eaSchristos {
754be9ac0eaSchristos   struct simple_object_elf_attributes *attrs =
755be9ac0eaSchristos     (struct simple_object_elf_attributes *) attributes_data;
756fc4f4269Schristos   struct simple_object_elf_write *ret;
757be9ac0eaSchristos 
758be9ac0eaSchristos   /* We're just going to record the attributes, but we need to make a
759be9ac0eaSchristos      copy because the user may delete them.  */
760fc4f4269Schristos   ret = XNEW (struct simple_object_elf_write);
761fc4f4269Schristos   ret->attrs = *attrs;
762fc4f4269Schristos   ret->shdrs = NULL;
763be9ac0eaSchristos   return ret;
764be9ac0eaSchristos }
765be9ac0eaSchristos 
766be9ac0eaSchristos /* Write out an ELF ehdr.  */
767be9ac0eaSchristos 
768be9ac0eaSchristos static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)769be9ac0eaSchristos simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
770be9ac0eaSchristos 			      const char **errmsg, int *err)
771be9ac0eaSchristos {
772be9ac0eaSchristos   struct simple_object_elf_attributes *attrs =
773be9ac0eaSchristos     (struct simple_object_elf_attributes *) sobj->data;
774be9ac0eaSchristos   const struct elf_type_functions* fns;
775be9ac0eaSchristos   unsigned char cl;
776be9ac0eaSchristos   size_t ehdr_size;
777be9ac0eaSchristos   unsigned char buf[sizeof (Elf64_External_Ehdr)];
778be9ac0eaSchristos   simple_object_write_section *section;
779be9ac0eaSchristos   unsigned int shnum;
7809573673dSchristos   unsigned int shstrndx;
781be9ac0eaSchristos 
782be9ac0eaSchristos   fns = attrs->type_functions;
783be9ac0eaSchristos   cl = attrs->ei_class;
784be9ac0eaSchristos 
785be9ac0eaSchristos   shnum = 0;
786be9ac0eaSchristos   for (section = sobj->sections; section != NULL; section = section->next)
787be9ac0eaSchristos     ++shnum;
788be9ac0eaSchristos   if (shnum > 0)
789be9ac0eaSchristos     {
790be9ac0eaSchristos       /* Add a section header for the dummy section and one for
791be9ac0eaSchristos 	 .shstrtab.  */
792be9ac0eaSchristos       shnum += 2;
793be9ac0eaSchristos     }
794be9ac0eaSchristos 
795be9ac0eaSchristos   ehdr_size = (cl == ELFCLASS32
796be9ac0eaSchristos 	       ? sizeof (Elf32_External_Ehdr)
797be9ac0eaSchristos 	       : sizeof (Elf64_External_Ehdr));
798be9ac0eaSchristos   memset (buf, 0, sizeof (Elf64_External_Ehdr));
799be9ac0eaSchristos 
800be9ac0eaSchristos   buf[EI_MAG0] = ELFMAG0;
801be9ac0eaSchristos   buf[EI_MAG1] = ELFMAG1;
802be9ac0eaSchristos   buf[EI_MAG2] = ELFMAG2;
803be9ac0eaSchristos   buf[EI_MAG3] = ELFMAG3;
804be9ac0eaSchristos   buf[EI_CLASS] = cl;
805be9ac0eaSchristos   buf[EI_DATA] = attrs->ei_data;
806be9ac0eaSchristos   buf[EI_VERSION] = EV_CURRENT;
807be9ac0eaSchristos   buf[EI_OSABI] = attrs->ei_osabi;
808be9ac0eaSchristos 
809be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
810be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
811be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
812be9ac0eaSchristos   /* e_entry left as zero.  */
813be9ac0eaSchristos   /* e_phoff left as zero.  */
814be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
815be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
816be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
817be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
818be9ac0eaSchristos 		 (cl == ELFCLASS32
819be9ac0eaSchristos 		  ? sizeof (Elf32_External_Phdr)
820be9ac0eaSchristos 		  : sizeof (Elf64_External_Phdr)));
821be9ac0eaSchristos   /* e_phnum left as zero.  */
822be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
823be9ac0eaSchristos 		 (cl == ELFCLASS32
824be9ac0eaSchristos 		  ? sizeof (Elf32_External_Shdr)
825be9ac0eaSchristos 		  : sizeof (Elf64_External_Shdr)));
8269573673dSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
8279573673dSchristos 		 shnum >= SHN_LORESERVE ? 0 : shnum);
8289573673dSchristos   if (shnum == 0)
8299573673dSchristos     shstrndx = 0;
8309573673dSchristos   else
8319573673dSchristos     {
8329573673dSchristos       shstrndx = shnum - 1;
8339573673dSchristos       if (shstrndx >= SHN_LORESERVE)
8349573673dSchristos 	shstrndx = SHN_XINDEX;
8359573673dSchristos     }
8369573673dSchristos   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
837be9ac0eaSchristos 
838be9ac0eaSchristos   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
839be9ac0eaSchristos 				       errmsg, err);
840be9ac0eaSchristos }
841be9ac0eaSchristos 
842be9ac0eaSchristos /* Write out an ELF shdr.  */
843be9ac0eaSchristos 
844be9ac0eaSchristos static int
simple_object_elf_write_shdr(simple_object_write * sobj,int descriptor,off_t offset,unsigned int sh_name,unsigned int sh_type,unsigned int sh_flags,off_t sh_addr,unsigned int sh_offset,unsigned int sh_size,unsigned int sh_link,unsigned int sh_info,size_t sh_addralign,size_t sh_entsize,const char ** errmsg,int * err)845be9ac0eaSchristos simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
846be9ac0eaSchristos 			      off_t offset, unsigned int sh_name,
847be9ac0eaSchristos 			      unsigned int sh_type, unsigned int sh_flags,
848fc4f4269Schristos 			      off_t sh_addr,
849be9ac0eaSchristos 			      unsigned int sh_offset, unsigned int sh_size,
850fc4f4269Schristos 			      unsigned int sh_link, unsigned int sh_info,
851fc4f4269Schristos 			      size_t sh_addralign,
852fc4f4269Schristos 			      size_t sh_entsize,
8539573673dSchristos 			      const char **errmsg, int *err)
854be9ac0eaSchristos {
855be9ac0eaSchristos   struct simple_object_elf_attributes *attrs =
856be9ac0eaSchristos     (struct simple_object_elf_attributes *) sobj->data;
857be9ac0eaSchristos   const struct elf_type_functions* fns;
858be9ac0eaSchristos   unsigned char cl;
859be9ac0eaSchristos   size_t shdr_size;
860be9ac0eaSchristos   unsigned char buf[sizeof (Elf64_External_Shdr)];
861be9ac0eaSchristos 
862be9ac0eaSchristos   fns = attrs->type_functions;
863be9ac0eaSchristos   cl = attrs->ei_class;
864be9ac0eaSchristos 
865be9ac0eaSchristos   shdr_size = (cl == ELFCLASS32
866be9ac0eaSchristos 	       ? sizeof (Elf32_External_Shdr)
867be9ac0eaSchristos 	       : sizeof (Elf64_External_Shdr));
868be9ac0eaSchristos   memset (buf, 0, sizeof (Elf64_External_Shdr));
869be9ac0eaSchristos 
870be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
871be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
872be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
873fc4f4269Schristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
874be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
875be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
8769573673dSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
877fc4f4269Schristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
878be9ac0eaSchristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
879fc4f4269Schristos   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize);
880be9ac0eaSchristos 
881be9ac0eaSchristos   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
882be9ac0eaSchristos 				       errmsg, err);
883be9ac0eaSchristos }
884be9ac0eaSchristos 
885be9ac0eaSchristos /* Write out a complete ELF file.
886be9ac0eaSchristos    Ehdr
887be9ac0eaSchristos    initial dummy Shdr
888be9ac0eaSchristos    user-created Shdrs
889be9ac0eaSchristos    .shstrtab Shdr
890be9ac0eaSchristos    user-created section data
891be9ac0eaSchristos    .shstrtab data  */
892be9ac0eaSchristos 
893be9ac0eaSchristos static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)894be9ac0eaSchristos simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
895be9ac0eaSchristos 				 int *err)
896be9ac0eaSchristos {
897fc4f4269Schristos   struct simple_object_elf_write *eow =
898fc4f4269Schristos     (struct simple_object_elf_write *) sobj->data;
899fc4f4269Schristos   struct simple_object_elf_attributes *attrs = &eow->attrs;
900be9ac0eaSchristos   unsigned char cl;
901be9ac0eaSchristos   size_t ehdr_size;
902be9ac0eaSchristos   size_t shdr_size;
903be9ac0eaSchristos   const char *errmsg;
904be9ac0eaSchristos   simple_object_write_section *section;
905be9ac0eaSchristos   unsigned int shnum;
906be9ac0eaSchristos   size_t shdr_offset;
907be9ac0eaSchristos   size_t sh_offset;
9089573673dSchristos   unsigned int first_sh_size;
9099573673dSchristos   unsigned int first_sh_link;
910be9ac0eaSchristos   size_t sh_name;
911be9ac0eaSchristos   unsigned char zero;
912fc4f4269Schristos   unsigned secnum;
913be9ac0eaSchristos 
914be9ac0eaSchristos   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
915be9ac0eaSchristos     return errmsg;
916be9ac0eaSchristos 
917be9ac0eaSchristos   cl = attrs->ei_class;
918be9ac0eaSchristos   if (cl == ELFCLASS32)
919be9ac0eaSchristos     {
920be9ac0eaSchristos       ehdr_size = sizeof (Elf32_External_Ehdr);
921be9ac0eaSchristos       shdr_size = sizeof (Elf32_External_Shdr);
922be9ac0eaSchristos     }
923be9ac0eaSchristos   else
924be9ac0eaSchristos     {
925be9ac0eaSchristos       ehdr_size = sizeof (Elf64_External_Ehdr);
926be9ac0eaSchristos       shdr_size = sizeof (Elf64_External_Shdr);
927be9ac0eaSchristos     }
928be9ac0eaSchristos 
929be9ac0eaSchristos   shnum = 0;
930be9ac0eaSchristos   for (section = sobj->sections; section != NULL; section = section->next)
931be9ac0eaSchristos     ++shnum;
932be9ac0eaSchristos   if (shnum == 0)
933be9ac0eaSchristos     return NULL;
934be9ac0eaSchristos 
935be9ac0eaSchristos   /* Add initial dummy Shdr and .shstrtab.  */
936be9ac0eaSchristos   shnum += 2;
937be9ac0eaSchristos 
938be9ac0eaSchristos   shdr_offset = ehdr_size;
939be9ac0eaSchristos   sh_offset = shdr_offset + shnum * shdr_size;
940be9ac0eaSchristos 
9419573673dSchristos   if (shnum < SHN_LORESERVE)
9429573673dSchristos     first_sh_size = 0;
9439573673dSchristos   else
9449573673dSchristos     first_sh_size = shnum;
9459573673dSchristos   if (shnum - 1 < SHN_LORESERVE)
9469573673dSchristos     first_sh_link = 0;
9479573673dSchristos   else
9489573673dSchristos     first_sh_link = shnum - 1;
949be9ac0eaSchristos   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
950fc4f4269Schristos 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
951fc4f4269Schristos 				     0, 0, 0, &errmsg, err))
952be9ac0eaSchristos     return errmsg;
953be9ac0eaSchristos 
954be9ac0eaSchristos   shdr_offset += shdr_size;
955be9ac0eaSchristos 
956be9ac0eaSchristos   sh_name = 1;
957fc4f4269Schristos   secnum = 0;
958be9ac0eaSchristos   for (section = sobj->sections; section != NULL; section = section->next)
959be9ac0eaSchristos     {
960be9ac0eaSchristos       size_t mask;
961be9ac0eaSchristos       size_t new_sh_offset;
962be9ac0eaSchristos       size_t sh_size;
963be9ac0eaSchristos       struct simple_object_write_section_buffer *buffer;
964fc4f4269Schristos       unsigned int sh_type = SHT_PROGBITS;
965fc4f4269Schristos       unsigned int sh_flags = 0;
966fc4f4269Schristos       off_t sh_addr = 0;
967fc4f4269Schristos       unsigned int sh_link = 0;
968fc4f4269Schristos       unsigned int sh_info = 0;
969fc4f4269Schristos       size_t sh_addralign = 1U << section->align;
970fc4f4269Schristos       size_t sh_entsize = 0;
971fc4f4269Schristos       if (eow->shdrs)
972fc4f4269Schristos 	{
973fc4f4269Schristos 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
974fc4f4269Schristos 				     eow->shdrs + secnum * shdr_size,
975fc4f4269Schristos 				     sh_type, Elf_Word);
976fc4f4269Schristos 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
977fc4f4269Schristos 				      eow->shdrs + secnum * shdr_size,
978fc4f4269Schristos 				      sh_flags, Elf_Addr);
979fc4f4269Schristos 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
980fc4f4269Schristos 				     eow->shdrs + secnum * shdr_size,
981fc4f4269Schristos 				     sh_addr, Elf_Addr);
982fc4f4269Schristos 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
983fc4f4269Schristos 				     eow->shdrs + secnum * shdr_size,
984fc4f4269Schristos 				     sh_link, Elf_Word);
985fc4f4269Schristos 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
986fc4f4269Schristos 				     eow->shdrs + secnum * shdr_size,
987fc4f4269Schristos 				     sh_info, Elf_Word);
988fc4f4269Schristos 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
989fc4f4269Schristos 					  eow->shdrs + secnum * shdr_size,
990fc4f4269Schristos 					  sh_addralign, Elf_Addr);
991fc4f4269Schristos 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
992fc4f4269Schristos 					eow->shdrs + secnum * shdr_size,
993fc4f4269Schristos 					sh_entsize, Elf_Addr);
994fc4f4269Schristos 	  secnum++;
995fc4f4269Schristos 	}
996be9ac0eaSchristos 
997fc4f4269Schristos       mask = sh_addralign - 1;
998be9ac0eaSchristos       new_sh_offset = sh_offset + mask;
999be9ac0eaSchristos       new_sh_offset &= ~ mask;
1000be9ac0eaSchristos       while (new_sh_offset > sh_offset)
1001be9ac0eaSchristos 	{
1002be9ac0eaSchristos 	  unsigned char zeroes[16];
1003be9ac0eaSchristos 	  size_t write;
1004be9ac0eaSchristos 
1005be9ac0eaSchristos 	  memset (zeroes, 0, sizeof zeroes);
1006be9ac0eaSchristos 	  write = new_sh_offset - sh_offset;
1007be9ac0eaSchristos 	  if (write > sizeof zeroes)
1008be9ac0eaSchristos 	    write = sizeof zeroes;
1009be9ac0eaSchristos 	  if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
1010be9ac0eaSchristos 					     write, &errmsg, err))
1011be9ac0eaSchristos 	    return errmsg;
1012be9ac0eaSchristos 	  sh_offset += write;
1013be9ac0eaSchristos 	}
1014be9ac0eaSchristos 
1015be9ac0eaSchristos       sh_size = 0;
1016be9ac0eaSchristos       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1017be9ac0eaSchristos 	{
1018be9ac0eaSchristos 	  if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
1019be9ac0eaSchristos 					     ((const unsigned char *)
1020be9ac0eaSchristos 					      buffer->buffer),
1021be9ac0eaSchristos 					     buffer->size, &errmsg, err))
1022be9ac0eaSchristos 	    return errmsg;
1023be9ac0eaSchristos 	  sh_size += buffer->size;
1024be9ac0eaSchristos 	}
1025be9ac0eaSchristos 
1026be9ac0eaSchristos       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1027fc4f4269Schristos 					 sh_name, sh_type, sh_flags,
1028fc4f4269Schristos 					 sh_addr, sh_offset,
1029fc4f4269Schristos 					 sh_size, sh_link, sh_info,
1030fc4f4269Schristos 					 sh_addralign, sh_entsize,
1031be9ac0eaSchristos 					 &errmsg, err))
1032be9ac0eaSchristos 	return errmsg;
1033be9ac0eaSchristos 
1034be9ac0eaSchristos       shdr_offset += shdr_size;
1035be9ac0eaSchristos       sh_name += strlen (section->name) + 1;
1036be9ac0eaSchristos       sh_offset += sh_size;
1037be9ac0eaSchristos     }
1038be9ac0eaSchristos 
1039be9ac0eaSchristos   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1040fc4f4269Schristos 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
1041fc4f4269Schristos 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
1042fc4f4269Schristos 				     1, 0, &errmsg, err))
1043be9ac0eaSchristos     return errmsg;
1044be9ac0eaSchristos 
1045be9ac0eaSchristos   /* .shstrtab has a leading zero byte.  */
1046be9ac0eaSchristos   zero = 0;
1047be9ac0eaSchristos   if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
1048be9ac0eaSchristos 				     &errmsg, err))
1049be9ac0eaSchristos     return errmsg;
1050be9ac0eaSchristos   ++sh_offset;
1051be9ac0eaSchristos 
1052be9ac0eaSchristos   for (section = sobj->sections; section != NULL; section = section->next)
1053be9ac0eaSchristos     {
1054be9ac0eaSchristos       size_t len;
1055be9ac0eaSchristos 
1056be9ac0eaSchristos       len = strlen (section->name) + 1;
1057be9ac0eaSchristos       if (!simple_object_internal_write (descriptor, sh_offset,
1058be9ac0eaSchristos 					 (const unsigned char *) section->name,
1059be9ac0eaSchristos 					 len, &errmsg, err))
1060be9ac0eaSchristos 	return errmsg;
1061be9ac0eaSchristos       sh_offset += len;
1062be9ac0eaSchristos     }
1063be9ac0eaSchristos 
1064be9ac0eaSchristos   if (!simple_object_internal_write (descriptor, sh_offset,
1065be9ac0eaSchristos 				     (const unsigned char *) ".shstrtab",
1066be9ac0eaSchristos 				     strlen (".shstrtab") + 1, &errmsg, err))
1067be9ac0eaSchristos     return errmsg;
1068be9ac0eaSchristos 
1069be9ac0eaSchristos   return NULL;
1070be9ac0eaSchristos }
1071be9ac0eaSchristos 
1072be9ac0eaSchristos /* Release the private data for an simple_object_write structure.  */
1073be9ac0eaSchristos 
1074be9ac0eaSchristos static void
simple_object_elf_release_write(void * data)1075be9ac0eaSchristos simple_object_elf_release_write (void *data)
1076be9ac0eaSchristos {
1077fc4f4269Schristos   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
1078fc4f4269Schristos   if (eow->shdrs)
1079fc4f4269Schristos     XDELETE (eow->shdrs);
1080be9ac0eaSchristos   XDELETE (data);
1081be9ac0eaSchristos }
1082be9ac0eaSchristos 
1083fc4f4269Schristos /* Copy all sections in an ELF file.  */
1084fc4f4269Schristos 
1085fc4f4269Schristos static const char *
simple_object_elf_copy_lto_debug_sections(simple_object_read * sobj,simple_object_write * dobj,char * (* pfn)(const char *),int * err)1086fc4f4269Schristos simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
1087fc4f4269Schristos 					   simple_object_write *dobj,
1088c1a20988Schristos 					   char *(*pfn) (const char *),
1089fc4f4269Schristos 					   int *err)
1090fc4f4269Schristos {
1091fc4f4269Schristos   struct simple_object_elf_read *eor =
1092fc4f4269Schristos     (struct simple_object_elf_read *) sobj->data;
1093fc4f4269Schristos   const struct elf_type_functions *type_functions = eor->type_functions;
1094fc4f4269Schristos   struct simple_object_elf_write *eow =
1095fc4f4269Schristos     (struct simple_object_elf_write *) dobj->data;
1096fc4f4269Schristos   unsigned char ei_class = eor->ei_class;
1097fc4f4269Schristos   size_t shdr_size;
1098fc4f4269Schristos   unsigned int shnum;
1099fc4f4269Schristos   unsigned char *shdrs;
1100fc4f4269Schristos   const char *errmsg;
1101fc4f4269Schristos   unsigned char *shstrhdr;
1102fc4f4269Schristos   size_t name_size;
1103fc4f4269Schristos   off_t shstroff;
1104fc4f4269Schristos   unsigned char *names;
1105fc4f4269Schristos   unsigned int i;
1106fc4f4269Schristos   int changed;
1107fc4f4269Schristos   int *pfnret;
1108fc4f4269Schristos   const char **pfnname;
1109c1a20988Schristos   unsigned new_i;
1110c1a20988Schristos   unsigned *sh_map;
1111fc4f4269Schristos   unsigned first_shndx = 0;
1112c1a20988Schristos   unsigned int *symtab_indices_shndx;
1113fc4f4269Schristos 
1114fc4f4269Schristos   shdr_size = (ei_class == ELFCLASS32
1115fc4f4269Schristos 	       ? sizeof (Elf32_External_Shdr)
1116fc4f4269Schristos 	       : sizeof (Elf64_External_Shdr));
1117fc4f4269Schristos 
1118fc4f4269Schristos   /* Read the section headers.  We skip section 0, which is not a
1119fc4f4269Schristos      useful section.  */
1120fc4f4269Schristos 
1121fc4f4269Schristos   shnum = eor->shnum;
1122fc4f4269Schristos   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
1123fc4f4269Schristos 
1124fc4f4269Schristos   if (!simple_object_internal_read (sobj->descriptor,
1125fc4f4269Schristos 				    sobj->offset + eor->shoff + shdr_size,
1126fc4f4269Schristos 				    shdrs,
1127fc4f4269Schristos 				    shdr_size * (shnum - 1),
1128fc4f4269Schristos 				    &errmsg, err))
1129fc4f4269Schristos     {
1130fc4f4269Schristos       XDELETEVEC (shdrs);
1131fc4f4269Schristos       return errmsg;
1132fc4f4269Schristos     }
1133fc4f4269Schristos 
1134fc4f4269Schristos   /* Read the section names.  */
1135fc4f4269Schristos 
1136fc4f4269Schristos   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
1137fc4f4269Schristos   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1138fc4f4269Schristos 			       shstrhdr, sh_size, Elf_Addr);
1139fc4f4269Schristos   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1140fc4f4269Schristos 			      shstrhdr, sh_offset, Elf_Addr);
1141fc4f4269Schristos   names = XNEWVEC (unsigned char, name_size);
1142fc4f4269Schristos   if (!simple_object_internal_read (sobj->descriptor,
1143fc4f4269Schristos 				    sobj->offset + shstroff,
1144fc4f4269Schristos 				    names, name_size, &errmsg, err))
1145fc4f4269Schristos     {
1146fc4f4269Schristos       XDELETEVEC (names);
1147fc4f4269Schristos       XDELETEVEC (shdrs);
1148fc4f4269Schristos       return errmsg;
1149fc4f4269Schristos     }
1150fc4f4269Schristos 
1151fc4f4269Schristos   pfnret = XNEWVEC (int, shnum);
1152fc4f4269Schristos   pfnname = XNEWVEC (const char *, shnum);
1153fc4f4269Schristos 
1154c1a20988Schristos   /* Map of symtab to index section.  */
1155c1a20988Schristos   symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1);
1156c1a20988Schristos 
1157fc4f4269Schristos   /* First perform the callbacks to know which sections to preserve and
1158fc4f4269Schristos      what name to use for those.  */
1159fc4f4269Schristos   for (i = 1; i < shnum; ++i)
1160fc4f4269Schristos     {
1161fc4f4269Schristos       unsigned char *shdr;
1162c1a20988Schristos       unsigned int sh_name, sh_type;
1163fc4f4269Schristos       const char *name;
1164c1a20988Schristos       char *ret;
1165fc4f4269Schristos 
1166fc4f4269Schristos       shdr = shdrs + (i - 1) * shdr_size;
1167fc4f4269Schristos       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1168fc4f4269Schristos 				 shdr, sh_name, Elf_Word);
1169fc4f4269Schristos       if (sh_name >= name_size)
1170fc4f4269Schristos 	{
1171fc4f4269Schristos 	  *err = 0;
1172fc4f4269Schristos 	  XDELETEVEC (names);
1173fc4f4269Schristos 	  XDELETEVEC (shdrs);
1174fc4f4269Schristos 	  return "ELF section name out of range";
1175fc4f4269Schristos 	}
1176fc4f4269Schristos 
1177fc4f4269Schristos       name = (const char *) names + sh_name;
1178fc4f4269Schristos 
1179c1a20988Schristos       ret = (*pfn) (name);
1180c1a20988Schristos       pfnret[i - 1] = ret == NULL ? -1 : 0;
1181c1a20988Schristos       pfnname[i - 1] = ret == NULL ? name : ret;
1182fc4f4269Schristos       if (first_shndx == 0
1183fc4f4269Schristos 	  && pfnret[i - 1] == 0)
1184fc4f4269Schristos 	first_shndx = i;
1185c1a20988Schristos 
1186c1a20988Schristos       /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections.  */
1187c1a20988Schristos       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1188c1a20988Schristos 				 shdr, sh_type, Elf_Word);
1189c1a20988Schristos       if (sh_type == SHT_SYMTAB_SHNDX)
1190c1a20988Schristos 	{
1191c1a20988Schristos 	  unsigned int sh_link;
1192c1a20988Schristos 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1193c1a20988Schristos 				     shdr, sh_link, Elf_Word);
11944f645668Schristos 	  symtab_indices_shndx[sh_link - 1] = i - 1;
1195c1a20988Schristos 	  /* Always discard the extended index sections, after
1196c1a20988Schristos 	     copying it will not be needed.  This way we don't need to
1197c1a20988Schristos 	     update it and deal with the ordering constraints of
1198c1a20988Schristos 	     processing the existing symtab and changing the index.  */
1199c1a20988Schristos 	  pfnret[i - 1] = -1;
1200c1a20988Schristos 	}
1201fc4f4269Schristos     }
1202fc4f4269Schristos 
1203fc4f4269Schristos   /* Mark sections as preserved that are required by to be preserved
1204fc4f4269Schristos      sections.  */
1205fc4f4269Schristos   do
1206fc4f4269Schristos     {
1207fc4f4269Schristos       changed = 0;
1208fc4f4269Schristos       for (i = 1; i < shnum; ++i)
1209fc4f4269Schristos 	{
1210fc4f4269Schristos 	  unsigned char *shdr;
1211fc4f4269Schristos 	  unsigned int sh_type, sh_info, sh_link;
1212fc4f4269Schristos 	  off_t offset;
1213fc4f4269Schristos 	  off_t length;
1214fc4f4269Schristos 
1215fc4f4269Schristos 	  shdr = shdrs + (i - 1) * shdr_size;
1216fc4f4269Schristos 	  sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1217fc4f4269Schristos 				     shdr, sh_type, Elf_Word);
1218fc4f4269Schristos 	  sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1219fc4f4269Schristos 				     shdr, sh_info, Elf_Word);
1220fc4f4269Schristos 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1221fc4f4269Schristos 				     shdr, sh_link, Elf_Word);
1222fc4f4269Schristos 	  if (sh_type == SHT_GROUP)
1223fc4f4269Schristos 	    {
1224fc4f4269Schristos 	      /* Mark groups containing copied sections.  */
1225fc4f4269Schristos 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class,
1226fc4f4269Schristos 						  Shdr, shdr, sh_entsize,
1227fc4f4269Schristos 						  Elf_Addr);
1228fc4f4269Schristos 	      unsigned char *ent, *buf;
1229fc4f4269Schristos 	      int keep = 0;
1230fc4f4269Schristos 	      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1231fc4f4269Schristos 					shdr, sh_offset, Elf_Addr);
1232fc4f4269Schristos 	      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1233fc4f4269Schristos 					shdr, sh_size, Elf_Addr);
1234fc4f4269Schristos 	      buf = XNEWVEC (unsigned char, length);
1235fc4f4269Schristos 	      if (!simple_object_internal_read (sobj->descriptor,
1236fc4f4269Schristos 						sobj->offset + offset, buf,
1237fc4f4269Schristos 						(size_t) length, &errmsg, err))
1238fc4f4269Schristos 		{
1239fc4f4269Schristos 		  XDELETEVEC (buf);
1240fc4f4269Schristos 		  XDELETEVEC (names);
1241fc4f4269Schristos 		  XDELETEVEC (shdrs);
1242fc4f4269Schristos 		  return errmsg;
1243fc4f4269Schristos 		}
1244fc4f4269Schristos 	      for (ent = buf + entsize; ent < buf + length; ent += entsize)
1245fc4f4269Schristos 		{
1246fc4f4269Schristos 		  unsigned sec = type_functions->fetch_Elf_Word (ent);
1247fc4f4269Schristos 		  if (pfnret[sec - 1] == 0)
1248fc4f4269Schristos 		    keep = 1;
1249fc4f4269Schristos 		}
1250fc4f4269Schristos 	      if (keep)
1251fc4f4269Schristos 		{
1252fc4f4269Schristos 		  changed |= (pfnret[sh_link - 1] == -1
1253fc4f4269Schristos 			      || pfnret[i - 1] == -1);
1254fc4f4269Schristos 		  pfnret[sh_link - 1] = 0;
1255fc4f4269Schristos 		  pfnret[i - 1] = 0;
1256fc4f4269Schristos 		}
1257fc4f4269Schristos 	    }
1258fc4f4269Schristos 	  if (sh_type == SHT_RELA
1259fc4f4269Schristos 	      || sh_type == SHT_REL)
1260fc4f4269Schristos 	    {
1261fc4f4269Schristos 	      /* Mark relocation sections and symtab of copied sections.  */
1262fc4f4269Schristos 	      if (pfnret[sh_info - 1] == 0)
1263fc4f4269Schristos 		{
1264fc4f4269Schristos 		  changed |= (pfnret[sh_link - 1] == -1
1265fc4f4269Schristos 			      || pfnret[i - 1] == -1);
1266fc4f4269Schristos 		  pfnret[sh_link - 1] = 0;
1267fc4f4269Schristos 		  pfnret[i - 1] = 0;
1268fc4f4269Schristos 		}
1269fc4f4269Schristos 	    }
1270fc4f4269Schristos 	  if (sh_type == SHT_SYMTAB)
1271fc4f4269Schristos 	    {
1272fc4f4269Schristos 	      /* Mark strings sections of copied symtabs.  */
1273fc4f4269Schristos 	      if (pfnret[i - 1] == 0)
1274fc4f4269Schristos 		{
1275fc4f4269Schristos 		  changed |= pfnret[sh_link - 1] == -1;
1276fc4f4269Schristos 		  pfnret[sh_link - 1] = 0;
1277fc4f4269Schristos 		}
1278fc4f4269Schristos 	    }
1279fc4f4269Schristos 	}
1280fc4f4269Schristos     }
1281fc4f4269Schristos   while (changed);
1282fc4f4269Schristos 
1283c1a20988Schristos   /* Compute a mapping of old -> new section numbers.  */
1284c1a20988Schristos   sh_map = XNEWVEC (unsigned, shnum);
1285c1a20988Schristos   sh_map[0] = 0;
1286c1a20988Schristos   new_i = 1;
1287c1a20988Schristos   for (i = 1; i < shnum; ++i)
1288c1a20988Schristos     {
1289c1a20988Schristos       if (pfnret[i - 1] == -1)
1290c1a20988Schristos 	sh_map[i] = 0;
1291c1a20988Schristos       else
1292c1a20988Schristos 	sh_map[i] = new_i++;
1293c1a20988Schristos     }
1294c1a20988Schristos   if (new_i - 1 >= SHN_LORESERVE)
1295c1a20988Schristos     {
1296c1a20988Schristos       *err = ENOTSUP;
1297c1a20988Schristos       return "Too many copied sections";
1298c1a20988Schristos     }
1299c1a20988Schristos   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
1300c1a20988Schristos 
1301fc4f4269Schristos   /* Then perform the actual copying.  */
1302c1a20988Schristos   new_i = 0;
1303fc4f4269Schristos   for (i = 1; i < shnum; ++i)
1304fc4f4269Schristos     {
1305fc4f4269Schristos       unsigned char *shdr;
1306fc4f4269Schristos       unsigned int sh_name, sh_type;
1307fc4f4269Schristos       const char *name;
1308fc4f4269Schristos       off_t offset;
1309fc4f4269Schristos       off_t length;
1310fc4f4269Schristos       simple_object_write_section *dest;
1311fc4f4269Schristos       off_t flags;
1312fc4f4269Schristos       unsigned char *buf;
1313fc4f4269Schristos 
1314c1a20988Schristos       if (pfnret[i - 1])
1315c1a20988Schristos 	continue;
1316c1a20988Schristos 
1317c1a20988Schristos       new_i++;
1318fc4f4269Schristos       shdr = shdrs + (i - 1) * shdr_size;
1319fc4f4269Schristos       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1320fc4f4269Schristos 				 shdr, sh_name, Elf_Word);
1321fc4f4269Schristos       if (sh_name >= name_size)
1322fc4f4269Schristos 	{
1323fc4f4269Schristos 	  *err = 0;
1324fc4f4269Schristos 	  XDELETEVEC (names);
1325fc4f4269Schristos 	  XDELETEVEC (shdrs);
1326c1a20988Schristos 	  XDELETEVEC (symtab_indices_shndx);
1327fc4f4269Schristos 	  return "ELF section name out of range";
1328fc4f4269Schristos 	}
1329fc4f4269Schristos 
1330c1a20988Schristos       name = pfnname[i - 1];
1331fc4f4269Schristos       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1332fc4f4269Schristos 				shdr, sh_offset, Elf_Addr);
1333fc4f4269Schristos       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1334fc4f4269Schristos 				shdr, sh_size, Elf_Addr);
1335fc4f4269Schristos       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1336fc4f4269Schristos 				 shdr, sh_type, Elf_Word);
1337fc4f4269Schristos 
1338c1a20988Schristos       dest = simple_object_write_create_section (dobj, pfnname[i - 1],
1339c1a20988Schristos 						 0, &errmsg, err);
1340fc4f4269Schristos       if (dest == NULL)
1341fc4f4269Schristos 	{
1342fc4f4269Schristos 	  XDELETEVEC (names);
1343fc4f4269Schristos 	  XDELETEVEC (shdrs);
1344c1a20988Schristos 	  XDELETEVEC (symtab_indices_shndx);
1345fc4f4269Schristos 	  return errmsg;
1346fc4f4269Schristos 	}
1347fc4f4269Schristos 
1348fc4f4269Schristos       /* Record the SHDR of the source.  */
1349c1a20988Schristos       memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size);
1350c1a20988Schristos       shdr = eow->shdrs + (new_i - 1) * shdr_size;
1351fc4f4269Schristos 
1352fc4f4269Schristos       /* Copy the data.
1353fc4f4269Schristos 	 ???  This is quite wasteful and ideally would be delayed until
1354fc4f4269Schristos 	 write_to_file ().  Thus it questions the interfacing
1355fc4f4269Schristos 	 which eventually should contain destination creation plus
1356fc4f4269Schristos 	 writing.  */
1357fc4f4269Schristos       buf = XNEWVEC (unsigned char, length);
1358fc4f4269Schristos       if (!simple_object_internal_read (sobj->descriptor,
1359fc4f4269Schristos 					sobj->offset + offset, buf,
1360fc4f4269Schristos 					(size_t) length, &errmsg, err))
1361fc4f4269Schristos 	{
1362fc4f4269Schristos 	  XDELETEVEC (buf);
1363fc4f4269Schristos 	  XDELETEVEC (names);
1364fc4f4269Schristos 	  XDELETEVEC (shdrs);
1365c1a20988Schristos 	  XDELETEVEC (symtab_indices_shndx);
1366fc4f4269Schristos 	  return errmsg;
1367fc4f4269Schristos 	}
1368fc4f4269Schristos 
13696f4ced0bSchristos       /* If we are processing .symtab purge any symbols
13706f4ced0bSchristos 	 in discarded sections.  */
1371fc4f4269Schristos       if (sh_type == SHT_SYMTAB)
1372fc4f4269Schristos 	{
1373fc4f4269Schristos 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1374fc4f4269Schristos 					      shdr, sh_entsize, Elf_Addr);
13756f4ced0bSchristos 	  size_t prevailing_name_idx = 0;
1376fc4f4269Schristos 	  unsigned char *ent;
1377c1a20988Schristos 	  unsigned *shndx_table = NULL;
1378c1a20988Schristos 	  /* Read the section index table if present.  */
1379c1a20988Schristos 	  if (symtab_indices_shndx[i - 1] != 0)
1380c1a20988Schristos 	    {
13814f645668Schristos 	      unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size;
1382c1a20988Schristos 	      off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1383c1a20988Schristos 					       sidxhdr, sh_offset, Elf_Addr);
1384c1a20988Schristos 	      size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1385c1a20988Schristos 					       sidxhdr, sh_size, Elf_Addr);
13864f645668Schristos 	      unsigned int shndx_type
13874f645668Schristos 		= ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
13884f645668Schristos 				   sidxhdr, sh_type, Elf_Word);
13894f645668Schristos 	      if (shndx_type != SHT_SYMTAB_SHNDX)
13904f645668Schristos 		return "Wrong section type of a SYMTAB SECTION INDICES section";
1391c1a20988Schristos 	      shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
1392c1a20988Schristos 	      simple_object_internal_read (sobj->descriptor,
1393c1a20988Schristos 					   sobj->offset + sidxoff,
1394c1a20988Schristos 					   (unsigned char *)shndx_table,
1395c1a20988Schristos 					   sidxsz, &errmsg, err);
1396c1a20988Schristos 	    }
13976f4ced0bSchristos 
13986f4ced0bSchristos 	  /* Find a WEAK HIDDEN symbol which name we will use for removed
13996f4ced0bSchristos 	     symbols.  We know there's a prevailing weak hidden symbol
14006f4ced0bSchristos 	     at the start of the .debug_info section.  */
14016f4ced0bSchristos 	  for (ent = buf; ent < buf + length; ent += entsize)
14026f4ced0bSchristos 	    {
14036f4ced0bSchristos 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
14046f4ced0bSchristos 						   Sym, ent,
14056f4ced0bSchristos 						   st_shndx, Elf_Half);
14066f4ced0bSchristos 	      unsigned char *st_info;
14076f4ced0bSchristos 	      unsigned char *st_other;
14086f4ced0bSchristos 	      if (ei_class == ELFCLASS32)
14096f4ced0bSchristos 		{
14106f4ced0bSchristos 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
14116f4ced0bSchristos 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
14126f4ced0bSchristos 		}
14136f4ced0bSchristos 	      else
14146f4ced0bSchristos 		{
14156f4ced0bSchristos 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
14166f4ced0bSchristos 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
14176f4ced0bSchristos 		}
14186f4ced0bSchristos 	      if (st_shndx == SHN_XINDEX)
14196f4ced0bSchristos 		st_shndx = type_functions->fetch_Elf_Word
14206f4ced0bSchristos 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
14216f4ced0bSchristos 
14226f4ced0bSchristos 	      if (st_shndx != SHN_COMMON
14236f4ced0bSchristos 		  && !(st_shndx != SHN_UNDEF
14246f4ced0bSchristos 		       && st_shndx < shnum
14256f4ced0bSchristos 		       && pfnret[st_shndx - 1] == -1)
14266f4ced0bSchristos 		  && ELF_ST_BIND (*st_info) == STB_WEAK
14276f4ced0bSchristos 		  && *st_other == STV_HIDDEN)
14286f4ced0bSchristos 		{
14296f4ced0bSchristos 		  prevailing_name_idx = ELF_FETCH_FIELD (type_functions,
14306f4ced0bSchristos 							 ei_class, Sym, ent,
14316f4ced0bSchristos 							 st_name, Elf_Word);
14326f4ced0bSchristos 		  break;
14336f4ced0bSchristos 		}
14346f4ced0bSchristos 	    }
14356f4ced0bSchristos 
1436fc4f4269Schristos 	  for (ent = buf; ent < buf + length; ent += entsize)
1437fc4f4269Schristos 	    {
1438fc4f4269Schristos 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
1439fc4f4269Schristos 						   Sym, ent,
1440fc4f4269Schristos 						   st_shndx, Elf_Half);
1441c1a20988Schristos 	      unsigned raw_st_shndx = st_shndx;
1442fc4f4269Schristos 	      unsigned char *st_info;
1443fc4f4269Schristos 	      unsigned char *st_other;
1444fc4f4269Schristos 	      int discard = 0;
1445fc4f4269Schristos 	      if (ei_class == ELFCLASS32)
1446fc4f4269Schristos 		{
1447fc4f4269Schristos 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
1448fc4f4269Schristos 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
1449fc4f4269Schristos 		}
1450fc4f4269Schristos 	      else
1451fc4f4269Schristos 		{
1452fc4f4269Schristos 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
1453fc4f4269Schristos 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
1454fc4f4269Schristos 		}
1455c1a20988Schristos 	      if (st_shndx == SHN_XINDEX)
1456c1a20988Schristos 		st_shndx = type_functions->fetch_Elf_Word
1457c1a20988Schristos 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
14586f4ced0bSchristos 	      /* Eliminate all COMMONs - this includes __gnu_lto_slim
14596f4ced0bSchristos 		 which otherwise cause endless LTO plugin invocation.
14606f4ced0bSchristos 		 FIXME: remove the condition once we remove emission
14616f4ced0bSchristos 		 of __gnu_lto_slim symbol.  */
1462fc4f4269Schristos 	      if (st_shndx == SHN_COMMON)
1463fc4f4269Schristos 		discard = 1;
1464fc4f4269Schristos 	      /* We also need to remove symbols refering to sections
1465fc4f4269Schristos 		 we'll eventually remove as with fat LTO objects
1466fc4f4269Schristos 		 we otherwise get duplicate symbols at final link
1467fc4f4269Schristos 		 (with GNU ld, gold is fine and ignores symbols in
1468fc4f4269Schristos 		 sections marked as EXCLUDE).  ld/20513  */
1469fc4f4269Schristos 	      else if (st_shndx != SHN_UNDEF
1470fc4f4269Schristos 		       && st_shndx < shnum
1471fc4f4269Schristos 		       && pfnret[st_shndx - 1] == -1)
1472fc4f4269Schristos 		discard = 1;
14734f645668Schristos 	      /* We also need to remove global UNDEFs which can
14744f645668Schristos 		 cause link fails later.  */
14754f645668Schristos 	      else if (st_shndx == SHN_UNDEF
14764f645668Schristos 		       && ELF_ST_BIND (*st_info) == STB_GLOBAL)
14774f645668Schristos 		discard = 1;
1478fc4f4269Schristos 
1479fc4f4269Schristos 	      if (discard)
1480fc4f4269Schristos 		{
1481fc4f4269Schristos 		  /* Make discarded symbols undefined and unnamed
1482fc4f4269Schristos 		     in case it is local.  */
1483fc4f4269Schristos 		  int bind = ELF_ST_BIND (*st_info);
1484fc4f4269Schristos 		  int other = STV_DEFAULT;
1485fc4f4269Schristos 		  if (bind == STB_LOCAL)
1486fc4f4269Schristos 		    {
1487fc4f4269Schristos 		      /* Make discarded local symbols unnamed and
1488fc4f4269Schristos 			 defined in the first prevailing section.  */
1489fc4f4269Schristos 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1490fc4f4269Schristos 				     ent, st_name, Elf_Word, 0);
1491fc4f4269Schristos 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1492c1a20988Schristos 				     ent, st_shndx, Elf_Half,
1493c1a20988Schristos 				     sh_map[first_shndx]);
1494fc4f4269Schristos 		    }
1495fc4f4269Schristos 		  else
1496fc4f4269Schristos 		    {
1497fc4f4269Schristos 		      /* Make discarded global symbols hidden weak
14986f4ced0bSchristos 			 undefined and sharing a name of a prevailing
14996f4ced0bSchristos 			 symbol.  */
1500fc4f4269Schristos 		      bind = STB_WEAK;
1501fc4f4269Schristos 		      other = STV_HIDDEN;
1502fc4f4269Schristos 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1503fc4f4269Schristos 				     ent, st_name, Elf_Word,
15046f4ced0bSchristos 				     prevailing_name_idx);
1505fc4f4269Schristos 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1506fc4f4269Schristos 				     ent, st_shndx, Elf_Half, SHN_UNDEF);
1507fc4f4269Schristos 		    }
1508fc4f4269Schristos 		  *st_other = other;
1509fc4f4269Schristos 		  *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
1510fc4f4269Schristos 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1511fc4f4269Schristos 				 ent, st_value, Elf_Addr, 0);
1512fc4f4269Schristos 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1513fc4f4269Schristos 				 ent, st_size, Elf_Word, 0);
1514fc4f4269Schristos 		}
1515c1a20988Schristos 	      else if (raw_st_shndx < SHN_LORESERVE
1516c1a20988Schristos 		       || raw_st_shndx == SHN_XINDEX)
1517c1a20988Schristos 		/* Remap the section reference.  */
1518c1a20988Schristos 		ELF_SET_FIELD (type_functions, ei_class, Sym,
1519c1a20988Schristos 			       ent, st_shndx, Elf_Half, sh_map[st_shndx]);
1520fc4f4269Schristos 	    }
1521c1a20988Schristos 	  XDELETEVEC (shndx_table);
1522c1a20988Schristos 	}
1523c1a20988Schristos       else if (sh_type == SHT_GROUP)
1524c1a20988Schristos 	{
1525c1a20988Schristos 	  /* Remap section indices in groups and remove removed members.  */
1526c1a20988Schristos 	  unsigned char *ent, *dst;
1527c1a20988Schristos 	  for (dst = ent = buf + 4; ent < buf + length; ent += 4)
1528c1a20988Schristos 	    {
1529c1a20988Schristos 	      unsigned shndx = type_functions->fetch_Elf_Word (ent);
1530c1a20988Schristos 	      if (pfnret[shndx - 1] == -1)
1531c1a20988Schristos 		;
1532c1a20988Schristos 	      else
1533c1a20988Schristos 		{
1534c1a20988Schristos 		  type_functions->set_Elf_Word (dst, sh_map[shndx]);
1535c1a20988Schristos 		  dst += 4;
1536c1a20988Schristos 		}
1537c1a20988Schristos 	    }
1538c1a20988Schristos 	  /* Adjust the length.  */
1539c1a20988Schristos 	  length = dst - buf;
1540fc4f4269Schristos 	}
1541fc4f4269Schristos 
1542fc4f4269Schristos       errmsg = simple_object_write_add_data (dobj, dest,
1543fc4f4269Schristos 					     buf, length, 1, err);
1544fc4f4269Schristos       XDELETEVEC (buf);
1545fc4f4269Schristos       if (errmsg)
1546fc4f4269Schristos 	{
1547fc4f4269Schristos 	  XDELETEVEC (names);
1548fc4f4269Schristos 	  XDELETEVEC (shdrs);
1549c1a20988Schristos 	  XDELETEVEC (symtab_indices_shndx);
1550fc4f4269Schristos 	  return errmsg;
1551fc4f4269Schristos 	}
1552fc4f4269Schristos 
1553fc4f4269Schristos       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1554fc4f4269Schristos 			       shdr, sh_flags, Elf_Addr);
1555c1a20988Schristos       /* Remap the section references.  */
1556fc4f4269Schristos       {
1557c1a20988Schristos 	unsigned int sh_info, sh_link;
1558c1a20988Schristos 	if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA)
1559c1a20988Schristos 	  {
1560c1a20988Schristos 	    sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1561c1a20988Schristos 				       shdr, sh_info, Elf_Word);
1562c1a20988Schristos 	    sh_info = sh_map[sh_info];
1563c1a20988Schristos 	    ELF_SET_FIELD (type_functions, ei_class, Shdr,
1564c1a20988Schristos 			   shdr, sh_info, Elf_Word, sh_info);
1565c1a20988Schristos 	  }
1566c1a20988Schristos 	sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1567c1a20988Schristos 				   shdr, sh_link, Elf_Word);
1568c1a20988Schristos 	sh_link = sh_map[sh_link];
1569c1a20988Schristos 	ELF_SET_FIELD (type_functions, ei_class, Shdr,
1570c1a20988Schristos 		       shdr, sh_link, Elf_Word, sh_link);
1571c1a20988Schristos       }
1572fc4f4269Schristos       /* The debugobj doesn't contain any code, thus no trampolines.
1573fc4f4269Schristos 	 Even when the original object needs trampolines, debugobj
1574fc4f4269Schristos 	 doesn't.  */
1575fc4f4269Schristos       if (strcmp (name, ".note.GNU-stack") == 0)
1576fc4f4269Schristos 	flags &= ~SHF_EXECINSTR;
1577c1a20988Schristos       /* Clear SHF_EXCLUDE on to be preserved sections.  */
1578fc4f4269Schristos       flags &= ~SHF_EXCLUDE;
1579fc4f4269Schristos       ELF_SET_FIELD (type_functions, ei_class, Shdr,
1580fc4f4269Schristos 		     shdr, sh_flags, Elf_Addr, flags);
1581fc4f4269Schristos     }
1582fc4f4269Schristos 
1583fc4f4269Schristos   XDELETEVEC (names);
1584fc4f4269Schristos   XDELETEVEC (shdrs);
1585fc4f4269Schristos   XDELETEVEC (pfnret);
1586fc4f4269Schristos   XDELETEVEC (pfnname);
1587c1a20988Schristos   XDELETEVEC (symtab_indices_shndx);
1588c1a20988Schristos   XDELETEVEC (sh_map);
1589fc4f4269Schristos 
1590fc4f4269Schristos   return NULL;
1591fc4f4269Schristos }
1592fc4f4269Schristos 
1593fc4f4269Schristos 
1594be9ac0eaSchristos /* The ELF functions.  */
1595be9ac0eaSchristos 
1596be9ac0eaSchristos const struct simple_object_functions simple_object_elf_functions =
1597be9ac0eaSchristos {
1598be9ac0eaSchristos   simple_object_elf_match,
1599be9ac0eaSchristos   simple_object_elf_find_sections,
1600be9ac0eaSchristos   simple_object_elf_fetch_attributes,
1601be9ac0eaSchristos   simple_object_elf_release_read,
1602883529b6Schristos   simple_object_elf_attributes_merge,
1603be9ac0eaSchristos   simple_object_elf_release_attributes,
1604be9ac0eaSchristos   simple_object_elf_start_write,
1605be9ac0eaSchristos   simple_object_elf_write_to_file,
1606fc4f4269Schristos   simple_object_elf_release_write,
1607fc4f4269Schristos   simple_object_elf_copy_lto_debug_sections
1608be9ac0eaSchristos };
1609