Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lang/lua/luajit2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luajit2
PKG_SOURCE_DATE:=2026-02-27
PKG_VERSION:=2.1.$(subst -,.,$(PKG_SOURCE_DATE))
PKG_RELEASE:=1
PKG_RELEASE:=2

PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/openresty/luajit2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
From 2b0b4f7fdb5fdefd13c5cbdeb159881da3098c96 Mon Sep 17 00:00:00 2001
From: Josef Schlehofer <pepe.schlehofer@gmail.com>
Date: Sat, 15 Aug 2026 09:11:08 +0200
Subject: [PATCH] PPC: Fix ipairs() on soft-float targets

The soft-float branch of the ipairs_aux fast function loads the array
slot value from WORD_HI instead of WORD_LO. On big-endian targets,
WORD_HI contains the itype while the value word is in WORD_LO, so the
itype is loaded twice and the actual value is never loaded.

Every element therefore comes back carrying the itype in its payload.
Numbers surface as -14, the LJ_TNUMX tag read as an int32. For GC
types the payload is the GCref, so the tag becomes a fabricated
pointer that tostring() then dereferences.

The original soft-float code used a hardcoded 4(TMP1), which is
WORD_LO on big-endian. Commit 2763a421 ("Patch for PPC64 support")
rewrote it as WORD_HI. Upstream LuaJIT is unaffected.

Reproducer on Turris 1.x (e500v2, 32-bit big-endian, soft-float):

$ luajit -e 'local s=0 for i,v in ipairs({10,20,30}) do s=s+v end print(s)'
-42 -- expected 60

Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
---
src/vm_ppc.dasc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

--- a/src/vm_ppc.dasc
+++ b/src/vm_ppc.dasc
@@ -1833,7 +1833,7 @@ static void build_subroutines(BuildCtx *
| lwz TMP2, WORD_HI(TMP1)
|.else
| lwzux TMP2, TMP1, TMP3
- | lwz TMP3, WORD_HI(TMP1)
+ | lwz TMP3, WORD_LO(TMP1)
|.endif
|1:
| checknil TMP2
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
From 0abde25c632e6b3343d07d978d9cc4209fe05f58 Mon Sep 17 00:00:00 2001
From: Josef Schlehofer <pepe.schlehofer@gmail.com>
Date: Sat, 15 Aug 2026 09:11:08 +0200
Subject: [PATCH] PPC: Fix pairs() over hash-less tables on soft-float targets

BC_ITERN checks the itype of the node value in RB to skip empty slots
in the hash part. Upstream loads RB unconditionally before the FPU
split; commit 2763a421 ("Patch for PPC64 support") moved that load
into the FPU branch only. On soft-float builds, RB still contains
RC*8 from the hash-part setup, so the nil check never succeeds and
iterating a table whose hash part is empty yields one extra
(nil, nil) pair.

Check CARG1 instead, which the soft-float branch already loads with
the itype. The FPU branch is left untouched. Upstream LuaJIT is
unaffected.

Reproducer on Turris 1.x (e500v2, 32-bit big-endian, soft-float):

$ luajit -e 'for k,v in pairs({7,8,9}) do print(k,v) end'
1 7
2 8
3 9
nil nil -- spurious

Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
---
src/vm_ppc.dasc | 4 ++++
1 file changed, 4 insertions(+)

--- a/src/vm_ppc.dasc
+++ b/src/vm_ppc.dasc
@@ -5807,7 +5807,11 @@ static void build_ins(BuildCtx *ctx, BCO
| lwz CARG2, 4(CARG3)
| add NODE:TMP3, TMP2, TMP3
|.endif
+ |.if FPU
| checknil RB
+ |.else
+ | checknil CARG1
+ |.endif
| lwz INS, -4(PC)
| beq >7
|.if FPU
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
From 3bc16e0b58704b8c3bd596b23d907516c7cc2493 Mon Sep 17 00:00:00 2001
From: Clint Bland <bland.cr@gmail.com>
Date: Thu, 14 Mar 2019 02:19:16 +0000
Subject: [PATCH] PPC: Call libm helpers via private GOT instead of the PLT

A bl sym@plt call emitted by the VM assembler produces an
R_PPC_PLTREL24 relocation with addend 0, which forces the linker to
use BSS-PLT for the entire link. GCC 12 and newer emit inline-PLT
relocations (R_PPC_PLTSEQ, R_PPC_PLTCALL, R_PPC_PLT16_*) that have no
BSS-PLT equivalent, so linking libluajit.so fails outright:

ld: bss-plt forced due to lj_vm.o
ld: crtstuff.c:(.text+0x46): R_PPC_PLT16_HA relocation unsupported
for bss-plt

Route these calls through a private GOT stored in GG_State, the way
the MIPS port already does. No PLT relocation is emitted, the linker
selects secure-PLT and the link succeeds.

Originally submitted upstream as LuaJIT/LuaJIT#486, against 2.0 and
addressing LuaJIT/LuaJIT#481, and closed without being merged. OpenWrt
has carried it for the upstream luajit package as 060-ppc-musl.patch
since 2019, extended with the soft-float helpers the 2.1 branch needs
in the GOT. Adapted here for luajit2 and verified on OpenWrt.

Tested on Turris 1.x (e500v2, 32-bit big-endian, musl, soft-float)
with BUILDMODE=dynamic. No R_PPC_PLTREL24 relocations remain, and the
resulting binary runs correctly, including all libm calls routed
through the new GOT. The previously produced dynamic binary crashed
during startup.

Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
---
src/lj_dispatch.c | 11 ++++++++++-
src/lj_dispatch.h | 32 +++++++++++++++++++++++++++++++-
src/vm_ppc.dasc | 12 +++++++++++-
3 files changed, 52 insertions(+), 3 deletions(-)

--- a/src/lj_dispatch.c
+++ b/src/lj_dispatch.c
@@ -56,6 +56,15 @@ static const ASMFunction dispatch_got[]
#undef GOTFUNC
#endif

+#if LJ_TARGET_PPC && LJ_32
+#include <math.h>
+#define GOTFUNC(name) (ASMFunction)name,
+static const ASMFunction dispatch_got[] = {
+ GOTDEF(GOTFUNC)
+};
+#undef GOTFUNC
+#endif
+
/* Initialize instruction dispatch table and hot counters. */
void lj_dispatch_init(GG_State *GG)
{
@@ -76,7 +85,7 @@ void lj_dispatch_init(GG_State *GG)
GG->g.bc_cfunc_ext = GG->g.bc_cfunc_int = BCINS_AD(BC_FUNCC, LUA_MINSTACK, 0);
for (i = 0; i < GG_NUM_ASMFF; i++)
GG->bcff[i] = BCINS_AD(BC__MAX+i, 0, 0);
-#if LJ_TARGET_MIPS
+#if LJ_TARGET_MIPS || (LJ_TARGET_PPC && LJ_32)
memcpy(GG->got, dispatch_got, LJ_GOT__MAX*sizeof(ASMFunction *));
#endif
}
--- a/src/lj_dispatch.h
+++ b/src/lj_dispatch.h
@@ -66,6 +66,36 @@ GOTDEF(GOTENUM)
};
#endif

+#if LJ_TARGET_PPC && LJ_32
+/* Call libm/libgcc helpers via our own GOT instead of the PLT. A PLT call
+** from the VM assembler forces the obsolete BSS-PLT for the whole link,
+** which fails against secure-PLT objects emitted by GCC 12 and newer.
+*/
+#if LJ_SOFTFP
+#ifndef _LJ_IRCALL_H
+extern double __ledf2(double a, double b);
+extern double __adddf3(double a, double b);
+extern double __subdf3(double a, double b);
+extern double __muldf3(double a, double b);
+extern double __divdf3(double a, double b);
+#endif
+#define SFGOTDEF(_) _(__ledf2) _(__adddf3) _(__subdf3) _(__muldf3) _(__divdf3)
+#else
+#define SFGOTDEF(_)
+#endif
+#define GOTDEF(_) \
+ _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \
+ _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \
+ _(pow) _(fmod) _(ldexp) _(sqrt) SFGOTDEF(_)
+
+enum {
+#define GOTENUM(name) LJ_GOT_##name,
+GOTDEF(GOTENUM)
+#undef GOTENUM
+ LJ_GOT__MAX
+};
+#endif
+
/* Type of hot counter. Must match the code in the assembler VM. */
/* 16 bits are sufficient. Only 0.0015% overhead with maximum slot penalty. */
typedef uint16_t HotCount;
@@ -93,7 +123,7 @@ typedef struct GG_State {
/* Make g reachable via K12 encoded DISPATCH-relative addressing. */
uint8_t align1[(16-sizeof(global_State))&15];
#endif
-#if LJ_TARGET_MIPS
+#if LJ_TARGET_MIPS || (LJ_TARGET_PPC && LJ_32)
ASMFunction got[LJ_GOT__MAX]; /* Global offset table. */
#endif
#if LJ_HASJIT
--- a/src/vm_ppc.dasc
+++ b/src/vm_ppc.dasc
@@ -50,7 +50,13 @@
|.macro blex, target; bl extern target; nop; .endmacro
|.macro .toc, a, b; a, b; .endmacro
|.else
-|.macro blex, target; bl extern target@plt; .endmacro
+|// Call via our own GOT to avoid PLT relocations, which force the obsolete
+|// BSS-PLT on PPC32 and break linking against secure-PLT objects.
+|.macro blex, target
+| lwz TMP0, DISPATCH_GOT(target)(DISPATCH)
+| mtctr TMP0
+| bctrl
+|.endmacro
|.macro .toc, a, b; .endmacro
|.endif
|.if OPD
@@ -577,6 +583,10 @@
|// Assumes DISPATCH is relative to GL.
#define DISPATCH_GL(field) (GG_DISP2G + (int)offsetof(global_State, field))
#define DISPATCH_J(field) (GG_DISP2J + (int)offsetof(jit_State, field))
+#if LJ_TARGET_PPC && LJ_32
+#define GG_DISP2GOT (GG_OFS(got) - GG_OFS(dispatch))
+#define DISPATCH_GOT(name) (GG_DISP2GOT + 4*LJ_GOT_##name)
+#endif
|
#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
|
Loading