xref: /netbsd-src/external/gpl3/gcc.old/dist/libiberty/simple-object-elf.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* simple-object-elf.c -- routines to manipulate ELF object files.
2*8feb0f0bSmrg    Copyright (C) 2010-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Written by Ian Lance Taylor, Google.
41debfc3dSmrg 
51debfc3dSmrg This program is free software; you can redistribute it and/or modify it
61debfc3dSmrg under the terms of the GNU General Public License as published by the
71debfc3dSmrg Free Software Foundation; either version 2, or (at your option) any
81debfc3dSmrg later version.
91debfc3dSmrg 
101debfc3dSmrg This program is distributed in the hope that it will be useful,
111debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
121debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131debfc3dSmrg GNU General Public License for more details.
141debfc3dSmrg 
151debfc3dSmrg You should have received a copy of the GNU General Public License
161debfc3dSmrg along with this program; if not, write to the Free Software
171debfc3dSmrg Foundation, 51 Franklin Street - Fifth Floor,
181debfc3dSmrg Boston, MA 02110-1301, USA.  */
191debfc3dSmrg 
201debfc3dSmrg #include "config.h"
211debfc3dSmrg #include "libiberty.h"
221debfc3dSmrg #include "simple-object.h"
231debfc3dSmrg 
241debfc3dSmrg #include <errno.h>
25a2dc1f3fSmrg /* mingw.org's MinGW doesn't have ENOTSUP.  */
26a2dc1f3fSmrg #ifndef ENOTSUP
27a2dc1f3fSmrg # define ENOTSUP ENOSYS
28a2dc1f3fSmrg #endif
291debfc3dSmrg #include <stddef.h>
301debfc3dSmrg 
311debfc3dSmrg #ifdef HAVE_STDLIB_H
321debfc3dSmrg #include <stdlib.h>
331debfc3dSmrg #endif
341debfc3dSmrg 
351debfc3dSmrg #ifdef HAVE_STDINT_H
361debfc3dSmrg #include <stdint.h>
371debfc3dSmrg #endif
381debfc3dSmrg 
391debfc3dSmrg #ifdef HAVE_STRING_H
401debfc3dSmrg #include <string.h>
411debfc3dSmrg #endif
421debfc3dSmrg 
431debfc3dSmrg #ifdef HAVE_INTTYPES_H
441debfc3dSmrg #include <inttypes.h>
451debfc3dSmrg #endif
461debfc3dSmrg 
471debfc3dSmrg #include "simple-object-common.h"
481debfc3dSmrg 
491debfc3dSmrg /* ELF structures and constants.  */
501debfc3dSmrg 
511debfc3dSmrg /* 32-bit ELF file header.  */
521debfc3dSmrg 
531debfc3dSmrg typedef struct {
541debfc3dSmrg   unsigned char	e_ident[16];		/* ELF "magic number" */
551debfc3dSmrg   unsigned char	e_type[2];		/* Identifies object file type */
561debfc3dSmrg   unsigned char	e_machine[2];		/* Specifies required architecture */
571debfc3dSmrg   unsigned char	e_version[4];		/* Identifies object file version */
581debfc3dSmrg   unsigned char	e_entry[4];		/* Entry point virtual address */
591debfc3dSmrg   unsigned char	e_phoff[4];		/* Program header table file offset */
601debfc3dSmrg   unsigned char	e_shoff[4];		/* Section header table file offset */
611debfc3dSmrg   unsigned char	e_flags[4];		/* Processor-specific flags */
621debfc3dSmrg   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
631debfc3dSmrg   unsigned char	e_phentsize[2];		/* Program header table entry size */
641debfc3dSmrg   unsigned char	e_phnum[2];		/* Program header table entry count */
651debfc3dSmrg   unsigned char	e_shentsize[2];		/* Section header table entry size */
661debfc3dSmrg   unsigned char	e_shnum[2];		/* Section header table entry count */
671debfc3dSmrg   unsigned char	e_shstrndx[2];		/* Section header string table index */
681debfc3dSmrg } Elf32_External_Ehdr;
691debfc3dSmrg 
701debfc3dSmrg /* 64-bit ELF file header.  */
711debfc3dSmrg 
721debfc3dSmrg typedef struct {
731debfc3dSmrg   unsigned char	e_ident[16];		/* ELF "magic number" */
741debfc3dSmrg   unsigned char	e_type[2];		/* Identifies object file type */
751debfc3dSmrg   unsigned char	e_machine[2];		/* Specifies required architecture */
761debfc3dSmrg   unsigned char	e_version[4];		/* Identifies object file version */
771debfc3dSmrg   unsigned char	e_entry[8];		/* Entry point virtual address */
781debfc3dSmrg   unsigned char	e_phoff[8];		/* Program header table file offset */
791debfc3dSmrg   unsigned char	e_shoff[8];		/* Section header table file offset */
801debfc3dSmrg   unsigned char	e_flags[4];		/* Processor-specific flags */
811debfc3dSmrg   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
821debfc3dSmrg   unsigned char	e_phentsize[2];		/* Program header table entry size */
831debfc3dSmrg   unsigned char	e_phnum[2];		/* Program header table entry count */
841debfc3dSmrg   unsigned char	e_shentsize[2];		/* Section header table entry size */
851debfc3dSmrg   unsigned char	e_shnum[2];		/* Section header table entry count */
861debfc3dSmrg   unsigned char	e_shstrndx[2];		/* Section header string table index */
871debfc3dSmrg } Elf64_External_Ehdr;
881debfc3dSmrg 
891debfc3dSmrg /* Indexes and values in e_ident field of Ehdr.  */
901debfc3dSmrg 
911debfc3dSmrg #define EI_MAG0		0	/* File identification byte 0 index */
921debfc3dSmrg #define ELFMAG0		   0x7F	/* Magic number byte 0 */
931debfc3dSmrg 
941debfc3dSmrg #define EI_MAG1		1	/* File identification byte 1 index */
951debfc3dSmrg #define ELFMAG1		    'E'	/* Magic number byte 1 */
961debfc3dSmrg 
971debfc3dSmrg #define EI_MAG2		2	/* File identification byte 2 index */
981debfc3dSmrg #define ELFMAG2		    'L'	/* Magic number byte 2 */
991debfc3dSmrg 
1001debfc3dSmrg #define EI_MAG3		3	/* File identification byte 3 index */
1011debfc3dSmrg #define ELFMAG3		    'F'	/* Magic number byte 3 */
1021debfc3dSmrg 
1031debfc3dSmrg #define EI_CLASS	4	/* File class */
1041debfc3dSmrg #define ELFCLASSNONE	      0	/* Invalid class */
1051debfc3dSmrg #define ELFCLASS32	      1	/* 32-bit objects */
1061debfc3dSmrg #define ELFCLASS64	      2	/* 64-bit objects */
1071debfc3dSmrg 
1081debfc3dSmrg #define EI_DATA		5	/* Data encoding */
1091debfc3dSmrg #define ELFDATANONE	      0	/* Invalid data encoding */
1101debfc3dSmrg #define ELFDATA2LSB	      1	/* 2's complement, little endian */
1111debfc3dSmrg #define ELFDATA2MSB	      2	/* 2's complement, big endian */
1121debfc3dSmrg 
1131debfc3dSmrg #define EI_VERSION	6	/* File version */
1141debfc3dSmrg #define EV_CURRENT	1		/* Current version */
1151debfc3dSmrg 
1161debfc3dSmrg #define EI_OSABI	7	/* Operating System/ABI indication */
1171debfc3dSmrg 
1181debfc3dSmrg /* Values for e_type field of Ehdr.  */
1191debfc3dSmrg 
1201debfc3dSmrg #define ET_REL		1	/* Relocatable file */
1211debfc3dSmrg 
1221debfc3dSmrg /* Values for e_machine field of Ehdr.  */
1231debfc3dSmrg 
1241debfc3dSmrg #define EM_SPARC	  2	/* SUN SPARC */
1251debfc3dSmrg #define EM_SPARC32PLUS	 18	/* Sun's "v8plus" */
1261debfc3dSmrg 
1271debfc3dSmrg /* Special section index values.  */
1281debfc3dSmrg 
129a2dc1f3fSmrg #define SHN_UNDEF	0		/* Undefined section */
1301debfc3dSmrg #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
131a2dc1f3fSmrg #define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
1321debfc3dSmrg #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
133a2dc1f3fSmrg #define SHN_HIRESERVE	0xffff		/* End of reserved indices */
134a2dc1f3fSmrg 
1351debfc3dSmrg 
1361debfc3dSmrg /* 32-bit ELF program header.  */
1371debfc3dSmrg 
1381debfc3dSmrg typedef struct {
1391debfc3dSmrg   unsigned char	p_type[4];		/* Identifies program segment type */
1401debfc3dSmrg   unsigned char	p_offset[4];		/* Segment file offset */
1411debfc3dSmrg   unsigned char	p_vaddr[4];		/* Segment virtual address */
1421debfc3dSmrg   unsigned char	p_paddr[4];		/* Segment physical address */
1431debfc3dSmrg   unsigned char	p_filesz[4];		/* Segment size in file */
1441debfc3dSmrg   unsigned char	p_memsz[4];		/* Segment size in memory */
1451debfc3dSmrg   unsigned char	p_flags[4];		/* Segment flags */
1461debfc3dSmrg   unsigned char	p_align[4];		/* Segment alignment, file & memory */
1471debfc3dSmrg } Elf32_External_Phdr;
1481debfc3dSmrg 
1491debfc3dSmrg /* 64-bit ELF program header.  */
1501debfc3dSmrg 
1511debfc3dSmrg typedef struct {
1521debfc3dSmrg   unsigned char	p_type[4];		/* Identifies program segment type */
1531debfc3dSmrg   unsigned char	p_flags[4];		/* Segment flags */
1541debfc3dSmrg   unsigned char	p_offset[8];		/* Segment file offset */
1551debfc3dSmrg   unsigned char	p_vaddr[8];		/* Segment virtual address */
1561debfc3dSmrg   unsigned char	p_paddr[8];		/* Segment physical address */
1571debfc3dSmrg   unsigned char	p_filesz[8];		/* Segment size in file */
1581debfc3dSmrg   unsigned char	p_memsz[8];		/* Segment size in memory */
1591debfc3dSmrg   unsigned char	p_align[8];		/* Segment alignment, file & memory */
1601debfc3dSmrg } Elf64_External_Phdr;
1611debfc3dSmrg 
1621debfc3dSmrg /* 32-bit ELF section header */
1631debfc3dSmrg 
1641debfc3dSmrg typedef struct {
1651debfc3dSmrg   unsigned char	sh_name[4];		/* Section name, index in string tbl */
1661debfc3dSmrg   unsigned char	sh_type[4];		/* Type of section */
1671debfc3dSmrg   unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
1681debfc3dSmrg   unsigned char	sh_addr[4];		/* Section virtual addr at execution */
1691debfc3dSmrg   unsigned char	sh_offset[4];		/* Section file offset */
1701debfc3dSmrg   unsigned char	sh_size[4];		/* Size of section in bytes */
1711debfc3dSmrg   unsigned char	sh_link[4];		/* Index of another section */
1721debfc3dSmrg   unsigned char	sh_info[4];		/* Additional section information */
1731debfc3dSmrg   unsigned char	sh_addralign[4];	/* Section alignment */
1741debfc3dSmrg   unsigned char	sh_entsize[4];		/* Entry size if section holds table */
1751debfc3dSmrg } Elf32_External_Shdr;
1761debfc3dSmrg 
1771debfc3dSmrg /* 64-bit ELF section header.  */
1781debfc3dSmrg 
1791debfc3dSmrg typedef struct {
1801debfc3dSmrg   unsigned char	sh_name[4];		/* Section name, index in string tbl */
1811debfc3dSmrg   unsigned char	sh_type[4];		/* Type of section */
1821debfc3dSmrg   unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
1831debfc3dSmrg   unsigned char	sh_addr[8];		/* Section virtual addr at execution */
1841debfc3dSmrg   unsigned char	sh_offset[8];		/* Section file offset */
1851debfc3dSmrg   unsigned char	sh_size[8];		/* Size of section in bytes */
1861debfc3dSmrg   unsigned char	sh_link[4];		/* Index of another section */
1871debfc3dSmrg   unsigned char	sh_info[4];		/* Additional section information */
1881debfc3dSmrg   unsigned char	sh_addralign[8];	/* Section alignment */
1891debfc3dSmrg   unsigned char	sh_entsize[8];		/* Entry size if section holds table */
1901debfc3dSmrg } Elf64_External_Shdr;
1911debfc3dSmrg 
1921debfc3dSmrg /* Values for sh_type field.  */
1931debfc3dSmrg 
194a2dc1f3fSmrg #define SHT_NULL	0		/* Section header table entry unused */
1951debfc3dSmrg #define SHT_PROGBITS	1		/* Program data */
196a2dc1f3fSmrg #define SHT_SYMTAB	2		/* Link editing symbol table */
1971debfc3dSmrg #define SHT_STRTAB	3		/* A string table */
198a2dc1f3fSmrg #define SHT_RELA	4		/* Relocation entries with addends */
199a2dc1f3fSmrg #define SHT_REL		9		/* Relocation entries, no addends */
200a2dc1f3fSmrg #define SHT_GROUP	17		/* Section contains a section group */
201a2dc1f3fSmrg #define SHT_SYMTAB_SHNDX 18		/* Extended section indeces */
202a2dc1f3fSmrg 
203a2dc1f3fSmrg /* Values for sh_flags field.  */
204a2dc1f3fSmrg 
205a2dc1f3fSmrg #define SHF_INFO_LINK	0x00000040	/* `sh_info' contains SHT index */
206a2dc1f3fSmrg #define SHF_EXECINSTR	0x00000004	/* Executable section.  */
207a2dc1f3fSmrg #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
208a2dc1f3fSmrg 					   section from executable and
209a2dc1f3fSmrg 					   shared library that it builds
210a2dc1f3fSmrg 					   when those objects are not to be
211a2dc1f3fSmrg 					   further relocated.  */
212a2dc1f3fSmrg /* Symbol table entry.  */
213a2dc1f3fSmrg 
214a2dc1f3fSmrg typedef struct
215a2dc1f3fSmrg {
216a2dc1f3fSmrg   unsigned char st_name[4];                /* Symbol name (string tbl index) */
217a2dc1f3fSmrg   unsigned char st_value[4];               /* Symbol value */
218a2dc1f3fSmrg   unsigned char st_size[4];                /* Symbol size */
219a2dc1f3fSmrg   unsigned char st_info;                /* Symbol type and binding */
220a2dc1f3fSmrg   unsigned char st_other;               /* Symbol visibility */
221a2dc1f3fSmrg   unsigned char st_shndx[2];               /* Section index */
222a2dc1f3fSmrg } Elf32_External_Sym;
223a2dc1f3fSmrg 
224a2dc1f3fSmrg typedef struct
225a2dc1f3fSmrg {
226a2dc1f3fSmrg   unsigned char st_name[4];                /* Symbol name (string tbl index) */
227a2dc1f3fSmrg   unsigned char st_info;                /* Symbol type and binding */
228a2dc1f3fSmrg   unsigned char st_other;               /* Symbol visibility */
229a2dc1f3fSmrg   unsigned char st_shndx[2];               /* Section index */
230a2dc1f3fSmrg   unsigned char st_value[8];               /* Symbol value */
231a2dc1f3fSmrg   unsigned char st_size[8];                /* Symbol size */
232a2dc1f3fSmrg } Elf64_External_Sym;
233a2dc1f3fSmrg 
234a2dc1f3fSmrg #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
235a2dc1f3fSmrg #define ELF_ST_TYPE(val)              ((val) & 0xf)
236a2dc1f3fSmrg #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
237a2dc1f3fSmrg 
238a2dc1f3fSmrg #define STT_NOTYPE	0	/* Symbol type is unspecified */
239a2dc1f3fSmrg #define STT_OBJECT	1	/* Symbol is a data object */
240a2dc1f3fSmrg #define STT_FUNC	2	/* Symbol is a code object */
241a2dc1f3fSmrg #define STT_TLS		6	/* Thread local data object */
242a2dc1f3fSmrg #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
243a2dc1f3fSmrg 
244a2dc1f3fSmrg #define STB_LOCAL	0	/* Local symbol */
245a2dc1f3fSmrg #define STB_GLOBAL	1	/* Global symbol */
246a2dc1f3fSmrg #define STB_WEAK	2	/* Weak global */
247a2dc1f3fSmrg 
248a2dc1f3fSmrg #define STV_DEFAULT	0	/* Visibility is specified by binding type */
249a2dc1f3fSmrg #define STV_HIDDEN	2	/* Can only be seen inside currect component */
2501debfc3dSmrg 
2511debfc3dSmrg /* Functions to fetch and store different ELF types, depending on the
2521debfc3dSmrg    endianness and size.  */
2531debfc3dSmrg 
2541debfc3dSmrg struct elf_type_functions
2551debfc3dSmrg {
2561debfc3dSmrg   unsigned short (*fetch_Elf_Half) (const unsigned char *);
2571debfc3dSmrg   unsigned int (*fetch_Elf_Word) (const unsigned char *);
2581debfc3dSmrg   ulong_type (*fetch_Elf_Addr) (const unsigned char *);
2591debfc3dSmrg   void (*set_Elf_Half) (unsigned char *, unsigned short);
2601debfc3dSmrg   void (*set_Elf_Word) (unsigned char *, unsigned int);
2611debfc3dSmrg   void (*set_Elf_Addr) (unsigned char *, ulong_type);
2621debfc3dSmrg };
2631debfc3dSmrg 
2641debfc3dSmrg static const struct elf_type_functions elf_big_32_functions =
2651debfc3dSmrg {
2661debfc3dSmrg   simple_object_fetch_big_16,
2671debfc3dSmrg   simple_object_fetch_big_32,
2681debfc3dSmrg   simple_object_fetch_big_32_ulong,
2691debfc3dSmrg   simple_object_set_big_16,
2701debfc3dSmrg   simple_object_set_big_32,
2711debfc3dSmrg   simple_object_set_big_32_ulong
2721debfc3dSmrg };
2731debfc3dSmrg 
2741debfc3dSmrg static const struct elf_type_functions elf_little_32_functions =
2751debfc3dSmrg {
2761debfc3dSmrg   simple_object_fetch_little_16,
2771debfc3dSmrg   simple_object_fetch_little_32,
2781debfc3dSmrg   simple_object_fetch_little_32_ulong,
2791debfc3dSmrg   simple_object_set_little_16,
2801debfc3dSmrg   simple_object_set_little_32,
2811debfc3dSmrg   simple_object_set_little_32_ulong
2821debfc3dSmrg };
2831debfc3dSmrg 
2841debfc3dSmrg #ifdef UNSIGNED_64BIT_TYPE
2851debfc3dSmrg 
2861debfc3dSmrg static const struct elf_type_functions elf_big_64_functions =
2871debfc3dSmrg {
2881debfc3dSmrg   simple_object_fetch_big_16,
2891debfc3dSmrg   simple_object_fetch_big_32,
2901debfc3dSmrg   simple_object_fetch_big_64,
2911debfc3dSmrg   simple_object_set_big_16,
2921debfc3dSmrg   simple_object_set_big_32,
2931debfc3dSmrg   simple_object_set_big_64
2941debfc3dSmrg };
2951debfc3dSmrg 
2961debfc3dSmrg static const struct elf_type_functions elf_little_64_functions =
2971debfc3dSmrg {
2981debfc3dSmrg   simple_object_fetch_little_16,
2991debfc3dSmrg   simple_object_fetch_little_32,
3001debfc3dSmrg   simple_object_fetch_little_64,
3011debfc3dSmrg   simple_object_set_little_16,
3021debfc3dSmrg   simple_object_set_little_32,
3031debfc3dSmrg   simple_object_set_little_64
3041debfc3dSmrg };
3051debfc3dSmrg 
3061debfc3dSmrg #endif
3071debfc3dSmrg 
3081debfc3dSmrg /* Hideous macro to fetch the value of a field from an external ELF
3091debfc3dSmrg    struct of some sort.  TYPEFUNCS is the set of type functions.
3101debfc3dSmrg    BUFFER points to the external data.  STRUCTTYPE is the appropriate
3111debfc3dSmrg    struct type.  FIELD is a field within the struct.  TYPE is the type
3121debfc3dSmrg    of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
3131debfc3dSmrg 
3141debfc3dSmrg #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
3151debfc3dSmrg   ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
3161debfc3dSmrg 
3171debfc3dSmrg /* Even more hideous macro to fetch the value of FIELD from BUFFER.
3181debfc3dSmrg    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
3191debfc3dSmrg    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
3201debfc3dSmrg    the struct.  TYPE is the type of the field in the struct: Elf_Half,
3211debfc3dSmrg    Elf_Word, or Elf_Addr.  */
3221debfc3dSmrg 
3231debfc3dSmrg #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
3241debfc3dSmrg 			      FIELD, TYPE)				\
3251debfc3dSmrg   ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
3261debfc3dSmrg 			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
3271debfc3dSmrg 			  FIELD, BUFFER, TYPE)
3281debfc3dSmrg 
3291debfc3dSmrg /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
3301debfc3dSmrg 
3311debfc3dSmrg #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
3321debfc3dSmrg 			FIELD, TYPE)					\
3331debfc3dSmrg   ((CLASS) == ELFCLASS32						\
3341debfc3dSmrg     ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
3351debfc3dSmrg 			     TYPE)					\
3361debfc3dSmrg     : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
3371debfc3dSmrg 			     TYPE))
3381debfc3dSmrg 
3391debfc3dSmrg /* Hideous macro to set the value of a field in an external ELF
3401debfc3dSmrg    structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
3411debfc3dSmrg    points to the external data.  STRUCTTYPE is the appropriate
3421debfc3dSmrg    structure type.  FIELD is a field within the struct.  TYPE is the
3431debfc3dSmrg    type of the field in the struct: Elf_Half, Elf_Word, or
3441debfc3dSmrg    Elf_Addr.  */
3451debfc3dSmrg 
3461debfc3dSmrg #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
3471debfc3dSmrg   (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
3481debfc3dSmrg 
3491debfc3dSmrg /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
3501debfc3dSmrg    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
3511debfc3dSmrg    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
3521debfc3dSmrg    the struct.  TYPE is the type of the field in the struct: Elf_Half,
3531debfc3dSmrg    Elf_Word, or Elf_Addr.  */
3541debfc3dSmrg 
3551debfc3dSmrg #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
3561debfc3dSmrg 			    TYPE, VAL)					\
3571debfc3dSmrg   ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
3581debfc3dSmrg 			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
3591debfc3dSmrg 			FIELD, BUFFER, TYPE, VAL)
3601debfc3dSmrg 
3611debfc3dSmrg /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
3621debfc3dSmrg 
3631debfc3dSmrg #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
3641debfc3dSmrg 		      TYPE, VAL)					\
3651debfc3dSmrg   ((CLASS) == ELFCLASS32						\
3661debfc3dSmrg     ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
3671debfc3dSmrg 			   TYPE, VAL)					\
3681debfc3dSmrg     : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
3691debfc3dSmrg 			   TYPE, VAL))
3701debfc3dSmrg 
3711debfc3dSmrg /* Private data for an simple_object_read.  */
3721debfc3dSmrg 
3731debfc3dSmrg struct simple_object_elf_read
3741debfc3dSmrg {
3751debfc3dSmrg   /* Type functions.  */
3761debfc3dSmrg   const struct elf_type_functions* type_functions;
3771debfc3dSmrg   /* Elf data.  */
3781debfc3dSmrg   unsigned char ei_data;
3791debfc3dSmrg   /* Elf class.  */
3801debfc3dSmrg   unsigned char ei_class;
3811debfc3dSmrg   /* ELF OS ABI.  */
3821debfc3dSmrg   unsigned char ei_osabi;
3831debfc3dSmrg   /* Elf machine number.  */
3841debfc3dSmrg   unsigned short machine;
3851debfc3dSmrg   /* Processor specific flags.  */
3861debfc3dSmrg   unsigned int flags;
3871debfc3dSmrg   /* File offset of section headers.  */
3881debfc3dSmrg   ulong_type shoff;
3891debfc3dSmrg   /* Number of sections.  */
3901debfc3dSmrg   unsigned int shnum;
3911debfc3dSmrg   /* Index of string table section header.  */
3921debfc3dSmrg   unsigned int shstrndx;
3931debfc3dSmrg };
3941debfc3dSmrg 
3951debfc3dSmrg /* Private data for an simple_object_attributes.  */
3961debfc3dSmrg 
3971debfc3dSmrg struct simple_object_elf_attributes
3981debfc3dSmrg {
3991debfc3dSmrg   /* Type functions.  */
4001debfc3dSmrg   const struct elf_type_functions* type_functions;
4011debfc3dSmrg   /* Elf data.  */
4021debfc3dSmrg   unsigned char ei_data;
4031debfc3dSmrg   /* Elf class.  */
4041debfc3dSmrg   unsigned char ei_class;
4051debfc3dSmrg   /* ELF OS ABI.  */
4061debfc3dSmrg   unsigned char ei_osabi;
4071debfc3dSmrg   /* Elf machine number.  */
4081debfc3dSmrg   unsigned short machine;
4091debfc3dSmrg   /* Processor specific flags.  */
4101debfc3dSmrg   unsigned int flags;
4111debfc3dSmrg };
4121debfc3dSmrg 
413a2dc1f3fSmrg /* Private data for an simple_object_write.  */
414a2dc1f3fSmrg 
415a2dc1f3fSmrg struct simple_object_elf_write
416a2dc1f3fSmrg {
417a2dc1f3fSmrg   struct simple_object_elf_attributes attrs;
418a2dc1f3fSmrg   unsigned char *shdrs;
419a2dc1f3fSmrg };
420a2dc1f3fSmrg 
4211debfc3dSmrg /* See if we have an ELF file.  */
4221debfc3dSmrg 
4231debfc3dSmrg 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)4241debfc3dSmrg simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
4251debfc3dSmrg 			 int descriptor, off_t offset,
4261debfc3dSmrg 			 const char *segment_name ATTRIBUTE_UNUSED,
4271debfc3dSmrg 			 const char **errmsg, int *err)
4281debfc3dSmrg {
4291debfc3dSmrg   unsigned char ei_data;
4301debfc3dSmrg   unsigned char ei_class;
4311debfc3dSmrg   const struct elf_type_functions *type_functions;
4321debfc3dSmrg   unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
4331debfc3dSmrg   struct simple_object_elf_read *eor;
4341debfc3dSmrg 
4351debfc3dSmrg   if (header[EI_MAG0] != ELFMAG0
4361debfc3dSmrg       || header[EI_MAG1] != ELFMAG1
4371debfc3dSmrg       || header[EI_MAG2] != ELFMAG2
4381debfc3dSmrg       || header[EI_MAG3] != ELFMAG3
4391debfc3dSmrg       || header[EI_VERSION] != EV_CURRENT)
4401debfc3dSmrg     {
4411debfc3dSmrg       *errmsg = NULL;
4421debfc3dSmrg       *err = 0;
4431debfc3dSmrg       return NULL;
4441debfc3dSmrg     }
4451debfc3dSmrg 
4461debfc3dSmrg   ei_data = header[EI_DATA];
4471debfc3dSmrg   if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
4481debfc3dSmrg     {
4491debfc3dSmrg       *errmsg = "unknown ELF endianness";
4501debfc3dSmrg       *err = 0;
4511debfc3dSmrg       return NULL;
4521debfc3dSmrg     }
4531debfc3dSmrg 
4541debfc3dSmrg   ei_class = header[EI_CLASS];
4551debfc3dSmrg   switch (ei_class)
4561debfc3dSmrg     {
4571debfc3dSmrg     case ELFCLASS32:
4581debfc3dSmrg       type_functions = (ei_data == ELFDATA2LSB
4591debfc3dSmrg 			? &elf_little_32_functions
4601debfc3dSmrg 			: &elf_big_32_functions);
4611debfc3dSmrg       break;
4621debfc3dSmrg 
4631debfc3dSmrg     case ELFCLASS64:
4641debfc3dSmrg #ifndef UNSIGNED_64BIT_TYPE
4651debfc3dSmrg       *errmsg = "64-bit ELF objects not supported";
4661debfc3dSmrg       *err = 0;
4671debfc3dSmrg       return NULL;
4681debfc3dSmrg #else
4691debfc3dSmrg       type_functions = (ei_data == ELFDATA2LSB
4701debfc3dSmrg 			? &elf_little_64_functions
4711debfc3dSmrg 			: &elf_big_64_functions);
4721debfc3dSmrg       break;
4731debfc3dSmrg #endif
4741debfc3dSmrg 
4751debfc3dSmrg     default:
4761debfc3dSmrg       *errmsg = "unrecognized ELF size";
4771debfc3dSmrg       *err = 0;
4781debfc3dSmrg       return NULL;
4791debfc3dSmrg     }
4801debfc3dSmrg 
4811debfc3dSmrg   if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
4821debfc3dSmrg 				    errmsg, err))
4831debfc3dSmrg     return NULL;
4841debfc3dSmrg 
4851debfc3dSmrg   eor = XNEW (struct simple_object_elf_read);
4861debfc3dSmrg   eor->type_functions = type_functions;
4871debfc3dSmrg   eor->ei_data = ei_data;
4881debfc3dSmrg   eor->ei_class = ei_class;
4891debfc3dSmrg   eor->ei_osabi = header[EI_OSABI];
4901debfc3dSmrg   eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
4911debfc3dSmrg 				  e_machine, Elf_Half);
4921debfc3dSmrg   eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
4931debfc3dSmrg 				e_flags, Elf_Word);
4941debfc3dSmrg   eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
4951debfc3dSmrg 				e_shoff, Elf_Addr);
4961debfc3dSmrg   eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
4971debfc3dSmrg 				e_shnum, Elf_Half);
4981debfc3dSmrg   eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
4991debfc3dSmrg 				   e_shstrndx, Elf_Half);
5001debfc3dSmrg 
5011debfc3dSmrg   if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
5021debfc3dSmrg       && eor->shoff != 0)
5031debfc3dSmrg     {
5041debfc3dSmrg       unsigned char shdr[sizeof (Elf64_External_Shdr)];
5051debfc3dSmrg 
5061debfc3dSmrg       /* Object file has more than 0xffff sections.  */
5071debfc3dSmrg 
5081debfc3dSmrg       if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
5091debfc3dSmrg 					(ei_class == ELFCLASS32
5101debfc3dSmrg 					 ? sizeof (Elf32_External_Shdr)
5111debfc3dSmrg 					 : sizeof (Elf64_External_Shdr)),
5121debfc3dSmrg 					errmsg, err))
5131debfc3dSmrg 	{
5141debfc3dSmrg 	  XDELETE (eor);
5151debfc3dSmrg 	  return NULL;
5161debfc3dSmrg 	}
5171debfc3dSmrg 
5181debfc3dSmrg       if (eor->shnum == 0)
5191debfc3dSmrg 	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
5201debfc3dSmrg 				      shdr, sh_size, Elf_Addr);
5211debfc3dSmrg 
5221debfc3dSmrg       if (eor->shstrndx == SHN_XINDEX)
5231debfc3dSmrg 	{
5241debfc3dSmrg 	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
5251debfc3dSmrg 					   shdr, sh_link, Elf_Word);
5261debfc3dSmrg 
5271debfc3dSmrg 	  /* Versions of the GNU binutils between 2.12 and 2.18 did
5281debfc3dSmrg 	     not handle objects with more than SHN_LORESERVE sections
5291debfc3dSmrg 	     correctly.  All large section indexes were offset by
5301debfc3dSmrg 	     0x100.  There is more information at
531*8feb0f0bSmrg 	     https://sourceware.org/PR5900 .
5321debfc3dSmrg 	     Fortunately these object files are easy to detect, as the
5331debfc3dSmrg 	     GNU binutils always put the section header string table
5341debfc3dSmrg 	     near the end of the list of sections.  Thus if the
5351debfc3dSmrg 	     section header string table index is larger than the
5361debfc3dSmrg 	     number of sections, then we know we have to subtract
5371debfc3dSmrg 	     0x100 to get the real section index.  */
5381debfc3dSmrg 	  if (eor->shstrndx >= eor->shnum
5391debfc3dSmrg 	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
5401debfc3dSmrg 	    eor->shstrndx -= 0x100;
5411debfc3dSmrg 	}
5421debfc3dSmrg     }
5431debfc3dSmrg 
5441debfc3dSmrg   if (eor->shstrndx >= eor->shnum)
5451debfc3dSmrg     {
5461debfc3dSmrg       *errmsg = "invalid ELF shstrndx >= shnum";
5471debfc3dSmrg       *err = 0;
5481debfc3dSmrg       XDELETE (eor);
5491debfc3dSmrg       return NULL;
5501debfc3dSmrg     }
5511debfc3dSmrg 
552a2dc1f3fSmrg   if (eor->shstrndx == 0)
553a2dc1f3fSmrg     {
554a2dc1f3fSmrg       *errmsg = "invalid ELF shstrndx == 0";
555a2dc1f3fSmrg       *err = 0;
556a2dc1f3fSmrg       XDELETE (eor);
557a2dc1f3fSmrg       return NULL;
558a2dc1f3fSmrg     }
559a2dc1f3fSmrg 
5601debfc3dSmrg   return (void *) eor;
5611debfc3dSmrg }
5621debfc3dSmrg 
5631debfc3dSmrg /* Find all sections in an ELF file.  */
5641debfc3dSmrg 
5651debfc3dSmrg 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)5661debfc3dSmrg simple_object_elf_find_sections (simple_object_read *sobj,
5671debfc3dSmrg 				 int (*pfn) (void *, const char *,
5681debfc3dSmrg 					     off_t offset, off_t length),
5691debfc3dSmrg 				 void *data,
5701debfc3dSmrg 				 int *err)
5711debfc3dSmrg {
5721debfc3dSmrg   struct simple_object_elf_read *eor =
5731debfc3dSmrg     (struct simple_object_elf_read *) sobj->data;
5741debfc3dSmrg   const struct elf_type_functions *type_functions = eor->type_functions;
5751debfc3dSmrg   unsigned char ei_class = eor->ei_class;
5761debfc3dSmrg   size_t shdr_size;
5771debfc3dSmrg   unsigned int shnum;
5781debfc3dSmrg   unsigned char *shdrs;
5791debfc3dSmrg   const char *errmsg;
5801debfc3dSmrg   unsigned char *shstrhdr;
5811debfc3dSmrg   size_t name_size;
5821debfc3dSmrg   off_t shstroff;
5831debfc3dSmrg   unsigned char *names;
5841debfc3dSmrg   unsigned int i;
5851debfc3dSmrg 
5861debfc3dSmrg   shdr_size = (ei_class == ELFCLASS32
5871debfc3dSmrg 	       ? sizeof (Elf32_External_Shdr)
5881debfc3dSmrg 	       : sizeof (Elf64_External_Shdr));
5891debfc3dSmrg 
5901debfc3dSmrg   /* Read the section headers.  We skip section 0, which is not a
5911debfc3dSmrg      useful section.  */
5921debfc3dSmrg 
5931debfc3dSmrg   shnum = eor->shnum;
5941debfc3dSmrg   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
5951debfc3dSmrg 
5961debfc3dSmrg   if (!simple_object_internal_read (sobj->descriptor,
5971debfc3dSmrg 				    sobj->offset + eor->shoff + shdr_size,
5981debfc3dSmrg 				    shdrs,
5991debfc3dSmrg 				    shdr_size * (shnum - 1),
6001debfc3dSmrg 				    &errmsg, err))
6011debfc3dSmrg     {
6021debfc3dSmrg       XDELETEVEC (shdrs);
6031debfc3dSmrg       return errmsg;
6041debfc3dSmrg     }
6051debfc3dSmrg 
6061debfc3dSmrg   /* Read the section names.  */
6071debfc3dSmrg 
6081debfc3dSmrg   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
6091debfc3dSmrg   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
6101debfc3dSmrg 			       shstrhdr, sh_size, Elf_Addr);
6111debfc3dSmrg   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
6121debfc3dSmrg 			      shstrhdr, sh_offset, Elf_Addr);
6131debfc3dSmrg   names = XNEWVEC (unsigned char, name_size);
6141debfc3dSmrg   if (!simple_object_internal_read (sobj->descriptor,
6151debfc3dSmrg 				    sobj->offset + shstroff,
6161debfc3dSmrg 				    names, name_size, &errmsg, err))
6171debfc3dSmrg     {
6181debfc3dSmrg       XDELETEVEC (names);
6191debfc3dSmrg       XDELETEVEC (shdrs);
6201debfc3dSmrg       return errmsg;
6211debfc3dSmrg     }
6221debfc3dSmrg 
6231debfc3dSmrg   for (i = 1; i < shnum; ++i)
6241debfc3dSmrg     {
6251debfc3dSmrg       unsigned char *shdr;
6261debfc3dSmrg       unsigned int sh_name;
6271debfc3dSmrg       const char *name;
6281debfc3dSmrg       off_t offset;
6291debfc3dSmrg       off_t length;
6301debfc3dSmrg 
6311debfc3dSmrg       shdr = shdrs + (i - 1) * shdr_size;
6321debfc3dSmrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
6331debfc3dSmrg 				 shdr, sh_name, Elf_Word);
6341debfc3dSmrg       if (sh_name >= name_size)
6351debfc3dSmrg 	{
6361debfc3dSmrg 	  *err = 0;
6371debfc3dSmrg 	  XDELETEVEC (names);
6381debfc3dSmrg 	  XDELETEVEC (shdrs);
6391debfc3dSmrg 	  return "ELF section name out of range";
6401debfc3dSmrg 	}
6411debfc3dSmrg 
6421debfc3dSmrg       name = (const char *) names + sh_name;
6431debfc3dSmrg       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
6441debfc3dSmrg 				shdr, sh_offset, Elf_Addr);
6451debfc3dSmrg       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
6461debfc3dSmrg 				shdr, sh_size, Elf_Addr);
6471debfc3dSmrg 
6481debfc3dSmrg       if (!(*pfn) (data, name, offset, length))
6491debfc3dSmrg 	break;
6501debfc3dSmrg     }
6511debfc3dSmrg 
6521debfc3dSmrg   XDELETEVEC (names);
6531debfc3dSmrg   XDELETEVEC (shdrs);
6541debfc3dSmrg 
6551debfc3dSmrg   return NULL;
6561debfc3dSmrg }
6571debfc3dSmrg 
6581debfc3dSmrg /* Fetch the attributes for an simple_object_read.  */
6591debfc3dSmrg 
6601debfc3dSmrg static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)6611debfc3dSmrg simple_object_elf_fetch_attributes (simple_object_read *sobj,
6621debfc3dSmrg 				    const char **errmsg ATTRIBUTE_UNUSED,
6631debfc3dSmrg 				    int *err ATTRIBUTE_UNUSED)
6641debfc3dSmrg {
6651debfc3dSmrg   struct simple_object_elf_read *eor =
6661debfc3dSmrg     (struct simple_object_elf_read *) sobj->data;
6671debfc3dSmrg   struct simple_object_elf_attributes *ret;
6681debfc3dSmrg 
6691debfc3dSmrg   ret = XNEW (struct simple_object_elf_attributes);
6701debfc3dSmrg   ret->type_functions = eor->type_functions;
6711debfc3dSmrg   ret->ei_data = eor->ei_data;
6721debfc3dSmrg   ret->ei_class = eor->ei_class;
6731debfc3dSmrg   ret->ei_osabi = eor->ei_osabi;
6741debfc3dSmrg   ret->machine = eor->machine;
6751debfc3dSmrg   ret->flags = eor->flags;
6761debfc3dSmrg   return ret;
6771debfc3dSmrg }
6781debfc3dSmrg 
6791debfc3dSmrg /* Release the privata data for an simple_object_read.  */
6801debfc3dSmrg 
6811debfc3dSmrg static void
simple_object_elf_release_read(void * data)6821debfc3dSmrg simple_object_elf_release_read (void *data)
6831debfc3dSmrg {
6841debfc3dSmrg   XDELETE (data);
6851debfc3dSmrg }
6861debfc3dSmrg 
6871debfc3dSmrg /* Compare two attributes structures.  */
6881debfc3dSmrg 
6891debfc3dSmrg static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)6901debfc3dSmrg simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
6911debfc3dSmrg {
6921debfc3dSmrg   struct simple_object_elf_attributes *to =
6931debfc3dSmrg     (struct simple_object_elf_attributes *) todata;
6941debfc3dSmrg   struct simple_object_elf_attributes *from =
6951debfc3dSmrg     (struct simple_object_elf_attributes *) fromdata;
6961debfc3dSmrg 
6971debfc3dSmrg   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
6981debfc3dSmrg     {
6991debfc3dSmrg       *err = 0;
7001debfc3dSmrg       return "ELF object format mismatch";
7011debfc3dSmrg     }
7021debfc3dSmrg 
7031debfc3dSmrg   if (to->machine != from->machine)
7041debfc3dSmrg     {
7051debfc3dSmrg       int ok;
7061debfc3dSmrg 
7071debfc3dSmrg       /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
7081debfc3dSmrg 	 output of EM_SPARC32PLUS.  */
7091debfc3dSmrg       ok = 0;
7101debfc3dSmrg       switch (to->machine)
7111debfc3dSmrg 	{
7121debfc3dSmrg 	case EM_SPARC:
7131debfc3dSmrg 	  if (from->machine == EM_SPARC32PLUS)
7141debfc3dSmrg 	    {
7151debfc3dSmrg 	      to->machine = from->machine;
7161debfc3dSmrg 	      ok = 1;
7171debfc3dSmrg 	    }
7181debfc3dSmrg 	  break;
7191debfc3dSmrg 
7201debfc3dSmrg 	case EM_SPARC32PLUS:
7211debfc3dSmrg 	  if (from->machine == EM_SPARC)
7221debfc3dSmrg 	    ok = 1;
7231debfc3dSmrg 	  break;
7241debfc3dSmrg 
7251debfc3dSmrg 	default:
7261debfc3dSmrg 	  break;
7271debfc3dSmrg 	}
7281debfc3dSmrg 
7291debfc3dSmrg       if (!ok)
7301debfc3dSmrg 	{
7311debfc3dSmrg 	  *err = 0;
7321debfc3dSmrg 	  return "ELF machine number mismatch";
7331debfc3dSmrg 	}
7341debfc3dSmrg     }
7351debfc3dSmrg 
7361debfc3dSmrg   return NULL;
7371debfc3dSmrg }
7381debfc3dSmrg 
7391debfc3dSmrg /* Release the private data for an attributes structure.  */
7401debfc3dSmrg 
7411debfc3dSmrg static void
simple_object_elf_release_attributes(void * data)7421debfc3dSmrg simple_object_elf_release_attributes (void *data)
7431debfc3dSmrg {
7441debfc3dSmrg   XDELETE (data);
7451debfc3dSmrg }
7461debfc3dSmrg 
7471debfc3dSmrg /* Prepare to write out a file.  */
7481debfc3dSmrg 
7491debfc3dSmrg static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)7501debfc3dSmrg simple_object_elf_start_write (void *attributes_data,
7511debfc3dSmrg 			       const char **errmsg ATTRIBUTE_UNUSED,
7521debfc3dSmrg 			       int *err ATTRIBUTE_UNUSED)
7531debfc3dSmrg {
7541debfc3dSmrg   struct simple_object_elf_attributes *attrs =
7551debfc3dSmrg     (struct simple_object_elf_attributes *) attributes_data;
756a2dc1f3fSmrg   struct simple_object_elf_write *ret;
7571debfc3dSmrg 
7581debfc3dSmrg   /* We're just going to record the attributes, but we need to make a
7591debfc3dSmrg      copy because the user may delete them.  */
760a2dc1f3fSmrg   ret = XNEW (struct simple_object_elf_write);
761a2dc1f3fSmrg   ret->attrs = *attrs;
762a2dc1f3fSmrg   ret->shdrs = NULL;
7631debfc3dSmrg   return ret;
7641debfc3dSmrg }
7651debfc3dSmrg 
7661debfc3dSmrg /* Write out an ELF ehdr.  */
7671debfc3dSmrg 
7681debfc3dSmrg static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)7691debfc3dSmrg simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
7701debfc3dSmrg 			      const char **errmsg, int *err)
7711debfc3dSmrg {
7721debfc3dSmrg   struct simple_object_elf_attributes *attrs =
7731debfc3dSmrg     (struct simple_object_elf_attributes *) sobj->data;
7741debfc3dSmrg   const struct elf_type_functions* fns;
7751debfc3dSmrg   unsigned char cl;
7761debfc3dSmrg   size_t ehdr_size;
7771debfc3dSmrg   unsigned char buf[sizeof (Elf64_External_Ehdr)];
7781debfc3dSmrg   simple_object_write_section *section;
7791debfc3dSmrg   unsigned int shnum;
7801debfc3dSmrg   unsigned int shstrndx;
7811debfc3dSmrg 
7821debfc3dSmrg   fns = attrs->type_functions;
7831debfc3dSmrg   cl = attrs->ei_class;
7841debfc3dSmrg 
7851debfc3dSmrg   shnum = 0;
7861debfc3dSmrg   for (section = sobj->sections; section != NULL; section = section->next)
7871debfc3dSmrg     ++shnum;
7881debfc3dSmrg   if (shnum > 0)
7891debfc3dSmrg     {
7901debfc3dSmrg       /* Add a section header for the dummy section and one for
7911debfc3dSmrg 	 .shstrtab.  */
7921debfc3dSmrg       shnum += 2;
7931debfc3dSmrg     }
7941debfc3dSmrg 
7951debfc3dSmrg   ehdr_size = (cl == ELFCLASS32
7961debfc3dSmrg 	       ? sizeof (Elf32_External_Ehdr)
7971debfc3dSmrg 	       : sizeof (Elf64_External_Ehdr));
7981debfc3dSmrg   memset (buf, 0, sizeof (Elf64_External_Ehdr));
7991debfc3dSmrg 
8001debfc3dSmrg   buf[EI_MAG0] = ELFMAG0;
8011debfc3dSmrg   buf[EI_MAG1] = ELFMAG1;
8021debfc3dSmrg   buf[EI_MAG2] = ELFMAG2;
8031debfc3dSmrg   buf[EI_MAG3] = ELFMAG3;
8041debfc3dSmrg   buf[EI_CLASS] = cl;
8051debfc3dSmrg   buf[EI_DATA] = attrs->ei_data;
8061debfc3dSmrg   buf[EI_VERSION] = EV_CURRENT;
8071debfc3dSmrg   buf[EI_OSABI] = attrs->ei_osabi;
8081debfc3dSmrg 
8091debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
8101debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
8111debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
8121debfc3dSmrg   /* e_entry left as zero.  */
8131debfc3dSmrg   /* e_phoff left as zero.  */
8141debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
8151debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
8161debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
8171debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
8181debfc3dSmrg 		 (cl == ELFCLASS32
8191debfc3dSmrg 		  ? sizeof (Elf32_External_Phdr)
8201debfc3dSmrg 		  : sizeof (Elf64_External_Phdr)));
8211debfc3dSmrg   /* e_phnum left as zero.  */
8221debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
8231debfc3dSmrg 		 (cl == ELFCLASS32
8241debfc3dSmrg 		  ? sizeof (Elf32_External_Shdr)
8251debfc3dSmrg 		  : sizeof (Elf64_External_Shdr)));
8261debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
8271debfc3dSmrg 		 shnum >= SHN_LORESERVE ? 0 : shnum);
8281debfc3dSmrg   if (shnum == 0)
8291debfc3dSmrg     shstrndx = 0;
8301debfc3dSmrg   else
8311debfc3dSmrg     {
8321debfc3dSmrg       shstrndx = shnum - 1;
8331debfc3dSmrg       if (shstrndx >= SHN_LORESERVE)
8341debfc3dSmrg 	shstrndx = SHN_XINDEX;
8351debfc3dSmrg     }
8361debfc3dSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
8371debfc3dSmrg 
8381debfc3dSmrg   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
8391debfc3dSmrg 				       errmsg, err);
8401debfc3dSmrg }
8411debfc3dSmrg 
8421debfc3dSmrg /* Write out an ELF shdr.  */
8431debfc3dSmrg 
8441debfc3dSmrg 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)8451debfc3dSmrg simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
8461debfc3dSmrg 			      off_t offset, unsigned int sh_name,
8471debfc3dSmrg 			      unsigned int sh_type, unsigned int sh_flags,
848a2dc1f3fSmrg 			      off_t sh_addr,
8491debfc3dSmrg 			      unsigned int sh_offset, unsigned int sh_size,
850a2dc1f3fSmrg 			      unsigned int sh_link, unsigned int sh_info,
851a2dc1f3fSmrg 			      size_t sh_addralign,
852a2dc1f3fSmrg 			      size_t sh_entsize,
8531debfc3dSmrg 			      const char **errmsg, int *err)
8541debfc3dSmrg {
8551debfc3dSmrg   struct simple_object_elf_attributes *attrs =
8561debfc3dSmrg     (struct simple_object_elf_attributes *) sobj->data;
8571debfc3dSmrg   const struct elf_type_functions* fns;
8581debfc3dSmrg   unsigned char cl;
8591debfc3dSmrg   size_t shdr_size;
8601debfc3dSmrg   unsigned char buf[sizeof (Elf64_External_Shdr)];
8611debfc3dSmrg 
8621debfc3dSmrg   fns = attrs->type_functions;
8631debfc3dSmrg   cl = attrs->ei_class;
8641debfc3dSmrg 
8651debfc3dSmrg   shdr_size = (cl == ELFCLASS32
8661debfc3dSmrg 	       ? sizeof (Elf32_External_Shdr)
8671debfc3dSmrg 	       : sizeof (Elf64_External_Shdr));
8681debfc3dSmrg   memset (buf, 0, sizeof (Elf64_External_Shdr));
8691debfc3dSmrg 
8701debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
8711debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
8721debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
873a2dc1f3fSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
8741debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
8751debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
8761debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
877a2dc1f3fSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
8781debfc3dSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
879a2dc1f3fSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize);
8801debfc3dSmrg 
8811debfc3dSmrg   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
8821debfc3dSmrg 				       errmsg, err);
8831debfc3dSmrg }
8841debfc3dSmrg 
8851debfc3dSmrg /* Write out a complete ELF file.
8861debfc3dSmrg    Ehdr
8871debfc3dSmrg    initial dummy Shdr
8881debfc3dSmrg    user-created Shdrs
8891debfc3dSmrg    .shstrtab Shdr
8901debfc3dSmrg    user-created section data
8911debfc3dSmrg    .shstrtab data  */
8921debfc3dSmrg 
8931debfc3dSmrg static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)8941debfc3dSmrg simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
8951debfc3dSmrg 				 int *err)
8961debfc3dSmrg {
897a2dc1f3fSmrg   struct simple_object_elf_write *eow =
898a2dc1f3fSmrg     (struct simple_object_elf_write *) sobj->data;
899a2dc1f3fSmrg   struct simple_object_elf_attributes *attrs = &eow->attrs;
9001debfc3dSmrg   unsigned char cl;
9011debfc3dSmrg   size_t ehdr_size;
9021debfc3dSmrg   size_t shdr_size;
9031debfc3dSmrg   const char *errmsg;
9041debfc3dSmrg   simple_object_write_section *section;
9051debfc3dSmrg   unsigned int shnum;
9061debfc3dSmrg   size_t shdr_offset;
9071debfc3dSmrg   size_t sh_offset;
9081debfc3dSmrg   unsigned int first_sh_size;
9091debfc3dSmrg   unsigned int first_sh_link;
9101debfc3dSmrg   size_t sh_name;
9111debfc3dSmrg   unsigned char zero;
912a2dc1f3fSmrg   unsigned secnum;
9131debfc3dSmrg 
9141debfc3dSmrg   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
9151debfc3dSmrg     return errmsg;
9161debfc3dSmrg 
9171debfc3dSmrg   cl = attrs->ei_class;
9181debfc3dSmrg   if (cl == ELFCLASS32)
9191debfc3dSmrg     {
9201debfc3dSmrg       ehdr_size = sizeof (Elf32_External_Ehdr);
9211debfc3dSmrg       shdr_size = sizeof (Elf32_External_Shdr);
9221debfc3dSmrg     }
9231debfc3dSmrg   else
9241debfc3dSmrg     {
9251debfc3dSmrg       ehdr_size = sizeof (Elf64_External_Ehdr);
9261debfc3dSmrg       shdr_size = sizeof (Elf64_External_Shdr);
9271debfc3dSmrg     }
9281debfc3dSmrg 
9291debfc3dSmrg   shnum = 0;
9301debfc3dSmrg   for (section = sobj->sections; section != NULL; section = section->next)
9311debfc3dSmrg     ++shnum;
9321debfc3dSmrg   if (shnum == 0)
9331debfc3dSmrg     return NULL;
9341debfc3dSmrg 
9351debfc3dSmrg   /* Add initial dummy Shdr and .shstrtab.  */
9361debfc3dSmrg   shnum += 2;
9371debfc3dSmrg 
9381debfc3dSmrg   shdr_offset = ehdr_size;
9391debfc3dSmrg   sh_offset = shdr_offset + shnum * shdr_size;
9401debfc3dSmrg 
9411debfc3dSmrg   if (shnum < SHN_LORESERVE)
9421debfc3dSmrg     first_sh_size = 0;
9431debfc3dSmrg   else
9441debfc3dSmrg     first_sh_size = shnum;
9451debfc3dSmrg   if (shnum - 1 < SHN_LORESERVE)
9461debfc3dSmrg     first_sh_link = 0;
9471debfc3dSmrg   else
9481debfc3dSmrg     first_sh_link = shnum - 1;
9491debfc3dSmrg   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
950a2dc1f3fSmrg 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
951a2dc1f3fSmrg 				     0, 0, 0, &errmsg, err))
9521debfc3dSmrg     return errmsg;
9531debfc3dSmrg 
9541debfc3dSmrg   shdr_offset += shdr_size;
9551debfc3dSmrg 
9561debfc3dSmrg   sh_name = 1;
957a2dc1f3fSmrg   secnum = 0;
9581debfc3dSmrg   for (section = sobj->sections; section != NULL; section = section->next)
9591debfc3dSmrg     {
9601debfc3dSmrg       size_t mask;
9611debfc3dSmrg       size_t new_sh_offset;
9621debfc3dSmrg       size_t sh_size;
9631debfc3dSmrg       struct simple_object_write_section_buffer *buffer;
964a2dc1f3fSmrg       unsigned int sh_type = SHT_PROGBITS;
965a2dc1f3fSmrg       unsigned int sh_flags = 0;
966a2dc1f3fSmrg       off_t sh_addr = 0;
967a2dc1f3fSmrg       unsigned int sh_link = 0;
968a2dc1f3fSmrg       unsigned int sh_info = 0;
969a2dc1f3fSmrg       size_t sh_addralign = 1U << section->align;
970a2dc1f3fSmrg       size_t sh_entsize = 0;
971a2dc1f3fSmrg       if (eow->shdrs)
972a2dc1f3fSmrg 	{
973a2dc1f3fSmrg 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
974a2dc1f3fSmrg 				     eow->shdrs + secnum * shdr_size,
975a2dc1f3fSmrg 				     sh_type, Elf_Word);
976a2dc1f3fSmrg 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
977a2dc1f3fSmrg 				      eow->shdrs + secnum * shdr_size,
978a2dc1f3fSmrg 				      sh_flags, Elf_Addr);
979a2dc1f3fSmrg 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
980a2dc1f3fSmrg 				     eow->shdrs + secnum * shdr_size,
981a2dc1f3fSmrg 				     sh_addr, Elf_Addr);
982a2dc1f3fSmrg 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
983a2dc1f3fSmrg 				     eow->shdrs + secnum * shdr_size,
984a2dc1f3fSmrg 				     sh_link, Elf_Word);
985a2dc1f3fSmrg 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
986a2dc1f3fSmrg 				     eow->shdrs + secnum * shdr_size,
987a2dc1f3fSmrg 				     sh_info, Elf_Word);
988a2dc1f3fSmrg 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
989a2dc1f3fSmrg 					  eow->shdrs + secnum * shdr_size,
990a2dc1f3fSmrg 					  sh_addralign, Elf_Addr);
991a2dc1f3fSmrg 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
992a2dc1f3fSmrg 					eow->shdrs + secnum * shdr_size,
993a2dc1f3fSmrg 					sh_entsize, Elf_Addr);
994a2dc1f3fSmrg 	  secnum++;
995a2dc1f3fSmrg 	}
9961debfc3dSmrg 
997a2dc1f3fSmrg       mask = sh_addralign - 1;
9981debfc3dSmrg       new_sh_offset = sh_offset + mask;
9991debfc3dSmrg       new_sh_offset &= ~ mask;
10001debfc3dSmrg       while (new_sh_offset > sh_offset)
10011debfc3dSmrg 	{
10021debfc3dSmrg 	  unsigned char zeroes[16];
10031debfc3dSmrg 	  size_t write;
10041debfc3dSmrg 
10051debfc3dSmrg 	  memset (zeroes, 0, sizeof zeroes);
10061debfc3dSmrg 	  write = new_sh_offset - sh_offset;
10071debfc3dSmrg 	  if (write > sizeof zeroes)
10081debfc3dSmrg 	    write = sizeof zeroes;
10091debfc3dSmrg 	  if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
10101debfc3dSmrg 					     write, &errmsg, err))
10111debfc3dSmrg 	    return errmsg;
10121debfc3dSmrg 	  sh_offset += write;
10131debfc3dSmrg 	}
10141debfc3dSmrg 
10151debfc3dSmrg       sh_size = 0;
10161debfc3dSmrg       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
10171debfc3dSmrg 	{
10181debfc3dSmrg 	  if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
10191debfc3dSmrg 					     ((const unsigned char *)
10201debfc3dSmrg 					      buffer->buffer),
10211debfc3dSmrg 					     buffer->size, &errmsg, err))
10221debfc3dSmrg 	    return errmsg;
10231debfc3dSmrg 	  sh_size += buffer->size;
10241debfc3dSmrg 	}
10251debfc3dSmrg 
10261debfc3dSmrg       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1027a2dc1f3fSmrg 					 sh_name, sh_type, sh_flags,
1028a2dc1f3fSmrg 					 sh_addr, sh_offset,
1029a2dc1f3fSmrg 					 sh_size, sh_link, sh_info,
1030a2dc1f3fSmrg 					 sh_addralign, sh_entsize,
10311debfc3dSmrg 					 &errmsg, err))
10321debfc3dSmrg 	return errmsg;
10331debfc3dSmrg 
10341debfc3dSmrg       shdr_offset += shdr_size;
10351debfc3dSmrg       sh_name += strlen (section->name) + 1;
10361debfc3dSmrg       sh_offset += sh_size;
10371debfc3dSmrg     }
10381debfc3dSmrg 
10391debfc3dSmrg   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1040a2dc1f3fSmrg 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
1041a2dc1f3fSmrg 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
1042a2dc1f3fSmrg 				     1, 0, &errmsg, err))
10431debfc3dSmrg     return errmsg;
10441debfc3dSmrg 
10451debfc3dSmrg   /* .shstrtab has a leading zero byte.  */
10461debfc3dSmrg   zero = 0;
10471debfc3dSmrg   if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
10481debfc3dSmrg 				     &errmsg, err))
10491debfc3dSmrg     return errmsg;
10501debfc3dSmrg   ++sh_offset;
10511debfc3dSmrg 
10521debfc3dSmrg   for (section = sobj->sections; section != NULL; section = section->next)
10531debfc3dSmrg     {
10541debfc3dSmrg       size_t len;
10551debfc3dSmrg 
10561debfc3dSmrg       len = strlen (section->name) + 1;
10571debfc3dSmrg       if (!simple_object_internal_write (descriptor, sh_offset,
10581debfc3dSmrg 					 (const unsigned char *) section->name,
10591debfc3dSmrg 					 len, &errmsg, err))
10601debfc3dSmrg 	return errmsg;
10611debfc3dSmrg       sh_offset += len;
10621debfc3dSmrg     }
10631debfc3dSmrg 
10641debfc3dSmrg   if (!simple_object_internal_write (descriptor, sh_offset,
10651debfc3dSmrg 				     (const unsigned char *) ".shstrtab",
10661debfc3dSmrg 				     strlen (".shstrtab") + 1, &errmsg, err))
10671debfc3dSmrg     return errmsg;
10681debfc3dSmrg 
10691debfc3dSmrg   return NULL;
10701debfc3dSmrg }
10711debfc3dSmrg 
10721debfc3dSmrg /* Release the private data for an simple_object_write structure.  */
10731debfc3dSmrg 
10741debfc3dSmrg static void
simple_object_elf_release_write(void * data)10751debfc3dSmrg simple_object_elf_release_write (void *data)
10761debfc3dSmrg {
1077a2dc1f3fSmrg   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
1078a2dc1f3fSmrg   if (eow->shdrs)
1079a2dc1f3fSmrg     XDELETE (eow->shdrs);
10801debfc3dSmrg   XDELETE (data);
10811debfc3dSmrg }
10821debfc3dSmrg 
1083a2dc1f3fSmrg /* Copy all sections in an ELF file.  */
1084a2dc1f3fSmrg 
1085a2dc1f3fSmrg static const char *
simple_object_elf_copy_lto_debug_sections(simple_object_read * sobj,simple_object_write * dobj,char * (* pfn)(const char *),int * err)1086a2dc1f3fSmrg simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
1087a2dc1f3fSmrg 					   simple_object_write *dobj,
1088a2dc1f3fSmrg 					   char *(*pfn) (const char *),
1089a2dc1f3fSmrg 					   int *err)
1090a2dc1f3fSmrg {
1091a2dc1f3fSmrg   struct simple_object_elf_read *eor =
1092a2dc1f3fSmrg     (struct simple_object_elf_read *) sobj->data;
1093a2dc1f3fSmrg   const struct elf_type_functions *type_functions = eor->type_functions;
1094a2dc1f3fSmrg   struct simple_object_elf_write *eow =
1095a2dc1f3fSmrg     (struct simple_object_elf_write *) dobj->data;
1096a2dc1f3fSmrg   unsigned char ei_class = eor->ei_class;
1097a2dc1f3fSmrg   size_t shdr_size;
1098a2dc1f3fSmrg   unsigned int shnum;
1099a2dc1f3fSmrg   unsigned char *shdrs;
1100a2dc1f3fSmrg   const char *errmsg;
1101a2dc1f3fSmrg   unsigned char *shstrhdr;
1102a2dc1f3fSmrg   size_t name_size;
1103a2dc1f3fSmrg   off_t shstroff;
1104a2dc1f3fSmrg   unsigned char *names;
1105a2dc1f3fSmrg   unsigned int i;
1106a2dc1f3fSmrg   int changed;
1107a2dc1f3fSmrg   int *pfnret;
1108a2dc1f3fSmrg   const char **pfnname;
1109a2dc1f3fSmrg   unsigned new_i;
1110a2dc1f3fSmrg   unsigned *sh_map;
1111a2dc1f3fSmrg   unsigned first_shndx = 0;
1112a2dc1f3fSmrg   unsigned int *symtab_indices_shndx;
1113a2dc1f3fSmrg 
1114a2dc1f3fSmrg   shdr_size = (ei_class == ELFCLASS32
1115a2dc1f3fSmrg 	       ? sizeof (Elf32_External_Shdr)
1116a2dc1f3fSmrg 	       : sizeof (Elf64_External_Shdr));
1117a2dc1f3fSmrg 
1118a2dc1f3fSmrg   /* Read the section headers.  We skip section 0, which is not a
1119a2dc1f3fSmrg      useful section.  */
1120a2dc1f3fSmrg 
1121a2dc1f3fSmrg   shnum = eor->shnum;
1122a2dc1f3fSmrg   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
1123a2dc1f3fSmrg 
1124a2dc1f3fSmrg   if (!simple_object_internal_read (sobj->descriptor,
1125a2dc1f3fSmrg 				    sobj->offset + eor->shoff + shdr_size,
1126a2dc1f3fSmrg 				    shdrs,
1127a2dc1f3fSmrg 				    shdr_size * (shnum - 1),
1128a2dc1f3fSmrg 				    &errmsg, err))
1129a2dc1f3fSmrg     {
1130a2dc1f3fSmrg       XDELETEVEC (shdrs);
1131a2dc1f3fSmrg       return errmsg;
1132a2dc1f3fSmrg     }
1133a2dc1f3fSmrg 
1134a2dc1f3fSmrg   /* Read the section names.  */
1135a2dc1f3fSmrg 
1136a2dc1f3fSmrg   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
1137a2dc1f3fSmrg   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1138a2dc1f3fSmrg 			       shstrhdr, sh_size, Elf_Addr);
1139a2dc1f3fSmrg   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1140a2dc1f3fSmrg 			      shstrhdr, sh_offset, Elf_Addr);
1141a2dc1f3fSmrg   names = XNEWVEC (unsigned char, name_size);
1142a2dc1f3fSmrg   if (!simple_object_internal_read (sobj->descriptor,
1143a2dc1f3fSmrg 				    sobj->offset + shstroff,
1144a2dc1f3fSmrg 				    names, name_size, &errmsg, err))
1145a2dc1f3fSmrg     {
1146a2dc1f3fSmrg       XDELETEVEC (names);
1147a2dc1f3fSmrg       XDELETEVEC (shdrs);
1148a2dc1f3fSmrg       return errmsg;
1149a2dc1f3fSmrg     }
1150a2dc1f3fSmrg 
1151a2dc1f3fSmrg   pfnret = XNEWVEC (int, shnum);
1152a2dc1f3fSmrg   pfnname = XNEWVEC (const char *, shnum);
1153a2dc1f3fSmrg 
1154a2dc1f3fSmrg   /* Map of symtab to index section.  */
1155a2dc1f3fSmrg   symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1);
1156a2dc1f3fSmrg 
1157a2dc1f3fSmrg   /* First perform the callbacks to know which sections to preserve and
1158a2dc1f3fSmrg      what name to use for those.  */
1159a2dc1f3fSmrg   for (i = 1; i < shnum; ++i)
1160a2dc1f3fSmrg     {
1161a2dc1f3fSmrg       unsigned char *shdr;
1162a2dc1f3fSmrg       unsigned int sh_name, sh_type;
1163a2dc1f3fSmrg       const char *name;
1164a2dc1f3fSmrg       char *ret;
1165a2dc1f3fSmrg 
1166a2dc1f3fSmrg       shdr = shdrs + (i - 1) * shdr_size;
1167a2dc1f3fSmrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1168a2dc1f3fSmrg 				 shdr, sh_name, Elf_Word);
1169a2dc1f3fSmrg       if (sh_name >= name_size)
1170a2dc1f3fSmrg 	{
1171a2dc1f3fSmrg 	  *err = 0;
1172a2dc1f3fSmrg 	  XDELETEVEC (names);
1173a2dc1f3fSmrg 	  XDELETEVEC (shdrs);
1174a2dc1f3fSmrg 	  return "ELF section name out of range";
1175a2dc1f3fSmrg 	}
1176a2dc1f3fSmrg 
1177a2dc1f3fSmrg       name = (const char *) names + sh_name;
1178a2dc1f3fSmrg 
1179a2dc1f3fSmrg       ret = (*pfn) (name);
1180a2dc1f3fSmrg       pfnret[i - 1] = ret == NULL ? -1 : 0;
1181a2dc1f3fSmrg       pfnname[i - 1] = ret == NULL ? name : ret;
1182a2dc1f3fSmrg       if (first_shndx == 0
1183a2dc1f3fSmrg 	  && pfnret[i - 1] == 0)
1184a2dc1f3fSmrg 	first_shndx = i;
1185a2dc1f3fSmrg 
1186a2dc1f3fSmrg       /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections.  */
1187a2dc1f3fSmrg       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1188a2dc1f3fSmrg 				 shdr, sh_type, Elf_Word);
1189a2dc1f3fSmrg       if (sh_type == SHT_SYMTAB_SHNDX)
1190a2dc1f3fSmrg 	{
1191a2dc1f3fSmrg 	  unsigned int sh_link;
1192a2dc1f3fSmrg 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1193a2dc1f3fSmrg 				     shdr, sh_link, Elf_Word);
1194*8feb0f0bSmrg 	  symtab_indices_shndx[sh_link - 1] = i - 1;
1195a2dc1f3fSmrg 	  /* Always discard the extended index sections, after
1196a2dc1f3fSmrg 	     copying it will not be needed.  This way we don't need to
1197a2dc1f3fSmrg 	     update it and deal with the ordering constraints of
1198a2dc1f3fSmrg 	     processing the existing symtab and changing the index.  */
1199a2dc1f3fSmrg 	  pfnret[i - 1] = -1;
1200a2dc1f3fSmrg 	}
1201a2dc1f3fSmrg     }
1202a2dc1f3fSmrg 
1203a2dc1f3fSmrg   /* Mark sections as preserved that are required by to be preserved
1204a2dc1f3fSmrg      sections.  */
1205a2dc1f3fSmrg   do
1206a2dc1f3fSmrg     {
1207a2dc1f3fSmrg       changed = 0;
1208a2dc1f3fSmrg       for (i = 1; i < shnum; ++i)
1209a2dc1f3fSmrg 	{
1210a2dc1f3fSmrg 	  unsigned char *shdr;
1211a2dc1f3fSmrg 	  unsigned int sh_type, sh_info, sh_link;
1212a2dc1f3fSmrg 	  off_t offset;
1213a2dc1f3fSmrg 	  off_t length;
1214a2dc1f3fSmrg 
1215a2dc1f3fSmrg 	  shdr = shdrs + (i - 1) * shdr_size;
1216a2dc1f3fSmrg 	  sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1217a2dc1f3fSmrg 				     shdr, sh_type, Elf_Word);
1218a2dc1f3fSmrg 	  sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1219a2dc1f3fSmrg 				     shdr, sh_info, Elf_Word);
1220a2dc1f3fSmrg 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1221a2dc1f3fSmrg 				     shdr, sh_link, Elf_Word);
1222a2dc1f3fSmrg 	  if (sh_type == SHT_GROUP)
1223a2dc1f3fSmrg 	    {
1224a2dc1f3fSmrg 	      /* Mark groups containing copied sections.  */
1225a2dc1f3fSmrg 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class,
1226a2dc1f3fSmrg 						  Shdr, shdr, sh_entsize,
1227a2dc1f3fSmrg 						  Elf_Addr);
1228a2dc1f3fSmrg 	      unsigned char *ent, *buf;
1229a2dc1f3fSmrg 	      int keep = 0;
1230a2dc1f3fSmrg 	      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1231a2dc1f3fSmrg 					shdr, sh_offset, Elf_Addr);
1232a2dc1f3fSmrg 	      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1233a2dc1f3fSmrg 					shdr, sh_size, Elf_Addr);
1234a2dc1f3fSmrg 	      buf = XNEWVEC (unsigned char, length);
1235a2dc1f3fSmrg 	      if (!simple_object_internal_read (sobj->descriptor,
1236a2dc1f3fSmrg 						sobj->offset + offset, buf,
1237a2dc1f3fSmrg 						(size_t) length, &errmsg, err))
1238a2dc1f3fSmrg 		{
1239a2dc1f3fSmrg 		  XDELETEVEC (buf);
1240a2dc1f3fSmrg 		  XDELETEVEC (names);
1241a2dc1f3fSmrg 		  XDELETEVEC (shdrs);
1242a2dc1f3fSmrg 		  return errmsg;
1243a2dc1f3fSmrg 		}
1244a2dc1f3fSmrg 	      for (ent = buf + entsize; ent < buf + length; ent += entsize)
1245a2dc1f3fSmrg 		{
1246a2dc1f3fSmrg 		  unsigned sec = type_functions->fetch_Elf_Word (ent);
1247a2dc1f3fSmrg 		  if (pfnret[sec - 1] == 0)
1248a2dc1f3fSmrg 		    keep = 1;
1249a2dc1f3fSmrg 		}
1250a2dc1f3fSmrg 	      if (keep)
1251a2dc1f3fSmrg 		{
1252a2dc1f3fSmrg 		  changed |= (pfnret[sh_link - 1] == -1
1253a2dc1f3fSmrg 			      || pfnret[i - 1] == -1);
1254a2dc1f3fSmrg 		  pfnret[sh_link - 1] = 0;
1255a2dc1f3fSmrg 		  pfnret[i - 1] = 0;
1256a2dc1f3fSmrg 		}
1257a2dc1f3fSmrg 	    }
1258a2dc1f3fSmrg 	  if (sh_type == SHT_RELA
1259a2dc1f3fSmrg 	      || sh_type == SHT_REL)
1260a2dc1f3fSmrg 	    {
1261a2dc1f3fSmrg 	      /* Mark relocation sections and symtab of copied sections.  */
1262a2dc1f3fSmrg 	      if (pfnret[sh_info - 1] == 0)
1263a2dc1f3fSmrg 		{
1264a2dc1f3fSmrg 		  changed |= (pfnret[sh_link - 1] == -1
1265a2dc1f3fSmrg 			      || pfnret[i - 1] == -1);
1266a2dc1f3fSmrg 		  pfnret[sh_link - 1] = 0;
1267a2dc1f3fSmrg 		  pfnret[i - 1] = 0;
1268a2dc1f3fSmrg 		}
1269a2dc1f3fSmrg 	    }
1270a2dc1f3fSmrg 	  if (sh_type == SHT_SYMTAB)
1271a2dc1f3fSmrg 	    {
1272a2dc1f3fSmrg 	      /* Mark strings sections of copied symtabs.  */
1273a2dc1f3fSmrg 	      if (pfnret[i - 1] == 0)
1274a2dc1f3fSmrg 		{
1275a2dc1f3fSmrg 		  changed |= pfnret[sh_link - 1] == -1;
1276a2dc1f3fSmrg 		  pfnret[sh_link - 1] = 0;
1277a2dc1f3fSmrg 		}
1278a2dc1f3fSmrg 	    }
1279a2dc1f3fSmrg 	}
1280a2dc1f3fSmrg     }
1281a2dc1f3fSmrg   while (changed);
1282a2dc1f3fSmrg 
1283a2dc1f3fSmrg   /* Compute a mapping of old -> new section numbers.  */
1284a2dc1f3fSmrg   sh_map = XNEWVEC (unsigned, shnum);
1285a2dc1f3fSmrg   sh_map[0] = 0;
1286a2dc1f3fSmrg   new_i = 1;
1287a2dc1f3fSmrg   for (i = 1; i < shnum; ++i)
1288a2dc1f3fSmrg     {
1289a2dc1f3fSmrg       if (pfnret[i - 1] == -1)
1290a2dc1f3fSmrg 	sh_map[i] = 0;
1291a2dc1f3fSmrg       else
1292a2dc1f3fSmrg 	sh_map[i] = new_i++;
1293a2dc1f3fSmrg     }
1294a2dc1f3fSmrg   if (new_i - 1 >= SHN_LORESERVE)
1295a2dc1f3fSmrg     {
1296a2dc1f3fSmrg       *err = ENOTSUP;
1297a2dc1f3fSmrg       return "Too many copied sections";
1298a2dc1f3fSmrg     }
1299a2dc1f3fSmrg   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
1300a2dc1f3fSmrg 
1301a2dc1f3fSmrg   /* Then perform the actual copying.  */
1302a2dc1f3fSmrg   new_i = 0;
1303a2dc1f3fSmrg   for (i = 1; i < shnum; ++i)
1304a2dc1f3fSmrg     {
1305a2dc1f3fSmrg       unsigned char *shdr;
1306a2dc1f3fSmrg       unsigned int sh_name, sh_type;
1307a2dc1f3fSmrg       const char *name;
1308a2dc1f3fSmrg       off_t offset;
1309a2dc1f3fSmrg       off_t length;
1310a2dc1f3fSmrg       simple_object_write_section *dest;
1311a2dc1f3fSmrg       off_t flags;
1312a2dc1f3fSmrg       unsigned char *buf;
1313a2dc1f3fSmrg 
1314a2dc1f3fSmrg       if (pfnret[i - 1])
1315a2dc1f3fSmrg 	continue;
1316a2dc1f3fSmrg 
1317a2dc1f3fSmrg       new_i++;
1318a2dc1f3fSmrg       shdr = shdrs + (i - 1) * shdr_size;
1319a2dc1f3fSmrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1320a2dc1f3fSmrg 				 shdr, sh_name, Elf_Word);
1321a2dc1f3fSmrg       if (sh_name >= name_size)
1322a2dc1f3fSmrg 	{
1323a2dc1f3fSmrg 	  *err = 0;
1324a2dc1f3fSmrg 	  XDELETEVEC (names);
1325a2dc1f3fSmrg 	  XDELETEVEC (shdrs);
1326a2dc1f3fSmrg 	  XDELETEVEC (symtab_indices_shndx);
1327a2dc1f3fSmrg 	  return "ELF section name out of range";
1328a2dc1f3fSmrg 	}
1329a2dc1f3fSmrg 
1330a2dc1f3fSmrg       name = pfnname[i - 1];
1331a2dc1f3fSmrg       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1332a2dc1f3fSmrg 				shdr, sh_offset, Elf_Addr);
1333a2dc1f3fSmrg       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1334a2dc1f3fSmrg 				shdr, sh_size, Elf_Addr);
1335a2dc1f3fSmrg       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1336a2dc1f3fSmrg 				 shdr, sh_type, Elf_Word);
1337a2dc1f3fSmrg 
1338a2dc1f3fSmrg       dest = simple_object_write_create_section (dobj, pfnname[i - 1],
1339a2dc1f3fSmrg 						 0, &errmsg, err);
1340a2dc1f3fSmrg       if (dest == NULL)
1341a2dc1f3fSmrg 	{
1342a2dc1f3fSmrg 	  XDELETEVEC (names);
1343a2dc1f3fSmrg 	  XDELETEVEC (shdrs);
1344a2dc1f3fSmrg 	  XDELETEVEC (symtab_indices_shndx);
1345a2dc1f3fSmrg 	  return errmsg;
1346a2dc1f3fSmrg 	}
1347a2dc1f3fSmrg 
1348a2dc1f3fSmrg       /* Record the SHDR of the source.  */
1349a2dc1f3fSmrg       memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size);
1350a2dc1f3fSmrg       shdr = eow->shdrs + (new_i - 1) * shdr_size;
1351a2dc1f3fSmrg 
1352a2dc1f3fSmrg       /* Copy the data.
1353a2dc1f3fSmrg 	 ???  This is quite wasteful and ideally would be delayed until
1354a2dc1f3fSmrg 	 write_to_file ().  Thus it questions the interfacing
1355a2dc1f3fSmrg 	 which eventually should contain destination creation plus
1356a2dc1f3fSmrg 	 writing.  */
1357a2dc1f3fSmrg       buf = XNEWVEC (unsigned char, length);
1358a2dc1f3fSmrg       if (!simple_object_internal_read (sobj->descriptor,
1359a2dc1f3fSmrg 					sobj->offset + offset, buf,
1360a2dc1f3fSmrg 					(size_t) length, &errmsg, err))
1361a2dc1f3fSmrg 	{
1362a2dc1f3fSmrg 	  XDELETEVEC (buf);
1363a2dc1f3fSmrg 	  XDELETEVEC (names);
1364a2dc1f3fSmrg 	  XDELETEVEC (shdrs);
1365a2dc1f3fSmrg 	  XDELETEVEC (symtab_indices_shndx);
1366a2dc1f3fSmrg 	  return errmsg;
1367a2dc1f3fSmrg 	}
1368a2dc1f3fSmrg 
1369*8feb0f0bSmrg       /* If we are processing .symtab purge any symbols
1370*8feb0f0bSmrg 	 in discarded sections.  */
1371a2dc1f3fSmrg       if (sh_type == SHT_SYMTAB)
1372a2dc1f3fSmrg 	{
1373a2dc1f3fSmrg 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1374a2dc1f3fSmrg 					      shdr, sh_entsize, Elf_Addr);
1375*8feb0f0bSmrg 	  size_t prevailing_name_idx = 0;
1376a2dc1f3fSmrg 	  unsigned char *ent;
1377a2dc1f3fSmrg 	  unsigned *shndx_table = NULL;
1378a2dc1f3fSmrg 	  /* Read the section index table if present.  */
1379a2dc1f3fSmrg 	  if (symtab_indices_shndx[i - 1] != 0)
1380a2dc1f3fSmrg 	    {
1381*8feb0f0bSmrg 	      unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size;
1382a2dc1f3fSmrg 	      off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1383a2dc1f3fSmrg 					       sidxhdr, sh_offset, Elf_Addr);
1384a2dc1f3fSmrg 	      size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1385a2dc1f3fSmrg 					       sidxhdr, sh_size, Elf_Addr);
1386*8feb0f0bSmrg 	      unsigned int shndx_type
1387*8feb0f0bSmrg 		= ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1388*8feb0f0bSmrg 				   sidxhdr, sh_type, Elf_Word);
1389*8feb0f0bSmrg 	      if (shndx_type != SHT_SYMTAB_SHNDX)
1390*8feb0f0bSmrg 		return "Wrong section type of a SYMTAB SECTION INDICES section";
1391a2dc1f3fSmrg 	      shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
1392a2dc1f3fSmrg 	      simple_object_internal_read (sobj->descriptor,
1393a2dc1f3fSmrg 					   sobj->offset + sidxoff,
1394a2dc1f3fSmrg 					   (unsigned char *)shndx_table,
1395a2dc1f3fSmrg 					   sidxsz, &errmsg, err);
1396a2dc1f3fSmrg 	    }
1397*8feb0f0bSmrg 
1398*8feb0f0bSmrg 	  /* Find a WEAK HIDDEN symbol which name we will use for removed
1399*8feb0f0bSmrg 	     symbols.  We know there's a prevailing weak hidden symbol
1400*8feb0f0bSmrg 	     at the start of the .debug_info section.  */
1401*8feb0f0bSmrg 	  for (ent = buf; ent < buf + length; ent += entsize)
1402*8feb0f0bSmrg 	    {
1403*8feb0f0bSmrg 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
1404*8feb0f0bSmrg 						   Sym, ent,
1405*8feb0f0bSmrg 						   st_shndx, Elf_Half);
1406*8feb0f0bSmrg 	      unsigned char *st_info;
1407*8feb0f0bSmrg 	      unsigned char *st_other;
1408*8feb0f0bSmrg 	      if (ei_class == ELFCLASS32)
1409*8feb0f0bSmrg 		{
1410*8feb0f0bSmrg 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
1411*8feb0f0bSmrg 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
1412*8feb0f0bSmrg 		}
1413*8feb0f0bSmrg 	      else
1414*8feb0f0bSmrg 		{
1415*8feb0f0bSmrg 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
1416*8feb0f0bSmrg 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
1417*8feb0f0bSmrg 		}
1418*8feb0f0bSmrg 	      if (st_shndx == SHN_XINDEX)
1419*8feb0f0bSmrg 		st_shndx = type_functions->fetch_Elf_Word
1420*8feb0f0bSmrg 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
1421*8feb0f0bSmrg 
1422*8feb0f0bSmrg 	      if (st_shndx != SHN_COMMON
1423*8feb0f0bSmrg 		  && !(st_shndx != SHN_UNDEF
1424*8feb0f0bSmrg 		       && st_shndx < shnum
1425*8feb0f0bSmrg 		       && pfnret[st_shndx - 1] == -1)
1426*8feb0f0bSmrg 		  && ELF_ST_BIND (*st_info) == STB_WEAK
1427*8feb0f0bSmrg 		  && *st_other == STV_HIDDEN)
1428*8feb0f0bSmrg 		{
1429*8feb0f0bSmrg 		  prevailing_name_idx = ELF_FETCH_FIELD (type_functions,
1430*8feb0f0bSmrg 							 ei_class, Sym, ent,
1431*8feb0f0bSmrg 							 st_name, Elf_Word);
1432*8feb0f0bSmrg 		  break;
1433*8feb0f0bSmrg 		}
1434*8feb0f0bSmrg 	    }
1435*8feb0f0bSmrg 
1436a2dc1f3fSmrg 	  for (ent = buf; ent < buf + length; ent += entsize)
1437a2dc1f3fSmrg 	    {
1438a2dc1f3fSmrg 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
1439a2dc1f3fSmrg 						   Sym, ent,
1440a2dc1f3fSmrg 						   st_shndx, Elf_Half);
1441a2dc1f3fSmrg 	      unsigned raw_st_shndx = st_shndx;
1442a2dc1f3fSmrg 	      unsigned char *st_info;
1443a2dc1f3fSmrg 	      unsigned char *st_other;
1444a2dc1f3fSmrg 	      int discard = 0;
1445a2dc1f3fSmrg 	      if (ei_class == ELFCLASS32)
1446a2dc1f3fSmrg 		{
1447a2dc1f3fSmrg 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
1448a2dc1f3fSmrg 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
1449a2dc1f3fSmrg 		}
1450a2dc1f3fSmrg 	      else
1451a2dc1f3fSmrg 		{
1452a2dc1f3fSmrg 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
1453a2dc1f3fSmrg 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
1454a2dc1f3fSmrg 		}
1455a2dc1f3fSmrg 	      if (st_shndx == SHN_XINDEX)
1456a2dc1f3fSmrg 		st_shndx = type_functions->fetch_Elf_Word
1457a2dc1f3fSmrg 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
1458*8feb0f0bSmrg 	      /* Eliminate all COMMONs - this includes __gnu_lto_slim
1459*8feb0f0bSmrg 		 which otherwise cause endless LTO plugin invocation.
1460*8feb0f0bSmrg 		 FIXME: remove the condition once we remove emission
1461*8feb0f0bSmrg 		 of __gnu_lto_slim symbol.  */
1462a2dc1f3fSmrg 	      if (st_shndx == SHN_COMMON)
1463a2dc1f3fSmrg 		discard = 1;
1464a2dc1f3fSmrg 	      /* We also need to remove symbols refering to sections
1465a2dc1f3fSmrg 		 we'll eventually remove as with fat LTO objects
1466a2dc1f3fSmrg 		 we otherwise get duplicate symbols at final link
1467a2dc1f3fSmrg 		 (with GNU ld, gold is fine and ignores symbols in
1468a2dc1f3fSmrg 		 sections marked as EXCLUDE).  ld/20513  */
1469a2dc1f3fSmrg 	      else if (st_shndx != SHN_UNDEF
1470a2dc1f3fSmrg 		       && st_shndx < shnum
1471a2dc1f3fSmrg 		       && pfnret[st_shndx - 1] == -1)
1472a2dc1f3fSmrg 		discard = 1;
1473*8feb0f0bSmrg 	      /* We also need to remove global UNDEFs which can
1474*8feb0f0bSmrg 		 cause link fails later.  */
1475*8feb0f0bSmrg 	      else if (st_shndx == SHN_UNDEF
1476*8feb0f0bSmrg 		       && ELF_ST_BIND (*st_info) == STB_GLOBAL)
1477*8feb0f0bSmrg 		discard = 1;
1478a2dc1f3fSmrg 
1479a2dc1f3fSmrg 	      if (discard)
1480a2dc1f3fSmrg 		{
1481a2dc1f3fSmrg 		  /* Make discarded symbols undefined and unnamed
1482a2dc1f3fSmrg 		     in case it is local.  */
1483a2dc1f3fSmrg 		  int bind = ELF_ST_BIND (*st_info);
1484a2dc1f3fSmrg 		  int other = STV_DEFAULT;
1485a2dc1f3fSmrg 		  if (bind == STB_LOCAL)
1486a2dc1f3fSmrg 		    {
1487a2dc1f3fSmrg 		      /* Make discarded local symbols unnamed and
1488a2dc1f3fSmrg 			 defined in the first prevailing section.  */
1489a2dc1f3fSmrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1490a2dc1f3fSmrg 				     ent, st_name, Elf_Word, 0);
1491a2dc1f3fSmrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1492a2dc1f3fSmrg 				     ent, st_shndx, Elf_Half,
1493a2dc1f3fSmrg 				     sh_map[first_shndx]);
1494a2dc1f3fSmrg 		    }
1495a2dc1f3fSmrg 		  else
1496a2dc1f3fSmrg 		    {
1497a2dc1f3fSmrg 		      /* Make discarded global symbols hidden weak
1498*8feb0f0bSmrg 			 undefined and sharing a name of a prevailing
1499*8feb0f0bSmrg 			 symbol.  */
1500a2dc1f3fSmrg 		      bind = STB_WEAK;
1501a2dc1f3fSmrg 		      other = STV_HIDDEN;
1502a2dc1f3fSmrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1503a2dc1f3fSmrg 				     ent, st_name, Elf_Word,
1504*8feb0f0bSmrg 				     prevailing_name_idx);
1505a2dc1f3fSmrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1506a2dc1f3fSmrg 				     ent, st_shndx, Elf_Half, SHN_UNDEF);
1507a2dc1f3fSmrg 		    }
1508a2dc1f3fSmrg 		  *st_other = other;
1509a2dc1f3fSmrg 		  *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
1510a2dc1f3fSmrg 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1511a2dc1f3fSmrg 				 ent, st_value, Elf_Addr, 0);
1512a2dc1f3fSmrg 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1513a2dc1f3fSmrg 				 ent, st_size, Elf_Word, 0);
1514a2dc1f3fSmrg 		}
1515a2dc1f3fSmrg 	      else if (raw_st_shndx < SHN_LORESERVE
1516a2dc1f3fSmrg 		       || raw_st_shndx == SHN_XINDEX)
1517a2dc1f3fSmrg 		/* Remap the section reference.  */
1518a2dc1f3fSmrg 		ELF_SET_FIELD (type_functions, ei_class, Sym,
1519a2dc1f3fSmrg 			       ent, st_shndx, Elf_Half, sh_map[st_shndx]);
1520a2dc1f3fSmrg 	    }
1521a2dc1f3fSmrg 	  XDELETEVEC (shndx_table);
1522a2dc1f3fSmrg 	}
1523a2dc1f3fSmrg       else if (sh_type == SHT_GROUP)
1524a2dc1f3fSmrg 	{
1525a2dc1f3fSmrg 	  /* Remap section indices in groups and remove removed members.  */
1526a2dc1f3fSmrg 	  unsigned char *ent, *dst;
1527a2dc1f3fSmrg 	  for (dst = ent = buf + 4; ent < buf + length; ent += 4)
1528a2dc1f3fSmrg 	    {
1529a2dc1f3fSmrg 	      unsigned shndx = type_functions->fetch_Elf_Word (ent);
1530a2dc1f3fSmrg 	      if (pfnret[shndx - 1] == -1)
1531a2dc1f3fSmrg 		;
1532a2dc1f3fSmrg 	      else
1533a2dc1f3fSmrg 		{
1534a2dc1f3fSmrg 		  type_functions->set_Elf_Word (dst, sh_map[shndx]);
1535a2dc1f3fSmrg 		  dst += 4;
1536a2dc1f3fSmrg 		}
1537a2dc1f3fSmrg 	    }
1538a2dc1f3fSmrg 	  /* Adjust the length.  */
1539a2dc1f3fSmrg 	  length = dst - buf;
1540a2dc1f3fSmrg 	}
1541a2dc1f3fSmrg 
1542a2dc1f3fSmrg       errmsg = simple_object_write_add_data (dobj, dest,
1543a2dc1f3fSmrg 					     buf, length, 1, err);
1544a2dc1f3fSmrg       XDELETEVEC (buf);
1545a2dc1f3fSmrg       if (errmsg)
1546a2dc1f3fSmrg 	{
1547a2dc1f3fSmrg 	  XDELETEVEC (names);
1548a2dc1f3fSmrg 	  XDELETEVEC (shdrs);
1549a2dc1f3fSmrg 	  XDELETEVEC (symtab_indices_shndx);
1550a2dc1f3fSmrg 	  return errmsg;
1551a2dc1f3fSmrg 	}
1552a2dc1f3fSmrg 
1553a2dc1f3fSmrg       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1554a2dc1f3fSmrg 			       shdr, sh_flags, Elf_Addr);
1555a2dc1f3fSmrg       /* Remap the section references.  */
1556a2dc1f3fSmrg       {
1557a2dc1f3fSmrg 	unsigned int sh_info, sh_link;
1558a2dc1f3fSmrg 	if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA)
1559a2dc1f3fSmrg 	  {
1560a2dc1f3fSmrg 	    sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1561a2dc1f3fSmrg 				       shdr, sh_info, Elf_Word);
1562a2dc1f3fSmrg 	    sh_info = sh_map[sh_info];
1563a2dc1f3fSmrg 	    ELF_SET_FIELD (type_functions, ei_class, Shdr,
1564a2dc1f3fSmrg 			   shdr, sh_info, Elf_Word, sh_info);
1565a2dc1f3fSmrg 	  }
1566a2dc1f3fSmrg 	sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1567a2dc1f3fSmrg 				   shdr, sh_link, Elf_Word);
1568a2dc1f3fSmrg 	sh_link = sh_map[sh_link];
1569a2dc1f3fSmrg 	ELF_SET_FIELD (type_functions, ei_class, Shdr,
1570a2dc1f3fSmrg 		       shdr, sh_link, Elf_Word, sh_link);
1571a2dc1f3fSmrg       }
1572a2dc1f3fSmrg       /* The debugobj doesn't contain any code, thus no trampolines.
1573a2dc1f3fSmrg 	 Even when the original object needs trampolines, debugobj
1574a2dc1f3fSmrg 	 doesn't.  */
1575a2dc1f3fSmrg       if (strcmp (name, ".note.GNU-stack") == 0)
1576a2dc1f3fSmrg 	flags &= ~SHF_EXECINSTR;
1577a2dc1f3fSmrg       /* Clear SHF_EXCLUDE on to be preserved sections.  */
1578a2dc1f3fSmrg       flags &= ~SHF_EXCLUDE;
1579a2dc1f3fSmrg       ELF_SET_FIELD (type_functions, ei_class, Shdr,
1580a2dc1f3fSmrg 		     shdr, sh_flags, Elf_Addr, flags);
1581a2dc1f3fSmrg     }
1582a2dc1f3fSmrg 
1583a2dc1f3fSmrg   XDELETEVEC (names);
1584a2dc1f3fSmrg   XDELETEVEC (shdrs);
1585a2dc1f3fSmrg   XDELETEVEC (pfnret);
1586a2dc1f3fSmrg   XDELETEVEC (pfnname);
1587a2dc1f3fSmrg   XDELETEVEC (symtab_indices_shndx);
1588a2dc1f3fSmrg   XDELETEVEC (sh_map);
1589a2dc1f3fSmrg 
1590a2dc1f3fSmrg   return NULL;
1591a2dc1f3fSmrg }
1592a2dc1f3fSmrg 
1593a2dc1f3fSmrg 
15941debfc3dSmrg /* The ELF functions.  */
15951debfc3dSmrg 
15961debfc3dSmrg const struct simple_object_functions simple_object_elf_functions =
15971debfc3dSmrg {
15981debfc3dSmrg   simple_object_elf_match,
15991debfc3dSmrg   simple_object_elf_find_sections,
16001debfc3dSmrg   simple_object_elf_fetch_attributes,
16011debfc3dSmrg   simple_object_elf_release_read,
16021debfc3dSmrg   simple_object_elf_attributes_merge,
16031debfc3dSmrg   simple_object_elf_release_attributes,
16041debfc3dSmrg   simple_object_elf_start_write,
16051debfc3dSmrg   simple_object_elf_write_to_file,
1606a2dc1f3fSmrg   simple_object_elf_release_write,
1607a2dc1f3fSmrg   simple_object_elf_copy_lto_debug_sections
16081debfc3dSmrg };
1609