From ee02e31788f88b3a349a021c2a57b9f7926068f1 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 21 Oct 2026 18:19:30 +0000 Subject: [PATCH 1/2] gh-128883: Keep the perf trampoline end marker inside its text section --- .../2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst | 2 ++ Python/asm_trampoline_aarch64.S | 1 + Python/asm_trampoline_riscv64.S | 1 + Python/asm_trampoline_x86_64.S | 1 + 4 files changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst diff --git a/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst new file mode 100644 index 000000000000000..f5b066d31ec71c1 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst @@ -0,0 +1,2 @@ +Add a byte after the ELF perf trampoline end marker so it does not share +the following function's address, which BOLT may otherwise move. diff --git a/Python/asm_trampoline_aarch64.S b/Python/asm_trampoline_aarch64.S index b3aeb728de200c6..aef34014ae85529 100644 --- a/Python/asm_trampoline_aarch64.S +++ b/Python/asm_trampoline_aarch64.S @@ -57,6 +57,7 @@ __Py_trampoline_func_end: #else .globl _Py_trampoline_func_end _Py_trampoline_func_end: + .byte 0 .section .note.GNU-stack,"",@progbits #endif diff --git a/Python/asm_trampoline_riscv64.S b/Python/asm_trampoline_riscv64.S index 6125ba95373f954..21aafbcf23d6f0a 100644 --- a/Python/asm_trampoline_riscv64.S +++ b/Python/asm_trampoline_riscv64.S @@ -9,4 +9,5 @@ _Py_trampoline_func_start: jr ra .globl _Py_trampoline_func_end _Py_trampoline_func_end: + .byte 0 .section .note.GNU-stack,"",@progbits diff --git a/Python/asm_trampoline_x86_64.S b/Python/asm_trampoline_x86_64.S index 0e6b11589eafc82..e1a714413abfd42 100644 --- a/Python/asm_trampoline_x86_64.S +++ b/Python/asm_trampoline_x86_64.S @@ -21,6 +21,7 @@ __Py_trampoline_func_end: #else .globl _Py_trampoline_func_end _Py_trampoline_func_end: + .byte 0 .section .note.GNU-stack,"",@progbits #endif # Note for indicating the assembly code supports CET From ac6015dc8a9e104de034ced2edd7e34704d6fcd5 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 23 Oct 2026 19:34:28 +0100 Subject: [PATCH 2/2] gh-128883: Store ELF perf trampoline templates in read-only data CPython copies the trampoline templates into executable memory. Keep the ELF source in .rodata so BOLT preserves its bytes and boundaries. --- Lib/test/test_perf_profiler.py | 5 ----- .../2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst | 4 ++-- Python/asm_trampoline_aarch64.S | 6 +++++- Python/asm_trampoline_riscv64.S | 4 ++-- Python/asm_trampoline_x86_64.S | 6 +++++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 6c28947bdeabaaa..7fe16116b00b991 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -62,7 +62,6 @@ def tearDown(self) -> None: for file in files_to_delete: file.unlink() - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works(self): code = """if 1: def foo(): @@ -113,7 +112,6 @@ def baz(): "Address should contain only hex characters", ) - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_with_unencodable_name(self): code = """if 1: import sys @@ -123,7 +121,6 @@ def test_trampoline_with_unencodable_name(self): """ assert_python_ok("-c", code, PYTHON_JIT="0") - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works_with_forks(self): code = """if 1: import os, sys @@ -193,7 +190,6 @@ def baz(): self.assertNotIn(f"py::bar:{script}", child_perf_file_contents) self.assertNotIn(f"py::baz:{script}", child_perf_file_contents) - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works_after_fork_with_many_code_objects(self): code = """if 1: import gc, os, sys, signal @@ -233,7 +229,6 @@ def test_trampoline_works_after_fork_with_many_code_objects(self): self.assertEqual(process.returncode, 0, stderr) self.assertEqual(stderr, "") - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_sys_api(self): for define_eval_hook in (False, True): code = """if 1: diff --git a/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst index f5b066d31ec71c1..e250415e72af144 100644 --- a/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst +++ b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst @@ -1,2 +1,2 @@ -Add a byte after the ELF perf trampoline end marker so it does not share -the following function's address, which BOLT may otherwise move. +Fix crashes with ``-X perf`` and ``-X perf_jit`` in BOLT builds. +The ELF perf trampoline templates now use read-only data sections. diff --git a/Python/asm_trampoline_aarch64.S b/Python/asm_trampoline_aarch64.S index aef34014ae85529..4052ea6e13edecc 100644 --- a/Python/asm_trampoline_aarch64.S +++ b/Python/asm_trampoline_aarch64.S @@ -35,7 +35,12 @@ #define GNU_PROPERTY_AARCH64_GCS 0 #endif +/* CPython copies this template into executable memory. */ +#if defined(__ELF__) + .section .rodata +#else .text +#endif #if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__) #if defined(__APPLE__) .globl __Py_trampoline_func_start @@ -57,7 +62,6 @@ __Py_trampoline_func_end: #else .globl _Py_trampoline_func_end _Py_trampoline_func_end: - .byte 0 .section .note.GNU-stack,"",@progbits #endif diff --git a/Python/asm_trampoline_riscv64.S b/Python/asm_trampoline_riscv64.S index 21aafbcf23d6f0a..7d32c904c995ece 100644 --- a/Python/asm_trampoline_riscv64.S +++ b/Python/asm_trampoline_riscv64.S @@ -1,4 +1,5 @@ - .text +/* CPython copies this template into executable memory. */ + .section .rodata .globl _Py_trampoline_func_start _Py_trampoline_func_start: addi sp,sp,-16 @@ -9,5 +10,4 @@ _Py_trampoline_func_start: jr ra .globl _Py_trampoline_func_end _Py_trampoline_func_end: - .byte 0 .section .note.GNU-stack,"",@progbits diff --git a/Python/asm_trampoline_x86_64.S b/Python/asm_trampoline_x86_64.S index e1a714413abfd42..0f83a4575828c23 100644 --- a/Python/asm_trampoline_x86_64.S +++ b/Python/asm_trampoline_x86_64.S @@ -1,4 +1,9 @@ +/* CPython copies this template into executable memory. */ +#if defined(__ELF__) + .section .rodata +#else .text +#endif #ifdef __x86_64__ #if defined(__APPLE__) .globl __Py_trampoline_func_start @@ -21,7 +26,6 @@ __Py_trampoline_func_end: #else .globl _Py_trampoline_func_end _Py_trampoline_func_end: - .byte 0 .section .note.GNU-stack,"",@progbits #endif # Note for indicating the assembly code supports CET