zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 11bb8ab9b3cf832a5e391ac8c73cbc33221db19d (tree)
parent b3747dd707eeaf06e0bacbde259bf71ef525a961
Author: Alex Rønne Petersen <alex@alexrp.com>
Date:   Tue, 26 May 2026 12:35:37 +0200

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

Diffstat:
Mlib/std/Thread.zig | 10++++++++++
Mlib/std/debug.zig | 2++
Mlib/std/elf.zig | 3+++
Mlib/std/os.zig | 3---
Mlib/std/os/linux.zig | 32++++++++++++++++++++++++++++++++
Mlib/std/os/linux/tls.zig | 11+++++++++++
Alib/std/os/linux/xtensa.zig | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/std/pie.zig | 21+++++++++++++++++++++
Mlib/std/start.zig | 10++++++++++
9 files changed, 260 insertions(+), 3 deletions(-)

diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig @@ -1411,6 +1411,16 @@ const LinuxThreadImpl = struct { : [ptr] "{r4}" (@intFromPtr(self.mapped.ptr)), [len] "{r5}" (self.mapped.len), : .{ .memory = true }), + .xtensa, .xtensaeb => asm volatile ( + \\ movi a2, 81 // SYS_munmap + \\ syscall + \\ movi a6, 0 + \\ movi a2, 118 // SYS_exit + \\ syscall + : + : [ptr] "{a6}" (@intFromPtr(self.mapped.ptr)), + [len] "{a3}" (self.mapped.len), + : .{ .memory = true }), else => |cpu_arch| @compileError("Unsupported linux arch: " ++ @tagName(cpu_arch)), } unreachable; diff --git a/lib/std/debug.zig b/lib/std/debug.zig @@ -994,6 +994,8 @@ const StackIterator = union(enum) { .sh, .sheb, .xcore, + .xtensa, + .xtensaeb, => .useless, .hexagon, // The PowerPC ABIs don't actually strictly require a backchain pointer; they allow omitting diff --git a/lib/std/elf.zig b/lib/std/elf.zig @@ -224,6 +224,9 @@ pub const DT_PPC64_NUM = 4; pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0); pub const DT_IA_64_NUM = 1; +pub const DT_XTENSA_GOT_LOC_OFF = 0x70000000; +pub const DT_XTENSA_GOT_LOC_SZ = 0x70000001; + pub const DT_NIOS2_GP = 0x70000002; pub const DF_ORIGIN = 0x00000001; diff --git a/lib/std/os.zig b/lib/std/os.zig @@ -28,9 +28,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool { .sheb, // https://codeberg.org/ziglang/zig/issues/30945 .sparc, - // https://codeberg.org/ziglang/zig/issues/30947 - .xtensa, - .xtensaeb, => true, else => false, }, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig @@ -56,6 +56,7 @@ const arch_bits = switch (native_arch) { .gnux32, .muslx32 => @import("linux/x32.zig"), else => @import("linux/x86_64.zig"), }, + .xtensa, .xtensaeb => @import("linux/xtensa.zig"), else => struct {}, }; @@ -338,6 +339,29 @@ pub const MAP = switch (native_arch) { _20: u1 = 0, _: u5 = 0, }, + .xtensa, .xtensaeb => packed struct(u32) { + TYPE: MAP_TYPE, + FIXED: bool = false, + _RENAME: bool = false, + _AUTOGROW: bool = false, + _LOCAL: bool = false, + _AUTORSRV: bool = false, + _1: u1 = 0, + NORESERVE: bool = false, + ANONYMOUS: bool = false, + GROWSDOWN: bool = false, + DENYWRITE: bool = false, + EXECUTABLE: bool = false, + LOCKED: bool = false, + POPULATE: bool = false, + NONBLOCK: bool = false, + STACK: bool = false, + HUGETLB: bool = false, + FIXED_NOREPLACE: bool = false, + _2: u5 = 0, + UNINITIALIZED: bool = false, + _3: u5 = 0, + }, else => @compileError("missing std.os.linux.MAP constants for this architecture"), }; @@ -497,6 +521,8 @@ pub const O = switch (native_arch) { .hexagon, .or1k, .s390x, + .xtensa, + .xtensaeb, => packed struct(u32) { ACCMODE: ACCMODE = .RDONLY, _2: u4 = 0, @@ -6617,6 +6643,12 @@ pub const k_sigaction = switch (native_arch) { mask: sigset_t, flags: c_int, }, + .xtensa, .xtensaeb => extern struct { + handler: k_sigaction_funcs.handler, + mask: sigset_t, + flags: c_ulong, + restorer: k_sigaction_funcs.restorer, + }, else => extern struct { handler: k_sigaction_funcs.handler, flags: c_ulong, diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig @@ -78,6 +78,8 @@ const current_variant: Variant = switch (native_arch) { .sheb, .thumb, .thumbeb, + .xtensa, + .xtensaeb, => .I_original, .loongarch32, .loongarch64, @@ -152,6 +154,8 @@ const AbiTcb = switch (current_variant) { .sheb, .thumb, .thumbeb, + .xtensa, + .xtensaeb, => extern struct { /// This is offset by `current_dtv_offset`. dtv: usize, @@ -364,6 +368,13 @@ pub fn setThreadPointer(addr: usize) void { : [addr] "r" (addr), ); }, + .xtensa, .xtensaeb => { + asm volatile ( + \\ wur %[addr], threadptr + : + : [addr] "a" (addr), + ); + }, else => @compileError("Unsupported architecture"), } } diff --git a/lib/std/os/linux/xtensa.zig b/lib/std/os/linux/xtensa.zig @@ -0,0 +1,171 @@ +const builtin = @import("builtin"); +const std = @import("../../std.zig"); +const SYS = std.os.linux.SYS; + +pub const syscall_arg_t = u32; + +pub fn syscall0( + number: SYS, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + : .{ .memory = true }); +} + +pub fn syscall1( + number: SYS, + arg1: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + : .{ .memory = true }); +} + +pub fn syscall2( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + [arg2] "{a3}" (arg2), + : .{ .memory = true }); +} + +pub fn syscall3( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + [arg2] "{a3}" (arg2), + [arg3] "{a4}" (arg3), + : .{ .memory = true }); +} + +pub fn syscall4( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + [arg2] "{a3}" (arg2), + [arg3] "{a4}" (arg3), + [arg4] "{a5}" (arg4), + : .{ .memory = true }); +} + +pub fn syscall5( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, + arg5: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + [arg2] "{a3}" (arg2), + [arg3] "{a4}" (arg3), + [arg4] "{a5}" (arg4), + [arg5] "{a8}" (arg5), + : .{ .memory = true }); +} + +pub fn syscall6( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, + arg5: syscall_arg_t, + arg6: syscall_arg_t, +) u32 { + return asm volatile ("syscall" + : [ret] "={a2}" (-> u32), + : [number] "{a2}" (@intFromEnum(number)), + [arg1] "{a6}" (arg1), + [arg2] "{a3}" (arg2), + [arg3] "{a4}" (arg3), + [arg4] "{a5}" (arg4), + [arg5] "{a8}" (arg5), + [arg6] "{a9}" (arg6), + : .{ .memory = true }); +} + +pub fn clone() callconv(.naked) u32 { + // __clone(func, stack, flags, arg, ptid, tls, ctid) + // a2, a3, a4, a5, a6, a7, +16 + // + // syscall(SYS_clone, flags, stack, ptid, tls, ctid) + // a2 a6, a3, a4, a5, a8 + asm volatile ( + \\ entry sp, 16 + \\ + \\ movi a8, -16 + \\ and a3, a3, a8 + \\ + \\ mov a9, a2 + \\ mov a10, a5 + \\ + \\ mov a5, a7 + \\ mov a8, a6 + \\ mov a6, a4 + \\ mov a4, a8 + \\ l32i a8, sp, 16 + \\ movi a2, 116 // SYS_clone + \\ syscall + \\ + \\ beqz a2, 1f + \\ // parent + \\ retw + \\ + \\ // child + \\1: + \\ movi a7, 0 + \\ movi a0, 0 + \\ + \\ mov a2, a10 + \\ callx0 a9 + \\ movi a2, 118 // SYS_exit + \\ syscall + ); +} + +pub const restore = restore_rt; + +pub fn restore_rt() callconv(.naked) noreturn { + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\ movi a2, %[number] + \\ syscall + : + : [number] "I" (@intFromEnum(SYS.rt_sigreturn)), + ), + else => asm volatile ( + \\ syscall + : + : [number] "{a2}" (@intFromEnum(SYS.rt_sigreturn)), + ), + } +} + +pub const VDSO = void; + +pub const time_t = i32; diff --git a/lib/std/pie.zig b/lib/std/pie.zig @@ -22,6 +22,7 @@ const R_RISCV_RELATIVE = 3; const R_390_RELATIVE = 12; const R_SH_RELATIVE = 165; const R_SPARC_RELATIVE = 22; +const R_XTENSA_RELATIVE = 5; const R_RELATIVE = switch (builtin.cpu.arch) { .x86 => R_386_RELATIVE, @@ -43,6 +44,7 @@ const R_RELATIVE = switch (builtin.cpu.arch) { .s390x => R_390_RELATIVE, .sh, .sheb => R_SH_RELATIVE, .sparc, .sparc64 => R_SPARC_RELATIVE, + .xtensa, .xtensaeb => R_XTENSA_RELATIVE, else => @compileError("Missing R_RELATIVE definition for this target"), }; @@ -261,6 +263,25 @@ inline fn getDynamicSymbol() [*]const elf.Dyn { : [ret] "=r" (-> [*]const elf.Dyn), : : .{ .l7 = true }), + .xtensa, .xtensaeb => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC + // Set things up such that after the `call0`, `a0` will point 1 byte before the + // embedded constant. Note that `call0` is a 3-byte instruction, so we need both + // `.balign` directives to be safe. + \\ .balign 4 + \\ .begin no-transform + \\ call0 1f + \\ .end no-transform + \\ .balign 4 + \\ .word _DYNAMIC - . + \\1: + \\ add a0, a0, 1 + \\ l32i a8, a0, 0 + \\ add %[ret], a0, a8 + : [ret] "=a" (-> [*]const elf.Dyn), + : + : .{ .a0 = true, .a8 = true }), else => { @compileError("PIE startup is not yet supported for this target!"); }, diff --git a/lib/std/start.zig b/lib/std/start.zig @@ -183,6 +183,7 @@ fn _start() callconv(.naked) noreturn { .sparc, .sparc64 => ".cfi_undefined %%i7", .x86 => ".cfi_undefined %%eip", .x86_64 => ".cfi_undefined %%rip", + .xtensa, .xtensaeb => "", // No CFI support. else => @compileError("unsupported arch"), }); @@ -486,6 +487,15 @@ fn _start() callconv(.naked) noreturn { \\ sub %%sp, 2047, %%sp \\ ba,a %[posixCallMainAndExit] , + .xtensa, .xtensaeb => + // a0 = LR, a7 = FP, a1 = SP + \\ movi a0, 0 + \\ movi a7, 0 + \\ mov a2, sp + \\ movi a8, -16 + \\ and sp, sp, a8 + \\ callx0 %[posixCallMainAndExit] + , else => @compileError("unsupported arch"), } :