Skip to content

Commit b2762a1

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 4be571d commit b2762a1

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+
const unsigned 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
const size_t written = reinterpret_cast<uint8_t*>(cursor) -

0 commit comments

Comments
 (0)