Skip to content

Commit 109ffcd

Browse files
trivikraduh95
authored andcommitted
ffi: preserve link register in ppc64 trampoline
The ppc64 fast FFI trampoline uses `bl` to obtain the address used to load its target literal. This overwrites the caller's link register, so optimized FFI calls return into the trampoline and loop indefinitely. Save and restore the caller's link register around the branch. Also align the target literal for both even and odd GP argument counts. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol PR-URL: #64792 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent e0f0830 commit 109ffcd

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

‎src/ffi/platforms/ppc64.cc‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,21 @@ extern "C" bool node_ffi_create_fast_trampoline(
134134
}
135135

136136
// Load the target address from the literal pool into r12, then branch through
137-
// CTR. ELFv2 functions can use r12 to establish their TOC on global entry.
138-
Emit32(&cursor, Bl(1)); // bl .+4
139-
Emit32(&cursor, Mfspr(12, 8)); // mflr r12
140-
Emit32(&cursor, Ld(12, 12, 20)); // ld r12, literal-mflr(r12)
141-
Emit32(&cursor, Mtspr(9, 12)); // mtctr r12
142-
Emit32(&cursor, 0x4e800420); // bctr
143-
Emit32(&cursor, 0x60000000); // nop; align literal to 8 bytes
137+
// CTR. Save the caller's link register before using `bl` to obtain the
138+
// trampoline's address, and restore it before the tail branch so the native
139+
// target returns to V8 rather than back into the trampoline. ELFv2 functions
140+
// can use r12 to establish their TOC on global entry.
141+
Emit32(&cursor, Mfspr(0, 8)); // mflr r0
142+
Emit32(&cursor, Bl(1)); // bl .+4
143+
Emit32(&cursor, Mfspr(12, 8)); // mflr r12
144+
Emit32(&cursor, Mtspr(8, 0)); // mtlr r0
145+
constunsigned literal_offset = gp_count % 2 == 0 ? 24 : 20;
146+
Emit32(&cursor, Ld(12, 12, literal_offset));
147+
Emit32(&cursor, Mtspr(9, 12)); // mtctr r12
148+
Emit32(&cursor, 0x4e800420); // bctr
149+
if (gp_count % 2 == 0) {
150+
Emit32(&cursor, 0x60000000); // nop; align literal to 8 bytes
151+
}
144152
Emit64(&cursor, reinterpret_cast<uintptr_t>(target));
145153

146154
constsize_t written = reinterpret_cast<uint8_t*>(cursor) -

0 commit comments

Comments
 (0)