git: 31a440a0e9a2 - main - rtld: Simplify walking program headers

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 14 Jan 2026 17:10:50 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=31a440a0e9a26fee109ed753e3493c72b9dc05e9

commit 31a440a0e9a26fee109ed753e3493c72b9dc05e9
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-01-14 17:10:33 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-01-14 17:10:33 +0000

    rtld: Simplify walking program headers
    
    Store phnum in Obj_Entry instead of phsize and use that to simplify
    the terminate expressions when iterating over program headers.
    
    Reviewed by:    kib
    Obtained from:  CheriBSD
    Sponsored by:   AFRL, DARPA
    Differential Revision:  https://reviews.freebsd.org/D54710
---
 libexec/rtld-elf/map_object.c      |  2 +-
 libexec/rtld-elf/powerpc/reloc.c   |  4 +---
 libexec/rtld-elf/powerpc64/reloc.c |  4 +---
 libexec/rtld-elf/rtld.c            | 18 ++++++++----------
 libexec/rtld-elf/rtld.h            |  2 +-
 5 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 5e5774c0b017..6c6f0c9289b9 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -318,7 +318,7 @@ map_object(int fd, const char *path, const struct stat *sb, bool ismain)
 		    phsize);
 		obj->phdr_alloc = true;
 	}
-	obj->phsize = phsize;
+	obj->phnum = phsize / sizeof(*phdr);
 	if (phinterp != NULL)
 		obj->interp = (const char *)(obj->relocbase +
 		    phinterp->p_vaddr);
diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c
index c160028cea6d..eb6f50c3c841 100644
--- a/libexec/rtld-elf/powerpc/reloc.c
+++ b/libexec/rtld-elf/powerpc/reloc.c
@@ -366,9 +366,7 @@ done:
 	 * Synchronize icache for executable segments in case we made
 	 * any changes.
 	 */
-	for (phdr = obj->phdr;
-	    (const char *)phdr < (const char *)obj->phdr + obj->phsize;
-	    phdr++) {
+	for (phdr = obj->phdr; phdr < obj->phdr + obj->phnum; phdr++) {
 		if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
 			__syncicache(obj->relocbase + phdr->p_vaddr,
 			    phdr->p_memsz);
diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c
index 4a4107aef861..a107da6b0a6a 100644
--- a/libexec/rtld-elf/powerpc64/reloc.c
+++ b/libexec/rtld-elf/powerpc64/reloc.c
@@ -364,9 +364,7 @@ done:
 	 * Synchronize icache for executable segments in case we made
 	 * any changes.
 	 */
-	for (phdr = obj->phdr;
-	    (const char *)phdr < (const char *)obj->phdr + obj->phsize;
-	    phdr++) {
+	for (phdr = obj->phdr; phdr < obj->phdr + obj->phnum; phdr++) {
 		if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
 			__syncicache(obj->relocbase + phdr->p_vaddr,
 			    phdr->p_memsz);
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 39fb6bc5fb31..7b5f31525853 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -1684,7 +1684,7 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
 			continue;
 
 		obj->phdr = phdr;
-		obj->phsize = ph->p_memsz;
+		obj->phnum = ph->p_memsz / sizeof(*ph);
 		obj->relocbase = __DECONST(char *, phdr) - ph->p_vaddr;
 		break;
 	}
@@ -2423,8 +2423,7 @@ parse_rtld_phdr(Obj_Entry *obj)
 
 	first_seg = true;
 	obj->stack_flags = PF_X | PF_R | PF_W;
-	for (ph = obj->phdr;
-	    (const char *)ph < (const char *)obj->phdr + obj->phsize; ph++) {
+	for (ph = obj->phdr; ph < obj->phdr + obj->phnum; ph++) {
 		switch (ph->p_type) {
 		case PT_LOAD:
 			if (first_seg) {
@@ -2486,7 +2485,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
 
 	ehdr = (Elf_Ehdr *)mapbase;
 	objtmp.phdr = (Elf_Phdr *)((char *)mapbase + ehdr->e_phoff);
-	objtmp.phsize = ehdr->e_phnum * sizeof(objtmp.phdr[0]);
+	objtmp.phnum = ehdr->e_phnum;
 
 	/* Initialize the object list. */
 	TAILQ_INIT(&obj_list);
@@ -2998,7 +2997,7 @@ load_kpreload(const void *addr)
 	obj = obj_new();
 	phdr = (const Elf_Phdr *)((const char *)addr + ehdr->e_phoff);
 	obj->phdr = phdr;
-	obj->phsize = ehdr->e_phnum * sizeof(*phdr);
+	obj->phnum = ehdr->e_phnum;
 	phlimit = phdr + ehdr->e_phnum;
 	seg0 = segn = NULL;
 
@@ -3380,10 +3379,10 @@ reloc_textrel_prot(Obj_Entry *obj, bool before)
 {
 	const Elf_Phdr *ph;
 	void *base;
-	size_t l, sz;
+	size_t sz;
 	int prot;
 
-	for (l = obj->phsize / sizeof(*ph), ph = obj->phdr; l > 0; l--, ph++) {
+	for (ph = obj->phdr; ph < obj->phdr + obj->phnum; ph++) {
 		if (ph->p_type != PT_LOAD || (ph->p_flags & PF_W) != 0)
 			continue;
 		base = obj->relocbase + rtld_trunc_page(ph->p_vaddr);
@@ -4331,7 +4330,7 @@ rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info)
 	phdr_info->dlpi_addr = (Elf_Addr)obj->relocbase;
 	phdr_info->dlpi_name = obj->path;
 	phdr_info->dlpi_phdr = obj->phdr;
-	phdr_info->dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
+	phdr_info->dlpi_phnum = obj->phnum;
 	phdr_info->dlpi_tls_modid = obj->tlsindex;
 	phdr_info->dlpi_tls_data = (char *)tls_get_addr_slow(_tcb_get(),
 	    obj->tlsindex, 0, true);
@@ -6149,8 +6148,7 @@ obj_remap_relro(Obj_Entry *obj, int prot)
 	caddr_t relro_page;
 	size_t relro_size;
 
-	for (ph = obj->phdr; (const char *)ph < (const char *)obj->phdr +
-	    obj->phsize; ph++) {
+	for (ph = obj->phdr; ph < obj->phdr + obj->phnum; ph++) {
 		if (ph->p_type != PT_GNU_RELRO)
 			continue;
 		relro_page = obj->relocbase + rtld_trunc_page(ph->p_vaddr);
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index d4829b17cebb..023e9af9a2a8 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -152,7 +152,7 @@ typedef struct Struct_Obj_Entry {
     const Elf_Dyn *dynamic;	/* Dynamic section */
     caddr_t entry;		/* Entry point */
     const Elf_Phdr *phdr;	/* Program header if it is mapped, else NULL */
-    size_t phsize;		/* Size of program header in bytes */
+    size_t phnum;		/* Number of program headers */
     const char *interp;		/* Pathname of the interpreter, if any */
     Elf_Word stack_flags;