/* simple-object-elf.c -- routines to manipulate ELF object files.
- Copyright (C) 2010-2017 Free Software Foundation, Inc.
+ Copyright (C) 2010-2024 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
This program is free software; you can redistribute it and/or modify it
#include "simple-object.h"
#include <errno.h>
+/* mingw.org's MinGW doesn't have ENOTSUP. */
+#ifndef ENOTSUP
+# define ENOTSUP ENOSYS
+#endif
#include <stddef.h>
#ifdef HAVE_STDLIB_H
/* Special section index values. */
+#define SHN_UNDEF 0 /* Undefined section */
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
+
/* 32-bit ELF program header. */
/* Values for sh_type field. */
+#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_GROUP 17 /* Section contains a section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+
+/* Values for sh_flags field. */
+
+#define SHF_INFO_LINK 0x00000040 /* `sh_info' contains SHT index */
+#define SHF_EXECINSTR 0x00000004 /* Executable section. */
+#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude this
+ section from executable and
+ shared library that it builds
+ when those objects are not to be
+ further relocated. */
+/* Symbol table entry. */
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_value[4]; /* Symbol value */
+ unsigned char st_size[4]; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+} Elf32_External_Sym;
+
+typedef struct
+{
+ unsigned char st_name[4]; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ unsigned char st_shndx[2]; /* Section index */
+ unsigned char st_value[8]; /* Symbol value */
+ unsigned char st_size[8]; /* Symbol size */
+} Elf64_External_Sym;
+
+#define ELF_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_TLS 6 /* Thread local data object */
+#define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak global */
+
+#define STV_DEFAULT 0 /* Visibility is specified by binding type */
+#define STV_HIDDEN 2 /* Can only be seen inside currect component */
/* Functions to fetch and store different ELF types, depending on the
endianness and size. */
unsigned int flags;
};
+/* Private data for an simple_object_write. */
+
+struct simple_object_elf_write
+{
+ struct simple_object_elf_attributes attrs;
+ unsigned char *shdrs;
+};
+
/* See if we have an ELF file. */
static void *
not handle objects with more than SHN_LORESERVE sections
correctly. All large section indexes were offset by
0x100. There is more information at
- http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
+ https://sourceware.org/PR5900 .
Fortunately these object files are easy to detect, as the
GNU binutils always put the section header string table
near the end of the list of sections. Thus if the
XDELETE (eor);
return NULL;
}
-
+
+ if (eor->shstrndx == 0)
+ {
+ *errmsg = "invalid ELF shstrndx == 0";
+ *err = 0;
+ XDELETE (eor);
+ return NULL;
+ }
+
return (void *) eor;
}
{
struct simple_object_elf_attributes *attrs =
(struct simple_object_elf_attributes *) attributes_data;
- struct simple_object_elf_attributes *ret;
+ struct simple_object_elf_write *ret;
/* We're just going to record the attributes, but we need to make a
copy because the user may delete them. */
- ret = XNEW (struct simple_object_elf_attributes);
- *ret = *attrs;
+ ret = XNEW (struct simple_object_elf_write);
+ ret->attrs = *attrs;
+ ret->shdrs = NULL;
return ret;
}
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_addralign,
+ unsigned int sh_link, unsigned int sh_info,
+ size_t sh_addralign,
+ size_t sh_entsize,
const char **errmsg, int *err)
{
struct simple_object_elf_attributes *attrs =
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
- /* sh_info left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
- /* sh_entsize left as zero. */
+ ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Addr, sh_entsize);
return simple_object_internal_write (descriptor, offset, buf, shdr_size,
errmsg, err);
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
int *err)
{
- struct simple_object_elf_attributes *attrs =
- (struct simple_object_elf_attributes *) sobj->data;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) sobj->data;
+ struct simple_object_elf_attributes *attrs = &eow->attrs;
unsigned char cl;
size_t ehdr_size;
size_t shdr_size;
unsigned int first_sh_link;
size_t sh_name;
unsigned char zero;
+ unsigned secnum;
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
return errmsg;
else
first_sh_link = shnum - 1;
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- 0, 0, 0, 0, first_sh_size, first_sh_link,
- 0, &errmsg, err))
+ 0, 0, 0, 0, 0, first_sh_size, first_sh_link,
+ 0, 0, 0, &errmsg, err))
return errmsg;
shdr_offset += shdr_size;
sh_name = 1;
+ secnum = 0;
for (section = sobj->sections; section != NULL; section = section->next)
{
size_t mask;
size_t new_sh_offset;
size_t sh_size;
struct simple_object_write_section_buffer *buffer;
+ unsigned int sh_type = SHT_PROGBITS;
+ unsigned int sh_flags = 0;
+ off_t sh_addr = 0;
+ unsigned int sh_link = 0;
+ unsigned int sh_info = 0;
+ size_t sh_addralign = 1U << section->align;
+ size_t sh_entsize = 0;
+ if (eow->shdrs)
+ {
+ sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_type, Elf_Word);
+ sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_flags, Elf_Addr);
+ sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addr, Elf_Addr);
+ sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_link, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_info, Elf_Word);
+ sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_addralign, Elf_Addr);
+ sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ eow->shdrs + secnum * shdr_size,
+ sh_entsize, Elf_Addr);
+ secnum++;
+ }
- mask = (1U << section->align) - 1;
+ mask = sh_addralign - 1;
new_sh_offset = sh_offset + mask;
new_sh_offset &= ~ mask;
while (new_sh_offset > sh_offset)
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_PROGBITS, 0, sh_offset,
- sh_size, 0, 1U << section->align,
+ sh_name, sh_type, sh_flags,
+ sh_addr, sh_offset,
+ sh_size, sh_link, sh_info,
+ sh_addralign, sh_entsize,
&errmsg, err))
return errmsg;
}
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
- sh_name, SHT_STRTAB, 0, sh_offset,
- sh_name + strlen (".shstrtab") + 1, 0,
- 1, &errmsg, err))
+ sh_name, SHT_STRTAB, 0, 0, sh_offset,
+ sh_name + strlen (".shstrtab") + 1, 0, 0,
+ 1, 0, &errmsg, err))
return errmsg;
/* .shstrtab has a leading zero byte. */
static void
simple_object_elf_release_write (void *data)
{
+ struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+ if (eow->shdrs)
+ XDELETE (eow->shdrs);
XDELETE (data);
}
+/* Copy all sections in an ELF file. */
+
+static const char *
+simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ simple_object_write *dobj,
+ char *(*pfn) (const char *),
+ int *err)
+{
+ struct simple_object_elf_read *eor =
+ (struct simple_object_elf_read *) sobj->data;
+ const struct elf_type_functions *type_functions = eor->type_functions;
+ struct simple_object_elf_write *eow =
+ (struct simple_object_elf_write *) dobj->data;
+ unsigned char ei_class = eor->ei_class;
+ size_t shdr_size;
+ unsigned int shnum;
+ unsigned char *shdrs;
+ const char *errmsg;
+ unsigned char *shstrhdr;
+ size_t name_size;
+ off_t shstroff;
+ unsigned char *names;
+ unsigned int i;
+ int changed;
+ int *pfnret;
+ const char **pfnname;
+ unsigned new_i;
+ unsigned *sh_map;
+ unsigned first_shndx = 0;
+ unsigned int *symtab_indices_shndx;
+
+ shdr_size = (ei_class == ELFCLASS32
+ ? sizeof (Elf32_External_Shdr)
+ : sizeof (Elf64_External_Shdr));
+
+ /* Read the section headers. We skip section 0, which is not a
+ useful section. */
+
+ shnum = eor->shnum;
+ shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + eor->shoff + shdr_size,
+ shdrs,
+ shdr_size * (shnum - 1),
+ &errmsg, err))
+ {
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ /* Read the section names. */
+
+ shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+ name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_size, Elf_Addr);
+ shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shstrhdr, sh_offset, Elf_Addr);
+ names = XNEWVEC (unsigned char, name_size);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + shstroff,
+ names, name_size, &errmsg, err))
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+
+ pfnret = XNEWVEC (int, shnum);
+ pfnname = XNEWVEC (const char *, shnum);
+
+ /* Map of symtab to index section. */
+ symtab_indices_shndx = XCNEWVEC (unsigned int, shnum - 1);
+
+ /* First perform the callbacks to know which sections to preserve and
+ what name to use for those. */
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name, sh_type;
+ const char *name;
+ char *ret;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return "ELF section name out of range";
+ }
+
+ name = (const char *) names + sh_name;
+
+ ret = (*pfn) (name);
+ pfnret[i - 1] = ret == NULL ? -1 : 0;
+ pfnname[i - 1] = ret == NULL ? name : ret;
+ if (first_shndx == 0
+ && pfnret[i - 1] == 0)
+ first_shndx = i;
+
+ /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections. */
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+ if (sh_type == SHT_SYMTAB_SHNDX)
+ {
+ unsigned int sh_link;
+ sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ symtab_indices_shndx[sh_link - 1] = i - 1;
+ /* Always discard the extended index sections, after
+ copying it will not be needed. This way we don't need to
+ update it and deal with the ordering constraints of
+ processing the existing symtab and changing the index. */
+ pfnret[i - 1] = -1;
+ }
+ }
+
+ /* Mark sections as preserved that are required by to be preserved
+ sections. */
+ do
+ {
+ changed = 0;
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_type, sh_info, sh_link;
+ off_t offset;
+ off_t length;
+
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+ sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_info, Elf_Word);
+ sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ if (sh_type == SHT_GROUP)
+ {
+ /* Mark groups containing copied sections. */
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class,
+ Shdr, shdr, sh_entsize,
+ Elf_Addr);
+ unsigned char *ent, *buf;
+ int keep = 0;
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ return errmsg;
+ }
+ for (ent = buf + entsize; ent < buf + length; ent += entsize)
+ {
+ unsigned sec = type_functions->fetch_Elf_Word (ent);
+ if (pfnret[sec - 1] == 0)
+ keep = 1;
+ }
+ if (keep)
+ {
+ changed |= (pfnret[sh_link - 1] == -1
+ || pfnret[i - 1] == -1);
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_RELA
+ || sh_type == SHT_REL)
+ {
+ /* Mark relocation sections and symtab of copied sections. */
+ if (pfnret[sh_info - 1] == 0)
+ {
+ changed |= (pfnret[sh_link - 1] == -1
+ || pfnret[i - 1] == -1);
+ pfnret[sh_link - 1] = 0;
+ pfnret[i - 1] = 0;
+ }
+ }
+ if (sh_type == SHT_SYMTAB)
+ {
+ /* Mark strings sections of copied symtabs. */
+ if (pfnret[i - 1] == 0)
+ {
+ changed |= pfnret[sh_link - 1] == -1;
+ pfnret[sh_link - 1] = 0;
+ }
+ }
+ }
+ }
+ while (changed);
+
+ /* Compute a mapping of old -> new section numbers. */
+ sh_map = XNEWVEC (unsigned, shnum);
+ sh_map[0] = 0;
+ new_i = 1;
+ for (i = 1; i < shnum; ++i)
+ {
+ if (pfnret[i - 1] == -1)
+ sh_map[i] = 0;
+ else
+ sh_map[i] = new_i++;
+ }
+ if (new_i - 1 >= SHN_LORESERVE)
+ {
+ *err = ENOTSUP;
+ return "Too many copied sections";
+ }
+ eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
+
+ /* Then perform the actual copying. */
+ new_i = 0;
+ for (i = 1; i < shnum; ++i)
+ {
+ unsigned char *shdr;
+ unsigned int sh_name, sh_type;
+ const char *name;
+ off_t offset;
+ off_t length;
+ simple_object_write_section *dest;
+ off_t flags;
+ unsigned char *buf;
+
+ if (pfnret[i - 1])
+ continue;
+
+ new_i++;
+ shdr = shdrs + (i - 1) * shdr_size;
+ sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_name, Elf_Word);
+ if (sh_name >= name_size)
+ {
+ *err = 0;
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (symtab_indices_shndx);
+ return "ELF section name out of range";
+ }
+
+ name = pfnname[i - 1];
+ offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_offset, Elf_Addr);
+ length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_size, Elf_Addr);
+ sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_type, Elf_Word);
+
+ dest = simple_object_write_create_section (dobj, pfnname[i - 1],
+ 0, &errmsg, err);
+ if (dest == NULL)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (symtab_indices_shndx);
+ return errmsg;
+ }
+
+ /* Record the SHDR of the source. */
+ memcpy (eow->shdrs + (new_i - 1) * shdr_size, shdr, shdr_size);
+ shdr = eow->shdrs + (new_i - 1) * shdr_size;
+
+ /* Copy the data.
+ ??? This is quite wasteful and ideally would be delayed until
+ write_to_file (). Thus it questions the interfacing
+ which eventually should contain destination creation plus
+ writing. */
+ buf = XNEWVEC (unsigned char, length);
+ if (!simple_object_internal_read (sobj->descriptor,
+ sobj->offset + offset, buf,
+ (size_t) length, &errmsg, err))
+ {
+ XDELETEVEC (buf);
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (symtab_indices_shndx);
+ return errmsg;
+ }
+
+ /* If we are processing .symtab purge any symbols
+ in discarded sections. */
+ if (sh_type == SHT_SYMTAB)
+ {
+ unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_entsize, Elf_Addr);
+ size_t prevailing_name_idx = 0;
+ unsigned char *ent;
+ unsigned *shndx_table = NULL;
+ /* Read the section index table if present. */
+ if (symtab_indices_shndx[i - 1] != 0)
+ {
+ unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * shdr_size;
+ off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ sidxhdr, sh_offset, Elf_Addr);
+ size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ sidxhdr, sh_size, Elf_Addr);
+ unsigned int shndx_type
+ = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ sidxhdr, sh_type, Elf_Word);
+ if (shndx_type != SHT_SYMTAB_SHNDX)
+ return "Wrong section type of a SYMTAB SECTION INDICES section";
+ shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
+ simple_object_internal_read (sobj->descriptor,
+ sobj->offset + sidxoff,
+ (unsigned char *)shndx_table,
+ sidxsz, &errmsg, err);
+ }
+
+ /* Find a WEAK HIDDEN symbol which name we will use for removed
+ symbols. We know there's a prevailing weak hidden symbol
+ at the start of the .debug_info section. */
+ for (ent = buf; ent < buf + length; ent += entsize)
+ {
+ unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ Sym, ent,
+ st_shndx, Elf_Half);
+ unsigned char *st_info;
+ unsigned char *st_other;
+ if (ei_class == ELFCLASS32)
+ {
+ st_info = &((Elf32_External_Sym *)ent)->st_info;
+ st_other = &((Elf32_External_Sym *)ent)->st_other;
+ }
+ else
+ {
+ st_info = &((Elf64_External_Sym *)ent)->st_info;
+ st_other = &((Elf64_External_Sym *)ent)->st_other;
+ }
+ if (st_shndx == SHN_XINDEX)
+ st_shndx = type_functions->fetch_Elf_Word
+ ((unsigned char *)(shndx_table + (ent - buf) / entsize));
+
+ if (st_shndx != SHN_COMMON
+ && !(st_shndx != SHN_UNDEF
+ && st_shndx < shnum
+ && pfnret[st_shndx - 1] == -1)
+ && ELF_ST_BIND (*st_info) == STB_WEAK
+ && *st_other == STV_HIDDEN)
+ {
+ prevailing_name_idx = ELF_FETCH_FIELD (type_functions,
+ ei_class, Sym, ent,
+ st_name, Elf_Word);
+ break;
+ }
+ }
+
+ for (ent = buf; ent < buf + length; ent += entsize)
+ {
+ unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ Sym, ent,
+ st_shndx, Elf_Half);
+ unsigned raw_st_shndx = st_shndx;
+ unsigned char *st_info;
+ unsigned char *st_other;
+ int discard = 0;
+ if (ei_class == ELFCLASS32)
+ {
+ st_info = &((Elf32_External_Sym *)ent)->st_info;
+ st_other = &((Elf32_External_Sym *)ent)->st_other;
+ }
+ else
+ {
+ st_info = &((Elf64_External_Sym *)ent)->st_info;
+ st_other = &((Elf64_External_Sym *)ent)->st_other;
+ }
+ if (st_shndx == SHN_XINDEX)
+ st_shndx = type_functions->fetch_Elf_Word
+ ((unsigned char *)(shndx_table + (ent - buf) / entsize));
+ /* Eliminate all COMMONs - this includes __gnu_lto_slim
+ which otherwise cause endless LTO plugin invocation.
+ FIXME: remove the condition once we remove emission
+ of __gnu_lto_slim symbol. */
+ if (st_shndx == SHN_COMMON)
+ discard = 1;
+ /* We also need to remove symbols refering to sections
+ we'll eventually remove as with fat LTO objects
+ we otherwise get duplicate symbols at final link
+ (with GNU ld, gold is fine and ignores symbols in
+ sections marked as EXCLUDE). ld/20513 */
+ else if (st_shndx != SHN_UNDEF
+ && st_shndx < shnum
+ && pfnret[st_shndx - 1] == -1)
+ discard = 1;
+ /* We also need to remove global UNDEFs which can
+ cause link fails later. */
+ else if (st_shndx == SHN_UNDEF
+ && ELF_ST_BIND (*st_info) == STB_GLOBAL)
+ discard = 1;
+
+ if (discard)
+ {
+ /* Make discarded symbols undefined and unnamed
+ in case it is local. */
+ int bind = ELF_ST_BIND (*st_info);
+ int other = STV_DEFAULT;
+ if (bind == STB_LOCAL)
+ {
+ /* Make discarded local symbols unnamed and
+ defined in the first prevailing section. */
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_name, Elf_Word, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_shndx, Elf_Half,
+ sh_map[first_shndx]);
+ }
+ else
+ {
+ /* Make discarded global symbols hidden weak
+ undefined and sharing a name of a prevailing
+ symbol. */
+ bind = STB_WEAK;
+ other = STV_HIDDEN;
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_name, Elf_Word,
+ prevailing_name_idx);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_shndx, Elf_Half, SHN_UNDEF);
+ }
+ *st_other = other;
+ *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_value, Elf_Addr, 0);
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_size, Elf_Word, 0);
+ }
+ else if (raw_st_shndx < SHN_LORESERVE
+ || raw_st_shndx == SHN_XINDEX)
+ /* Remap the section reference. */
+ ELF_SET_FIELD (type_functions, ei_class, Sym,
+ ent, st_shndx, Elf_Half, sh_map[st_shndx]);
+ }
+ XDELETEVEC (shndx_table);
+ }
+ else if (sh_type == SHT_GROUP)
+ {
+ /* Remap section indices in groups and remove removed members. */
+ unsigned char *ent, *dst;
+ for (dst = ent = buf + 4; ent < buf + length; ent += 4)
+ {
+ unsigned shndx = type_functions->fetch_Elf_Word (ent);
+ if (pfnret[shndx - 1] == -1)
+ ;
+ else
+ {
+ type_functions->set_Elf_Word (dst, sh_map[shndx]);
+ dst += 4;
+ }
+ }
+ /* Adjust the length. */
+ length = dst - buf;
+ }
+
+ errmsg = simple_object_write_add_data (dobj, dest,
+ buf, length, 1, err);
+ XDELETEVEC (buf);
+ if (errmsg)
+ {
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (symtab_indices_shndx);
+ return errmsg;
+ }
+
+ flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr);
+ /* Remap the section references. */
+ {
+ unsigned int sh_info, sh_link;
+ if (flags & SHF_INFO_LINK || sh_type == SHT_REL || sh_type == SHT_RELA)
+ {
+ sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_info, Elf_Word);
+ sh_info = sh_map[sh_info];
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_info, Elf_Word, sh_info);
+ }
+ sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word);
+ sh_link = sh_map[sh_link];
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_link, Elf_Word, sh_link);
+ }
+ /* The debugobj doesn't contain any code, thus no trampolines.
+ Even when the original object needs trampolines, debugobj
+ doesn't. */
+ if (strcmp (name, ".note.GNU-stack") == 0)
+ flags &= ~SHF_EXECINSTR;
+ /* Clear SHF_EXCLUDE on to be preserved sections. */
+ flags &= ~SHF_EXCLUDE;
+ ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ shdr, sh_flags, Elf_Addr, flags);
+ }
+
+ XDELETEVEC (names);
+ XDELETEVEC (shdrs);
+ XDELETEVEC (pfnret);
+ XDELETEVEC (pfnname);
+ XDELETEVEC (symtab_indices_shndx);
+ XDELETEVEC (sh_map);
+
+ return NULL;
+}
+
+
/* The ELF functions. */
const struct simple_object_functions simple_object_elf_functions =
simple_object_elf_release_attributes,
simple_object_elf_start_write,
simple_object_elf_write_to_file,
- simple_object_elf_release_write
+ simple_object_elf_release_write,
+ simple_object_elf_copy_lto_debug_sections
};