Subject: Re: compatibility and emulation fixes for exec_elf
To: None <tech-kern@NetBSD.org, port-mips@NetBSD.org>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: tech-kern
Date: 10/30/2003 20:37:23
This is a multipart MIME message.

--==_Exmh_52098809409620
Content-Type: text/plain; charset=us-ascii


M.Drochner@fz-juelich.de said:
> -In principle, case (3) above wouldn't be needed anymore, and the
>  address return argument to the "probe" function could be replaced
>  by just a flag bit.

svr4 emulation code uses hardcoded addresses, so this can't be done

I'll append patches which implement the rest of my proposal:
-fix for ELF_INTERP_NON_RELOCATABLE
-nuke irix_load_addr()
-make NO_ADDR the default and remove then unneeded assignments in
 emulation elf_probe() functions
-allocate buffer for interpreter name only if needed

(The mips/elf_machdep patch switching off ELF_INTERP_NON_RELOCATABLE
if no COMPAT_16 is needed is from simonb.)

kern/exec_elf32.c could still be streanlined a bit. In particular
NO_ADDR is only used internally now and could be removed from the
public namespace. I also don't see a point in having 2 ways to
express the same: ELF_NO_ADDR and ELFDEFNNAME(NO_ADDR). Also,
ELF_NO_ADDR and ELF_LINK_ADDR are used for the same thing partially.

If noone objects, I'll commit that stuff soon, probably tomorrow.

best regards
Matthias



--==_Exmh_52098809409620
Content-Type: text/plain ; name="elf.txt"; charset=us-ascii
Content-Description: elf.txt
Content-Disposition: attachment; filename="elf.txt"

Index: arch/mips/include/elf_machdep.h
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/include/elf_machdep.h,v
retrieving revision 1.8
diff -u -p -r1.8 elf_machdep.h
--- arch/mips/include/elf_machdep.h	9 Dec 2001 23:05:58 -0000	1.8
+++ arch/mips/include/elf_machdep.h	30 Oct 2003 19:30:55 -0000
@@ -86,10 +86,16 @@
 #define DT_MIPS_HIPAGENO	0x70000014
 #define	DT_MIPS_RLD_MAP		0x70000016	/* address of loader map */
 
+#ifdef _KERNEL
+#ifdef _KERNEL_OPT
+#include "opt_compat_netbsd.h"
+#endif
+#ifdef COMPAT_16
 /*
+ * Up to 1.6, the ELF dynamic loader (ld.elf_so) was not relocatable.
  * Tell the kernel ELF exec code not to try relocating the interpreter
- * (ld.so) for dynamically-linked ELF binaries.
+ * for dynamically-linked ELF binaries.
  */
-#ifdef _KERNEL
 #define ELF_INTERP_NON_RELOCATABLE
-#endif
+#endif /* COMPAT_16 */
+#endif /* _KERNEL */
Index: kern/exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/kern/exec_elf32.c,v
retrieving revision 1.94
diff -u -p -r1.94 exec_elf32.c
--- kern/exec_elf32.c	8 Aug 2003 18:53:13 -0000	1.94
+++ kern/exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -399,8 +399,6 @@ ELFNAME(load_file)(struct proc *p, struc
 	if ((error = exec_read_from(p, vp, eh.e_phoff, ph, phsize)) != 0)
 		goto bad;
 
-	/* this breaks on, e.g., OpenBSD-compatible mips shared binaries. */
-#ifndef ELF_INTERP_NON_RELOCATABLE
 	/*
 	 * If no position to load the interpreter was set by a probe
 	 * function, pick the same address that a non-fixed mmap(0, ..)
@@ -429,8 +427,7 @@ ELFNAME(load_file)(struct proc *p, struc
 		addr = VM_DEFAULT_ADDRESS(epp->ep_daddr,
 		    round_page(limit) - trunc_page(base_ph->p_vaddr));
 	} else
-#endif	/* !ELF_INTERP_NON_RELOCATABLE */
-		addr = *last;
+		addr = *last; /* may be ELF_LINK_ADDR */
 
 	/*
 	 * Load all the necessary sections
@@ -452,6 +449,8 @@ ELFNAME(load_file)(struct proc *p, struc
 				 */
 				base_ph = ph0;
 				flags = VMCMD_BASE;
+				if (addr == ELF_LINK_ADDR)
+					addr = ph0->p_vaddr;
 				if (p->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN)
 					addr = ELF_TRUNC(addr, ph0->p_align);
 				else
@@ -574,14 +573,13 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 	epp->ep_taddr = epp->ep_tsize = ELFDEFNNAME(NO_ADDR);
 	epp->ep_daddr = epp->ep_dsize = ELFDEFNNAME(NO_ADDR);
 
-	MALLOC(interp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
-	interp[0] = '\0';
-
 	for (i = 0; i < eh->e_phnum; i++) {
 		pp = &ph[i];
 		if (pp->p_type == PT_INTERP) {
 			if (pp->p_filesz >= MAXPATHLEN)
 				goto bad;
+			MALLOC(interp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
+			interp[0] = '\0';
 			if ((error = exec_read_from(p, epp->ep_vp,
 			    pp->p_offset, interp, pp->p_filesz)) != 0)
 				goto bad;
@@ -599,16 +597,15 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 	 * exists. Emulation packages may possibly replace the interpreter in
 	 * interp[] with a changed path (/emul/xxx/<path>).
 	 */
-	if (!epp->ep_esch->u.elf_probe_func) {
-		pos = ELFDEFNNAME(NO_ADDR);
-	} else {
-		vaddr_t startp = 0;
+	pos = ELFDEFNNAME(NO_ADDR);
+	if (epp->ep_esch->u.elf_probe_func) {
+		vaddr_t startp = (vaddr_t)pos;
 
 		error = (*epp->ep_esch->u.elf_probe_func)(p, epp, eh, interp,
 							  &startp);
-		pos = (Elf_Addr)startp;
 		if (error)
 			goto bad;
+		pos = (Elf_Addr)startp;
 	}
 
 	/*
@@ -675,7 +672,7 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 	 * Check if we found a dynamically linked binary and arrange to load
 	 * its interpreter
 	 */
-	if (interp[0]) {
+	if (interp) {
 		struct elf_args *ap;
 		int i = epp->ep_vmcmds.evs_used;
 		u_long interp_offset;
@@ -696,6 +693,8 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 		ap->arg_entry = eh->e_entry;
 
 		epp->ep_emul_arg = ap;
+
+		FREE(interp, M_TEMP);
 	} else
 		epp->ep_entry = eh->e_entry;
 
@@ -704,7 +703,6 @@ ELFNAME2(exec,makecmds)(struct proc *p, 
 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, PAGE_SIZE, 0,
 	    epp->ep_vp, 0, VM_PROT_READ);
 #endif
-	FREE(interp, M_TEMP);
 	free(ph, M_TEMP);
 	return (*epp->ep_esch->es_setup_stack)(p, epp);
 
@@ -779,6 +777,8 @@ ELFNAME2(netbsd,probe)(struct proc *p, s
 
 	if ((error = ELFNAME2(netbsd,signature)(p, epp, eh)) != 0)
 		return error;
-	*pos = ELFDEFNNAME(NO_ADDR);
+#ifdef ELF_INTERP_NON_RELOCATABLE
+	*pos = ELF_LINK_ADDR;
+#endif
 	return 0;
 }
Index: sys/exec_elf.h
===================================================================
RCS file: /cvsroot/src/sys/sys/exec_elf.h,v
retrieving revision 1.72
diff -u -p -r1.72 exec_elf.h
--- sys/exec_elf.h	8 Aug 2003 18:54:16 -0000	1.72
+++ sys/exec_elf.h	30 Oct 2003 19:30:56 -0000
@@ -768,12 +768,16 @@ struct netbsd_elfcore_procinfo {
 
 #define ELF_AUX_ENTRIES	12		/* Size of aux array passed to loader */
 #define ELF32_NO_ADDR	(~(Elf32_Addr)0) /* Indicates addr. not yet filled in */
+#define ELF32_LINK_ADDR	((Elf32_Addr)-2) /* advises to use link address */
 #define ELF64_NO_ADDR	(~(Elf64_Addr)0) /* Indicates addr. not yet filled in */
+#define ELF64_LINK_ADDR	((Elf64_Addr)-2) /* advises to use link address */
 
 #if defined(ELFSIZE) && (ELFSIZE == 64)
 #define ELF_NO_ADDR	ELF64_NO_ADDR
+#define ELF_LINK_ADDR	ELF64_LINK_ADDR
 #elif defined(ELFSIZE) && (ELFSIZE == 32)
 #define ELF_NO_ADDR	ELF32_NO_ADDR
+#define ELF_LINK_ADDR	ELF32_LINK_ADDR
 #endif
 
 #ifndef ELF32_EHDR_FLAGS_OK
Index: compat/freebsd/freebsd_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/freebsd/freebsd_exec_elf32.c,v
retrieving revision 1.11
diff -u -p -r1.11 freebsd_exec_elf32.c
--- compat/freebsd/freebsd_exec_elf32.c	29 Jun 2003 22:29:16 -0000	1.11
+++ compat/freebsd/freebsd_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -115,12 +115,11 @@ ELFNAME2(freebsd,probe)(p, epp, veh, itp
 		free(ph, M_TEMP);
 	}
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
 		    itp)))
 			return error;
 	}
-	*pos = ELF_NO_ADDR;
 #ifdef DEBUG_FREEBSD_ELF
 	printf("freebsd_elf32_probe: returning 0\n");
 #endif
Index: compat/ibcs2/ibcs2_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/ibcs2/ibcs2_exec_elf32.c,v
retrieving revision 1.6
diff -u -p -r1.6 ibcs2_exec_elf32.c
--- compat/ibcs2/ibcs2_exec_elf32.c	29 Jun 2003 22:29:20 -0000	1.6
+++ compat/ibcs2/ibcs2_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -132,10 +132,9 @@ ibcs2_elf32_probe(p, epp, eh, itp, pos)
 	if ((error = ibcs2_elf32_signature(p, epp, eh)) != 0)
                 return error;
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path, itp)))
 			return error;
 	}
-	*pos = ELF32_NO_ADDR;
 	return 0;
 }
Index: compat/irix/irix_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/irix/irix_exec_elf32.c,v
retrieving revision 1.8
diff -u -p -r1.8 irix_exec_elf32.c
--- compat/irix/irix_exec_elf32.c	6 Aug 2003 01:04:44 -0000	1.8
+++ compat/irix/irix_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -63,8 +63,6 @@ __KERNEL_RCSID(0, "$NetBSD: irix_exec_el
 
 #include <compat/irix/irix_exec.h>
 
-static int irix_load_addr(struct proc *, char *, vaddr_t *);
-
 /*
  * IRIX o32 ABI probe function
  */
@@ -85,7 +83,7 @@ ELFNAME2(irix,probe_o32)(p, epp, eh, itp
 	    IRIX_EF_IRIX_ABIO32)
 		return error;
 
-	if (itp[0]) {
+	if (itp) {
 		/* o32 binaries use /lib/libc.so.1 */
 		if (strncmp(itp, "/lib/libc.so", 12) && 
 		    strncmp(itp, "/usr/lib/libc.so", 16))
@@ -93,10 +91,7 @@ ELFNAME2(irix,probe_o32)(p, epp, eh, itp
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
 		    itp)))
 			return error;
-		if ((error = irix_load_addr(p, itp, pos)) != 0)
-			return error;
-	} else {
-		*pos = ELF_NO_ADDR;
+		*pos = ELF_LINK_ADDR;
 	}
 #ifdef DEBUG_IRIX
 	printf("irix_probe_o32: returning 0\n");
@@ -126,7 +121,7 @@ ELFNAME2(irix,probe_n32)(p, epp, eh, itp
 	    IRIX_EF_IRIX_ABIN32)
 		return error;
 
-	if (itp[0]) {
+	if (itp) {
 		/* n32 binaries use /lib32/libc.so.1 */
 		if (strncmp(itp, "/lib32/libc.so", 14) &&
 		    strncmp(itp, "/usr/lib32/libc.so", 18))
@@ -135,7 +130,6 @@ ELFNAME2(irix,probe_n32)(p, epp, eh, itp
 		    itp)))
 			return error;
 	}
-	*pos = ELF_NO_ADDR;
 #ifdef DEBUG_IRIX
 	printf("irix_probe_n32: returning 0\n");
 	printf("epp->ep_vm_minaddr = 0x%lx\n", epp->ep_vm_minaddr);
@@ -263,73 +257,4 @@ ELFNAME2(irix,copyargs)(p, pack, arginfo
 	printf("*stackp = %p\n", *stackp);
 #endif
 	return 0;
-}
-
-/* 
- * Find the load address of the intepreter. Most of the code is 
- * borrowed from sys/kern/exec_elf32.c:load_file(). 
- * There is nothing specific to IRIX here, it may move to 
- * sys/compat/compat_util.c if another emulation needs it.
- */
-#define MAXPHNUM	50
-static int
-irix_load_addr(p, itp, pos)
-	struct proc *p;
-	char *itp;
-	vaddr_t *pos;
-{
-	int error = 0;
-	int i;
-	struct nameidata nd;
-	struct vnode *vp;
-	Elf_Ehdr eh;
-	Elf_Phdr *ph = NULL;
-	u_long phsize;
-
-	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, itp, p);
-	if ((error = namei(&nd)) != 0)
-		return ELFDEFNNAME(NO_ADDR);
-	vp = nd.ni_vp;
-
-	/* Check this is a regular file */
-	if (vp->v_type != VREG)  {
-		VOP_UNLOCK(vp, 0);
-		error = EACCES;
-		goto bad;
-	}
-
-	VOP_UNLOCK(vp, 0);
-
-	if ((error = exec_read_from(p, vp, 0, &eh, sizeof(eh))) != 0)
-		goto bad;
-
-	if ((error = ELFNAME(check_header)(&eh, ET_DYN)) != 0)
-		goto bad;
-
-	if (eh.e_phnum > MAXPHNUM)
-		goto bad;
-
-	phsize = eh.e_phnum * sizeof(Elf_Phdr);
-	ph = (Elf_Phdr *)malloc(phsize, M_TEMP, M_WAITOK);
-	if ((error = exec_read_from(p, vp, eh.e_phoff, ph, phsize)) != 0)
-		goto bad;
-
-	/* Look for the first loadable section */
-	for (i = 0; i < eh.e_phnum; i++)
-		if (ph[i].p_type == PT_LOAD)
-			break;
-	if (i == eh.e_phnum) {
-		error = ENOEXEC;
-		goto bad;
-	}
-
-	*pos = ph[i].p_vaddr;
-#ifdef DEBUG_IRIX
-	printf("irix_load_addr: file %s, addr %p\n", itp, (void *)*pos);
-#endif
-bad:
-	if (ph != NULL)
-		free(ph, M_TEMP);
-	vrele(vp);
-	return error;
 }
Index: compat/linux/common/linux_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/linux/common/linux_exec_elf32.c,v
retrieving revision 1.65
diff -u -p -r1.65 linux_exec_elf32.c
--- compat/linux/common/linux_exec_elf32.c	27 Oct 2003 07:07:34 -0000	1.65
+++ compat/linux/common/linux_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -294,7 +294,7 @@ ELFNAME2(linux,signature)(p, epp, eh, it
 	}
 
 	/* Check for certain intepreter names. */
-	if (itp[0]) {
+	if (itp) {
 		if (!strncmp(itp, "/lib/ld-linux", 13) ||
 		    !strncmp(itp, "/lib/ld.so.", 11))
 			error = 0;
@@ -329,12 +329,11 @@ ELFNAME2(linux,probe)(p, epp, eh, itp, p
 	    1) 
 			return error;
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
 		    itp)))
 			return (error);
 	}
-	*pos = ELF_NO_ADDR;
 	DPRINTF(("linux_probe: returning 0\n"));
 	return 0;
 }
Index: compat/netbsd32/netbsd32_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/netbsd32/netbsd32_exec_elf32.c,v
retrieving revision 1.20
diff -u -p -r1.20 netbsd32_exec_elf32.c
--- compat/netbsd32/netbsd32_exec_elf32.c	13 Oct 2003 14:22:20 -0000	1.20
+++ compat/netbsd32/netbsd32_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -105,7 +105,7 @@ ELFNAME2(netbsd32,probe_noteless)(struct
 {
 	int error;
 
-	if (itp[0]) {
+	if (itp) {
 		/* Translate interpreter name if needed */
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path,
 		    itp)) != 0)
@@ -114,7 +114,9 @@ ELFNAME2(netbsd32,probe_noteless)(struct
 	epp->ep_flags |= EXEC_32;
 	epp->ep_vm_minaddr = VM_MIN_ADDRESS;
 	epp->ep_vm_maxaddr = USRSTACK32;
-	*pos = ELFDEFNNAME(NO_ADDR);
+#ifdef ELF_INTERP_NON_RELOCATABLE
+	*pos = ELF_LINK_ADDR;
+#endif
 	return 0;
 }
 
Index: compat/svr4/svr4_exec.h
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4/svr4_exec.h,v
retrieving revision 1.22
diff -u -p -r1.22 svr4_exec.h
--- compat/svr4/svr4_exec.h	29 Jun 2003 22:29:46 -0000	1.22
+++ compat/svr4/svr4_exec.h	30 Oct 2003 19:30:56 -0000
@@ -68,10 +68,6 @@
 #define SVR4_INTERP_ADDR	0x10000000
 #endif
 
-#ifndef SVR4_INTERP_ADDR
-# define SVR4_INTERP_ADDR	ELFDEFNNAME(NO_ADDR)
-#endif
-
 extern const struct emul emul_svr4;
 
 void svr4_setregs __P((struct lwp *, struct exec_package *, u_long));
Index: compat/svr4/svr4_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4/svr4_exec_elf32.c,v
retrieving revision 1.7
diff -u -p -r1.7 svr4_exec_elf32.c
--- compat/svr4/svr4_exec_elf32.c	29 Jun 2003 22:29:46 -0000	1.7
+++ compat/svr4/svr4_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -71,10 +71,12 @@ svr4_elf32_probe(p, epp, eh, itp, pos)
 {
 	int error;
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path, itp)))
 			return error;
 	}
+#ifdef SVR4_INTERP_ADDR
 	*pos = SVR4_INTERP_ADDR;
+#endif
 	return 0;
 }
Index: compat/svr4/svr4_exec_elf64.c
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4/svr4_exec_elf64.c,v
retrieving revision 1.8
diff -u -p -r1.8 svr4_exec_elf64.c
--- compat/svr4/svr4_exec_elf64.c	29 Jun 2003 22:29:46 -0000	1.8
+++ compat/svr4/svr4_exec_elf64.c	30 Oct 2003 19:30:56 -0000
@@ -71,10 +71,12 @@ svr4_elf64_probe(p, epp, eh, itp, pos)
 {
 	int error;
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path, itp)))
 			return error;
 	}
+#ifdef SVR4_INTERP_ADDR
 	*pos = SVR4_INTERP_ADDR;
+#endif
 	return 0;
 }
Index: compat/svr4_32/svr4_32_exec.h
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4_32/svr4_32_exec.h,v
retrieving revision 1.7
diff -u -p -r1.7 svr4_32_exec.h
--- compat/svr4_32/svr4_32_exec.h	29 Jun 2003 22:29:50 -0000	1.7
+++ compat/svr4_32/svr4_32_exec.h	30 Oct 2003 19:30:56 -0000
@@ -67,10 +67,6 @@ int svr4_32_copyargs __P((struct proc *,
 #endif
 #endif
 
-#ifndef SVR4_32_INTERP_ADDR
-# define SVR4_32_INTERP_ADDR	ELFDEFNNAME(NO_ADDR)
-#endif
-
 extern const struct emul emul_svr4_32;
 
 void svr4_32_setregs __P((struct lwp *, struct exec_package *, u_long));
Index: compat/svr4_32/svr4_32_exec_elf32.c
===================================================================
RCS file: /cvsroot/src/sys/compat/svr4_32/svr4_32_exec_elf32.c,v
retrieving revision 1.12
diff -u -p -r1.12 svr4_32_exec_elf32.c
--- compat/svr4_32/svr4_32_exec_elf32.c	29 Jun 2003 22:29:50 -0000	1.12
+++ compat/svr4_32/svr4_32_exec_elf32.c	30 Oct 2003 19:30:56 -0000
@@ -284,11 +284,13 @@ svr4_32_elf32_probe(p, epp, eh, itp, pos
 {
 	int error;
 
-	if (itp[0]) {
+	if (itp) {
 		if ((error = emul_find_interp(p, epp->ep_esch->es_emul->e_path, itp)))
 			return error;
 	}
 	epp->ep_flags |= EXEC_32;
+#ifdef SVR4_32_INTERP_ADDR
 	*pos = SVR4_32_INTERP_ADDR;
+#endif
 	return 0;
 }

--==_Exmh_52098809409620--