From f8ad2513754f5a53fecb407cf64fcb586836b60c Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 1 Sep 2017 10:52:53 +0100 Subject: [PATCH] Import latest fixes to libiberty from GCC. PR lto/81968 * simple-object-elf.c (simple_object_elf_copy_lto_debug_section): Keep names of removed global symbols. * simple-object-xcoff.c (simple_object_xcoff_find_sections): Improve .go_export csect handling. Don't make assumptions on containing section or number of auxiliary entries. PR lto/81968 * simple-object-elf.c (simple_object_elf_copy_lto_debug_section): Adjust field with for sh_type write, set SHF_EXCLUDE only for removed sections. PR lto/81925 * simple-object-elf.c (simple_object_elf_write_shdr): Adjust type of sh_addralign and sh_entsize and properly write sh_entsize as Elf_Addr. (simple_object_elf_write_to_file): Read sh_entsize as Elf_Addr. * simple-object-common.h (struct simple_object_functions): Add copy_lto_debug_sections hook. * simple-object.c: Include fcntl.h. (handle_lto_debug_sections): New helper function. (simple_object_copy_lto_debug_sections): New function copying early LTO debug sections to regular debug sections in a new file. (simple_object_start_write): Handle NULL segment_name. * simple-object-coff.c (simple_object_coff_functions): Adjust for not implemented copy_lto_debug_sections hook. * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise. * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise. * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL, SHT_GROUP): Add various sectopn header types. (SHF_EXCLUDE): Add flag. (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct. (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors. (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types. (STV_DEFAULT): Add symbol visibility. (SHN_COMMON): Add special section index name. (struct simple_object_elf_write): New. (simple_object_elf_start_write): Adjust for new private data. (simple_object_elf_write_shdr): Pass in values for all fields we write. (simple_object_elf_write_to_file): Adjust. Copy from recorded section headers if requested. (simple_object_elf_release_write): Release private data. (simple_object_elf_copy_lto_debug_sections): Copy and rename sections as denoted by PFN and all their dependences, symbols and relocations to the empty destination file. (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook. * simple-object-xcoff.c (simple_object_xcoff_find_sections): Search symbol table for .go_export symbol and apply pfn if found. --- libiberty/ChangeLog | 77 ++++- libiberty/simple-object-coff.c | 3 +- libiberty/simple-object-common.h | 6 + libiberty/simple-object-elf.c | 489 +++++++++++++++++++++++++++++-- libiberty/simple-object-mach-o.c | 3 +- libiberty/simple-object-xcoff.c | 177 ++++++++++- libiberty/simple-object.c | 83 +++++- 7 files changed, 802 insertions(+), 36 deletions(-) diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 925b1521d6..191a3116bb 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,18 +1,80 @@ +2017-08-31 Richard Biener + + PR lto/81968 + * simple-object-elf.c (simple_object_elf_copy_lto_debug_section): + Keep names of removed global symbols. + +2017-08-29 Tony Reix + + * simple-object-xcoff.c (simple_object_xcoff_find_sections): + Improve .go_export csect handling. Don't make assumptions + on containing section or number of auxiliary entries. + +2017-08-28 Richard Biener + + PR lto/81968 + * simple-object-elf.c (simple_object_elf_copy_lto_debug_section): + Adjust field with for sh_type write, set SHF_EXCLUDE only for + removed sections. + +2017-08-22 Richard Biener + + PR lto/81925 + * simple-object-elf.c (simple_object_elf_write_shdr): Adjust + type of sh_addralign and sh_entsize and properly write + sh_entsize as Elf_Addr. + (simple_object_elf_write_to_file): Read sh_entsize as Elf_Addr. + +2017-08-21 Richard Biener + + * simple-object-common.h (struct simple_object_functions): Add + copy_lto_debug_sections hook. + * simple-object.c: Include fcntl.h. + (handle_lto_debug_sections): New helper function. + (simple_object_copy_lto_debug_sections): New function copying + early LTO debug sections to regular debug sections in a new file. + (simple_object_start_write): Handle NULL segment_name. + * simple-object-coff.c (simple_object_coff_functions): Adjust + for not implemented copy_lto_debug_sections hook. + * simple-object-mach-o.c (simple_object_mach_o_functions): Likewise. + * simple-object-xcoff.c (simple_object_xcoff_functions): Likewise. + * simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL, + SHT_GROUP): Add various sectopn header types. + (SHF_EXCLUDE): Add flag. + (Elf32_External_Sym, Elf64_External_Sym): Add symbol struct. + (ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors. + (STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types. + (STV_DEFAULT): Add symbol visibility. + (SHN_COMMON): Add special section index name. + (struct simple_object_elf_write): New. + (simple_object_elf_start_write): Adjust for new private data. + (simple_object_elf_write_shdr): Pass in values for all fields + we write. + (simple_object_elf_write_to_file): Adjust. Copy from recorded + section headers if requested. + (simple_object_elf_release_write): Release private data. + (simple_object_elf_copy_lto_debug_sections): Copy and rename sections + as denoted by PFN and all their dependences, symbols and relocations + to the empty destination file. + (simple_object_elf_functions): Adjust for copy_lto_debug_sections hook. + 2017-07-02 Jan Kratochvil * dwarfnames.c (DW_FIRST_IDX, DW_END_IDX, DW_IDX, DW_IDX_DUP): New. +2017-06-07 Tony Reix + Matthieu Sarter + David Edelsohn + + * simple-object-xcoff.c (simple_object_xcoff_find_sections): + Search symbol table for .go_export symbol and apply pfn if found. + 2017-05-31 DJ Delorie * configure.ac (strnlen): Add to AC_CHECK_DECLS. * configure: Likewise. * config.in: Add HACE_DECL_STRNLEN. -2017-05-31 Eli Zaretskii - - * waitpid.c (wait) [__MINGW32__]: Define as a macro - that calls _cwait, so that this function works on MinGW. - 2017-05-27 Iain Buclaw * d-demangle.c (dlang_identifier): Prefix mangled init symbols @@ -32,6 +94,11 @@ the demangled hexadecimal directly to string. * testsuite/d-demangle-expected: Add tests. +2017-05-24 Eli Zaretskii + + * waitpid.c (wait) [__MINGW32__]: Define as a macro + that calls _cwait, so that this function works on MinGW. + 2017-05-02 Iain Buclaw * d-demangle.c (dlang_hexdigit): New function. diff --git a/libiberty/simple-object-coff.c b/libiberty/simple-object-coff.c index 0283b15c80..54d430dad9 100644 --- a/libiberty/simple-object-coff.c +++ b/libiberty/simple-object-coff.c @@ -800,5 +800,6 @@ const struct simple_object_functions simple_object_coff_functions = simple_object_coff_release_attributes, simple_object_coff_start_write, simple_object_coff_write_to_file, - simple_object_coff_release_write + simple_object_coff_release_write, + NULL }; diff --git a/libiberty/simple-object-common.h b/libiberty/simple-object-common.h index cda4038c9d..733bdd0e7b 100644 --- a/libiberty/simple-object-common.h +++ b/libiberty/simple-object-common.h @@ -141,6 +141,12 @@ struct simple_object_functions /* Release the private data for an simple_object_write. */ void (*release_write) (void *); + + /* Copy LTO debug sections. */ + const char *(*copy_lto_debug_sections) (simple_object_read *sobj, + simple_object_write *dobj, + int (*pfn) (const char **), + int *err); }; /* The known object file formats. */ diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c index a733e4b1a2..9799e72546 100644 --- a/libiberty/simple-object-elf.c +++ b/libiberty/simple-object-elf.c @@ -122,9 +122,12 @@ typedef struct { /* 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 { @@ -183,8 +186,57 @@ 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_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 STV_DEFAULT 0 /* Visibility is specified by binding type */ /* Functions to fetch and store different ELF types, depending on the endianness and size. */ @@ -348,6 +400,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 * @@ -527,6 +587,11 @@ simple_object_elf_find_sections (simple_object_read *sobj, /* Read the section names. */ + if (eor->shstrndx == 0) + { + XDELETEVEC (shdrs); + return "ELF section header string table missing"; + } shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size; name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, shstrhdr, sh_size, Elf_Addr); @@ -675,12 +740,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; } @@ -766,8 +832,11 @@ static int simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, off_t offset, unsigned int sh_name, unsigned int sh_type, unsigned int sh_flags, + off_t sh_addr, unsigned int sh_offset, unsigned int sh_size, - unsigned int sh_link, unsigned int sh_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 = @@ -788,12 +857,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); 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); @@ -811,8 +881,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; @@ -825,6 +896,7 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, 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; @@ -862,21 +934,54 @@ simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, 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) @@ -906,8 +1011,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, 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; @@ -917,9 +1024,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, 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. */ @@ -954,9 +1061,356 @@ 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 *pfnret; + const char **pfnname; + + 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; + } + + /* Mark sections as preserved that are required by to be preserved + sections. */ + 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) + { + 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) + { + 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) + pfnret[sh_link - 1] = 0; + } + } + + /* 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; + const char *errmsg; + 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); + 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) + /* Setting st_name to "" seems to work to purge + COMMON symbols (in addition to setting their + size to zero). */ + 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. */ + if (ELF_ST_BIND (*st_info) == STB_LOCAL) + ELF_SET_FIELD (type_functions, ei_class, Sym, + ent, st_name, Elf_Word, 0); + 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); + ELF_SET_FIELD (type_functions, ei_class, Sym, + ent, st_shndx, Elf_Half, SHN_UNDEF); + *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info), + STT_NOTYPE); + *st_other = STV_DEFAULT; + } + } + 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); + } + + flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, + shdr, sh_flags, Elf_Addr); + if (ret == 0) + 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 = @@ -969,5 +1423,6 @@ 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 }; diff --git a/libiberty/simple-object-mach-o.c b/libiberty/simple-object-mach-o.c index bbadf5d833..b90fca88b2 100644 --- a/libiberty/simple-object-mach-o.c +++ b/libiberty/simple-object-mach-o.c @@ -1374,5 +1374,6 @@ const struct simple_object_functions simple_object_mach_o_functions = simple_object_mach_o_release_attributes, simple_object_mach_o_start_write, simple_object_mach_o_write_to_file, - simple_object_mach_o_release_write + simple_object_mach_o_release_write, + NULL }; diff --git a/libiberty/simple-object-xcoff.c b/libiberty/simple-object-xcoff.c index 8a15939878..9a8f581563 100644 --- a/libiberty/simple-object-xcoff.c +++ b/libiberty/simple-object-xcoff.c @@ -138,15 +138,15 @@ struct external_syment union { struct { union { - /* The name of the symbol. There is an implicit null character - after the end of the array. */ - char n_name[N_SYMNMLEN]; - struct { - /* If n_zeroes is zero, n_offset is the offset the name from - the start of the string table. */ - unsigned char n_zeroes[4]; - unsigned char n_offset[4]; - } n; +/* The name of the symbol. There is an implicit null character + after the end of the array. */ + char n_name[N_SYMNMLEN]; + struct { + /* If n_zeroes is zero, n_offset is the offset the name from + the start of the string table. */ + unsigned char n_zeroes[4]; + unsigned char n_offset[4]; + } n; } n; /* The symbol's value. */ @@ -255,8 +255,14 @@ union external_auxent #define IMAGE_SYM_TYPE \ ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL) +#define C_EXT (2) #define C_STAT (3) #define C_FILE (103) +#define C_HIDEXT (107) + +#define XTY_SD (1) /* section definition */ + +#define XMC_XO (7) /* extended operation */ /* Private data for an simple_object_read. */ @@ -398,11 +404,13 @@ simple_object_xcoff_find_sections (simple_object_read *sobj, size_t scnhdr_size; unsigned char *scnbuf; const char *errmsg; + unsigned short (*fetch_16) (const unsigned char *); unsigned int (*fetch_32) (const unsigned char *); ulong_type (*fetch_64) (const unsigned char *); unsigned int nscns; char *strtab; size_t strtab_size; + struct external_syment *symtab = NULL; unsigned int i; scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32; @@ -416,6 +424,7 @@ simple_object_xcoff_find_sections (simple_object_read *sobj, return errmsg; } + fetch_16 = simple_object_fetch_big_16; fetch_32 = simple_object_fetch_big_32; fetch_64 = simple_object_fetch_big_64; @@ -429,7 +438,7 @@ simple_object_xcoff_find_sections (simple_object_read *sobj, char namebuf[SCNNMLEN + 1]; char *name; off_t scnptr; - unsigned int size; + off_t size; scnhdr = scnbuf + i * scnhdr_size; scnname = scnhdr + offsetof (struct external_scnhdr, s_name); @@ -489,6 +498,151 @@ simple_object_xcoff_find_sections (simple_object_read *sobj, break; } + /* Special handling for .go_export csect. */ + if (ocr->nsyms > 0) + { + unsigned char *sym; + const char *n_name; + off_t size, n_value; + unsigned int n_numaux, n_offset, n_zeroes; + short n_scnum; + + /* Read symbol table. */ + symtab = XNEWVEC (struct external_syment, ocr->nsyms * SYMESZ); + if (!simple_object_internal_read (sobj->descriptor, + sobj->offset + ocr->symptr, + (unsigned char *) symtab, + ocr->nsyms * SYMESZ, + &errmsg, err)) + { + XDELETEVEC (symtab); + XDELETEVEC (scnbuf); + return NULL; + } + + /* Search in symbol table if we have a ".go_export" symbol. */ + for (i = 0; i < ocr->nsyms; i += n_numaux + 1) + { + sym = (unsigned char *) &symtab[i]; + n_numaux = symtab[i].n_numaux[0]; + + if (symtab[i].n_sclass[0] != C_EXT + && symtab[i].n_sclass[0] != C_HIDEXT) + continue; + + /* Must have at least one csect auxiliary entry. */ + if (n_numaux < 1 || i + n_numaux >= ocr->nsyms) + continue; + + n_scnum = fetch_16 (sym + offsetof (struct external_syment, + n_scnum)); + if (n_scnum < 1 || (unsigned int) n_scnum > nscns) + continue; + + if (u64) + { + n_value = fetch_64 (sym + offsetof (struct external_syment, + u.xcoff64.n_value)); + n_offset = fetch_32 (sym + offsetof (struct external_syment, + u.xcoff64.n_offset)); + } + else + { + /* ".go_export" is longer than N_SYMNMLEN. */ + n_zeroes = fetch_32 (sym + offsetof (struct external_syment, + u.xcoff32.n.n.n_zeroes)); + if (n_zeroes != 0) + continue; + + n_value = fetch_32 (sym + offsetof (struct external_syment, + u.xcoff32.n_value)); + n_offset = fetch_32 (sym + offsetof (struct external_syment, + u.xcoff32.n.n.n_offset)); + } + + /* The real symbol name is found in the string table. */ + if (strtab == NULL) + { + strtab = simple_object_xcoff_read_strtab (sobj, + &strtab_size, + &errmsg, err); + if (strtab == NULL) + { + XDELETEVEC (symtab); + XDELETEVEC (scnbuf); + return errmsg; + } + } + + if (n_offset >= strtab_size) + { + XDELETEVEC (strtab); + XDELETEVEC (symtab); + XDELETEVEC (scnbuf); + *err = 0; + return "symbol string index out of range"; + } + n_name = strtab + n_offset; + + if (!strcmp (n_name, ".go_export")) + { + union external_auxent *auxent; + unsigned char *aux, *scnhdr; + off_t scnptr, x_scnlen; + + /* Found .go_export symbol, read its csect auxiliary entry. + By convention, it is the last auxiliary entry. */ + auxent = (union external_auxent *) &symtab[i + n_numaux]; + aux = (unsigned char *) auxent; + if (u64) + { + if ((auxent->u.xcoff64.x_csect.x_smtyp & 0x7) != XTY_SD + || auxent->u.xcoff64.x_csect.x_smclas != XMC_XO) + continue; + + x_scnlen = fetch_32 (aux + offsetof (union external_auxent, + u.xcoff64.x_csect.x_scnlen_hi)); + x_scnlen = x_scnlen << 32 + | fetch_32 (aux + offsetof (union external_auxent, + u.xcoff64.x_csect.x_scnlen_lo)); + } + else + { + if ((auxent->u.xcoff32.x_csect.x_smtyp & 0x7) != XTY_SD + || auxent->u.xcoff32.x_csect.x_smclas != XMC_XO) + continue; + + x_scnlen = fetch_32 (aux + offsetof (union external_auxent, + u.xcoff32.x_csect.x_scnlen)); + } + + /* Get header of containing section. */ + scnhdr = scnbuf + (n_scnum - 1) * scnhdr_size; + if (u64) + { + scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr, + u.xcoff64.s_scnptr)); + size = fetch_64 (scnhdr + offsetof (struct external_scnhdr, + u.xcoff64.s_size)); + } + else + { + scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, + u.xcoff32.s_scnptr)); + size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, + u.xcoff32.s_size)); + } + if (n_value + x_scnlen > size) + break; + + (*pfn) (data, ".go_export", scnptr + n_value, x_scnlen); + break; + } + } + } + + if (symtab != NULL) + XDELETEVEC (symtab); if (strtab != NULL) XDELETEVEC (strtab); XDELETEVEC (scnbuf); @@ -894,5 +1048,6 @@ const struct simple_object_functions simple_object_xcoff_functions = simple_object_xcoff_release_attributes, simple_object_xcoff_start_write, simple_object_xcoff_write_to_file, - simple_object_xcoff_release_write + simple_object_xcoff_release_write, + NULL }; diff --git a/libiberty/simple-object.c b/libiberty/simple-object.c index 8ea9cf129f..553e90f504 100644 --- a/libiberty/simple-object.c +++ b/libiberty/simple-object.c @@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA. */ #include "simple-object.h" #include +#include #ifdef HAVE_STDLIB_H #include @@ -249,6 +250,86 @@ simple_object_find_section (simple_object_read *sobj, const char *name, return 1; } +/* Callback to identify and rename LTO debug sections by name. + Returns 1 if NAME is a LTO debug section, 0 if not. */ + +static int +handle_lto_debug_sections (const char **name) +{ + /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler + complains about bogus section flags. Which means we need to arrange + for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make + fat lto object tooling work for the fat part). */ + /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed + sections. */ + /* Copy LTO debug sections and rename them to their non-LTO name. */ + if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0) + { + *name = *name + sizeof (".gnu.debuglto_") - 1; + return 1; + } + else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0) + { + *name = *name + sizeof (".gnu.lto_") - 1; + return 1; + } + return 0; +} + +/* Copy LTO debug sections. */ + +const char * +simple_object_copy_lto_debug_sections (simple_object_read *sobj, + const char *dest, int *err) +{ + const char *errmsg; + simple_object_write *dest_sobj; + simple_object_attributes *attrs; + int outfd; + + if (! sobj->functions->copy_lto_debug_sections) + { + *err = EINVAL; + return "simple_object_copy_lto_debug_sections not implemented"; + } + + attrs = simple_object_fetch_attributes (sobj, &errmsg, err); + if (! attrs) + return errmsg; + dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err); + simple_object_release_attributes (attrs); + if (! dest_sobj) + return errmsg; + + errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj, + handle_lto_debug_sections, + err); + if (errmsg) + { + simple_object_release_write (dest_sobj); + return errmsg; + } + + outfd = creat (dest, 00777); + if (outfd == -1) + { + *err = errno; + simple_object_release_write (dest_sobj); + return "open failed"; + } + + errmsg = simple_object_write_to_file (dest_sobj, outfd, err); + close (outfd); + if (errmsg) + { + simple_object_release_write (dest_sobj); + return errmsg; + } + + simple_object_release_write (dest_sobj); + return NULL; +} + /* Fetch attributes. */ simple_object_attributes * @@ -315,7 +396,7 @@ simple_object_start_write (simple_object_attributes *attrs, return NULL; ret = XNEW (simple_object_write); ret->functions = attrs->functions; - ret->segment_name = xstrdup (segment_name); + ret->segment_name = segment_name ? xstrdup (segment_name) : NULL; ret->sections = NULL; ret->last_section = NULL; ret->data = data; -- 2.34.1