Hi Heather,

On Tue, 2023-10-10 at 15:42 +0200, Mark Wielaard wrote:
> From: Heather McIntyre <h...@rice.edu>
> 
>       * libelf/elf32_getchdr.c: Move getchdr function to
>       elf32_getchdr.h.
>       * libelf/elf32_getchdr.h: New file.
>       Add macro to create getchdr_wrlock.

That is clever. I do wonder if the new file should be named
elf_getchdr.h (since it isn't really directly 32 or 64 bit, but
included (indirectly) from one of them. This is a nitpick though.

You do have to include it in the noinst_HEADERS:

diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index aabce43e..3402863e 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -41,7 +41,7 @@ include_HEADERS = libelf.h gelf.h nlist.h
 
 noinst_HEADERS = abstract.h common.h exttypes.h gelf_xlate.h libelfP.h \
                 version_xlate.h gnuhash_xlate.h note_xlate.h dl-hash.h \
-                chdr_xlate.h
+                chdr_xlate.h elf32_getchdr.h
 
 if INSTALL_ELFH
 include_HEADERS += elf.h

Otherwise it won't be included in a dist (make distcheck would show
that as an issue).

>       * libelf/elf32_updatenull.c: Change call from getchdr to
>       getchdr_wrlock.
>       * libelf/elf_getdata.c: Add elf_getdata_wrlock.
>       * libelf/libelfP.h: Add internal function declarations.
> 
> Signed-off-by: Heather S. McIntyre <h...@rice.edu>
> Signed-off-by: Mark Wielaard <m...@klomp.org>
> ---
>  libelf/elf32_getchdr.c    | 46 +++--------------------------
>  libelf/elf32_getchdr.h    | 61 +++++++++++++++++++++++++++++++++++++++
>  libelf/elf32_updatenull.c |  2 +-
>  libelf/elf_getdata.c      | 14 +++++++++
>  libelf/libelfP.h          |  4 +++
>  5 files changed, 84 insertions(+), 43 deletions(-)
>  create mode 100644 libelf/elf32_getchdr.h
> 
> diff --git a/libelf/elf32_getchdr.c b/libelf/elf32_getchdr.c
> index 982a614c..41591300 100644
> --- a/libelf/elf32_getchdr.c
> +++ b/libelf/elf32_getchdr.c
> @@ -38,46 +38,8 @@
>  # define LIBELFBITS 32
>  #endif
>  
> +#define ELF_WRLOCK_HELD 1
> +#include "elf32_getchdr.h"
>  
> -ElfW2(LIBELFBITS,Chdr) *
> -elfw2(LIBELFBITS,getchdr) (Elf_Scn *scn)
> -{
> -  ElfW2(LIBELFBITS,Shdr) *shdr = elfw2(LIBELFBITS,getshdr) (scn);
> -  if (shdr == NULL)
> -    return NULL;
> -
> -  /* Must have SHF_COMPRESSED flag set.  Allocated or no bits sections
> -     can never be compressed.  */
> -  if ((shdr->sh_flags & SHF_ALLOC) != 0)
> -    {
> -      __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
> -      return NULL;
> -    }
> -
> -  if (shdr->sh_type == SHT_NULL
> -      || shdr->sh_type == SHT_NOBITS)
> -    {
> -      __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
> -      return NULL;
> -    }
> -
> -  if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
> -    {
> -      __libelf_seterrno (ELF_E_NOT_COMPRESSED);
> -      return NULL;
> -    }
> -
> -  /* This makes sure the data is in the correct format, so we don't
> -     need to swap fields. */
> -  Elf_Data *d  = elf_getdata (scn, NULL);
> -  if (d == NULL)
> -    return NULL;
> -
> -  if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
> -    {
> -      __libelf_seterrno (ELF_E_INVALID_DATA);
> -      return NULL;
> -    }
> -
> -  return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
> -}
> +#define ELF_WRLOCK_HELD 0
> +#include "elf32_getchdr.h"
> \ No newline at end of file
> diff --git a/libelf/elf32_getchdr.h b/libelf/elf32_getchdr.h
> new file mode 100644
> index 00000000..04d47e7a
> --- /dev/null
> +++ b/libelf/elf32_getchdr.h
> @@ -0,0 +1,61 @@
> +#undef ADD_ROUTINE_PREFIX
> +#undef ADD_ROUTINE_SUFFIX
> +
> +#if ELF_WRLOCK_HELD
> +#define CONCAT(x,y) x##y
> +#define ADD_ROUTINE_PREFIX(y) CONCAT(__,y)
> +#define ADD_ROUTINE_SUFFIX(x) x ## _wrlock
> +#define INTERNAL internal_function
> +#else
> +#define ADD_ROUTINE_PREFIX(y) y
> +#define ADD_ROUTINE_SUFFIX(x) x
> +#define INTERNAL
> +#endif
> +
> +ElfW2(LIBELFBITS,Chdr) *
> +INTERNAL
> +ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, ADD_ROUTINE_SUFFIX(getchdr))) (Elf_Scn 
> *scn)
> +{
> +
> +  ElfW2(LIBELFBITS,Shdr) *shdr = ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, 
> ADD_ROUTINE_SUFFIX(getshdr)))(scn);
> +
> +  if (shdr == NULL)
> +    return NULL;
> +
> +  /* Must have SHF_COMPRESSED flag set.  Allocated or no bits sections
> +     can never be compressed.  */
> +  if ((shdr->sh_flags & SHF_ALLOC) != 0)
> +    {
> +      __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
> +      return NULL;
> +    }
> +
> +  if (shdr->sh_type == SHT_NULL
> +      || shdr->sh_type == SHT_NOBITS)
> +    {
> +      __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
> +      return NULL;
> +    }
> +
> +  if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
> +    {
> +      __libelf_seterrno (ELF_E_NOT_COMPRESSED);
> +      return NULL;
> +    }
> +
> +  /* This makes sure the data is in the correct format, so we don't
> +     need to swap fields. */
> +  Elf_Data *d  = ADD_ROUTINE_PREFIX(ADD_ROUTINE_SUFFIX(elf_getdata)) (scn, 
> NULL);
> +  if (d == NULL)
> +    return NULL;
> +
> +  if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
> +    {
> +      __libelf_seterrno (ELF_E_INVALID_DATA);
> +      return NULL;
> +    }
> +
> +  return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
> +}

It is interesting the general version and the version that is called
when the lock are held are totally separate functions. As far as I can
see that works out fine here.

Just surprising because in most other functions that have a wrlock
variant the general version takes a lock and then calls the wrlock
variant.

> +#undef INTERNAL
> +#undef ELF_WRLOCK_HELD
> \ No newline at end of file
> diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
> index c5d26b00..3594e8ba 100644
> --- a/libelf/elf32_updatenull.c
> +++ b/libelf/elf32_updatenull.c
> @@ -407,7 +407,7 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int 
> *change_bop, size_t shnum)
>                 else
>                   {
>                     ElfW2(LIBELFBITS,Chdr) *chdr;
> -                   chdr = elfw2(LIBELFBITS,getchdr) (scn);
> +                   chdr = __elfw2(LIBELFBITS,getchdr_wrlock) (scn);
>                     if (unlikely (chdr == NULL))
>                       return -1;
>                     sh_size = chdr->ch_size;

OK, so this is the only caller of the new getchdr_wrlock variants.

> diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
> index 5ebd270f..7c3ac043 100644
> --- a/libelf/elf_getdata.c
> +++ b/libelf/elf_getdata.c
> @@ -582,4 +582,18 @@ elf_getdata (Elf_Scn *scn, Elf_Data *data)
>  
>    return result;
>  }
> +
> +Elf_Data *
> +internal_function
> +__elf_getdata_wrlock (Elf_Scn *scn, Elf_Data *data)
> +{
> +  Elf_Data *result;
> +
> +  if (scn == NULL)
> +    return NULL;
> +
> +  result = __elf_getdata_rdlock (scn, data);
> +
> +  return result;
> +}
>  INTDEF(elf_getdata)

Right. So now the getchdr_wrlock variants can call elf_getdata.
This is good. But I have been tinkering with trying to get rid of the
elf_getdata call from elf[32|64]_getchdr. It can result in a lot of
work (copying all of the compressed data) just to get the header. But
that is a work in progress (and would also change elf_compress a bit).

> diff --git a/libelf/libelfP.h b/libelf/libelfP.h
> index 96476064..ed061abb 100644
> --- a/libelf/libelfP.h
> +++ b/libelf/libelfP.h
> @@ -514,6 +514,8 @@ extern Elf32_Shdr *__elf32_getshdr_rdlock (Elf_Scn 
> *__scn) internal_function;
>  extern Elf64_Shdr *__elf64_getshdr_rdlock (Elf_Scn *__scn) internal_function;
>  extern Elf32_Shdr *__elf32_getshdr_wrlock (Elf_Scn *__scn) internal_function;
>  extern Elf64_Shdr *__elf64_getshdr_wrlock (Elf_Scn *__scn) internal_function;
> +extern Elf32_Chdr *__elf32_getchdr_wrlock (Elf_Scn *__scn) internal_function;
> +extern Elf64_Chdr *__elf64_getchdr_wrlock (Elf_Scn *__scn) internal_function;
>  extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index)
>       attribute_hidden;
>  extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn)
> @@ -523,6 +525,8 @@ extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, 
> Elf_Data *__data)
>       attribute_hidden;
>  extern Elf_Data *__elf_getdata_rdlock (Elf_Scn *__scn, Elf_Data *__data)
>       internal_function;
> +extern Elf_Data *__elf_getdata_wrlock (Elf_Scn *__scn, Elf_Data *__data)
> +     internal_function;
>  extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data)
>       attribute_hidden;
>  /* Should be called to setup first section data element if

Looks good with that noinstall_HEADERS fix.

Cheers,

Mark

Reply via email to