ELF handling patch

Joerg Sonnenberger joerg at britannica.bec.de
Mon May 30 08:45:57 PDT 2005


Hi all,
please test the attached carefully. It's an important step for better
OS emulation support. brandelf should no longer be necessary, not even
for static Linux binaries. There's still a lot room for improvements :)

Joerg
Index: kern/imgact_elf.c
===================================================================
RCS file: /home/joerg/wd/repository/dragonflybsd/src/sys/kern/imgact_elf.c,v
retrieving revision 1.26
diff -u -r1.26 imgact_elf.c
--- kern/imgact_elf.c	8 Mar 2005 12:30:32 -0000	1.26
+++ kern/imgact_elf.c	30 May 2005 15:42:58 -0000
@@ -87,6 +87,9 @@
 SYSCTL_INT(_debug, OID_AUTO, elf_legacy_coredump, CTLFLAG_RW,
     &elf_legacy_coredump, 0, "");
 
+static int dragonfly_match_abi_note(const Elf_Note *);
+static int freebsd_match_abi_note(const Elf_Note *);
+
 static struct sysentvec elf_freebsd_sysvec = {
         SYS_MAXSYSCALL,
         sysent,
@@ -110,16 +113,54 @@
 static Elf_Brandinfo freebsd_brand_info = {
 						ELFOSABI_FREEBSD,
 						"FreeBSD",
+						freebsd_match_abi_note,
 						"",
 						"/usr/libexec/ld-elf.so.1",
 						&elf_freebsd_sysvec
 					  };
+
+static Elf_Brandinfo dragonfly_brand_info = {
+						ELFOSABI_NONE,
+						"DragonFly",
+						dragonfly_match_abi_note,
+						"",
+						"/usr/libexec/ld-elf.so.2",
+						&elf_freebsd_sysvec
+					  };
+
 static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = {
+							&dragonfly_brand_info,
 							&freebsd_brand_info,
 							NULL, NULL, NULL,
-							NULL, NULL, NULL, NULL
+							NULL, NULL, NULL
 						    };
 
+static int
+freebsd_match_abi_note(const Elf_Note *abi_note)
+{
+	const char *abi_name = (const char *)
+	    ((const uint8_t *)abi_note + sizeof(*abi_note));
+
+	if (abi_note->n_namesz < sizeof("FreeBSD"))
+		return(0);
+	if (memcmp(abi_name, "FreeBSD", sizeof("FreeBSD")))
+		return(0);
+	return(1);
+}
+
+static int
+dragonfly_match_abi_note(const Elf_Note *abi_note)
+{
+	const char *abi_name = (const char *)
+	    ((const uint8_t *)abi_note + sizeof(*abi_note));
+
+	if (abi_note->n_namesz < sizeof("DragonFly"))
+		return(0);
+	if (memcmp(abi_name, "DragonFly", sizeof("DragonFly")))
+		return(0);
+	return(1);
+}
+
 int
 elf_insert_brand_entry(Elf_Brandinfo *entry)
 {
@@ -483,6 +524,7 @@
 	u_long addr, entry = 0, proghdr = 0;
 	int error, i;
 	const char *interp = NULL;
+	const Elf_Note *abi_note = NULL;
 	Elf_Brandinfo *brand_info;
 	char *path;
 
@@ -606,6 +648,23 @@
 			}
 			interp = imgp->image_header + phdr[i].p_offset;
 			break;
+		case PT_NOTE:	/* Check for .note.ABI-tag */
+		{
+			const Elf_Note *tmp_note;
+			/* XXX handle anything outside the first page */
+			if (phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE)
+				continue;
+			if (phdr[i].p_filesz < sizeof(Elf_Note))
+				continue; /* ENOEXEC? */
+			tmp_note = (const Elf_Note *)(imgp->image_header + phdr[i].p_offset);
+			if (tmp_note->n_type != 1)
+				continue;
+			if (tmp_note->n_namesz + sizeof(Elf_Note) +
+			    tmp_note->n_descsz > phdr[i].p_filesz)
+				continue; /* ENOEXEC? */
+			abi_note = tmp_note;
+		}	
+			break;
 		case PT_PHDR: 	/* Program header table info */
 			proghdr = phdr[i].p_vaddr;
 			break;
@@ -633,7 +692,7 @@
 	 */
 
 	/* If the executable has a brand, search for it in the brand list. */
-	if (brand_info == NULL) {
+	if (brand_info == NULL && hdr->e_ident[EI_OSABI] != ELFOSABI_NONE) {
 		for (i = 0;  i < MAX_BRANDS;  i++) {
 			Elf_Brandinfo *bi = elf_brand_list[i];
 
@@ -648,7 +707,20 @@
 		}
 	}
 
-	/* Lacking a known brand, search for a recognized interpreter. */
+	/* Search for a recognized ABI. */
+	if (brand_info == NULL && abi_note != NULL) {
+		for (i = 0; i < MAX_BRANDS; i++) {
+			Elf_Brandinfo *bi = elf_brand_list[i];
+
+			if (bi != NULL && bi->match_abi_note != NULL
+			    && (*bi->match_abi_note)(abi_note)) {
+				brand_info = bi;
+				break;
+			}
+		}
+	}
+
+	/* Lacking a recognized ABI, search for a recognized interpreter. */
 	if (brand_info == NULL && interp != NULL) {
 		for (i = 0;  i < MAX_BRANDS;  i++) {
 			Elf_Brandinfo *bi = elf_brand_list[i];
@@ -678,7 +750,7 @@
 		    hdr->e_ident[EI_OSABI]);
 		error = ENOEXEC;
 		goto fail;
-	}
+	} else
 
 	imgp->proc->p_sysent = brand_info->sysvec;
 	if (interp != NULL) {
Index: emulation/linux/i386/linux_sysvec.c
===================================================================
RCS file: /home/joerg/wd/repository/dragonflybsd/src/sys/emulation/linux/i386/linux_sysvec.c,v
retrieving revision 1.16
diff -u -r1.16 linux_sysvec.c
--- emulation/linux/i386/linux_sysvec.c	15 Aug 2004 14:15:00 -0000	1.16
+++ emulation/linux/i386/linux_sysvec.c	30 May 2005 14:17:06 -0000
@@ -793,9 +793,12 @@
 	LINUX_MINSIGSTKSZ
 };
 
+static int	linux_match_abi_note(const Elf_Note *abi_note);
+
 static Elf32_Brandinfo linux_brand = {
 					ELFOSABI_LINUX,
 					"Linux",
+					linux_match_abi_note,
 					"/compat/linux",
 					"/lib/ld-linux.so.1",
 					&elf_linux_sysvec
@@ -804,6 +807,7 @@
 static Elf32_Brandinfo linux_glibc2brand = {
 					ELFOSABI_LINUX,
 					"Linux",
+					linux_match_abi_note,
 					"/compat/linux",
 					"/lib/ld-linux.so.2",
 					&elf_linux_sysvec
@@ -816,6 +820,26 @@
 				};
 
 static int
+linux_match_abi_note(const Elf_Note *abi_note)
+{
+	const char *abi_name = (const char *)
+	    ((const uint8_t *)abi_note + sizeof(*abi_note));
+	const uint32_t *descr = (const uint32_t *)
+	    ((const uint8_t *)abi_name + abi_note->n_namesz);
+
+	if (abi_note->n_namesz < sizeof("GNU"))
+		return(0);
+	if (memcmp(abi_name, "GNU", sizeof("GNU")))
+		return(0);
+	if (abi_note->n_descsz < sizeof(uint32_t))
+		return(0);
+
+	if (*descr != 0)
+		return(0);
+	return(1);
+}
+
+static int
 linux_elf_modevent(module_t mod, int type, void *data)
 {
 	Elf32_Brandinfo **brandinfo;
Index: emulation/svr4/svr4_sysvec.c
===================================================================
RCS file: /home/joerg/wd/repository/dragonflybsd/src/sys/emulation/svr4/svr4_sysvec.c,v
retrieving revision 1.11
diff -u -r1.11 svr4_sysvec.c
--- emulation/svr4/svr4_sysvec.c	12 Nov 2004 00:09:22 -0000	1.11
+++ emulation/svr4/svr4_sysvec.c	30 May 2005 15:24:27 -0000
@@ -190,6 +190,7 @@
 Elf32_Brandinfo svr4_brand = {
   ELFOSABI_SYSV,
   "SVR4",
+  NULL,
   "/compat/svr4",
   "/lib/libc.so.1",
   &svr4_sysvec
Index: sys/imgact_elf.h
===================================================================
RCS file: /home/joerg/wd/repository/dragonflybsd/src/sys/sys/imgact_elf.h,v
retrieving revision 1.5
diff -u -r1.5 imgact_elf.h
--- sys/imgact_elf.h	25 Oct 2004 08:57:50 -0000	1.5
+++ sys/imgact_elf.h	30 May 2005 13:39:26 -0000
@@ -32,6 +32,7 @@
 #ifndef _SYS_IMGACT_ELF_H_
 #define _SYS_IMGACT_ELF_H_
 
+#include <sys/elf_common.h>
 #include <machine/elf.h>
 
 #ifdef _KERNEL
@@ -59,6 +60,7 @@
 typedef struct {
 	int brand;
 	const char *compat_3_brand;	/* pre Binutils 2.10 method (FBSD 3) */
+	int (*match_abi_note)(const Elf_Note *);
 	const char *emul_path;
 	const char *interp_path;
         struct sysentvec *sysvec;




More information about the Submit mailing list