From 2c3b41e222ff1ad8eefd64fe3641522f3b801526 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Sat, 3 Nov 2018 04:08:28 +0000 Subject: system/binutils: disable -z separate-code by default on x86 since it breaks kernels --- system/binutils/memory.patch | 449 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 system/binutils/memory.patch (limited to 'system/binutils/memory.patch') diff --git a/system/binutils/memory.patch b/system/binutils/memory.patch new file mode 100644 index 000000000..f2cfea130 --- /dev/null +++ b/system/binutils/memory.patch @@ -0,0 +1,449 @@ +From 9999de060bbcc7cca9dce213deeeec6593887a8e Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 27 Feb 2018 12:22:58 -0800 +Subject: [PATCH] Limit memory size to half of address space + +When link_info.keep_memory is TRUE, linker caches the relocation +information and symbol tables of input files in memory. On 32-bit +hosts, linker runs out of 32-bit virtual memory on input files with many +relocations. This patch limits the allocated memory size to half of +the address space for 32-bit hosts. + +bfd/ + + PR ld/18028 + * bfd-in.h (_bfd_link_keep_memory): New. + * bfd-in2.h: Regenerated. + * bfd.c (bfd): Add alloc_size. + * elf-bfd.h (_bfd_elf_link_info_read_relocs): New. + * elf32-i386.c (elf_i386_check_relocs): Use _bfd_link_keep_memory. + Update cache_size. + * elf64-x86-64.c (elf_x86_64_check_relocs): Likewise. + * elflink.c (_bfd_elf_link_read_relocs): Renamed to ... + (_bfd_elf_link_info_read_relocs): This. Update cache_size. + (_bfd_elf_link_read_relocs): New. + (_bfd_elf_link_check_relocs): Call _bfd_elf_link_info_read_relocs + instead of _bfd_elf_link_read_relocs. + (elf_link_add_object_symbols): Likewise. + (elf_link_input_bfd): Likewise. + (init_reloc_cookie_rels): Likewise. + (init_reloc_cookie): Update cache_size. Call + _bfd_elf_link_info_read_relocs instead of + _bfd_elf_link_read_relocs. + (link_info_ok): New. + (elf_gc_smash_unused_vtentry_relocs): Updated. Call + _bfd_elf_link_info_read_relocs instead of + _bfd_elf_link_read_relocs. + (bfd_elf_gc_sections): Use link_info_ok. Pass &link_info_ok + to elf_gc_smash_unused_vtentry_relocs. + * linker.c (_bfd_link_keep_memory): New. + * opncls.c (bfd_alloc): Update alloc_size. + +include/ + + PR ld/18028 + * bfdlink.h (bfd_link_info): Add cache_size and max_alloc_size. + +ld/ + + PR ld/18028 + * ldmain.c: Include "bfd_stdint.h". + (main): Set link_info.max_alloc_size to half of the address space. +--- + bfd/bfd-in.h | 2 ++ + bfd/bfd-in2.h | 5 +++ + bfd/bfd.c | 3 ++ + bfd/elf-bfd.h | 3 ++ + bfd/elf32-i386.c | 3 +- + bfd/elf64-x86-64.c | 3 +- + bfd/elflink.c | 89 ++++++++++++++++++++++++++++++++++++++++-------------- + bfd/linker.c | 33 ++++++++++++++++++++ + bfd/opncls.c | 2 ++ + include/bfdlink.h | 7 +++++ + ld/ldmain.c | 3 ++ + 11 files changed, 128 insertions(+), 25 deletions(-) + +diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h +index a06cd740c0..ca4bec8aab 100644 +--- a/bfd/bfd-in.h ++++ b/bfd/bfd-in.h +@@ -600,6 +600,8 @@ struct bfd_section_already_linked; + struct bfd_elf_version_tree; + #endif + ++extern bfd_boolean _bfd_link_keep_memory (struct bfd_link_info *); ++ + extern bfd_boolean bfd_section_already_linked_table_init (void); + extern void bfd_section_already_linked_table_free (void); + extern bfd_boolean _bfd_handle_already_linked +diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h +index 9742c1ac7f..0794bcdcdb 100644 +--- a/bfd/bfd-in2.h ++++ b/bfd/bfd-in2.h +@@ -607,6 +607,8 @@ struct bfd_section_already_linked; + struct bfd_elf_version_tree; + #endif + ++extern bfd_boolean _bfd_link_keep_memory (struct bfd_link_info *); ++ + extern bfd_boolean bfd_section_already_linked_table_init (void); + extern void bfd_section_already_linked_table_free (void); + extern bfd_boolean _bfd_handle_already_linked +@@ -6989,6 +6991,9 @@ struct bfd + be used only for archive elements. */ + int archive_pass; + ++ /* The total size of memory from bfd_alloc. */ ++ bfd_size_type alloc_size; ++ + /* Stuff only useful for object files: + The start address. */ + bfd_vma start_address; +diff --git a/bfd/bfd.c b/bfd/bfd.c +index 288b5b14fe..182b544662 100644 +--- a/bfd/bfd.c ++++ b/bfd/bfd.c +@@ -267,6 +267,9 @@ CODE_FRAGMENT + . be used only for archive elements. *} + . int archive_pass; + . ++. {* The total size of memory from bfd_alloc. *} ++. bfd_size_type alloc_size; ++. + . {* Stuff only useful for object files: + . The start address. *} + . bfd_vma start_address; +diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h +index afd6982a92..37a7b07e51 100644 +--- a/bfd/elf-bfd.h ++++ b/bfd/elf-bfd.h +@@ -2294,6 +2294,9 @@ extern char *_bfd_elfcore_strndup + + extern Elf_Internal_Rela *_bfd_elf_link_read_relocs + (bfd *, asection *, void *, Elf_Internal_Rela *, bfd_boolean); ++extern Elf_Internal_Rela *_bfd_elf_link_info_read_relocs ++ (bfd *, struct bfd_link_info *, asection *, void *, Elf_Internal_Rela *, ++ bfd_boolean); + + extern bfd_boolean _bfd_elf_link_output_relocs + (bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *, +diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c +index 61a14097b0..9a781dc089 100644 +--- a/bfd/elf32-i386.c ++++ b/bfd/elf32-i386.c +@@ -1909,13 +1909,14 @@ elf_i386_check_relocs (bfd *abfd, + + if (elf_section_data (sec)->this_hdr.contents != contents) + { +- if (!converted && !info->keep_memory) ++ if (!converted && !_bfd_link_keep_memory (info)) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd if any + load is converted or --no-keep-memory isn't used. */ + elf_section_data (sec)->this_hdr.contents = contents; ++ info->cache_size += sec->size; + } + } + +diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c +index 7016964ace..4ba15ec9fa 100644 +--- a/bfd/elf64-x86-64.c ++++ b/bfd/elf64-x86-64.c +@@ -2281,13 +2281,14 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, + + if (elf_section_data (sec)->this_hdr.contents != contents) + { +- if (!converted && !info->keep_memory) ++ if (!converted && !_bfd_link_keep_memory (info)) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd if any + load is converted or --no-keep-memory isn't used. */ + elf_section_data (sec)->this_hdr.contents = contents; ++ info->cache_size += sec->size; + } + } + +diff --git a/bfd/elflink.c b/bfd/elflink.c +index 092edaea26..831605b80a 100644 +--- a/bfd/elflink.c ++++ b/bfd/elflink.c +@@ -2475,14 +2475,16 @@ elf_link_read_relocs_from_section (bfd *abfd, + according to the KEEP_MEMORY argument. If O has two relocation + sections (both REL and RELA relocations), then the REL_HDR + relocations will appear first in INTERNAL_RELOCS, followed by the +- RELA_HDR relocations. */ ++ RELA_HDR relocations. If INFO isn't NULL and KEEP_MEMORY is TRUE, ++ update cache_size. */ + + Elf_Internal_Rela * +-_bfd_elf_link_read_relocs (bfd *abfd, +- asection *o, +- void *external_relocs, +- Elf_Internal_Rela *internal_relocs, +- bfd_boolean keep_memory) ++_bfd_elf_link_info_read_relocs (bfd *abfd, ++ struct bfd_link_info *info, ++ asection *o, ++ void *external_relocs, ++ Elf_Internal_Rela *internal_relocs, ++ bfd_boolean keep_memory) + { + void *alloc1 = NULL; + Elf_Internal_Rela *alloc2 = NULL; +@@ -2502,7 +2504,11 @@ _bfd_elf_link_read_relocs (bfd *abfd, + + size = (bfd_size_type) o->reloc_count * sizeof (Elf_Internal_Rela); + if (keep_memory) +- internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size); ++ { ++ internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size); ++ if (info) ++ info->cache_size += size; ++ } + else + internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size); + if (internal_relocs == NULL) +@@ -2568,6 +2574,22 @@ _bfd_elf_link_read_relocs (bfd *abfd, + return NULL; + } + ++/* This is similar to _bfd_elf_link_info_read_relocs, except for that ++ NULL is passed to _bfd_elf_link_info_read_relocs for pointer to ++ struct bfd_link_info. */ ++ ++Elf_Internal_Rela * ++_bfd_elf_link_read_relocs (bfd *abfd, ++ asection *o, ++ void *external_relocs, ++ Elf_Internal_Rela *internal_relocs, ++ bfd_boolean keep_memory) ++{ ++ return _bfd_elf_link_info_read_relocs (abfd, NULL, o, external_relocs, ++ internal_relocs, keep_memory); ++ ++} ++ + /* Compute the size of, and allocate space for, REL_HDR which is the + section header for a section containing relocations for O. */ + +@@ -3736,8 +3758,10 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info) + || bfd_is_abs_section (o->output_section)) + continue; + +- internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, +- info->keep_memory); ++ internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info, ++ o, NULL, ++ NULL, ++ _bfd_link_keep_memory (info)); + if (internal_relocs == NULL) + return FALSE; + +@@ -4990,9 +5014,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) + && (s->flags & SEC_DEBUGGING) != 0)) + continue; + +- internal_relocs = _bfd_elf_link_read_relocs (abfd, s, NULL, +- NULL, +- info->keep_memory); ++ internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info, ++ s, NULL, ++ NULL, ++ _bfd_link_keep_memory (info)); + if (internal_relocs == NULL) + goto error_free_vers; + +@@ -10518,8 +10543,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) + + /* Get the swapped relocs. */ + internal_relocs +- = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs, +- flinfo->internal_relocs, FALSE); ++ = _bfd_elf_link_info_read_relocs (input_bfd, flinfo->info, o, ++ flinfo->external_relocs, ++ flinfo->internal_relocs, ++ FALSE); + if (internal_relocs == NULL + && o->reloc_count > 0) + return FALSE; +@@ -12684,8 +12711,12 @@ init_reloc_cookie (struct elf_reloc_cookie *cookie, + info->callbacks->einfo (_("%P%X: can not read symbols: %E\n")); + return FALSE; + } +- if (info->keep_memory) +- symtab_hdr->contents = (bfd_byte *) cookie->locsyms; ++ if (_bfd_link_keep_memory (info) ) ++ { ++ symtab_hdr->contents = (bfd_byte *) cookie->locsyms; ++ info->cache_size += (cookie->locsymcount ++ * sizeof (Elf_External_Sym_Shndx)); ++ } + } + return TRUE; + } +@@ -12718,8 +12749,9 @@ init_reloc_cookie_rels (struct elf_reloc_cookie *cookie, + } + else + { +- cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, +- info->keep_memory); ++ cookie->rels = _bfd_elf_link_info_read_relocs (abfd, info, sec, ++ NULL, NULL, ++ _bfd_link_keep_memory (info)); + if (cookie->rels == NULL) + return FALSE; + cookie->rel = cookie->rels; +@@ -13233,14 +13265,21 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp) + return TRUE; + } + ++struct link_info_ok ++{ ++ struct bfd_link_info *info; ++ bfd_boolean ok; ++}; ++ + static bfd_boolean +-elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) ++elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *ptr) + { + asection *sec; + bfd_vma hstart, hend; + Elf_Internal_Rela *relstart, *relend, *rel; + const struct elf_backend_data *bed; + unsigned int log_file_align; ++ struct link_info_ok *info = (struct link_info_ok *) ptr; + + /* Take care of both those symbols that do not describe vtables as + well as those that are not loaded. */ +@@ -13256,9 +13295,10 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) + hstart = h->root.u.def.value; + hend = hstart + h->size; + +- relstart = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, TRUE); ++ relstart = _bfd_elf_link_info_read_relocs (sec->owner, info->info, ++ sec, NULL, NULL, TRUE); + if (!relstart) +- return *(bfd_boolean *) okp = FALSE; ++ return info->ok = FALSE; + bed = get_elf_backend_data (sec->owner); + log_file_align = bed->s->log_file_align; + +@@ -13379,6 +13419,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) + elf_gc_mark_hook_fn gc_mark_hook; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_link_hash_table *htab; ++ struct link_info_ok info_ok; + + if (!bed->can_gc_sections + || !is_elf_hash_table (info->hash)) +@@ -13420,8 +13461,10 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) + return FALSE; + + /* Kill the vtable relocations that were not used. */ +- elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok); +- if (!ok) ++ info_ok.info = info; ++ info_ok.ok = TRUE; ++ elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &info_ok); ++ if (!info_ok.ok) + return FALSE; + + /* Mark dynamically referenced symbols. */ +diff --git a/bfd/linker.c b/bfd/linker.c +index c29a6e7e10..909d768552 100644 +--- a/bfd/linker.c ++++ b/bfd/linker.c +@@ -3471,3 +3471,36 @@ _bfd_nolink_bfd_define_start_stop (struct bfd_link_info *info ATTRIBUTE_UNUSED, + { + return (struct bfd_link_hash_entry *) _bfd_ptr_bfd_null_error (sec->owner); + } ++ ++bfd_boolean ++_bfd_link_keep_memory (struct bfd_link_info * info) ++{ ++ bfd *abfd; ++ bfd_size_type size; ++ ++ if (!info->keep_memory) ++ return FALSE; ++ ++ /* Keep allocated memory size below limit only for 32-bit hosts. */ ++ if (sizeof (void *) > 4) ++ return TRUE; ++ ++ abfd = info->input_bfds; ++ size = info->cache_size; ++ do ++ { ++ if (size >= info->max_alloc_size) ++ { ++ /* Over the limit. Reduce the memory usage. */ ++ info->keep_memory = FALSE; ++ return FALSE; ++ } ++ if (!abfd) ++ break; ++ size += abfd->alloc_size; ++ abfd = abfd->link.next; ++ } ++ while (1); ++ ++ return TRUE; ++} +diff --git a/bfd/opncls.c b/bfd/opncls.c +index 16b568c8ab..86262e1231 100644 +--- a/bfd/opncls.c ++++ b/bfd/opncls.c +@@ -949,6 +949,8 @@ bfd_alloc (bfd *abfd, bfd_size_type size) + ret = objalloc_alloc ((struct objalloc *) abfd->memory, ul_size); + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); ++ else ++ abfd->alloc_size += size; + return ret; + } + +diff --git a/include/bfdlink.h b/include/bfdlink.h +index 5d637acbab..f06d5171c3 100644 +--- a/include/bfdlink.h ++++ b/include/bfdlink.h +@@ -635,6 +635,13 @@ struct bfd_link_info + + /* The version information. */ + struct bfd_elf_version_tree *version_info; ++ ++ /* Size of cache. Backend can use it to keep strace cache size. */ ++ bfd_size_type cache_size; ++ ++ /* The maximum size of allocated memory. Backend can use cache_size ++ and and max_alloc_size to decide if keep_memory should be honored. */ ++ bfd_size_type max_alloc_size; + }; + + /* This structures holds a set of callback functions. These are called +diff --git a/ld/ldmain.c b/ld/ldmain.c +index b6914db5da..14c3349c97 100644 +--- a/ld/ldmain.c ++++ b/ld/ldmain.c +@@ -21,6 +21,7 @@ + + #include "sysdep.h" + #include "bfd.h" ++#include "bfd_stdint.h" + #include "safe-ctype.h" + #include "libiberty.h" + #include "progress.h" +@@ -271,6 +272,8 @@ main (int argc, char **argv) + + link_info.allow_undefined_version = TRUE; + link_info.keep_memory = TRUE; ++ /* Limit the allocated memory size to half of the address space. */ ++ link_info.max_alloc_size = ((uintptr_t) (void *) -1) / 2; + link_info.combreloc = TRUE; + link_info.strip_discarded = TRUE; + link_info.emit_hash = DEFAULT_EMIT_SYSV_HASH; -- cgit v1.2.3-60-g2f50