mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 01:53:38 +08:00
elf: Use mmap to map in read-only sections
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. Add _bfd_mmap_readonly_persistent and _bfd_mmap_readonly_temporary to mmap in reado-only sections with size >= 4 * page size. 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. * 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_persistent 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_temporary and _bfd_munmap_readonly_temporary instead of _bfd_malloc_and_read 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.
This commit is contained in:
parent
f89ae595dd
commit
9ba56acee5
@ -1962,6 +1962,20 @@ enum bfd_lto_object_type
|
||||
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];
|
||||
};
|
||||
|
||||
struct bfd
|
||||
{
|
||||
/* The filename the application opened the BFD with. */
|
||||
@ -2291,6 +2305,9 @@ struct bfd
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
static inline const char *
|
||||
|
17
bfd/bfd.c
17
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];
|
||||
. };
|
||||
.
|
||||
|
||||
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;
|
||||
.};
|
||||
.
|
||||
|
||||
|
@ -157,7 +157,7 @@ bfd_get_file_window (bfd *abfd,
|
||||
bool writable)
|
||||
{
|
||||
static int ok_to_map = 1;
|
||||
static size_t pagesize;
|
||||
size_t pagesize = _bfd_pagesize;
|
||||
bfd_window_internal *i = windowp->i;
|
||||
bfd_size_type size_to_alloc = size;
|
||||
|
||||
@ -167,12 +167,6 @@ bfd_get_file_window (bfd *abfd,
|
||||
windowp, windowp->data, (unsigned long) windowp->size,
|
||||
windowp->i, writable);
|
||||
|
||||
/* Make sure we know the page size, so we can be friendly to mmap. */
|
||||
if (pagesize == 0)
|
||||
pagesize = getpagesize ();
|
||||
if (pagesize == 0)
|
||||
abort ();
|
||||
|
||||
if (i == NULL)
|
||||
{
|
||||
i = bfd_zmalloc (sizeof (bfd_window_internal));
|
||||
|
@ -494,10 +494,10 @@ cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
|
||||
#ifdef HAVE_MMAP
|
||||
else
|
||||
{
|
||||
static uintptr_t pagesize_m1;
|
||||
uintptr_t pagesize_m1 = _bfd_pagesize_m1;
|
||||
FILE *f;
|
||||
file_ptr pg_offset;
|
||||
bfd_size_type pg_len;
|
||||
size_t pg_len;
|
||||
|
||||
f = bfd_cache_lookup (abfd, CACHE_NO_SEEK_ERROR);
|
||||
if (f == NULL)
|
||||
@ -506,9 +506,6 @@ cache_bmmap (struct bfd *abfd ATTRIBUTE_UNUSED,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pagesize_m1 == 0)
|
||||
pagesize_m1 = getpagesize () - 1;
|
||||
|
||||
/* Align. */
|
||||
pg_offset = offset & ~pagesize_m1;
|
||||
pg_len = (len + (offset - pg_offset) + pagesize_m1) & ~pagesize_m1;
|
||||
|
79
bfd/elf.c
79
bfd/elf.c
@ -289,16 +289,23 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
|
||||
in case the string table is not terminated. */
|
||||
if (shstrtabsize + 1 <= 1
|
||||
|| bfd_seek (abfd, offset, SEEK_SET) != 0
|
||||
|| (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1,
|
||||
shstrtabsize)) == NULL)
|
||||
|| (shstrtab
|
||||
= _bfd_mmap_readonly_persistent (abfd, shstrtabsize)) == 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 = 0;
|
||||
}
|
||||
else
|
||||
shstrtab[shstrtabsize] = '\0';
|
||||
else if (shstrtab[shstrtabsize - 1] != '\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 = shstrtab;
|
||||
}
|
||||
return (char *) shstrtab;
|
||||
@ -1897,6 +1904,8 @@ get_hash_table_data (bfd *abfd, bfd_size_type number,
|
||||
unsigned char *e_data = NULL;
|
||||
bfd_vma *i_data = NULL;
|
||||
bfd_size_type size;
|
||||
void *e_data_addr;
|
||||
size_t e_data_size ATTRIBUTE_UNUSED;
|
||||
|
||||
if (ent_size != 4 && ent_size != 8)
|
||||
return NULL;
|
||||
@ -1918,7 +1927,8 @@ get_hash_table_data (bfd *abfd, bfd_size_type number,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e_data = _bfd_malloc_and_read (abfd, size, size);
|
||||
e_data = _bfd_mmap_readonly_temporary (abfd, size, &e_data_addr,
|
||||
&e_data_size);
|
||||
if (e_data == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -1936,7 +1946,7 @@ get_hash_table_data (bfd *abfd, bfd_size_type number,
|
||||
while (number--)
|
||||
i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size);
|
||||
|
||||
free (e_data);
|
||||
_bfd_munmap_readonly_temporary (e_data_addr, e_data_size);
|
||||
return i_data;
|
||||
}
|
||||
|
||||
@ -1985,6 +1995,10 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
|
||||
size_t verneed_size = 0;
|
||||
size_t extsym_size;
|
||||
const struct elf_backend_data *bed;
|
||||
void *dynbuf_addr = NULL;
|
||||
void *esymbuf_addr = NULL;
|
||||
size_t dynbuf_size = 0;
|
||||
size_t esymbuf_size = 0;
|
||||
|
||||
/* 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) != 0)
|
||||
goto error_return;
|
||||
|
||||
dynbuf = _bfd_malloc_and_read (abfd, phdr->p_filesz, phdr->p_filesz);
|
||||
dynbuf_size = phdr->p_filesz;
|
||||
dynbuf = _bfd_mmap_readonly_temporary (abfd, dynbuf_size,
|
||||
&dynbuf_addr, &dynbuf_size);
|
||||
if (dynbuf == NULL)
|
||||
goto error_return;
|
||||
|
||||
@ -2080,11 +2096,17 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
|
||||
goto error_return;
|
||||
|
||||
/* Dynamic string table must be valid until ABFD is closed. */
|
||||
strbuf = (char *) _bfd_alloc_and_read (abfd, dt_strsz + 1, dt_strsz);
|
||||
strbuf = (char *) _bfd_mmap_readonly_persistent (abfd, dt_strsz);
|
||||
if (strbuf == NULL)
|
||||
goto error_return;
|
||||
/* Since this is a string table, make sure that it is terminated. */
|
||||
strbuf[dt_strsz] = 0;
|
||||
if (strbuf[dt_strsz - 1] != 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;
|
||||
}
|
||||
|
||||
/* 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_Internal_Phdr *phdr,
|
||||
if (filepos == (file_ptr) -1
|
||||
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
|
||||
goto error_return;
|
||||
esymbuf = _bfd_malloc_and_read (abfd, amt, amt);
|
||||
esymbuf_size = amt;
|
||||
esymbuf = _bfd_mmap_readonly_temporary (abfd, esymbuf_size,
|
||||
&esymbuf_addr,
|
||||
&esymbuf_size);
|
||||
if (esymbuf == NULL)
|
||||
goto error_return;
|
||||
|
||||
@ -2303,7 +2328,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
|
||||
goto error_return;
|
||||
|
||||
/* DT_VERSYM info must be valid until ABFD is closed. */
|
||||
versym = _bfd_alloc_and_read (abfd, amt, amt);
|
||||
versym = _bfd_mmap_readonly_persistent (abfd, amt);
|
||||
|
||||
if (dt_verdef)
|
||||
{
|
||||
@ -2315,8 +2340,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
|
||||
goto error_return;
|
||||
|
||||
/* DT_VERDEF info must be valid until ABFD is closed. */
|
||||
verdef = _bfd_alloc_and_read (abfd, verdef_size,
|
||||
verdef_size);
|
||||
verdef = _bfd_mmap_readonly_persistent (abfd, verdef_size);
|
||||
}
|
||||
|
||||
if (dt_verneed)
|
||||
@ -2329,8 +2353,7 @@ _bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
|
||||
goto error_return;
|
||||
|
||||
/* DT_VERNEED info must be valid until ABFD is closed. */
|
||||
verneed = _bfd_alloc_and_read (abfd, verneed_size,
|
||||
verneed_size);
|
||||
verneed = _bfd_mmap_readonly_persistent (abfd, verneed_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) != 0)
|
||||
res = 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 default_imported_symver)
|
||||
bfd_byte *contents = NULL;
|
||||
unsigned int freeidx = 0;
|
||||
size_t amt;
|
||||
void *contents_addr = NULL;
|
||||
size_t contents_size = 0;
|
||||
|
||||
if (elf_dynverref (abfd) != 0 || elf_tdata (abfd)->dt_verneed != NULL)
|
||||
{
|
||||
@ -9449,7 +9474,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
|
||||
|
||||
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
|
||||
goto error_return_verref;
|
||||
contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
|
||||
contents_size = hdr->sh_size;
|
||||
contents = _bfd_mmap_readonly_temporary (abfd, contents_size,
|
||||
&contents_addr,
|
||||
&contents_size);
|
||||
if (contents == NULL)
|
||||
goto error_return_verref;
|
||||
|
||||
@ -9582,8 +9610,9 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
|
||||
elf_tdata (abfd)->cverrefs = i;
|
||||
|
||||
if (contents != elf_tdata (abfd)->dt_verneed)
|
||||
free (contents);
|
||||
_bfd_munmap_readonly_temporary (contents_addr, contents_size);
|
||||
contents = NULL;
|
||||
contents_addr = NULL;
|
||||
}
|
||||
|
||||
if (elf_dynverdef (abfd) != 0 || elf_tdata (abfd)->dt_verdef != NULL)
|
||||
@ -9624,7 +9653,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
|
||||
|
||||
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
|
||||
goto error_return_verdef;
|
||||
contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
|
||||
contents_size = hdr->sh_size;
|
||||
contents = _bfd_mmap_readonly_temporary (abfd, contents_size,
|
||||
&contents_addr,
|
||||
&contents_size);
|
||||
if (contents == NULL)
|
||||
goto error_return_verdef;
|
||||
|
||||
@ -9778,8 +9810,9 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
|
||||
}
|
||||
|
||||
if (contents != elf_tdata (abfd)->dt_verdef)
|
||||
free (contents);
|
||||
_bfd_munmap_readonly_temporary (contents_addr, contents_size);
|
||||
contents = NULL;
|
||||
contents_addr = NULL;
|
||||
}
|
||||
else if (default_imported_symver)
|
||||
{
|
||||
@ -9835,7 +9868,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bool default_imported_symver)
|
||||
error_return:
|
||||
if (contents != elf_tdata (abfd)->dt_verneed
|
||||
&& contents != elf_tdata (abfd)->dt_verdef)
|
||||
free (contents);
|
||||
_bfd_munmap_readonly_temporary (contents_addr, contents_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -549,22 +549,24 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
|
||||
return false;
|
||||
}
|
||||
|
||||
char *unversioned_name = NULL;
|
||||
|
||||
/* We don't put any version information in the dynamic string
|
||||
table. */
|
||||
name = h->root.root.string;
|
||||
p = strchr (name, ELF_VER_CHR);
|
||||
if (p != 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 = 0;
|
||||
{
|
||||
unversioned_name = bfd_malloc (p - name + 1);
|
||||
memcpy (unversioned_name, name, p - name);
|
||||
unversioned_name[p - name] = 0;
|
||||
name = unversioned_name;
|
||||
}
|
||||
|
||||
indx = _bfd_elf_strtab_add (dynstr, name, p != NULL);
|
||||
|
||||
if (p != NULL)
|
||||
*p = ELF_VER_CHR;
|
||||
free (unversioned_name);
|
||||
|
||||
if (indx == (size_t) -1)
|
||||
return false;
|
||||
|
@ -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;
|
||||
|
||||
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 >= 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, bfd_size_type rsize)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#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 = _bfd_malloc_and_read (abfd, rsize, rsize);
|
||||
*map_addr = mem;
|
||||
*map_size = rsize;
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
|
151
bfd/libbfd.c
151
bfd/libbfd.c
@ -1038,6 +1038,141 @@ bfd_get_bits (const void *p, int bits, bool big_p)
|
||||
return data;
|
||||
}
|
||||
|
||||
#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
|
||||
= (struct bfd_mmapped *) mmap (NULL, _bfd_pagesize,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (mmapped == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
mmapped->next = abfd->mmapped;
|
||||
mmapped->max_entry
|
||||
= ((_bfd_pagesize - offsetof (struct bfd_mmapped, entries))
|
||||
/ sizeof (struct bfd_mmapped_entry));
|
||||
mmapped->next_entry = 1;
|
||||
abfd->mmapped = mmapped;
|
||||
*entry = 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 = bfd_get_file_size (abfd);
|
||||
if (filesize != 0 && rsize > filesize)
|
||||
{
|
||||
bfd_set_error (bfd_error_file_truncated);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *mem;
|
||||
ufile_ptr offset = bfd_tell (abfd);
|
||||
mem = 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 >= the minimum mmap section size. */
|
||||
if (rsize < _bfd_minimum_mmap_size)
|
||||
{
|
||||
void *mem = _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 = mem;
|
||||
*map_size = 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 == NULL)
|
||||
return;
|
||||
if (rsize != 0)
|
||||
{
|
||||
if (munmap (ptr, rsize) != 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 >= 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 = bfd_mmap_local (abfd, rsize, PROT_READ, &map_addr, &map_size);
|
||||
if (mem == NULL)
|
||||
return mem;
|
||||
if (mem == MAP_FAILED)
|
||||
return _bfd_alloc_and_read (abfd, rsize, rsize);
|
||||
|
||||
struct bfd_mmapped_entry *entry;
|
||||
unsigned int next_entry;
|
||||
struct bfd_mmapped *mmapped = abfd->mmapped;
|
||||
if (mmapped != NULL
|
||||
&& (next_entry = mmapped->next_entry) < mmapped->max_entry)
|
||||
{
|
||||
entry = &mmapped->entries[next_entry];
|
||||
mmapped->next_entry++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mmapped = bfd_allocate_mmapped_page (abfd, &entry);
|
||||
if (mmapped == NULL)
|
||||
{
|
||||
munmap (map_addr, map_size);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
entry->addr = map_addr;
|
||||
entry->size = map_size;
|
||||
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default implementation */
|
||||
|
||||
bool
|
||||
@ -1326,3 +1461,19 @@ _bfd_generic_init_private_section_data (bfd *ibfd ATTRIBUTE_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 = getpagesize ();
|
||||
if (_bfd_pagesize == 0)
|
||||
abort ();
|
||||
_bfd_pagesize_m1 = _bfd_pagesize - 1;
|
||||
/* The minimum section size to use mmap. */
|
||||
_bfd_minimum_mmap_size = _bfd_pagesize * 4;
|
||||
}
|
||||
|
29
bfd/libbfd.h
29
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;
|
||||
|
||||
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 >= 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, bfd_size_type rsize)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#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 = _bfd_malloc_and_read (abfd, rsize, rsize);
|
||||
*map_addr = mem;
|
||||
*map_size = rsize;
|
||||
return mem;
|
||||
}
|
||||
#endif
|
||||
/* Extracted from libbfd.c. */
|
||||
void *bfd_malloc (bfd_size_type /*size*/) ATTRIBUTE_HIDDEN;
|
||||
|
||||
|
@ -96,7 +96,7 @@ lynx_core_file_p (bfd *abfd)
|
||||
asection *newsect;
|
||||
size_t amt;
|
||||
|
||||
pagesize = getpagesize (); /* Serious cross-target issue here... This
|
||||
pagesize = _bfd_pagesize; /* Serious cross-target issue here... This
|
||||
really needs to come from a system-specific
|
||||
header file. */
|
||||
|
||||
|
12
bfd/opncls.c
12
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 = abfd->mmapped; mmapped != NULL; mmapped = next)
|
||||
{
|
||||
struct bfd_mmapped_entry *entries = mmapped->entries;
|
||||
next = mmapped->next;
|
||||
for (unsigned int i = 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);
|
||||
|
@ -98,6 +98,10 @@
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
#endif
|
||||
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#include "filenames.h"
|
||||
|
||||
#if !HAVE_DECL_FFS
|
||||
|
Loading…
Reference in New Issue
Block a user