diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index df9e822c07..f5c5f09fa4 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -32,14 +32,9 @@ test { } const arch_bits = switch (native_arch) { - .x86 => @import("linux/x86.zig"), - .x86_64 => @import("linux/x86_64.zig"), .aarch64, .aarch64_be => @import("linux/aarch64.zig"), .arm, .armeb, .thumb, .thumbeb => @import("linux/arm.zig"), .hexagon => @import("linux/hexagon.zig"), - .riscv32 => @import("linux/riscv32.zig"), - .riscv64 => @import("linux/riscv64.zig"), - .sparc64 => @import("linux/sparc64.zig"), .loongarch64 => @import("linux/loongarch64.zig"), .m68k => @import("linux/m68k.zig"), .mips, .mipsel => @import("linux/mips.zig"), @@ -49,7 +44,15 @@ const arch_bits = switch (native_arch) { }, .powerpc, .powerpcle => @import("linux/powerpc.zig"), .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"), + .riscv32 => @import("linux/riscv32.zig"), + .riscv64 => @import("linux/riscv64.zig"), .s390x => @import("linux/s390x.zig"), + .sparc64 => @import("linux/sparc64.zig"), + .x86 => @import("linux/x86.zig"), + .x86_64 => switch (builtin.abi) { + .gnux32, .muslx32 => @import("linux/x32.zig"), + else => @import("linux/x86_64.zig"), + }, else => struct {}, }; @@ -113,8 +116,8 @@ pub const SECCOMP = @import("linux/seccomp.zig"); pub const syscalls = @import("linux/syscalls.zig"); pub const SYS = switch (native_arch) { .arc => syscalls.Arc, - .arm, .armeb, .thumb, .thumbeb => syscalls.Arm, .aarch64, .aarch64_be => syscalls.Arm64, + .arm, .armeb, .thumb, .thumbeb => syscalls.Arm, .csky => syscalls.CSky, .hexagon => syscalls.Hexagon, .loongarch64 => syscalls.LoongArch64, @@ -124,20 +127,20 @@ pub const SYS = switch (native_arch) { .gnuabin32, .muslabin32 => syscalls.MipsN32, else => syscalls.MipsN64, }, + .or1k => syscalls.OpenRisc, + .powerpc, .powerpcle => syscalls.PowerPC, + .powerpc64, .powerpc64le => syscalls.PowerPC64, .riscv32 => syscalls.RiscV32, .riscv64 => syscalls.RiscV64, .s390x => syscalls.S390x, .sparc => syscalls.Sparc, .sparc64 => syscalls.Sparc64, - .powerpc, .powerpcle => syscalls.PowerPC, - .powerpc64, .powerpc64le => syscalls.PowerPC64, .x86 => syscalls.X86, .x86_64 => switch (builtin.abi) { .gnux32, .muslx32 => syscalls.X32, else => syscalls.X64, }, .xtensa => syscalls.Xtensa, - .or1k => syscalls.OpenRisc, else => @compileError("The Zig Standard Library is missing syscall definitions for the target CPU architecture"), }; diff --git a/lib/std/os/linux/x32.zig b/lib/std/os/linux/x32.zig new file mode 100644 index 0000000000..4335fac04b --- /dev/null +++ b/lib/std/os/linux/x32.zig @@ -0,0 +1,192 @@ +// TODO: A lot of this file is very likely wrong. + +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" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn syscall1(number: SYS, arg1: u32) u32 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5), + : .{ .rcx = true, .r11 = 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" + : [ret] "={rax}" (-> u32), + : [number] "{rax}" (@intFromEnum(number)), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5), + [arg6] "{r9}" (arg6), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + +pub fn clone() callconv(.naked) u32 { + asm volatile ( + \\ movl $56,%%eax // SYS_clone + \\ movq %%rdi,%%r11 + \\ movq %%rdx,%%rdi + \\ movq %%r8,%%rdx + \\ movq %%r9,%%r8 + \\ movq 8(%%rsp),%%r10 + \\ movq %%r11,%%r9 + \\ andq $-16,%%rsi + \\ subq $8,%%rsi + \\ movq %%rcx,(%%rsi) + \\ syscall + \\ testq %%rax,%%rax + \\ jz 1f + \\ retq + \\ + \\1: + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined %%rip + ); + asm volatile ( + \\ xorl %%ebp,%%ebp + \\ + \\ popq %%rdi + \\ callq *%%r9 + \\ movl %%eax,%%edi + \\ movl $60,%%eax // SYS_exit + \\ syscall + \\ + ); +} + +pub const restore = restore_rt; + +pub fn restore_rt() callconv(.naked) noreturn { + switch (builtin.zig_backend) { + .stage2_c => asm volatile ( + \\ movl %[number], %%eax + \\ syscall + : + : [number] "i" (@intFromEnum(SYS.rt_sigreturn)), + ), + else => asm volatile ( + \\ syscall + : + : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)), + ), + } +} + +pub const mode_t = u32; +pub const time_t = i32; +pub const nlink_t = u32; +pub const blksize_t = i32; +pub const blkcnt_t = i32; +pub const off_t = i64; +pub const ino_t = u64; +pub const dev_t = u64; + +pub const VDSO = struct { + pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_VER = "LINUX_2.6"; + + pub const GETCPU_SYM = "__vdso_getcpu"; + pub const GETCPU_VER = "LINUX_2.6"; +}; + +pub const ARCH = struct { + pub const SET_GS = 0x1001; + pub const SET_FS = 0x1002; + pub const GET_FS = 0x1003; + pub const GET_GS = 0x1004; +}; + +// The `stat` definition used by the Linux kernel. +pub const Stat = extern struct { + dev: dev_t, + ino: ino_t, + nlink: nlink_t, + + mode: mode_t, + uid: std.os.linux.uid_t, + gid: std.os.linux.gid_t, + __pad0: u32, + rdev: dev_t, + size: off_t, + blksize: blksize_t, + blocks: i64, + + atim: std.os.linux.timespec, + mtim: std.os.linux.timespec, + ctim: std.os.linux.timespec, + __unused: [3]i32, + + pub fn atime(self: @This()) std.os.linux.timespec { + return self.atim; + } + + pub fn mtime(self: @This()) std.os.linux.timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) std.os.linux.timespec { + return self.ctim; + } +};