aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf.c31
-rw-r--r--bfd/elflink.c50
-rw-r--r--bfd/libbfd-in.h3
-rw-r--r--bfd/libbfd.c52
-rw-r--r--bfd/libbfd.h3
5 files changed, 98 insertions, 41 deletions
diff --git a/bfd/elf.c b/bfd/elf.c
index 5d29965..868abec 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -460,19 +460,16 @@ bfd_elf_get_elf_syms (bfd *ibfd,
goto out;
}
pos = symtab_hdr->sh_offset + symoffset * extsym_size;
- if (extsym_buf == NULL)
- {
- alloc_ext = bfd_malloc (amt);
- extsym_buf = alloc_ext;
- }
- if (extsym_buf == NULL
- || bfd_seek (ibfd, pos, SEEK_SET) != 0
- || bfd_read (extsym_buf, amt, ibfd) != amt)
+ size_t alloc_ext_size = amt;
+ if (bfd_seek (ibfd, pos, SEEK_SET) != 0
+ || !_bfd_mmap_read_temporary (&extsym_buf, &alloc_ext_size,
+ &alloc_ext, ibfd, false))
{
intsym_buf = NULL;
goto out;
}
+ size_t alloc_extshndx_size = 0;
if (shndx_hdr == NULL || shndx_hdr->sh_size == 0)
extshndx_buf = NULL;
else
@@ -483,15 +480,13 @@ bfd_elf_get_elf_syms (bfd *ibfd,
intsym_buf = NULL;
goto out;
}
+ alloc_extshndx_size = amt;
pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
- if (extshndx_buf == NULL)
- {
- alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- extshndx_buf = alloc_extshndx;
- }
- if (extshndx_buf == NULL
- || bfd_seek (ibfd, pos, SEEK_SET) != 0
- || bfd_read (extshndx_buf, amt, ibfd) != amt)
+ if (bfd_seek (ibfd, pos, SEEK_SET) != 0
+ || !_bfd_mmap_read_temporary ((void **) &extshndx_buf,
+ &alloc_extshndx_size,
+ (void **) &alloc_extshndx,
+ ibfd, false))
{
intsym_buf = NULL;
goto out;
@@ -530,8 +525,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
}
out:
- free (alloc_ext);
- free (alloc_extshndx);
+ _bfd_munmap_readonly_temporary (alloc_ext, alloc_ext_size);
+ _bfd_munmap_readonly_temporary (alloc_extshndx, alloc_extshndx_size);
return intsym_buf;
}
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 2991e06..7e9f4c7 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2644,8 +2644,11 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
may be either a REL or a RELA section. The relocations are
translated into RELA relocations and stored in INTERNAL_RELOCS,
which should have already been allocated to contain enough space.
- The EXTERNAL_RELOCS are a buffer where the external form of the
- relocations should be stored.
+ The *EXTERNAL_RELOCS_P are a buffer where the external form of the
+ relocations should be stored. If *EXTERNAL_RELOCS_ADDR is NULL,
+ *EXTERNAL_RELOCS_ADDR and *EXTERNAL_RELOCS_SIZE returns the mmap
+ memory address and size. Otherwise, *EXTERNAL_RELOCS_ADDR is
+ unchanged and *EXTERNAL_RELOCS_SIZE returns 0.
Returns FALSE if something goes wrong. */
@@ -2653,7 +2656,8 @@ static bool
elf_link_read_relocs_from_section (bfd *abfd,
const asection *sec,
Elf_Internal_Shdr *shdr,
- void *external_relocs,
+ void **external_relocs_addr,
+ size_t *external_relocs_size,
Elf_Internal_Rela *internal_relocs)
{
const struct elf_backend_data *bed;
@@ -2663,13 +2667,17 @@ elf_link_read_relocs_from_section (bfd *abfd,
Elf_Internal_Rela *irela;
Elf_Internal_Shdr *symtab_hdr;
size_t nsyms;
+ void *external_relocs = *external_relocs_addr;
/* Position ourselves at the start of the section. */
if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0)
return false;
/* Read the relocations. */
- if (bfd_read (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
+ *external_relocs_size = shdr->sh_size;
+ if (!_bfd_mmap_read_temporary (&external_relocs,
+ external_relocs_size,
+ external_relocs_addr, abfd, true))
return false;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -2754,6 +2762,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd,
bool keep_memory)
{
void *alloc1 = NULL;
+ size_t alloc1_size;
Elf_Internal_Rela *alloc2 = NULL;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct bfd_elf_section_data *esdo = elf_section_data (o);
@@ -2782,26 +2791,12 @@ _bfd_elf_link_info_read_relocs (bfd *abfd,
goto error_return;
}
- if (external_relocs == NULL)
- {
- bfd_size_type size = 0;
-
- if (esdo->rel.hdr)
- size += esdo->rel.hdr->sh_size;
- if (esdo->rela.hdr)
- size += esdo->rela.hdr->sh_size;
-
- alloc1 = bfd_malloc (size);
- if (alloc1 == NULL)
- goto error_return;
- external_relocs = alloc1;
- }
-
+ alloc1 = external_relocs;
internal_rela_relocs = internal_relocs;
if (esdo->rel.hdr)
{
if (!elf_link_read_relocs_from_section (abfd, o, esdo->rel.hdr,
- external_relocs,
+ &alloc1, &alloc1_size,
internal_relocs))
goto error_return;
external_relocs = (((bfd_byte *) external_relocs)
@@ -2812,7 +2807,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd,
if (esdo->rela.hdr
&& (!elf_link_read_relocs_from_section (abfd, o, esdo->rela.hdr,
- external_relocs,
+ &alloc1, &alloc1_size,
internal_rela_relocs)))
goto error_return;
@@ -2820,7 +2815,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd,
if (keep_memory)
esdo->relocs = internal_relocs;
- free (alloc1);
+ _bfd_munmap_readonly_temporary (alloc1, alloc1_size);
/* Don't free alloc2, since if it was allocated we are passing it
back (under the name of internal_relocs). */
@@ -2828,7 +2823,7 @@ _bfd_elf_link_info_read_relocs (bfd *abfd,
return internal_relocs;
error_return:
- free (alloc1);
+ _bfd_munmap_readonly_temporary (alloc1, alloc1_size);
if (alloc2 != NULL)
{
if (keep_memory)
@@ -12446,7 +12441,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
section, so that we know the sizes of the reloc sections. We
also figure out some maximum sizes. */
max_contents_size = 0;
+#ifdef USE_MMAP
+ /* Mmap is used only if section size >= the minimum mmap section
+ size. max_external_reloc_size covers all relocation sections
+ smaller than the minimum mmap section size. */
+ max_external_reloc_size = _bfd_minimum_mmap_size;
+#else
max_external_reloc_size = 0;
+#endif
max_internal_reloc_count = 0;
max_sym_count = 0;
max_sym_shndx_count = 0;
@@ -12535,8 +12537,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if (esdi->rela.hdr != NULL)
ext_size += esdi->rela.hdr->sh_size;
+#ifndef USE_MMAP
if (ext_size > max_external_reloc_size)
max_external_reloc_size = ext_size;
+#endif
if (sec->reloc_count > max_internal_reloc_count)
max_internal_reloc_count = sec->reloc_count;
}
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index c5a79cf..889b221 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -905,6 +905,9 @@ extern void _bfd_munmap_readonly_temporary
#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr)
#endif
+extern bool _bfd_mmap_read_temporary
+ (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN;
+
static inline void *
_bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize)
{
diff --git a/bfd/libbfd.c b/bfd/libbfd.c
index e5147a2..869f0ed 100644
--- a/bfd/libbfd.c
+++ b/bfd/libbfd.c
@@ -1174,6 +1174,58 @@ _bfd_mmap_readonly_persistent (bfd *abfd, size_t rsize)
}
#endif
+/* Attempt to read *SIZE_P bytes from ABFD's iostream to *DATA_P.
+ Return true if the full the amount has been read. If *DATA_P is
+ NULL, mmap should be used, return the memory address at the
+ current offset in *DATA_P as well as return mmap address and size
+ in *MMAP_BASE and *SIZE_P. Otherwise, return NULL in *MMAP_BASE
+ and 0 in *SIZE_P. If FINAL_LINK is true, this is called from
+ elf_link_read_relocs_from_section. */
+
+bool
+_bfd_mmap_read_temporary (void **data_p, size_t *size_p,
+ void **mmap_base, bfd *abfd,
+ bool final_link ATTRIBUTE_UNUSED)
+{
+ void *data = *data_p;
+ size_t size = *size_p;
+
+#ifdef USE_MMAP
+ /* NB: When FINAL_LINK is true, the size of the preallocated buffer
+ is _bfd_minimum_mmap_size and use mmap if the data size >=
+ _bfd_minimum_mmap_size. Otherwise, use mmap if ABFD isn't an IR
+ input or the data size >= _bfd_minimum_mmap_size. */
+ bool use_mmmap;
+ bool mmap_size = size >= _bfd_minimum_mmap_size;
+ if (final_link)
+ use_mmmap = mmap_size;
+ else
+ use_mmmap = (mmap_size
+ && data == NULL
+ && (abfd->flags & BFD_PLUGIN) == 0);
+ if (use_mmmap)
+ {
+ data = _bfd_mmap_readonly_temporary (abfd, size, mmap_base,
+ size_p);
+ if (data == NULL || data == MAP_FAILED)
+ abort ();
+ *data_p = data;
+ return true;
+ }
+#endif
+
+ if (data == NULL)
+ {
+ data = bfd_malloc (size);
+ if (data == NULL)
+ return false;
+ *data_p = data;
+ }
+ *mmap_base = NULL;
+ *size_p = 0;
+ return bfd_read (data, size, abfd) == size;
+}
+
/* Default implementation */
bool
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 0caf0f3..0676f46 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -911,6 +911,9 @@ extern void _bfd_munmap_readonly_temporary
#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr)
#endif
+extern bool _bfd_mmap_read_temporary
+ (void **, size_t *, void **, bfd *, bool) ATTRIBUTE_HIDDEN;
+
static inline void *
_bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize)
{