diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/elf.c | 31 | ||||
-rw-r--r-- | bfd/elflink.c | 50 | ||||
-rw-r--r-- | bfd/libbfd-in.h | 3 | ||||
-rw-r--r-- | bfd/libbfd.c | 52 | ||||
-rw-r--r-- | bfd/libbfd.h | 3 |
5 files changed, 98 insertions, 41 deletions
@@ -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) { |