authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-03-20 02:04:25+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-03-20 02:04:25+01:00
log30de1678a624bb90a8664a10f8c15a81382f749e
treeab01359deb50211c32316f7352bfc61991864dd5
parent10d523f068ba0e2a0fcde1e03bc525d0be502bd0
parenteeb62ef3465702d54dd0c064c913b40c7b5b927f

Merge pull request 'basic `loongarch32-linux` support' (#31587) from alexrp/zig:loongarch32 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31587

5 files changed, 162 insertions(+), 4 deletions(-)

lib/std/debug/SelfInfo/Elf.zig+1
...@@ -118,6 +118,7 @@ pub const can_unwind: bool = s: {...@@ -118,6 +118,7 @@ pub const can_unwind: bool = s: {
118 .aarch64_be,118 .aarch64_be,
119 .arc,119 .arc,
120 .csky,120 .csky,
121 .loongarch32,
121 .loongarch64,122 .loongarch64,
122 .m68k,123 .m68k,
123 .mips,124 .mips,
lib/std/debug/cpu_context.zig+12-1
...@@ -51,6 +51,16 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {...@@ -51,6 +51,16 @@ pub fn fromPosixSignalContext(ctx_ptr: ?*const anyopaque) ?Native {
51 std.mem.reverse(native.r[0..]);51 std.mem.reverse(native.r[0..]);
5252
53 return native;53 return native;
54 } else if (native_arch == .loongarch32 and native_os == .linux) {
55 // The 32-bit kABI (added later) kept the 64-bit layout.
56 return .{
57 .r = s: {
58 var regs: [32]LoongArch.Gpr = undefined;
59 for (uc.mcontext.r, 0..) |r, i| regs[i] = @truncate(r);
60 break :s regs;
61 },
62 .pc = @truncate(uc.mcontext.pc),
63 };
54 } else if (native_arch.isMIPS32() and native_os == .linux) {64 } else if (native_arch.isMIPS32() and native_os == .linux) {
55 // The O32 kABI uses 64-bit fields for some reason.65 // The O32 kABI uses 64-bit fields for some reason.
56 return .{66 return .{
...@@ -1754,6 +1764,7 @@ const signal_ucontext_t = switch (native_os) {...@@ -1754,6 +1764,7 @@ const signal_ucontext_t = switch (native_os) {
1754 .aarch64,1764 .aarch64,
1755 .aarch64_be,1765 .aarch64_be,
1756 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/ucontext.h1766 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/ucontext.h
1767 .loongarch32,
1757 .loongarch64,1768 .loongarch64,
1758 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/ucontext.h1769 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/powerpc/include/uapi/asm/ucontext.h
1759 .powerpc64,1770 .powerpc64,
...@@ -1777,7 +1788,7 @@ const signal_ucontext_t = switch (native_os) {...@@ -1777,7 +1788,7 @@ const signal_ucontext_t = switch (native_os) {
1777 pc: u64,1788 pc: u64,
1778 },1789 },
1779 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/sigcontext.h1790 // https://github.com/torvalds/linux/blob/cd5a0afbdf8033dc83786315d63f8b325bdba2fd/arch/loongarch/include/uapi/asm/sigcontext.h
1780 .loongarch64 => extern struct {1791 .loongarch32, .loongarch64 => extern struct {
1781 pc: u64 align(16),1792 pc: u64 align(16),
1782 r: [32]u64,1793 r: [32]u64,
1783 },1794 },
lib/std/os/linux.zig+5-2
...@@ -33,6 +33,7 @@ const arch_bits = switch (native_arch) {...@@ -33,6 +33,7 @@ const arch_bits = switch (native_arch) {
33 .aarch64, .aarch64_be => @import("linux/aarch64.zig"),33 .aarch64, .aarch64_be => @import("linux/aarch64.zig"),
34 .arm, .armeb, .thumb, .thumbeb => @import("linux/arm.zig"),34 .arm, .armeb, .thumb, .thumbeb => @import("linux/arm.zig"),
35 .hexagon => @import("linux/hexagon.zig"),35 .hexagon => @import("linux/hexagon.zig"),
36 .loongarch32 => @import("linux/loongarch32.zig"),
36 .loongarch64 => @import("linux/loongarch64.zig"),37 .loongarch64 => @import("linux/loongarch64.zig"),
37 .m68k => @import("linux/m68k.zig"),38 .m68k => @import("linux/m68k.zig"),
38 .mips, .mipsel => @import("linux/mips.zig"),39 .mips, .mipsel => @import("linux/mips.zig"),
...@@ -194,7 +195,7 @@ pub const MAP = switch (native_arch) {...@@ -194,7 +195,7 @@ pub const MAP = switch (native_arch) {
194 UNINITIALIZED: bool = false,195 UNINITIALIZED: bool = false,
195 _: u5 = 0,196 _: u5 = 0,
196 },197 },
197 .riscv32, .riscv64, .loongarch64 => packed struct(u32) {198 .riscv32, .riscv64, .loongarch32, .loongarch64 => packed struct(u32) {
198 TYPE: MAP_TYPE,199 TYPE: MAP_TYPE,
199 FIXED: bool = false,200 FIXED: bool = false,
200 ANONYMOUS: bool = false,201 ANONYMOUS: bool = false,
...@@ -330,7 +331,7 @@ pub const O = switch (native_arch) {...@@ -330,7 +331,7 @@ pub const O = switch (native_arch) {
330 TMPFILE: bool = false,331 TMPFILE: bool = false,
331 _23: u9 = 0,332 _23: u9 = 0,
332 },333 },
333 .x86, .riscv32, .riscv64, .loongarch64 => packed struct(u32) {334 .x86, .riscv32, .riscv64, .loongarch32, .loongarch64 => packed struct(u32) {
334 ACCMODE: ACCMODE = .RDONLY,335 ACCMODE: ACCMODE = .RDONLY,
335 _2: u4 = 0,336 _2: u4 = 0,
336 CREAT: bool = false,337 CREAT: bool = false,
...@@ -6345,6 +6346,7 @@ pub const MINSIGSTKSZ = switch (native_arch) {...@@ -6345,6 +6346,7 @@ pub const MINSIGSTKSZ = switch (native_arch) {
6345 .xtensa,6346 .xtensa,
6346 .xtensaeb,6347 .xtensaeb,
6347 => 2048,6348 => 2048,
6349 .loongarch32,
6348 .loongarch64,6350 .loongarch64,
6349 .sparc,6351 .sparc,
6350 .sparc64,6352 .sparc64,
...@@ -6384,6 +6386,7 @@ pub const SIGSTKSZ = switch (native_arch) {...@@ -6384,6 +6386,7 @@ pub const SIGSTKSZ = switch (native_arch) {
6384 => 8192,6386 => 8192,
6385 .aarch64,6387 .aarch64,
6386 .aarch64_be,6388 .aarch64_be,
6389 .loongarch32,
6387 .loongarch64,6390 .loongarch64,
6388 .sparc,6391 .sparc,
6389 .sparc64,6392 .sparc64,
lib/std/os/linux/loongarch32.zig created+135
...@@ -0,0 +1,135 @@
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub fn syscall0(number: SYS) u32 {
6 return asm volatile (
7 \\ syscall 0
8 : [ret] "={$r4}" (-> u32),
9 : [number] "{$r11}" (@intFromEnum(number)),
10 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
11}
12
13pub fn syscall1(number: SYS, arg1: u32) u32 {
14 return asm volatile (
15 \\ syscall 0
16 : [ret] "={$r4}" (-> u32),
17 : [number] "{$r11}" (@intFromEnum(number)),
18 [arg1] "{$r4}" (arg1),
19 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
20}
21
22pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 {
23 return asm volatile (
24 \\ syscall 0
25 : [ret] "={$r4}" (-> u32),
26 : [number] "{$r11}" (@intFromEnum(number)),
27 [arg1] "{$r4}" (arg1),
28 [arg2] "{$r5}" (arg2),
29 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
30}
31
32pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 {
33 return asm volatile (
34 \\ syscall 0
35 : [ret] "={$r4}" (-> u32),
36 : [number] "{$r11}" (@intFromEnum(number)),
37 [arg1] "{$r4}" (arg1),
38 [arg2] "{$r5}" (arg2),
39 [arg3] "{$r6}" (arg3),
40 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
41}
42
43pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 {
44 return asm volatile (
45 \\ syscall 0
46 : [ret] "={$r4}" (-> u32),
47 : [number] "{$r11}" (@intFromEnum(number)),
48 [arg1] "{$r4}" (arg1),
49 [arg2] "{$r5}" (arg2),
50 [arg3] "{$r6}" (arg3),
51 [arg4] "{$r7}" (arg4),
52 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
53}
54
55pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 {
56 return asm volatile (
57 \\ syscall 0
58 : [ret] "={$r4}" (-> u32),
59 : [number] "{$r11}" (@intFromEnum(number)),
60 [arg1] "{$r4}" (arg1),
61 [arg2] "{$r5}" (arg2),
62 [arg3] "{$r6}" (arg3),
63 [arg4] "{$r7}" (arg4),
64 [arg5] "{$r8}" (arg5),
65 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
66}
67
68pub fn syscall6(
69 number: SYS,
70 arg1: u32,
71 arg2: u32,
72 arg3: u32,
73 arg4: u32,
74 arg5: u32,
75 arg6: u32,
76) u32 {
77 return asm volatile (
78 \\ syscall 0
79 : [ret] "={$r4}" (-> u32),
80 : [number] "{$r11}" (@intFromEnum(number)),
81 [arg1] "{$r4}" (arg1),
82 [arg2] "{$r5}" (arg2),
83 [arg3] "{$r6}" (arg3),
84 [arg4] "{$r7}" (arg4),
85 [arg5] "{$r8}" (arg5),
86 [arg6] "{$r9}" (arg6),
87 : .{ .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r16 = true, .r17 = true, .r18 = true, .r19 = true, .r20 = true, .memory = true });
88}
89
90// FIXME
91pub fn clone() callconv(.naked) u32 {
92 // __clone(func, stack, flags, arg, ptid, tls, ctid)
93 // a0, a1, a2, a3, a4, a5, a6
94 // sys_clone(flags, stack, ptid, ctid, tls)
95 // a0, a1, a2, a3, a4
96 asm volatile (
97 \\ srli.w $a1, $a1, 4
98 \\ slli.w $a1, $a1, 4
99 \\
100 \\ # Save function pointer and argument pointer on new thread stack
101 \\ addi.w $a1, $a1, -16
102 \\ st.w $a0, $a1, 0 # save function pointer
103 \\ st.w $a3, $a1, 4 # save argument pointer
104 \\ or $a0, $a2, $zero
105 \\ or $a2, $a4, $zero
106 \\ or $a3, $a6, $zero
107 \\ or $a4, $a5, $zero
108 \\ ori $a7, $zero, 220 # SYS_clone
109 \\ syscall 0
110 \\
111 \\ beq $a0, $zero, 1f
112 \\ jirl $zero, $ra, 0
113 \\1:
114 );
115 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
116 \\ .cfi_undefined 1
117 );
118 asm volatile (
119 \\ move $fp, $zero
120 \\ move $ra, $zero
121 \\
122 \\ ld.w $t8, $sp, 0 # function pointer
123 \\ ld.w $a0, $sp, 4 # argument pointer
124 \\ jirl $ra, $t8, 0 # call the user's function
125 \\ ori $a7, $zero, 93 # SYS_exit
126 \\ syscall 0 # child process exit
127 );
128}
129
130pub const time_t = i64;
131
132pub const VDSO = struct {
133 pub const CGT_SYM = "__vdso_clock_gettime";
134 pub const CGT_VER = "LINUX_5.10";
135};
lib/std/start.zig+9-1
...@@ -276,7 +276,15 @@ fn _start() callconv(.naked) noreturn {...@@ -276,7 +276,15 @@ fn _start() callconv(.naked) noreturn {
276 \\ ;;276 \\ ;;
277 \\ goto %[posixCallMainAndExit]277 \\ goto %[posixCallMainAndExit]
278 ,278 ,
279 .loongarch32, .loongarch64 =>279 .loongarch32 =>
280 \\ move $fp, $zero
281 \\ move $ra, $zero
282 \\ move $a0, $sp
283 \\ srli.w $sp, $sp, 4
284 \\ slli.w $sp, $sp, 4
285 \\ b %[posixCallMainAndExit]
286 ,
287 .loongarch64 =>
280 \\ move $fp, $zero288 \\ move $fp, $zero
281 \\ move $ra, $zero289 \\ move $ra, $zero
282 \\ move $a0, $sp290 \\ move $a0, $sp