Module Name: src
Committed By: christos
Date: Sun Jul 8 17:58:39 UTC 2018
Modified Files:
src/sys/compat/linux/common: linux_exec_elf32.c
Log Message:
Enable executing linux go binaries by using a special probe function for them.
To generate a diff of this commit:
cvs rdiff -u -r1.94 -r1.95 src/sys/compat/linux/common/linux_exec_elf32.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/compat/linux/common/linux_exec_elf32.c
diff -u src/sys/compat/linux/common/linux_exec_elf32.c:1.94 src/sys/compat/linux/common/linux_exec_elf32.c:1.95
--- src/sys/compat/linux/common/linux_exec_elf32.c:1.94 Mon Feb 6 18:45:49 2017
+++ src/sys/compat/linux/common/linux_exec_elf32.c Sun Jul 8 13:58:39 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_exec_elf32.c,v 1.94 2017/02/06 23:45:49 uwe Exp $ */
+/* $NetBSD: linux_exec_elf32.c,v 1.95 2018/07/08 17:58:39 christos Exp $ */
/*-
* Copyright (c) 1995, 1998, 2000, 2001 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.94 2017/02/06 23:45:49 uwe Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.95 2018/07/08 17:58:39 christos Exp $");
#ifndef ELFSIZE
/* XXX should die */
@@ -73,6 +73,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec_e
#include <compat/linux/linux_syscallargs.h>
#include <compat/linux/linux_syscall.h>
+#define LINUX_GO_RT0_SIGNATURE
+
#ifdef DEBUG_LINUX
#define DPRINTF(a) uprintf a
#else
@@ -264,6 +266,93 @@ out:
}
#endif
+#ifdef LINUX_GO_RT0_SIGNATURE
+/*
+ * Look for a .gopclntab, specific to go binaries
+ * in it look for a symbol called _rt0_<cpu>_linux
+ */
+static int
+ELFNAME2(linux,go_rt0_signature)(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh)
+{
+ Elf_Shdr *sh;
+ size_t shsize;
+ u_int shstrndx;
+ size_t i;
+ static const char signature[] = ".gopclntab";
+ const size_t sigsz = sizeof(signature);
+ char tbuf[sizeof(signature)], *tmp = NULL;
+ char mbuf[64];
+ const char *m;
+ int mlen;
+ int error;
+
+ /* Load the section header table. */
+ shsize = eh->e_shnum * sizeof(Elf_Shdr);
+ sh = malloc(shsize, M_TEMP, M_WAITOK);
+ error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
+ if (error)
+ goto out;
+
+ /* Now let's find the string table. If it does not exist, give up. */
+ shstrndx = eh->e_shstrndx;
+ if (shstrndx == SHN_UNDEF || shstrndx >= eh->e_shnum) {
+ error = ENOEXEC;
+ goto out;
+ }
+
+ /* Check if any section has the name we're looking for. */
+ const off_t stroff = sh[shstrndx].sh_offset;
+ for (i = 0; i < eh->e_shnum; i++) {
+ Elf_Shdr *s = &sh[i];
+
+ if (s->sh_name + sigsz > sh[shstrndx].sh_size)
+ continue;
+
+ error = exec_read_from(l, epp->ep_vp, stroff + s->sh_name, tbuf,
+ sigsz);
+ if (error)
+ goto out;
+ if (!memcmp(tbuf, signature, sigsz)) {
+ DPRINTF(("linux_goplcntab_sig=%s\n", tbuf);
+ break;
+ }
+ }
+
+ if (i == eh->e_shnum) {
+ error = ENOEXEC;
+ goto out;
+ }
+
+ if (sh[i].sh_size > 1024 * 1014)
+ sh[i].sh_size = 1014 * 1014;
+
+ tmp = malloc(sh[i].sh_size, M_TEMP, M_WAITOK);
+ error = exec_read_from(l, epp->ep_vp, sh[i].sh_offset, tmp,
+ sh[i].sh_size);
+ if (error)
+ goto out;
+
+#if (ELFSIZE == 32)
+ if (strcmp(machine, "amd64") == 0)
+ m = "i386";
+ else
+ m = machine;
+#else
+ m = machine;
+#endif
+ mlen = snprintf(mbuf, sizeof(mbuf), "_rt0_%s_linux", m);
+ if (memmem(tmp, sh[i].sh_size, mbuf, mlen) == NULL)
+ error = ENOEXEC;
+ else
+ DPRINTF(("linux_rt0_sig=%s\n", mbuf));
+out:
+ if (tmp)
+ free(tmp, M_TEMP);
+ free(sh, M_TEMP);
+ return error;
+}
+#endif
+
int
ELFNAME2(linux,signature)(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh, char *itp)
{
@@ -356,6 +445,9 @@ ELFNAME2(linux,probe)(struct lwp *l, str
#ifdef LINUX_DEBUGLINK_SIGNATURE
((error = ELFNAME2(linux,debuglink_signature)(l, epp, eh)) != 0) &&
#endif
+#ifdef LINUX_GO_RT0_SIGNATURE
+ ((error = ELFNAME2(linux,go_rt0_signature)(l, epp, eh)) != 0) &&
+#endif
1) {
DPRINTF(("linux_probe: returning %d\n", error));
return error;