authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-05-26 12:35:37+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-05-26 12:35:37+02:00
log11bb8ab9b3cf832a5e391ac8c73cbc33221db19d
treeb7b1dbe0280a1843a515678f63955de1bc4c996e
parentb3747dd707eeaf06e0bacbde259bf71ef525a961
parent84a100b3e06afec33d4077052a50f8126396021f

Merge pull request 'std: initial `xtensa-linux-none` port' (#35463) from alexrp/zig:xtensa-linux into master

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

9 files changed, 260 insertions(+), 3 deletions(-)

lib/std/Thread.zig+10
......@@ -1411,6 +1411,16 @@ const LinuxThreadImpl = struct {
14111411 : [ptr] "{r4}" (@intFromPtr(self.mapped.ptr)),
14121412 [len] "{r5}" (self.mapped.len),
14131413 : .{ .memory = true }),
1414 .xtensa, .xtensaeb => asm volatile (
1415 \\ movi a2, 81 // SYS_munmap
1416 \\ syscall
1417 \\ movi a6, 0
1418 \\ movi a2, 118 // SYS_exit
1419 \\ syscall
1420 :
1421 : [ptr] "{a6}" (@intFromPtr(self.mapped.ptr)),
1422 [len] "{a3}" (self.mapped.len),
1423 : .{ .memory = true }),
14141424 else => |cpu_arch| @compileError("Unsupported linux arch: " ++ @tagName(cpu_arch)),
14151425 }
14161426 unreachable;
lib/std/debug.zig+2
......@@ -994,6 +994,8 @@ const StackIterator = union(enum) {
994994 .sh,
995995 .sheb,
996996 .xcore,
997 .xtensa,
998 .xtensaeb,
997999 => .useless,
9981000 .hexagon,
9991001 // The PowerPC ABIs don't actually strictly require a backchain pointer; they allow omitting
lib/std/elf.zig+3
......@@ -224,6 +224,9 @@ pub const DT_PPC64_NUM = 4;
224224pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0);
225225pub const DT_IA_64_NUM = 1;
226226
227pub const DT_XTENSA_GOT_LOC_OFF = 0x70000000;
228pub const DT_XTENSA_GOT_LOC_SZ = 0x70000001;
229
227230pub const DT_NIOS2_GP = 0x70000002;
228231
229232pub const DF_ORIGIN = 0x00000001;
lib/std/os.zig-3
......@@ -28,9 +28,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool {
2828 .sheb,
2929 // https://codeberg.org/ziglang/zig/issues/30945
3030 .sparc,
31 // https://codeberg.org/ziglang/zig/issues/30947
32 .xtensa,
33 .xtensaeb,
3431 => true,
3532 else => false,
3633 },
lib/std/os/linux.zig+32
......@@ -56,6 +56,7 @@ const arch_bits = switch (native_arch) {
5656 .gnux32, .muslx32 => @import("linux/x32.zig"),
5757 else => @import("linux/x86_64.zig"),
5858 },
59 .xtensa, .xtensaeb => @import("linux/xtensa.zig"),
5960 else => struct {},
6061};
6162
......@@ -338,6 +339,29 @@ pub const MAP = switch (native_arch) {
338339 _20: u1 = 0,
339340 _: u5 = 0,
340341 },
342 .xtensa, .xtensaeb => packed struct(u32) {
343 TYPE: MAP_TYPE,
344 FIXED: bool = false,
345 _RENAME: bool = false,
346 _AUTOGROW: bool = false,
347 _LOCAL: bool = false,
348 _AUTORSRV: bool = false,
349 _1: u1 = 0,
350 NORESERVE: bool = false,
351 ANONYMOUS: bool = false,
352 GROWSDOWN: bool = false,
353 DENYWRITE: bool = false,
354 EXECUTABLE: bool = false,
355 LOCKED: bool = false,
356 POPULATE: bool = false,
357 NONBLOCK: bool = false,
358 STACK: bool = false,
359 HUGETLB: bool = false,
360 FIXED_NOREPLACE: bool = false,
361 _2: u5 = 0,
362 UNINITIALIZED: bool = false,
363 _3: u5 = 0,
364 },
341365 else => @compileError("missing std.os.linux.MAP constants for this architecture"),
342366};
343367
......@@ -497,6 +521,8 @@ pub const O = switch (native_arch) {
497521 .hexagon,
498522 .or1k,
499523 .s390x,
524 .xtensa,
525 .xtensaeb,
500526 => packed struct(u32) {
501527 ACCMODE: ACCMODE = .RDONLY,
502528 _2: u4 = 0,
......@@ -6617,6 +6643,12 @@ pub const k_sigaction = switch (native_arch) {
66176643 mask: sigset_t,
66186644 flags: c_int,
66196645 },
6646 .xtensa, .xtensaeb => extern struct {
6647 handler: k_sigaction_funcs.handler,
6648 mask: sigset_t,
6649 flags: c_ulong,
6650 restorer: k_sigaction_funcs.restorer,
6651 },
66206652 else => extern struct {
66216653 handler: k_sigaction_funcs.handler,
66226654 flags: c_ulong,
lib/std/os/linux/tls.zig+11
......@@ -78,6 +78,8 @@ const current_variant: Variant = switch (native_arch) {
7878 .sheb,
7979 .thumb,
8080 .thumbeb,
81 .xtensa,
82 .xtensaeb,
8183 => .I_original,
8284 .loongarch32,
8385 .loongarch64,
......@@ -152,6 +154,8 @@ const AbiTcb = switch (current_variant) {
152154 .sheb,
153155 .thumb,
154156 .thumbeb,
157 .xtensa,
158 .xtensaeb,
155159 => extern struct {
156160 /// This is offset by `current_dtv_offset`.
157161 dtv: usize,
......@@ -364,6 +368,13 @@ pub fn setThreadPointer(addr: usize) void {
364368 : [addr] "r" (addr),
365369 );
366370 },
371 .xtensa, .xtensaeb => {
372 asm volatile (
373 \\ wur %[addr], threadptr
374 :
375 : [addr] "a" (addr),
376 );
377 },
367378 else => @compileError("Unsupported architecture"),
368379 }
369380}
lib/std/os/linux/xtensa.zig created+171
......@@ -0,0 +1,171 @@
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub const syscall_arg_t = u32;
6
7pub fn syscall0(
8 number: SYS,
9) u32 {
10 return asm volatile ("syscall"
11 : [ret] "={a2}" (-> u32),
12 : [number] "{a2}" (@intFromEnum(number)),
13 : .{ .memory = true });
14}
15
16pub fn syscall1(
17 number: SYS,
18 arg1: syscall_arg_t,
19) u32 {
20 return asm volatile ("syscall"
21 : [ret] "={a2}" (-> u32),
22 : [number] "{a2}" (@intFromEnum(number)),
23 [arg1] "{a6}" (arg1),
24 : .{ .memory = true });
25}
26
27pub fn syscall2(
28 number: SYS,
29 arg1: syscall_arg_t,
30 arg2: syscall_arg_t,
31) u32 {
32 return asm volatile ("syscall"
33 : [ret] "={a2}" (-> u32),
34 : [number] "{a2}" (@intFromEnum(number)),
35 [arg1] "{a6}" (arg1),
36 [arg2] "{a3}" (arg2),
37 : .{ .memory = true });
38}
39
40pub fn syscall3(
41 number: SYS,
42 arg1: syscall_arg_t,
43 arg2: syscall_arg_t,
44 arg3: syscall_arg_t,
45) u32 {
46 return asm volatile ("syscall"
47 : [ret] "={a2}" (-> u32),
48 : [number] "{a2}" (@intFromEnum(number)),
49 [arg1] "{a6}" (arg1),
50 [arg2] "{a3}" (arg2),
51 [arg3] "{a4}" (arg3),
52 : .{ .memory = true });
53}
54
55pub fn syscall4(
56 number: SYS,
57 arg1: syscall_arg_t,
58 arg2: syscall_arg_t,
59 arg3: syscall_arg_t,
60 arg4: syscall_arg_t,
61) u32 {
62 return asm volatile ("syscall"
63 : [ret] "={a2}" (-> u32),
64 : [number] "{a2}" (@intFromEnum(number)),
65 [arg1] "{a6}" (arg1),
66 [arg2] "{a3}" (arg2),
67 [arg3] "{a4}" (arg3),
68 [arg4] "{a5}" (arg4),
69 : .{ .memory = true });
70}
71
72pub fn syscall5(
73 number: SYS,
74 arg1: syscall_arg_t,
75 arg2: syscall_arg_t,
76 arg3: syscall_arg_t,
77 arg4: syscall_arg_t,
78 arg5: syscall_arg_t,
79) u32 {
80 return asm volatile ("syscall"
81 : [ret] "={a2}" (-> u32),
82 : [number] "{a2}" (@intFromEnum(number)),
83 [arg1] "{a6}" (arg1),
84 [arg2] "{a3}" (arg2),
85 [arg3] "{a4}" (arg3),
86 [arg4] "{a5}" (arg4),
87 [arg5] "{a8}" (arg5),
88 : .{ .memory = true });
89}
90
91pub fn syscall6(
92 number: SYS,
93 arg1: syscall_arg_t,
94 arg2: syscall_arg_t,
95 arg3: syscall_arg_t,
96 arg4: syscall_arg_t,
97 arg5: syscall_arg_t,
98 arg6: syscall_arg_t,
99) u32 {
100 return asm volatile ("syscall"
101 : [ret] "={a2}" (-> u32),
102 : [number] "{a2}" (@intFromEnum(number)),
103 [arg1] "{a6}" (arg1),
104 [arg2] "{a3}" (arg2),
105 [arg3] "{a4}" (arg3),
106 [arg4] "{a5}" (arg4),
107 [arg5] "{a8}" (arg5),
108 [arg6] "{a9}" (arg6),
109 : .{ .memory = true });
110}
111
112pub fn clone() callconv(.naked) u32 {
113 // __clone(func, stack, flags, arg, ptid, tls, ctid)
114 // a2, a3, a4, a5, a6, a7, +16
115 //
116 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
117 // a2 a6, a3, a4, a5, a8
118 asm volatile (
119 \\ entry sp, 16
120 \\
121 \\ movi a8, -16
122 \\ and a3, a3, a8
123 \\
124 \\ mov a9, a2
125 \\ mov a10, a5
126 \\
127 \\ mov a5, a7
128 \\ mov a8, a6
129 \\ mov a6, a4
130 \\ mov a4, a8
131 \\ l32i a8, sp, 16
132 \\ movi a2, 116 // SYS_clone
133 \\ syscall
134 \\
135 \\ beqz a2, 1f
136 \\ // parent
137 \\ retw
138 \\
139 \\ // child
140 \\1:
141 \\ movi a7, 0
142 \\ movi a0, 0
143 \\
144 \\ mov a2, a10
145 \\ callx0 a9
146 \\ movi a2, 118 // SYS_exit
147 \\ syscall
148 );
149}
150
151pub const restore = restore_rt;
152
153pub fn restore_rt() callconv(.naked) noreturn {
154 switch (builtin.zig_backend) {
155 .stage2_c => asm volatile (
156 \\ movi a2, %[number]
157 \\ syscall
158 :
159 : [number] "I" (@intFromEnum(SYS.rt_sigreturn)),
160 ),
161 else => asm volatile (
162 \\ syscall
163 :
164 : [number] "{a2}" (@intFromEnum(SYS.rt_sigreturn)),
165 ),
166 }
167}
168
169pub const VDSO = void;
170
171pub const time_t = i32;
lib/std/pie.zig+21
......@@ -22,6 +22,7 @@ const R_RISCV_RELATIVE = 3;
2222const R_390_RELATIVE = 12;
2323const R_SH_RELATIVE = 165;
2424const R_SPARC_RELATIVE = 22;
25const R_XTENSA_RELATIVE = 5;
2526
2627const R_RELATIVE = switch (builtin.cpu.arch) {
2728 .x86 => R_386_RELATIVE,
......@@ -43,6 +44,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
4344 .s390x => R_390_RELATIVE,
4445 .sh, .sheb => R_SH_RELATIVE,
4546 .sparc, .sparc64 => R_SPARC_RELATIVE,
47 .xtensa, .xtensaeb => R_XTENSA_RELATIVE,
4648 else => @compileError("Missing R_RELATIVE definition for this target"),
4749};
4850
......@@ -261,6 +263,25 @@ inline fn getDynamicSymbol() [*]const elf.Dyn {
261263 : [ret] "=r" (-> [*]const elf.Dyn),
262264 :
263265 : .{ .l7 = true }),
266 .xtensa, .xtensaeb => asm volatile (
267 \\ .weak _DYNAMIC
268 \\ .hidden _DYNAMIC
269 // Set things up such that after the `call0`, `a0` will point 1 byte before the
270 // embedded constant. Note that `call0` is a 3-byte instruction, so we need both
271 // `.balign` directives to be safe.
272 \\ .balign 4
273 \\ .begin no-transform
274 \\ call0 1f
275 \\ .end no-transform
276 \\ .balign 4
277 \\ .word _DYNAMIC - .
278 \\1:
279 \\ add a0, a0, 1
280 \\ l32i a8, a0, 0
281 \\ add %[ret], a0, a8
282 : [ret] "=a" (-> [*]const elf.Dyn),
283 :
284 : .{ .a0 = true, .a8 = true }),
264285 else => {
265286 @compileError("PIE startup is not yet supported for this target!");
266287 },
lib/std/start.zig+10
......@@ -183,6 +183,7 @@ fn _start() callconv(.naked) noreturn {
183183 .sparc, .sparc64 => ".cfi_undefined %%i7",
184184 .x86 => ".cfi_undefined %%eip",
185185 .x86_64 => ".cfi_undefined %%rip",
186 .xtensa, .xtensaeb => "", // No CFI support.
186187 else => @compileError("unsupported arch"),
187188 });
188189
......@@ -486,6 +487,15 @@ fn _start() callconv(.naked) noreturn {
486487 \\ sub %%sp, 2047, %%sp
487488 \\ ba,a %[posixCallMainAndExit]
488489 ,
490 .xtensa, .xtensaeb =>
491 // a0 = LR, a7 = FP, a1 = SP
492 \\ movi a0, 0
493 \\ movi a7, 0
494 \\ mov a2, sp
495 \\ movi a8, -16
496 \\ and sp, sp, a8
497 \\ callx0 %[posixCallMainAndExit]
498 ,
489499 else => @compileError("unsupported arch"),
490500 }
491501 :