[PATCH 1/6] elf: Batch program-header reads in _dl_map_segments (oversight fix)

H.J. Lu hjl.tools@gmail.com
Fri May 15 01:59:31 GMT 2026


On Thu, May 14, 2026 at 3:20 AM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> The fix for BZ 26577 ("Fix stack overflow in _dl_map_object_from_fd
> with large e_phnum") removed the alloca for the program-header table
> and introduced a streaming iterator (dl_pt_load_iterator) so segments
> could be walked without staging the entire table on the stack.
>
> That patch batched reads correctly in _dl_map_object_scan_phdrs (the
> first walk, which collects PT_DYNAMIC/PT_TLS/PT_GNU_* metadata), but
> overlooked the second walk in _dl_map_segments:
> _dl_pt_load_iterator_next issued one pread64 per program header to
> find the next PT_LOAD entry.  For an object with N program headers
> this added N redundant per-phdr syscalls on every dlopen / loader
> startup -- regardless of whether the table had already been read by
> open_verify into struct filebuf.
>
> Unify both walks behind a single batched helper,
> _dl_pt_load_iterator_phdr_at:
>
>   - When the program header table fits in the bytes already read by
>     open_verify into fbp->buf (the common case for nearly all shared
>     objects), all phdr accesses are served from that buffer with no
>     syscall at all.
>
>   - Otherwise, up to FILEBUF_SIZE / sizeof(ElfW(Phdr)) program headers
>     are read into fbp->buf with a single pread64; subsequent indices
>     in the same window hit the buffer.
>
> Both _dl_map_object_scan_phdrs and _dl_pt_load_iterator_next now go
> through this helper, eliminating the separate batching logic in
> _dl_map_object_scan_phdrs.  struct filebuf moves from dl-load.c to
> dl-load.h so the inline iterator in dl-map-segments.h can reach
> fbp->buf.
>
> The filebuf size is also bumped to ensure the cached fast path
> triggers for all observed binaries.  A survey of an Ubuntu 24.04
> installation (scanning /usr) shows:
>
>     Candidate files       : 465834
>     ELF files inspected   : 11624
>     glibc-linked binaries : 10164
>     Minimum e_phnum       : 5
>     Maximum e_phnum       : 14
>     Average e_phnum       : 11.37
>     Median  e_phnum       : 11.0
>
> shows e_phnum capped at 14 (for instance gcc's cc1, lto1, perl,
> and gdb).  The previous FILEBUF_SIZE of 832 on 64-bit fit only 13
> program headers after the ELF header (64 + 13*56 = 792), so 64-bit
> binaries with 14 phdrs missed the cached path.  FILEBUF_SIZE is
> bumped from 512/832 to 640/1024 (32-bit / 64-bit) -- enough for at
> least 16 program headers on either ABI, leaving headroom over the
> observed maximum.
>
> For a typical shared library where open_verify's initial read covers
> the program header table, this reduces _dl_map_segments from N
> preads to 0.  For a worst-case e_phnum that does not fit in fbp->buf,
> reads drop from N to ceil(N / phdrs_per_buf) -- the same cost
> _dl_map_object_scan_phdrs already pays.
>
> No functional change.  Tested on x86_64-linux-gnu, aaarch64-linux-gnu,
> and i686-linux-gnu.
> ---
>  elf/dl-load.c | 285 +++++++++++++++++++++-----------------------------
>  elf/dl-load.h | 100 ++++++++++++++----
>  2 files changed, 201 insertions(+), 184 deletions(-)
>
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index f6e391a4689..d20e49d526a 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -34,31 +34,6 @@
>  #include <gnu/lib-names.h>
>  #include <dl-tunables.h>
>
> -/* Type for the buffer we put the ELF header and hopefully the program
> -   header.  This buffer does not really have to be too large.  In most
> -   cases the program header follows the ELF header directly.  If this
> -   is not the case all bets are off and we can make the header
> -   arbitrarily large and still won't get it read.  This means the only
> -   question is how large are the ELF and program header combined.  The
> -   ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
> -   bytes long.  Each program header entry is again 32 and 56 bytes
> -   long respectively.  I.e., even with a file which has 10 program
> -   header entries we only have to read 372B/624B respectively.  Add to
> -   this a bit of margin for program notes and reading 512B and 832B
> -   for 32-bit and 64-bit files respectively is enough.  If this
> -   heuristic should really fail for some file the code in
> -   `_dl_map_object_from_fd' knows how to recover.  */
> -struct filebuf
> -{
> -  ssize_t len;
> -#if __WORDSIZE == 32
> -# define FILEBUF_SIZE 512
> -#else
> -# define FILEBUF_SIZE 832
> -#endif
> -  char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
> -};
> -
>  #include "dynamic-link.h"
>  #include "get-dynamic-info.h"
>  #include <abi-tag.h>
> @@ -936,13 +911,18 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
>  }
>
>  /* Initialize the PT_LOAD iterator IT for reading program headers from FD
> -   at file offset PHOFF with PHNUM entries.  Zeros all precomputed fields
> -   so the caller's scan loop can fill them in.  */
> +   at file offset PHOFF with PHNUM entries.  FBP is used as scratch space
> +   for batched program-header reads; if open_verify's initial read into
> +   FBP->buf already covers the whole phdr table, the iterator runs
> +   entirely from that buffer without any further pread.  Zeros all
> +   precomputed fields so the caller's scan loop can fill them in.  */
>  static void
> -_dl_pt_load_iterator_init (struct dl_pt_load_iterator *it,
> -                          int fd, ElfW(Off) phoff, uint16_t phnum)
> +_dl_pt_load_iterator_init (struct dl_pt_load_iterator *it, int fd,
> +                          struct filebuf *fbp, ElfW(Off) phoff,
> +                          uint16_t phnum)
>  {
>    it->fd = fd;
> +  it->fbp = fbp;
>    it->phoff = phoff;
>    it->phnum = phnum;
>    it->idx = 0;
> @@ -952,161 +932,134 @@ _dl_pt_load_iterator_init (struct dl_pt_load_iterator *it,
>    it->first_mapstart = 0;
>    it->last_mapstart = 0;
>    it->last_allocend = 0;
> +  it->cached = (phoff + (ElfW(Off)) phnum * sizeof (ElfW(Phdr))
> +               <= (ElfW(Off)) fbp->len);
> +  it->buf_base = 0;
> +  it->buf_count = it->cached ? phnum : 0;
>  }
>
> -/* Scan all program headers from IT->fd in chunks, using FBP->buf as a
> -   scratch buffer.  Fills in IT's precomputed PT_LOAD metadata and collects
> -   segment attributes into L.  Returns NULL on success, or an error message
> -   string on failure; sets *ERRVALP to errno for I/O errors, 0 otherwise.  */
> +/* Scan all program headers from IT->fd, using the iterator's filebuf as a
> +   scratch buffer for batched reads (skipped entirely if open_verify
> +   already read the whole table).  Fills in IT's precomputed PT_LOAD
> +   metadata and collects segment attributes into L.  Returns NULL on
> +   success, or an error message string on failure; sets *ERRVALP to errno
> +   for I/O errors, 0 otherwise.  */
>  static const char *
>  _dl_map_object_scan_phdrs (struct dl_pt_load_iterator *it,
> -                          struct filebuf *fbp, struct link_map *l, int mode,
> +                          struct link_map *l, int mode,
>                            unsigned int *stack_flagsp, bool *has_holesp,
>                            bool *empty_dynamicp, int *errvalp)
>  {
>    ElfW(Addr) prev_mapend = 0;
> -  const ElfW(Half) phdrs_per_buf = sizeof (fbp->buf) / sizeof (ElfW(Phdr));
> -  ElfW(Phdr) *chunk = (ElfW(Phdr) *) fbp->buf;
>    struct dl_machine_phdr_info minfo;
>    elf_machine_phdr_info_init (&minfo);
>
> -  /* Fast path: if all program headers fit within the bytes already read
> -     into fbp->buf by open_verify, iterate them directly without any
> -     additional pread syscalls.  The slow path falls through to pread
> -     in chunks (which overwrites fbp->buf, but the caller has already
> -     saved the ELF header to a local copy).  */
> -  const bool cached
> -    = (it->phoff + (ElfW(Off)) it->phnum * sizeof (ElfW(Phdr))
> -       <= (ElfW(Off)) fbp->len);
> -
> -  for (ElfW(Half) base = 0; base < it->phnum; )
> +  for (ElfW(Half) i = 0; i < it->phnum; i++)
>      {
> -      ElfW(Half) batch;
> -      const ElfW(Phdr) *batch_ptr;
> -
> -      if (__glibc_likely (cached))
> +      const ElfW(Phdr) *ph = _dl_pt_load_iterator_phdr_at (it, i);
> +      if (__glibc_unlikely (ph == NULL))
>         {
> -         batch = it->phnum;
> -         batch_ptr = (const ElfW(Phdr) *) (fbp->buf + it->phoff);
> +         *errvalp = errno;
> +         return N_("cannot read file data");
>         }
> -      else
> +      elf_machine_phdr_collect (&minfo, ph);
> +      switch (ph->p_type)
>         {
> -         batch = it->phnum - base;
> -         if (batch > phdrs_per_buf)
> -           batch = phdrs_per_buf;
> -         size_t bytes = (size_t) batch * sizeof (ElfW(Phdr));
> -         ElfW(Off) off = it->phoff + (ElfW(Off)) base * sizeof (ElfW(Phdr));
> -         if (__pread64_nocancel (it->fd, chunk, bytes, off) != bytes)
> -           {
> -             *errvalp = errno;
> -             return N_("cannot read file data");
> -           }
> -         batch_ptr = chunk;
> -       }
> -
> -      for (ElfW(Half) i = 0; i < batch; i++)
> -       {
> -         const ElfW(Phdr) *ph = &batch_ptr[i];
> -         elf_machine_phdr_collect (&minfo, ph);
> -         switch (ph->p_type)
> -           {
> -           case PT_LOAD:
> +       case PT_LOAD:
> +         {
> +           if (__glibc_unlikely (((ph->p_vaddr - ph->p_offset)
> +                                  & (it->pagesize - 1)) != 0))
>               {
> -               if (__glibc_unlikely (((ph->p_vaddr - ph->p_offset)
> -                                      & (it->pagesize - 1)) != 0))
> -                 {
> -                   *errvalp = 0;
> -                   return N_("ELF load command address/offset not page-aligned");
> -                 }
> -               ElfW(Addr) mapstart = ALIGN_DOWN (ph->p_vaddr, it->pagesize);
> -               ElfW(Addr) mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz,
> -                                             it->pagesize);
> -               ElfW(Off)  mapoff = ALIGN_DOWN (ph->p_offset, it->pagesize);
> -               int prot = pf_to_prot (ph->p_flags);
> -               if (powerof2 (ph->p_align) && ph->p_align > it->p_align_max)
> -                 it->p_align_max = ph->p_align;
> -               it->p_align_max = _dl_map_segment_align (&(struct loadcmd) {
> -                                                          .mapstart = mapstart,
> -                                                          .mapend   = mapend,
> -                                                          .mapoff   = mapoff,
> -                                                          .prot     = prot },
> -                                                        it->p_align_max);
> -               if (it->nloadcmds > 0 && prev_mapend != mapstart)
> -                 *has_holesp = true;
> -               prev_mapend = mapend;
> -               if (it->nloadcmds == 0)
> -                 it->first_mapstart = mapstart;
> -               it->last_mapstart = mapstart;
> -               it->last_allocend = ph->p_vaddr + ph->p_memsz;
> -               it->nloadcmds++;
> +               *errvalp = 0;
> +               return N_("ELF load command address/offset not page-aligned");
>               }
> -             break;
> +           ElfW(Addr) mapstart = ALIGN_DOWN (ph->p_vaddr, it->pagesize);
> +           ElfW(Addr) mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz,
> +                                         it->pagesize);
> +           ElfW(Off)  mapoff = ALIGN_DOWN (ph->p_offset, it->pagesize);
> +           int prot = pf_to_prot (ph->p_flags);
> +           if (powerof2 (ph->p_align) && ph->p_align > it->p_align_max)
> +             it->p_align_max = ph->p_align;
> +           it->p_align_max = _dl_map_segment_align (&(struct loadcmd) {
> +                                                      .mapstart = mapstart,
> +                                                      .mapend   = mapend,
> +                                                      .mapoff   = mapoff,
> +                                                      .prot     = prot },
> +                                                    it->p_align_max);
> +           if (it->nloadcmds > 0 && prev_mapend != mapstart)
> +             *has_holesp = true;
> +           prev_mapend = mapend;
> +           if (it->nloadcmds == 0)
> +             it->first_mapstart = mapstart;
> +           it->last_mapstart = mapstart;
> +           it->last_allocend = ph->p_vaddr + ph->p_memsz;
> +           it->nloadcmds++;
> +         }
> +         break;
>
> -           /* These entries tell us where to find things once the file's
> -              segments are mapped in.  We record the addresses it says
> -              verbatim, and later correct for the run-time load address.  */
> -           case PT_DYNAMIC:
> -             if (ph->p_filesz == 0)
> -               *empty_dynamicp = true; /* Usually separate debuginfo.  */
> -             else
> -               {
> -                 /* Debuginfo only files from "objcopy --only-keep-debug"
> -                    contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
> -                    such a segment to avoid a crash later.  */
> -                 l->l_ld = (void *) ph->p_vaddr;
> -                 l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
> -                 l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> -               }
> -             break;
> -
> -           case PT_PHDR:
> -             l->l_phdr = (void *) ph->p_vaddr;
> -             break;
> -
> -           case PT_TLS:
> -             if (ph->p_memsz == 0)
> -               /* Nothing to do for an empty segment.  */
> -               break;
> -
> -             l->l_tls_blocksize = ph->p_memsz;
> -             l->l_tls_align = ph->p_align;
> -             if (ph->p_align == 0)
> -               l->l_tls_firstbyte_offset = 0;
> -             else
> -               l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1);
> -             l->l_tls_initimage_size = ph->p_filesz;
> -             /* Since we don't know the load address yet only store the
> -                offset.  We will adjust it later.  */
> -             l->l_tls_initimage = (void *) ph->p_vaddr;
> -
> -             /* l->l_tls_modid is assigned below, once there is no
> -                possibility for failure.  */
> -
> -             if (l->l_type != lt_library
> -                 && GL(dl_tls_dtv_slotinfo_list) == NULL)
> -               {
> -#ifdef SHARED
> -                 /* We are loading the executable itself when the dynamic
> -                    linker was executed directly.  The setup will happen
> -                    later.  */
> -                 assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
> -#else
> -                 assert (false && "TLS not initialized in static application");
> -#endif
> -               }
> -             break;
> -
> -           case PT_GNU_STACK:
> -             *stack_flagsp = pf_to_prot (ph->p_flags);
> -             break;
> -
> -           case PT_GNU_RELRO:
> -             l->l_relro_addr = ph->p_vaddr;
> -             l->l_relro_size = ph->p_memsz;
> -             break;
> +       /* These entries tell us where to find things once the file's
> +          segments are mapped in.  We record the addresses it says
> +          verbatim, and later correct for the run-time load address.  */
> +       case PT_DYNAMIC:
> +         if (ph->p_filesz == 0)
> +           *empty_dynamicp = true; /* Usually separate debuginfo.  */
> +         else
> +           {
> +             /* Debuginfo only files from "objcopy --only-keep-debug"
> +                contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
> +                such a segment to avoid a crash later.  */
> +             l->l_ld = (void *) ph->p_vaddr;
> +             l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
> +             l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
>             }
> +         break;
> +
> +       case PT_PHDR:
> +         l->l_phdr = (void *) ph->p_vaddr;
> +         break;
> +
> +       case PT_TLS:
> +         if (ph->p_memsz == 0)
> +           /* Nothing to do for an empty segment.  */
> +           break;
> +
> +         l->l_tls_blocksize = ph->p_memsz;
> +         l->l_tls_align = ph->p_align;
> +         if (ph->p_align == 0)
> +           l->l_tls_firstbyte_offset = 0;
> +         else
> +           l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1);
> +         l->l_tls_initimage_size = ph->p_filesz;
> +         /* Since we don't know the load address yet only store the
> +            offset.  We will adjust it later.  */
> +         l->l_tls_initimage = (void *) ph->p_vaddr;
> +
> +         /* l->l_tls_modid is assigned below, once there is no
> +            possibility for failure.  */
> +
> +         if (l->l_type != lt_library
> +             && GL(dl_tls_dtv_slotinfo_list) == NULL)
> +           {
> +#ifdef SHARED
> +             /* We are loading the executable itself when the dynamic
> +                linker was executed directly.  The setup will happen
> +                later.  */
> +             assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
> +#else
> +             assert (false && "TLS not initialized in static application");
> +#endif
> +           }
> +         break;
> +
> +       case PT_GNU_STACK:
> +         *stack_flagsp = pf_to_prot (ph->p_flags);
> +         break;
> +
> +       case PT_GNU_RELRO:
> +         l->l_relro_addr = ph->p_vaddr;
> +         l->l_relro_size = ph->p_memsz;
> +         break;
>         }
> -      base += batch;
>      }
>
>    if (__glibc_unlikely (elf_machine_reject_phdr_p (&minfo, l, it->fd)))
> @@ -1275,10 +1228,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
>      bool has_holes;
>      bool empty_dynamic = false;
>
> -    _dl_pt_load_iterator_init (&it, fd, header.e_phoff, l->l_phnum);
> +    _dl_pt_load_iterator_init (&it, fd, fbp, header.e_phoff, l->l_phnum);
>      has_holes = false;
>
> -    errstring = _dl_map_object_scan_phdrs (&it, fbp, l, mode, &stack_flags,
> +    errstring = _dl_map_object_scan_phdrs (&it, l, mode, &stack_flags,
>                                            &has_holes, &empty_dynamic, &errval);
>      if (__glibc_unlikely (errstring != NULL))
>        goto lose;
> diff --git a/elf/dl-load.h b/elf/dl-load.h
> index e58028038c9..80ae5db4b3d 100644
> --- a/elf/dl-load.h
> +++ b/elf/dl-load.h
> @@ -21,12 +21,41 @@
>  #define _DL_LOAD_H     1
>
>  #include <link.h>
> +#include <stddef.h>
>  #include <sys/mman.h>
> +#include <sys/types.h>
>  #include <libc-pointer-arith.h>
>  #include <stackinfo.h>
>  #include <not-cancel.h>
>
>
> +/* Type for the buffer we put the ELF header and hopefully the program
> +   header.  This buffer does not really have to be too large.  In most
> +   cases the program header follows the ELF header directly.  If this
> +   is not the case all bets are off and we can make the header
> +   arbitrarily large and still won't get it read.  This means the only
> +   question is how large are the ELF and program header combined.  The
> +   ELF header for 32-bit files is 52 bytes long and for 64-bit files
> +   64 bytes long.  Each program header entry is 32 and 56 bytes long
> +   respectively.
> +
> +   Size for at least 16 entries (with a little margin for program notes)
> +   needs 52 + 16*32 = 564 bytes on 32-bit and 64 + 16*56 = 960 bytes on
> +   64-bit; round up to 640 and  1024 respectively.  If this heuristic
> +   should still fail for some file the code in
> +   `_dl_map_object_from_fd' knows how to recover.  */
> +struct filebuf
> +{
> +  ssize_t len;
> +#if __WORDSIZE == 32
> +# define FILEBUF_SIZE 640
> +#else
> +# define FILEBUF_SIZE 1024
> +#endif
> +  char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
> +};
> +
> +
>  /* On some systems, no flag bits are given to specify file mapping.  */
>  #ifndef MAP_FILE
>  # define MAP_FILE       0
> @@ -84,28 +113,65 @@ struct loadcmd
>  };
>
>
> -/* Iterator for PT_LOAD program header segments.  It should be initialized
> -   by _dl_pt_load_iterator_init once, then _dl_pt_load_iterator_next
> -   repeatedly to walk each PT_LOAD segment without storing them all.
> -   Segments are re-read one at a time via pread so that no large stack
> -   buffer is needed for the program header table.  */
> +/* Iterator for program header segments.  Initialize with
> +   _dl_pt_load_iterator_init, then either walk PT_LOAD segments via
> +   _dl_pt_load_iterator_next or do random access via
> +   _dl_pt_load_iterator_phdr_at.  A scratch buffer (fbp->buf) is used to
> +   batch-read program headers; if the entire program header table was
> +   already loaded by open_verify's initial read no pread is issued.  */
>  struct dl_pt_load_iterator
>  {
>    int fd;                       /* File descriptor for pread.  */
> +  struct filebuf *fbp;          /* Scratch buffer for batched phdr reads.  */
>    ElfW(Off) phoff;              /* Program header table file offset.  */
>    ElfW(Half) phnum;             /* Total number of program headers.  */
>    ElfW(Half) idx;               /* Index of next header to read.  */
> +  ElfW(Half) buf_base;          /* Index of phdr at start of fbp->buf
> +                                   (chunked mode only).  */
> +  ElfW(Half) buf_count;         /* Number of phdrs currently in fbp->buf.  */
> +  bool cached;                  /* True iff entire phdr table is already
> +                                   resident in fbp->buf from open_verify.  */
>    ElfW(Addr) p_align_max;       /* Maximum p_align over all PT_LOAD segments.  */
>    ElfW(Addr) pagesize;          /* System page size (GLRO(dl_pagesize)).  */
>
> -  /* Fields below are precomputed by _dl_pt_load_iterator_init and
> -     are intended for use by _dl_map_segments.  */
> +  /* Fields below are precomputed by _dl_map_object_scan_phdrs and are
> +     intended for use by _dl_map_segments.  */
>    ElfW(Addr) first_mapstart;    /* mapstart of the first PT_LOAD segment.  */
>    ElfW(Addr) last_mapstart;     /* mapstart of the last PT_LOAD segment.  */
>    ElfW(Addr) last_allocend;     /* allocend of the last PT_LOAD segment.  */
>    size_t nloadcmds;             /* Number of PT_LOAD segments found.  */
>  };
>
> +/* Return a pointer to the program header at INDEX.  If the entire phdr
> +   table is already cached in fbp->buf (from open_verify), it is served
> +   directly with no syscall; otherwise a batch of up to FILEBUF_SIZE /
> +   sizeof(ElfW(Phdr)) entries is read into fbp->buf via a single pread.
> +   Subsequent calls within the same batch hit the buffer.  Returns NULL on
> +   read failure (errno set by pread).  */
> +static __always_inline const ElfW(Phdr) *
> +_dl_pt_load_iterator_phdr_at (struct dl_pt_load_iterator *it, ElfW(Half) idx)
> +{
> +  if (__glibc_likely (it->cached))
> +    return (const ElfW(Phdr) *) (it->fbp->buf + it->phoff) + idx;
> +
> +  if (idx < it->buf_base || idx >= it->buf_base + it->buf_count)
> +    {
> +      const ElfW(Half) phdrs_per_buf
> +       = sizeof (it->fbp->buf) / sizeof (ElfW(Phdr));
> +      ElfW(Half) batch = it->phnum - idx;
> +      if (batch > phdrs_per_buf)
> +       batch = phdrs_per_buf;
> +      size_t bytes = (size_t) batch * sizeof (ElfW(Phdr));
> +      ElfW(Off) off = it->phoff + (ElfW(Off)) idx * sizeof (ElfW(Phdr));
> +      if (__pread64_nocancel (it->fd, it->fbp->buf, bytes, off)
> +         != (ssize_t) bytes)
> +       return NULL;
> +      it->buf_base = idx;
> +      it->buf_count = batch;
> +    }
> +  return (const ElfW(Phdr) *) it->fbp->buf + (idx - it->buf_base);
> +}
> +
>  /* Advance iterator IT to the next PT_LOAD segment and fill C with its
>     decoded load command.  Returns true when a segment was found, false
>     when the end of the program header table has been reached or a read
> @@ -115,21 +181,19 @@ _dl_pt_load_iterator_next (struct dl_pt_load_iterator *it, struct loadcmd *c)
>  {
>    while (it->idx < it->phnum)
>      {
> -      ElfW(Phdr) ph;
> -      ElfW(Off) off = it->phoff + (ElfW(Off)) it->idx * sizeof ph;
> +      const ElfW(Phdr) *ph = _dl_pt_load_iterator_phdr_at (it, it->idx);
>        it->idx++;
> -      if (__pread64_nocancel (it->fd, &ph, sizeof ph, off)
> -         != (ssize_t) sizeof ph)
> +      if (__glibc_unlikely (ph == NULL))
>          return false;
> -      if (ph.p_type != PT_LOAD)
> +      if (ph->p_type != PT_LOAD)
>          continue;
>
> -      c->mapstart = ALIGN_DOWN (ph.p_vaddr, it->pagesize);
> -      c->mapend   = ALIGN_UP (ph.p_vaddr + ph.p_filesz, it->pagesize);
> -      c->dataend  = ph.p_vaddr + ph.p_filesz;
> -      c->allocend = ph.p_vaddr + ph.p_memsz;
> -      c->mapoff   = ALIGN_DOWN (ph.p_offset, it->pagesize);
> -      c->prot     = pf_to_prot (ph.p_flags);
> +      c->mapstart = ALIGN_DOWN (ph->p_vaddr, it->pagesize);
> +      c->mapend   = ALIGN_UP (ph->p_vaddr + ph->p_filesz, it->pagesize);
> +      c->dataend  = ph->p_vaddr + ph->p_filesz;
> +      c->allocend = ph->p_vaddr + ph->p_memsz;
> +      c->mapoff   = ALIGN_DOWN (ph->p_offset, it->pagesize);
> +      c->prot     = pf_to_prot (ph->p_flags);
>        c->mapalign = it->p_align_max;
>        return true;
>      }
> --
> 2.43.0
>

LGTM.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>

Thanks.

-- 
H.J.


More information about the Libc-alpha mailing list