Skip to content

Commit 8a0993f

Browse files
hugovkbrandtbucherFidget-Spinner
authored
[3.13] GH-146128: Remove the buggy AArch64 "33rx" relocation (#146263) (#148199)
GH-146128: Remove the buggy AArch64 "33rx" relocation (#146263) (cherry picked from commit 6bb7b33) Co-authored-by: Brandt Bucher <brandt@python.org> Co-authored-by: Ken Jin <kenjin@python.org>
1 parent 9f15d25 commit 8a0993f

File tree

4 files changed

+10
-96
lines changed

4 files changed

+10
-96
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a bug which could cause constant values to be partially corrupted in
2+
AArch64 JIT code. This issue is theoretical, and hasn't actually been
3+
observed in unmodified Python interpreters.

Python/jit.c

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,6 @@ patch_aarch64_12(unsigned char *location, uint64_t value)
220220
set_bits(loc32, 10, value, shift, 12);
221221
}
222222

223-
// Relaxable 12-bit low part of an absolute address. Pairs nicely with
224-
// patch_aarch64_21rx (below).
225-
void
226-
patch_aarch64_12x(unsigned char *location, uint64_t value)
227-
{
228-
// This can *only* be relaxed if it occurs immediately before a matching
229-
// patch_aarch64_21rx. If that happens, the JIT build step will replace both
230-
// calls with a single call to patch_aarch64_33rx. Otherwise, we end up
231-
// here, and the instruction is patched normally:
232-
patch_aarch64_12(location, value);
233-
}
234-
235223
// 16-bit low part of an absolute address.
236224
void
237225
patch_aarch64_16a(unsigned char *location, uint64_t value)
@@ -292,18 +280,6 @@ patch_aarch64_21r(unsigned char *location, uint64_t value)
292280
set_bits(loc32, 5, value, 2, 19);
293281
}
294282

295-
// Relaxable 21-bit count of pages between this page and an absolute address's
296-
// page. Pairs nicely with patch_aarch64_12x (above).
297-
void
298-
patch_aarch64_21rx(unsigned char *location, uint64_t value)
299-
{
300-
// This can *only* be relaxed if it occurs immediately before a matching
301-
// patch_aarch64_12x. If that happens, the JIT build step will replace both
302-
// calls with a single call to patch_aarch64_33rx. Otherwise, we end up
303-
// here, and the instruction is patched normally:
304-
patch_aarch64_21r(location, value);
305-
}
306-
307283
// 28-bit relative branch.
308284
void
309285
patch_aarch64_26r(unsigned char *location, uint64_t value)
@@ -319,46 +295,6 @@ patch_aarch64_26r(unsigned char *location, uint64_t value)
319295
set_bits(loc32, 0, value, 2, 26);
320296
}
321297

322-
// A pair of patch_aarch64_21rx and patch_aarch64_12x.
323-
void
324-
patch_aarch64_33rx(unsigned char *location, uint64_t value)
325-
{
326-
uint32_t *loc32 = (uint32_t *)location;
327-
// Try to relax the pair of GOT loads into an immediate value:
328-
assert(IS_AARCH64_ADRP(*loc32));
329-
unsigned char reg = get_bits(loc32[0], 0, 5);
330-
assert(IS_AARCH64_LDR_OR_STR(loc32[1]));
331-
// There should be only one register involved:
332-
assert(reg == get_bits(loc32[1], 0, 5)); // ldr's output register.
333-
assert(reg == get_bits(loc32[1], 5, 5)); // ldr's input register.
334-
uint64_t relaxed = *(uint64_t *)value;
335-
if (relaxed < (1UL << 16)) {
336-
// adrp reg, AAA; ldr reg, [reg + BBB] -> movz reg, XXX; nop
337-
loc32[0] = 0xD2800000 | (get_bits(relaxed, 0, 16) << 5) | reg;
338-
loc32[1] = 0xD503201F;
339-
return;
340-
}
341-
if (relaxed < (1ULL << 32)) {
342-
// adrp reg, AAA; ldr reg, [reg + BBB] -> movz reg, XXX; movk reg, YYY
343-
loc32[0] = 0xD2800000 | (get_bits(relaxed, 0, 16) << 5) | reg;
344-
loc32[1] = 0xF2A00000 | (get_bits(relaxed, 16, 16) << 5) | reg;
345-
return;
346-
}
347-
relaxed = value - (uintptr_t)location;
348-
if ((relaxed & 0x3) == 0 &&
349-
(int64_t)relaxed >= -(1L << 19) &&
350-
(int64_t)relaxed < (1L << 19))
351-
{
352-
// adrp reg, AAA; ldr reg, [reg + BBB] -> ldr reg, XXX; nop
353-
loc32[0] = 0x58000000 | (get_bits(relaxed, 2, 19) << 5) | reg;
354-
loc32[1] = 0xD503201F;
355-
return;
356-
}
357-
// Couldn't do it. Just patch the two instructions normally:
358-
patch_aarch64_21rx(location, value);
359-
patch_aarch64_12x(location + 4, value);
360-
}
361-
362298
// Relaxable 32-bit relative address.
363299
void
364300
patch_x86_64_32rx(unsigned char *location, uint64_t value)

Tools/jit/_stencils.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,29 @@ class HoleValue(enum.Enum):
5454
_PATCH_FUNCS = {
5555
# aarch64-apple-darwin:
5656
"ARM64_RELOC_BRANCH26": "patch_aarch64_26r",
57-
"ARM64_RELOC_GOT_LOAD_PAGE21": "patch_aarch64_21rx",
58-
"ARM64_RELOC_GOT_LOAD_PAGEOFF12": "patch_aarch64_12x",
57+
"ARM64_RELOC_GOT_LOAD_PAGE21": "patch_aarch64_21r",
58+
"ARM64_RELOC_GOT_LOAD_PAGEOFF12": "patch_aarch64_12",
5959
"ARM64_RELOC_PAGE21": "patch_aarch64_21r",
6060
"ARM64_RELOC_PAGEOFF12": "patch_aarch64_12",
6161
"ARM64_RELOC_UNSIGNED": "patch_64",
6262
# x86_64-pc-windows-msvc:
6363
"IMAGE_REL_AMD64_REL32": "patch_x86_64_32rx",
6464
# aarch64-pc-windows-msvc:
6565
"IMAGE_REL_ARM64_BRANCH26": "patch_aarch64_26r",
66-
"IMAGE_REL_ARM64_PAGEBASE_REL21": "patch_aarch64_21rx",
66+
"IMAGE_REL_ARM64_PAGEBASE_REL21": "patch_aarch64_21r",
6767
"IMAGE_REL_ARM64_PAGEOFFSET_12A": "patch_aarch64_12",
68-
"IMAGE_REL_ARM64_PAGEOFFSET_12L": "patch_aarch64_12x",
68+
"IMAGE_REL_ARM64_PAGEOFFSET_12L": "patch_aarch64_12",
6969
# i686-pc-windows-msvc:
7070
"IMAGE_REL_I386_DIR32": "patch_32",
7171
"IMAGE_REL_I386_REL32": "patch_x86_64_32rx",
7272
# aarch64-unknown-linux-gnu:
7373
"R_AARCH64_ABS64": "patch_64",
7474
"R_AARCH64_ADD_ABS_LO12_NC": "patch_aarch64_12",
75-
"R_AARCH64_ADR_GOT_PAGE": "patch_aarch64_21rx",
75+
"R_AARCH64_ADR_GOT_PAGE": "patch_aarch64_21r",
7676
"R_AARCH64_ADR_PREL_PG_HI21": "patch_aarch64_21r",
7777
"R_AARCH64_CALL26": "patch_aarch64_26r",
7878
"R_AARCH64_JUMP26": "patch_aarch64_26r",
79-
"R_AARCH64_LD64_GOT_LO12_NC": "patch_aarch64_12x",
79+
"R_AARCH64_LD64_GOT_LO12_NC": "patch_aarch64_12",
8080
"R_AARCH64_MOVW_UABS_G0_NC": "patch_aarch64_16a",
8181
"R_AARCH64_MOVW_UABS_G1_NC": "patch_aarch64_16b",
8282
"R_AARCH64_MOVW_UABS_G2_NC": "patch_aarch64_16c",
@@ -138,23 +138,6 @@ class Hole:
138138
def __post_init__(self) -> None:
139139
self.func = _PATCH_FUNCS[self.kind]
140140

141-
def fold(self, other: typing.Self) -> typing.Self | None:
142-
"""Combine two holes into a single hole, if possible."""
143-
if (
144-
self.offset + 4 == other.offset
145-
and self.value == other.value
146-
and self.symbol == other.symbol
147-
and self.addend == other.addend
148-
and self.func == "patch_aarch64_21rx"
149-
and other.func == "patch_aarch64_12x"
150-
):
151-
# These can *only* be properly relaxed when they appear together and
152-
# patch the same value:
153-
folded = self.replace()
154-
folded.func = "patch_aarch64_33rx"
155-
return folded
156-
return None
157-
158141
def as_c(self, where: str) -> str:
159142
"""Dump this hole as a call to a patch_* function."""
160143
location = f"{where} + {self.offset:#x}"

Tools/jit/_writer.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Utilities for writing StencilGroups out to a C header file."""
22

3-
import itertools
43
import typing
54

65
import _stencils
@@ -44,15 +43,8 @@ def _dump_stencil(opname: str, group: _stencils.StencilGroup) -> typing.Iterator
4443
for part, stencil in [("data", group.data), ("code", group.code)]:
4544
if stencil.body:
4645
yield f" memcpy({part}, {part}_body, sizeof({part}_body));"
47-
skip = False
4846
stencil.holes.sort(key=lambda hole: hole.offset)
49-
for hole, pair in itertools.zip_longest(stencil.holes, stencil.holes[1:]):
50-
if skip:
51-
skip = False
52-
continue
53-
if pair and (folded := hole.fold(pair)):
54-
skip = True
55-
hole = folded
47+
for hole in stencil.holes:
5648
yield f" {hole.as_c(part)}"
5749
yield "}"
5850
yield ""

0 commit comments

Comments
 (0)