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