xref: /dflybsd-src/contrib/gcc-8.0/libiberty/simple-object-elf.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* simple-object-elf.c -- routines to manipulate ELF object files.
238fd1498Szrj    Copyright (C) 2010-2018 Free Software Foundation, Inc.
338fd1498Szrj    Written by Ian Lance Taylor, Google.
438fd1498Szrj 
538fd1498Szrj This program is free software; you can redistribute it and/or modify it
638fd1498Szrj under the terms of the GNU General Public License as published by the
738fd1498Szrj Free Software Foundation; either version 2, or (at your option) any
838fd1498Szrj later version.
938fd1498Szrj 
1038fd1498Szrj This program is distributed in the hope that it will be useful,
1138fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
1238fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1338fd1498Szrj GNU General Public License for more details.
1438fd1498Szrj 
1538fd1498Szrj You should have received a copy of the GNU General Public License
1638fd1498Szrj along with this program; if not, write to the Free Software
1738fd1498Szrj Foundation, 51 Franklin Street - Fifth Floor,
1838fd1498Szrj Boston, MA 02110-1301, USA.  */
1938fd1498Szrj 
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "libiberty.h"
2238fd1498Szrj #include "simple-object.h"
2338fd1498Szrj 
2438fd1498Szrj #include <errno.h>
25*58e805e6Szrj /* mingw.org's MinGW doesn't have ENOTSUP.  */
26*58e805e6Szrj #ifndef ENOTSUP
27*58e805e6Szrj # define ENOTSUP ENOSYS
28*58e805e6Szrj #endif
2938fd1498Szrj #include <stddef.h>
3038fd1498Szrj 
3138fd1498Szrj #ifdef HAVE_STDLIB_H
3238fd1498Szrj #include <stdlib.h>
3338fd1498Szrj #endif
3438fd1498Szrj 
3538fd1498Szrj #ifdef HAVE_STDINT_H
3638fd1498Szrj #include <stdint.h>
3738fd1498Szrj #endif
3838fd1498Szrj 
3938fd1498Szrj #ifdef HAVE_STRING_H
4038fd1498Szrj #include <string.h>
4138fd1498Szrj #endif
4238fd1498Szrj 
4338fd1498Szrj #ifdef HAVE_INTTYPES_H
4438fd1498Szrj #include <inttypes.h>
4538fd1498Szrj #endif
4638fd1498Szrj 
4738fd1498Szrj #include "simple-object-common.h"
4838fd1498Szrj 
4938fd1498Szrj /* ELF structures and constants.  */
5038fd1498Szrj 
5138fd1498Szrj /* 32-bit ELF file header.  */
5238fd1498Szrj 
5338fd1498Szrj typedef struct {
5438fd1498Szrj   unsigned char	e_ident[16];		/* ELF "magic number" */
5538fd1498Szrj   unsigned char	e_type[2];		/* Identifies object file type */
5638fd1498Szrj   unsigned char	e_machine[2];		/* Specifies required architecture */
5738fd1498Szrj   unsigned char	e_version[4];		/* Identifies object file version */
5838fd1498Szrj   unsigned char	e_entry[4];		/* Entry point virtual address */
5938fd1498Szrj   unsigned char	e_phoff[4];		/* Program header table file offset */
6038fd1498Szrj   unsigned char	e_shoff[4];		/* Section header table file offset */
6138fd1498Szrj   unsigned char	e_flags[4];		/* Processor-specific flags */
6238fd1498Szrj   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
6338fd1498Szrj   unsigned char	e_phentsize[2];		/* Program header table entry size */
6438fd1498Szrj   unsigned char	e_phnum[2];		/* Program header table entry count */
6538fd1498Szrj   unsigned char	e_shentsize[2];		/* Section header table entry size */
6638fd1498Szrj   unsigned char	e_shnum[2];		/* Section header table entry count */
6738fd1498Szrj   unsigned char	e_shstrndx[2];		/* Section header string table index */
6838fd1498Szrj } Elf32_External_Ehdr;
6938fd1498Szrj 
7038fd1498Szrj /* 64-bit ELF file header.  */
7138fd1498Szrj 
7238fd1498Szrj typedef struct {
7338fd1498Szrj   unsigned char	e_ident[16];		/* ELF "magic number" */
7438fd1498Szrj   unsigned char	e_type[2];		/* Identifies object file type */
7538fd1498Szrj   unsigned char	e_machine[2];		/* Specifies required architecture */
7638fd1498Szrj   unsigned char	e_version[4];		/* Identifies object file version */
7738fd1498Szrj   unsigned char	e_entry[8];		/* Entry point virtual address */
7838fd1498Szrj   unsigned char	e_phoff[8];		/* Program header table file offset */
7938fd1498Szrj   unsigned char	e_shoff[8];		/* Section header table file offset */
8038fd1498Szrj   unsigned char	e_flags[4];		/* Processor-specific flags */
8138fd1498Szrj   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
8238fd1498Szrj   unsigned char	e_phentsize[2];		/* Program header table entry size */
8338fd1498Szrj   unsigned char	e_phnum[2];		/* Program header table entry count */
8438fd1498Szrj   unsigned char	e_shentsize[2];		/* Section header table entry size */
8538fd1498Szrj   unsigned char	e_shnum[2];		/* Section header table entry count */
8638fd1498Szrj   unsigned char	e_shstrndx[2];		/* Section header string table index */
8738fd1498Szrj } Elf64_External_Ehdr;
8838fd1498Szrj 
8938fd1498Szrj /* Indexes and values in e_ident field of Ehdr.  */
9038fd1498Szrj 
9138fd1498Szrj #define EI_MAG0		0	/* File identification byte 0 index */
9238fd1498Szrj #define ELFMAG0		   0x7F	/* Magic number byte 0 */
9338fd1498Szrj 
9438fd1498Szrj #define EI_MAG1		1	/* File identification byte 1 index */
9538fd1498Szrj #define ELFMAG1		    'E'	/* Magic number byte 1 */
9638fd1498Szrj 
9738fd1498Szrj #define EI_MAG2		2	/* File identification byte 2 index */
9838fd1498Szrj #define ELFMAG2		    'L'	/* Magic number byte 2 */
9938fd1498Szrj 
10038fd1498Szrj #define EI_MAG3		3	/* File identification byte 3 index */
10138fd1498Szrj #define ELFMAG3		    'F'	/* Magic number byte 3 */
10238fd1498Szrj 
10338fd1498Szrj #define EI_CLASS	4	/* File class */
10438fd1498Szrj #define ELFCLASSNONE	      0	/* Invalid class */
10538fd1498Szrj #define ELFCLASS32	      1	/* 32-bit objects */
10638fd1498Szrj #define ELFCLASS64	      2	/* 64-bit objects */
10738fd1498Szrj 
10838fd1498Szrj #define EI_DATA		5	/* Data encoding */
10938fd1498Szrj #define ELFDATANONE	      0	/* Invalid data encoding */
11038fd1498Szrj #define ELFDATA2LSB	      1	/* 2's complement, little endian */
11138fd1498Szrj #define ELFDATA2MSB	      2	/* 2's complement, big endian */
11238fd1498Szrj 
11338fd1498Szrj #define EI_VERSION	6	/* File version */
11438fd1498Szrj #define EV_CURRENT	1		/* Current version */
11538fd1498Szrj 
11638fd1498Szrj #define EI_OSABI	7	/* Operating System/ABI indication */
11738fd1498Szrj 
11838fd1498Szrj /* Values for e_type field of Ehdr.  */
11938fd1498Szrj 
12038fd1498Szrj #define ET_REL		1	/* Relocatable file */
12138fd1498Szrj 
12238fd1498Szrj /* Values for e_machine field of Ehdr.  */
12338fd1498Szrj 
12438fd1498Szrj #define EM_SPARC	  2	/* SUN SPARC */
12538fd1498Szrj #define EM_SPARC32PLUS	 18	/* Sun's "v8plus" */
12638fd1498Szrj 
12738fd1498Szrj /* Special section index values.  */
12838fd1498Szrj 
12938fd1498Szrj #define SHN_UNDEF	0		/* Undefined section */
13038fd1498Szrj #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
13138fd1498Szrj #define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
13238fd1498Szrj #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
13338fd1498Szrj #define SHN_HIRESERVE	0xffff		/* End of reserved indices */
13438fd1498Szrj 
13538fd1498Szrj 
13638fd1498Szrj /* 32-bit ELF program header.  */
13738fd1498Szrj 
13838fd1498Szrj typedef struct {
13938fd1498Szrj   unsigned char	p_type[4];		/* Identifies program segment type */
14038fd1498Szrj   unsigned char	p_offset[4];		/* Segment file offset */
14138fd1498Szrj   unsigned char	p_vaddr[4];		/* Segment virtual address */
14238fd1498Szrj   unsigned char	p_paddr[4];		/* Segment physical address */
14338fd1498Szrj   unsigned char	p_filesz[4];		/* Segment size in file */
14438fd1498Szrj   unsigned char	p_memsz[4];		/* Segment size in memory */
14538fd1498Szrj   unsigned char	p_flags[4];		/* Segment flags */
14638fd1498Szrj   unsigned char	p_align[4];		/* Segment alignment, file & memory */
14738fd1498Szrj } Elf32_External_Phdr;
14838fd1498Szrj 
14938fd1498Szrj /* 64-bit ELF program header.  */
15038fd1498Szrj 
15138fd1498Szrj typedef struct {
15238fd1498Szrj   unsigned char	p_type[4];		/* Identifies program segment type */
15338fd1498Szrj   unsigned char	p_flags[4];		/* Segment flags */
15438fd1498Szrj   unsigned char	p_offset[8];		/* Segment file offset */
15538fd1498Szrj   unsigned char	p_vaddr[8];		/* Segment virtual address */
15638fd1498Szrj   unsigned char	p_paddr[8];		/* Segment physical address */
15738fd1498Szrj   unsigned char	p_filesz[8];		/* Segment size in file */
15838fd1498Szrj   unsigned char	p_memsz[8];		/* Segment size in memory */
15938fd1498Szrj   unsigned char	p_align[8];		/* Segment alignment, file & memory */
16038fd1498Szrj } Elf64_External_Phdr;
16138fd1498Szrj 
16238fd1498Szrj /* 32-bit ELF section header */
16338fd1498Szrj 
16438fd1498Szrj typedef struct {
16538fd1498Szrj   unsigned char	sh_name[4];		/* Section name, index in string tbl */
16638fd1498Szrj   unsigned char	sh_type[4];		/* Type of section */
16738fd1498Szrj   unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
16838fd1498Szrj   unsigned char	sh_addr[4];		/* Section virtual addr at execution */
16938fd1498Szrj   unsigned char	sh_offset[4];		/* Section file offset */
17038fd1498Szrj   unsigned char	sh_size[4];		/* Size of section in bytes */
17138fd1498Szrj   unsigned char	sh_link[4];		/* Index of another section */
17238fd1498Szrj   unsigned char	sh_info[4];		/* Additional section information */
17338fd1498Szrj   unsigned char	sh_addralign[4];	/* Section alignment */
17438fd1498Szrj   unsigned char	sh_entsize[4];		/* Entry size if section holds table */
17538fd1498Szrj } Elf32_External_Shdr;
17638fd1498Szrj 
17738fd1498Szrj /* 64-bit ELF section header.  */
17838fd1498Szrj 
17938fd1498Szrj typedef struct {
18038fd1498Szrj   unsigned char	sh_name[4];		/* Section name, index in string tbl */
18138fd1498Szrj   unsigned char	sh_type[4];		/* Type of section */
18238fd1498Szrj   unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
18338fd1498Szrj   unsigned char	sh_addr[8];		/* Section virtual addr at execution */
18438fd1498Szrj   unsigned char	sh_offset[8];		/* Section file offset */
18538fd1498Szrj   unsigned char	sh_size[8];		/* Size of section in bytes */
18638fd1498Szrj   unsigned char	sh_link[4];		/* Index of another section */
18738fd1498Szrj   unsigned char	sh_info[4];		/* Additional section information */
18838fd1498Szrj   unsigned char	sh_addralign[8];	/* Section alignment */
18938fd1498Szrj   unsigned char	sh_entsize[8];		/* Entry size if section holds table */
19038fd1498Szrj } Elf64_External_Shdr;
19138fd1498Szrj 
19238fd1498Szrj /* Values for sh_type field.  */
19338fd1498Szrj 
19438fd1498Szrj #define SHT_NULL	0		/* Section header table entry unused */
19538fd1498Szrj #define SHT_PROGBITS	1		/* Program data */
19638fd1498Szrj #define SHT_SYMTAB	2		/* Link editing symbol table */
19738fd1498Szrj #define SHT_STRTAB	3		/* A string table */
19838fd1498Szrj #define SHT_RELA	4		/* Relocation entries with addends */
19938fd1498Szrj #define SHT_REL		9		/* Relocation entries, no addends */
20038fd1498Szrj #define SHT_GROUP	17		/* Section contains a section group */
20138fd1498Szrj #define SHT_SYMTAB_SHNDX 18		/* Extended section indeces */
20238fd1498Szrj 
20338fd1498Szrj /* Values for sh_flags field.  */
20438fd1498Szrj 
20538fd1498Szrj #define SHF_INFO_LINK	0x00000040	/* `sh_info' contains SHT index */
20638fd1498Szrj #define SHF_EXECINSTR	0x00000004	/* Executable section.  */
20738fd1498Szrj #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
20838fd1498Szrj 					   section from executable and
20938fd1498Szrj 					   shared library that it builds
21038fd1498Szrj 					   when those objects are not to be
21138fd1498Szrj 					   further relocated.  */
21238fd1498Szrj /* Symbol table entry.  */
21338fd1498Szrj 
21438fd1498Szrj typedef struct
21538fd1498Szrj {
21638fd1498Szrj   unsigned char st_name[4];                /* Symbol name (string tbl index) */
21738fd1498Szrj   unsigned char st_value[4];               /* Symbol value */
21838fd1498Szrj   unsigned char st_size[4];                /* Symbol size */
21938fd1498Szrj   unsigned char st_info;                /* Symbol type and binding */
22038fd1498Szrj   unsigned char st_other;               /* Symbol visibility */
22138fd1498Szrj   unsigned char st_shndx[2];               /* Section index */
22238fd1498Szrj } Elf32_External_Sym;
22338fd1498Szrj 
22438fd1498Szrj typedef struct
22538fd1498Szrj {
22638fd1498Szrj   unsigned char st_name[4];                /* Symbol name (string tbl index) */
22738fd1498Szrj   unsigned char st_info;                /* Symbol type and binding */
22838fd1498Szrj   unsigned char st_other;               /* Symbol visibility */
22938fd1498Szrj   unsigned char st_shndx[2];               /* Section index */
23038fd1498Szrj   unsigned char st_value[8];               /* Symbol value */
23138fd1498Szrj   unsigned char st_size[8];                /* Symbol size */
23238fd1498Szrj } Elf64_External_Sym;
23338fd1498Szrj 
23438fd1498Szrj #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
23538fd1498Szrj #define ELF_ST_TYPE(val)              ((val) & 0xf)
23638fd1498Szrj #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
23738fd1498Szrj 
23838fd1498Szrj #define STT_NOTYPE	0	/* Symbol type is unspecified */
23938fd1498Szrj #define STT_OBJECT	1	/* Symbol is a data object */
24038fd1498Szrj #define STT_FUNC	2	/* Symbol is a code object */
24138fd1498Szrj #define STT_TLS		6	/* Thread local data object */
24238fd1498Szrj #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
24338fd1498Szrj 
24438fd1498Szrj #define STB_LOCAL	0	/* Local symbol */
24538fd1498Szrj #define STB_GLOBAL	1	/* Global symbol */
24638fd1498Szrj #define STB_WEAK	2	/* Weak global */
24738fd1498Szrj 
24838fd1498Szrj #define STV_DEFAULT	0	/* Visibility is specified by binding type */
24938fd1498Szrj #define STV_HIDDEN	2	/* Can only be seen inside currect component */
25038fd1498Szrj 
25138fd1498Szrj /* Functions to fetch and store different ELF types, depending on the
25238fd1498Szrj    endianness and size.  */
25338fd1498Szrj 
25438fd1498Szrj struct elf_type_functions
25538fd1498Szrj {
25638fd1498Szrj   unsigned short (*fetch_Elf_Half) (const unsigned char *);
25738fd1498Szrj   unsigned int (*fetch_Elf_Word) (const unsigned char *);
25838fd1498Szrj   ulong_type (*fetch_Elf_Addr) (const unsigned char *);
25938fd1498Szrj   void (*set_Elf_Half) (unsigned char *, unsigned short);
26038fd1498Szrj   void (*set_Elf_Word) (unsigned char *, unsigned int);
26138fd1498Szrj   void (*set_Elf_Addr) (unsigned char *, ulong_type);
26238fd1498Szrj };
26338fd1498Szrj 
26438fd1498Szrj static const struct elf_type_functions elf_big_32_functions =
26538fd1498Szrj {
26638fd1498Szrj   simple_object_fetch_big_16,
26738fd1498Szrj   simple_object_fetch_big_32,
26838fd1498Szrj   simple_object_fetch_big_32_ulong,
26938fd1498Szrj   simple_object_set_big_16,
27038fd1498Szrj   simple_object_set_big_32,
27138fd1498Szrj   simple_object_set_big_32_ulong
27238fd1498Szrj };
27338fd1498Szrj 
27438fd1498Szrj static const struct elf_type_functions elf_little_32_functions =
27538fd1498Szrj {
27638fd1498Szrj   simple_object_fetch_little_16,
27738fd1498Szrj   simple_object_fetch_little_32,
27838fd1498Szrj   simple_object_fetch_little_32_ulong,
27938fd1498Szrj   simple_object_set_little_16,
28038fd1498Szrj   simple_object_set_little_32,
28138fd1498Szrj   simple_object_set_little_32_ulong
28238fd1498Szrj };
28338fd1498Szrj 
28438fd1498Szrj #ifdef UNSIGNED_64BIT_TYPE
28538fd1498Szrj 
28638fd1498Szrj static const struct elf_type_functions elf_big_64_functions =
28738fd1498Szrj {
28838fd1498Szrj   simple_object_fetch_big_16,
28938fd1498Szrj   simple_object_fetch_big_32,
29038fd1498Szrj   simple_object_fetch_big_64,
29138fd1498Szrj   simple_object_set_big_16,
29238fd1498Szrj   simple_object_set_big_32,
29338fd1498Szrj   simple_object_set_big_64
29438fd1498Szrj };
29538fd1498Szrj 
29638fd1498Szrj static const struct elf_type_functions elf_little_64_functions =
29738fd1498Szrj {
29838fd1498Szrj   simple_object_fetch_little_16,
29938fd1498Szrj   simple_object_fetch_little_32,
30038fd1498Szrj   simple_object_fetch_little_64,
30138fd1498Szrj   simple_object_set_little_16,
30238fd1498Szrj   simple_object_set_little_32,
30338fd1498Szrj   simple_object_set_little_64
30438fd1498Szrj };
30538fd1498Szrj 
30638fd1498Szrj #endif
30738fd1498Szrj 
30838fd1498Szrj /* Hideous macro to fetch the value of a field from an external ELF
30938fd1498Szrj    struct of some sort.  TYPEFUNCS is the set of type functions.
31038fd1498Szrj    BUFFER points to the external data.  STRUCTTYPE is the appropriate
31138fd1498Szrj    struct type.  FIELD is a field within the struct.  TYPE is the type
31238fd1498Szrj    of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
31338fd1498Szrj 
31438fd1498Szrj #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
31538fd1498Szrj   ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
31638fd1498Szrj 
31738fd1498Szrj /* Even more hideous macro to fetch the value of FIELD from BUFFER.
31838fd1498Szrj    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
31938fd1498Szrj    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
32038fd1498Szrj    the struct.  TYPE is the type of the field in the struct: Elf_Half,
32138fd1498Szrj    Elf_Word, or Elf_Addr.  */
32238fd1498Szrj 
32338fd1498Szrj #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
32438fd1498Szrj 			      FIELD, TYPE)				\
32538fd1498Szrj   ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
32638fd1498Szrj 			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
32738fd1498Szrj 			  FIELD, BUFFER, TYPE)
32838fd1498Szrj 
32938fd1498Szrj /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
33038fd1498Szrj 
33138fd1498Szrj #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
33238fd1498Szrj 			FIELD, TYPE)					\
33338fd1498Szrj   ((CLASS) == ELFCLASS32						\
33438fd1498Szrj     ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
33538fd1498Szrj 			     TYPE)					\
33638fd1498Szrj     : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
33738fd1498Szrj 			     TYPE))
33838fd1498Szrj 
33938fd1498Szrj /* Hideous macro to set the value of a field in an external ELF
34038fd1498Szrj    structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
34138fd1498Szrj    points to the external data.  STRUCTTYPE is the appropriate
34238fd1498Szrj    structure type.  FIELD is a field within the struct.  TYPE is the
34338fd1498Szrj    type of the field in the struct: Elf_Half, Elf_Word, or
34438fd1498Szrj    Elf_Addr.  */
34538fd1498Szrj 
34638fd1498Szrj #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
34738fd1498Szrj   (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
34838fd1498Szrj 
34938fd1498Szrj /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
35038fd1498Szrj    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
35138fd1498Szrj    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
35238fd1498Szrj    the struct.  TYPE is the type of the field in the struct: Elf_Half,
35338fd1498Szrj    Elf_Word, or Elf_Addr.  */
35438fd1498Szrj 
35538fd1498Szrj #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
35638fd1498Szrj 			    TYPE, VAL)					\
35738fd1498Szrj   ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
35838fd1498Szrj 			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
35938fd1498Szrj 			FIELD, BUFFER, TYPE, VAL)
36038fd1498Szrj 
36138fd1498Szrj /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
36238fd1498Szrj 
36338fd1498Szrj #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
36438fd1498Szrj 		      TYPE, VAL)					\
36538fd1498Szrj   ((CLASS) == ELFCLASS32						\
36638fd1498Szrj     ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
36738fd1498Szrj 			   TYPE, VAL)					\
36838fd1498Szrj     : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
36938fd1498Szrj 			   TYPE, VAL))
37038fd1498Szrj 
37138fd1498Szrj /* Private data for an simple_object_read.  */
37238fd1498Szrj 
37338fd1498Szrj struct simple_object_elf_read
37438fd1498Szrj {
37538fd1498Szrj   /* Type functions.  */
37638fd1498Szrj   const struct elf_type_functions* type_functions;
37738fd1498Szrj   /* Elf data.  */
37838fd1498Szrj   unsigned char ei_data;
37938fd1498Szrj   /* Elf class.  */
38038fd1498Szrj   unsigned char ei_class;
38138fd1498Szrj   /* ELF OS ABI.  */
38238fd1498Szrj   unsigned char ei_osabi;
38338fd1498Szrj   /* Elf machine number.  */
38438fd1498Szrj   unsigned short machine;
38538fd1498Szrj   /* Processor specific flags.  */
38638fd1498Szrj   unsigned int flags;
38738fd1498Szrj   /* File offset of section headers.  */
38838fd1498Szrj   ulong_type shoff;
38938fd1498Szrj   /* Number of sections.  */
39038fd1498Szrj   unsigned int shnum;
39138fd1498Szrj   /* Index of string table section header.  */
39238fd1498Szrj   unsigned int shstrndx;
39338fd1498Szrj };
39438fd1498Szrj 
39538fd1498Szrj /* Private data for an simple_object_attributes.  */
39638fd1498Szrj 
39738fd1498Szrj struct simple_object_elf_attributes
39838fd1498Szrj {
39938fd1498Szrj   /* Type functions.  */
40038fd1498Szrj   const struct elf_type_functions* type_functions;
40138fd1498Szrj   /* Elf data.  */
40238fd1498Szrj   unsigned char ei_data;
40338fd1498Szrj   /* Elf class.  */
40438fd1498Szrj   unsigned char ei_class;
40538fd1498Szrj   /* ELF OS ABI.  */
40638fd1498Szrj   unsigned char ei_osabi;
40738fd1498Szrj   /* Elf machine number.  */
40838fd1498Szrj   unsigned short machine;
40938fd1498Szrj   /* Processor specific flags.  */
41038fd1498Szrj   unsigned int flags;
41138fd1498Szrj };
41238fd1498Szrj 
41338fd1498Szrj /* Private data for an simple_object_write.  */
41438fd1498Szrj 
41538fd1498Szrj struct simple_object_elf_write
41638fd1498Szrj {
41738fd1498Szrj   struct simple_object_elf_attributes attrs;
41838fd1498Szrj   unsigned char *shdrs;
41938fd1498Szrj };
42038fd1498Szrj 
42138fd1498Szrj /* See if we have an ELF file.  */
42238fd1498Szrj 
42338fd1498Szrj 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)42438fd1498Szrj simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
42538fd1498Szrj 			 int descriptor, off_t offset,
42638fd1498Szrj 			 const char *segment_name ATTRIBUTE_UNUSED,
42738fd1498Szrj 			 const char **errmsg, int *err)
42838fd1498Szrj {
42938fd1498Szrj   unsigned char ei_data;
43038fd1498Szrj   unsigned char ei_class;
43138fd1498Szrj   const struct elf_type_functions *type_functions;
43238fd1498Szrj   unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
43338fd1498Szrj   struct simple_object_elf_read *eor;
43438fd1498Szrj 
43538fd1498Szrj   if (header[EI_MAG0] != ELFMAG0
43638fd1498Szrj       || header[EI_MAG1] != ELFMAG1
43738fd1498Szrj       || header[EI_MAG2] != ELFMAG2
43838fd1498Szrj       || header[EI_MAG3] != ELFMAG3
43938fd1498Szrj       || header[EI_VERSION] != EV_CURRENT)
44038fd1498Szrj     {
44138fd1498Szrj       *errmsg = NULL;
44238fd1498Szrj       *err = 0;
44338fd1498Szrj       return NULL;
44438fd1498Szrj     }
44538fd1498Szrj 
44638fd1498Szrj   ei_data = header[EI_DATA];
44738fd1498Szrj   if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
44838fd1498Szrj     {
44938fd1498Szrj       *errmsg = "unknown ELF endianness";
45038fd1498Szrj       *err = 0;
45138fd1498Szrj       return NULL;
45238fd1498Szrj     }
45338fd1498Szrj 
45438fd1498Szrj   ei_class = header[EI_CLASS];
45538fd1498Szrj   switch (ei_class)
45638fd1498Szrj     {
45738fd1498Szrj     case ELFCLASS32:
45838fd1498Szrj       type_functions = (ei_data == ELFDATA2LSB
45938fd1498Szrj 			? &elf_little_32_functions
46038fd1498Szrj 			: &elf_big_32_functions);
46138fd1498Szrj       break;
46238fd1498Szrj 
46338fd1498Szrj     case ELFCLASS64:
46438fd1498Szrj #ifndef UNSIGNED_64BIT_TYPE
46538fd1498Szrj       *errmsg = "64-bit ELF objects not supported";
46638fd1498Szrj       *err = 0;
46738fd1498Szrj       return NULL;
46838fd1498Szrj #else
46938fd1498Szrj       type_functions = (ei_data == ELFDATA2LSB
47038fd1498Szrj 			? &elf_little_64_functions
47138fd1498Szrj 			: &elf_big_64_functions);
47238fd1498Szrj       break;
47338fd1498Szrj #endif
47438fd1498Szrj 
47538fd1498Szrj     default:
47638fd1498Szrj       *errmsg = "unrecognized ELF size";
47738fd1498Szrj       *err = 0;
47838fd1498Szrj       return NULL;
47938fd1498Szrj     }
48038fd1498Szrj 
48138fd1498Szrj   if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
48238fd1498Szrj 				    errmsg, err))
48338fd1498Szrj     return NULL;
48438fd1498Szrj 
48538fd1498Szrj   eor = XNEW (struct simple_object_elf_read);
48638fd1498Szrj   eor->type_functions = type_functions;
48738fd1498Szrj   eor->ei_data = ei_data;
48838fd1498Szrj   eor->ei_class = ei_class;
48938fd1498Szrj   eor->ei_osabi = header[EI_OSABI];
49038fd1498Szrj   eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49138fd1498Szrj 				  e_machine, Elf_Half);
49238fd1498Szrj   eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49338fd1498Szrj 				e_flags, Elf_Word);
49438fd1498Szrj   eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49538fd1498Szrj 				e_shoff, Elf_Addr);
49638fd1498Szrj   eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49738fd1498Szrj 				e_shnum, Elf_Half);
49838fd1498Szrj   eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49938fd1498Szrj 				   e_shstrndx, Elf_Half);
50038fd1498Szrj 
50138fd1498Szrj   if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
50238fd1498Szrj       && eor->shoff != 0)
50338fd1498Szrj     {
50438fd1498Szrj       unsigned char shdr[sizeof (Elf64_External_Shdr)];
50538fd1498Szrj 
50638fd1498Szrj       /* Object file has more than 0xffff sections.  */
50738fd1498Szrj 
50838fd1498Szrj       if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
50938fd1498Szrj 					(ei_class == ELFCLASS32
51038fd1498Szrj 					 ? sizeof (Elf32_External_Shdr)
51138fd1498Szrj 					 : sizeof (Elf64_External_Shdr)),
51238fd1498Szrj 					errmsg, err))
51338fd1498Szrj 	{
51438fd1498Szrj 	  XDELETE (eor);
51538fd1498Szrj 	  return NULL;
51638fd1498Szrj 	}
51738fd1498Szrj 
51838fd1498Szrj       if (eor->shnum == 0)
51938fd1498Szrj 	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
52038fd1498Szrj 				      shdr, sh_size, Elf_Addr);
52138fd1498Szrj 
52238fd1498Szrj       if (eor->shstrndx == SHN_XINDEX)
52338fd1498Szrj 	{
52438fd1498Szrj 	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
52538fd1498Szrj 					   shdr, sh_link, Elf_Word);
52638fd1498Szrj 
52738fd1498Szrj 	  /* Versions of the GNU binutils between 2.12 and 2.18 did
52838fd1498Szrj 	     not handle objects with more than SHN_LORESERVE sections
52938fd1498Szrj 	     correctly.  All large section indexes were offset by
53038fd1498Szrj 	     0x100.  There is more information at
53138fd1498Szrj 	     http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
53238fd1498Szrj 	     Fortunately these object files are easy to detect, as the
53338fd1498Szrj 	     GNU binutils always put the section header string table
53438fd1498Szrj 	     near the end of the list of sections.  Thus if the
53538fd1498Szrj 	     section header string table index is larger than the
53638fd1498Szrj 	     number of sections, then we know we have to subtract
53738fd1498Szrj 	     0x100 to get the real section index.  */
53838fd1498Szrj 	  if (eor->shstrndx >= eor->shnum
53938fd1498Szrj 	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
54038fd1498Szrj 	    eor->shstrndx -= 0x100;
54138fd1498Szrj 	}
54238fd1498Szrj     }
54338fd1498Szrj 
54438fd1498Szrj   if (eor->shstrndx >= eor->shnum)
54538fd1498Szrj     {
54638fd1498Szrj       *errmsg = "invalid ELF shstrndx >= shnum";
54738fd1498Szrj       *err = 0;
54838fd1498Szrj       XDELETE (eor);
54938fd1498Szrj       return NULL;
55038fd1498Szrj     }
55138fd1498Szrj 
55238fd1498Szrj   return (void *) eor;
55338fd1498Szrj }
55438fd1498Szrj 
55538fd1498Szrj /* Find all sections in an ELF file.  */
55638fd1498Szrj 
55738fd1498Szrj 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)55838fd1498Szrj simple_object_elf_find_sections (simple_object_read *sobj,
55938fd1498Szrj 				 int (*pfn) (void *, const char *,
56038fd1498Szrj 					     off_t offset, off_t length),
56138fd1498Szrj 				 void *data,
56238fd1498Szrj 				 int *err)
56338fd1498Szrj {
56438fd1498Szrj   struct simple_object_elf_read *eor =
56538fd1498Szrj     (struct simple_object_elf_read *) sobj->data;
56638fd1498Szrj   const struct elf_type_functions *type_functions = eor->type_functions;
56738fd1498Szrj   unsigned char ei_class = eor->ei_class;
56838fd1498Szrj   size_t shdr_size;
56938fd1498Szrj   unsigned int shnum;
57038fd1498Szrj   unsigned char *shdrs;
57138fd1498Szrj   const char *errmsg;
57238fd1498Szrj   unsigned char *shstrhdr;
57338fd1498Szrj   size_t name_size;
57438fd1498Szrj   off_t shstroff;
57538fd1498Szrj   unsigned char *names;
57638fd1498Szrj   unsigned int i;
57738fd1498Szrj 
57838fd1498Szrj   shdr_size = (ei_class == ELFCLASS32
57938fd1498Szrj 	       ? sizeof (Elf32_External_Shdr)
58038fd1498Szrj 	       : sizeof (Elf64_External_Shdr));
58138fd1498Szrj 
58238fd1498Szrj   /* Read the section headers.  We skip section 0, which is not a
58338fd1498Szrj      useful section.  */
58438fd1498Szrj 
58538fd1498Szrj   shnum = eor->shnum;
58638fd1498Szrj   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
58738fd1498Szrj 
58838fd1498Szrj   if (!simple_object_internal_read (sobj->descriptor,
58938fd1498Szrj 				    sobj->offset + eor->shoff + shdr_size,
59038fd1498Szrj 				    shdrs,
59138fd1498Szrj 				    shdr_size * (shnum - 1),
59238fd1498Szrj 				    &errmsg, err))
59338fd1498Szrj     {
59438fd1498Szrj       XDELETEVEC (shdrs);
59538fd1498Szrj       return errmsg;
59638fd1498Szrj     }
59738fd1498Szrj 
59838fd1498Szrj   /* Read the section names.  */
59938fd1498Szrj 
60038fd1498Szrj   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
60138fd1498Szrj   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
60238fd1498Szrj 			       shstrhdr, sh_size, Elf_Addr);
60338fd1498Szrj   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
60438fd1498Szrj 			      shstrhdr, sh_offset, Elf_Addr);
60538fd1498Szrj   names = XNEWVEC (unsigned char, name_size);
60638fd1498Szrj   if (!simple_object_internal_read (sobj->descriptor,
60738fd1498Szrj 				    sobj->offset + shstroff,
60838fd1498Szrj 				    names, name_size, &errmsg, err))
60938fd1498Szrj     {
61038fd1498Szrj       XDELETEVEC (names);
61138fd1498Szrj       XDELETEVEC (shdrs);
61238fd1498Szrj       return errmsg;
61338fd1498Szrj     }
61438fd1498Szrj 
61538fd1498Szrj   for (i = 1; i < shnum; ++i)
61638fd1498Szrj     {
61738fd1498Szrj       unsigned char *shdr;
61838fd1498Szrj       unsigned int sh_name;
61938fd1498Szrj       const char *name;
62038fd1498Szrj       off_t offset;
62138fd1498Szrj       off_t length;
62238fd1498Szrj 
62338fd1498Szrj       shdr = shdrs + (i - 1) * shdr_size;
62438fd1498Szrj       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
62538fd1498Szrj 				 shdr, sh_name, Elf_Word);
62638fd1498Szrj       if (sh_name >= name_size)
62738fd1498Szrj 	{
62838fd1498Szrj 	  *err = 0;
62938fd1498Szrj 	  XDELETEVEC (names);
63038fd1498Szrj 	  XDELETEVEC (shdrs);
63138fd1498Szrj 	  return "ELF section name out of range";
63238fd1498Szrj 	}
63338fd1498Szrj 
63438fd1498Szrj       name = (const char *) names + sh_name;
63538fd1498Szrj       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
63638fd1498Szrj 				shdr, sh_offset, Elf_Addr);
63738fd1498Szrj       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
63838fd1498Szrj 				shdr, sh_size, Elf_Addr);
63938fd1498Szrj 
64038fd1498Szrj       if (!(*pfn) (data, name, offset, length))
64138fd1498Szrj 	break;
64238fd1498Szrj     }
64338fd1498Szrj 
64438fd1498Szrj   XDELETEVEC (names);
64538fd1498Szrj   XDELETEVEC (shdrs);
64638fd1498Szrj 
64738fd1498Szrj   return NULL;
64838fd1498Szrj }
64938fd1498Szrj 
65038fd1498Szrj /* Fetch the attributes for an simple_object_read.  */
65138fd1498Szrj 
65238fd1498Szrj static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)65338fd1498Szrj simple_object_elf_fetch_attributes (simple_object_read *sobj,
65438fd1498Szrj 				    const char **errmsg ATTRIBUTE_UNUSED,
65538fd1498Szrj 				    int *err ATTRIBUTE_UNUSED)
65638fd1498Szrj {
65738fd1498Szrj   struct simple_object_elf_read *eor =
65838fd1498Szrj     (struct simple_object_elf_read *) sobj->data;
65938fd1498Szrj   struct simple_object_elf_attributes *ret;
66038fd1498Szrj 
66138fd1498Szrj   ret = XNEW (struct simple_object_elf_attributes);
66238fd1498Szrj   ret->type_functions = eor->type_functions;
66338fd1498Szrj   ret->ei_data = eor->ei_data;
66438fd1498Szrj   ret->ei_class = eor->ei_class;
66538fd1498Szrj   ret->ei_osabi = eor->ei_osabi;
66638fd1498Szrj   ret->machine = eor->machine;
66738fd1498Szrj   ret->flags = eor->flags;
66838fd1498Szrj   return ret;
66938fd1498Szrj }
67038fd1498Szrj 
67138fd1498Szrj /* Release the privata data for an simple_object_read.  */
67238fd1498Szrj 
67338fd1498Szrj static void
simple_object_elf_release_read(void * data)67438fd1498Szrj simple_object_elf_release_read (void *data)
67538fd1498Szrj {
67638fd1498Szrj   XDELETE (data);
67738fd1498Szrj }
67838fd1498Szrj 
67938fd1498Szrj /* Compare two attributes structures.  */
68038fd1498Szrj 
68138fd1498Szrj static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)68238fd1498Szrj simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
68338fd1498Szrj {
68438fd1498Szrj   struct simple_object_elf_attributes *to =
68538fd1498Szrj     (struct simple_object_elf_attributes *) todata;
68638fd1498Szrj   struct simple_object_elf_attributes *from =
68738fd1498Szrj     (struct simple_object_elf_attributes *) fromdata;
68838fd1498Szrj 
68938fd1498Szrj   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
69038fd1498Szrj     {
69138fd1498Szrj       *err = 0;
69238fd1498Szrj       return "ELF object format mismatch";
69338fd1498Szrj     }
69438fd1498Szrj 
69538fd1498Szrj   if (to->machine != from->machine)
69638fd1498Szrj     {
69738fd1498Szrj       int ok;
69838fd1498Szrj 
69938fd1498Szrj       /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
70038fd1498Szrj 	 output of EM_SPARC32PLUS.  */
70138fd1498Szrj       ok = 0;
70238fd1498Szrj       switch (to->machine)
70338fd1498Szrj 	{
70438fd1498Szrj 	case EM_SPARC:
70538fd1498Szrj 	  if (from->machine == EM_SPARC32PLUS)
70638fd1498Szrj 	    {
70738fd1498Szrj 	      to->machine = from->machine;
70838fd1498Szrj 	      ok = 1;
70938fd1498Szrj 	    }
71038fd1498Szrj 	  break;
71138fd1498Szrj 
71238fd1498Szrj 	case EM_SPARC32PLUS:
71338fd1498Szrj 	  if (from->machine == EM_SPARC)
71438fd1498Szrj 	    ok = 1;
71538fd1498Szrj 	  break;
71638fd1498Szrj 
71738fd1498Szrj 	default:
71838fd1498Szrj 	  break;
71938fd1498Szrj 	}
72038fd1498Szrj 
72138fd1498Szrj       if (!ok)
72238fd1498Szrj 	{
72338fd1498Szrj 	  *err = 0;
72438fd1498Szrj 	  return "ELF machine number mismatch";
72538fd1498Szrj 	}
72638fd1498Szrj     }
72738fd1498Szrj 
72838fd1498Szrj   return NULL;
72938fd1498Szrj }
73038fd1498Szrj 
73138fd1498Szrj /* Release the private data for an attributes structure.  */
73238fd1498Szrj 
73338fd1498Szrj static void
simple_object_elf_release_attributes(void * data)73438fd1498Szrj simple_object_elf_release_attributes (void *data)
73538fd1498Szrj {
73638fd1498Szrj   XDELETE (data);
73738fd1498Szrj }
73838fd1498Szrj 
73938fd1498Szrj /* Prepare to write out a file.  */
74038fd1498Szrj 
74138fd1498Szrj static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)74238fd1498Szrj simple_object_elf_start_write (void *attributes_data,
74338fd1498Szrj 			       const char **errmsg ATTRIBUTE_UNUSED,
74438fd1498Szrj 			       int *err ATTRIBUTE_UNUSED)
74538fd1498Szrj {
74638fd1498Szrj   struct simple_object_elf_attributes *attrs =
74738fd1498Szrj     (struct simple_object_elf_attributes *) attributes_data;
74838fd1498Szrj   struct simple_object_elf_write *ret;
74938fd1498Szrj 
75038fd1498Szrj   /* We're just going to record the attributes, but we need to make a
75138fd1498Szrj      copy because the user may delete them.  */
75238fd1498Szrj   ret = XNEW (struct simple_object_elf_write);
75338fd1498Szrj   ret->attrs = *attrs;
75438fd1498Szrj   ret->shdrs = NULL;
75538fd1498Szrj   return ret;
75638fd1498Szrj }
75738fd1498Szrj 
75838fd1498Szrj /* Write out an ELF ehdr.  */
75938fd1498Szrj 
76038fd1498Szrj static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)76138fd1498Szrj simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
76238fd1498Szrj 			      const char **errmsg, int *err)
76338fd1498Szrj {
76438fd1498Szrj   struct simple_object_elf_attributes *attrs =
76538fd1498Szrj     (struct simple_object_elf_attributes *) sobj->data;
76638fd1498Szrj   const struct elf_type_functions* fns;
76738fd1498Szrj   unsigned char cl;
76838fd1498Szrj   size_t ehdr_size;
76938fd1498Szrj   unsigned char buf[sizeof (Elf64_External_Ehdr)];
77038fd1498Szrj   simple_object_write_section *section;
77138fd1498Szrj   unsigned int shnum;
77238fd1498Szrj   unsigned int shstrndx;
77338fd1498Szrj 
77438fd1498Szrj   fns = attrs->type_functions;
77538fd1498Szrj   cl = attrs->ei_class;
77638fd1498Szrj 
77738fd1498Szrj   shnum = 0;
77838fd1498Szrj   for (section = sobj->sections; section != NULL; section = section->next)
77938fd1498Szrj     ++shnum;
78038fd1498Szrj   if (shnum > 0)
78138fd1498Szrj     {
78238fd1498Szrj       /* Add a section header for the dummy section and one for
78338fd1498Szrj 	 .shstrtab.  */
78438fd1498Szrj       shnum += 2;
78538fd1498Szrj     }
78638fd1498Szrj 
78738fd1498Szrj   ehdr_size = (cl == ELFCLASS32
78838fd1498Szrj 	       ? sizeof (Elf32_External_Ehdr)
78938fd1498Szrj 	       : sizeof (Elf64_External_Ehdr));
79038fd1498Szrj   memset (buf, 0, sizeof (Elf64_External_Ehdr));
79138fd1498Szrj 
79238fd1498Szrj   buf[EI_MAG0] = ELFMAG0;
79338fd1498Szrj   buf[EI_MAG1] = ELFMAG1;
79438fd1498Szrj   buf[EI_MAG2] = ELFMAG2;
79538fd1498Szrj   buf[EI_MAG3] = ELFMAG3;
79638fd1498Szrj   buf[EI_CLASS] = cl;
79738fd1498Szrj   buf[EI_DATA] = attrs->ei_data;
79838fd1498Szrj   buf[EI_VERSION] = EV_CURRENT;
79938fd1498Szrj   buf[EI_OSABI] = attrs->ei_osabi;
80038fd1498Szrj 
80138fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
80238fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
80338fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
80438fd1498Szrj   /* e_entry left as zero.  */
80538fd1498Szrj   /* e_phoff left as zero.  */
80638fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
80738fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
80838fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
80938fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
81038fd1498Szrj 		 (cl == ELFCLASS32
81138fd1498Szrj 		  ? sizeof (Elf32_External_Phdr)
81238fd1498Szrj 		  : sizeof (Elf64_External_Phdr)));
81338fd1498Szrj   /* e_phnum left as zero.  */
81438fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
81538fd1498Szrj 		 (cl == ELFCLASS32
81638fd1498Szrj 		  ? sizeof (Elf32_External_Shdr)
81738fd1498Szrj 		  : sizeof (Elf64_External_Shdr)));
81838fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
81938fd1498Szrj 		 shnum >= SHN_LORESERVE ? 0 : shnum);
82038fd1498Szrj   if (shnum == 0)
82138fd1498Szrj     shstrndx = 0;
82238fd1498Szrj   else
82338fd1498Szrj     {
82438fd1498Szrj       shstrndx = shnum - 1;
82538fd1498Szrj       if (shstrndx >= SHN_LORESERVE)
82638fd1498Szrj 	shstrndx = SHN_XINDEX;
82738fd1498Szrj     }
82838fd1498Szrj   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
82938fd1498Szrj 
83038fd1498Szrj   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
83138fd1498Szrj 				       errmsg, err);
83238fd1498Szrj }
83338fd1498Szrj 
83438fd1498Szrj /* Write out an ELF shdr.  */
83538fd1498Szrj 
83638fd1498Szrj 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)83738fd1498Szrj simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
83838fd1498Szrj 			      off_t offset, unsigned int sh_name,
83938fd1498Szrj 			      unsigned int sh_type, unsigned int sh_flags,
84038fd1498Szrj 			      off_t sh_addr,
84138fd1498Szrj 			      unsigned int sh_offset, unsigned int sh_size,
84238fd1498Szrj 			      unsigned int sh_link, unsigned int sh_info,
84338fd1498Szrj 			      size_t sh_addralign,
84438fd1498Szrj 			      size_t sh_entsize,
84538fd1498Szrj 			      const char **errmsg, int *err)
84638fd1498Szrj {
84738fd1498Szrj   struct simple_object_elf_attributes *attrs =
84838fd1498Szrj     (struct simple_object_elf_attributes *) sobj->data;
84938fd1498Szrj   const struct elf_type_functions* fns;
85038fd1498Szrj   unsigned char cl;
85138fd1498Szrj   size_t shdr_size;
85238fd1498Szrj   unsigned char buf[sizeof (Elf64_External_Shdr)];
85338fd1498Szrj 
85438fd1498Szrj   fns = attrs->type_functions;
85538fd1498Szrj   cl = attrs->ei_class;
85638fd1498Szrj 
85738fd1498Szrj   shdr_size = (cl == ELFCLASS32
85838fd1498Szrj 	       ? sizeof (Elf32_External_Shdr)
85938fd1498Szrj 	       : sizeof (Elf64_External_Shdr));
86038fd1498Szrj   memset (buf, 0, sizeof (Elf64_External_Shdr));
86138fd1498Szrj 
86238fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
86338fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
86438fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
86538fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
86638fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
86738fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
86838fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
86938fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
87038fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
87138fd1498Szrj   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize);
87238fd1498Szrj 
87338fd1498Szrj   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
87438fd1498Szrj 				       errmsg, err);
87538fd1498Szrj }
87638fd1498Szrj 
87738fd1498Szrj /* Write out a complete ELF file.
87838fd1498Szrj    Ehdr
87938fd1498Szrj    initial dummy Shdr
88038fd1498Szrj    user-created Shdrs
88138fd1498Szrj    .shstrtab Shdr
88238fd1498Szrj    user-created section data
88338fd1498Szrj    .shstrtab data  */
88438fd1498Szrj 
88538fd1498Szrj static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)88638fd1498Szrj simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
88738fd1498Szrj 				 int *err)
88838fd1498Szrj {
88938fd1498Szrj   struct simple_object_elf_write *eow =
89038fd1498Szrj     (struct simple_object_elf_write *) sobj->data;
89138fd1498Szrj   struct simple_object_elf_attributes *attrs = &eow->attrs;
89238fd1498Szrj   unsigned char cl;
89338fd1498Szrj   size_t ehdr_size;
89438fd1498Szrj   size_t shdr_size;
89538fd1498Szrj   const char *errmsg;
89638fd1498Szrj   simple_object_write_section *section;
89738fd1498Szrj   unsigned int shnum;
89838fd1498Szrj   size_t shdr_offset;
89938fd1498Szrj   size_t sh_offset;
90038fd1498Szrj   unsigned int first_sh_size;
90138fd1498Szrj   unsigned int first_sh_link;
90238fd1498Szrj   size_t sh_name;
90338fd1498Szrj   unsigned char zero;
90438fd1498Szrj   unsigned secnum;
90538fd1498Szrj 
90638fd1498Szrj   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
90738fd1498Szrj     return errmsg;
90838fd1498Szrj 
90938fd1498Szrj   cl = attrs->ei_class;
91038fd1498Szrj   if (cl == ELFCLASS32)
91138fd1498Szrj     {
91238fd1498Szrj       ehdr_size = sizeof (Elf32_External_Ehdr);
91338fd1498Szrj       shdr_size = sizeof (Elf32_External_Shdr);
91438fd1498Szrj     }
91538fd1498Szrj   else
91638fd1498Szrj     {
91738fd1498Szrj       ehdr_size = sizeof (Elf64_External_Ehdr);
91838fd1498Szrj       shdr_size = sizeof (Elf64_External_Shdr);
91938fd1498Szrj     }
92038fd1498Szrj 
92138fd1498Szrj   shnum = 0;
92238fd1498Szrj   for (section = sobj->sections; section != NULL; section = section->next)
92338fd1498Szrj     ++shnum;
92438fd1498Szrj   if (shnum == 0)
92538fd1498Szrj     return NULL;
92638fd1498Szrj 
92738fd1498Szrj   /* Add initial dummy Shdr and .shstrtab.  */
92838fd1498Szrj   shnum += 2;
92938fd1498Szrj 
93038fd1498Szrj   shdr_offset = ehdr_size;
93138fd1498Szrj   sh_offset = shdr_offset + shnum * shdr_size;
93238fd1498Szrj 
93338fd1498Szrj   if (shnum < SHN_LORESERVE)
93438fd1498Szrj     first_sh_size = 0;
93538fd1498Szrj   else
93638fd1498Szrj     first_sh_size = shnum;
93738fd1498Szrj   if (shnum - 1 < SHN_LORESERVE)
93838fd1498Szrj     first_sh_link = 0;
93938fd1498Szrj   else
94038fd1498Szrj     first_sh_link = shnum - 1;
94138fd1498Szrj   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
94238fd1498Szrj 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
94338fd1498Szrj 				     0, 0, 0, &errmsg, err))
94438fd1498Szrj     return errmsg;
94538fd1498Szrj 
94638fd1498Szrj   shdr_offset += shdr_size;
94738fd1498Szrj 
94838fd1498Szrj   sh_name = 1;
94938fd1498Szrj   secnum = 0;
95038fd1498Szrj   for (section = sobj->sections; section != NULL; section = section->next)
95138fd1498Szrj     {
95238fd1498Szrj       size_t mask;
95338fd1498Szrj       size_t new_sh_offset;
95438fd1498Szrj       size_t sh_size;
95538fd1498Szrj       struct simple_object_write_section_buffer *buffer;
95638fd1498Szrj       unsigned int sh_type = SHT_PROGBITS;
95738fd1498Szrj       unsigned int sh_flags = 0;
95838fd1498Szrj       off_t sh_addr = 0;
95938fd1498Szrj       unsigned int sh_link = 0;
96038fd1498Szrj       unsigned int sh_info = 0;
96138fd1498Szrj       size_t sh_addralign = 1U << section->align;
96238fd1498Szrj       size_t sh_entsize = 0;
96338fd1498Szrj       if (eow->shdrs)
96438fd1498Szrj 	{
96538fd1498Szrj 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
96638fd1498Szrj 				     eow->shdrs + secnum * shdr_size,
96738fd1498Szrj 				     sh_type, Elf_Word);
96838fd1498Szrj 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
96938fd1498Szrj 				      eow->shdrs + secnum * shdr_size,
97038fd1498Szrj 				      sh_flags, Elf_Addr);
97138fd1498Szrj 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
97238fd1498Szrj 				     eow->shdrs + secnum * shdr_size,
97338fd1498Szrj 				     sh_addr, Elf_Addr);
97438fd1498Szrj 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
97538fd1498Szrj 				     eow->shdrs + secnum * shdr_size,
97638fd1498Szrj 				     sh_link, Elf_Word);
97738fd1498Szrj 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
97838fd1498Szrj 				     eow->shdrs + secnum * shdr_size,
97938fd1498Szrj 				     sh_info, Elf_Word);
98038fd1498Szrj 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
98138fd1498Szrj 					  eow->shdrs + secnum * shdr_size,
98238fd1498Szrj 					  sh_addralign, Elf_Addr);
98338fd1498Szrj 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
98438fd1498Szrj 					eow->shdrs + secnum * shdr_size,
98538fd1498Szrj 					sh_entsize, Elf_Addr);
98638fd1498Szrj 	  secnum++;
98738fd1498Szrj 	}
98838fd1498Szrj 
98938fd1498Szrj       mask = sh_addralign - 1;
99038fd1498Szrj       new_sh_offset = sh_offset + mask;
99138fd1498Szrj       new_sh_offset &= ~ mask;
99238fd1498Szrj       while (new_sh_offset > sh_offset)
99338fd1498Szrj 	{
99438fd1498Szrj 	  unsigned char zeroes[16];
99538fd1498Szrj 	  size_t write;
99638fd1498Szrj 
99738fd1498Szrj 	  memset (zeroes, 0, sizeof zeroes);
99838fd1498Szrj 	  write = new_sh_offset - sh_offset;
99938fd1498Szrj 	  if (write > sizeof zeroes)
100038fd1498Szrj 	    write = sizeof zeroes;
100138fd1498Szrj 	  if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
100238fd1498Szrj 					     write, &errmsg, err))
100338fd1498Szrj 	    return errmsg;
100438fd1498Szrj 	  sh_offset += write;
100538fd1498Szrj 	}
100638fd1498Szrj 
100738fd1498Szrj       sh_size = 0;
100838fd1498Szrj       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
100938fd1498Szrj 	{
101038fd1498Szrj 	  if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
101138fd1498Szrj 					     ((const unsigned char *)
101238fd1498Szrj 					      buffer->buffer),
101338fd1498Szrj 					     buffer->size, &errmsg, err))
101438fd1498Szrj 	    return errmsg;
101538fd1498Szrj 	  sh_size += buffer->size;
101638fd1498Szrj 	}
101738fd1498Szrj 
101838fd1498Szrj       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
101938fd1498Szrj 					 sh_name, sh_type, sh_flags,
102038fd1498Szrj 					 sh_addr, sh_offset,
102138fd1498Szrj 					 sh_size, sh_link, sh_info,
102238fd1498Szrj 					 sh_addralign, sh_entsize,
102338fd1498Szrj 					 &errmsg, err))
102438fd1498Szrj 	return errmsg;
102538fd1498Szrj 
102638fd1498Szrj       shdr_offset += shdr_size;
102738fd1498Szrj       sh_name += strlen (section->name) + 1;
102838fd1498Szrj       sh_offset += sh_size;
102938fd1498Szrj     }
103038fd1498Szrj 
103138fd1498Szrj   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
103238fd1498Szrj 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
103338fd1498Szrj 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
103438fd1498Szrj 				     1, 0, &errmsg, err))
103538fd1498Szrj     return errmsg;
103638fd1498Szrj 
103738fd1498Szrj   /* .shstrtab has a leading zero byte.  */
103838fd1498Szrj   zero = 0;
103938fd1498Szrj   if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
104038fd1498Szrj 				     &errmsg, err))
104138fd1498Szrj     return errmsg;
104238fd1498Szrj   ++sh_offset;
104338fd1498Szrj 
104438fd1498Szrj   for (section = sobj->sections; section != NULL; section = section->next)
104538fd1498Szrj     {
104638fd1498Szrj       size_t len;
104738fd1498Szrj 
104838fd1498Szrj       len = strlen (section->name) + 1;
104938fd1498Szrj       if (!simple_object_internal_write (descriptor, sh_offset,
105038fd1498Szrj 					 (const unsigned char *) section->name,
105138fd1498Szrj 					 len, &errmsg, err))
105238fd1498Szrj 	return errmsg;
105338fd1498Szrj       sh_offset += len;
105438fd1498Szrj     }
105538fd1498Szrj 
105638fd1498Szrj   if (!simple_object_internal_write (descriptor, sh_offset,
105738fd1498Szrj 				     (const unsigned char *) ".shstrtab",
105838fd1498Szrj 				     strlen (".shstrtab") + 1, &errmsg, err))
105938fd1498Szrj     return errmsg;
106038fd1498Szrj 
106138fd1498Szrj   return NULL;
106238fd1498Szrj }
106338fd1498Szrj 
106438fd1498Szrj /* Release the private data for an simple_object_write structure.  */
106538fd1498Szrj 
106638fd1498Szrj static void
simple_object_elf_release_write(void * data)106738fd1498Szrj simple_object_elf_release_write (void *data)
106838fd1498Szrj {
106938fd1498Szrj   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
107038fd1498Szrj   if (eow->shdrs)
107138fd1498Szrj     XDELETE (eow->shdrs);
107238fd1498Szrj   XDELETE (data);
107338fd1498Szrj }
107438fd1498Szrj 
107538fd1498Szrj /* Copy all sections in an ELF file.  */
107638fd1498Szrj 
107738fd1498Szrj static const char *
simple_object_elf_copy_lto_debug_sections(simple_object_read * sobj,simple_object_write * dobj,char * (* pfn)(const char *),int * err)107838fd1498Szrj simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
107938fd1498Szrj 					   simple_object_write *dobj,
108038fd1498Szrj 					   char *(*pfn) (const char *),
108138fd1498Szrj 					   int *err)
108238fd1498Szrj {
108338fd1498Szrj   struct simple_object_elf_read *eor =
108438fd1498Szrj     (struct simple_object_elf_read *) sobj->data;
108538fd1498Szrj   const struct elf_type_functions *type_functions = eor->type_functions;
108638fd1498Szrj   struct simple_object_elf_write *eow =
108738fd1498Szrj     (struct simple_object_elf_write *) dobj->data;
108838fd1498Szrj   unsigned char ei_class = eor->ei_class;
108938fd1498Szrj   size_t shdr_size;
109038fd1498Szrj   unsigned int shnum;
109138fd1498Szrj   unsigned char *shdrs;
109238fd1498Szrj   const char *errmsg;
109338fd1498Szrj   unsigned char *shstrhdr;
109438fd1498Szrj   size_t name_size;
109538fd1498Szrj   off_t shstroff;
109638fd1498Szrj   unsigned char *names;
109738fd1498Szrj   unsigned int i;
109838fd1498Szrj   int changed;
109938fd1498Szrj   int *pfnret;
110038fd1498Szrj   const char **pfnname;
110138fd1498Szrj   unsigned new_i;
110238fd1498Szrj   unsigned *sh_map;
110338fd1498Szrj   unsigned first_shndx = 0;
110438fd1498Szrj   unsigned int *symtab_indices_shndx;
110538fd1498Szrj 
110638fd1498Szrj   shdr_size = (ei_class == ELFCLASS32
110738fd1498Szrj 	       ? sizeof (Elf32_External_Shdr)
110838fd1498Szrj 	       : sizeof (Elf64_External_Shdr));
110938fd1498Szrj 
111038fd1498Szrj   /* Read the section headers.  We skip section 0, which is not a
111138fd1498Szrj      useful section.  */
111238fd1498Szrj 
111338fd1498Szrj   shnum = eor->shnum;
111438fd1498Szrj   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
111538fd1498Szrj 
111638fd1498Szrj   if (!simple_object_internal_read (sobj->descriptor,
111738fd1498Szrj 				    sobj->offset + eor->shoff + shdr_size,
111838fd1498Szrj 				    shdrs,
111938fd1498Szrj 				    shdr_size * (shnum - 1),
112038fd1498Szrj 				    &errmsg, err))
112138fd1498Szrj     {
112238fd1498Szrj       XDELETEVEC (shdrs);
112338fd1498Szrj       return errmsg;
112438fd1498Szrj     }
112538fd1498Szrj 
112638fd1498Szrj   /* Read the section names.  */
112738fd1498Szrj 
112838fd1498Szrj   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
112938fd1498Szrj   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
113038fd1498Szrj 			       shstrhdr, sh_size, Elf_Addr);
113138fd1498Szrj   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
113238fd1498Szrj 			      shstrhdr, sh_offset, Elf_Addr);
113338fd1498Szrj   names = XNEWVEC (unsigned char, name_size);
113438fd1498Szrj   if (!simple_object_internal_read (sobj->descriptor,
113538fd1498Szrj 				    sobj->offset + shstroff,
113638fd1498Szrj 				    names, name_size, &errmsg, err))
113738fd1498Szrj     {
113838fd1498Szrj       XDELETEVEC (names);
113938fd1498Szrj       XDELETEVEC (shdrs);
114038fd1498Szrj       return errmsg;
114138fd1498Szrj     }
114238fd1498Szrj 
114338fd1498Szrj   pfnret = XNEWVEC (int, shnum);
114438fd1498Szrj   pfnname = XNEWVEC (const char *, shnum);
114538fd1498Szrj 
114638fd1498Szrj   /* Map of symtab to index section.  */
114738fd1498Szrj   symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1);
114838fd1498Szrj 
114938fd1498Szrj   /* First perform the callbacks to know which sections to preserve and
115038fd1498Szrj      what name to use for those.  */
115138fd1498Szrj   for (i = 1; i < shnum; ++i)
115238fd1498Szrj     {
115338fd1498Szrj       unsigned char *shdr;
115438fd1498Szrj       unsigned int sh_name, sh_type;
115538fd1498Szrj       const char *name;
115638fd1498Szrj       char *ret;
115738fd1498Szrj 
115838fd1498Szrj       shdr = shdrs + (i - 1) * shdr_size;
115938fd1498Szrj       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
116038fd1498Szrj 				 shdr, sh_name, Elf_Word);
116138fd1498Szrj       if (sh_name >= name_size)
116238fd1498Szrj 	{
116338fd1498Szrj 	  *err = 0;
116438fd1498Szrj 	  XDELETEVEC (names);
116538fd1498Szrj 	  XDELETEVEC (shdrs);
116638fd1498Szrj 	  return "ELF section name out of range";
116738fd1498Szrj 	}
116838fd1498Szrj 
116938fd1498Szrj       name = (const char *) names + sh_name;
117038fd1498Szrj 
117138fd1498Szrj       ret = (*pfn) (name);
117238fd1498Szrj       pfnret[i - 1] = ret == NULL ? -1 : 0;
117338fd1498Szrj       pfnname[i - 1] = ret == NULL ? name : ret;
117438fd1498Szrj       if (first_shndx == 0
117538fd1498Szrj 	  && pfnret[i - 1] == 0)
117638fd1498Szrj 	first_shndx = i;
117738fd1498Szrj 
117838fd1498Szrj       /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections.  */
117938fd1498Szrj       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
118038fd1498Szrj 				 shdr, sh_type, Elf_Word);
118138fd1498Szrj       if (sh_type == SHT_SYMTAB_SHNDX)
118238fd1498Szrj 	{
118338fd1498Szrj 	  unsigned int sh_link;
118438fd1498Szrj 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
118538fd1498Szrj 				     shdr, sh_link, Elf_Word);
118638fd1498Szrj 	  symtab_indices_shndx[sh_link - 1] = i;
118738fd1498Szrj 	  /* Always discard the extended index sections, after
118838fd1498Szrj 	     copying it will not be needed.  This way we don't need to
118938fd1498Szrj 	     update it and deal with the ordering constraints of
119038fd1498Szrj 	     processing the existing symtab and changing the index.  */
119138fd1498Szrj 	  pfnret[i - 1] = -1;
119238fd1498Szrj 	}
119338fd1498Szrj     }
119438fd1498Szrj 
119538fd1498Szrj   /* Mark sections as preserved that are required by to be preserved
119638fd1498Szrj      sections.  */
119738fd1498Szrj   do
119838fd1498Szrj     {
119938fd1498Szrj       changed = 0;
120038fd1498Szrj       for (i = 1; i < shnum; ++i)
120138fd1498Szrj 	{
120238fd1498Szrj 	  unsigned char *shdr;
120338fd1498Szrj 	  unsigned int sh_type, sh_info, sh_link;
120438fd1498Szrj 	  off_t offset;
120538fd1498Szrj 	  off_t length;
120638fd1498Szrj 
120738fd1498Szrj 	  shdr = shdrs + (i - 1) * shdr_size;
120838fd1498Szrj 	  sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
120938fd1498Szrj 				     shdr, sh_type, Elf_Word);
121038fd1498Szrj 	  sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
121138fd1498Szrj 				     shdr, sh_info, Elf_Word);
121238fd1498Szrj 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
121338fd1498Szrj 				     shdr, sh_link, Elf_Word);
121438fd1498Szrj 	  if (sh_type == SHT_GROUP)
121538fd1498Szrj 	    {
121638fd1498Szrj 	      /* Mark groups containing copied sections.  */
121738fd1498Szrj 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class,
121838fd1498Szrj 						  Shdr, shdr, sh_entsize,
121938fd1498Szrj 						  Elf_Addr);
122038fd1498Szrj 	      unsigned char *ent, *buf;
122138fd1498Szrj 	      int keep = 0;
122238fd1498Szrj 	      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
122338fd1498Szrj 					shdr, sh_offset, Elf_Addr);
122438fd1498Szrj 	      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
122538fd1498Szrj 					shdr, sh_size, Elf_Addr);
122638fd1498Szrj 	      buf = XNEWVEC (unsigned char, length);
122738fd1498Szrj 	      if (!simple_object_internal_read (sobj->descriptor,
122838fd1498Szrj 						sobj->offset + offset, buf,
122938fd1498Szrj 						(size_t) length, &errmsg, err))
123038fd1498Szrj 		{
123138fd1498Szrj 		  XDELETEVEC (buf);
123238fd1498Szrj 		  XDELETEVEC (names);
123338fd1498Szrj 		  XDELETEVEC (shdrs);
123438fd1498Szrj 		  return errmsg;
123538fd1498Szrj 		}
123638fd1498Szrj 	      for (ent = buf + entsize; ent < buf + length; ent += entsize)
123738fd1498Szrj 		{
123838fd1498Szrj 		  unsigned sec = type_functions->fetch_Elf_Word (ent);
123938fd1498Szrj 		  if (pfnret[sec - 1] == 0)
124038fd1498Szrj 		    keep = 1;
124138fd1498Szrj 		}
124238fd1498Szrj 	      if (keep)
124338fd1498Szrj 		{
124438fd1498Szrj 		  changed |= (pfnret[sh_link - 1] == -1
124538fd1498Szrj 			      || pfnret[i - 1] == -1);
124638fd1498Szrj 		  pfnret[sh_link - 1] = 0;
124738fd1498Szrj 		  pfnret[i - 1] = 0;
124838fd1498Szrj 		}
124938fd1498Szrj 	    }
125038fd1498Szrj 	  if (sh_type == SHT_RELA
125138fd1498Szrj 	      || sh_type == SHT_REL)
125238fd1498Szrj 	    {
125338fd1498Szrj 	      /* Mark relocation sections and symtab of copied sections.  */
125438fd1498Szrj 	      if (pfnret[sh_info - 1] == 0)
125538fd1498Szrj 		{
125638fd1498Szrj 		  changed |= (pfnret[sh_link - 1] == -1
125738fd1498Szrj 			      || pfnret[i - 1] == -1);
125838fd1498Szrj 		  pfnret[sh_link - 1] = 0;
125938fd1498Szrj 		  pfnret[i - 1] = 0;
126038fd1498Szrj 		}
126138fd1498Szrj 	    }
126238fd1498Szrj 	  if (sh_type == SHT_SYMTAB)
126338fd1498Szrj 	    {
126438fd1498Szrj 	      /* Mark strings sections of copied symtabs.  */
126538fd1498Szrj 	      if (pfnret[i - 1] == 0)
126638fd1498Szrj 		{
126738fd1498Szrj 		  changed |= pfnret[sh_link - 1] == -1;
126838fd1498Szrj 		  pfnret[sh_link - 1] = 0;
126938fd1498Szrj 		}
127038fd1498Szrj 	    }
127138fd1498Szrj 	}
127238fd1498Szrj     }
127338fd1498Szrj   while (changed);
127438fd1498Szrj 
127538fd1498Szrj   /* Compute a mapping of old -> new section numbers.  */
127638fd1498Szrj   sh_map = XNEWVEC (unsigned, shnum);
127738fd1498Szrj   sh_map[0] = 0;
127838fd1498Szrj   new_i = 1;
127938fd1498Szrj   for (i = 1; i < shnum; ++i)
128038fd1498Szrj     {
128138fd1498Szrj       if (pfnret[i - 1] == -1)
128238fd1498Szrj 	sh_map[i] = 0;
128338fd1498Szrj       else
128438fd1498Szrj 	sh_map[i] = new_i++;
128538fd1498Szrj     }
128638fd1498Szrj   if (new_i - 1 >= SHN_LORESERVE)
128738fd1498Szrj     {
128838fd1498Szrj       *err = ENOTSUP;
128938fd1498Szrj       return "Too many copied sections";
129038fd1498Szrj     }
129138fd1498Szrj   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
129238fd1498Szrj 
129338fd1498Szrj   /* Then perform the actual copying.  */
129438fd1498Szrj   new_i = 0;
129538fd1498Szrj   for (i = 1; i < shnum; ++i)
129638fd1498Szrj     {
129738fd1498Szrj       unsigned char *shdr;
129838fd1498Szrj       unsigned int sh_name, sh_type;
129938fd1498Szrj       const char *name;
130038fd1498Szrj       off_t offset;
130138fd1498Szrj       off_t length;
130238fd1498Szrj       simple_object_write_section *dest;
130338fd1498Szrj       off_t flags;
130438fd1498Szrj       unsigned char *buf;
130538fd1498Szrj 
130638fd1498Szrj       if (pfnret[i - 1])
130738fd1498Szrj 	continue;
130838fd1498Szrj 
130938fd1498Szrj       new_i++;
131038fd1498Szrj       shdr = shdrs + (i - 1) * shdr_size;
131138fd1498Szrj       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
131238fd1498Szrj 				 shdr, sh_name, Elf_Word);
131338fd1498Szrj       if (sh_name >= name_size)
131438fd1498Szrj 	{
131538fd1498Szrj 	  *err = 0;
131638fd1498Szrj 	  XDELETEVEC (names);
131738fd1498Szrj 	  XDELETEVEC (shdrs);
131838fd1498Szrj 	  XDELETEVEC (symtab_indices_shndx);
131938fd1498Szrj 	  return "ELF section name out of range";
132038fd1498Szrj 	}
132138fd1498Szrj 
132238fd1498Szrj       name = pfnname[i - 1];
132338fd1498Szrj       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
132438fd1498Szrj 				shdr, sh_offset, Elf_Addr);
132538fd1498Szrj       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
132638fd1498Szrj 				shdr, sh_size, Elf_Addr);
132738fd1498Szrj       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
132838fd1498Szrj 				 shdr, sh_type, Elf_Word);
132938fd1498Szrj 
133038fd1498Szrj       dest = simple_object_write_create_section (dobj, pfnname[i - 1],
133138fd1498Szrj 						 0, &errmsg, err);
133238fd1498Szrj       if (dest == NULL)
133338fd1498Szrj 	{
133438fd1498Szrj 	  XDELETEVEC (names);
133538fd1498Szrj 	  XDELETEVEC (shdrs);
133638fd1498Szrj 	  XDELETEVEC (symtab_indices_shndx);
133738fd1498Szrj 	  return errmsg;
133838fd1498Szrj 	}
133938fd1498Szrj 
134038fd1498Szrj       /* Record the SHDR of the source.  */
134138fd1498Szrj       memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size);
134238fd1498Szrj       shdr = eow->shdrs + (new_i - 1) * shdr_size;
134338fd1498Szrj 
134438fd1498Szrj       /* Copy the data.
134538fd1498Szrj 	 ???  This is quite wasteful and ideally would be delayed until
134638fd1498Szrj 	 write_to_file ().  Thus it questions the interfacing
134738fd1498Szrj 	 which eventually should contain destination creation plus
134838fd1498Szrj 	 writing.  */
134938fd1498Szrj       buf = XNEWVEC (unsigned char, length);
135038fd1498Szrj       if (!simple_object_internal_read (sobj->descriptor,
135138fd1498Szrj 					sobj->offset + offset, buf,
135238fd1498Szrj 					(size_t) length, &errmsg, err))
135338fd1498Szrj 	{
135438fd1498Szrj 	  XDELETEVEC (buf);
135538fd1498Szrj 	  XDELETEVEC (names);
135638fd1498Szrj 	  XDELETEVEC (shdrs);
135738fd1498Szrj 	  XDELETEVEC (symtab_indices_shndx);
135838fd1498Szrj 	  return errmsg;
135938fd1498Szrj 	}
136038fd1498Szrj 
136138fd1498Szrj       /* If we are processing .symtab purge __gnu_lto_v1 and
136238fd1498Szrj 	 __gnu_lto_slim symbols from it and any symbols in discarded
136338fd1498Szrj 	 sections.  */
136438fd1498Szrj       if (sh_type == SHT_SYMTAB)
136538fd1498Szrj 	{
136638fd1498Szrj 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
136738fd1498Szrj 					      shdr, sh_entsize, Elf_Addr);
136838fd1498Szrj 	  unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
136938fd1498Szrj 					     shdr, sh_link, Elf_Word);
137038fd1498Szrj 	  unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
137138fd1498Szrj 	  off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
137238fd1498Szrj 					  strshdr, sh_offset, Elf_Addr);
137338fd1498Szrj 	  size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
137438fd1498Szrj 					  strshdr, sh_size, Elf_Addr);
137538fd1498Szrj 	  char *strings = XNEWVEC (char, strsz);
137638fd1498Szrj 	  char *gnu_lto = strings;
137738fd1498Szrj 	  unsigned char *ent;
137838fd1498Szrj 	  unsigned *shndx_table = NULL;
137938fd1498Szrj 	  simple_object_internal_read (sobj->descriptor,
138038fd1498Szrj 				       sobj->offset + stroff,
138138fd1498Szrj 				       (unsigned char *)strings,
138238fd1498Szrj 				       strsz, &errmsg, err);
138338fd1498Szrj 	  /* Find gnu_lto_ in strings.  */
138438fd1498Szrj 	  while ((gnu_lto = (char *) memchr (gnu_lto, 'g',
138538fd1498Szrj 					     strings + strsz - gnu_lto)))
138638fd1498Szrj 	    if (strncmp (gnu_lto, "gnu_lto_v1",
138738fd1498Szrj 			 strings + strsz - gnu_lto) == 0)
138838fd1498Szrj 	      break;
138938fd1498Szrj 	    else
139038fd1498Szrj 	      gnu_lto++;
139138fd1498Szrj 	  /* Read the section index table if present.  */
139238fd1498Szrj 	  if (symtab_indices_shndx[i - 1] != 0)
139338fd1498Szrj 	    {
139438fd1498Szrj 	      unsigned char *sidxhdr = shdrs + (strtab - 1) * shdr_size;
139538fd1498Szrj 	      off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
139638fd1498Szrj 					       sidxhdr, sh_offset, Elf_Addr);
139738fd1498Szrj 	      size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
139838fd1498Szrj 					       sidxhdr, sh_size, Elf_Addr);
139938fd1498Szrj 	      shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
140038fd1498Szrj 	      simple_object_internal_read (sobj->descriptor,
140138fd1498Szrj 					   sobj->offset + sidxoff,
140238fd1498Szrj 					   (unsigned char *)shndx_table,
140338fd1498Szrj 					   sidxsz, &errmsg, err);
140438fd1498Szrj 	    }
140538fd1498Szrj 	  for (ent = buf; ent < buf + length; ent += entsize)
140638fd1498Szrj 	    {
140738fd1498Szrj 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
140838fd1498Szrj 						   Sym, ent,
140938fd1498Szrj 						   st_shndx, Elf_Half);
141038fd1498Szrj 	      unsigned raw_st_shndx = st_shndx;
141138fd1498Szrj 	      unsigned char *st_info;
141238fd1498Szrj 	      unsigned char *st_other;
141338fd1498Szrj 	      int discard = 0;
141438fd1498Szrj 	      if (ei_class == ELFCLASS32)
141538fd1498Szrj 		{
141638fd1498Szrj 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
141738fd1498Szrj 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
141838fd1498Szrj 		}
141938fd1498Szrj 	      else
142038fd1498Szrj 		{
142138fd1498Szrj 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
142238fd1498Szrj 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
142338fd1498Szrj 		}
142438fd1498Szrj 	      if (st_shndx == SHN_XINDEX)
142538fd1498Szrj 		st_shndx = type_functions->fetch_Elf_Word
142638fd1498Szrj 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
142738fd1498Szrj 	      /* Eliminate all COMMONs - this includes __gnu_lto_v1
142838fd1498Szrj 		 and __gnu_lto_slim which otherwise cause endless
142938fd1498Szrj 		 LTO plugin invocation.  */
143038fd1498Szrj 	      if (st_shndx == SHN_COMMON)
143138fd1498Szrj 		discard = 1;
143238fd1498Szrj 	      /* We also need to remove symbols refering to sections
143338fd1498Szrj 		 we'll eventually remove as with fat LTO objects
143438fd1498Szrj 		 we otherwise get duplicate symbols at final link
143538fd1498Szrj 		 (with GNU ld, gold is fine and ignores symbols in
143638fd1498Szrj 		 sections marked as EXCLUDE).  ld/20513  */
143738fd1498Szrj 	      else if (st_shndx != SHN_UNDEF
143838fd1498Szrj 		       && st_shndx < shnum
143938fd1498Szrj 		       && pfnret[st_shndx - 1] == -1)
144038fd1498Szrj 		discard = 1;
144138fd1498Szrj 
144238fd1498Szrj 	      if (discard)
144338fd1498Szrj 		{
144438fd1498Szrj 		  /* Make discarded symbols undefined and unnamed
144538fd1498Szrj 		     in case it is local.  */
144638fd1498Szrj 		  int bind = ELF_ST_BIND (*st_info);
144738fd1498Szrj 		  int other = STV_DEFAULT;
144838fd1498Szrj 		  if (bind == STB_LOCAL)
144938fd1498Szrj 		    {
145038fd1498Szrj 		      /* Make discarded local symbols unnamed and
145138fd1498Szrj 			 defined in the first prevailing section.  */
145238fd1498Szrj 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
145338fd1498Szrj 				     ent, st_name, Elf_Word, 0);
145438fd1498Szrj 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
145538fd1498Szrj 				     ent, st_shndx, Elf_Half,
145638fd1498Szrj 				     sh_map[first_shndx]);
145738fd1498Szrj 		    }
145838fd1498Szrj 		  else
145938fd1498Szrj 		    {
146038fd1498Szrj 		      /* Make discarded global symbols hidden weak
146138fd1498Szrj 			 undefined and sharing the gnu_lto_ name.  */
146238fd1498Szrj 		      bind = STB_WEAK;
146338fd1498Szrj 		      other = STV_HIDDEN;
146438fd1498Szrj 		      if (gnu_lto)
146538fd1498Szrj 			ELF_SET_FIELD (type_functions, ei_class, Sym,
146638fd1498Szrj 				       ent, st_name, Elf_Word,
146738fd1498Szrj 				       gnu_lto - strings);
146838fd1498Szrj 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
146938fd1498Szrj 				     ent, st_shndx, Elf_Half, SHN_UNDEF);
147038fd1498Szrj 		    }
147138fd1498Szrj 		  *st_other = other;
147238fd1498Szrj 		  *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
147338fd1498Szrj 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
147438fd1498Szrj 				 ent, st_value, Elf_Addr, 0);
147538fd1498Szrj 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
147638fd1498Szrj 				 ent, st_size, Elf_Word, 0);
147738fd1498Szrj 		}
147838fd1498Szrj 	      else if (raw_st_shndx < SHN_LORESERVE
147938fd1498Szrj 		       || raw_st_shndx == SHN_XINDEX)
148038fd1498Szrj 		/* Remap the section reference.  */
148138fd1498Szrj 		ELF_SET_FIELD (type_functions, ei_class, Sym,
148238fd1498Szrj 			       ent, st_shndx, Elf_Half, sh_map[st_shndx]);
148338fd1498Szrj 	    }
148438fd1498Szrj 	  XDELETEVEC (strings);
148538fd1498Szrj 	  XDELETEVEC (shndx_table);
148638fd1498Szrj 	}
148738fd1498Szrj       else if (sh_type == SHT_GROUP)
148838fd1498Szrj 	{
148938fd1498Szrj 	  /* Remap section indices in groups and remove removed members.  */
149038fd1498Szrj 	  unsigned char *ent, *dst;
149138fd1498Szrj 	  for (dst = ent = buf + 4; ent < buf + length; ent += 4)
149238fd1498Szrj 	    {
149338fd1498Szrj 	      unsigned shndx = type_functions->fetch_Elf_Word (ent);
149438fd1498Szrj 	      if (pfnret[shndx - 1] == -1)
149538fd1498Szrj 		;
149638fd1498Szrj 	      else
149738fd1498Szrj 		{
149838fd1498Szrj 		  type_functions->set_Elf_Word (dst, sh_map[shndx]);
149938fd1498Szrj 		  dst += 4;
150038fd1498Szrj 		}
150138fd1498Szrj 	    }
150238fd1498Szrj 	  /* Adjust the length.  */
150338fd1498Szrj 	  length = dst - buf;
150438fd1498Szrj 	}
150538fd1498Szrj 
150638fd1498Szrj       errmsg = simple_object_write_add_data (dobj, dest,
150738fd1498Szrj 					     buf, length, 1, err);
150838fd1498Szrj       XDELETEVEC (buf);
150938fd1498Szrj       if (errmsg)
151038fd1498Szrj 	{
151138fd1498Szrj 	  XDELETEVEC (names);
151238fd1498Szrj 	  XDELETEVEC (shdrs);
151338fd1498Szrj 	  XDELETEVEC (symtab_indices_shndx);
151438fd1498Szrj 	  return errmsg;
151538fd1498Szrj 	}
151638fd1498Szrj 
151738fd1498Szrj       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
151838fd1498Szrj 			       shdr, sh_flags, Elf_Addr);
151938fd1498Szrj       /* Remap the section references.  */
152038fd1498Szrj       {
152138fd1498Szrj 	unsigned int sh_info, sh_link;
152238fd1498Szrj 	if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA)
152338fd1498Szrj 	  {
152438fd1498Szrj 	    sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
152538fd1498Szrj 				       shdr, sh_info, Elf_Word);
152638fd1498Szrj 	    if (sh_info < SHN_LORESERVE
152738fd1498Szrj 		|| sh_info > SHN_HIRESERVE)
152838fd1498Szrj 	      sh_info = sh_map[sh_info];
152938fd1498Szrj 	    ELF_SET_FIELD (type_functions, ei_class, Shdr,
153038fd1498Szrj 			   shdr, sh_info, Elf_Word, sh_info);
153138fd1498Szrj 	  }
153238fd1498Szrj 	sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
153338fd1498Szrj 				   shdr, sh_link, Elf_Word);
153438fd1498Szrj 	if (sh_link < SHN_LORESERVE
153538fd1498Szrj 	    || sh_link > SHN_HIRESERVE)
153638fd1498Szrj 	  sh_link = sh_map[sh_link];
153738fd1498Szrj 	ELF_SET_FIELD (type_functions, ei_class, Shdr,
153838fd1498Szrj 		       shdr, sh_link, Elf_Word, sh_link);
153938fd1498Szrj       }
154038fd1498Szrj       /* The debugobj doesn't contain any code, thus no trampolines.
154138fd1498Szrj 	 Even when the original object needs trampolines, debugobj
154238fd1498Szrj 	 doesn't.  */
154338fd1498Szrj       if (strcmp (name, ".note.GNU-stack") == 0)
154438fd1498Szrj 	flags &= ~SHF_EXECINSTR;
154538fd1498Szrj       /* Clear SHF_EXCLUDE on to be preserved sections.  */
154638fd1498Szrj       flags &= ~SHF_EXCLUDE;
154738fd1498Szrj       ELF_SET_FIELD (type_functions, ei_class, Shdr,
154838fd1498Szrj 		     shdr, sh_flags, Elf_Addr, flags);
154938fd1498Szrj     }
155038fd1498Szrj 
155138fd1498Szrj   XDELETEVEC (names);
155238fd1498Szrj   XDELETEVEC (shdrs);
155338fd1498Szrj   XDELETEVEC (pfnret);
155438fd1498Szrj   XDELETEVEC (pfnname);
155538fd1498Szrj   XDELETEVEC (symtab_indices_shndx);
155638fd1498Szrj   XDELETEVEC (sh_map);
155738fd1498Szrj 
155838fd1498Szrj   return NULL;
155938fd1498Szrj }
156038fd1498Szrj 
156138fd1498Szrj 
156238fd1498Szrj /* The ELF functions.  */
156338fd1498Szrj 
156438fd1498Szrj const struct simple_object_functions simple_object_elf_functions =
156538fd1498Szrj {
156638fd1498Szrj   simple_object_elf_match,
156738fd1498Szrj   simple_object_elf_find_sections,
156838fd1498Szrj   simple_object_elf_fetch_attributes,
156938fd1498Szrj   simple_object_elf_release_read,
157038fd1498Szrj   simple_object_elf_attributes_merge,
157138fd1498Szrj   simple_object_elf_release_attributes,
157238fd1498Szrj   simple_object_elf_start_write,
157338fd1498Szrj   simple_object_elf_write_to_file,
157438fd1498Szrj   simple_object_elf_release_write,
157538fd1498Szrj   simple_object_elf_copy_lto_debug_sections
157638fd1498Szrj };
1577