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;
. 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;
extern Elf_Internal_Rela *_bfd_elf_link_read_relocs
(bfd *, asection *, void *, Elf_Internal_Rela *, bool);
+extern Elf_Internal_Rela *_bfd_elf_link_info_read_relocs
+ (bfd *, struct bfd_link_info *, asection *, void *, Elf_Internal_Rela *,
+ bool);
extern bool _bfd_elf_link_output_relocs
(bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *,
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;
}
}
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;
}
}
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,
- bool 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,
+ bool keep_memory)
{
void *alloc1 = NULL;
Elf_Internal_Rela *alloc2 = NULL;
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)
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,
+ bool 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. */
|| 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;
&& (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;
/* 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;
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;
}
}
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;
return true;
}
+struct link_info_ok
+{
+ struct bfd_link_info *info;
+ bool ok;
+};
+
static bool
-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. */
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 *(bool *) okp = false;
+ return info->ok = false;
bed = get_elf_backend_data (sec->owner);
log_file_align = bed->s->log_file_align;
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))
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. */
extern struct bfd_link_info *_bfd_get_link_info (bfd *);
+extern bool _bfd_link_keep_memory (struct bfd_link_info *)
+ ATTRIBUTE_HIDDEN;
+
#if GCC_VERSION >= 7000
#define _bfd_mul_overflow(a, b, res) __builtin_mul_overflow (a, b, res)
#else
extern struct bfd_link_info *_bfd_get_link_info (bfd *);
+extern bool _bfd_link_keep_memory (struct bfd_link_info *)
+ ATTRIBUTE_HIDDEN;
+
#if GCC_VERSION >= 7000
#define _bfd_mul_overflow(a, b, res) __builtin_mul_overflow (a, b, res)
#else
{
return (struct bfd_link_hash_entry *) _bfd_ptr_bfd_null_error (sec->owner);
}
+
+/* Return false if linker should avoid caching relocation infomation
+ and symbol tables of input files in memory. */
+
+bool
+_bfd_link_keep_memory (struct bfd_link_info * info)
+{
+ bfd *abfd;
+ bfd_size_type size;
+
+ if (!info->keep_memory)
+ return false;
+
+ if (info->max_cache_size == (bfd_size_type) -1)
+ return true;
+
+ abfd = info->input_bfds;
+ size = info->cache_size;
+ do
+ {
+ if (size >= info->max_cache_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;
+}
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;
}
/* 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 cache size. Backend can use cache_size and and
+ max_cache_size to decide if keep_memory should be honored. */
+ bfd_size_type max_cache_size;
};
/* Some forward-definitions used by some callbacks. */
-*- text -*-
+* Add --max-cache-size=SIZE to set the the maximum cache size to SIZE
+ bytes.
+
Changes in 2.37:
* arm-symbianelf support removed.
The @option{--reduce-memory-overheads} switch may be also be used to
enable other tradeoffs in future versions of the linker.
+@kindex --max-cache-size=@var{size}
+@item --max-cache-size=@var{size}
+@command{ld} normally caches the relocation information and symbol tables
+of input files in memory with the unlimited size. This option sets the
+maximum cache size to @var{size}.
+
@kindex --build-id
@kindex --build-id=@var{style}
@item --build-id
OPTION_WARN_TEXTREL,
OPTION_WARN_ALTERNATE_EM,
OPTION_REDUCE_MEMORY_OVERHEADS,
+ OPTION_MAX_CACHE_SIZE,
#if BFD_SUPPORTS_PLUGINS
OPTION_PLUGIN,
OPTION_PLUGIN_OPT,
link_info.allow_undefined_version = true;
link_info.keep_memory = true;
+ link_info.max_cache_size = (bfd_size_type) -1;
link_info.combreloc = true;
link_info.strip_discarded = true;
link_info.prohibit_multiple_definition_absolute = false;
OPTION_REDUCE_MEMORY_OVERHEADS},
'\0', NULL, N_("Reduce memory overheads, possibly taking much longer"),
TWO_DASHES },
+ { {"max-cache-size=SIZE", required_argument, NULL,
+ OPTION_MAX_CACHE_SIZE},
+ '\0', NULL, N_("Set the maximum cache size to SIZE bytes"),
+ TWO_DASHES },
{ {"relax", no_argument, NULL, OPTION_RELAX},
'\0', NULL, N_("Reduce code size by using target specific optimizations"), TWO_DASHES },
{ {"no-relax", no_argument, NULL, OPTION_NO_RELAX},
config.hash_table_size = 1021;
break;
+ case OPTION_MAX_CACHE_SIZE:
+ {
+ char *end;
+ bfd_size_type cache_size = strtoul (optarg, &end, 0);
+ if (*end != '\0')
+ einfo (_("%F%P: invalid cache memory size: %s\n"),
+ optarg);
+ link_info.max_cache_size = cache_size;
+ }
+ break;
+
case OPTION_HASH_SIZE:
{
bfd_size_type new_size;
# really test -r. Use ld1 to link a fresh ld, ld2. Use ld2 to link a
# new ld, ld3. ld2 and ld3 should be identical.
set test_flags {"" "strip" "--static" "-Wl,--traditional-format"
- "-Wl,--no-keep-memory" "-Wl,--relax"}
+ "-Wl,--no-keep-memory" "-Wl,--relax"
+ "-Wl,--max-cache-size=-1"}
if { [istarget "powerpc-*-*"] } {
lappend test_flags "-Wl,--ppc476-workaround"
}