[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