From 57db8498df5db731e0680ec979e01da0c0eae2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 19 Mar 2026 19:41:44 +0100 Subject: [PATCH 1/3] start: add loongarch32 support --- lib/std/start.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/std/start.zig b/lib/std/start.zig index 9bc001fe598b5182943be40b85794ba95e7c7158..8d1b793cbb14ec0f84c6198a2e4215cd1bfb1cf1 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -276,7 +276,15 @@ fn _start() callconv(.naked) noreturn { \\ ;; \\ goto %[posixCallMainAndExit] , - .loongarch32, .loongarch64 => + .loongarch32 => + \\ move $fp, $zero + \\ move $ra, $zero + \\ move $a0, $sp + \\ srli.w $sp, $sp, 4 + \\ slli.w $sp, $sp, 4 + \\ b %[posixCallMainAndExit] + , + .loongarch64 => \\ move $fp, $zero \\ move $ra, $zero \\ move $a0, $sp -- 2.54.0 From a62d8e332330dbae2681bca6ca353dd26c9c7b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 19 Mar 2026 19:52:11 +0100 Subject: [PATCH 2/3] std.os.linux: add loongarch32 arch bits closes https://codeberg.org/ziglang/zig/issues/30948 --- lib/std/os/linux.zig | 7 +- lib/std/os/linux/loongarch32.zig | 135 +++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 lib/std/os/linux/loongarch32.zig diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index c8ee085e2d407bf4cd1381799d52a19339b69ad2..9cd050d8cda42b2a57e80bc3f3f704602f4fe196 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -33,6 +33,7 @@ const arch_bits = switch (native_arch) { .aarch64, .aarch64_be => @import("linux/aarch64.zig"), .arm, .armeb, .thumb, .thumbeb => @import("linux/arm.zig"), .hexagon => @import("linux/hexagon.zig"), + .loongarch32 => @import("linux/loongarch32.zig"), .loongarch64 => @import("linux/loongarch64.zig"), .m68k => @import("linux/m68k.zig"), .mips, .mipsel => @import("linux/mips.zig"), @@ -194,7 +195,7 @@ pub const MAP = switch (native_arch) { UNINITIALIZED: bool = false, _: u5 = 0, }, - .riscv32, .riscv64, .loongarch64 => packed struct(u32) { + .riscv32, .riscv64, .loongarch32, .loongarch64 => packed struct(u32) { TYPE: MAP_TYPE, FIXED: bool = false, ANONYMOUS: bool = false, @@ -330,7 +331,7 @@ pub const O = switch (native_arch) { TMPFILE: bool = false, _23: u9 = 0, }, - .x86, .riscv32, .riscv64, .loongarch64 => packed struct(u32) { + .x86, .riscv32, .riscv64, .loongarch32, .loongarch64 => packed struct(u32) { ACCMODE: ACCMODE = .RDONLY, _2: u4 = 0, CREAT: bool = false, @@ -6345,6 +6346,7 @@ pub const MINSIGSTKSZ = switch (native_arch) { .xtensa, .xtensaeb, => 2048, + .loongarch32, .loongarch64, .sparc, .sparc64, @@ -6384,6 +6386,7 @@ pub const SIGSTKSZ = switch (native_arch) { => 8192, .aarch64, .aarch64_be, + .loongarch32, .loongarch64, .sparc, .sparc64, diff --git a/lib/std/os/linux/loongarch32.zig b/lib/std/os/linux/loongarch32.zig new file mode 100644 index 0000000000000000000000000000000000000000..5d4fc1512ba692674b5c8323f41b69a7ced37fe0 --- /dev/null +++ b/lib/std/os/linux/loongarch32.zig @@ -0,0 +1,135 @@ +const builtin = @import("builtin"); +const std = @import("../../std.zig"); +const SYS = std.os.linux.SYS; + +pub fn syscall0(number: SYS) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall1(number: SYS, arg1: u32) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + [arg5] "{$r8}" (arg5), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +pub fn syscall6( + number: SYS, + arg1: u32, + arg2: u32, + arg3: u32, + arg4: u32, + arg5: u32, + arg6: u32, +) u32 { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> u32), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + [arg5] "{$r8}" (arg5), + [arg6] "{$r9}" (arg6), + : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true }); +} + +// FIXME +pub fn clone() callconv(.naked) u32 { + // __clone(func, stack, flags, arg, ptid, tls, ctid) + // a0, a1, a2, a3, a4, a5, a6 + // sys_clone(flags, stack, ptid, ctid, tls) + // a0, a1, a2, a3, a4 + asm volatile ( + \\ srli.w $a1, $a1, 4 + \\ slli.w $a1, $a1, 4 + \\ + \\ # Save function pointer and argument pointer on new thread stack + \\ addi.w $a1, $a1, -16 + \\ st.w $a0, $a1, 0 # save function pointer + \\ st.w $a3, $a1, 4 # save argument pointer + \\ or $a0, $a2, $zero + \\ or $a2, $a4, $zero + \\ or $a3, $a6, $zero + \\ or $a4, $a5, $zero + \\ ori $a7, $zero, 220 # SYS_clone + \\ syscall 0 + \\ + \\ beq $a0, $zero, 1f + \\ jirl $zero, $ra, 0 + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined 1 + ); + asm volatile ( + \\ move $fp, $zero + \\ move $ra, $zero + \\ + \\ ld.w $t8, $sp, 0 # function pointer + \\ ld.w $a0, $sp, 4 # argument pointer + \\ jirl $ra, $t8, 0 # call the user's function + \\ ori $a7, $zero, 93 # SYS_exit + \\ syscall 0 # child process exit + ); +} + +pub const time_t = i64; + +pub const VDSO = struct { + pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_VER = "LINUX_5.10"; +}; -- 2.54.0 From eeb62ef3465702d54dd0c064c913b40c7b5b927f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Thu, 19 Mar 2026 19:15:52 +0100 Subject: [PATCH 3/3] std.debug.cpu_context: add loongarch32-linux support --- lib/std/debug/SelfInfo/Elf.zig | 1 + lib/std/debug/cpu_context.zig | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index a264b1170db05e5ee5510b75b0bdf354e3ae3026..263f292e9964f32cd16edd1c1519ccdd354d076e 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -118,6 +118,7 @@ pub const can_unwind: bool = s: { .aarch64_be, .arc, .csky, + .loongarch32, .loongarch64, .m68k, .mips, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index de8baffea4d1fd6a01cc3cac94f9e0490b427dd5..244765b9a7b9227285c97ac436c28aabb7eb3b2c 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -51,6 +51,16 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native { std.mem.reverse(native.r[0..]); return native; + } else if (native_arch == .loongarch32 and native_os == .linux) { + // The 32-bit kABI (added later) kept the 64-bit layout. + return .{ + .r = s: { + var regs: [32]LoongArch.Gpr = undefined; + for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r); + break :s regs; + }, + .pc = @truncate(uc.mcontext.pc), + }; } else if (native_arch.isMIPS32() and native_os == .linux) { // The O32 kABI uses 64-bit fields for some reason. return .{ @@ -1754,6 +1764,7 @@ const signal_ucontext_t = switch (native_os) { .aarch64, .aarch64_be, // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/ucontext.h + .loongarch32, .loongarch64, // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/ucontext.h .powerpc64, @@ -1777,7 +1788,7 @@ const signal_ucontext_t = switch (native_os) { pc: u64, }, // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/sigcontext.h - .loongarch64 => extern struct { + .loongarch32, .loongarch64 => extern struct { pc: u64 align(16), r: [32]u64, }, -- 2.54.0