From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1039) id 5A9E83847718; Wed, 3 Apr 2024 16:17:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A9E83847718 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1712161051; bh=olfMEGC8ZlyYUIZzbpDZcE67phXdoQq201qSs5l5j9M=; h=From:To:Subject:Date:From; b=wbO70Ldh532nWlE9oIwJF5XxT48YFCVCVDXceghnkVVNaOypyRoXuSqqj88pGr/Q/ LAAtZbGW0K3WQVrptjphNjBsA/+xbSkK6/ZZPO+u97U8vmYqGMmJdUNJvwY9AiNfV/ XAVUDDaTz03ktTo+uVnJW+TRBJTnEZmdPOukoYK4= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: H.J. Lu To: binutils-cvs@sourceware.org Subject: [binutils-gdb] elf: Use mmap to map in read-only sections X-Act-Checkin: binutils-gdb X-Git-Author: H.J. Lu X-Git-Refname: refs/heads/master X-Git-Oldrev: f89ae595dd1f5195dd6e8e57bc2217463c436888 X-Git-Newrev: 9ba56acee518492cfe21434b974c807f52ac7950 Message-Id: <20240403161731.5A9E83847718@sourceware.org> Date: Wed, 3 Apr 2024 16:17:31 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D9ba56acee518= 492cfe21434b974c807f52ac7950 commit 9ba56acee518492cfe21434b974c807f52ac7950 Author: H.J. Lu Date: Thu Feb 29 11:17:01 2024 -0800 elf: Use mmap to map in read-only sections =20 There are many linker input files in LLVM debug build with huge string sections. All these string sections can be treated as read-only. But linker copies all of them into memory which consumes huge amount of memory and slows down linker significantly. =20 Add _bfd_mmap_readonly_persistent and _bfd_mmap_readonly_temporary to mmap in reado-only sections with size >=3D 4 * page size. =20 NB: All string sections in valid ELF inputs must be null terminated. There is no need to terminate it again and string sections are mmapped as read-only. =20 * bfd.c (bfd_mmapped_entry): New. (bfd_mmapped): Likewise. (bfd): Add mmapped. * bfdwin.c (bfd_get_file_window): Use _bfd_pagesize. * cache.c (cache_bmmap): Remove pagesize_m1 and use pagesize_m1 instead. * elf.c (bfd_elf_get_str_section): Call _bfd_mmap_readonly_persistent instead of _bfd_alloc_and_read. Don't terminate the string section again. (get_hash_table_data): Call _bfd_mmap_readonly_temporary and _bfd_munmap_readonly_temporary instead of _bfd_malloc_and_read and free. (_bfd_elf_get_dynamic_symbols): Call _bfd_mmap_readonly_persist= ent instead of _bfd_alloc_and_read. Don't terminate the string section again. Call _bfd_mmap_readonly_temporary and _bfd_munmap_readonly_temporary instead of _bfd_malloc_and_read and free. (_bfd_elf_slurp_version_tables): Call _bfd_mmap_readonly_tempor= ary and _bfd_munmap_readonly_temporary instead of _bfd_malloc_and_r= ead and free. * elflink.c (bfd_elf_link_record_dynamic_symbol): Use bfd_malloc to get the unversioned symbol. * libbfd-in.h (_bfd_pagesize): New. (_bfd_pagesize_m1): Likewise. (_bfd_minimum_mmap_size): Likewise. (_bfd_mmap_readonly_persistent): Likewise. (_bfd_mmap_readonly_temporary): Likewise. (_bfd_munmap_readonly_temporary): Likewise. * libbfd.c (bfd_allocate_mmapped_page): New. (_bfd_mmap_readonly_temporary): Likewise. (_bfd_munmap_readonly_temporary): Likewise. (_bfd_mmap_readonly_persistent): Likewise. (_bfd_pagesize): Likewise. (_bfd_pagesize_m1): Likewise. (_bfd_minimum_mmap_size): Likewise. (bfd_init_pagesize): Likewise. * lynx-core.c (lynx_core_file_p): Use _bfd_pagesize. * opncls.c (_bfd_delete_bfd): Munmap tracked mmapped memories. * sysdep.h (MAP_ANONYMOUS): New. Define if undefined. * bfd-in2.h: Regenerated. * libbfd.h: Likewise. Diff: --- bfd/bfd-in2.h | 17 +++++++ bfd/bfd.c | 17 +++++++ bfd/bfdwin.c | 8 +-- bfd/cache.c | 7 +-- bfd/elf.c | 79 ++++++++++++++++++++--------- bfd/elflink.c | 16 +++--- bfd/libbfd-in.h | 29 +++++++++++ bfd/libbfd.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ bfd/libbfd.h | 29 +++++++++++ bfd/lynx-core.c | 2 +- bfd/opncls.c | 12 +++++ bfd/sysdep.h | 4 ++ 12 files changed, 328 insertions(+), 43 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index b332f5adad1..8b86607ec1d 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1962,6 +1962,20 @@ enum bfd_lto_object_type lto_fat_ir_object /* A fat LTO IR object. */ }; =20 +struct bfd_mmapped_entry + { + void *addr; + size_t size; + }; + +struct bfd_mmapped + { + struct bfd_mmapped *next; + unsigned int max_entry; + unsigned int next_entry; + struct bfd_mmapped_entry entries[1]; + }; + struct bfd { /* The filename the application opened the BFD with. */ @@ -2291,6 +2305,9 @@ struct bfd =20 /* For input BFDs, the build ID, if the object has one. */ const struct bfd_build_id *build_id; + + /* For input BFDs, mmapped entries. */ + struct bfd_mmapped *mmapped; }; =20 static inline const char * diff --git a/bfd/bfd.c b/bfd/bfd.c index e579788e42f..8fd86f68e6e 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -82,6 +82,20 @@ EXTERNAL . lto_fat_ir_object {* A fat LTO IR object. *} . }; . +.struct bfd_mmapped_entry +. { +. void *addr; +. size_t size; +. }; +. +.struct bfd_mmapped +. { +. struct bfd_mmapped *next; +. unsigned int max_entry; +. unsigned int next_entry; +. struct bfd_mmapped_entry entries[1]; +. }; +. =20 CODE_FRAGMENT .struct bfd @@ -414,6 +428,9 @@ CODE_FRAGMENT . . {* For input BFDs, the build ID, if the object has one. *} . const struct bfd_build_id *build_id; +. +. {* For input BFDs, mmapped entries. *} +. struct bfd_mmapped *mmapped; .}; . =20 diff --git a/bfd/bfdwin.c b/bfd/bfdwin.c index 2919c71b3cb..73e44635bcb 100644 --- a/bfd/bfdwin.c +++ b/bfd/bfdwin.c @@ -157,7 +157,7 @@ bfd_get_file_window (bfd *abfd, bool writable) { static int ok_to_map =3D 1; - static size_t pagesize; + size_t pagesize =3D _bfd_pagesize; bfd_window_internal *i =3D windowp->i; bfd_size_type size_to_alloc =3D size; =20 @@ -167,12 +167,6 @@ bfd_get_file_window (bfd *abfd, windowp, windowp->data, (unsigned long) windowp->size, windowp->i, writable); =20 - /* Make sure we know the page size, so we can be friendly to mmap. */ - if (pagesize =3D=3D 0) - pagesize =3D getpagesize (); - if (pagesize =3D=3D 0) - abort (); - if (i =3D=3D NULL) { i =3D bfd_zmalloc (sizeof (bfd_window_internal)); diff --git a/bfd/cache.c b/bfd/cache.c index d0e7be293a5..0f994c74239 100644 --- a/bfd/cache.c +++ b/bfd/cache.c @@ -494,10 +494,10 @@ cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, #ifdef HAVE_MMAP else { - static uintptr_t pagesize_m1; + uintptr_t pagesize_m1 =3D _bfd_pagesize_m1; FILE *f; file_ptr pg_offset; - bfd_size_type pg_len; + size_t pg_len; =20 f =3D bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR); if (f =3D=3D NULL) @@ -506,9 +506,6 @@ cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED, return ret; } =20 - if (pagesize_m1 =3D=3D 0) - pagesize_m1 =3D getpagesize () - 1; - /* Align. */ pg_offset =3D offset & ~pagesize_m1; pg_len =3D (len + (offset - pg_offset) + pagesize_m1) & ~pagesize_m1; diff --git a/bfd/elf.c b/bfd/elf.c index f7717547fad..34100d81355 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -289,16 +289,23 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shin= dex) in case the string table is not terminated. */ if (shstrtabsize + 1 <=3D 1 || bfd_seek (abfd, offset, SEEK_SET) !=3D 0 - || (shstrtab =3D _bfd_alloc_and_read (abfd, shstrtabsize + 1, - shstrtabsize)) =3D=3D NULL) + || (shstrtab + =3D _bfd_mmap_readonly_persistent (abfd, shstrtabsize)) =3D=3D NULL) { /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for the string table over and over. */ i_shdrp[shindex]->sh_size =3D 0; } - else - shstrtab[shstrtabsize] =3D '\0'; + else if (shstrtab[shstrtabsize - 1] !=3D '\0') + { + /* It is an error if a string table isn't terminated. */ + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): string table is corrupt"), + abfd, i_shdrp[shindex]->bfd_section); + return NULL; + } i_shdrp[shindex]->contents =3D shstrtab; } return (char *) shstrtab; @@ -1897,6 +1904,8 @@ get_hash_table_data (bfd *abfd, bfd_size_type number, unsigned char *e_data =3D NULL; bfd_vma *i_data =3D NULL; bfd_size_type size; + void *e_data_addr; + size_t e_data_size ATTRIBUTE_UNUSED; =20 if (ent_size !=3D 4 && ent_size !=3D 8) return NULL; @@ -1918,7 +1927,8 @@ get_hash_table_data (bfd *abfd, bfd_size_type number, return NULL; } =20 - e_data =3D _bfd_malloc_and_read (abfd, size, size); + e_data =3D _bfd_mmap_readonly_temporary (abfd, size, &e_data_addr, + &e_data_size); if (e_data =3D=3D NULL) return NULL; =20 @@ -1936,7 +1946,7 @@ get_hash_table_data (bfd *abfd, bfd_size_type number, while (number--) i_data[number] =3D bfd_get_64 (abfd, e_data + number * ent_size); =20 - free (e_data); + _bfd_munmap_readonly_temporary (e_data_addr, e_data_size); return i_data; } =20 @@ -1985,6 +1995,10 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Interna= l_Phdr *phdr, size_t verneed_size =3D 0; size_t extsym_size; const struct elf_backend_data *bed; + void *dynbuf_addr =3D NULL; + void *esymbuf_addr =3D NULL; + size_t dynbuf_size =3D 0; + size_t esymbuf_size =3D 0; =20 /* Return TRUE if symbol table is bad. */ if (elf_bad_symtab (abfd)) @@ -2002,7 +2016,9 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal= _Phdr *phdr, if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) !=3D 0) goto error_return; =20 - dynbuf =3D _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz); + dynbuf_size =3D phdr->p_filesz; + dynbuf =3D _bfd_mmap_readonly_temporary (abfd, dynbuf_size, + &dynbuf_addr, &dynbuf_size); if (dynbuf =3D=3D NULL) goto error_return; =20 @@ -2080,11 +2096,17 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Intern= al_Phdr *phdr, goto error_return; =20 /* Dynamic string table must be valid until ABFD is closed. */ - strbuf =3D (char *) _bfd_alloc_and_read (abfd, dt_strsz + 1, dt_strsz); + strbuf =3D (char *) _bfd_mmap_readonly_persistent (abfd, dt_strsz); if (strbuf =3D=3D NULL) goto error_return; - /* Since this is a string table, make sure that it is terminated. */ - strbuf[dt_strsz] =3D 0; + if (strbuf[dt_strsz - 1] !=3D 0) + { + /* It is an error if a string table is't terminated. */ + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: DT_STRTAB table is corrupt"), abfd); + goto error_return; + } =20 /* Get the real symbol count from DT_HASH or DT_GNU_HASH. Prefer DT_HASH since it is simpler than DT_GNU_HASH. */ @@ -2259,7 +2281,10 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Interna= l_Phdr *phdr, if (filepos =3D=3D (file_ptr) -1 || bfd_seek (abfd, filepos, SEEK_SET) !=3D 0) goto error_return; - esymbuf =3D _bfd_malloc_and_read (abfd, amt, amt); + esymbuf_size =3D amt; + esymbuf =3D _bfd_mmap_readonly_temporary (abfd, esymbuf_size, + &esymbuf_addr, + &esymbuf_size); if (esymbuf =3D=3D NULL) goto error_return; =20 @@ -2303,7 +2328,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal= _Phdr *phdr, goto error_return; =20 /* DT_VERSYM info must be valid until ABFD is closed. */ - versym =3D _bfd_alloc_and_read (abfd, amt, amt); + versym =3D _bfd_mmap_readonly_persistent (abfd, amt); =20 if (dt_verdef) { @@ -2315,8 +2340,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal= _Phdr *phdr, goto error_return; =20 /* DT_VERDEF info must be valid until ABFD is closed. */ - verdef =3D _bfd_alloc_and_read (abfd, verdef_size, - verdef_size); + verdef =3D _bfd_mmap_readonly_persistent (abfd, verdef_size); } =20 if (dt_verneed) @@ -2329,8 +2353,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal= _Phdr *phdr, goto error_return; =20 /* DT_VERNEED info must be valid until ABFD is closed. */ - verneed =3D _bfd_alloc_and_read (abfd, verneed_size, - verneed_size); + verneed =3D _bfd_mmap_readonly_persistent (abfd, verneed_size); } } =20 @@ -2353,8 +2376,8 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal= _Phdr *phdr, /* Restore file position for elf_object_p. */ if (bfd_seek (abfd, saved_filepos, SEEK_SET) !=3D 0) res =3D false; - free (dynbuf); - free (esymbuf); + _bfd_munmap_readonly_temporary (dynbuf_addr, dynbuf_size); + _bfd_munmap_readonly_temporary (esymbuf_addr, esymbuf_size); free (gnubuckets); free (gnuchains); free (mipsxlat); @@ -9413,6 +9436,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) bfd_byte *contents =3D NULL; unsigned int freeidx =3D 0; size_t amt; + void *contents_addr =3D NULL; + size_t contents_size =3D 0; =20 if (elf_dynverref (abfd) !=3D 0 || elf_tdata (abfd)->dt_verneed !=3D NUL= L) { @@ -9449,7 +9474,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defau= lt_imported_symver) =20 if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) goto error_return_verref; - contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + contents_size =3D hdr->sh_size; + contents =3D _bfd_mmap_readonly_temporary (abfd, contents_size, + &contents_addr, + &contents_size); if (contents =3D=3D NULL) goto error_return_verref; =20 @@ -9582,8 +9610,9 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) elf_tdata (abfd)->cverrefs =3D i; =20 if (contents !=3D elf_tdata (abfd)->dt_verneed) - free (contents); + _bfd_munmap_readonly_temporary (contents_addr, contents_size); contents =3D NULL; + contents_addr =3D NULL; } =20 if (elf_dynverdef (abfd) !=3D 0 || elf_tdata (abfd)->dt_verdef !=3D NULL) @@ -9624,7 +9653,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defau= lt_imported_symver) =20 if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) !=3D 0) goto error_return_verdef; - contents =3D _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + contents_size =3D hdr->sh_size; + contents =3D _bfd_mmap_readonly_temporary (abfd, contents_size, + &contents_addr, + &contents_size); if (contents =3D=3D NULL) goto error_return_verdef; =20 @@ -9778,8 +9810,9 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) } =20 if (contents !=3D elf_tdata (abfd)->dt_verdef) - free (contents); + _bfd_munmap_readonly_temporary (contents_addr, contents_size); contents =3D NULL; + contents_addr =3D NULL; } else if (default_imported_symver) { @@ -9835,7 +9868,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool defaul= t_imported_symver) error_return: if (contents !=3D elf_tdata (abfd)->dt_verneed && contents !=3D elf_tdata (abfd)->dt_verdef) - free (contents); + _bfd_munmap_readonly_temporary (contents_addr, contents_size); return false; } =0C diff --git a/bfd/elflink.c b/bfd/elflink.c index e9cef470333..44709c9830c 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -549,22 +549,24 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_i= nfo *info, return false; } =20 + char *unversioned_name =3D NULL; + /* We don't put any version information in the dynamic string table. */ name =3D h->root.root.string; p =3D strchr (name, ELF_VER_CHR); if (p !=3D NULL) - /* We know that the p points into writable memory. In fact, - there are only a few symbols that have read-only names, being - those like _GLOBAL_OFFSET_TABLE_ that are created specially - by the backends. Most symbols will have names pointing into - an ELF string table read from a file, or to objalloc memory. */ - *p =3D 0; + { + unversioned_name =3D bfd_malloc (p - name + 1); + memcpy (unversioned_name, name, p - name); + unversioned_name[p - name] =3D 0; + name =3D unversioned_name; + } =20 indx =3D _bfd_elf_strtab_add (dynstr, name, p !=3D NULL); =20 if (p !=3D NULL) - *p =3D ELF_VER_CHR; + free (unversioned_name); =20 if (indx =3D=3D (size_t) -1) return false; diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index b8b2ce7ba09..c5a79cf932c 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -851,6 +851,10 @@ extern struct bfd_link_info *_bfd_get_link_info (bfd *) extern bool _bfd_link_keep_memory (struct bfd_link_info *) ATTRIBUTE_HIDDEN; =20 +extern uintptr_t _bfd_pagesize ATTRIBUTE_HIDDEN; +extern uintptr_t _bfd_pagesize_m1 ATTRIBUTE_HIDDEN; +extern uintptr_t _bfd_minimum_mmap_size ATTRIBUTE_HIDDEN; + #if GCC_VERSION >=3D 7000 #define _bfd_mul_overflow(a, b, res) __builtin_mul_overflow (a, b, res) #else @@ -888,6 +892,19 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, b= fd_size_type rsize) return NULL; } =20 +#ifdef USE_MMAP +extern void *_bfd_mmap_readonly_persistent + (bfd *, size_t) ATTRIBUTE_HIDDEN; +extern void *_bfd_mmap_readonly_temporary + (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; +extern void _bfd_munmap_readonly_temporary + (void *, size_t) ATTRIBUTE_HIDDEN; +#else +#define _bfd_mmap_readonly_persistent(abfd, rsize) \ + _bfd_alloc_and_read (abfd, rsize, rsize) +#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr) +#endif + static inline void * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { @@ -910,3 +927,15 @@ _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, = bfd_size_type rsize) } return NULL; } + +#ifndef USE_MMAP +static inline void * +_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) +{ + void *mem =3D _bfd_malloc_and_read (abfd, rsize, rsize); + *map_addr =3D mem; + *map_size =3D rsize; + return mem; +} +#endif diff --git a/bfd/libbfd.c b/bfd/libbfd.c index f8d148c9677..a79c814a0dc 100644 --- a/bfd/libbfd.c +++ b/bfd/libbfd.c @@ -1038,6 +1038,141 @@ bfd_get_bits (const void *p, int bits, bool big_p) return data; } =0C +#ifdef USE_MMAP +/* Allocate a page to track mmapped memory and return the page and + the first entry. Return NULL if mmap fails. */ + +static struct bfd_mmapped * +bfd_allocate_mmapped_page (bfd *abfd, struct bfd_mmapped_entry **entry) +{ + struct bfd_mmapped * mmapped + =3D (struct bfd_mmapped *) mmap (NULL, _bfd_pagesize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (mmapped =3D=3D MAP_FAILED) + return NULL; + + mmapped->next =3D abfd->mmapped; + mmapped->max_entry + =3D ((_bfd_pagesize - offsetof (struct bfd_mmapped, entries)) + / sizeof (struct bfd_mmapped_entry)); + mmapped->next_entry =3D 1; + abfd->mmapped =3D mmapped; + *entry =3D mmapped->entries; + return mmapped; +} + +/* Mmap a memory region of RSIZE bytes with PROT at the current offset. + Return mmap address and size in MAP_ADDR and MAP_SIZE. Return NULL + on invalid input and MAP_FAILED for mmap failure. */ + +static void * +bfd_mmap_local (bfd *abfd, size_t rsize, int prot, void **map_addr, + size_t *map_size) +{ + if (!_bfd_constant_p (rsize)) + { + ufile_ptr filesize =3D bfd_get_file_size (abfd); + if (filesize !=3D 0 && rsize > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + } + + void *mem; + ufile_ptr offset =3D bfd_tell (abfd); + mem =3D bfd_mmap (abfd, NULL, rsize, prot, MAP_PRIVATE, offset, + map_addr, map_size); + return mem; +} + +/* Mmap a readonly memory region of RSIZE bytes at the current offset. + Return mmap address and size in MAP_ADDR and MAP_SIZE. Return NULL + on invalid input and MAP_FAILED for mmap failure. */ + +void * +_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) +{ + /* Use mmap only if section size >=3D the minimum mmap section size. */ + if (rsize < _bfd_minimum_mmap_size) + { + void *mem =3D _bfd_malloc_and_read (abfd, rsize, rsize); + /* NB: Set *MAP_ADDR to MEM and *MAP_SIZE to 0 to indicate that + _bfd_malloc_and_read is called. */ + *map_addr =3D mem; + *map_size =3D 0; + return mem; + } + + return bfd_mmap_local (abfd, rsize, PROT_READ, map_addr, map_size); +} + +/* Munmap RSIZE bytes at PTR. */ + +void +_bfd_munmap_readonly_temporary (void *ptr, size_t rsize) +{ + /* NB: Since _bfd_munmap_readonly_temporary is called like free, PTR + may be NULL. Otherwise, PTR and RSIZE must be valid. If RSIZE is + 0, _bfd_malloc_and_read is called. */ + if (ptr =3D=3D NULL) + return; + if (rsize !=3D 0) + { + if (munmap (ptr, rsize) !=3D 0) + abort (); + } + else + free (ptr); +} + +/* Mmap a readonly memory region of RSIZE bytes at the current offset. + Return NULL on invalid input or mmap failure. */ + +void * +_bfd_mmap_readonly_persistent (bfd *abfd, size_t rsize) +{ + /* Use mmap only if section size >=3D the minimum mmap section size. */ + if (rsize < _bfd_minimum_mmap_size) + return _bfd_alloc_and_read (abfd, rsize, rsize); + + void *mem, *map_addr; + size_t map_size; + mem =3D bfd_mmap_local (abfd, rsize, PROT_READ, &map_addr, &map_size); + if (mem =3D=3D NULL) + return mem; + if (mem =3D=3D MAP_FAILED) + return _bfd_alloc_and_read (abfd, rsize, rsize); + + struct bfd_mmapped_entry *entry; + unsigned int next_entry; + struct bfd_mmapped *mmapped =3D abfd->mmapped; + if (mmapped !=3D NULL + && (next_entry =3D mmapped->next_entry) < mmapped->max_entry) + { + entry =3D &mmapped->entries[next_entry]; + mmapped->next_entry++; + } + else + { + mmapped =3D bfd_allocate_mmapped_page (abfd, &entry); + if (mmapped =3D=3D NULL) + { + munmap (map_addr, map_size); + return NULL; + } + } + + entry->addr =3D map_addr; + entry->size =3D map_size; + + return mem; +} +#endif + /* Default implementation */ =20 bool @@ -1326,3 +1461,19 @@ _bfd_generic_init_private_section_data (bfd *ibfd AT= TRIBUTE_UNUSED, { return true; } + +uintptr_t _bfd_pagesize; +uintptr_t _bfd_pagesize_m1; +uintptr_t _bfd_minimum_mmap_size; + +__attribute__ ((unused, constructor)) +static void +bfd_init_pagesize (void) +{ + _bfd_pagesize =3D getpagesize (); + if (_bfd_pagesize =3D=3D 0) + abort (); + _bfd_pagesize_m1 =3D _bfd_pagesize - 1; + /* The minimum section size to use mmap. */ + _bfd_minimum_mmap_size =3D _bfd_pagesize * 4; +} diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 7de23a50d18..0caf0f39e61 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -857,6 +857,10 @@ extern struct bfd_link_info *_bfd_get_link_info (bfd *) extern bool _bfd_link_keep_memory (struct bfd_link_info *) ATTRIBUTE_HIDDEN; =20 +extern uintptr_t _bfd_pagesize ATTRIBUTE_HIDDEN; +extern uintptr_t _bfd_pagesize_m1 ATTRIBUTE_HIDDEN; +extern uintptr_t _bfd_minimum_mmap_size ATTRIBUTE_HIDDEN; + #if GCC_VERSION >=3D 7000 #define _bfd_mul_overflow(a, b, res) __builtin_mul_overflow (a, b, res) #else @@ -894,6 +898,19 @@ _bfd_alloc_and_read (bfd *abfd, bfd_size_type asize, b= fd_size_type rsize) return NULL; } =20 +#ifdef USE_MMAP +extern void *_bfd_mmap_readonly_persistent + (bfd *, size_t) ATTRIBUTE_HIDDEN; +extern void *_bfd_mmap_readonly_temporary + (bfd *, size_t, void **, size_t *) ATTRIBUTE_HIDDEN; +extern void _bfd_munmap_readonly_temporary + (void *, size_t) ATTRIBUTE_HIDDEN; +#else +#define _bfd_mmap_readonly_persistent(abfd, rsize) \ + _bfd_alloc_and_read (abfd, rsize, rsize) +#define _bfd_munmap_readonly_temporary(ptr, rsize) free (ptr) +#endif + static inline void * _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, bfd_size_type rsize) { @@ -916,6 +933,18 @@ _bfd_malloc_and_read (bfd *abfd, bfd_size_type asize, = bfd_size_type rsize) } return NULL; } + +#ifndef USE_MMAP +static inline void * +_bfd_mmap_readonly_temporary (bfd *abfd, size_t rsize, void **map_addr, + size_t *map_size) +{ + void *mem =3D _bfd_malloc_and_read (abfd, rsize, rsize); + *map_addr =3D mem; + *map_size =3D rsize; + return mem; +} +#endif /* Extracted from libbfd.c. */ void *bfd_malloc (bfd_size_type /*size*/) ATTRIBUTE_HIDDEN; =20 diff --git a/bfd/lynx-core.c b/bfd/lynx-core.c index 44d94ad8745..9ec5a0d2028 100644 --- a/bfd/lynx-core.c +++ b/bfd/lynx-core.c @@ -96,7 +96,7 @@ lynx_core_file_p (bfd *abfd) asection *newsect; size_t amt; =20 - pagesize =3D getpagesize (); /* Serious cross-target issue here... This + pagesize =3D _bfd_pagesize; /* Serious cross-target issue here... This really needs to come from a system-specific header file. */ =20 diff --git a/bfd/opncls.c b/bfd/opncls.c index c764d204831..e6337b88e18 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -163,6 +163,18 @@ _bfd_new_bfd_contained_in (bfd *obfd) static void _bfd_delete_bfd (bfd *abfd) { +#ifdef USE_MMAP + struct bfd_mmapped *mmapped, *next; + for (mmapped =3D abfd->mmapped; mmapped !=3D NULL; mmapped =3D next) + { + struct bfd_mmapped_entry *entries =3D mmapped->entries; + next =3D mmapped->next; + for (unsigned int i =3D 0; i < mmapped->next_entry; i++) + munmap (entries[i].addr, entries[i].size); + munmap (mmapped, _bfd_pagesize); + } +#endif + /* Give the target _bfd_free_cached_info a chance to free memory. */ if (abfd->memory && abfd->xvec) bfd_free_cached_info (abfd); diff --git a/bfd/sysdep.h b/bfd/sysdep.h index b907bc26a09..173f5804df3 100644 --- a/bfd/sysdep.h +++ b/bfd/sysdep.h @@ -98,6 +98,10 @@ #define MAP_FAILED ((void *) -1) #endif =20 +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + #include "filenames.h" =20 #if !HAVE_DECL_FFS