xref: /netbsd-src/external/gpl3/gcc/dist/libiberty/simple-object-elf.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
148fb7bfaSmrg /* simple-object-elf.c -- routines to manipulate ELF object files.
2*b1e83836Smrg    Copyright (C) 2010-2022 Free Software Foundation, Inc.
348fb7bfaSmrg    Written by Ian Lance Taylor, Google.
448fb7bfaSmrg 
548fb7bfaSmrg This program is free software; you can redistribute it and/or modify it
648fb7bfaSmrg under the terms of the GNU General Public License as published by the
748fb7bfaSmrg Free Software Foundation; either version 2, or (at your option) any
848fb7bfaSmrg later version.
948fb7bfaSmrg 
1048fb7bfaSmrg This program is distributed in the hope that it will be useful,
1148fb7bfaSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1248fb7bfaSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1348fb7bfaSmrg GNU General Public License for more details.
1448fb7bfaSmrg 
1548fb7bfaSmrg You should have received a copy of the GNU General Public License
1648fb7bfaSmrg along with this program; if not, write to the Free Software
1748fb7bfaSmrg Foundation, 51 Franklin Street - Fifth Floor,
1848fb7bfaSmrg Boston, MA 02110-1301, USA.  */
1948fb7bfaSmrg 
2048fb7bfaSmrg #include "config.h"
2148fb7bfaSmrg #include "libiberty.h"
2248fb7bfaSmrg #include "simple-object.h"
2348fb7bfaSmrg 
2448fb7bfaSmrg #include <errno.h>
25a3e9eb18Smrg /* mingw.org's MinGW doesn't have ENOTSUP.  */
26a3e9eb18Smrg #ifndef ENOTSUP
27a3e9eb18Smrg # define ENOTSUP ENOSYS
28a3e9eb18Smrg #endif
2948fb7bfaSmrg #include <stddef.h>
3048fb7bfaSmrg 
3148fb7bfaSmrg #ifdef HAVE_STDLIB_H
3248fb7bfaSmrg #include <stdlib.h>
3348fb7bfaSmrg #endif
3448fb7bfaSmrg 
3548fb7bfaSmrg #ifdef HAVE_STDINT_H
3648fb7bfaSmrg #include <stdint.h>
3748fb7bfaSmrg #endif
3848fb7bfaSmrg 
3948fb7bfaSmrg #ifdef HAVE_STRING_H
4048fb7bfaSmrg #include <string.h>
4148fb7bfaSmrg #endif
4248fb7bfaSmrg 
4348fb7bfaSmrg #ifdef HAVE_INTTYPES_H
4448fb7bfaSmrg #include <inttypes.h>
4548fb7bfaSmrg #endif
4648fb7bfaSmrg 
4748fb7bfaSmrg #include "simple-object-common.h"
4848fb7bfaSmrg 
4948fb7bfaSmrg /* ELF structures and constants.  */
5048fb7bfaSmrg 
5148fb7bfaSmrg /* 32-bit ELF file header.  */
5248fb7bfaSmrg 
5348fb7bfaSmrg typedef struct {
5448fb7bfaSmrg   unsigned char	e_ident[16];		/* ELF "magic number" */
5548fb7bfaSmrg   unsigned char	e_type[2];		/* Identifies object file type */
5648fb7bfaSmrg   unsigned char	e_machine[2];		/* Specifies required architecture */
5748fb7bfaSmrg   unsigned char	e_version[4];		/* Identifies object file version */
5848fb7bfaSmrg   unsigned char	e_entry[4];		/* Entry point virtual address */
5948fb7bfaSmrg   unsigned char	e_phoff[4];		/* Program header table file offset */
6048fb7bfaSmrg   unsigned char	e_shoff[4];		/* Section header table file offset */
6148fb7bfaSmrg   unsigned char	e_flags[4];		/* Processor-specific flags */
6248fb7bfaSmrg   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
6348fb7bfaSmrg   unsigned char	e_phentsize[2];		/* Program header table entry size */
6448fb7bfaSmrg   unsigned char	e_phnum[2];		/* Program header table entry count */
6548fb7bfaSmrg   unsigned char	e_shentsize[2];		/* Section header table entry size */
6648fb7bfaSmrg   unsigned char	e_shnum[2];		/* Section header table entry count */
6748fb7bfaSmrg   unsigned char	e_shstrndx[2];		/* Section header string table index */
6848fb7bfaSmrg } Elf32_External_Ehdr;
6948fb7bfaSmrg 
7048fb7bfaSmrg /* 64-bit ELF file header.  */
7148fb7bfaSmrg 
7248fb7bfaSmrg typedef struct {
7348fb7bfaSmrg   unsigned char	e_ident[16];		/* ELF "magic number" */
7448fb7bfaSmrg   unsigned char	e_type[2];		/* Identifies object file type */
7548fb7bfaSmrg   unsigned char	e_machine[2];		/* Specifies required architecture */
7648fb7bfaSmrg   unsigned char	e_version[4];		/* Identifies object file version */
7748fb7bfaSmrg   unsigned char	e_entry[8];		/* Entry point virtual address */
7848fb7bfaSmrg   unsigned char	e_phoff[8];		/* Program header table file offset */
7948fb7bfaSmrg   unsigned char	e_shoff[8];		/* Section header table file offset */
8048fb7bfaSmrg   unsigned char	e_flags[4];		/* Processor-specific flags */
8148fb7bfaSmrg   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
8248fb7bfaSmrg   unsigned char	e_phentsize[2];		/* Program header table entry size */
8348fb7bfaSmrg   unsigned char	e_phnum[2];		/* Program header table entry count */
8448fb7bfaSmrg   unsigned char	e_shentsize[2];		/* Section header table entry size */
8548fb7bfaSmrg   unsigned char	e_shnum[2];		/* Section header table entry count */
8648fb7bfaSmrg   unsigned char	e_shstrndx[2];		/* Section header string table index */
8748fb7bfaSmrg } Elf64_External_Ehdr;
8848fb7bfaSmrg 
8948fb7bfaSmrg /* Indexes and values in e_ident field of Ehdr.  */
9048fb7bfaSmrg 
9148fb7bfaSmrg #define EI_MAG0		0	/* File identification byte 0 index */
9248fb7bfaSmrg #define ELFMAG0		   0x7F	/* Magic number byte 0 */
9348fb7bfaSmrg 
9448fb7bfaSmrg #define EI_MAG1		1	/* File identification byte 1 index */
9548fb7bfaSmrg #define ELFMAG1		    'E'	/* Magic number byte 1 */
9648fb7bfaSmrg 
9748fb7bfaSmrg #define EI_MAG2		2	/* File identification byte 2 index */
9848fb7bfaSmrg #define ELFMAG2		    'L'	/* Magic number byte 2 */
9948fb7bfaSmrg 
10048fb7bfaSmrg #define EI_MAG3		3	/* File identification byte 3 index */
10148fb7bfaSmrg #define ELFMAG3		    'F'	/* Magic number byte 3 */
10248fb7bfaSmrg 
10348fb7bfaSmrg #define EI_CLASS	4	/* File class */
10448fb7bfaSmrg #define ELFCLASSNONE	      0	/* Invalid class */
10548fb7bfaSmrg #define ELFCLASS32	      1	/* 32-bit objects */
10648fb7bfaSmrg #define ELFCLASS64	      2	/* 64-bit objects */
10748fb7bfaSmrg 
10848fb7bfaSmrg #define EI_DATA		5	/* Data encoding */
10948fb7bfaSmrg #define ELFDATANONE	      0	/* Invalid data encoding */
11048fb7bfaSmrg #define ELFDATA2LSB	      1	/* 2's complement, little endian */
11148fb7bfaSmrg #define ELFDATA2MSB	      2	/* 2's complement, big endian */
11248fb7bfaSmrg 
11348fb7bfaSmrg #define EI_VERSION	6	/* File version */
11448fb7bfaSmrg #define EV_CURRENT	1		/* Current version */
11548fb7bfaSmrg 
11648fb7bfaSmrg #define EI_OSABI	7	/* Operating System/ABI indication */
11748fb7bfaSmrg 
11848fb7bfaSmrg /* Values for e_type field of Ehdr.  */
11948fb7bfaSmrg 
12048fb7bfaSmrg #define ET_REL		1	/* Relocatable file */
12148fb7bfaSmrg 
12248fb7bfaSmrg /* Values for e_machine field of Ehdr.  */
12348fb7bfaSmrg 
12448fb7bfaSmrg #define EM_SPARC	  2	/* SUN SPARC */
12548fb7bfaSmrg #define EM_SPARC32PLUS	 18	/* Sun's "v8plus" */
12648fb7bfaSmrg 
12748fb7bfaSmrg /* Special section index values.  */
12848fb7bfaSmrg 
129a3e9eb18Smrg #define SHN_UNDEF	0		/* Undefined section */
13048fb7bfaSmrg #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
131a3e9eb18Smrg #define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
13248fb7bfaSmrg #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
133a3e9eb18Smrg #define SHN_HIRESERVE	0xffff		/* End of reserved indices */
134a3e9eb18Smrg 
13548fb7bfaSmrg 
13648fb7bfaSmrg /* 32-bit ELF program header.  */
13748fb7bfaSmrg 
13848fb7bfaSmrg typedef struct {
13948fb7bfaSmrg   unsigned char	p_type[4];		/* Identifies program segment type */
14048fb7bfaSmrg   unsigned char	p_offset[4];		/* Segment file offset */
14148fb7bfaSmrg   unsigned char	p_vaddr[4];		/* Segment virtual address */
14248fb7bfaSmrg   unsigned char	p_paddr[4];		/* Segment physical address */
14348fb7bfaSmrg   unsigned char	p_filesz[4];		/* Segment size in file */
14448fb7bfaSmrg   unsigned char	p_memsz[4];		/* Segment size in memory */
14548fb7bfaSmrg   unsigned char	p_flags[4];		/* Segment flags */
14648fb7bfaSmrg   unsigned char	p_align[4];		/* Segment alignment, file & memory */
14748fb7bfaSmrg } Elf32_External_Phdr;
14848fb7bfaSmrg 
14948fb7bfaSmrg /* 64-bit ELF program header.  */
15048fb7bfaSmrg 
15148fb7bfaSmrg typedef struct {
15248fb7bfaSmrg   unsigned char	p_type[4];		/* Identifies program segment type */
15348fb7bfaSmrg   unsigned char	p_flags[4];		/* Segment flags */
15448fb7bfaSmrg   unsigned char	p_offset[8];		/* Segment file offset */
15548fb7bfaSmrg   unsigned char	p_vaddr[8];		/* Segment virtual address */
15648fb7bfaSmrg   unsigned char	p_paddr[8];		/* Segment physical address */
15748fb7bfaSmrg   unsigned char	p_filesz[8];		/* Segment size in file */
15848fb7bfaSmrg   unsigned char	p_memsz[8];		/* Segment size in memory */
15948fb7bfaSmrg   unsigned char	p_align[8];		/* Segment alignment, file & memory */
16048fb7bfaSmrg } Elf64_External_Phdr;
16148fb7bfaSmrg 
16248fb7bfaSmrg /* 32-bit ELF section header */
16348fb7bfaSmrg 
16448fb7bfaSmrg typedef struct {
16548fb7bfaSmrg   unsigned char	sh_name[4];		/* Section name, index in string tbl */
16648fb7bfaSmrg   unsigned char	sh_type[4];		/* Type of section */
16748fb7bfaSmrg   unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
16848fb7bfaSmrg   unsigned char	sh_addr[4];		/* Section virtual addr at execution */
16948fb7bfaSmrg   unsigned char	sh_offset[4];		/* Section file offset */
17048fb7bfaSmrg   unsigned char	sh_size[4];		/* Size of section in bytes */
17148fb7bfaSmrg   unsigned char	sh_link[4];		/* Index of another section */
17248fb7bfaSmrg   unsigned char	sh_info[4];		/* Additional section information */
17348fb7bfaSmrg   unsigned char	sh_addralign[4];	/* Section alignment */
17448fb7bfaSmrg   unsigned char	sh_entsize[4];		/* Entry size if section holds table */
17548fb7bfaSmrg } Elf32_External_Shdr;
17648fb7bfaSmrg 
17748fb7bfaSmrg /* 64-bit ELF section header.  */
17848fb7bfaSmrg 
17948fb7bfaSmrg typedef struct {
18048fb7bfaSmrg   unsigned char	sh_name[4];		/* Section name, index in string tbl */
18148fb7bfaSmrg   unsigned char	sh_type[4];		/* Type of section */
18248fb7bfaSmrg   unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
18348fb7bfaSmrg   unsigned char	sh_addr[8];		/* Section virtual addr at execution */
18448fb7bfaSmrg   unsigned char	sh_offset[8];		/* Section file offset */
18548fb7bfaSmrg   unsigned char	sh_size[8];		/* Size of section in bytes */
18648fb7bfaSmrg   unsigned char	sh_link[4];		/* Index of another section */
18748fb7bfaSmrg   unsigned char	sh_info[4];		/* Additional section information */
18848fb7bfaSmrg   unsigned char	sh_addralign[8];	/* Section alignment */
18948fb7bfaSmrg   unsigned char	sh_entsize[8];		/* Entry size if section holds table */
19048fb7bfaSmrg } Elf64_External_Shdr;
19148fb7bfaSmrg 
19248fb7bfaSmrg /* Values for sh_type field.  */
19348fb7bfaSmrg 
194a3e9eb18Smrg #define SHT_NULL	0		/* Section header table entry unused */
19548fb7bfaSmrg #define SHT_PROGBITS	1		/* Program data */
196a3e9eb18Smrg #define SHT_SYMTAB	2		/* Link editing symbol table */
19748fb7bfaSmrg #define SHT_STRTAB	3		/* A string table */
198a3e9eb18Smrg #define SHT_RELA	4		/* Relocation entries with addends */
199a3e9eb18Smrg #define SHT_REL		9		/* Relocation entries, no addends */
200a3e9eb18Smrg #define SHT_GROUP	17		/* Section contains a section group */
201a3e9eb18Smrg #define SHT_SYMTAB_SHNDX 18		/* Extended section indeces */
202a3e9eb18Smrg 
203a3e9eb18Smrg /* Values for sh_flags field.  */
204a3e9eb18Smrg 
205a3e9eb18Smrg #define SHF_INFO_LINK	0x00000040	/* `sh_info' contains SHT index */
206a3e9eb18Smrg #define SHF_EXECINSTR	0x00000004	/* Executable section.  */
207a3e9eb18Smrg #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
208a3e9eb18Smrg 					   section from executable and
209a3e9eb18Smrg 					   shared library that it builds
210a3e9eb18Smrg 					   when those objects are not to be
211a3e9eb18Smrg 					   further relocated.  */
212a3e9eb18Smrg /* Symbol table entry.  */
213a3e9eb18Smrg 
214a3e9eb18Smrg typedef struct
215a3e9eb18Smrg {
216a3e9eb18Smrg   unsigned char st_name[4];                /* Symbol name (string tbl index) */
217a3e9eb18Smrg   unsigned char st_value[4];               /* Symbol value */
218a3e9eb18Smrg   unsigned char st_size[4];                /* Symbol size */
219a3e9eb18Smrg   unsigned char st_info;                /* Symbol type and binding */
220a3e9eb18Smrg   unsigned char st_other;               /* Symbol visibility */
221a3e9eb18Smrg   unsigned char st_shndx[2];               /* Section index */
222a3e9eb18Smrg } Elf32_External_Sym;
223a3e9eb18Smrg 
224a3e9eb18Smrg typedef struct
225a3e9eb18Smrg {
226a3e9eb18Smrg   unsigned char st_name[4];                /* Symbol name (string tbl index) */
227a3e9eb18Smrg   unsigned char st_info;                /* Symbol type and binding */
228a3e9eb18Smrg   unsigned char st_other;               /* Symbol visibility */
229a3e9eb18Smrg   unsigned char st_shndx[2];               /* Section index */
230a3e9eb18Smrg   unsigned char st_value[8];               /* Symbol value */
231a3e9eb18Smrg   unsigned char st_size[8];                /* Symbol size */
232a3e9eb18Smrg } Elf64_External_Sym;
233a3e9eb18Smrg 
234a3e9eb18Smrg #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
235a3e9eb18Smrg #define ELF_ST_TYPE(val)              ((val) & 0xf)
236a3e9eb18Smrg #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
237a3e9eb18Smrg 
238a3e9eb18Smrg #define STT_NOTYPE	0	/* Symbol type is unspecified */
239a3e9eb18Smrg #define STT_OBJECT	1	/* Symbol is a data object */
240a3e9eb18Smrg #define STT_FUNC	2	/* Symbol is a code object */
241a3e9eb18Smrg #define STT_TLS		6	/* Thread local data object */
242a3e9eb18Smrg #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
243a3e9eb18Smrg 
244a3e9eb18Smrg #define STB_LOCAL	0	/* Local symbol */
245a3e9eb18Smrg #define STB_GLOBAL	1	/* Global symbol */
246a3e9eb18Smrg #define STB_WEAK	2	/* Weak global */
247a3e9eb18Smrg 
248a3e9eb18Smrg #define STV_DEFAULT	0	/* Visibility is specified by binding type */
249a3e9eb18Smrg #define STV_HIDDEN	2	/* Can only be seen inside currect component */
25048fb7bfaSmrg 
25148fb7bfaSmrg /* Functions to fetch and store different ELF types, depending on the
25248fb7bfaSmrg    endianness and size.  */
25348fb7bfaSmrg 
25448fb7bfaSmrg struct elf_type_functions
25548fb7bfaSmrg {
25648fb7bfaSmrg   unsigned short (*fetch_Elf_Half) (const unsigned char *);
25748fb7bfaSmrg   unsigned int (*fetch_Elf_Word) (const unsigned char *);
25848fb7bfaSmrg   ulong_type (*fetch_Elf_Addr) (const unsigned char *);
25948fb7bfaSmrg   void (*set_Elf_Half) (unsigned char *, unsigned short);
26048fb7bfaSmrg   void (*set_Elf_Word) (unsigned char *, unsigned int);
26148fb7bfaSmrg   void (*set_Elf_Addr) (unsigned char *, ulong_type);
26248fb7bfaSmrg };
26348fb7bfaSmrg 
26448fb7bfaSmrg static const struct elf_type_functions elf_big_32_functions =
26548fb7bfaSmrg {
26648fb7bfaSmrg   simple_object_fetch_big_16,
26748fb7bfaSmrg   simple_object_fetch_big_32,
26848fb7bfaSmrg   simple_object_fetch_big_32_ulong,
26948fb7bfaSmrg   simple_object_set_big_16,
27048fb7bfaSmrg   simple_object_set_big_32,
27148fb7bfaSmrg   simple_object_set_big_32_ulong
27248fb7bfaSmrg };
27348fb7bfaSmrg 
27448fb7bfaSmrg static const struct elf_type_functions elf_little_32_functions =
27548fb7bfaSmrg {
27648fb7bfaSmrg   simple_object_fetch_little_16,
27748fb7bfaSmrg   simple_object_fetch_little_32,
27848fb7bfaSmrg   simple_object_fetch_little_32_ulong,
27948fb7bfaSmrg   simple_object_set_little_16,
28048fb7bfaSmrg   simple_object_set_little_32,
28148fb7bfaSmrg   simple_object_set_little_32_ulong
28248fb7bfaSmrg };
28348fb7bfaSmrg 
28448fb7bfaSmrg #ifdef UNSIGNED_64BIT_TYPE
28548fb7bfaSmrg 
28648fb7bfaSmrg static const struct elf_type_functions elf_big_64_functions =
28748fb7bfaSmrg {
28848fb7bfaSmrg   simple_object_fetch_big_16,
28948fb7bfaSmrg   simple_object_fetch_big_32,
29048fb7bfaSmrg   simple_object_fetch_big_64,
29148fb7bfaSmrg   simple_object_set_big_16,
29248fb7bfaSmrg   simple_object_set_big_32,
29348fb7bfaSmrg   simple_object_set_big_64
29448fb7bfaSmrg };
29548fb7bfaSmrg 
29648fb7bfaSmrg static const struct elf_type_functions elf_little_64_functions =
29748fb7bfaSmrg {
29848fb7bfaSmrg   simple_object_fetch_little_16,
29948fb7bfaSmrg   simple_object_fetch_little_32,
30048fb7bfaSmrg   simple_object_fetch_little_64,
30148fb7bfaSmrg   simple_object_set_little_16,
30248fb7bfaSmrg   simple_object_set_little_32,
30348fb7bfaSmrg   simple_object_set_little_64
30448fb7bfaSmrg };
30548fb7bfaSmrg 
30648fb7bfaSmrg #endif
30748fb7bfaSmrg 
30848fb7bfaSmrg /* Hideous macro to fetch the value of a field from an external ELF
30948fb7bfaSmrg    struct of some sort.  TYPEFUNCS is the set of type functions.
31048fb7bfaSmrg    BUFFER points to the external data.  STRUCTTYPE is the appropriate
31148fb7bfaSmrg    struct type.  FIELD is a field within the struct.  TYPE is the type
31248fb7bfaSmrg    of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
31348fb7bfaSmrg 
31448fb7bfaSmrg #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
31548fb7bfaSmrg   ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
31648fb7bfaSmrg 
31748fb7bfaSmrg /* Even more hideous macro to fetch the value of FIELD from BUFFER.
31848fb7bfaSmrg    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
31948fb7bfaSmrg    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
32048fb7bfaSmrg    the struct.  TYPE is the type of the field in the struct: Elf_Half,
32148fb7bfaSmrg    Elf_Word, or Elf_Addr.  */
32248fb7bfaSmrg 
32348fb7bfaSmrg #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
32448fb7bfaSmrg 			      FIELD, TYPE)				\
32548fb7bfaSmrg   ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
32648fb7bfaSmrg 			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
32748fb7bfaSmrg 			  FIELD, BUFFER, TYPE)
32848fb7bfaSmrg 
32948fb7bfaSmrg /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
33048fb7bfaSmrg 
33148fb7bfaSmrg #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
33248fb7bfaSmrg 			FIELD, TYPE)					\
33348fb7bfaSmrg   ((CLASS) == ELFCLASS32						\
33448fb7bfaSmrg     ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
33548fb7bfaSmrg 			     TYPE)					\
33648fb7bfaSmrg     : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
33748fb7bfaSmrg 			     TYPE))
33848fb7bfaSmrg 
33948fb7bfaSmrg /* Hideous macro to set the value of a field in an external ELF
34048fb7bfaSmrg    structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
34148fb7bfaSmrg    points to the external data.  STRUCTTYPE is the appropriate
34248fb7bfaSmrg    structure type.  FIELD is a field within the struct.  TYPE is the
34348fb7bfaSmrg    type of the field in the struct: Elf_Half, Elf_Word, or
34448fb7bfaSmrg    Elf_Addr.  */
34548fb7bfaSmrg 
34648fb7bfaSmrg #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
34748fb7bfaSmrg   (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
34848fb7bfaSmrg 
34948fb7bfaSmrg /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
35048fb7bfaSmrg    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
35148fb7bfaSmrg    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
35248fb7bfaSmrg    the struct.  TYPE is the type of the field in the struct: Elf_Half,
35348fb7bfaSmrg    Elf_Word, or Elf_Addr.  */
35448fb7bfaSmrg 
35548fb7bfaSmrg #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
35648fb7bfaSmrg 			    TYPE, VAL)					\
35748fb7bfaSmrg   ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
35848fb7bfaSmrg 			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
35948fb7bfaSmrg 			FIELD, BUFFER, TYPE, VAL)
36048fb7bfaSmrg 
36148fb7bfaSmrg /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
36248fb7bfaSmrg 
36348fb7bfaSmrg #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
36448fb7bfaSmrg 		      TYPE, VAL)					\
36548fb7bfaSmrg   ((CLASS) == ELFCLASS32						\
36648fb7bfaSmrg     ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
36748fb7bfaSmrg 			   TYPE, VAL)					\
36848fb7bfaSmrg     : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
36948fb7bfaSmrg 			   TYPE, VAL))
37048fb7bfaSmrg 
37148fb7bfaSmrg /* Private data for an simple_object_read.  */
37248fb7bfaSmrg 
37348fb7bfaSmrg struct simple_object_elf_read
37448fb7bfaSmrg {
37548fb7bfaSmrg   /* Type functions.  */
37648fb7bfaSmrg   const struct elf_type_functions* type_functions;
37748fb7bfaSmrg   /* Elf data.  */
37848fb7bfaSmrg   unsigned char ei_data;
37948fb7bfaSmrg   /* Elf class.  */
38048fb7bfaSmrg   unsigned char ei_class;
38148fb7bfaSmrg   /* ELF OS ABI.  */
38248fb7bfaSmrg   unsigned char ei_osabi;
38348fb7bfaSmrg   /* Elf machine number.  */
38448fb7bfaSmrg   unsigned short machine;
38548fb7bfaSmrg   /* Processor specific flags.  */
38648fb7bfaSmrg   unsigned int flags;
38748fb7bfaSmrg   /* File offset of section headers.  */
38848fb7bfaSmrg   ulong_type shoff;
38948fb7bfaSmrg   /* Number of sections.  */
39048fb7bfaSmrg   unsigned int shnum;
39148fb7bfaSmrg   /* Index of string table section header.  */
39248fb7bfaSmrg   unsigned int shstrndx;
39348fb7bfaSmrg };
39448fb7bfaSmrg 
39548fb7bfaSmrg /* Private data for an simple_object_attributes.  */
39648fb7bfaSmrg 
39748fb7bfaSmrg struct simple_object_elf_attributes
39848fb7bfaSmrg {
39948fb7bfaSmrg   /* Type functions.  */
40048fb7bfaSmrg   const struct elf_type_functions* type_functions;
40148fb7bfaSmrg   /* Elf data.  */
40248fb7bfaSmrg   unsigned char ei_data;
40348fb7bfaSmrg   /* Elf class.  */
40448fb7bfaSmrg   unsigned char ei_class;
40548fb7bfaSmrg   /* ELF OS ABI.  */
40648fb7bfaSmrg   unsigned char ei_osabi;
40748fb7bfaSmrg   /* Elf machine number.  */
40848fb7bfaSmrg   unsigned short machine;
40948fb7bfaSmrg   /* Processor specific flags.  */
41048fb7bfaSmrg   unsigned int flags;
41148fb7bfaSmrg };
41248fb7bfaSmrg 
413a3e9eb18Smrg /* Private data for an simple_object_write.  */
414a3e9eb18Smrg 
415a3e9eb18Smrg struct simple_object_elf_write
416a3e9eb18Smrg {
417a3e9eb18Smrg   struct simple_object_elf_attributes attrs;
418a3e9eb18Smrg   unsigned char *shdrs;
419a3e9eb18Smrg };
420a3e9eb18Smrg 
42148fb7bfaSmrg /* See if we have an ELF file.  */
42248fb7bfaSmrg 
42348fb7bfaSmrg 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)42448fb7bfaSmrg simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
42548fb7bfaSmrg 			 int descriptor, off_t offset,
42648fb7bfaSmrg 			 const char *segment_name ATTRIBUTE_UNUSED,
42748fb7bfaSmrg 			 const char **errmsg, int *err)
42848fb7bfaSmrg {
42948fb7bfaSmrg   unsigned char ei_data;
43048fb7bfaSmrg   unsigned char ei_class;
43148fb7bfaSmrg   const struct elf_type_functions *type_functions;
43248fb7bfaSmrg   unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
43348fb7bfaSmrg   struct simple_object_elf_read *eor;
43448fb7bfaSmrg 
43548fb7bfaSmrg   if (header[EI_MAG0] != ELFMAG0
43648fb7bfaSmrg       || header[EI_MAG1] != ELFMAG1
43748fb7bfaSmrg       || header[EI_MAG2] != ELFMAG2
43848fb7bfaSmrg       || header[EI_MAG3] != ELFMAG3
43948fb7bfaSmrg       || header[EI_VERSION] != EV_CURRENT)
44048fb7bfaSmrg     {
44148fb7bfaSmrg       *errmsg = NULL;
44248fb7bfaSmrg       *err = 0;
44348fb7bfaSmrg       return NULL;
44448fb7bfaSmrg     }
44548fb7bfaSmrg 
44648fb7bfaSmrg   ei_data = header[EI_DATA];
44748fb7bfaSmrg   if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
44848fb7bfaSmrg     {
44948fb7bfaSmrg       *errmsg = "unknown ELF endianness";
45048fb7bfaSmrg       *err = 0;
45148fb7bfaSmrg       return NULL;
45248fb7bfaSmrg     }
45348fb7bfaSmrg 
45448fb7bfaSmrg   ei_class = header[EI_CLASS];
45548fb7bfaSmrg   switch (ei_class)
45648fb7bfaSmrg     {
45748fb7bfaSmrg     case ELFCLASS32:
45848fb7bfaSmrg       type_functions = (ei_data == ELFDATA2LSB
45948fb7bfaSmrg 			? &elf_little_32_functions
46048fb7bfaSmrg 			: &elf_big_32_functions);
46148fb7bfaSmrg       break;
46248fb7bfaSmrg 
46348fb7bfaSmrg     case ELFCLASS64:
46448fb7bfaSmrg #ifndef UNSIGNED_64BIT_TYPE
46548fb7bfaSmrg       *errmsg = "64-bit ELF objects not supported";
46648fb7bfaSmrg       *err = 0;
46748fb7bfaSmrg       return NULL;
46848fb7bfaSmrg #else
46948fb7bfaSmrg       type_functions = (ei_data == ELFDATA2LSB
47048fb7bfaSmrg 			? &elf_little_64_functions
47148fb7bfaSmrg 			: &elf_big_64_functions);
47248fb7bfaSmrg       break;
47348fb7bfaSmrg #endif
47448fb7bfaSmrg 
47548fb7bfaSmrg     default:
47648fb7bfaSmrg       *errmsg = "unrecognized ELF size";
47748fb7bfaSmrg       *err = 0;
47848fb7bfaSmrg       return NULL;
47948fb7bfaSmrg     }
48048fb7bfaSmrg 
48148fb7bfaSmrg   if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
48248fb7bfaSmrg 				    errmsg, err))
48348fb7bfaSmrg     return NULL;
48448fb7bfaSmrg 
48548fb7bfaSmrg   eor = XNEW (struct simple_object_elf_read);
48648fb7bfaSmrg   eor->type_functions = type_functions;
48748fb7bfaSmrg   eor->ei_data = ei_data;
48848fb7bfaSmrg   eor->ei_class = ei_class;
48948fb7bfaSmrg   eor->ei_osabi = header[EI_OSABI];
49048fb7bfaSmrg   eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49148fb7bfaSmrg 				  e_machine, Elf_Half);
49248fb7bfaSmrg   eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49348fb7bfaSmrg 				e_flags, Elf_Word);
49448fb7bfaSmrg   eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49548fb7bfaSmrg 				e_shoff, Elf_Addr);
49648fb7bfaSmrg   eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49748fb7bfaSmrg 				e_shnum, Elf_Half);
49848fb7bfaSmrg   eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
49948fb7bfaSmrg 				   e_shstrndx, Elf_Half);
50048fb7bfaSmrg 
50148fb7bfaSmrg   if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
50248fb7bfaSmrg       && eor->shoff != 0)
50348fb7bfaSmrg     {
50448fb7bfaSmrg       unsigned char shdr[sizeof (Elf64_External_Shdr)];
50548fb7bfaSmrg 
50648fb7bfaSmrg       /* Object file has more than 0xffff sections.  */
50748fb7bfaSmrg 
50848fb7bfaSmrg       if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
50948fb7bfaSmrg 					(ei_class == ELFCLASS32
51048fb7bfaSmrg 					 ? sizeof (Elf32_External_Shdr)
51148fb7bfaSmrg 					 : sizeof (Elf64_External_Shdr)),
51248fb7bfaSmrg 					errmsg, err))
51348fb7bfaSmrg 	{
51448fb7bfaSmrg 	  XDELETE (eor);
51548fb7bfaSmrg 	  return NULL;
51648fb7bfaSmrg 	}
51748fb7bfaSmrg 
51848fb7bfaSmrg       if (eor->shnum == 0)
51948fb7bfaSmrg 	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
52048fb7bfaSmrg 				      shdr, sh_size, Elf_Addr);
52148fb7bfaSmrg 
52248fb7bfaSmrg       if (eor->shstrndx == SHN_XINDEX)
52348fb7bfaSmrg 	{
52448fb7bfaSmrg 	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
52548fb7bfaSmrg 					   shdr, sh_link, Elf_Word);
52648fb7bfaSmrg 
52748fb7bfaSmrg 	  /* Versions of the GNU binutils between 2.12 and 2.18 did
52848fb7bfaSmrg 	     not handle objects with more than SHN_LORESERVE sections
52948fb7bfaSmrg 	     correctly.  All large section indexes were offset by
53048fb7bfaSmrg 	     0x100.  There is more information at
531a448f87cSmrg 	     https://sourceware.org/PR5900 .
53248fb7bfaSmrg 	     Fortunately these object files are easy to detect, as the
53348fb7bfaSmrg 	     GNU binutils always put the section header string table
53448fb7bfaSmrg 	     near the end of the list of sections.  Thus if the
53548fb7bfaSmrg 	     section header string table index is larger than the
53648fb7bfaSmrg 	     number of sections, then we know we have to subtract
53748fb7bfaSmrg 	     0x100 to get the real section index.  */
53848fb7bfaSmrg 	  if (eor->shstrndx >= eor->shnum
53948fb7bfaSmrg 	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
54048fb7bfaSmrg 	    eor->shstrndx -= 0x100;
54148fb7bfaSmrg 	}
54248fb7bfaSmrg     }
54348fb7bfaSmrg 
54448fb7bfaSmrg   if (eor->shstrndx >= eor->shnum)
54548fb7bfaSmrg     {
54648fb7bfaSmrg       *errmsg = "invalid ELF shstrndx >= shnum";
54748fb7bfaSmrg       *err = 0;
54848fb7bfaSmrg       XDELETE (eor);
54948fb7bfaSmrg       return NULL;
55048fb7bfaSmrg     }
55148fb7bfaSmrg 
552003ba354Smrg   if (eor->shstrndx == 0)
553003ba354Smrg     {
554003ba354Smrg       *errmsg = "invalid ELF shstrndx == 0";
555003ba354Smrg       *err = 0;
556003ba354Smrg       XDELETE (eor);
557003ba354Smrg       return NULL;
558003ba354Smrg     }
559003ba354Smrg 
56048fb7bfaSmrg   return (void *) eor;
56148fb7bfaSmrg }
56248fb7bfaSmrg 
56348fb7bfaSmrg /* Find all sections in an ELF file.  */
56448fb7bfaSmrg 
56548fb7bfaSmrg 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)56648fb7bfaSmrg simple_object_elf_find_sections (simple_object_read *sobj,
56748fb7bfaSmrg 				 int (*pfn) (void *, const char *,
56848fb7bfaSmrg 					     off_t offset, off_t length),
56948fb7bfaSmrg 				 void *data,
57048fb7bfaSmrg 				 int *err)
57148fb7bfaSmrg {
57248fb7bfaSmrg   struct simple_object_elf_read *eor =
57348fb7bfaSmrg     (struct simple_object_elf_read *) sobj->data;
57448fb7bfaSmrg   const struct elf_type_functions *type_functions = eor->type_functions;
57548fb7bfaSmrg   unsigned char ei_class = eor->ei_class;
57648fb7bfaSmrg   size_t shdr_size;
57748fb7bfaSmrg   unsigned int shnum;
57848fb7bfaSmrg   unsigned char *shdrs;
57948fb7bfaSmrg   const char *errmsg;
58048fb7bfaSmrg   unsigned char *shstrhdr;
58148fb7bfaSmrg   size_t name_size;
58248fb7bfaSmrg   off_t shstroff;
58348fb7bfaSmrg   unsigned char *names;
58448fb7bfaSmrg   unsigned int i;
58548fb7bfaSmrg 
58648fb7bfaSmrg   shdr_size = (ei_class == ELFCLASS32
58748fb7bfaSmrg 	       ? sizeof (Elf32_External_Shdr)
58848fb7bfaSmrg 	       : sizeof (Elf64_External_Shdr));
58948fb7bfaSmrg 
59048fb7bfaSmrg   /* Read the section headers.  We skip section 0, which is not a
59148fb7bfaSmrg      useful section.  */
59248fb7bfaSmrg 
59348fb7bfaSmrg   shnum = eor->shnum;
59448fb7bfaSmrg   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
59548fb7bfaSmrg 
59648fb7bfaSmrg   if (!simple_object_internal_read (sobj->descriptor,
59748fb7bfaSmrg 				    sobj->offset + eor->shoff + shdr_size,
59848fb7bfaSmrg 				    shdrs,
59948fb7bfaSmrg 				    shdr_size * (shnum - 1),
60048fb7bfaSmrg 				    &errmsg, err))
60148fb7bfaSmrg     {
60248fb7bfaSmrg       XDELETEVEC (shdrs);
60348fb7bfaSmrg       return errmsg;
60448fb7bfaSmrg     }
60548fb7bfaSmrg 
60648fb7bfaSmrg   /* Read the section names.  */
60748fb7bfaSmrg 
60848fb7bfaSmrg   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
60948fb7bfaSmrg   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
61048fb7bfaSmrg 			       shstrhdr, sh_size, Elf_Addr);
61148fb7bfaSmrg   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
61248fb7bfaSmrg 			      shstrhdr, sh_offset, Elf_Addr);
61348fb7bfaSmrg   names = XNEWVEC (unsigned char, name_size);
61448fb7bfaSmrg   if (!simple_object_internal_read (sobj->descriptor,
61548fb7bfaSmrg 				    sobj->offset + shstroff,
61648fb7bfaSmrg 				    names, name_size, &errmsg, err))
61748fb7bfaSmrg     {
61848fb7bfaSmrg       XDELETEVEC (names);
61948fb7bfaSmrg       XDELETEVEC (shdrs);
62048fb7bfaSmrg       return errmsg;
62148fb7bfaSmrg     }
62248fb7bfaSmrg 
62348fb7bfaSmrg   for (i = 1; i < shnum; ++i)
62448fb7bfaSmrg     {
62548fb7bfaSmrg       unsigned char *shdr;
62648fb7bfaSmrg       unsigned int sh_name;
62748fb7bfaSmrg       const char *name;
62848fb7bfaSmrg       off_t offset;
62948fb7bfaSmrg       off_t length;
63048fb7bfaSmrg 
63148fb7bfaSmrg       shdr = shdrs + (i - 1) * shdr_size;
63248fb7bfaSmrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
63348fb7bfaSmrg 				 shdr, sh_name, Elf_Word);
63448fb7bfaSmrg       if (sh_name >= name_size)
63548fb7bfaSmrg 	{
63648fb7bfaSmrg 	  *err = 0;
63748fb7bfaSmrg 	  XDELETEVEC (names);
63848fb7bfaSmrg 	  XDELETEVEC (shdrs);
63948fb7bfaSmrg 	  return "ELF section name out of range";
64048fb7bfaSmrg 	}
64148fb7bfaSmrg 
64248fb7bfaSmrg       name = (const char *) names + sh_name;
64348fb7bfaSmrg       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
64448fb7bfaSmrg 				shdr, sh_offset, Elf_Addr);
64548fb7bfaSmrg       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
64648fb7bfaSmrg 				shdr, sh_size, Elf_Addr);
64748fb7bfaSmrg 
64848fb7bfaSmrg       if (!(*pfn) (data, name, offset, length))
64948fb7bfaSmrg 	break;
65048fb7bfaSmrg     }
65148fb7bfaSmrg 
65248fb7bfaSmrg   XDELETEVEC (names);
65348fb7bfaSmrg   XDELETEVEC (shdrs);
65448fb7bfaSmrg 
65548fb7bfaSmrg   return NULL;
65648fb7bfaSmrg }
65748fb7bfaSmrg 
65848fb7bfaSmrg /* Fetch the attributes for an simple_object_read.  */
65948fb7bfaSmrg 
66048fb7bfaSmrg static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)66148fb7bfaSmrg simple_object_elf_fetch_attributes (simple_object_read *sobj,
66248fb7bfaSmrg 				    const char **errmsg ATTRIBUTE_UNUSED,
66348fb7bfaSmrg 				    int *err ATTRIBUTE_UNUSED)
66448fb7bfaSmrg {
66548fb7bfaSmrg   struct simple_object_elf_read *eor =
66648fb7bfaSmrg     (struct simple_object_elf_read *) sobj->data;
66748fb7bfaSmrg   struct simple_object_elf_attributes *ret;
66848fb7bfaSmrg 
66948fb7bfaSmrg   ret = XNEW (struct simple_object_elf_attributes);
67048fb7bfaSmrg   ret->type_functions = eor->type_functions;
67148fb7bfaSmrg   ret->ei_data = eor->ei_data;
67248fb7bfaSmrg   ret->ei_class = eor->ei_class;
67348fb7bfaSmrg   ret->ei_osabi = eor->ei_osabi;
67448fb7bfaSmrg   ret->machine = eor->machine;
67548fb7bfaSmrg   ret->flags = eor->flags;
67648fb7bfaSmrg   return ret;
67748fb7bfaSmrg }
67848fb7bfaSmrg 
67948fb7bfaSmrg /* Release the privata data for an simple_object_read.  */
68048fb7bfaSmrg 
68148fb7bfaSmrg static void
simple_object_elf_release_read(void * data)68248fb7bfaSmrg simple_object_elf_release_read (void *data)
68348fb7bfaSmrg {
68448fb7bfaSmrg   XDELETE (data);
68548fb7bfaSmrg }
68648fb7bfaSmrg 
68748fb7bfaSmrg /* Compare two attributes structures.  */
68848fb7bfaSmrg 
68948fb7bfaSmrg static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)69048fb7bfaSmrg simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
69148fb7bfaSmrg {
69248fb7bfaSmrg   struct simple_object_elf_attributes *to =
69348fb7bfaSmrg     (struct simple_object_elf_attributes *) todata;
69448fb7bfaSmrg   struct simple_object_elf_attributes *from =
69548fb7bfaSmrg     (struct simple_object_elf_attributes *) fromdata;
69648fb7bfaSmrg 
69748fb7bfaSmrg   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
69848fb7bfaSmrg     {
69948fb7bfaSmrg       *err = 0;
70048fb7bfaSmrg       return "ELF object format mismatch";
70148fb7bfaSmrg     }
70248fb7bfaSmrg 
70348fb7bfaSmrg   if (to->machine != from->machine)
70448fb7bfaSmrg     {
70548fb7bfaSmrg       int ok;
70648fb7bfaSmrg 
70748fb7bfaSmrg       /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
70848fb7bfaSmrg 	 output of EM_SPARC32PLUS.  */
70948fb7bfaSmrg       ok = 0;
71048fb7bfaSmrg       switch (to->machine)
71148fb7bfaSmrg 	{
71248fb7bfaSmrg 	case EM_SPARC:
71348fb7bfaSmrg 	  if (from->machine == EM_SPARC32PLUS)
71448fb7bfaSmrg 	    {
71548fb7bfaSmrg 	      to->machine = from->machine;
71648fb7bfaSmrg 	      ok = 1;
71748fb7bfaSmrg 	    }
71848fb7bfaSmrg 	  break;
71948fb7bfaSmrg 
72048fb7bfaSmrg 	case EM_SPARC32PLUS:
72148fb7bfaSmrg 	  if (from->machine == EM_SPARC)
72248fb7bfaSmrg 	    ok = 1;
72348fb7bfaSmrg 	  break;
72448fb7bfaSmrg 
72548fb7bfaSmrg 	default:
72648fb7bfaSmrg 	  break;
72748fb7bfaSmrg 	}
72848fb7bfaSmrg 
72948fb7bfaSmrg       if (!ok)
73048fb7bfaSmrg 	{
73148fb7bfaSmrg 	  *err = 0;
73248fb7bfaSmrg 	  return "ELF machine number mismatch";
73348fb7bfaSmrg 	}
73448fb7bfaSmrg     }
73548fb7bfaSmrg 
73648fb7bfaSmrg   return NULL;
73748fb7bfaSmrg }
73848fb7bfaSmrg 
73948fb7bfaSmrg /* Release the private data for an attributes structure.  */
74048fb7bfaSmrg 
74148fb7bfaSmrg static void
simple_object_elf_release_attributes(void * data)74248fb7bfaSmrg simple_object_elf_release_attributes (void *data)
74348fb7bfaSmrg {
74448fb7bfaSmrg   XDELETE (data);
74548fb7bfaSmrg }
74648fb7bfaSmrg 
74748fb7bfaSmrg /* Prepare to write out a file.  */
74848fb7bfaSmrg 
74948fb7bfaSmrg static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)75048fb7bfaSmrg simple_object_elf_start_write (void *attributes_data,
75148fb7bfaSmrg 			       const char **errmsg ATTRIBUTE_UNUSED,
75248fb7bfaSmrg 			       int *err ATTRIBUTE_UNUSED)
75348fb7bfaSmrg {
75448fb7bfaSmrg   struct simple_object_elf_attributes *attrs =
75548fb7bfaSmrg     (struct simple_object_elf_attributes *) attributes_data;
756a3e9eb18Smrg   struct simple_object_elf_write *ret;
75748fb7bfaSmrg 
75848fb7bfaSmrg   /* We're just going to record the attributes, but we need to make a
75948fb7bfaSmrg      copy because the user may delete them.  */
760a3e9eb18Smrg   ret = XNEW (struct simple_object_elf_write);
761a3e9eb18Smrg   ret->attrs = *attrs;
762a3e9eb18Smrg   ret->shdrs = NULL;
76348fb7bfaSmrg   return ret;
76448fb7bfaSmrg }
76548fb7bfaSmrg 
76648fb7bfaSmrg /* Write out an ELF ehdr.  */
76748fb7bfaSmrg 
76848fb7bfaSmrg static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)76948fb7bfaSmrg simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
77048fb7bfaSmrg 			      const char **errmsg, int *err)
77148fb7bfaSmrg {
77248fb7bfaSmrg   struct simple_object_elf_attributes *attrs =
77348fb7bfaSmrg     (struct simple_object_elf_attributes *) sobj->data;
77448fb7bfaSmrg   const struct elf_type_functions* fns;
77548fb7bfaSmrg   unsigned char cl;
77648fb7bfaSmrg   size_t ehdr_size;
77748fb7bfaSmrg   unsigned char buf[sizeof (Elf64_External_Ehdr)];
77848fb7bfaSmrg   simple_object_write_section *section;
77948fb7bfaSmrg   unsigned int shnum;
7804d5abbe8Smrg   unsigned int shstrndx;
78148fb7bfaSmrg 
78248fb7bfaSmrg   fns = attrs->type_functions;
78348fb7bfaSmrg   cl = attrs->ei_class;
78448fb7bfaSmrg 
78548fb7bfaSmrg   shnum = 0;
78648fb7bfaSmrg   for (section = sobj->sections; section != NULL; section = section->next)
78748fb7bfaSmrg     ++shnum;
78848fb7bfaSmrg   if (shnum > 0)
78948fb7bfaSmrg     {
79048fb7bfaSmrg       /* Add a section header for the dummy section and one for
79148fb7bfaSmrg 	 .shstrtab.  */
79248fb7bfaSmrg       shnum += 2;
79348fb7bfaSmrg     }
79448fb7bfaSmrg 
79548fb7bfaSmrg   ehdr_size = (cl == ELFCLASS32
79648fb7bfaSmrg 	       ? sizeof (Elf32_External_Ehdr)
79748fb7bfaSmrg 	       : sizeof (Elf64_External_Ehdr));
79848fb7bfaSmrg   memset (buf, 0, sizeof (Elf64_External_Ehdr));
79948fb7bfaSmrg 
80048fb7bfaSmrg   buf[EI_MAG0] = ELFMAG0;
80148fb7bfaSmrg   buf[EI_MAG1] = ELFMAG1;
80248fb7bfaSmrg   buf[EI_MAG2] = ELFMAG2;
80348fb7bfaSmrg   buf[EI_MAG3] = ELFMAG3;
80448fb7bfaSmrg   buf[EI_CLASS] = cl;
80548fb7bfaSmrg   buf[EI_DATA] = attrs->ei_data;
80648fb7bfaSmrg   buf[EI_VERSION] = EV_CURRENT;
80748fb7bfaSmrg   buf[EI_OSABI] = attrs->ei_osabi;
80848fb7bfaSmrg 
80948fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
81048fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
81148fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
81248fb7bfaSmrg   /* e_entry left as zero.  */
81348fb7bfaSmrg   /* e_phoff left as zero.  */
81448fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
81548fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
81648fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
81748fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
81848fb7bfaSmrg 		 (cl == ELFCLASS32
81948fb7bfaSmrg 		  ? sizeof (Elf32_External_Phdr)
82048fb7bfaSmrg 		  : sizeof (Elf64_External_Phdr)));
82148fb7bfaSmrg   /* e_phnum left as zero.  */
82248fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
82348fb7bfaSmrg 		 (cl == ELFCLASS32
82448fb7bfaSmrg 		  ? sizeof (Elf32_External_Shdr)
82548fb7bfaSmrg 		  : sizeof (Elf64_External_Shdr)));
8264d5abbe8Smrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half,
8274d5abbe8Smrg 		 shnum >= SHN_LORESERVE ? 0 : shnum);
8284d5abbe8Smrg   if (shnum == 0)
8294d5abbe8Smrg     shstrndx = 0;
8304d5abbe8Smrg   else
8314d5abbe8Smrg     {
8324d5abbe8Smrg       shstrndx = shnum - 1;
8334d5abbe8Smrg       if (shstrndx >= SHN_LORESERVE)
8344d5abbe8Smrg 	shstrndx = SHN_XINDEX;
8354d5abbe8Smrg     }
8364d5abbe8Smrg   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx);
83748fb7bfaSmrg 
83848fb7bfaSmrg   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
83948fb7bfaSmrg 				       errmsg, err);
84048fb7bfaSmrg }
84148fb7bfaSmrg 
84248fb7bfaSmrg /* Write out an ELF shdr.  */
84348fb7bfaSmrg 
84448fb7bfaSmrg 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)84548fb7bfaSmrg simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
84648fb7bfaSmrg 			      off_t offset, unsigned int sh_name,
84748fb7bfaSmrg 			      unsigned int sh_type, unsigned int sh_flags,
848a3e9eb18Smrg 			      off_t sh_addr,
84948fb7bfaSmrg 			      unsigned int sh_offset, unsigned int sh_size,
850a3e9eb18Smrg 			      unsigned int sh_link, unsigned int sh_info,
851a3e9eb18Smrg 			      size_t sh_addralign,
852a3e9eb18Smrg 			      size_t sh_entsize,
8534d5abbe8Smrg 			      const char **errmsg, int *err)
85448fb7bfaSmrg {
85548fb7bfaSmrg   struct simple_object_elf_attributes *attrs =
85648fb7bfaSmrg     (struct simple_object_elf_attributes *) sobj->data;
85748fb7bfaSmrg   const struct elf_type_functions* fns;
85848fb7bfaSmrg   unsigned char cl;
85948fb7bfaSmrg   size_t shdr_size;
86048fb7bfaSmrg   unsigned char buf[sizeof (Elf64_External_Shdr)];
86148fb7bfaSmrg 
86248fb7bfaSmrg   fns = attrs->type_functions;
86348fb7bfaSmrg   cl = attrs->ei_class;
86448fb7bfaSmrg 
86548fb7bfaSmrg   shdr_size = (cl == ELFCLASS32
86648fb7bfaSmrg 	       ? sizeof (Elf32_External_Shdr)
86748fb7bfaSmrg 	       : sizeof (Elf64_External_Shdr));
86848fb7bfaSmrg   memset (buf, 0, sizeof (Elf64_External_Shdr));
86948fb7bfaSmrg 
87048fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
87148fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
87248fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
873a3e9eb18Smrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
87448fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
87548fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
8764d5abbe8Smrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
877a3e9eb18Smrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
87848fb7bfaSmrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
879a3e9eb18Smrg   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize);
88048fb7bfaSmrg 
88148fb7bfaSmrg   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
88248fb7bfaSmrg 				       errmsg, err);
88348fb7bfaSmrg }
88448fb7bfaSmrg 
88548fb7bfaSmrg /* Write out a complete ELF file.
88648fb7bfaSmrg    Ehdr
88748fb7bfaSmrg    initial dummy Shdr
88848fb7bfaSmrg    user-created Shdrs
88948fb7bfaSmrg    .shstrtab Shdr
89048fb7bfaSmrg    user-created section data
89148fb7bfaSmrg    .shstrtab data  */
89248fb7bfaSmrg 
89348fb7bfaSmrg static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)89448fb7bfaSmrg simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
89548fb7bfaSmrg 				 int *err)
89648fb7bfaSmrg {
897a3e9eb18Smrg   struct simple_object_elf_write *eow =
898a3e9eb18Smrg     (struct simple_object_elf_write *) sobj->data;
899a3e9eb18Smrg   struct simple_object_elf_attributes *attrs = &eow->attrs;
90048fb7bfaSmrg   unsigned char cl;
90148fb7bfaSmrg   size_t ehdr_size;
90248fb7bfaSmrg   size_t shdr_size;
90348fb7bfaSmrg   const char *errmsg;
90448fb7bfaSmrg   simple_object_write_section *section;
90548fb7bfaSmrg   unsigned int shnum;
90648fb7bfaSmrg   size_t shdr_offset;
90748fb7bfaSmrg   size_t sh_offset;
9084d5abbe8Smrg   unsigned int first_sh_size;
9094d5abbe8Smrg   unsigned int first_sh_link;
91048fb7bfaSmrg   size_t sh_name;
91148fb7bfaSmrg   unsigned char zero;
912a3e9eb18Smrg   unsigned secnum;
91348fb7bfaSmrg 
91448fb7bfaSmrg   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
91548fb7bfaSmrg     return errmsg;
91648fb7bfaSmrg 
91748fb7bfaSmrg   cl = attrs->ei_class;
91848fb7bfaSmrg   if (cl == ELFCLASS32)
91948fb7bfaSmrg     {
92048fb7bfaSmrg       ehdr_size = sizeof (Elf32_External_Ehdr);
92148fb7bfaSmrg       shdr_size = sizeof (Elf32_External_Shdr);
92248fb7bfaSmrg     }
92348fb7bfaSmrg   else
92448fb7bfaSmrg     {
92548fb7bfaSmrg       ehdr_size = sizeof (Elf64_External_Ehdr);
92648fb7bfaSmrg       shdr_size = sizeof (Elf64_External_Shdr);
92748fb7bfaSmrg     }
92848fb7bfaSmrg 
92948fb7bfaSmrg   shnum = 0;
93048fb7bfaSmrg   for (section = sobj->sections; section != NULL; section = section->next)
93148fb7bfaSmrg     ++shnum;
93248fb7bfaSmrg   if (shnum == 0)
93348fb7bfaSmrg     return NULL;
93448fb7bfaSmrg 
93548fb7bfaSmrg   /* Add initial dummy Shdr and .shstrtab.  */
93648fb7bfaSmrg   shnum += 2;
93748fb7bfaSmrg 
93848fb7bfaSmrg   shdr_offset = ehdr_size;
93948fb7bfaSmrg   sh_offset = shdr_offset + shnum * shdr_size;
94048fb7bfaSmrg 
9414d5abbe8Smrg   if (shnum < SHN_LORESERVE)
9424d5abbe8Smrg     first_sh_size = 0;
9434d5abbe8Smrg   else
9444d5abbe8Smrg     first_sh_size = shnum;
9454d5abbe8Smrg   if (shnum - 1 < SHN_LORESERVE)
9464d5abbe8Smrg     first_sh_link = 0;
9474d5abbe8Smrg   else
9484d5abbe8Smrg     first_sh_link = shnum - 1;
94948fb7bfaSmrg   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
950a3e9eb18Smrg 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
951a3e9eb18Smrg 				     0, 0, 0, &errmsg, err))
95248fb7bfaSmrg     return errmsg;
95348fb7bfaSmrg 
95448fb7bfaSmrg   shdr_offset += shdr_size;
95548fb7bfaSmrg 
95648fb7bfaSmrg   sh_name = 1;
957a3e9eb18Smrg   secnum = 0;
95848fb7bfaSmrg   for (section = sobj->sections; section != NULL; section = section->next)
95948fb7bfaSmrg     {
96048fb7bfaSmrg       size_t mask;
96148fb7bfaSmrg       size_t new_sh_offset;
96248fb7bfaSmrg       size_t sh_size;
96348fb7bfaSmrg       struct simple_object_write_section_buffer *buffer;
964a3e9eb18Smrg       unsigned int sh_type = SHT_PROGBITS;
965a3e9eb18Smrg       unsigned int sh_flags = 0;
966a3e9eb18Smrg       off_t sh_addr = 0;
967a3e9eb18Smrg       unsigned int sh_link = 0;
968a3e9eb18Smrg       unsigned int sh_info = 0;
969a3e9eb18Smrg       size_t sh_addralign = 1U << section->align;
970a3e9eb18Smrg       size_t sh_entsize = 0;
971a3e9eb18Smrg       if (eow->shdrs)
972a3e9eb18Smrg 	{
973a3e9eb18Smrg 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
974a3e9eb18Smrg 				     eow->shdrs + secnum * shdr_size,
975a3e9eb18Smrg 				     sh_type, Elf_Word);
976a3e9eb18Smrg 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
977a3e9eb18Smrg 				      eow->shdrs + secnum * shdr_size,
978a3e9eb18Smrg 				      sh_flags, Elf_Addr);
979a3e9eb18Smrg 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
980a3e9eb18Smrg 				     eow->shdrs + secnum * shdr_size,
981a3e9eb18Smrg 				     sh_addr, Elf_Addr);
982a3e9eb18Smrg 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
983a3e9eb18Smrg 				     eow->shdrs + secnum * shdr_size,
984a3e9eb18Smrg 				     sh_link, Elf_Word);
985a3e9eb18Smrg 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
986a3e9eb18Smrg 				     eow->shdrs + secnum * shdr_size,
987a3e9eb18Smrg 				     sh_info, Elf_Word);
988a3e9eb18Smrg 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
989a3e9eb18Smrg 					  eow->shdrs + secnum * shdr_size,
990a3e9eb18Smrg 					  sh_addralign, Elf_Addr);
991a3e9eb18Smrg 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
992a3e9eb18Smrg 					eow->shdrs + secnum * shdr_size,
993a3e9eb18Smrg 					sh_entsize, Elf_Addr);
994a3e9eb18Smrg 	  secnum++;
995a3e9eb18Smrg 	}
99648fb7bfaSmrg 
997a3e9eb18Smrg       mask = sh_addralign - 1;
99848fb7bfaSmrg       new_sh_offset = sh_offset + mask;
99948fb7bfaSmrg       new_sh_offset &= ~ mask;
100048fb7bfaSmrg       while (new_sh_offset > sh_offset)
100148fb7bfaSmrg 	{
100248fb7bfaSmrg 	  unsigned char zeroes[16];
100348fb7bfaSmrg 	  size_t write;
100448fb7bfaSmrg 
100548fb7bfaSmrg 	  memset (zeroes, 0, sizeof zeroes);
100648fb7bfaSmrg 	  write = new_sh_offset - sh_offset;
100748fb7bfaSmrg 	  if (write > sizeof zeroes)
100848fb7bfaSmrg 	    write = sizeof zeroes;
100948fb7bfaSmrg 	  if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
101048fb7bfaSmrg 					     write, &errmsg, err))
101148fb7bfaSmrg 	    return errmsg;
101248fb7bfaSmrg 	  sh_offset += write;
101348fb7bfaSmrg 	}
101448fb7bfaSmrg 
101548fb7bfaSmrg       sh_size = 0;
101648fb7bfaSmrg       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
101748fb7bfaSmrg 	{
101848fb7bfaSmrg 	  if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
101948fb7bfaSmrg 					     ((const unsigned char *)
102048fb7bfaSmrg 					      buffer->buffer),
102148fb7bfaSmrg 					     buffer->size, &errmsg, err))
102248fb7bfaSmrg 	    return errmsg;
102348fb7bfaSmrg 	  sh_size += buffer->size;
102448fb7bfaSmrg 	}
102548fb7bfaSmrg 
102648fb7bfaSmrg       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1027a3e9eb18Smrg 					 sh_name, sh_type, sh_flags,
1028a3e9eb18Smrg 					 sh_addr, sh_offset,
1029a3e9eb18Smrg 					 sh_size, sh_link, sh_info,
1030a3e9eb18Smrg 					 sh_addralign, sh_entsize,
103148fb7bfaSmrg 					 &errmsg, err))
103248fb7bfaSmrg 	return errmsg;
103348fb7bfaSmrg 
103448fb7bfaSmrg       shdr_offset += shdr_size;
103548fb7bfaSmrg       sh_name += strlen (section->name) + 1;
103648fb7bfaSmrg       sh_offset += sh_size;
103748fb7bfaSmrg     }
103848fb7bfaSmrg 
103948fb7bfaSmrg   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
1040a3e9eb18Smrg 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
1041a3e9eb18Smrg 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
1042a3e9eb18Smrg 				     1, 0, &errmsg, err))
104348fb7bfaSmrg     return errmsg;
104448fb7bfaSmrg 
104548fb7bfaSmrg   /* .shstrtab has a leading zero byte.  */
104648fb7bfaSmrg   zero = 0;
104748fb7bfaSmrg   if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
104848fb7bfaSmrg 				     &errmsg, err))
104948fb7bfaSmrg     return errmsg;
105048fb7bfaSmrg   ++sh_offset;
105148fb7bfaSmrg 
105248fb7bfaSmrg   for (section = sobj->sections; section != NULL; section = section->next)
105348fb7bfaSmrg     {
105448fb7bfaSmrg       size_t len;
105548fb7bfaSmrg 
105648fb7bfaSmrg       len = strlen (section->name) + 1;
105748fb7bfaSmrg       if (!simple_object_internal_write (descriptor, sh_offset,
105848fb7bfaSmrg 					 (const unsigned char *) section->name,
105948fb7bfaSmrg 					 len, &errmsg, err))
106048fb7bfaSmrg 	return errmsg;
106148fb7bfaSmrg       sh_offset += len;
106248fb7bfaSmrg     }
106348fb7bfaSmrg 
106448fb7bfaSmrg   if (!simple_object_internal_write (descriptor, sh_offset,
106548fb7bfaSmrg 				     (const unsigned char *) ".shstrtab",
106648fb7bfaSmrg 				     strlen (".shstrtab") + 1, &errmsg, err))
106748fb7bfaSmrg     return errmsg;
106848fb7bfaSmrg 
106948fb7bfaSmrg   return NULL;
107048fb7bfaSmrg }
107148fb7bfaSmrg 
107248fb7bfaSmrg /* Release the private data for an simple_object_write structure.  */
107348fb7bfaSmrg 
107448fb7bfaSmrg static void
simple_object_elf_release_write(void * data)107548fb7bfaSmrg simple_object_elf_release_write (void *data)
107648fb7bfaSmrg {
1077a3e9eb18Smrg   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
1078a3e9eb18Smrg   if (eow->shdrs)
1079a3e9eb18Smrg     XDELETE (eow->shdrs);
108048fb7bfaSmrg   XDELETE (data);
108148fb7bfaSmrg }
108248fb7bfaSmrg 
1083a3e9eb18Smrg /* Copy all sections in an ELF file.  */
1084a3e9eb18Smrg 
1085a3e9eb18Smrg static const char *
simple_object_elf_copy_lto_debug_sections(simple_object_read * sobj,simple_object_write * dobj,char * (* pfn)(const char *),int * err)1086a3e9eb18Smrg simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
1087a3e9eb18Smrg 					   simple_object_write *dobj,
1088a3e9eb18Smrg 					   char *(*pfn) (const char *),
1089a3e9eb18Smrg 					   int *err)
1090a3e9eb18Smrg {
1091a3e9eb18Smrg   struct simple_object_elf_read *eor =
1092a3e9eb18Smrg     (struct simple_object_elf_read *) sobj->data;
1093a3e9eb18Smrg   const struct elf_type_functions *type_functions = eor->type_functions;
1094a3e9eb18Smrg   struct simple_object_elf_write *eow =
1095a3e9eb18Smrg     (struct simple_object_elf_write *) dobj->data;
1096a3e9eb18Smrg   unsigned char ei_class = eor->ei_class;
1097a3e9eb18Smrg   size_t shdr_size;
1098a3e9eb18Smrg   unsigned int shnum;
1099a3e9eb18Smrg   unsigned char *shdrs;
1100a3e9eb18Smrg   const char *errmsg;
1101a3e9eb18Smrg   unsigned char *shstrhdr;
1102a3e9eb18Smrg   size_t name_size;
1103a3e9eb18Smrg   off_t shstroff;
1104a3e9eb18Smrg   unsigned char *names;
1105a3e9eb18Smrg   unsigned int i;
1106a3e9eb18Smrg   int changed;
1107a3e9eb18Smrg   int *pfnret;
1108a3e9eb18Smrg   const char **pfnname;
1109a3e9eb18Smrg   unsigned new_i;
1110a3e9eb18Smrg   unsigned *sh_map;
1111a3e9eb18Smrg   unsigned first_shndx = 0;
1112a3e9eb18Smrg   unsigned int *symtab_indices_shndx;
1113a3e9eb18Smrg 
1114a3e9eb18Smrg   shdr_size = (ei_class == ELFCLASS32
1115a3e9eb18Smrg 	       ? sizeof (Elf32_External_Shdr)
1116a3e9eb18Smrg 	       : sizeof (Elf64_External_Shdr));
1117a3e9eb18Smrg 
1118a3e9eb18Smrg   /* Read the section headers.  We skip section 0, which is not a
1119a3e9eb18Smrg      useful section.  */
1120a3e9eb18Smrg 
1121a3e9eb18Smrg   shnum = eor->shnum;
1122a3e9eb18Smrg   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
1123a3e9eb18Smrg 
1124a3e9eb18Smrg   if (!simple_object_internal_read (sobj->descriptor,
1125a3e9eb18Smrg 				    sobj->offset + eor->shoff + shdr_size,
1126a3e9eb18Smrg 				    shdrs,
1127a3e9eb18Smrg 				    shdr_size * (shnum - 1),
1128a3e9eb18Smrg 				    &errmsg, err))
1129a3e9eb18Smrg     {
1130a3e9eb18Smrg       XDELETEVEC (shdrs);
1131a3e9eb18Smrg       return errmsg;
1132a3e9eb18Smrg     }
1133a3e9eb18Smrg 
1134a3e9eb18Smrg   /* Read the section names.  */
1135a3e9eb18Smrg 
1136a3e9eb18Smrg   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
1137a3e9eb18Smrg   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1138a3e9eb18Smrg 			       shstrhdr, sh_size, Elf_Addr);
1139a3e9eb18Smrg   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1140a3e9eb18Smrg 			      shstrhdr, sh_offset, Elf_Addr);
1141a3e9eb18Smrg   names = XNEWVEC (unsigned char, name_size);
1142a3e9eb18Smrg   if (!simple_object_internal_read (sobj->descriptor,
1143a3e9eb18Smrg 				    sobj->offset + shstroff,
1144a3e9eb18Smrg 				    names, name_size, &errmsg, err))
1145a3e9eb18Smrg     {
1146a3e9eb18Smrg       XDELETEVEC (names);
1147a3e9eb18Smrg       XDELETEVEC (shdrs);
1148a3e9eb18Smrg       return errmsg;
1149a3e9eb18Smrg     }
1150a3e9eb18Smrg 
1151a3e9eb18Smrg   pfnret = XNEWVEC (int, shnum);
1152a3e9eb18Smrg   pfnname = XNEWVEC (const char *, shnum);
1153a3e9eb18Smrg 
1154a3e9eb18Smrg   /* Map of symtab to index section.  */
1155a3e9eb18Smrg   symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1);
1156a3e9eb18Smrg 
1157a3e9eb18Smrg   /* First perform the callbacks to know which sections to preserve and
1158a3e9eb18Smrg      what name to use for those.  */
1159a3e9eb18Smrg   for (i = 1; i < shnum; ++i)
1160a3e9eb18Smrg     {
1161a3e9eb18Smrg       unsigned char *shdr;
1162a3e9eb18Smrg       unsigned int sh_name, sh_type;
1163a3e9eb18Smrg       const char *name;
1164a3e9eb18Smrg       char *ret;
1165a3e9eb18Smrg 
1166a3e9eb18Smrg       shdr = shdrs + (i - 1) * shdr_size;
1167a3e9eb18Smrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1168a3e9eb18Smrg 				 shdr, sh_name, Elf_Word);
1169a3e9eb18Smrg       if (sh_name >= name_size)
1170a3e9eb18Smrg 	{
1171a3e9eb18Smrg 	  *err = 0;
1172a3e9eb18Smrg 	  XDELETEVEC (names);
1173a3e9eb18Smrg 	  XDELETEVEC (shdrs);
1174a3e9eb18Smrg 	  return "ELF section name out of range";
1175a3e9eb18Smrg 	}
1176a3e9eb18Smrg 
1177a3e9eb18Smrg       name = (const char *) names + sh_name;
1178a3e9eb18Smrg 
1179a3e9eb18Smrg       ret = (*pfn) (name);
1180a3e9eb18Smrg       pfnret[i - 1] = ret == NULL ? -1 : 0;
1181a3e9eb18Smrg       pfnname[i - 1] = ret == NULL ? name : ret;
1182a3e9eb18Smrg       if (first_shndx == 0
1183a3e9eb18Smrg 	  && pfnret[i - 1] == 0)
1184a3e9eb18Smrg 	first_shndx = i;
1185a3e9eb18Smrg 
1186a3e9eb18Smrg       /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections.  */
1187a3e9eb18Smrg       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1188a3e9eb18Smrg 				 shdr, sh_type, Elf_Word);
1189a3e9eb18Smrg       if (sh_type == SHT_SYMTAB_SHNDX)
1190a3e9eb18Smrg 	{
1191a3e9eb18Smrg 	  unsigned int sh_link;
1192a3e9eb18Smrg 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1193a3e9eb18Smrg 				     shdr, sh_link, Elf_Word);
1194fb8a8121Smrg 	  symtab_indices_shndx[sh_link - 1] = i - 1;
1195a3e9eb18Smrg 	  /* Always discard the extended index sections, after
1196a3e9eb18Smrg 	     copying it will not be needed.  This way we don't need to
1197a3e9eb18Smrg 	     update it and deal with the ordering constraints of
1198a3e9eb18Smrg 	     processing the existing symtab and changing the index.  */
1199a3e9eb18Smrg 	  pfnret[i - 1] = -1;
1200a3e9eb18Smrg 	}
1201a3e9eb18Smrg     }
1202a3e9eb18Smrg 
1203a3e9eb18Smrg   /* Mark sections as preserved that are required by to be preserved
1204a3e9eb18Smrg      sections.  */
1205a3e9eb18Smrg   do
1206a3e9eb18Smrg     {
1207a3e9eb18Smrg       changed = 0;
1208a3e9eb18Smrg       for (i = 1; i < shnum; ++i)
1209a3e9eb18Smrg 	{
1210a3e9eb18Smrg 	  unsigned char *shdr;
1211a3e9eb18Smrg 	  unsigned int sh_type, sh_info, sh_link;
1212a3e9eb18Smrg 	  off_t offset;
1213a3e9eb18Smrg 	  off_t length;
1214a3e9eb18Smrg 
1215a3e9eb18Smrg 	  shdr = shdrs + (i - 1) * shdr_size;
1216a3e9eb18Smrg 	  sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1217a3e9eb18Smrg 				     shdr, sh_type, Elf_Word);
1218a3e9eb18Smrg 	  sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1219a3e9eb18Smrg 				     shdr, sh_info, Elf_Word);
1220a3e9eb18Smrg 	  sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1221a3e9eb18Smrg 				     shdr, sh_link, Elf_Word);
1222a3e9eb18Smrg 	  if (sh_type == SHT_GROUP)
1223a3e9eb18Smrg 	    {
1224a3e9eb18Smrg 	      /* Mark groups containing copied sections.  */
1225a3e9eb18Smrg 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class,
1226a3e9eb18Smrg 						  Shdr, shdr, sh_entsize,
1227a3e9eb18Smrg 						  Elf_Addr);
1228a3e9eb18Smrg 	      unsigned char *ent, *buf;
1229a3e9eb18Smrg 	      int keep = 0;
1230a3e9eb18Smrg 	      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1231a3e9eb18Smrg 					shdr, sh_offset, Elf_Addr);
1232a3e9eb18Smrg 	      length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1233a3e9eb18Smrg 					shdr, sh_size, Elf_Addr);
1234a3e9eb18Smrg 	      buf = XNEWVEC (unsigned char, length);
1235a3e9eb18Smrg 	      if (!simple_object_internal_read (sobj->descriptor,
1236a3e9eb18Smrg 						sobj->offset + offset, buf,
1237a3e9eb18Smrg 						(size_t) length, &errmsg, err))
1238a3e9eb18Smrg 		{
1239a3e9eb18Smrg 		  XDELETEVEC (buf);
1240a3e9eb18Smrg 		  XDELETEVEC (names);
1241a3e9eb18Smrg 		  XDELETEVEC (shdrs);
1242a3e9eb18Smrg 		  return errmsg;
1243a3e9eb18Smrg 		}
1244a3e9eb18Smrg 	      for (ent = buf + entsize; ent < buf + length; ent += entsize)
1245a3e9eb18Smrg 		{
1246a3e9eb18Smrg 		  unsigned sec = type_functions->fetch_Elf_Word (ent);
1247a3e9eb18Smrg 		  if (pfnret[sec - 1] == 0)
1248a3e9eb18Smrg 		    keep = 1;
1249a3e9eb18Smrg 		}
1250a3e9eb18Smrg 	      if (keep)
1251a3e9eb18Smrg 		{
1252a3e9eb18Smrg 		  changed |= (pfnret[sh_link - 1] == -1
1253a3e9eb18Smrg 			      || pfnret[i - 1] == -1);
1254a3e9eb18Smrg 		  pfnret[sh_link - 1] = 0;
1255a3e9eb18Smrg 		  pfnret[i - 1] = 0;
1256a3e9eb18Smrg 		}
1257a3e9eb18Smrg 	    }
1258a3e9eb18Smrg 	  if (sh_type == SHT_RELA
1259a3e9eb18Smrg 	      || sh_type == SHT_REL)
1260a3e9eb18Smrg 	    {
1261a3e9eb18Smrg 	      /* Mark relocation sections and symtab of copied sections.  */
1262a3e9eb18Smrg 	      if (pfnret[sh_info - 1] == 0)
1263a3e9eb18Smrg 		{
1264a3e9eb18Smrg 		  changed |= (pfnret[sh_link - 1] == -1
1265a3e9eb18Smrg 			      || pfnret[i - 1] == -1);
1266a3e9eb18Smrg 		  pfnret[sh_link - 1] = 0;
1267a3e9eb18Smrg 		  pfnret[i - 1] = 0;
1268a3e9eb18Smrg 		}
1269a3e9eb18Smrg 	    }
1270a3e9eb18Smrg 	  if (sh_type == SHT_SYMTAB)
1271a3e9eb18Smrg 	    {
1272a3e9eb18Smrg 	      /* Mark strings sections of copied symtabs.  */
1273a3e9eb18Smrg 	      if (pfnret[i - 1] == 0)
1274a3e9eb18Smrg 		{
1275a3e9eb18Smrg 		  changed |= pfnret[sh_link - 1] == -1;
1276a3e9eb18Smrg 		  pfnret[sh_link - 1] = 0;
1277a3e9eb18Smrg 		}
1278a3e9eb18Smrg 	    }
1279a3e9eb18Smrg 	}
1280a3e9eb18Smrg     }
1281a3e9eb18Smrg   while (changed);
1282a3e9eb18Smrg 
1283a3e9eb18Smrg   /* Compute a mapping of old -> new section numbers.  */
1284a3e9eb18Smrg   sh_map = XNEWVEC (unsigned, shnum);
1285a3e9eb18Smrg   sh_map[0] = 0;
1286a3e9eb18Smrg   new_i = 1;
1287a3e9eb18Smrg   for (i = 1; i < shnum; ++i)
1288a3e9eb18Smrg     {
1289a3e9eb18Smrg       if (pfnret[i - 1] == -1)
1290a3e9eb18Smrg 	sh_map[i] = 0;
1291a3e9eb18Smrg       else
1292a3e9eb18Smrg 	sh_map[i] = new_i++;
1293a3e9eb18Smrg     }
1294a3e9eb18Smrg   if (new_i - 1 >= SHN_LORESERVE)
1295a3e9eb18Smrg     {
1296a3e9eb18Smrg       *err = ENOTSUP;
1297a3e9eb18Smrg       return "Too many copied sections";
1298a3e9eb18Smrg     }
1299a3e9eb18Smrg   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
1300a3e9eb18Smrg 
1301a3e9eb18Smrg   /* Then perform the actual copying.  */
1302a3e9eb18Smrg   new_i = 0;
1303a3e9eb18Smrg   for (i = 1; i < shnum; ++i)
1304a3e9eb18Smrg     {
1305a3e9eb18Smrg       unsigned char *shdr;
1306a3e9eb18Smrg       unsigned int sh_name, sh_type;
1307a3e9eb18Smrg       const char *name;
1308a3e9eb18Smrg       off_t offset;
1309a3e9eb18Smrg       off_t length;
1310a3e9eb18Smrg       simple_object_write_section *dest;
1311a3e9eb18Smrg       off_t flags;
1312a3e9eb18Smrg       unsigned char *buf;
1313a3e9eb18Smrg 
1314a3e9eb18Smrg       if (pfnret[i - 1])
1315a3e9eb18Smrg 	continue;
1316a3e9eb18Smrg 
1317a3e9eb18Smrg       new_i++;
1318a3e9eb18Smrg       shdr = shdrs + (i - 1) * shdr_size;
1319a3e9eb18Smrg       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1320a3e9eb18Smrg 				 shdr, sh_name, Elf_Word);
1321a3e9eb18Smrg       if (sh_name >= name_size)
1322a3e9eb18Smrg 	{
1323a3e9eb18Smrg 	  *err = 0;
1324a3e9eb18Smrg 	  XDELETEVEC (names);
1325a3e9eb18Smrg 	  XDELETEVEC (shdrs);
1326a3e9eb18Smrg 	  XDELETEVEC (symtab_indices_shndx);
1327a3e9eb18Smrg 	  return "ELF section name out of range";
1328a3e9eb18Smrg 	}
1329a3e9eb18Smrg 
1330a3e9eb18Smrg       name = pfnname[i - 1];
1331a3e9eb18Smrg       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1332a3e9eb18Smrg 				shdr, sh_offset, Elf_Addr);
1333a3e9eb18Smrg       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1334a3e9eb18Smrg 				shdr, sh_size, Elf_Addr);
1335a3e9eb18Smrg       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1336a3e9eb18Smrg 				 shdr, sh_type, Elf_Word);
1337a3e9eb18Smrg 
1338a3e9eb18Smrg       dest = simple_object_write_create_section (dobj, pfnname[i - 1],
1339a3e9eb18Smrg 						 0, &errmsg, err);
1340a3e9eb18Smrg       if (dest == NULL)
1341a3e9eb18Smrg 	{
1342a3e9eb18Smrg 	  XDELETEVEC (names);
1343a3e9eb18Smrg 	  XDELETEVEC (shdrs);
1344a3e9eb18Smrg 	  XDELETEVEC (symtab_indices_shndx);
1345a3e9eb18Smrg 	  return errmsg;
1346a3e9eb18Smrg 	}
1347a3e9eb18Smrg 
1348a3e9eb18Smrg       /* Record the SHDR of the source.  */
1349a3e9eb18Smrg       memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size);
1350a3e9eb18Smrg       shdr = eow->shdrs + (new_i - 1) * shdr_size;
1351a3e9eb18Smrg 
1352a3e9eb18Smrg       /* Copy the data.
1353a3e9eb18Smrg 	 ???  This is quite wasteful and ideally would be delayed until
1354a3e9eb18Smrg 	 write_to_file ().  Thus it questions the interfacing
1355a3e9eb18Smrg 	 which eventually should contain destination creation plus
1356a3e9eb18Smrg 	 writing.  */
1357a3e9eb18Smrg       buf = XNEWVEC (unsigned char, length);
1358a3e9eb18Smrg       if (!simple_object_internal_read (sobj->descriptor,
1359a3e9eb18Smrg 					sobj->offset + offset, buf,
1360a3e9eb18Smrg 					(size_t) length, &errmsg, err))
1361a3e9eb18Smrg 	{
1362a3e9eb18Smrg 	  XDELETEVEC (buf);
1363a3e9eb18Smrg 	  XDELETEVEC (names);
1364a3e9eb18Smrg 	  XDELETEVEC (shdrs);
1365a3e9eb18Smrg 	  XDELETEVEC (symtab_indices_shndx);
1366a3e9eb18Smrg 	  return errmsg;
1367a3e9eb18Smrg 	}
1368a3e9eb18Smrg 
1369fb8a8121Smrg       /* If we are processing .symtab purge any symbols
1370fb8a8121Smrg 	 in discarded sections.  */
1371a3e9eb18Smrg       if (sh_type == SHT_SYMTAB)
1372a3e9eb18Smrg 	{
1373a3e9eb18Smrg 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1374a3e9eb18Smrg 					      shdr, sh_entsize, Elf_Addr);
1375fb8a8121Smrg 	  size_t prevailing_name_idx = 0;
1376a3e9eb18Smrg 	  unsigned char *ent;
1377a3e9eb18Smrg 	  unsigned *shndx_table = NULL;
1378a3e9eb18Smrg 	  /* Read the section index table if present.  */
1379a3e9eb18Smrg 	  if (symtab_indices_shndx[i - 1] != 0)
1380a3e9eb18Smrg 	    {
1381fb8a8121Smrg 	      unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size;
1382a3e9eb18Smrg 	      off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1383a3e9eb18Smrg 					       sidxhdr, sh_offset, Elf_Addr);
1384a3e9eb18Smrg 	      size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1385a3e9eb18Smrg 					       sidxhdr, sh_size, Elf_Addr);
1386fb8a8121Smrg 	      unsigned int shndx_type
1387fb8a8121Smrg 		= ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1388fb8a8121Smrg 				   sidxhdr, sh_type, Elf_Word);
1389fb8a8121Smrg 	      if (shndx_type != SHT_SYMTAB_SHNDX)
1390fb8a8121Smrg 		return "Wrong section type of a SYMTAB SECTION INDICES section";
1391a3e9eb18Smrg 	      shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
1392a3e9eb18Smrg 	      simple_object_internal_read (sobj->descriptor,
1393a3e9eb18Smrg 					   sobj->offset + sidxoff,
1394a3e9eb18Smrg 					   (unsigned char *)shndx_table,
1395a3e9eb18Smrg 					   sidxsz, &errmsg, err);
1396a3e9eb18Smrg 	    }
1397fb8a8121Smrg 
1398fb8a8121Smrg 	  /* Find a WEAK HIDDEN symbol which name we will use for removed
1399fb8a8121Smrg 	     symbols.  We know there's a prevailing weak hidden symbol
1400fb8a8121Smrg 	     at the start of the .debug_info section.  */
1401fb8a8121Smrg 	  for (ent = buf; ent < buf + length; ent += entsize)
1402fb8a8121Smrg 	    {
1403fb8a8121Smrg 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
1404fb8a8121Smrg 						   Sym, ent,
1405fb8a8121Smrg 						   st_shndx, Elf_Half);
1406fb8a8121Smrg 	      unsigned char *st_info;
1407fb8a8121Smrg 	      unsigned char *st_other;
1408fb8a8121Smrg 	      if (ei_class == ELFCLASS32)
1409fb8a8121Smrg 		{
1410fb8a8121Smrg 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
1411fb8a8121Smrg 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
1412fb8a8121Smrg 		}
1413fb8a8121Smrg 	      else
1414fb8a8121Smrg 		{
1415fb8a8121Smrg 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
1416fb8a8121Smrg 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
1417fb8a8121Smrg 		}
1418fb8a8121Smrg 	      if (st_shndx == SHN_XINDEX)
1419fb8a8121Smrg 		st_shndx = type_functions->fetch_Elf_Word
1420fb8a8121Smrg 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
1421fb8a8121Smrg 
1422fb8a8121Smrg 	      if (st_shndx != SHN_COMMON
1423fb8a8121Smrg 		  && !(st_shndx != SHN_UNDEF
1424fb8a8121Smrg 		       && st_shndx < shnum
1425fb8a8121Smrg 		       && pfnret[st_shndx - 1] == -1)
1426fb8a8121Smrg 		  && ELF_ST_BIND (*st_info) == STB_WEAK
1427fb8a8121Smrg 		  && *st_other == STV_HIDDEN)
1428fb8a8121Smrg 		{
1429fb8a8121Smrg 		  prevailing_name_idx = ELF_FETCH_FIELD (type_functions,
1430fb8a8121Smrg 							 ei_class, Sym, ent,
1431fb8a8121Smrg 							 st_name, Elf_Word);
1432fb8a8121Smrg 		  break;
1433fb8a8121Smrg 		}
1434fb8a8121Smrg 	    }
1435fb8a8121Smrg 
1436a3e9eb18Smrg 	  for (ent = buf; ent < buf + length; ent += entsize)
1437a3e9eb18Smrg 	    {
1438a3e9eb18Smrg 	      unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
1439a3e9eb18Smrg 						   Sym, ent,
1440a3e9eb18Smrg 						   st_shndx, Elf_Half);
1441a3e9eb18Smrg 	      unsigned raw_st_shndx = st_shndx;
1442a3e9eb18Smrg 	      unsigned char *st_info;
1443a3e9eb18Smrg 	      unsigned char *st_other;
1444a3e9eb18Smrg 	      int discard = 0;
1445a3e9eb18Smrg 	      if (ei_class == ELFCLASS32)
1446a3e9eb18Smrg 		{
1447a3e9eb18Smrg 		  st_info = &((Elf32_External_Sym *)ent)->st_info;
1448a3e9eb18Smrg 		  st_other = &((Elf32_External_Sym *)ent)->st_other;
1449a3e9eb18Smrg 		}
1450a3e9eb18Smrg 	      else
1451a3e9eb18Smrg 		{
1452a3e9eb18Smrg 		  st_info = &((Elf64_External_Sym *)ent)->st_info;
1453a3e9eb18Smrg 		  st_other = &((Elf64_External_Sym *)ent)->st_other;
1454a3e9eb18Smrg 		}
1455a3e9eb18Smrg 	      if (st_shndx == SHN_XINDEX)
1456a3e9eb18Smrg 		st_shndx = type_functions->fetch_Elf_Word
1457a3e9eb18Smrg 		    ((unsigned char *)(shndx_table + (ent - buf) / entsize));
1458fb8a8121Smrg 	      /* Eliminate all COMMONs - this includes __gnu_lto_slim
1459fb8a8121Smrg 		 which otherwise cause endless LTO plugin invocation.
1460fb8a8121Smrg 		 FIXME: remove the condition once we remove emission
1461fb8a8121Smrg 		 of __gnu_lto_slim symbol.  */
1462a3e9eb18Smrg 	      if (st_shndx == SHN_COMMON)
1463a3e9eb18Smrg 		discard = 1;
1464a3e9eb18Smrg 	      /* We also need to remove symbols refering to sections
1465a3e9eb18Smrg 		 we'll eventually remove as with fat LTO objects
1466a3e9eb18Smrg 		 we otherwise get duplicate symbols at final link
1467a3e9eb18Smrg 		 (with GNU ld, gold is fine and ignores symbols in
1468a3e9eb18Smrg 		 sections marked as EXCLUDE).  ld/20513  */
1469a3e9eb18Smrg 	      else if (st_shndx != SHN_UNDEF
1470a3e9eb18Smrg 		       && st_shndx < shnum
1471a3e9eb18Smrg 		       && pfnret[st_shndx - 1] == -1)
1472a3e9eb18Smrg 		discard = 1;
1473fb8a8121Smrg 	      /* We also need to remove global UNDEFs which can
1474fb8a8121Smrg 		 cause link fails later.  */
1475fb8a8121Smrg 	      else if (st_shndx == SHN_UNDEF
1476fb8a8121Smrg 		       && ELF_ST_BIND (*st_info) == STB_GLOBAL)
1477fb8a8121Smrg 		discard = 1;
1478a3e9eb18Smrg 
1479a3e9eb18Smrg 	      if (discard)
1480a3e9eb18Smrg 		{
1481a3e9eb18Smrg 		  /* Make discarded symbols undefined and unnamed
1482a3e9eb18Smrg 		     in case it is local.  */
1483a3e9eb18Smrg 		  int bind = ELF_ST_BIND (*st_info);
1484a3e9eb18Smrg 		  int other = STV_DEFAULT;
1485a3e9eb18Smrg 		  if (bind == STB_LOCAL)
1486a3e9eb18Smrg 		    {
1487a3e9eb18Smrg 		      /* Make discarded local symbols unnamed and
1488a3e9eb18Smrg 			 defined in the first prevailing section.  */
1489a3e9eb18Smrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1490a3e9eb18Smrg 				     ent, st_name, Elf_Word, 0);
1491a3e9eb18Smrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1492a3e9eb18Smrg 				     ent, st_shndx, Elf_Half,
1493a3e9eb18Smrg 				     sh_map[first_shndx]);
1494a3e9eb18Smrg 		    }
1495a3e9eb18Smrg 		  else
1496a3e9eb18Smrg 		    {
1497a3e9eb18Smrg 		      /* Make discarded global symbols hidden weak
1498fb8a8121Smrg 			 undefined and sharing a name of a prevailing
1499fb8a8121Smrg 			 symbol.  */
1500a3e9eb18Smrg 		      bind = STB_WEAK;
1501a3e9eb18Smrg 		      other = STV_HIDDEN;
1502a3e9eb18Smrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1503a3e9eb18Smrg 				     ent, st_name, Elf_Word,
1504fb8a8121Smrg 				     prevailing_name_idx);
1505a3e9eb18Smrg 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
1506a3e9eb18Smrg 				     ent, st_shndx, Elf_Half, SHN_UNDEF);
1507a3e9eb18Smrg 		    }
1508a3e9eb18Smrg 		  *st_other = other;
1509a3e9eb18Smrg 		  *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
1510a3e9eb18Smrg 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1511a3e9eb18Smrg 				 ent, st_value, Elf_Addr, 0);
1512a3e9eb18Smrg 		  ELF_SET_FIELD (type_functions, ei_class, Sym,
1513a3e9eb18Smrg 				 ent, st_size, Elf_Word, 0);
1514a3e9eb18Smrg 		}
1515a3e9eb18Smrg 	      else if (raw_st_shndx < SHN_LORESERVE
1516a3e9eb18Smrg 		       || raw_st_shndx == SHN_XINDEX)
1517a3e9eb18Smrg 		/* Remap the section reference.  */
1518a3e9eb18Smrg 		ELF_SET_FIELD (type_functions, ei_class, Sym,
1519a3e9eb18Smrg 			       ent, st_shndx, Elf_Half, sh_map[st_shndx]);
1520a3e9eb18Smrg 	    }
1521a3e9eb18Smrg 	  XDELETEVEC (shndx_table);
1522a3e9eb18Smrg 	}
1523a3e9eb18Smrg       else if (sh_type == SHT_GROUP)
1524a3e9eb18Smrg 	{
1525a3e9eb18Smrg 	  /* Remap section indices in groups and remove removed members.  */
1526a3e9eb18Smrg 	  unsigned char *ent, *dst;
1527a3e9eb18Smrg 	  for (dst = ent = buf + 4; ent < buf + length; ent += 4)
1528a3e9eb18Smrg 	    {
1529a3e9eb18Smrg 	      unsigned shndx = type_functions->fetch_Elf_Word (ent);
1530a3e9eb18Smrg 	      if (pfnret[shndx - 1] == -1)
1531a3e9eb18Smrg 		;
1532a3e9eb18Smrg 	      else
1533a3e9eb18Smrg 		{
1534a3e9eb18Smrg 		  type_functions->set_Elf_Word (dst, sh_map[shndx]);
1535a3e9eb18Smrg 		  dst += 4;
1536a3e9eb18Smrg 		}
1537a3e9eb18Smrg 	    }
1538a3e9eb18Smrg 	  /* Adjust the length.  */
1539a3e9eb18Smrg 	  length = dst - buf;
1540a3e9eb18Smrg 	}
1541a3e9eb18Smrg 
1542a3e9eb18Smrg       errmsg = simple_object_write_add_data (dobj, dest,
1543a3e9eb18Smrg 					     buf, length, 1, err);
1544a3e9eb18Smrg       XDELETEVEC (buf);
1545a3e9eb18Smrg       if (errmsg)
1546a3e9eb18Smrg 	{
1547a3e9eb18Smrg 	  XDELETEVEC (names);
1548a3e9eb18Smrg 	  XDELETEVEC (shdrs);
1549a3e9eb18Smrg 	  XDELETEVEC (symtab_indices_shndx);
1550a3e9eb18Smrg 	  return errmsg;
1551a3e9eb18Smrg 	}
1552a3e9eb18Smrg 
1553a3e9eb18Smrg       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1554a3e9eb18Smrg 			       shdr, sh_flags, Elf_Addr);
1555a3e9eb18Smrg       /* Remap the section references.  */
1556a3e9eb18Smrg       {
1557a3e9eb18Smrg 	unsigned int sh_info, sh_link;
1558a3e9eb18Smrg 	if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA)
1559a3e9eb18Smrg 	  {
1560a3e9eb18Smrg 	    sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1561a3e9eb18Smrg 				       shdr, sh_info, Elf_Word);
1562a3e9eb18Smrg 	    sh_info = sh_map[sh_info];
1563a3e9eb18Smrg 	    ELF_SET_FIELD (type_functions, ei_class, Shdr,
1564a3e9eb18Smrg 			   shdr, sh_info, Elf_Word, sh_info);
1565a3e9eb18Smrg 	  }
1566a3e9eb18Smrg 	sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
1567a3e9eb18Smrg 				   shdr, sh_link, Elf_Word);
1568a3e9eb18Smrg 	sh_link = sh_map[sh_link];
1569a3e9eb18Smrg 	ELF_SET_FIELD (type_functions, ei_class, Shdr,
1570a3e9eb18Smrg 		       shdr, sh_link, Elf_Word, sh_link);
1571a3e9eb18Smrg       }
1572a3e9eb18Smrg       /* The debugobj doesn't contain any code, thus no trampolines.
1573a3e9eb18Smrg 	 Even when the original object needs trampolines, debugobj
1574a3e9eb18Smrg 	 doesn't.  */
1575a3e9eb18Smrg       if (strcmp (name, ".note.GNU-stack") == 0)
1576a3e9eb18Smrg 	flags &= ~SHF_EXECINSTR;
1577a3e9eb18Smrg       /* Clear SHF_EXCLUDE on to be preserved sections.  */
1578a3e9eb18Smrg       flags &= ~SHF_EXCLUDE;
1579a3e9eb18Smrg       ELF_SET_FIELD (type_functions, ei_class, Shdr,
1580a3e9eb18Smrg 		     shdr, sh_flags, Elf_Addr, flags);
1581a3e9eb18Smrg     }
1582a3e9eb18Smrg 
1583a3e9eb18Smrg   XDELETEVEC (names);
1584a3e9eb18Smrg   XDELETEVEC (shdrs);
1585a3e9eb18Smrg   XDELETEVEC (pfnret);
1586a3e9eb18Smrg   XDELETEVEC (pfnname);
1587a3e9eb18Smrg   XDELETEVEC (symtab_indices_shndx);
1588a3e9eb18Smrg   XDELETEVEC (sh_map);
1589a3e9eb18Smrg 
1590a3e9eb18Smrg   return NULL;
1591a3e9eb18Smrg }
1592a3e9eb18Smrg 
1593a3e9eb18Smrg 
159448fb7bfaSmrg /* The ELF functions.  */
159548fb7bfaSmrg 
159648fb7bfaSmrg const struct simple_object_functions simple_object_elf_functions =
159748fb7bfaSmrg {
159848fb7bfaSmrg   simple_object_elf_match,
159948fb7bfaSmrg   simple_object_elf_find_sections,
160048fb7bfaSmrg   simple_object_elf_fetch_attributes,
160148fb7bfaSmrg   simple_object_elf_release_read,
160248fb7bfaSmrg   simple_object_elf_attributes_merge,
160348fb7bfaSmrg   simple_object_elf_release_attributes,
160448fb7bfaSmrg   simple_object_elf_start_write,
160548fb7bfaSmrg   simple_object_elf_write_to_file,
1606a3e9eb18Smrg   simple_object_elf_release_write,
1607a3e9eb18Smrg   simple_object_elf_copy_lto_debug_sections
160848fb7bfaSmrg };
1609