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 */
--
⑨