git: purgatorio

Download patch

ref: 997b975323c0454493777e70e836e15390d22ed1
parent: b7defb5ff290bb2f97e5e7d6948db0a9dc4bdd6a
author: Tomas Glozar <tglozar@gmail.com>
date: Wed Oct 22 15:45:10 EDT 2025

libinterp/comp-386: Fix native compiler for Linux/386

On Linux/386, malloc()ed code cannot be executed. Replace
malloc()/mallocz()/free() with newly defined functions xalloc(),
xallocz(), xfree(), xactivate().

The new functions are implemented using mmap() to allocate executable
pages. Through the use of xactivate(), they also support W/X.

All other 386 platforms define xalloc() as malloc(),
xallocz() as mallocz(..., 0), xfree() as free(), and xactivate()
as NOP for compatibility.

--- a/libinterp/comp-386.c
+++ b/libinterp/comp-386.c
@@ -2,6 +2,7 @@
 #include "isa.h"
 #include "interp.h"
 #include "raise.h"
+#include "xalloc.h"
 
 #define DOT			((ulong)code)
 
@@ -1520,7 +1521,7 @@
 	if(comvec)
 		return;
 
-	comvec = malloc(32);
+	comvec = xalloc(32);
 	if(comvec == nil)
 		error(exNomem);
 	code = (uchar*)comvec;
@@ -1536,6 +1537,7 @@
 	modrm(Ojmprm, O(REG, PC), RTMP, 4);
 
 	segflush(comvec, 32);
+	xactivate(comvec);
 }
 
 static void
@@ -1855,7 +1857,7 @@
 	n += code - tmp;
 	free(tmp);
 
-	code = mallocz(n, 0);
+	code = xallocz(n);
 	if(code == nil)
 		return;
 
@@ -1869,6 +1871,7 @@
 			(ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
 
 	segflush(t->initialize, n);
+	xactivate(t->initialize);
 }
 
 static void
@@ -1929,7 +1932,7 @@
 	n = (n+3)&~3;
 
 	nlit *= sizeof(ulong);
-	base = mallocz(n + nlit, 0);
+	base = xallocz(n + nlit);
 	if(base == nil)
 		goto bad;
 
@@ -1980,6 +1983,7 @@
 	m->prog = (Inst*)base;
 	m->compiled = 1;
 	segflush(base, n*sizeof(base));
+	xactivate(base);
 	return 1;
 bad:
 	free(patch);
--- a/libinterp/heap.c
+++ b/libinterp/heap.c
@@ -3,6 +3,7 @@
 #include "interp.h"
 #include "pool.h"
 #include "raise.h"
+#include "xalloc.h"
 
 void	freearray(Heap*, int);
 void	freelist(Heap*, int);
@@ -277,7 +278,7 @@
 	if(t == nil || --t->ref > 0)
 		return;
 
-	free(t->initialize);
+	xfree(t->initialize);
 	free(t);
 }
 
--- a/libinterp/load.c
+++ b/libinterp/load.c
@@ -2,6 +2,7 @@
 #include "isa.h"
 #include "interp.h"
 #include "raise.h"
+#include "xalloc.h"
 #include <kernel.h>
 
 #define	A(r)	*((Array**)(r))
@@ -568,7 +569,7 @@
 		free(m->type);
 	}
 	free(m->name);
-	free(m->prog);
+	xfree(m->prog);
 	free(m->path);
 	free(m->pctab);
 	if(m->ldt != nil){
--- /dev/null
+++ b/libinterp/xalloc.h
@@ -1,0 +1,47 @@
+#ifdef LINUX_386
+#include <sys/mman.h>
+#include <unistd.h>
+
+static void* xalloc(int s)
+{
+	s += sizeof(int); /* For storing the size */
+	void *r = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (r != MAP_FAILED) {
+		/* Use first byte to store the size */
+		int *r2 = r;
+		*r2 = s;
+		++r2;
+		r = r2;
+		return r;
+	}
+	return 0;
+}
+
+static void* xallocz(int s)
+{
+	return xalloc(s);
+}
+
+static void xfree(void *p)
+{
+	if (p == NULL)
+		return;
+	int *p2 = p;
+	--p;
+	p = p2;
+	munmap(p, *p2);
+}
+
+static void xactivate(void *p)
+{
+	int *p2 = p;
+	--p2;
+	p = p2;
+	mprotect(p, *p2, PROT_READ | PROT_EXEC);
+}
+#else
+#define xalloc(s) malloc(s)
+#define xallocz(s) mallocz(s, 0)
+#define xfree(p) free(p)
+#define xactivate(p) {}
+#endif /* LINUX_386 */
--