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 {...@@ -1411,6 +1411,16 @@ const LinuxThreadImpl = struct {
1411 : [ptr] "{r4}" (@intFromPtr(self.mapped.ptr)),1411 : [ptr] "{r4}" (@intFromPtr(self.mapped.ptr)),
1412 [len] "{r5}" (self.mapped.len),1412 [len] "{r5}" (self.mapped.len),
1413 : .{ .memory = true }),1413 : .{ .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 }),
1414 else => |cpu_arch| @compileError("Unsupported linux arch: " ++ @tagName(cpu_arch)),1424 else => |cpu_arch| @compileError("Unsupported linux arch: " ++ @tagName(cpu_arch)),
1415 }1425 }
1416 unreachable;1426 unreachable;
lib/std/debug.zig+2
...@@ -994,6 +994,8 @@ const StackIterator = union(enum) {...@@ -994,6 +994,8 @@ const StackIterator = union(enum) {
994 .sh,994 .sh,
995 .sheb,995 .sheb,
996 .xcore,996 .xcore,
997 .xtensa,
998 .xtensaeb,
997 => .useless,999 => .useless,
998 .hexagon,1000 .hexagon,
999 // The PowerPC ABIs don't actually strictly require a backchain pointer; they allow omitting1001 // 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;...@@ -224,6 +224,9 @@ pub const DT_PPC64_NUM = 4;
224pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0);224pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0);
225pub const DT_IA_64_NUM = 1;225pub const DT_IA_64_NUM = 1;
226226
227pub const DT_XTENSA_GOT_LOC_OFF = 0x70000000;
228pub const DT_XTENSA_GOT_LOC_SZ = 0x70000001;
229
227pub const DT_NIOS2_GP = 0x70000002;230pub const DT_NIOS2_GP = 0x70000002;
228231
229pub const DF_ORIGIN = 0x00000001;232pub const DF_ORIGIN = 0x00000001;
lib/std/os.zig-3
...@@ -28,9 +28,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool {...@@ -28,9 +28,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool {
28 .sheb,28 .sheb,
29 // https://codeberg.org/ziglang/zig/issues/3094529 // https://codeberg.org/ziglang/zig/issues/30945
30 .sparc,30 .sparc,
31 // https://codeberg.org/ziglang/zig/issues/30947
32 .xtensa,
33 .xtensaeb,
34 => true,31 => true,
35 else => false,32 else => false,
36 },33 },
lib/std/os/linux.zig+32
...@@ -56,6 +56,7 @@ const arch_bits = switch (native_arch) {...@@ -56,6 +56,7 @@ const arch_bits = switch (native_arch) {
56 .gnux32, .muslx32 => @import("linux/x32.zig"),56 .gnux32, .muslx32 => @import("linux/x32.zig"),
57 else => @import("linux/x86_64.zig"),57 else => @import("linux/x86_64.zig"),
58 },58 },
59 .xtensa, .xtensaeb => @import("linux/xtensa.zig"),
59 else => struct {},60 else => struct {},
60};61};
6162
...@@ -338,6 +339,29 @@ pub const MAP = switch (native_arch) {...@@ -338,6 +339,29 @@ pub const MAP = switch (native_arch) {
338 _20: u1 = 0,339 _20: u1 = 0,
339 _: u5 = 0,340 _: u5 = 0,
340 },341 },
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 },
341 else => @compileError("missing std.os.linux.MAP constants for this architecture"),365 else => @compileError("missing std.os.linux.MAP constants for this architecture"),
342};366};
343367
...@@ -497,6 +521,8 @@ pub const O = switch (native_arch) {...@@ -497,6 +521,8 @@ pub const O = switch (native_arch) {
497 .hexagon,521 .hexagon,
498 .or1k,522 .or1k,
499 .s390x,523 .s390x,
524 .xtensa,
525 .xtensaeb,
500 => packed struct(u32) {526 => packed struct(u32) {
501 ACCMODE: ACCMODE = .RDONLY,527 ACCMODE: ACCMODE = .RDONLY,
502 _2: u4 = 0,528 _2: u4 = 0,
...@@ -6617,6 +6643,12 @@ pub const k_sigaction = switch (native_arch) {...@@ -6617,6 +6643,12 @@ pub const k_sigaction = switch (native_arch) {
6617 mask: sigset_t,6643 mask: sigset_t,
6618 flags: c_int,6644 flags: c_int,
6619 },6645 },
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 },
6620 else => extern struct {6652 else => extern struct {
6621 handler: k_sigaction_funcs.handler,6653 handler: k_sigaction_funcs.handler,
6622 flags: c_ulong,6654 flags: c_ulong,
lib/std/os/linux/tls.zig+11
...@@ -78,6 +78,8 @@ const current_variant: Variant = switch (native_arch) {...@@ -78,6 +78,8 @@ const current_variant: Variant = switch (native_arch) {
78 .sheb,78 .sheb,
79 .thumb,79 .thumb,
80 .thumbeb,80 .thumbeb,
81 .xtensa,
82 .xtensaeb,
81 => .I_original,83 => .I_original,
82 .loongarch32,84 .loongarch32,
83 .loongarch64,85 .loongarch64,
...@@ -152,6 +154,8 @@ const AbiTcb = switch (current_variant) {...@@ -152,6 +154,8 @@ const AbiTcb = switch (current_variant) {
152 .sheb,154 .sheb,
153 .thumb,155 .thumb,
154 .thumbeb,156 .thumbeb,
157 .xtensa,
158 .xtensaeb,
155 => extern struct {159 => extern struct {
156 /// This is offset by `current_dtv_offset`.160 /// This is offset by `current_dtv_offset`.
157 dtv: usize,161 dtv: usize,
...@@ -364,6 +368,13 @@ pub fn setThreadPointer(addr: usize) void {...@@ -364,6 +368,13 @@ pub fn setThreadPointer(addr: usize) void {
364 : [addr] "r" (addr),368 : [addr] "r" (addr),
365 );369 );
366 },370 },
371 .xtensa, .xtensaeb => {
372 asm volatile (
373 \\ wur %[addr], threadptr
374 :
375 : [addr] "a" (addr),
376 );
377 },
367 else => @compileError("Unsupported architecture"),378 else => @compileError("Unsupported architecture"),
368 }379 }
369}380}
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;...@@ -22,6 +22,7 @@ const R_RISCV_RELATIVE = 3;
22const R_390_RELATIVE = 12;22const R_390_RELATIVE = 12;
23const R_SH_RELATIVE = 165;23const R_SH_RELATIVE = 165;
24const R_SPARC_RELATIVE = 22;24const R_SPARC_RELATIVE = 22;
25const R_XTENSA_RELATIVE = 5;
2526
26const R_RELATIVE = switch (builtin.cpu.arch) {27const R_RELATIVE = switch (builtin.cpu.arch) {
27 .x86 => R_386_RELATIVE,28 .x86 => R_386_RELATIVE,
...@@ -43,6 +44,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) {...@@ -43,6 +44,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
43 .s390x => R_390_RELATIVE,44 .s390x => R_390_RELATIVE,
44 .sh, .sheb => R_SH_RELATIVE,45 .sh, .sheb => R_SH_RELATIVE,
45 .sparc, .sparc64 => R_SPARC_RELATIVE,46 .sparc, .sparc64 => R_SPARC_RELATIVE,
47 .xtensa, .xtensaeb => R_XTENSA_RELATIVE,
46 else => @compileError("Missing R_RELATIVE definition for this target"),48 else => @compileError("Missing R_RELATIVE definition for this target"),
47};49};
4850
...@@ -261,6 +263,25 @@ inline fn getDynamicSymbol() [*]const elf.Dyn {...@@ -261,6 +263,25 @@ inline fn getDynamicSymbol() [*]const elf.Dyn {
261 : [ret] "=r" (-> [*]const elf.Dyn),263 : [ret] "=r" (-> [*]const elf.Dyn),
262 :264 :
263 : .{ .l7 = true }),265 : .{ .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 }),
264 else => {285 else => {
265 @compileError("PIE startup is not yet supported for this target!");286 @compileError("PIE startup is not yet supported for this target!");
266 },287 },
lib/std/start.zig+10
...@@ -183,6 +183,7 @@ fn _start() callconv(.naked) noreturn {...@@ -183,6 +183,7 @@ fn _start() callconv(.naked) noreturn {
183 .sparc, .sparc64 => ".cfi_undefined %%i7",183 .sparc, .sparc64 => ".cfi_undefined %%i7",
184 .x86 => ".cfi_undefined %%eip",184 .x86 => ".cfi_undefined %%eip",
185 .x86_64 => ".cfi_undefined %%rip",185 .x86_64 => ".cfi_undefined %%rip",
186 .xtensa, .xtensaeb => "", // No CFI support.
186 else => @compileError("unsupported arch"),187 else => @compileError("unsupported arch"),
187 });188 });
188189
...@@ -486,6 +487,15 @@ fn _start() callconv(.naked) noreturn {...@@ -486,6 +487,15 @@ fn _start() callconv(.naked) noreturn {
486 \\ sub %%sp, 2047, %%sp487 \\ sub %%sp, 2047, %%sp
487 \\ ba,a %[posixCallMainAndExit]488 \\ ba,a %[posixCallMainAndExit]
488 ,489 ,
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 ,
489 else => @compileError("unsupported arch"),499 else => @compileError("unsupported arch"),
490 }500 }
491 :501 :