Skip to content

Commit 3fedfcf

Browse files
authored
gh-96143: Clear instruction cache after mprotect call (#96476)
1 parent c580a81 commit 3fedfcf

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

Objects/perf_trampoline.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,22 @@ typedef enum {
149149
#include <sys/types.h>
150150
#include <unistd.h>
151151

152+
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
153+
#define PY_HAVE_INVALIDATE_ICACHE
154+
155+
#if defined(__clang__) || defined(__GNUC__)
156+
extern void __clear_cache(void *, void*);
157+
#endif
158+
159+
static void invalidate_icache(char* begin, char*end) {
160+
#if defined(__clang__) || defined(__GNUC__)
161+
return __clear_cache(begin, end);
162+
#else
163+
return;
164+
#endif
165+
}
166+
#endif
167+
152168
/* The function pointer is passed as last argument. The other three arguments
153169
* are passed in the same order as the function requires. This results in
154170
* shorter, more efficient ASM code for trampoline.
@@ -185,6 +201,7 @@ struct trampoline_api_st {
185201

186202
typedef struct trampoline_api_st trampoline_api_t;
187203

204+
188205
static perf_status_t perf_status = PERF_STATUS_NO_INIT;
189206
static Py_ssize_t extra_code_index = -1;
190207
static code_arena_t *code_arena;
@@ -297,10 +314,6 @@ new_code_arena(void)
297314
memcpy(memory + i * code_size, start, code_size * sizeof(char));
298315
}
299316
// Some systems may prevent us from creating executable code on the fly.
300-
// TODO: Call icache invalidation intrinsics if available:
301-
// __builtin___clear_cache/__clear_cache (depending if clang/gcc). This is
302-
// technically not necessary but we could be missing something so better be
303-
// safe.
304317
int res = mprotect(memory, mem_size, PROT_READ | PROT_EXEC);
305318
if (res == -1) {
306319
PyErr_SetFromErrno(PyExc_OSError);
@@ -311,6 +324,12 @@ new_code_arena(void)
311324
return -1;
312325
}
313326

327+
#ifdef PY_HAVE_INVALIDATE_ICACHE
328+
// Before the JIT can run a block of code that has been emitted it must invalidate
329+
// the instruction cache on some platforms like arm and aarch64.
330+
invalidate_icache(memory, memory + mem_size);
331+
#endif
332+
314333
code_arena_t *new_arena = PyMem_RawCalloc(1, sizeof(code_arena_t));
315334
if (new_arena == NULL) {
316335
PyErr_NoMemory();

0 commit comments

Comments
 (0)