diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 8b86607ec1d..d107a22f27e 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -689,6 +689,9 @@ typedef struct bfd_section /* Nonzero if this section uses RELA relocations, rather than REL. */ unsigned int use_rela_p:1; + /* Nonzero if this section contents are mmapped, rather than malloced. */ + unsigned int mmapped_p:1; + /* Bits used by various backends. The generic code doesn't touch these fields. */ @@ -976,8 +979,8 @@ discarded_section (const asection *sec) /* linker_mark, linker_has_input, gc_mark, decompress_status, */ \ 0, 0, 1, 0, \ \ - /* segment_mark, sec_info_type, use_rela_p, */ \ - 0, 0, 0, \ + /* segment_mark, sec_info_type, use_rela_p, mmapped_p, */ \ + 0, 0, 0, 0, \ \ /* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, */ \ 0, 0, 0, 0, 0, 0, \ diff --git a/bfd/compress.c b/bfd/compress.c index 19436a93955..3885c6d0080 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -753,7 +753,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) switch (compress_status) { case COMPRESS_SECTION_NONE: - if (p == NULL) + if (p == NULL && !sec->mmapped_p) { p = (bfd_byte *) bfd_malloc (allocsz); if (p == NULL) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 29283f24895..01e0da135b9 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1778,6 +1778,12 @@ struct elf_backend_data /* True if the 64-bit Linux PRPSINFO structure's `pr_uid' and `pr_gid' members use a 16-bit data type. */ unsigned linux_prpsinfo64_ugid16 : 1; + + /* True if the backend can use mmap to map in all input section + contents. All bfd_malloc_and_get_section and free usages on + section contents must be replaced by _bfd_elf_mmap_section_contents + and _bfd_elf_munmap_section_contents. */ + unsigned use_mmap : 1; }; /* Information about reloc sections associated with a bfd_elf_section_data @@ -1859,6 +1865,15 @@ struct bfd_elf_section_data /* Link from a text section to its .eh_frame_entry section. */ asection *eh_frame_entry; + /* If the mmapped_p flag is set, this points to the actual mmapped + address of contents. If it is set to NULL, contents isn't + mmapped. */ + void *contents_addr; + + /* If the mmapped_p flag is set, this is the actual mmapped size of + contents. */ + size_t contents_size; + /* TRUE if the section has secondary reloc sections associated with it. FIXME: In the future it might be better to change this into a list of secondary reloc sections, making lookup easier and faster. */ @@ -3127,6 +3142,11 @@ extern bool _bfd_elf_maybe_set_textrel extern bool _bfd_elf_add_dynamic_tags (bfd *, struct bfd_link_info *, bool); +extern bool _bfd_elf_mmap_section_contents + (bfd *abfd, asection *section, bfd_byte **buf); +extern void _bfd_elf_munmap_section_contents + (asection *, void *); + /* Large common section. */ extern asection _bfd_elf_large_com_section; diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 9a504234163..902d7c16334 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -618,7 +618,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, /* Read the frame unwind information from abfd. */ - REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); + REQUIRE (_bfd_elf_mmap_section_contents (abfd, sec, &ehbuf)); /* If .eh_frame section size doesn't fit into int, we cannot handle it (it would need to use 64-bit .eh_frame format anyway). */ @@ -1052,7 +1052,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, hdr_info->u.dwarf.table = false; free (sec_info); success: - free (ehbuf); + _bfd_elf_munmap_section_contents (sec, ehbuf); free (local_cies); #undef REQUIRE } diff --git a/bfd/elf-sframe.c b/bfd/elf-sframe.c index bfc875cd9fc..a4e3143e9d2 100644 --- a/bfd/elf-sframe.c +++ b/bfd/elf-sframe.c @@ -208,7 +208,7 @@ _bfd_elf_parse_sframe (bfd *abfd, } /* Read the SFrame stack trace information from abfd. */ - if (!bfd_malloc_and_get_section (abfd, sec, &sfbuf)) + if (!_bfd_elf_mmap_section_contents (abfd, sec, &sfbuf)) goto fail_no_free; /* Decode the buffer and keep decoded contents for later use. @@ -241,7 +241,7 @@ fail_no_free: abfd, sec); return false; success: - free (sfbuf); + _bfd_elf_munmap_section_contents (sec, sfbuf); return true; } diff --git a/bfd/elf.c b/bfd/elf.c index 34100d81355..5d2996505f4 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1111,12 +1111,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, { bfd_byte *contents; - if (!bfd_malloc_and_get_section (abfd, newsect, &contents)) + if (!_bfd_elf_mmap_section_contents (abfd, newsect, &contents)) return false; elf_parse_notes (abfd, (char *) contents, hdr->sh_size, hdr->sh_offset, hdr->sh_addralign); - free (contents); + _bfd_elf_munmap_section_contents (newsect, contents); } if ((newsect->flags & SEC_ALLOC) != 0) @@ -1686,7 +1686,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) fprintf (f, _("\nDynamic Section:\n")); - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + if (!_bfd_elf_mmap_section_contents (abfd, s, &dynbuf)) goto error_return; elfsec = _bfd_elf_section_from_bfd_section (abfd, s); @@ -1808,7 +1808,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) fprintf (f, "\n"); } - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); dynbuf = NULL; } @@ -1865,7 +1865,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) return true; error_return: - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); return false; } @@ -14370,3 +14370,80 @@ _bfd_elf_write_secondary_reloc_section (bfd *abfd, asection *sec) return result; } + +/* Mmap in section contents. */ + +bool +_bfd_elf_mmap_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **buf) +{ +#ifdef USE_MMAP + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + if (bed->use_mmap + && sec->compress_status == COMPRESS_SECTION_NONE + && (sec->flags & SEC_LINKER_CREATED) == 0) + { + /* Use mmap only if section size >= the minimum mmap section + size. */ + size_t readsz = bfd_get_section_limit_octets (abfd, sec); + size_t allocsz = bfd_get_section_alloc_size (abfd, sec); + if (readsz == allocsz && readsz >= _bfd_minimum_mmap_size) + { + if (sec->contents != NULL) + { + if (!sec->mmapped_p) + abort (); + *buf = sec->contents; + return true; + } + if (sec->mmapped_p) + abort (); + sec->mmapped_p = 1; + } + } +#endif + *buf = NULL; + bool ret = bfd_get_full_section_contents (abfd, sec, buf); + if (ret && sec->mmapped_p) + *buf = sec->contents; + return ret; +} + +/* Munmap section contents. */ + +void +_bfd_elf_munmap_section_contents (asection *sec ATTRIBUTE_UNUSED, + void *contents) +{ + /* NB: Since _bfd_elf_munmap_section_contents is called like free, + CONTENTS may be NULL. */ + if (contents == NULL) + return; + +#ifdef USE_MMAP + if (sec->mmapped_p) + { + /* _bfd_elf_mmap_section_contents may return the previously + mapped section contents. Munmap the section contents only + if they haven't been cached. */ + if (elf_section_data (sec)->this_hdr.contents == contents) + return; + + /* When _bfd_elf_mmap_section_contents returns CONTENTS as + malloced, CONTENTS_ADDR is set to NULL. */ + if (elf_section_data (sec)->contents_addr != NULL) + { + /* NB: CONTENTS_ADDR and CONTENTS_SIZE must be valid. */ + if (munmap (elf_section_data (sec)->contents_addr, + elf_section_data (sec)->contents_size) != 0) + abort (); + sec->mmapped_p = 0; + sec->contents = NULL; + elf_section_data (sec)->contents_addr = NULL; + elf_section_data (sec)->contents_size = 0; + return; + } + } +#endif + + free (contents); +} diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 9fa568fa979..fa1846881d3 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1499,7 +1499,7 @@ elf_i386_scan_relocs (bfd *abfd, /* Get the section contents. */ if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + else if (!_bfd_elf_mmap_section_contents (abfd, sec, &contents)) { sec->check_relocs_failed = 1; return false; @@ -1933,7 +1933,7 @@ elf_i386_scan_relocs (bfd *abfd, if (elf_section_data (sec)->this_hdr.contents != contents) { if (!converted && !_bfd_link_keep_memory (info)) - free (contents); + _bfd_elf_munmap_section_contents (sec, contents); else { /* Cache the section contents for elf_link_input_bfd if any @@ -1951,7 +1951,7 @@ elf_i386_scan_relocs (bfd *abfd, error_return: if (elf_section_data (sec)->this_hdr.contents != contents) - free (contents); + _bfd_elf_munmap_section_contents (sec, contents); sec->check_relocs_failed = 1; return false; } diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 8058d713c03..ebfd455a822 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -2057,7 +2057,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, /* Get the section contents. */ if (elf_section_data (sec)->this_hdr.contents != NULL) contents = elf_section_data (sec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + else if (!_bfd_elf_mmap_section_contents (abfd, sec, &contents)) { sec->check_relocs_failed = 1; return false; @@ -2591,7 +2591,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, if (elf_section_data (sec)->this_hdr.contents != contents) { if (!converted && !_bfd_link_keep_memory (info)) - free (contents); + _bfd_elf_munmap_section_contents (sec, contents); else { /* Cache the section contents for elf_link_input_bfd if any @@ -2609,7 +2609,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, error_return: if (elf_section_data (sec)->this_hdr.contents != contents) - free (contents); + _bfd_elf_munmap_section_contents (sec, contents); sec->check_relocs_failed = 1; return false; } @@ -5273,7 +5273,7 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd, continue; /* Get the PLT section contents. */ - if (!bfd_malloc_and_get_section (abfd, plt, &plt_contents)) + if (!_bfd_elf_mmap_section_contents (abfd, plt, &plt_contents)) break; /* Check what kind of PLT it is. */ @@ -5366,7 +5366,7 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd, if (plt_type == plt_unknown) { - free (plt_contents); + _bfd_elf_munmap_section_contents (plt, plt_contents); continue; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 1e0784611bc..39dfe0ba234 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -1195,6 +1195,7 @@ elf_checksum_contents (bfd *abfd, Elf_Internal_Shdr i_shdr; Elf_External_Shdr x_shdr; bfd_byte *contents, *free_contents; + asection *sec = NULL; i_shdr = *i_shdrp[count]; i_shdr.sh_offset = 0; @@ -1210,8 +1211,6 @@ elf_checksum_contents (bfd *abfd, contents = i_shdr.contents; if (contents == NULL) { - asection *sec; - sec = bfd_section_from_elf_index (abfd, count); if (sec != NULL) { @@ -1220,7 +1219,7 @@ elf_checksum_contents (bfd *abfd, { /* Force rereading from file. */ sec->flags &= ~SEC_IN_MEMORY; - if (!bfd_malloc_and_get_section (abfd, sec, &free_contents)) + if (!_bfd_elf_mmap_section_contents (abfd, sec, &free_contents)) continue; contents = free_contents; } @@ -1229,7 +1228,7 @@ elf_checksum_contents (bfd *abfd, if (contents != NULL) { (*process) (contents, i_shdr.sh_size, arg); - free (free_contents); + _bfd_elf_munmap_section_contents (sec, free_contents); } } diff --git a/bfd/elflink.c b/bfd/elflink.c index 44709c9830c..2991e06fe46 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -4426,10 +4426,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) unsigned int elfsec; unsigned long shlink; - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + if (!_bfd_elf_mmap_section_contents (abfd, s, &dynbuf)) { error_free_dyn: - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); goto error_return; } @@ -4535,7 +4535,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) elf_tdata (abfd)->is_pie = (dyn.d_un.d_val & DF_1_PIE) != 0; } - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); } /* DT_RUNPATH overrides DT_RPATH. Do _NOT_ bfd_release, as that @@ -8282,7 +8282,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd, if (s == NULL || s->size == 0 || (s->flags & SEC_HAS_CONTENTS) == 0) return true; - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + if (!_bfd_elf_mmap_section_contents (abfd, s, &dynbuf)) goto error_return; elfsec = _bfd_elf_section_from_bfd_section (abfd, s); @@ -8328,12 +8328,12 @@ bfd_elf_get_bfd_needed_list (bfd *abfd, } } - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); return true; error_return: - free (dynbuf); + _bfd_elf_munmap_section_contents (s, dynbuf); return false; } diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index efda910d59b..e52ec54e34f 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -148,6 +148,9 @@ #ifndef elf_backend_strtab_flags #define elf_backend_strtab_flags 0 #endif +#ifndef elf_backend_use_mmap +#define elf_backend_use_mmap false +#endif #define bfd_elfNN_bfd_debug_info_start _bfd_void_bfd #define bfd_elfNN_bfd_debug_info_end _bfd_void_bfd @@ -979,7 +982,8 @@ static const struct elf_backend_data elfNN_bed = elf_backend_extern_protected_data, elf_backend_always_renumber_dynsyms, elf_backend_linux_prpsinfo32_ugid16, - elf_backend_linux_prpsinfo64_ugid16 + elf_backend_linux_prpsinfo64_ugid16, + elf_backend_use_mmap }; /* Forward declaration for use when initialising alternative_target field. */ diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 7436158f8b7..7d189bc66d1 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -1566,9 +1566,9 @@ elf_x86_size_or_finish_relative_reloc = elf_section_data (sec)->this_hdr.contents; else { - if (!bfd_malloc_and_get_section (sec->owner, - sec, - &contents)) + if (!_bfd_elf_mmap_section_contents (sec->owner, + sec, + &contents)) info->callbacks->einfo /* xgettext:c-format */ (_("%F%P: %pB: failed to allocate memory for section `%pA'\n"), @@ -3789,7 +3789,7 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd, count = n; for (j = 0; plts[j].name != NULL; j++) - free (plts[j].contents); + _bfd_elf_munmap_section_contents (plts[j].sec, plts[j].contents); free (dynrelbuf); diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index dacf36805cd..0f79d83e99c 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -960,6 +960,7 @@ extern void _bfd_x86_elf_link_report_relative_reloc _bfd_elf_x86_size_relative_relocs #define elf_backend_finish_relative_relocs \ _bfd_elf_x86_finish_relative_relocs +#define elf_backend_use_mmap true #define ELF_P_ALIGN ELF_MINPAGESIZE diff --git a/bfd/libbfd.c b/bfd/libbfd.c index a79c814a0dc..e5147a29d69 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -21,6 +21,7 @@ #include "sysdep.h" #include "bfd.h" +#include "elf-bfd.h" #include "libbfd.h" #include "objalloc.h" @@ -1196,6 +1197,19 @@ _bfd_generic_get_section_contents (bfd *abfd, return false; } +#ifdef USE_MMAP + if (section->mmapped_p + && (section->contents != NULL || location != NULL)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: mapped section %pA has non-NULL buffer"), + abfd, section); + bfd_set_error (bfd_error_invalid_operation); + return false; + } +#endif + sz = bfd_get_section_limit_octets (abfd, section); if (offset + count < count || offset + count > sz @@ -1208,8 +1222,49 @@ _bfd_generic_get_section_contents (bfd *abfd, return false; } - if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 - || bfd_read (location, count, abfd) != count) + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) + return false; + +#ifdef USE_MMAP + if (section->mmapped_p) + { + if (location != 0 + || bfd_get_flavour (abfd) != bfd_target_elf_flavour) + abort (); + + int prot = ((section->reloc_count == 0) + ? PROT_READ : PROT_READ | PROT_WRITE); + + location = bfd_mmap_local + (abfd, count, prot, &elf_section_data (section)->contents_addr, + &elf_section_data (section)->contents_size); + + if (location == NULL) + return false; + + /* Check for iovec not supporting mmap. */ + if (location != MAP_FAILED) + { + section->contents = location; + return true; + } + + /* Malloc the buffer and call bfd_read. */ + location = (bfd_byte *) bfd_malloc (count); + if (location == NULL) + { + if (bfd_get_error () == bfd_error_no_memory) + _bfd_error_handler + /* xgettext:c-format */ + (_("error: %pB(%pA) is too large (%#" PRIx64 " bytes)"), + abfd, section, (uint64_t) count); + return false; + } + section->contents = location; + } +#endif + + if (bfd_read (location, count, abfd) != count) return false; return true; diff --git a/bfd/opncls.c b/bfd/opncls.c index e6337b88e18..5efec37175e 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -164,6 +164,15 @@ static void _bfd_delete_bfd (bfd *abfd) { #ifdef USE_MMAP + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + asection *sec; + for (sec = abfd->sections; sec != NULL; sec = sec->next) + if (sec->mmapped_p) + munmap (elf_section_data (sec)->contents_addr, + elf_section_data (sec)->contents_size); + } + struct bfd_mmapped *mmapped, *next; for (mmapped = abfd->mmapped; mmapped != NULL; mmapped = next) { diff --git a/bfd/section.c b/bfd/section.c index 4eaa460a2a2..778a6f75160 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -422,6 +422,9 @@ CODE_FRAGMENT . {* Nonzero if this section uses RELA relocations, rather than REL. *} . unsigned int use_rela_p:1; . +. {* Nonzero if this section contents are mmapped, rather than malloced. *} +. unsigned int mmapped_p:1; +. . {* Bits used by various backends. The generic code doesn't touch . these fields. *} . @@ -711,8 +714,8 @@ EXTERNAL . {* linker_mark, linker_has_input, gc_mark, decompress_status, *} \ . 0, 0, 1, 0, \ . \ -. {* segment_mark, sec_info_type, use_rela_p, *} \ -. 0, 0, 0, \ +. {* segment_mark, sec_info_type, use_rela_p, mmapped_p, *} \ +. 0, 0, 0, 0, \ . \ . {* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, *} \ . 0, 0, 0, 0, 0, 0, \ @@ -1625,6 +1628,8 @@ DESCRIPTION bool bfd_malloc_and_get_section (bfd *abfd, sec_ptr sec, bfd_byte **buf) { + if (sec->mmapped_p) + abort (); *buf = NULL; return bfd_get_full_section_contents (abfd, sec, buf); }