diff options
author | Richard Biener <rguenther@suse.de> | 2017-08-21 10:29:00 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2017-08-21 10:29:00 +0000 |
commit | 1ea85365b430b5ade1d0b824e5406c006e6ffdb7 (patch) | |
tree | 3f66db94dd051305b43f1de3bf2077e236deb8a7 /libiberty | |
parent | 9f33a5d9acbed950bf446849e9d6968cf22cb9a2 (diff) | |
download | gcc-1ea85365b430b5ade1d0b824e5406c006e6ffdb7.tar.gz |
re PR go/78628 (GO fails to build a translation unit decl)
2017-08-21 Richard Biener <rguenther@suse.de>
include/
* simple-object.h (simple_object_copy_lto_debug_sections): New
function.
libiberty/
* 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.
gcc/
* debug.h (struct gcc_debug_hooks): Add die_ref_for_decl and
register_external_die hooks.
(debug_false_tree_charstarstar_uhwistar): Declare.
(debug_nothing_tree_charstar_uhwi): Likewise.
* debug.c (do_nothing_debug_hooks): Adjust.
(debug_false_tree_charstarstar_uhwistar): New do nothing.
(debug_nothing_tree_charstar_uhwi): Likewise.
* dbxout.c (dbx_debug_hooks): Adjust.
(xcoff_debug_hooks): Likewise.
* sdbout.c (sdb_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* dwarf2out.c (macinfo_label_base): New global.
(dwarf2out_register_external_die): New function for the
register_external_die hook.
(dwarf2out_die_ref_for_decl): Likewise for die_ref_for_decl.
(dwarf2_debug_hooks): Use them.
(dwarf2_lineno_debug_hooks): Adjust.
(struct die_struct): Add with_offset flag.
(DEBUG_LTO_DWO_INFO_SECTION, DEBUG_LTO_INFO_SECTION,
DEBUG_LTO_DWO_ABBREV_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_DWO_MACINFO_SECTION, DEBUG_LTO_MACINFO_SECTION,
DEBUG_LTO_DWO_MACRO_SECTION, DEBUG_LTO_MACRO_SECTION,
DEBUG_LTO_LINE_SECTION, DEBUG_LTO_DWO_STR_OFFSETS_SECTION,
DEBUG_LTO_STR_DWO_SECTION, DEBUG_STR_LTO_SECTION): New macros
defining section names for the early LTO debug variants.
(reset_indirect_string): New helper.
(add_AT_external_die_ref): Helper for dwarf2out_register_external_die.
(print_dw_val): Add support for offsetted symbol references.
(get_ultimate_context): Split out from is_cxx.
(is_cxx): Use get_ultimate_context.
(is_fortran): Add decl overload.
(compute_comp_unit_symbol): Split out worker from
compute_section_prefix.
(compute_section_prefix): Call compute_comp_unit_symbol and
set comdat_type_p here.
(output_die): Skip DIE symbol output for the LTO added one.
Handle DIE symbol references with offset.
(output_comp_unit): Guard section name mangling properly.
For LTO debug sections emit a symbol at the section beginning
which we use to refer to its DIEs.
(add_abstract_origin_attribute): For DIEs registered via
dwarf2out_register_external_die directly refer to the early
DIE rather than indirectly through the shadow one we created.
Remove obsolete call to dwarf2out_abstract_function for
non-function/block origins.
(gen_array_type_die): When generating early LTO debug do
not emit DW_AT_string_length.
(gen_formal_parameter_die): Do not re-create DIEs for PARM_DECLs
late when in LTO. As suggested place a gcc_unreachable for
the DECL_ABSTRACT_P case.
(gen_subprogram_die): Avoid another specification DIE
for early built declarations/definitions for the late LTO case.
(gen_variable_die): Add type references for late duplicated VLA dies
when in late LTO.
(gen_inlined_subroutine_die): Do not call dwarf2out_abstract_function,
we have the abstract instance already.
(process_scope_var): Adjust decl DIE contexts in LTO which
first puts them in limbo.
(gen_decl_die): Do not generate type DIEs late apart from
types for VLAs or for decls we do not yet have a DIE. Do not
call dwarf2out_abstract_function late.
(dwarf2out_early_global_decl): Make sure to create DIEs
for abstract instances of a decl first.
(dwarf2out_late_global_decl): Adjust comment.
(output_macinfo_op): With multiple macro sections use
macinfo_label_base to distinguish labels.
(output_macinfo): Likewise. Update macinfo_label_base.
Pass in the line info label.
(note_variable_value_in_expr): When generating LTO resolve
all variable values here by generating DIEs as needed.
(init_sections_and_labels): Add early LTO debug flag parameter
and generate different sections and names if set. Add generation
counter for the labels so we can have multiple of them.
(reset_dies): Helper to allow DIEs to be output multiple times.
(dwarf2out_finish): When outputting DIEs to the fat part of an
LTO object first reset DIEs.
(dwarf2out_early_finish): Output early DIEs when generating LTO.
(modified_type_die): Check for decl_ultimate_origin being self
before recursing.
(gen_type_die_with_usage): Likewise.
(gen_typedef_die): Allow decl_ultimate_origin being self.
(set_decl_abstract_flags): Remove.
(set_block_abstract_flags): Likewise.
(dwarf2out_abstract_function): Treat the early generated DIEs
as the abstract copy and only add DW_AT_inline and
DW_AT_artificial here and call set_decl_origin_self.
If the DIE has an abstract origin don't do anything.
* tree.c (free_lang_data): Build a dummy TRANSLATION_UNIT_DECL
if we have none yet (Go fails to build one, PR78628).
(variably_modified_type_p): Prevent endless recursion for Ada
cyclic pointer types.
* lto-streamer-in.c: Include debug.h.
(dref_queue): New global.
(lto_read_tree_1): Stream in DIE references.
(lto_input_tree): Register DIE references.
(input_function): Stream DECL_DEBUG_ARGS.
* lto-streamer-out.c: Include debug.h.
(lto_write_tree_1): Output DIE references.
(DFS::DFS_write_tree_body): Follow DECL_ABSTRACT_ORIGIN.
Force a TRANSLATION_UNIT_DECL DECL_CONTEXT for file-scope decls.
(output_function): Stream DECL_DEBUG_ARGS.
* tree-streamer-in.c (lto_input_ts_decl_common_tree_pointers):
Stream DECL_ABSTRACT_ORIGIN.
* tree-streamer-out.c (write_ts_decl_common_tree_pointers): Likewise.
(write_ts_decl_minimal_tree_pointers): Force a TRANSLATION_UNIT_DECL
DECL_CONTEXT for file-scope decls.
* lto-streamer.h (struct dref_entry): Declare.
(dref_queue): Likewise.
* cfgexpand.c (pass_expand::execute): Do not call the
outlining_inline_function hook here.
* lto-wrapper.c (debug_obj): New global.
(tool_cleanup): Unlink it if required.
(debug_objcopy): New function.
(run_gcc): Handle early debug sections in the IL files by
extracting them to separate files, partially linkin them and
feeding the result back as result to the linker.
* config/darwin.h (DEBUG_LTO_INFO_SECTION, DEBUG_LTO_ABBREV_SECTION,
DEBUG_LTO_MACINFO_SECTION, DEBUG_LTO_LINE_SECTION,
DEBUG_STR_LTO_SECTION, DEBUG_LTO_MACRO_SECTION): Put early debug
sections into a separate segment.
* config/darwin.c (darwin_asm_named_section): Handle __GNU_DWARF_LTO
segments.
(darwin_asm_dwarf_section): Likewise.
(darwin_asm_output_dwarf_offset): Likewise.
* config/i386/i386.c (make_resolver_func): Set DECL_IGNORED_P.
lto/
* lto.c (unify_scc): Truncate DIE reference queue for dropped SCCs.
(lto_read_decls): Process TRANSLATION_UNIT_DECLs. Remove
TYPE_DECL debug processing, register DIE references from
prevailing SCCs with the debug machinery.
(lto_section_with_id): Handle LTO debug sections.
libstdc++/
* testsuite/libstdc++-prettyprinters/prettyprinters.exp: Run all
tests with -flto as well if supported.
testsuite/
* c-c++-common/asan/global-overflow-1.c: Adjust diagnostic location
regex to handle the LTO case.
* c-c++-common/asan/heap-overflow-1.c: Likewise.
* c-c++-common/asan/misalign-1.c: Likewise.
* c-c++-common/asan/misalign-2.c: Likewise.
* c-c++-common/asan/null-deref-1.c: Likewise.
* c-c++-common/asan/stack-overflow-1.c: Likewise.
* c-c++-common/asan/strncpy-overflow-1.c: Likewise.
* c-c++-common/asan/use-after-free-1.c: Likewise.
* c-c++-common/asan/alloca_big_alignment.c: Likewise.
* c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
* c-c++-common/asan/alloca_overflow_partial.c: Likewise.
* c-c++-common/asan/alloca_overflow_right.c: Likewise.
* c-c++-common/asan/alloca_underflow_left.c: Likewise.
* g++.dg/asan/large-func-test-1.C: Likewise.
* gfortran.dg/save_6.f90: Add -flto -g variant of save_5.f90.
From-SVN: r251220
Diffstat (limited to 'libiberty')
-rw-r--r-- | libiberty/ChangeLog | 33 | ||||
-rw-r--r-- | libiberty/simple-object-coff.c | 3 | ||||
-rw-r--r-- | libiberty/simple-object-common.h | 6 | ||||
-rw-r--r-- | libiberty/simple-object-elf.c | 482 | ||||
-rw-r--r-- | libiberty/simple-object-mach-o.c | 3 | ||||
-rw-r--r-- | libiberty/simple-object-xcoff.c | 3 | ||||
-rw-r--r-- | libiberty/simple-object.c | 83 |
7 files changed, 592 insertions, 21 deletions
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 027aa56c88d..48ee098f3d7 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,36 @@ +2017-08-21 Richard Biener <rguenther@suse.de> + + * 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 <jan.kratochvil@redhat.com> * dwarfnames.c (DW_FIRST_IDX, DW_END_IDX, DW_IDX, DW_IDX_DUP): New. diff --git a/libiberty/simple-object-coff.c b/libiberty/simple-object-coff.c index 0283b15c803..54d430dad9b 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 cda4038c9d7..733bdd0e7b6 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 a733e4b1a2a..56336264ce9 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 * @@ -675,12 +735,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 +827,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, + unsigned int sh_addralign, + unsigned int sh_entsize, const char **errmsg, int *err) { struct simple_object_elf_attributes *attrs = @@ -788,12 +852,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_Word, sh_entsize); return simple_object_internal_write (descriptor, offset, buf, shdr_size, errmsg, err); @@ -811,8 +876,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 +891,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 +929,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; + unsigned int sh_addralign = 1U << section->align; + unsigned int 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_Word); + 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 +1006,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 +1019,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 +1056,354 @@ 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. */ + 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_Addr, 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 +1416,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 bbadf5d8330..b90fca88b23 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 7be1bf33fe3..2adebe37107 100644 --- a/libiberty/simple-object-xcoff.c +++ b/libiberty/simple-object-xcoff.c @@ -1006,5 +1006,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 8ea9cf129fd..553e90f5048 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 <errno.h> +#include <fcntl.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -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; |