[PATCH] readelf: use fseeko64 or fseeko if possible

Alan Modra amodra@gmail.com
Thu Nov 17 07:02:16 GMT 2022


On Tue, Nov 15, 2022 at 08:57:17AM -0600, Brett Werling via Binutils wrote:
> Changes readelf to make use first of fseeko64 and then fseeko,
> depending on which of those is available. If neither is available,
> reverts to the previous behavior of using fseek. In all cases, the
> offset argument given is cast accoridngly.
> 
> This is necessary when building readelf for LLP64 systems, where a
> long will only be 32 bits wide. If the elf file in question is >= 2 GiB,
> that is greater than the max long value and therefore fseek will fail
> indicating that the offset is negative. On such systems, making use of
> fseeko64 or fseeko will result in the ability so seek past the 2 GiB
> max long boundary.
> ---
>  binutils/config.in |  6 ++++++
>  binutils/configure |  2 +-
>  binutils/readelf.c | 47 ++++++++++++++++++++++++++++------------------
>  3 files changed, 36 insertions(+), 19 deletions(-)
> 
> diff --git a/binutils/config.in b/binutils/config.in
> index 4d22a80971b..91fe00af777 100644
> --- a/binutils/config.in
> +++ b/binutils/config.in
> @@ -67,6 +67,12 @@
>  /* Define to 1 if you have the <fcntl.h> header file. */
>  #undef HAVE_FCNTL_H
>  
> +/* Define to 1 if you have the `fseeko' function. */
> +#undef HAVE_FSEEKO
> +
> +/* Define to 1 if you have the `fseeko64' function. */
> +#undef HAVE_FSEEKO64
> +
>  /* Define to 1 if you have the `getc_unlocked' function. */
>  #undef HAVE_GETC_UNLOCKED
>  
> diff --git a/binutils/configure b/binutils/configure
> index 6176d699e57..46519a31701 100755
> --- a/binutils/configure
> +++ b/binutils/configure
> @@ -13155,7 +13155,7 @@ $as_echo "#define HAVE_MMAP 1" >>confdefs.h
>  fi
>  rm -f conftest.mmap conftest.txt
>  
> -for ac_func in getc_unlocked mkdtemp mkstemp utimensat utimes
> +for ac_func in getc_unlocked mkdtemp mkstemp utimensat utimes fseeko fseeko64
>  do :
>    as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
>  ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index c8323539a21..3e5e4f29ff2 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -177,6 +177,17 @@
>  #define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *) 0)->MEMBER))
>  #endif
>  
> +#if defined (HAVE_FSEEKO64)
> +#define FSEEK_FUNC fseeko64
> +#define FSEEK_OFF_TYPE off64_t
> +#elif defined (HAVE_FSEEKO)
> +#define FSEEK_FUNC fseeko
> +#define FSEEK_OFF_TYPE off_t
> +#else
> +#define FSEEK_FUNC fseek
> +#define FSEEK_OFF_TYPE long
> +#endif
> +
>  typedef struct elf_section_list
>  {
>    Elf_Internal_Shdr *        hdr;
> @@ -479,7 +490,7 @@ get_data (void *var,
>        return NULL;
>      }
>  
> -  if (fseek (filedata->handle, filedata->archive_file_offset + offset,
> +  if (FSEEK_FUNC (filedata->handle, (FSEEK_OFF_TYPE)filedata->archive_file_offset + offset,
>  	     SEEK_SET))
>      {

There shouldn't be a need for the FSEEK_OFF_TYPE cast.  Casts always
make me question the code, and indeed in this case you have a whole
lot of unsigned long variables and struct fields that will need to be
wider in order to support large archives.  Also, functions like
offset_from_vma will need changing.

>        if (reason)
> @@ -6262,8 +6273,8 @@ the .dynamic section is not the same as the dynamic segment\n"));
>  	  if (segment->p_offset >= filedata->file_size
>  	      || segment->p_filesz > filedata->file_size - segment->p_offset
>  	      || segment->p_filesz - 1 >= (size_t) -2
> -	      || fseek (filedata->handle,
> -			filedata->archive_file_offset + (long) segment->p_offset,
> +	      || FSEEK_FUNC (filedata->handle,
> +			(FSEEK_OFF_TYPE)filedata->archive_file_offset + (long) segment->p_offset,
>  			SEEK_SET))

and the (long) also should go.  I'm happy enough with the patch as-is,
except please remove all those FSEEK_OFF_TYPE casts.  Further fixes
can be done in followup patches.

-- 
Alan Modra
Australia Development Lab, IBM


More information about the Binutils mailing list