X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=libiberty%2Fsimple-object-elf.c;h=b249146fc6003912d8cf702eb3765ba9199dc85d;hb=d5f4488f09b811b0ca44e687da2acbc286d84d4a;hp=5b8cfba1cd64a40f2fb02c6ad3ac577a0567706c;hpb=ffa54e5c48223b42840f93e56a5eff69998ab4e1;p=deliverable%2Fbinutils-gdb.git diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c index 5b8cfba1cd..b249146fc6 100644 --- a/libiberty/simple-object-elf.c +++ b/libiberty/simple-object-elf.c @@ -1,5 +1,5 @@ /* simple-object-elf.c -- routines to manipulate ELF object files. - Copyright 2010 Free Software Foundation, Inc. + Copyright (C) 2010-2018 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. This program is free software; you can redistribute it and/or modify it @@ -115,11 +115,19 @@ typedef struct { #define ET_REL 1 /* Relocatable file */ +/* Values for e_machine field of Ehdr. */ + +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + /* 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 */ + /* 32-bit ELF program header. */ typedef struct { @@ -178,8 +186,60 @@ typedef struct { /* 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 */ + +/* Values for sh_flags field. */ + +#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. */ @@ -343,6 +403,14 @@ struct simple_object_elf_attributes 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 * @@ -604,20 +672,52 @@ simple_object_elf_release_read (void *data) /* Compare two attributes structures. */ static const char * -simple_object_elf_attributes_compare (void *data1, void *data2, int *err) +simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err) { - struct simple_object_elf_attributes *attrs1 = - (struct simple_object_elf_attributes *) data1; - struct simple_object_elf_attributes *attrs2 = - (struct simple_object_elf_attributes *) data2; - - if (attrs1->ei_data != attrs2->ei_data - || attrs1->ei_class != attrs2->ei_class - || attrs1->machine != attrs2->machine) + struct simple_object_elf_attributes *to = + (struct simple_object_elf_attributes *) todata; + struct simple_object_elf_attributes *from = + (struct simple_object_elf_attributes *) fromdata; + + if (to->ei_data != from->ei_data || to->ei_class != from->ei_class) { *err = 0; return "ELF object format mismatch"; } + + if (to->machine != from->machine) + { + int ok; + + /* EM_SPARC and EM_SPARC32PLUS are compatible and force an + output of EM_SPARC32PLUS. */ + ok = 0; + switch (to->machine) + { + case EM_SPARC: + if (from->machine == EM_SPARC32PLUS) + { + to->machine = from->machine; + ok = 1; + } + break; + + case EM_SPARC32PLUS: + if (from->machine == EM_SPARC) + ok = 1; + break; + + default: + break; + } + + if (!ok) + { + *err = 0; + return "ELF machine number mismatch"; + } + } + return NULL; } @@ -638,12 +738,13 @@ simple_object_elf_start_write (void *attributes_data, { 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; } @@ -661,6 +762,7 @@ simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, unsigned char buf[sizeof (Elf64_External_Ehdr)]; simple_object_write_section *section; unsigned int shnum; + unsigned int shstrndx; fns = attrs->type_functions; cl = attrs->ei_class; @@ -706,9 +808,17 @@ simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, (cl == ELFCLASS32 ? sizeof (Elf32_External_Shdr) : sizeof (Elf64_External_Shdr))); - ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum); - ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, - shnum == 0 ? 0 : shnum - 1); + ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, + shnum >= SHN_LORESERVE ? 0 : shnum); + if (shnum == 0) + shstrndx = 0; + else + { + shstrndx = shnum - 1; + if (shstrndx >= SHN_LORESERVE) + shstrndx = SHN_XINDEX; + } + ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, shstrndx); return simple_object_internal_write (descriptor, 0, buf, ehdr_size, errmsg, err); @@ -720,9 +830,12 @@ 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_addralign, const char **errmsg, - int *err) + 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 = (struct simple_object_elf_attributes *) sobj->data; @@ -742,12 +855,13 @@ simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, 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); - /* sh_link left as zero. */ - /* sh_info left as zero. */ + ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link); + 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); @@ -765,8 +879,9 @@ static const char * 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; @@ -775,8 +890,11 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, unsigned int shnum; size_t shdr_offset; size_t sh_offset; + unsigned int first_sh_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; @@ -805,21 +923,63 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, shdr_offset = ehdr_size; sh_offset = shdr_offset + shnum * shdr_size; + if (shnum < SHN_LORESERVE) + first_sh_size = 0; + else + first_sh_size = shnum; + if (shnum - 1 < SHN_LORESERVE) + first_sh_link = 0; + else + first_sh_link = shnum - 1; if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, - 0, 0, 0, 0, 0, 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) @@ -849,8 +1009,10 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, } if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, - sh_name, SHT_PROGBITS, 0, sh_offset, - sh_size, 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; @@ -860,9 +1022,9 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, } if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, - sh_name, SHT_STRTAB, 0, sh_offset, - sh_name + strlen (".shstrtab") + 1, - 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. */ @@ -897,9 +1059,408 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, 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, + int (*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 first_shndx = 0; + + 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; + } + + eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1)); + pfnret = XNEWVEC (int, shnum); + pfnname = XNEWVEC (const char *, shnum); + + /* 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; + const char *name; + int 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 == 1 ? 0 : -1; + pfnname[i - 1] = name; + if (first_shndx == 0 + && pfnret[i - 1] == 0) + first_shndx = i; + } + + /* 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); + + /* Then perform the actual copying. */ + for (i = 1; i < shnum; ++i) + { + unsigned char *shdr; + unsigned int sh_name, sh_type; + const char *name; + off_t offset; + off_t length; + int ret; + simple_object_write_section *dest; + off_t flags; + unsigned char *buf; + + 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; + 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); + + ret = pfnret[i - 1]; + name = ret == 0 ? pfnname[i - 1] : ""; + + dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err); + if (dest == NULL) + { + XDELETEVEC (names); + XDELETEVEC (shdrs); + return errmsg; + } + + /* Record the SHDR of the source. */ + memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size); + shdr = eow->shdrs + (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. */ + /* Keep empty sections for sections we should discard. This avoids + the need to rewrite section indices in symtab and relocation + sections. */ + if (ret == 0) + { + 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; + } + + /* If we are processing .symtab purge __gnu_lto_v1 and + __gnu_lto_slim symbols from it. */ + if (sh_type == SHT_SYMTAB) + { + unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + shdr, sh_entsize, Elf_Addr); + unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + shdr, sh_link, Elf_Word); + unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size; + off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + strshdr, sh_offset, Elf_Addr); + size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + strshdr, sh_size, Elf_Addr); + char *strings = XNEWVEC (char, strsz); + unsigned char *ent; + simple_object_internal_read (sobj->descriptor, + sobj->offset + stroff, + (unsigned char *)strings, + strsz, &errmsg, err); + /* Find gnu_lto_ in strings. */ + char *gnu_lto = strings; + while ((gnu_lto = memchr (gnu_lto, 'g', + strings + strsz - gnu_lto))) + if (strncmp (gnu_lto, "gnu_lto_v1", + strings + strsz - gnu_lto) == 0) + break; + else + gnu_lto++; + 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; + 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; + } + /* Eliminate all COMMONs - this includes __gnu_lto_v1 + and __gnu_lto_slim which otherwise cause endless + LTO plugin invocation. */ + 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; + + 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, first_shndx); + } + else + { + /* Make discarded global symbols hidden weak + undefined and sharing the gnu_lto_ name. */ + bind = STB_WEAK; + other = STV_HIDDEN; + if (gnu_lto) + ELF_SET_FIELD (type_functions, ei_class, Sym, + ent, st_name, Elf_Word, + gnu_lto - strings); + 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); + } + } + XDELETEVEC (strings); + } + + errmsg = simple_object_write_add_data (dobj, dest, + buf, length, 1, err); + XDELETEVEC (buf); + if (errmsg) + { + XDELETEVEC (names); + XDELETEVEC (shdrs); + return errmsg; + } + } + else + { + /* For deleted sections mark the section header table entry as + unused. That allows the link editor to remove it in a partial + link. */ + ELF_SET_FIELD (type_functions, ei_class, Shdr, + shdr, sh_type, Elf_Word, SHT_NULL); + ELF_SET_FIELD (type_functions, ei_class, Shdr, + shdr, sh_info, Elf_Word, 0); + ELF_SET_FIELD (type_functions, ei_class, Shdr, + shdr, sh_link, Elf_Word, 0); + } + + flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + shdr, sh_flags, Elf_Addr); + if (ret == 0) + { + /* 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; + flags &= ~SHF_EXCLUDE; + } + else if (ret == -1) + 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); + + return NULL; +} + + /* The ELF functions. */ const struct simple_object_functions simple_object_elf_functions = @@ -908,9 +1469,10 @@ const struct simple_object_functions simple_object_elf_functions = simple_object_elf_find_sections, simple_object_elf_fetch_attributes, simple_object_elf_release_read, - simple_object_elf_attributes_compare, + simple_object_elf_attributes_merge, 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 };