From b03202e32c8235997b3485b0b4655926ad97a1cc Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 19 Feb 2020 13:14:28 +1030 Subject: [PATCH] bfd_get_size cache We have calls to bfd_get_size when swapping in ELF section headers. Since object files can have a large number of sections, it's worth caching the file size rather than making lots of stat system calls. * bfd.c (struct bfd): Move format and direction to other bitfields. Add "size". * bfdio.c (bfd_get_size): Cache size when not writing file. * opncls.c (bfd_get_debug_link_info_1): Allow for bfd_get_size returning zero, ie. unknown. (bfd_get_alt_debug_link_info): Likewise. * bfd-in2.h: Regenerate. --- bfd/ChangeLog | 10 ++++++++++ bfd/bfd-in2.h | 19 ++++++++++++------- bfd/bfd.c | 19 ++++++++++++------- bfd/bfdio.c | 23 +++++++++++++++++++---- bfd/opncls.c | 8 ++++++-- 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index fe2ffd341a0..58dbb567f2f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2020-02-19 Alan Modra + + * bfd.c (struct bfd): Move format and direction to other + bitfields. Add "size". + * bfdio.c (bfd_get_size): Cache size when not writing file. + * opncls.c (bfd_get_debug_link_info_1): Allow for bfd_get_size + returning zero, ie. unknown. + (bfd_get_alt_debug_link_info): Likewise. + * bfd-in2.h: Regenerate. + 2020-02-19 Alan Modra * coffgen.c (_bfd_coff_get_external_symbols): Don't call diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 6b30f5fbd80..2d56fdad41d 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -6497,12 +6497,6 @@ struct bfd /* A unique identifier of the BFD */ unsigned int id; - /* The format which belongs to the BFD. (object, core, etc.) */ - ENUM_BITFIELD (bfd_format) format : 3; - - /* The direction with which the BFD was opened. */ - ENUM_BITFIELD (bfd_direction) direction : 2; - /* Format_specific flags. */ flagword flags; @@ -6606,6 +6600,12 @@ struct bfd | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \ | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON) + /* The format which belongs to the BFD. (object, core, etc.) */ + ENUM_BITFIELD (bfd_format) format : 3; + + /* The direction with which the BFD was opened. */ + ENUM_BITFIELD (bfd_direction) direction : 2; + /* Is the file descriptor being cached? That is, can it be closed as needed, and re-opened when accessed later? */ unsigned int cacheable : 1; @@ -6695,7 +6695,7 @@ struct bfd /* Symbol table for output BFD (with symcount entries). Also used by the linker to cache input BFD symbols. */ - struct bfd_symbol **outsymbols; + struct bfd_symbol **outsymbols; /* Used for input and output. */ unsigned int symcount; @@ -6706,6 +6706,11 @@ struct bfd /* Pointer to structure which contains architecture information. */ const struct bfd_arch_info *arch_info; + /* Cached length of file for bfd_get_size. 0 until bfd_get_size is + called, 1 if stat returns an error or the file size is too large to + return in ufile_ptr. Both 0 and 1 should be treated as "unknown". */ + ufile_ptr size; + /* Stuff only useful for archives. */ void *arelt_data; struct bfd *my_archive; /* The containing archive BFD. */ diff --git a/bfd/bfd.c b/bfd/bfd.c index 574cebd8de2..463f94bb945 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -85,12 +85,6 @@ CODE_FRAGMENT . {* A unique identifier of the BFD *} . unsigned int id; . -. {* The format which belongs to the BFD. (object, core, etc.) *} -. ENUM_BITFIELD (bfd_format) format : 3; -. -. {* The direction with which the BFD was opened. *} -. ENUM_BITFIELD (bfd_direction) direction : 2; -. . {* Format_specific flags. *} . flagword flags; . @@ -194,6 +188,12 @@ CODE_FRAGMENT . | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \ . | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON) . +. {* The format which belongs to the BFD. (object, core, etc.) *} +. ENUM_BITFIELD (bfd_format) format : 3; +. +. {* The direction with which the BFD was opened. *} +. ENUM_BITFIELD (bfd_direction) direction : 2; +. . {* Is the file descriptor being cached? That is, can it be closed as . needed, and re-opened when accessed later? *} . unsigned int cacheable : 1; @@ -283,7 +283,7 @@ CODE_FRAGMENT . . {* Symbol table for output BFD (with symcount entries). . Also used by the linker to cache input BFD symbols. *} -. struct bfd_symbol **outsymbols; +. struct bfd_symbol **outsymbols; . . {* Used for input and output. *} . unsigned int symcount; @@ -294,6 +294,11 @@ CODE_FRAGMENT . {* Pointer to structure which contains architecture information. *} . const struct bfd_arch_info *arch_info; . +. {* Cached length of file for bfd_get_size. 0 until bfd_get_size is +. called, 1 if stat returns an error or the file size is too large to +. return in ufile_ptr. Both 0 and 1 should be treated as "unknown". *} +. ufile_ptr size; +. . {* Stuff only useful for archives. *} . void *arelt_data; . struct bfd *my_archive; {* The containing archive BFD. *} diff --git a/bfd/bfdio.c b/bfd/bfdio.c index fd81b93cd9f..49e09585264 100644 --- a/bfd/bfdio.c +++ b/bfd/bfdio.c @@ -415,17 +415,32 @@ DESCRIPTION of space for the 15 bazillon byte table it is about to read. This function at least allows us to answer the question, "is the size reasonable?". + + A return value of zero indicates the file size is unknown. */ ufile_ptr bfd_get_size (bfd *abfd) { - struct stat buf; + /* A size of 0 means we haven't yet called bfd_stat. A size of 1 + means we have a cached value of 0, ie. unknown. */ + if (abfd->size <= 1 || bfd_write_p (abfd)) + { + struct stat buf; - if (bfd_stat (abfd, &buf) != 0) - return 0; + if (abfd->size == 1 && !bfd_write_p (abfd)) + return 0; - return buf.st_size; + if (bfd_stat (abfd, &buf) != 0 + || buf.st_size == 0 + || buf.st_size - (ufile_ptr) buf.st_size != 0) + { + abfd->size = 1; + return 0; + } + abfd->size = buf.st_size; + } + return abfd->size; } /* diff --git a/bfd/opncls.c b/bfd/opncls.c index a03ad51c8fa..796202d31a5 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -1209,6 +1209,7 @@ bfd_get_debug_link_info_1 (bfd *abfd, void *crc32_out) unsigned int crc_offset; char *name; bfd_size_type size; + ufile_ptr file_size; BFD_ASSERT (abfd); BFD_ASSERT (crc32_out); @@ -1219,9 +1220,10 @@ bfd_get_debug_link_info_1 (bfd *abfd, void *crc32_out) return NULL; size = bfd_section_size (sect); + file_size = bfd_get_size (abfd); /* PR 22794: Make sure that the section has a reasonable size. */ - if (size < 8 || size >= bfd_get_size (abfd)) + if (size < 8 || (file_size != 0 && size >= file_size)) return NULL; if (!bfd_malloc_and_get_section (abfd, sect, &contents)) @@ -1298,6 +1300,7 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len, unsigned int buildid_offset; char *name; bfd_size_type size; + ufile_ptr file_size; BFD_ASSERT (abfd); BFD_ASSERT (buildid_len); @@ -1309,7 +1312,8 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len, return NULL; size = bfd_section_size (sect); - if (size < 8 || size >= bfd_get_size (abfd)) + file_size = bfd_get_size (abfd); + if (size < 8 || (file_size != 0 && size >= file_size)) return NULL; if (!bfd_malloc_and_get_section (abfd, sect, & contents)) -- 2.30.2