diff --git a/src/ffi/platforms/ppc64.cc b/src/ffi/platforms/ppc64.cc index a0a53cfdb44363..78cd914405618c 100644 --- a/src/ffi/platforms/ppc64.cc +++ b/src/ffi/platforms/ppc64.cc @@ -134,13 +134,21 @@ extern "C" bool node_ffi_create_fast_trampoline( } // Load the target address from the literal pool into r12, then branch through - // CTR. ELFv2 functions can use r12 to establish their TOC on global entry. - Emit32(&cursor, Bl(1)); // bl .+4 - Emit32(&cursor, Mfspr(12, 8)); // mflr r12 - Emit32(&cursor, Ld(12, 12, 20)); // ld r12, literal-mflr(r12) - Emit32(&cursor, Mtspr(9, 12)); // mtctr r12 - Emit32(&cursor, 0x4e800420); // bctr - Emit32(&cursor, 0x60000000); // nop; align literal to 8 bytes + // CTR. Save the caller's link register before using `bl` to obtain the + // trampoline's address, and restore it before the tail branch so the native + // target returns to V8 rather than back into the trampoline. ELFv2 functions + // can use r12 to establish their TOC on global entry. + Emit32(&cursor, Mfspr(0, 8)); // mflr r0 + Emit32(&cursor, Bl(1)); // bl .+4 + Emit32(&cursor, Mfspr(12, 8)); // mflr r12 + Emit32(&cursor, Mtspr(8, 0)); // mtlr r0 + const unsigned literal_offset = gp_count % 2 == 0 ? 24 : 20; + Emit32(&cursor, Ld(12, 12, literal_offset)); + Emit32(&cursor, Mtspr(9, 12)); // mtctr r12 + Emit32(&cursor, 0x4e800420); // bctr + if (gp_count % 2 == 0) { + Emit32(&cursor, 0x60000000); // nop; align literal to 8 bytes + } Emit64(&cursor, reinterpret_cast(target)); const size_t written = reinterpret_cast(cursor) -