186d7f5d3SJohn Marino /* simple-object-elf.c -- routines to manipulate ELF object files.
286d7f5d3SJohn Marino Copyright 2010 Free Software Foundation, Inc.
386d7f5d3SJohn Marino Written by Ian Lance Taylor, Google.
486d7f5d3SJohn Marino
586d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify it
686d7f5d3SJohn Marino under the terms of the GNU General Public License as published by the
786d7f5d3SJohn Marino Free Software Foundation; either version 2, or (at your option) any
886d7f5d3SJohn Marino later version.
986d7f5d3SJohn Marino
1086d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
1186d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1286d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1386d7f5d3SJohn Marino GNU General Public License for more details.
1486d7f5d3SJohn Marino
1586d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
1686d7f5d3SJohn Marino along with this program; if not, write to the Free Software
1786d7f5d3SJohn Marino Foundation, 51 Franklin Street - Fifth Floor,
1886d7f5d3SJohn Marino Boston, MA 02110-1301, USA. */
1986d7f5d3SJohn Marino
2086d7f5d3SJohn Marino #include "config.h"
2186d7f5d3SJohn Marino #include "libiberty.h"
2286d7f5d3SJohn Marino #include "simple-object.h"
2386d7f5d3SJohn Marino
2486d7f5d3SJohn Marino #include <errno.h>
2586d7f5d3SJohn Marino #include <stddef.h>
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino #ifdef HAVE_STDLIB_H
2886d7f5d3SJohn Marino #include <stdlib.h>
2986d7f5d3SJohn Marino #endif
3086d7f5d3SJohn Marino
3186d7f5d3SJohn Marino #ifdef HAVE_STDINT_H
3286d7f5d3SJohn Marino #include <stdint.h>
3386d7f5d3SJohn Marino #endif
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino #ifdef HAVE_STRING_H
3686d7f5d3SJohn Marino #include <string.h>
3786d7f5d3SJohn Marino #endif
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marino #ifdef HAVE_INTTYPES_H
4086d7f5d3SJohn Marino #include <inttypes.h>
4186d7f5d3SJohn Marino #endif
4286d7f5d3SJohn Marino
4386d7f5d3SJohn Marino #include "simple-object-common.h"
4486d7f5d3SJohn Marino
4586d7f5d3SJohn Marino /* ELF structures and constants. */
4686d7f5d3SJohn Marino
4786d7f5d3SJohn Marino /* 32-bit ELF file header. */
4886d7f5d3SJohn Marino
4986d7f5d3SJohn Marino typedef struct {
5086d7f5d3SJohn Marino unsigned char e_ident[16]; /* ELF "magic number" */
5186d7f5d3SJohn Marino unsigned char e_type[2]; /* Identifies object file type */
5286d7f5d3SJohn Marino unsigned char e_machine[2]; /* Specifies required architecture */
5386d7f5d3SJohn Marino unsigned char e_version[4]; /* Identifies object file version */
5486d7f5d3SJohn Marino unsigned char e_entry[4]; /* Entry point virtual address */
5586d7f5d3SJohn Marino unsigned char e_phoff[4]; /* Program header table file offset */
5686d7f5d3SJohn Marino unsigned char e_shoff[4]; /* Section header table file offset */
5786d7f5d3SJohn Marino unsigned char e_flags[4]; /* Processor-specific flags */
5886d7f5d3SJohn Marino unsigned char e_ehsize[2]; /* ELF header size in bytes */
5986d7f5d3SJohn Marino unsigned char e_phentsize[2]; /* Program header table entry size */
6086d7f5d3SJohn Marino unsigned char e_phnum[2]; /* Program header table entry count */
6186d7f5d3SJohn Marino unsigned char e_shentsize[2]; /* Section header table entry size */
6286d7f5d3SJohn Marino unsigned char e_shnum[2]; /* Section header table entry count */
6386d7f5d3SJohn Marino unsigned char e_shstrndx[2]; /* Section header string table index */
6486d7f5d3SJohn Marino } Elf32_External_Ehdr;
6586d7f5d3SJohn Marino
6686d7f5d3SJohn Marino /* 64-bit ELF file header. */
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino typedef struct {
6986d7f5d3SJohn Marino unsigned char e_ident[16]; /* ELF "magic number" */
7086d7f5d3SJohn Marino unsigned char e_type[2]; /* Identifies object file type */
7186d7f5d3SJohn Marino unsigned char e_machine[2]; /* Specifies required architecture */
7286d7f5d3SJohn Marino unsigned char e_version[4]; /* Identifies object file version */
7386d7f5d3SJohn Marino unsigned char e_entry[8]; /* Entry point virtual address */
7486d7f5d3SJohn Marino unsigned char e_phoff[8]; /* Program header table file offset */
7586d7f5d3SJohn Marino unsigned char e_shoff[8]; /* Section header table file offset */
7686d7f5d3SJohn Marino unsigned char e_flags[4]; /* Processor-specific flags */
7786d7f5d3SJohn Marino unsigned char e_ehsize[2]; /* ELF header size in bytes */
7886d7f5d3SJohn Marino unsigned char e_phentsize[2]; /* Program header table entry size */
7986d7f5d3SJohn Marino unsigned char e_phnum[2]; /* Program header table entry count */
8086d7f5d3SJohn Marino unsigned char e_shentsize[2]; /* Section header table entry size */
8186d7f5d3SJohn Marino unsigned char e_shnum[2]; /* Section header table entry count */
8286d7f5d3SJohn Marino unsigned char e_shstrndx[2]; /* Section header string table index */
8386d7f5d3SJohn Marino } Elf64_External_Ehdr;
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino /* Indexes and values in e_ident field of Ehdr. */
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino #define EI_MAG0 0 /* File identification byte 0 index */
8886d7f5d3SJohn Marino #define ELFMAG0 0x7F /* Magic number byte 0 */
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino #define EI_MAG1 1 /* File identification byte 1 index */
9186d7f5d3SJohn Marino #define ELFMAG1 'E' /* Magic number byte 1 */
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino #define EI_MAG2 2 /* File identification byte 2 index */
9486d7f5d3SJohn Marino #define ELFMAG2 'L' /* Magic number byte 2 */
9586d7f5d3SJohn Marino
9686d7f5d3SJohn Marino #define EI_MAG3 3 /* File identification byte 3 index */
9786d7f5d3SJohn Marino #define ELFMAG3 'F' /* Magic number byte 3 */
9886d7f5d3SJohn Marino
9986d7f5d3SJohn Marino #define EI_CLASS 4 /* File class */
10086d7f5d3SJohn Marino #define ELFCLASSNONE 0 /* Invalid class */
10186d7f5d3SJohn Marino #define ELFCLASS32 1 /* 32-bit objects */
10286d7f5d3SJohn Marino #define ELFCLASS64 2 /* 64-bit objects */
10386d7f5d3SJohn Marino
10486d7f5d3SJohn Marino #define EI_DATA 5 /* Data encoding */
10586d7f5d3SJohn Marino #define ELFDATANONE 0 /* Invalid data encoding */
10686d7f5d3SJohn Marino #define ELFDATA2LSB 1 /* 2's complement, little endian */
10786d7f5d3SJohn Marino #define ELFDATA2MSB 2 /* 2's complement, big endian */
10886d7f5d3SJohn Marino
10986d7f5d3SJohn Marino #define EI_VERSION 6 /* File version */
11086d7f5d3SJohn Marino #define EV_CURRENT 1 /* Current version */
11186d7f5d3SJohn Marino
11286d7f5d3SJohn Marino #define EI_OSABI 7 /* Operating System/ABI indication */
11386d7f5d3SJohn Marino
11486d7f5d3SJohn Marino /* Values for e_type field of Ehdr. */
11586d7f5d3SJohn Marino
11686d7f5d3SJohn Marino #define ET_REL 1 /* Relocatable file */
11786d7f5d3SJohn Marino
11886d7f5d3SJohn Marino /* Values for e_machine field of Ehdr. */
11986d7f5d3SJohn Marino
12086d7f5d3SJohn Marino #define EM_SPARC 2 /* SUN SPARC */
12186d7f5d3SJohn Marino #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
12286d7f5d3SJohn Marino
12386d7f5d3SJohn Marino /* Special section index values. */
12486d7f5d3SJohn Marino
12586d7f5d3SJohn Marino #define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
12686d7f5d3SJohn Marino #define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
12786d7f5d3SJohn Marino
12886d7f5d3SJohn Marino /* 32-bit ELF program header. */
12986d7f5d3SJohn Marino
13086d7f5d3SJohn Marino typedef struct {
13186d7f5d3SJohn Marino unsigned char p_type[4]; /* Identifies program segment type */
13286d7f5d3SJohn Marino unsigned char p_offset[4]; /* Segment file offset */
13386d7f5d3SJohn Marino unsigned char p_vaddr[4]; /* Segment virtual address */
13486d7f5d3SJohn Marino unsigned char p_paddr[4]; /* Segment physical address */
13586d7f5d3SJohn Marino unsigned char p_filesz[4]; /* Segment size in file */
13686d7f5d3SJohn Marino unsigned char p_memsz[4]; /* Segment size in memory */
13786d7f5d3SJohn Marino unsigned char p_flags[4]; /* Segment flags */
13886d7f5d3SJohn Marino unsigned char p_align[4]; /* Segment alignment, file & memory */
13986d7f5d3SJohn Marino } Elf32_External_Phdr;
14086d7f5d3SJohn Marino
14186d7f5d3SJohn Marino /* 64-bit ELF program header. */
14286d7f5d3SJohn Marino
14386d7f5d3SJohn Marino typedef struct {
14486d7f5d3SJohn Marino unsigned char p_type[4]; /* Identifies program segment type */
14586d7f5d3SJohn Marino unsigned char p_flags[4]; /* Segment flags */
14686d7f5d3SJohn Marino unsigned char p_offset[8]; /* Segment file offset */
14786d7f5d3SJohn Marino unsigned char p_vaddr[8]; /* Segment virtual address */
14886d7f5d3SJohn Marino unsigned char p_paddr[8]; /* Segment physical address */
14986d7f5d3SJohn Marino unsigned char p_filesz[8]; /* Segment size in file */
15086d7f5d3SJohn Marino unsigned char p_memsz[8]; /* Segment size in memory */
15186d7f5d3SJohn Marino unsigned char p_align[8]; /* Segment alignment, file & memory */
15286d7f5d3SJohn Marino } Elf64_External_Phdr;
15386d7f5d3SJohn Marino
15486d7f5d3SJohn Marino /* 32-bit ELF section header */
15586d7f5d3SJohn Marino
15686d7f5d3SJohn Marino typedef struct {
15786d7f5d3SJohn Marino unsigned char sh_name[4]; /* Section name, index in string tbl */
15886d7f5d3SJohn Marino unsigned char sh_type[4]; /* Type of section */
15986d7f5d3SJohn Marino unsigned char sh_flags[4]; /* Miscellaneous section attributes */
16086d7f5d3SJohn Marino unsigned char sh_addr[4]; /* Section virtual addr at execution */
16186d7f5d3SJohn Marino unsigned char sh_offset[4]; /* Section file offset */
16286d7f5d3SJohn Marino unsigned char sh_size[4]; /* Size of section in bytes */
16386d7f5d3SJohn Marino unsigned char sh_link[4]; /* Index of another section */
16486d7f5d3SJohn Marino unsigned char sh_info[4]; /* Additional section information */
16586d7f5d3SJohn Marino unsigned char sh_addralign[4]; /* Section alignment */
16686d7f5d3SJohn Marino unsigned char sh_entsize[4]; /* Entry size if section holds table */
16786d7f5d3SJohn Marino } Elf32_External_Shdr;
16886d7f5d3SJohn Marino
16986d7f5d3SJohn Marino /* 64-bit ELF section header. */
17086d7f5d3SJohn Marino
17186d7f5d3SJohn Marino typedef struct {
17286d7f5d3SJohn Marino unsigned char sh_name[4]; /* Section name, index in string tbl */
17386d7f5d3SJohn Marino unsigned char sh_type[4]; /* Type of section */
17486d7f5d3SJohn Marino unsigned char sh_flags[8]; /* Miscellaneous section attributes */
17586d7f5d3SJohn Marino unsigned char sh_addr[8]; /* Section virtual addr at execution */
17686d7f5d3SJohn Marino unsigned char sh_offset[8]; /* Section file offset */
17786d7f5d3SJohn Marino unsigned char sh_size[8]; /* Size of section in bytes */
17886d7f5d3SJohn Marino unsigned char sh_link[4]; /* Index of another section */
17986d7f5d3SJohn Marino unsigned char sh_info[4]; /* Additional section information */
18086d7f5d3SJohn Marino unsigned char sh_addralign[8]; /* Section alignment */
18186d7f5d3SJohn Marino unsigned char sh_entsize[8]; /* Entry size if section holds table */
18286d7f5d3SJohn Marino } Elf64_External_Shdr;
18386d7f5d3SJohn Marino
18486d7f5d3SJohn Marino /* Values for sh_type field. */
18586d7f5d3SJohn Marino
18686d7f5d3SJohn Marino #define SHT_PROGBITS 1 /* Program data */
18786d7f5d3SJohn Marino #define SHT_STRTAB 3 /* A string table */
18886d7f5d3SJohn Marino
18986d7f5d3SJohn Marino /* Functions to fetch and store different ELF types, depending on the
19086d7f5d3SJohn Marino endianness and size. */
19186d7f5d3SJohn Marino
19286d7f5d3SJohn Marino struct elf_type_functions
19386d7f5d3SJohn Marino {
19486d7f5d3SJohn Marino unsigned short (*fetch_Elf_Half) (const unsigned char *);
19586d7f5d3SJohn Marino unsigned int (*fetch_Elf_Word) (const unsigned char *);
19686d7f5d3SJohn Marino ulong_type (*fetch_Elf_Addr) (const unsigned char *);
19786d7f5d3SJohn Marino void (*set_Elf_Half) (unsigned char *, unsigned short);
19886d7f5d3SJohn Marino void (*set_Elf_Word) (unsigned char *, unsigned int);
19986d7f5d3SJohn Marino void (*set_Elf_Addr) (unsigned char *, ulong_type);
20086d7f5d3SJohn Marino };
20186d7f5d3SJohn Marino
20286d7f5d3SJohn Marino static const struct elf_type_functions elf_big_32_functions =
20386d7f5d3SJohn Marino {
20486d7f5d3SJohn Marino simple_object_fetch_big_16,
20586d7f5d3SJohn Marino simple_object_fetch_big_32,
20686d7f5d3SJohn Marino simple_object_fetch_big_32_ulong,
20786d7f5d3SJohn Marino simple_object_set_big_16,
20886d7f5d3SJohn Marino simple_object_set_big_32,
20986d7f5d3SJohn Marino simple_object_set_big_32_ulong
21086d7f5d3SJohn Marino };
21186d7f5d3SJohn Marino
21286d7f5d3SJohn Marino static const struct elf_type_functions elf_little_32_functions =
21386d7f5d3SJohn Marino {
21486d7f5d3SJohn Marino simple_object_fetch_little_16,
21586d7f5d3SJohn Marino simple_object_fetch_little_32,
21686d7f5d3SJohn Marino simple_object_fetch_little_32_ulong,
21786d7f5d3SJohn Marino simple_object_set_little_16,
21886d7f5d3SJohn Marino simple_object_set_little_32,
21986d7f5d3SJohn Marino simple_object_set_little_32_ulong
22086d7f5d3SJohn Marino };
22186d7f5d3SJohn Marino
22286d7f5d3SJohn Marino #ifdef UNSIGNED_64BIT_TYPE
22386d7f5d3SJohn Marino
22486d7f5d3SJohn Marino static const struct elf_type_functions elf_big_64_functions =
22586d7f5d3SJohn Marino {
22686d7f5d3SJohn Marino simple_object_fetch_big_16,
22786d7f5d3SJohn Marino simple_object_fetch_big_32,
22886d7f5d3SJohn Marino simple_object_fetch_big_64,
22986d7f5d3SJohn Marino simple_object_set_big_16,
23086d7f5d3SJohn Marino simple_object_set_big_32,
23186d7f5d3SJohn Marino simple_object_set_big_64
23286d7f5d3SJohn Marino };
23386d7f5d3SJohn Marino
23486d7f5d3SJohn Marino static const struct elf_type_functions elf_little_64_functions =
23586d7f5d3SJohn Marino {
23686d7f5d3SJohn Marino simple_object_fetch_little_16,
23786d7f5d3SJohn Marino simple_object_fetch_little_32,
23886d7f5d3SJohn Marino simple_object_fetch_little_64,
23986d7f5d3SJohn Marino simple_object_set_little_16,
24086d7f5d3SJohn Marino simple_object_set_little_32,
24186d7f5d3SJohn Marino simple_object_set_little_64
24286d7f5d3SJohn Marino };
24386d7f5d3SJohn Marino
24486d7f5d3SJohn Marino #endif
24586d7f5d3SJohn Marino
24686d7f5d3SJohn Marino /* Hideous macro to fetch the value of a field from an external ELF
24786d7f5d3SJohn Marino struct of some sort. TYPEFUNCS is the set of type functions.
24886d7f5d3SJohn Marino BUFFER points to the external data. STRUCTTYPE is the appropriate
24986d7f5d3SJohn Marino struct type. FIELD is a field within the struct. TYPE is the type
25086d7f5d3SJohn Marino of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */
25186d7f5d3SJohn Marino
25286d7f5d3SJohn Marino #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
25386d7f5d3SJohn Marino ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
25486d7f5d3SJohn Marino
25586d7f5d3SJohn Marino /* Even more hideous macro to fetch the value of FIELD from BUFFER.
25686d7f5d3SJohn Marino SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
25786d7f5d3SJohn Marino elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
25886d7f5d3SJohn Marino the struct. TYPE is the type of the field in the struct: Elf_Half,
25986d7f5d3SJohn Marino Elf_Word, or Elf_Addr. */
26086d7f5d3SJohn Marino
26186d7f5d3SJohn Marino #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \
26286d7f5d3SJohn Marino FIELD, TYPE) \
26386d7f5d3SJohn Marino ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \
26486d7f5d3SJohn Marino Elf ## SIZE ## _External_ ## STRUCTTYPE, \
26586d7f5d3SJohn Marino FIELD, BUFFER, TYPE)
26686d7f5d3SJohn Marino
26786d7f5d3SJohn Marino /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */
26886d7f5d3SJohn Marino
26986d7f5d3SJohn Marino #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \
27086d7f5d3SJohn Marino FIELD, TYPE) \
27186d7f5d3SJohn Marino ((CLASS) == ELFCLASS32 \
27286d7f5d3SJohn Marino ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
27386d7f5d3SJohn Marino TYPE) \
27486d7f5d3SJohn Marino : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
27586d7f5d3SJohn Marino TYPE))
27686d7f5d3SJohn Marino
27786d7f5d3SJohn Marino /* Hideous macro to set the value of a field in an external ELF
27886d7f5d3SJohn Marino structure to VAL. TYPEFUNCS is the set of type functions. BUFFER
27986d7f5d3SJohn Marino points to the external data. STRUCTTYPE is the appropriate
28086d7f5d3SJohn Marino structure type. FIELD is a field within the struct. TYPE is the
28186d7f5d3SJohn Marino type of the field in the struct: Elf_Half, Elf_Word, or
28286d7f5d3SJohn Marino Elf_Addr. */
28386d7f5d3SJohn Marino
28486d7f5d3SJohn Marino #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
28586d7f5d3SJohn Marino (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
28686d7f5d3SJohn Marino
28786d7f5d3SJohn Marino /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
28886d7f5d3SJohn Marino SIZE is 32 or 64. STRUCTTYPE is the name of the struct from
28986d7f5d3SJohn Marino elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in
29086d7f5d3SJohn Marino the struct. TYPE is the type of the field in the struct: Elf_Half,
29186d7f5d3SJohn Marino Elf_Word, or Elf_Addr. */
29286d7f5d3SJohn Marino
29386d7f5d3SJohn Marino #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
29486d7f5d3SJohn Marino TYPE, VAL) \
29586d7f5d3SJohn Marino ELF_SET_STRUCT_FIELD (TYPEFUNCS, \
29686d7f5d3SJohn Marino Elf ## SIZE ## _External_ ## STRUCTTYPE, \
29786d7f5d3SJohn Marino FIELD, BUFFER, TYPE, VAL)
29886d7f5d3SJohn Marino
29986d7f5d3SJohn Marino /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */
30086d7f5d3SJohn Marino
30186d7f5d3SJohn Marino #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \
30286d7f5d3SJohn Marino TYPE, VAL) \
30386d7f5d3SJohn Marino ((CLASS) == ELFCLASS32 \
30486d7f5d3SJohn Marino ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \
30586d7f5d3SJohn Marino TYPE, VAL) \
30686d7f5d3SJohn Marino : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \
30786d7f5d3SJohn Marino TYPE, VAL))
30886d7f5d3SJohn Marino
30986d7f5d3SJohn Marino /* Private data for an simple_object_read. */
31086d7f5d3SJohn Marino
31186d7f5d3SJohn Marino struct simple_object_elf_read
31286d7f5d3SJohn Marino {
31386d7f5d3SJohn Marino /* Type functions. */
31486d7f5d3SJohn Marino const struct elf_type_functions* type_functions;
31586d7f5d3SJohn Marino /* Elf data. */
31686d7f5d3SJohn Marino unsigned char ei_data;
31786d7f5d3SJohn Marino /* Elf class. */
31886d7f5d3SJohn Marino unsigned char ei_class;
31986d7f5d3SJohn Marino /* ELF OS ABI. */
32086d7f5d3SJohn Marino unsigned char ei_osabi;
32186d7f5d3SJohn Marino /* Elf machine number. */
32286d7f5d3SJohn Marino unsigned short machine;
32386d7f5d3SJohn Marino /* Processor specific flags. */
32486d7f5d3SJohn Marino unsigned int flags;
32586d7f5d3SJohn Marino /* File offset of section headers. */
32686d7f5d3SJohn Marino ulong_type shoff;
32786d7f5d3SJohn Marino /* Number of sections. */
32886d7f5d3SJohn Marino unsigned int shnum;
32986d7f5d3SJohn Marino /* Index of string table section header. */
33086d7f5d3SJohn Marino unsigned int shstrndx;
33186d7f5d3SJohn Marino };
33286d7f5d3SJohn Marino
33386d7f5d3SJohn Marino /* Private data for an simple_object_attributes. */
33486d7f5d3SJohn Marino
33586d7f5d3SJohn Marino struct simple_object_elf_attributes
33686d7f5d3SJohn Marino {
33786d7f5d3SJohn Marino /* Type functions. */
33886d7f5d3SJohn Marino const struct elf_type_functions* type_functions;
33986d7f5d3SJohn Marino /* Elf data. */
34086d7f5d3SJohn Marino unsigned char ei_data;
34186d7f5d3SJohn Marino /* Elf class. */
34286d7f5d3SJohn Marino unsigned char ei_class;
34386d7f5d3SJohn Marino /* ELF OS ABI. */
34486d7f5d3SJohn Marino unsigned char ei_osabi;
34586d7f5d3SJohn Marino /* Elf machine number. */
34686d7f5d3SJohn Marino unsigned short machine;
34786d7f5d3SJohn Marino /* Processor specific flags. */
34886d7f5d3SJohn Marino unsigned int flags;
34986d7f5d3SJohn Marino };
35086d7f5d3SJohn Marino
35186d7f5d3SJohn Marino /* See if we have an ELF file. */
35286d7f5d3SJohn Marino
35386d7f5d3SJohn Marino 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)35486d7f5d3SJohn Marino simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
35586d7f5d3SJohn Marino int descriptor, off_t offset,
35686d7f5d3SJohn Marino const char *segment_name ATTRIBUTE_UNUSED,
35786d7f5d3SJohn Marino const char **errmsg, int *err)
35886d7f5d3SJohn Marino {
35986d7f5d3SJohn Marino unsigned char ei_data;
36086d7f5d3SJohn Marino unsigned char ei_class;
36186d7f5d3SJohn Marino const struct elf_type_functions *type_functions;
36286d7f5d3SJohn Marino unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
36386d7f5d3SJohn Marino struct simple_object_elf_read *eor;
36486d7f5d3SJohn Marino
36586d7f5d3SJohn Marino if (header[EI_MAG0] != ELFMAG0
36686d7f5d3SJohn Marino || header[EI_MAG1] != ELFMAG1
36786d7f5d3SJohn Marino || header[EI_MAG2] != ELFMAG2
36886d7f5d3SJohn Marino || header[EI_MAG3] != ELFMAG3
36986d7f5d3SJohn Marino || header[EI_VERSION] != EV_CURRENT)
37086d7f5d3SJohn Marino {
37186d7f5d3SJohn Marino *errmsg = NULL;
37286d7f5d3SJohn Marino *err = 0;
37386d7f5d3SJohn Marino return NULL;
37486d7f5d3SJohn Marino }
37586d7f5d3SJohn Marino
37686d7f5d3SJohn Marino ei_data = header[EI_DATA];
37786d7f5d3SJohn Marino if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
37886d7f5d3SJohn Marino {
37986d7f5d3SJohn Marino *errmsg = "unknown ELF endianness";
38086d7f5d3SJohn Marino *err = 0;
38186d7f5d3SJohn Marino return NULL;
38286d7f5d3SJohn Marino }
38386d7f5d3SJohn Marino
38486d7f5d3SJohn Marino ei_class = header[EI_CLASS];
38586d7f5d3SJohn Marino switch (ei_class)
38686d7f5d3SJohn Marino {
38786d7f5d3SJohn Marino case ELFCLASS32:
38886d7f5d3SJohn Marino type_functions = (ei_data == ELFDATA2LSB
38986d7f5d3SJohn Marino ? &elf_little_32_functions
39086d7f5d3SJohn Marino : &elf_big_32_functions);
39186d7f5d3SJohn Marino break;
39286d7f5d3SJohn Marino
39386d7f5d3SJohn Marino case ELFCLASS64:
39486d7f5d3SJohn Marino #ifndef UNSIGNED_64BIT_TYPE
39586d7f5d3SJohn Marino *errmsg = "64-bit ELF objects not supported";
39686d7f5d3SJohn Marino *err = 0;
39786d7f5d3SJohn Marino return NULL;
39886d7f5d3SJohn Marino #else
39986d7f5d3SJohn Marino type_functions = (ei_data == ELFDATA2LSB
40086d7f5d3SJohn Marino ? &elf_little_64_functions
40186d7f5d3SJohn Marino : &elf_big_64_functions);
40286d7f5d3SJohn Marino break;
40386d7f5d3SJohn Marino #endif
40486d7f5d3SJohn Marino
40586d7f5d3SJohn Marino default:
40686d7f5d3SJohn Marino *errmsg = "unrecognized ELF size";
40786d7f5d3SJohn Marino *err = 0;
40886d7f5d3SJohn Marino return NULL;
40986d7f5d3SJohn Marino }
41086d7f5d3SJohn Marino
41186d7f5d3SJohn Marino if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
41286d7f5d3SJohn Marino errmsg, err))
41386d7f5d3SJohn Marino return NULL;
41486d7f5d3SJohn Marino
41586d7f5d3SJohn Marino eor = XNEW (struct simple_object_elf_read);
41686d7f5d3SJohn Marino eor->type_functions = type_functions;
41786d7f5d3SJohn Marino eor->ei_data = ei_data;
41886d7f5d3SJohn Marino eor->ei_class = ei_class;
41986d7f5d3SJohn Marino eor->ei_osabi = header[EI_OSABI];
42086d7f5d3SJohn Marino eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42186d7f5d3SJohn Marino e_machine, Elf_Half);
42286d7f5d3SJohn Marino eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42386d7f5d3SJohn Marino e_flags, Elf_Word);
42486d7f5d3SJohn Marino eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42586d7f5d3SJohn Marino e_shoff, Elf_Addr);
42686d7f5d3SJohn Marino eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42786d7f5d3SJohn Marino e_shnum, Elf_Half);
42886d7f5d3SJohn Marino eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42986d7f5d3SJohn Marino e_shstrndx, Elf_Half);
43086d7f5d3SJohn Marino
43186d7f5d3SJohn Marino if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
43286d7f5d3SJohn Marino && eor->shoff != 0)
43386d7f5d3SJohn Marino {
43486d7f5d3SJohn Marino unsigned char shdr[sizeof (Elf64_External_Shdr)];
43586d7f5d3SJohn Marino
43686d7f5d3SJohn Marino /* Object file has more than 0xffff sections. */
43786d7f5d3SJohn Marino
43886d7f5d3SJohn Marino if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
43986d7f5d3SJohn Marino (ei_class == ELFCLASS32
44086d7f5d3SJohn Marino ? sizeof (Elf32_External_Shdr)
44186d7f5d3SJohn Marino : sizeof (Elf64_External_Shdr)),
44286d7f5d3SJohn Marino errmsg, err))
44386d7f5d3SJohn Marino {
44486d7f5d3SJohn Marino XDELETE (eor);
44586d7f5d3SJohn Marino return NULL;
44686d7f5d3SJohn Marino }
44786d7f5d3SJohn Marino
44886d7f5d3SJohn Marino if (eor->shnum == 0)
44986d7f5d3SJohn Marino eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
45086d7f5d3SJohn Marino shdr, sh_size, Elf_Addr);
45186d7f5d3SJohn Marino
45286d7f5d3SJohn Marino if (eor->shstrndx == SHN_XINDEX)
45386d7f5d3SJohn Marino {
45486d7f5d3SJohn Marino eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
45586d7f5d3SJohn Marino shdr, sh_link, Elf_Word);
45686d7f5d3SJohn Marino
45786d7f5d3SJohn Marino /* Versions of the GNU binutils between 2.12 and 2.18 did
45886d7f5d3SJohn Marino not handle objects with more than SHN_LORESERVE sections
45986d7f5d3SJohn Marino correctly. All large section indexes were offset by
46086d7f5d3SJohn Marino 0x100. There is more information at
46186d7f5d3SJohn Marino http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
46286d7f5d3SJohn Marino Fortunately these object files are easy to detect, as the
46386d7f5d3SJohn Marino GNU binutils always put the section header string table
46486d7f5d3SJohn Marino near the end of the list of sections. Thus if the
46586d7f5d3SJohn Marino section header string table index is larger than the
46686d7f5d3SJohn Marino number of sections, then we know we have to subtract
46786d7f5d3SJohn Marino 0x100 to get the real section index. */
46886d7f5d3SJohn Marino if (eor->shstrndx >= eor->shnum
46986d7f5d3SJohn Marino && eor->shstrndx >= SHN_LORESERVE + 0x100)
47086d7f5d3SJohn Marino eor->shstrndx -= 0x100;
47186d7f5d3SJohn Marino }
47286d7f5d3SJohn Marino }
47386d7f5d3SJohn Marino
47486d7f5d3SJohn Marino if (eor->shstrndx >= eor->shnum)
47586d7f5d3SJohn Marino {
47686d7f5d3SJohn Marino *errmsg = "invalid ELF shstrndx >= shnum";
47786d7f5d3SJohn Marino *err = 0;
47886d7f5d3SJohn Marino XDELETE (eor);
47986d7f5d3SJohn Marino return NULL;
48086d7f5d3SJohn Marino }
48186d7f5d3SJohn Marino
48286d7f5d3SJohn Marino return (void *) eor;
48386d7f5d3SJohn Marino }
48486d7f5d3SJohn Marino
48586d7f5d3SJohn Marino /* Find all sections in an ELF file. */
48686d7f5d3SJohn Marino
48786d7f5d3SJohn Marino 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)48886d7f5d3SJohn Marino simple_object_elf_find_sections (simple_object_read *sobj,
48986d7f5d3SJohn Marino int (*pfn) (void *, const char *,
49086d7f5d3SJohn Marino off_t offset, off_t length),
49186d7f5d3SJohn Marino void *data,
49286d7f5d3SJohn Marino int *err)
49386d7f5d3SJohn Marino {
49486d7f5d3SJohn Marino struct simple_object_elf_read *eor =
49586d7f5d3SJohn Marino (struct simple_object_elf_read *) sobj->data;
49686d7f5d3SJohn Marino const struct elf_type_functions *type_functions = eor->type_functions;
49786d7f5d3SJohn Marino unsigned char ei_class = eor->ei_class;
49886d7f5d3SJohn Marino size_t shdr_size;
49986d7f5d3SJohn Marino unsigned int shnum;
50086d7f5d3SJohn Marino unsigned char *shdrs;
50186d7f5d3SJohn Marino const char *errmsg;
50286d7f5d3SJohn Marino unsigned char *shstrhdr;
50386d7f5d3SJohn Marino size_t name_size;
50486d7f5d3SJohn Marino off_t shstroff;
50586d7f5d3SJohn Marino unsigned char *names;
50686d7f5d3SJohn Marino unsigned int i;
50786d7f5d3SJohn Marino
50886d7f5d3SJohn Marino shdr_size = (ei_class == ELFCLASS32
50986d7f5d3SJohn Marino ? sizeof (Elf32_External_Shdr)
51086d7f5d3SJohn Marino : sizeof (Elf64_External_Shdr));
51186d7f5d3SJohn Marino
51286d7f5d3SJohn Marino /* Read the section headers. We skip section 0, which is not a
51386d7f5d3SJohn Marino useful section. */
51486d7f5d3SJohn Marino
51586d7f5d3SJohn Marino shnum = eor->shnum;
51686d7f5d3SJohn Marino shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
51786d7f5d3SJohn Marino
51886d7f5d3SJohn Marino if (!simple_object_internal_read (sobj->descriptor,
51986d7f5d3SJohn Marino sobj->offset + eor->shoff + shdr_size,
52086d7f5d3SJohn Marino shdrs,
52186d7f5d3SJohn Marino shdr_size * (shnum - 1),
52286d7f5d3SJohn Marino &errmsg, err))
52386d7f5d3SJohn Marino {
52486d7f5d3SJohn Marino XDELETEVEC (shdrs);
52586d7f5d3SJohn Marino return errmsg;
52686d7f5d3SJohn Marino }
52786d7f5d3SJohn Marino
52886d7f5d3SJohn Marino /* Read the section names. */
52986d7f5d3SJohn Marino
53086d7f5d3SJohn Marino shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
53186d7f5d3SJohn Marino name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
53286d7f5d3SJohn Marino shstrhdr, sh_size, Elf_Addr);
53386d7f5d3SJohn Marino shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
53486d7f5d3SJohn Marino shstrhdr, sh_offset, Elf_Addr);
53586d7f5d3SJohn Marino names = XNEWVEC (unsigned char, name_size);
53686d7f5d3SJohn Marino if (!simple_object_internal_read (sobj->descriptor,
53786d7f5d3SJohn Marino sobj->offset + shstroff,
53886d7f5d3SJohn Marino names, name_size, &errmsg, err))
53986d7f5d3SJohn Marino {
54086d7f5d3SJohn Marino XDELETEVEC (names);
54186d7f5d3SJohn Marino XDELETEVEC (shdrs);
54286d7f5d3SJohn Marino return errmsg;
54386d7f5d3SJohn Marino }
54486d7f5d3SJohn Marino
54586d7f5d3SJohn Marino for (i = 1; i < shnum; ++i)
54686d7f5d3SJohn Marino {
54786d7f5d3SJohn Marino unsigned char *shdr;
54886d7f5d3SJohn Marino unsigned int sh_name;
54986d7f5d3SJohn Marino const char *name;
55086d7f5d3SJohn Marino off_t offset;
55186d7f5d3SJohn Marino off_t length;
55286d7f5d3SJohn Marino
55386d7f5d3SJohn Marino shdr = shdrs + (i - 1) * shdr_size;
55486d7f5d3SJohn Marino sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
55586d7f5d3SJohn Marino shdr, sh_name, Elf_Word);
55686d7f5d3SJohn Marino if (sh_name >= name_size)
55786d7f5d3SJohn Marino {
55886d7f5d3SJohn Marino *err = 0;
55986d7f5d3SJohn Marino XDELETEVEC (names);
56086d7f5d3SJohn Marino XDELETEVEC (shdrs);
56186d7f5d3SJohn Marino return "ELF section name out of range";
56286d7f5d3SJohn Marino }
56386d7f5d3SJohn Marino
56486d7f5d3SJohn Marino name = (const char *) names + sh_name;
56586d7f5d3SJohn Marino offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
56686d7f5d3SJohn Marino shdr, sh_offset, Elf_Addr);
56786d7f5d3SJohn Marino length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
56886d7f5d3SJohn Marino shdr, sh_size, Elf_Addr);
56986d7f5d3SJohn Marino
57086d7f5d3SJohn Marino if (!(*pfn) (data, name, offset, length))
57186d7f5d3SJohn Marino break;
57286d7f5d3SJohn Marino }
57386d7f5d3SJohn Marino
57486d7f5d3SJohn Marino XDELETEVEC (names);
57586d7f5d3SJohn Marino XDELETEVEC (shdrs);
57686d7f5d3SJohn Marino
57786d7f5d3SJohn Marino return NULL;
57886d7f5d3SJohn Marino }
57986d7f5d3SJohn Marino
58086d7f5d3SJohn Marino /* Fetch the attributes for an simple_object_read. */
58186d7f5d3SJohn Marino
58286d7f5d3SJohn Marino static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)58386d7f5d3SJohn Marino simple_object_elf_fetch_attributes (simple_object_read *sobj,
58486d7f5d3SJohn Marino const char **errmsg ATTRIBUTE_UNUSED,
58586d7f5d3SJohn Marino int *err ATTRIBUTE_UNUSED)
58686d7f5d3SJohn Marino {
58786d7f5d3SJohn Marino struct simple_object_elf_read *eor =
58886d7f5d3SJohn Marino (struct simple_object_elf_read *) sobj->data;
58986d7f5d3SJohn Marino struct simple_object_elf_attributes *ret;
59086d7f5d3SJohn Marino
59186d7f5d3SJohn Marino ret = XNEW (struct simple_object_elf_attributes);
59286d7f5d3SJohn Marino ret->type_functions = eor->type_functions;
59386d7f5d3SJohn Marino ret->ei_data = eor->ei_data;
59486d7f5d3SJohn Marino ret->ei_class = eor->ei_class;
59586d7f5d3SJohn Marino ret->ei_osabi = eor->ei_osabi;
59686d7f5d3SJohn Marino ret->machine = eor->machine;
59786d7f5d3SJohn Marino ret->flags = eor->flags;
59886d7f5d3SJohn Marino return ret;
59986d7f5d3SJohn Marino }
60086d7f5d3SJohn Marino
60186d7f5d3SJohn Marino /* Release the privata data for an simple_object_read. */
60286d7f5d3SJohn Marino
60386d7f5d3SJohn Marino static void
simple_object_elf_release_read(void * data)60486d7f5d3SJohn Marino simple_object_elf_release_read (void *data)
60586d7f5d3SJohn Marino {
60686d7f5d3SJohn Marino XDELETE (data);
60786d7f5d3SJohn Marino }
60886d7f5d3SJohn Marino
60986d7f5d3SJohn Marino /* Compare two attributes structures. */
61086d7f5d3SJohn Marino
61186d7f5d3SJohn Marino static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)61286d7f5d3SJohn Marino simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
61386d7f5d3SJohn Marino {
61486d7f5d3SJohn Marino struct simple_object_elf_attributes *to =
61586d7f5d3SJohn Marino (struct simple_object_elf_attributes *) todata;
61686d7f5d3SJohn Marino struct simple_object_elf_attributes *from =
61786d7f5d3SJohn Marino (struct simple_object_elf_attributes *) fromdata;
61886d7f5d3SJohn Marino
61986d7f5d3SJohn Marino if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
62086d7f5d3SJohn Marino {
62186d7f5d3SJohn Marino *err = 0;
62286d7f5d3SJohn Marino return "ELF object format mismatch";
62386d7f5d3SJohn Marino }
62486d7f5d3SJohn Marino
62586d7f5d3SJohn Marino if (to->machine != from->machine)
62686d7f5d3SJohn Marino {
62786d7f5d3SJohn Marino int ok;
62886d7f5d3SJohn Marino
62986d7f5d3SJohn Marino /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
63086d7f5d3SJohn Marino output of EM_SPARC32PLUS. */
63186d7f5d3SJohn Marino ok = 0;
63286d7f5d3SJohn Marino switch (to->machine)
63386d7f5d3SJohn Marino {
63486d7f5d3SJohn Marino case EM_SPARC:
63586d7f5d3SJohn Marino if (from->machine == EM_SPARC32PLUS)
63686d7f5d3SJohn Marino {
63786d7f5d3SJohn Marino to->machine = from->machine;
63886d7f5d3SJohn Marino ok = 1;
63986d7f5d3SJohn Marino }
64086d7f5d3SJohn Marino break;
64186d7f5d3SJohn Marino
64286d7f5d3SJohn Marino case EM_SPARC32PLUS:
64386d7f5d3SJohn Marino if (from->machine == EM_SPARC)
64486d7f5d3SJohn Marino ok = 1;
64586d7f5d3SJohn Marino break;
64686d7f5d3SJohn Marino
64786d7f5d3SJohn Marino default:
64886d7f5d3SJohn Marino break;
64986d7f5d3SJohn Marino }
65086d7f5d3SJohn Marino
65186d7f5d3SJohn Marino if (!ok)
65286d7f5d3SJohn Marino {
65386d7f5d3SJohn Marino *err = 0;
65486d7f5d3SJohn Marino return "ELF machine number mismatch";
65586d7f5d3SJohn Marino }
65686d7f5d3SJohn Marino }
65786d7f5d3SJohn Marino
65886d7f5d3SJohn Marino return NULL;
65986d7f5d3SJohn Marino }
66086d7f5d3SJohn Marino
66186d7f5d3SJohn Marino /* Release the private data for an attributes structure. */
66286d7f5d3SJohn Marino
66386d7f5d3SJohn Marino static void
simple_object_elf_release_attributes(void * data)66486d7f5d3SJohn Marino simple_object_elf_release_attributes (void *data)
66586d7f5d3SJohn Marino {
66686d7f5d3SJohn Marino XDELETE (data);
66786d7f5d3SJohn Marino }
66886d7f5d3SJohn Marino
66986d7f5d3SJohn Marino /* Prepare to write out a file. */
67086d7f5d3SJohn Marino
67186d7f5d3SJohn Marino static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)67286d7f5d3SJohn Marino simple_object_elf_start_write (void *attributes_data,
67386d7f5d3SJohn Marino const char **errmsg ATTRIBUTE_UNUSED,
67486d7f5d3SJohn Marino int *err ATTRIBUTE_UNUSED)
67586d7f5d3SJohn Marino {
67686d7f5d3SJohn Marino struct simple_object_elf_attributes *attrs =
67786d7f5d3SJohn Marino (struct simple_object_elf_attributes *) attributes_data;
67886d7f5d3SJohn Marino struct simple_object_elf_attributes *ret;
67986d7f5d3SJohn Marino
68086d7f5d3SJohn Marino /* We're just going to record the attributes, but we need to make a
68186d7f5d3SJohn Marino copy because the user may delete them. */
68286d7f5d3SJohn Marino ret = XNEW (struct simple_object_elf_attributes);
68386d7f5d3SJohn Marino *ret = *attrs;
68486d7f5d3SJohn Marino return ret;
68586d7f5d3SJohn Marino }
68686d7f5d3SJohn Marino
68786d7f5d3SJohn Marino /* Write out an ELF ehdr. */
68886d7f5d3SJohn Marino
68986d7f5d3SJohn Marino static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)69086d7f5d3SJohn Marino simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
69186d7f5d3SJohn Marino const char **errmsg, int *err)
69286d7f5d3SJohn Marino {
69386d7f5d3SJohn Marino struct simple_object_elf_attributes *attrs =
69486d7f5d3SJohn Marino (struct simple_object_elf_attributes *) sobj->data;
69586d7f5d3SJohn Marino const struct elf_type_functions* fns;
69686d7f5d3SJohn Marino unsigned char cl;
69786d7f5d3SJohn Marino size_t ehdr_size;
69886d7f5d3SJohn Marino unsigned char buf[sizeof (Elf64_External_Ehdr)];
69986d7f5d3SJohn Marino simple_object_write_section *section;
70086d7f5d3SJohn Marino unsigned int shnum;
70186d7f5d3SJohn Marino
70286d7f5d3SJohn Marino fns = attrs->type_functions;
70386d7f5d3SJohn Marino cl = attrs->ei_class;
70486d7f5d3SJohn Marino
70586d7f5d3SJohn Marino shnum = 0;
70686d7f5d3SJohn Marino for (section = sobj->sections; section != NULL; section = section->next)
70786d7f5d3SJohn Marino ++shnum;
70886d7f5d3SJohn Marino if (shnum > 0)
70986d7f5d3SJohn Marino {
71086d7f5d3SJohn Marino /* Add a section header for the dummy section and one for
71186d7f5d3SJohn Marino .shstrtab. */
71286d7f5d3SJohn Marino shnum += 2;
71386d7f5d3SJohn Marino }
71486d7f5d3SJohn Marino
71586d7f5d3SJohn Marino ehdr_size = (cl == ELFCLASS32
71686d7f5d3SJohn Marino ? sizeof (Elf32_External_Ehdr)
71786d7f5d3SJohn Marino : sizeof (Elf64_External_Ehdr));
71886d7f5d3SJohn Marino memset (buf, 0, sizeof (Elf64_External_Ehdr));
71986d7f5d3SJohn Marino
72086d7f5d3SJohn Marino buf[EI_MAG0] = ELFMAG0;
72186d7f5d3SJohn Marino buf[EI_MAG1] = ELFMAG1;
72286d7f5d3SJohn Marino buf[EI_MAG2] = ELFMAG2;
72386d7f5d3SJohn Marino buf[EI_MAG3] = ELFMAG3;
72486d7f5d3SJohn Marino buf[EI_CLASS] = cl;
72586d7f5d3SJohn Marino buf[EI_DATA] = attrs->ei_data;
72686d7f5d3SJohn Marino buf[EI_VERSION] = EV_CURRENT;
72786d7f5d3SJohn Marino buf[EI_OSABI] = attrs->ei_osabi;
72886d7f5d3SJohn Marino
72986d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
73086d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
73186d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
73286d7f5d3SJohn Marino /* e_entry left as zero. */
73386d7f5d3SJohn Marino /* e_phoff left as zero. */
73486d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
73586d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
73686d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
73786d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
73886d7f5d3SJohn Marino (cl == ELFCLASS32
73986d7f5d3SJohn Marino ? sizeof (Elf32_External_Phdr)
74086d7f5d3SJohn Marino : sizeof (Elf64_External_Phdr)));
74186d7f5d3SJohn Marino /* e_phnum left as zero. */
74286d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
74386d7f5d3SJohn Marino (cl == ELFCLASS32
74486d7f5d3SJohn Marino ? sizeof (Elf32_External_Shdr)
74586d7f5d3SJohn Marino : sizeof (Elf64_External_Shdr)));
74686d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
74786d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
74886d7f5d3SJohn Marino shnum == 0 ? 0 : shnum - 1);
74986d7f5d3SJohn Marino
75086d7f5d3SJohn Marino return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
75186d7f5d3SJohn Marino errmsg, err);
75286d7f5d3SJohn Marino }
75386d7f5d3SJohn Marino
75486d7f5d3SJohn Marino /* Write out an ELF shdr. */
75586d7f5d3SJohn Marino
75686d7f5d3SJohn Marino 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,unsigned int sh_offset,unsigned int sh_size,unsigned int sh_addralign,const char ** errmsg,int * err)75786d7f5d3SJohn Marino simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
75886d7f5d3SJohn Marino off_t offset, unsigned int sh_name,
75986d7f5d3SJohn Marino unsigned int sh_type, unsigned int sh_flags,
76086d7f5d3SJohn Marino unsigned int sh_offset, unsigned int sh_size,
76186d7f5d3SJohn Marino unsigned int sh_addralign, const char **errmsg,
76286d7f5d3SJohn Marino int *err)
76386d7f5d3SJohn Marino {
76486d7f5d3SJohn Marino struct simple_object_elf_attributes *attrs =
76586d7f5d3SJohn Marino (struct simple_object_elf_attributes *) sobj->data;
76686d7f5d3SJohn Marino const struct elf_type_functions* fns;
76786d7f5d3SJohn Marino unsigned char cl;
76886d7f5d3SJohn Marino size_t shdr_size;
76986d7f5d3SJohn Marino unsigned char buf[sizeof (Elf64_External_Shdr)];
77086d7f5d3SJohn Marino
77186d7f5d3SJohn Marino fns = attrs->type_functions;
77286d7f5d3SJohn Marino cl = attrs->ei_class;
77386d7f5d3SJohn Marino
77486d7f5d3SJohn Marino shdr_size = (cl == ELFCLASS32
77586d7f5d3SJohn Marino ? sizeof (Elf32_External_Shdr)
77686d7f5d3SJohn Marino : sizeof (Elf64_External_Shdr));
77786d7f5d3SJohn Marino memset (buf, 0, sizeof (Elf64_External_Shdr));
77886d7f5d3SJohn Marino
77986d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
78086d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
78186d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
78286d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
78386d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
78486d7f5d3SJohn Marino /* sh_link left as zero. */
78586d7f5d3SJohn Marino /* sh_info left as zero. */
78686d7f5d3SJohn Marino ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
78786d7f5d3SJohn Marino /* sh_entsize left as zero. */
78886d7f5d3SJohn Marino
78986d7f5d3SJohn Marino return simple_object_internal_write (descriptor, offset, buf, shdr_size,
79086d7f5d3SJohn Marino errmsg, err);
79186d7f5d3SJohn Marino }
79286d7f5d3SJohn Marino
79386d7f5d3SJohn Marino /* Write out a complete ELF file.
79486d7f5d3SJohn Marino Ehdr
79586d7f5d3SJohn Marino initial dummy Shdr
79686d7f5d3SJohn Marino user-created Shdrs
79786d7f5d3SJohn Marino .shstrtab Shdr
79886d7f5d3SJohn Marino user-created section data
79986d7f5d3SJohn Marino .shstrtab data */
80086d7f5d3SJohn Marino
80186d7f5d3SJohn Marino static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)80286d7f5d3SJohn Marino simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
80386d7f5d3SJohn Marino int *err)
80486d7f5d3SJohn Marino {
80586d7f5d3SJohn Marino struct simple_object_elf_attributes *attrs =
80686d7f5d3SJohn Marino (struct simple_object_elf_attributes *) sobj->data;
80786d7f5d3SJohn Marino unsigned char cl;
80886d7f5d3SJohn Marino size_t ehdr_size;
80986d7f5d3SJohn Marino size_t shdr_size;
81086d7f5d3SJohn Marino const char *errmsg;
81186d7f5d3SJohn Marino simple_object_write_section *section;
81286d7f5d3SJohn Marino unsigned int shnum;
81386d7f5d3SJohn Marino size_t shdr_offset;
81486d7f5d3SJohn Marino size_t sh_offset;
81586d7f5d3SJohn Marino size_t sh_name;
81686d7f5d3SJohn Marino unsigned char zero;
81786d7f5d3SJohn Marino
81886d7f5d3SJohn Marino if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
81986d7f5d3SJohn Marino return errmsg;
82086d7f5d3SJohn Marino
82186d7f5d3SJohn Marino cl = attrs->ei_class;
82286d7f5d3SJohn Marino if (cl == ELFCLASS32)
82386d7f5d3SJohn Marino {
82486d7f5d3SJohn Marino ehdr_size = sizeof (Elf32_External_Ehdr);
82586d7f5d3SJohn Marino shdr_size = sizeof (Elf32_External_Shdr);
82686d7f5d3SJohn Marino }
82786d7f5d3SJohn Marino else
82886d7f5d3SJohn Marino {
82986d7f5d3SJohn Marino ehdr_size = sizeof (Elf64_External_Ehdr);
83086d7f5d3SJohn Marino shdr_size = sizeof (Elf64_External_Shdr);
83186d7f5d3SJohn Marino }
83286d7f5d3SJohn Marino
83386d7f5d3SJohn Marino shnum = 0;
83486d7f5d3SJohn Marino for (section = sobj->sections; section != NULL; section = section->next)
83586d7f5d3SJohn Marino ++shnum;
83686d7f5d3SJohn Marino if (shnum == 0)
83786d7f5d3SJohn Marino return NULL;
83886d7f5d3SJohn Marino
83986d7f5d3SJohn Marino /* Add initial dummy Shdr and .shstrtab. */
84086d7f5d3SJohn Marino shnum += 2;
84186d7f5d3SJohn Marino
84286d7f5d3SJohn Marino shdr_offset = ehdr_size;
84386d7f5d3SJohn Marino sh_offset = shdr_offset + shnum * shdr_size;
84486d7f5d3SJohn Marino
84586d7f5d3SJohn Marino if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
84686d7f5d3SJohn Marino 0, 0, 0, 0, 0, 0, &errmsg, err))
84786d7f5d3SJohn Marino return errmsg;
84886d7f5d3SJohn Marino
84986d7f5d3SJohn Marino shdr_offset += shdr_size;
85086d7f5d3SJohn Marino
85186d7f5d3SJohn Marino sh_name = 1;
85286d7f5d3SJohn Marino for (section = sobj->sections; section != NULL; section = section->next)
85386d7f5d3SJohn Marino {
85486d7f5d3SJohn Marino size_t mask;
85586d7f5d3SJohn Marino size_t new_sh_offset;
85686d7f5d3SJohn Marino size_t sh_size;
85786d7f5d3SJohn Marino struct simple_object_write_section_buffer *buffer;
85886d7f5d3SJohn Marino
85986d7f5d3SJohn Marino mask = (1U << section->align) - 1;
86086d7f5d3SJohn Marino new_sh_offset = sh_offset + mask;
86186d7f5d3SJohn Marino new_sh_offset &= ~ mask;
86286d7f5d3SJohn Marino while (new_sh_offset > sh_offset)
86386d7f5d3SJohn Marino {
86486d7f5d3SJohn Marino unsigned char zeroes[16];
86586d7f5d3SJohn Marino size_t write;
86686d7f5d3SJohn Marino
86786d7f5d3SJohn Marino memset (zeroes, 0, sizeof zeroes);
86886d7f5d3SJohn Marino write = new_sh_offset - sh_offset;
86986d7f5d3SJohn Marino if (write > sizeof zeroes)
87086d7f5d3SJohn Marino write = sizeof zeroes;
87186d7f5d3SJohn Marino if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
87286d7f5d3SJohn Marino write, &errmsg, err))
87386d7f5d3SJohn Marino return errmsg;
87486d7f5d3SJohn Marino sh_offset += write;
87586d7f5d3SJohn Marino }
87686d7f5d3SJohn Marino
87786d7f5d3SJohn Marino sh_size = 0;
87886d7f5d3SJohn Marino for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
87986d7f5d3SJohn Marino {
88086d7f5d3SJohn Marino if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
88186d7f5d3SJohn Marino ((const unsigned char *)
88286d7f5d3SJohn Marino buffer->buffer),
88386d7f5d3SJohn Marino buffer->size, &errmsg, err))
88486d7f5d3SJohn Marino return errmsg;
88586d7f5d3SJohn Marino sh_size += buffer->size;
88686d7f5d3SJohn Marino }
88786d7f5d3SJohn Marino
88886d7f5d3SJohn Marino if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
88986d7f5d3SJohn Marino sh_name, SHT_PROGBITS, 0, sh_offset,
89086d7f5d3SJohn Marino sh_size, 1U << section->align,
89186d7f5d3SJohn Marino &errmsg, err))
89286d7f5d3SJohn Marino return errmsg;
89386d7f5d3SJohn Marino
89486d7f5d3SJohn Marino shdr_offset += shdr_size;
89586d7f5d3SJohn Marino sh_name += strlen (section->name) + 1;
89686d7f5d3SJohn Marino sh_offset += sh_size;
89786d7f5d3SJohn Marino }
89886d7f5d3SJohn Marino
89986d7f5d3SJohn Marino if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
90086d7f5d3SJohn Marino sh_name, SHT_STRTAB, 0, sh_offset,
90186d7f5d3SJohn Marino sh_name + strlen (".shstrtab") + 1,
90286d7f5d3SJohn Marino 1, &errmsg, err))
90386d7f5d3SJohn Marino return errmsg;
90486d7f5d3SJohn Marino
90586d7f5d3SJohn Marino /* .shstrtab has a leading zero byte. */
90686d7f5d3SJohn Marino zero = 0;
90786d7f5d3SJohn Marino if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
90886d7f5d3SJohn Marino &errmsg, err))
90986d7f5d3SJohn Marino return errmsg;
91086d7f5d3SJohn Marino ++sh_offset;
91186d7f5d3SJohn Marino
91286d7f5d3SJohn Marino for (section = sobj->sections; section != NULL; section = section->next)
91386d7f5d3SJohn Marino {
91486d7f5d3SJohn Marino size_t len;
91586d7f5d3SJohn Marino
91686d7f5d3SJohn Marino len = strlen (section->name) + 1;
91786d7f5d3SJohn Marino if (!simple_object_internal_write (descriptor, sh_offset,
91886d7f5d3SJohn Marino (const unsigned char *) section->name,
91986d7f5d3SJohn Marino len, &errmsg, err))
92086d7f5d3SJohn Marino return errmsg;
92186d7f5d3SJohn Marino sh_offset += len;
92286d7f5d3SJohn Marino }
92386d7f5d3SJohn Marino
92486d7f5d3SJohn Marino if (!simple_object_internal_write (descriptor, sh_offset,
92586d7f5d3SJohn Marino (const unsigned char *) ".shstrtab",
92686d7f5d3SJohn Marino strlen (".shstrtab") + 1, &errmsg, err))
92786d7f5d3SJohn Marino return errmsg;
92886d7f5d3SJohn Marino
92986d7f5d3SJohn Marino return NULL;
93086d7f5d3SJohn Marino }
93186d7f5d3SJohn Marino
93286d7f5d3SJohn Marino /* Release the private data for an simple_object_write structure. */
93386d7f5d3SJohn Marino
93486d7f5d3SJohn Marino static void
simple_object_elf_release_write(void * data)93586d7f5d3SJohn Marino simple_object_elf_release_write (void *data)
93686d7f5d3SJohn Marino {
93786d7f5d3SJohn Marino XDELETE (data);
93886d7f5d3SJohn Marino }
93986d7f5d3SJohn Marino
94086d7f5d3SJohn Marino /* The ELF functions. */
94186d7f5d3SJohn Marino
94286d7f5d3SJohn Marino const struct simple_object_functions simple_object_elf_functions =
94386d7f5d3SJohn Marino {
94486d7f5d3SJohn Marino simple_object_elf_match,
94586d7f5d3SJohn Marino simple_object_elf_find_sections,
94686d7f5d3SJohn Marino simple_object_elf_fetch_attributes,
94786d7f5d3SJohn Marino simple_object_elf_release_read,
94886d7f5d3SJohn Marino simple_object_elf_attributes_merge,
94986d7f5d3SJohn Marino simple_object_elf_release_attributes,
95086d7f5d3SJohn Marino simple_object_elf_start_write,
95186d7f5d3SJohn Marino simple_object_elf_write_to_file,
95286d7f5d3SJohn Marino simple_object_elf_release_write
95386d7f5d3SJohn Marino };
954