From ec0d775524e0b8b8f0bc41baa3e6d4e11c50557d Mon Sep 17 00:00:00 2001 From: Shawn Anastasio Date: Wed, 3 Jun 2020 19:37:14 -0500 Subject: [PATCH 1/4] Implement std.os for powerpc64{,le} --- lib/std/os/bits/linux.zig | 1 + lib/std/os/bits/linux/powerpc64.zig | 602 ++++++++++++++++++++++++++++ lib/std/os/linux.zig | 1 + lib/std/os/linux/powerpc64.zig | 127 ++++++ lib/std/os/linux/tls.zig | 13 +- 5 files changed, 741 insertions(+), 3 deletions(-) create mode 100644 lib/std/os/bits/linux/powerpc64.zig create mode 100644 lib/std/os/linux/powerpc64.zig diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 64832673f1..9ec7038b07 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -15,6 +15,7 @@ pub usingnamespace switch (builtin.arch) { .arm => @import("linux/arm-eabi.zig"), .riscv64 => @import("linux/riscv64.zig"), .mips, .mipsel => @import("linux/mips.zig"), + .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"), else => struct {}, }; diff --git a/lib/std/os/bits/linux/powerpc64.zig b/lib/std/os/bits/linux/powerpc64.zig new file mode 100644 index 0000000000..a6884aa024 --- /dev/null +++ b/lib/std/os/bits/linux/powerpc64.zig @@ -0,0 +1,602 @@ +const std = @import("../../../std.zig"); +const linux = std.os.linux; +const socklen_t = linux.socklen_t; +const iovec = linux.iovec; +const iovec_const = linux.iovec_const; +const uid_t = linux.uid_t; +const gid_t = linux.gid_t; +const pid_t = linux.pid_t; +const stack_t = linux.stack_t; +const sigset_t = linux.sigset_t; +pub const SYS = extern enum(usize) { + restart_syscall = 0, + exit = 1, + fork = 2, + read = 3, + write = 4, + open = 5, + close = 6, + waitpid = 7, + creat = 8, + link = 9, + unlink = 10, + execve = 11, + chdir = 12, + time = 13, + mknod = 14, + chmod = 15, + lchown = 16, + sys_break = 17, // sys_ prepended to avoid clashing with keyword + oldstat = 18, + lseek = 19, + getpid = 20, + mount = 21, + umount = 22, + setuid = 23, + getuid = 24, + stime = 25, + ptrace = 26, + alarm = 27, + oldfstat = 28, + pause = 29, + utime = 30, + stty = 31, + gtty = 32, + access = 33, + nice = 34, + ftime = 35, + sync = 36, + kill = 37, + rename = 38, + mkdir = 39, + rmdir = 40, + dup = 41, + pipe = 42, + times = 43, + prof = 44, + brk = 45, + setgid = 46, + getgid = 47, + signal = 48, + geteuid = 49, + getegid = 50, + acct = 51, + umount2 = 52, + lock = 53, + ioctl = 54, + fcntl = 55, + mpx = 56, + setpgid = 57, + ulimit = 58, + oldolduname = 59, + umask = 60, + chroot = 61, + ustat = 62, + dup2 = 63, + getppid = 64, + getpgrp = 65, + setsid = 66, + sigaction = 67, + sgetmask = 68, + ssetmask = 69, + setreuid = 70, + setregid = 71, + sigsuspend = 72, + sigpending = 73, + sethostname = 74, + setrlimit = 75, + getrlimit = 76, + getrusage = 77, + gettimeofday = 78, + settimeofday = 79, + getgroups = 80, + setgroups = 81, + select = 82, + symlink = 83, + oldlstat = 84, + readlink = 85, + uselib = 86, + swapon = 87, + reboot = 88, + readdir = 89, + mmap = 90, + munmap = 91, + truncate = 92, + ftruncate = 93, + fchmod = 94, + fchown = 95, + getpriority = 96, + setpriority = 97, + profil = 98, + statfs = 99, + fstatfs = 100, + ioperm = 101, + socketcall = 102, + syslog = 103, + setitimer = 104, + getitimer = 105, + stat = 106, + lstat = 107, + fstat = 108, + olduname = 109, + iopl = 110, + vhangup = 111, + idle = 112, + vm86 = 113, + wait4 = 114, + swapoff = 115, + sysinfo = 116, + ipc = 117, + fsync = 118, + sigreturn = 119, + clone = 120, + setdomainname = 121, + uname = 122, + modify_ldt = 123, + adjtimex = 124, + mprotect = 125, + sigprocmask = 126, + create_module = 127, + init_module = 128, + delete_module = 129, + get_kernel_syms = 130, + quotactl = 131, + getpgid = 132, + fchdir = 133, + bdflush = 134, + sysfs = 135, + personality = 136, + afs_syscall = 137, + setfsuid = 138, + setfsgid = 139, + _llseek = 140, + getdents = 141, + _newselect = 142, + flock = 143, + msync = 144, + readv = 145, + writev = 146, + getsid = 147, + fdatasync = 148, + _sysctl = 149, + mlock = 150, + munlock = 151, + mlockall = 152, + munlockall = 153, + sched_setparam = 154, + sched_getparam = 155, + sched_setscheduler = 156, + sched_getscheduler = 157, + sched_yield = 158, + sched_get_priority_max = 159, + sched_get_priority_min = 160, + sched_rr_get_interval = 161, + nanosleep = 162, + mremap = 163, + setresuid = 164, + getresuid = 165, + query_module = 166, + poll = 167, + nfsservctl = 168, + setresgid = 169, + getresgid = 170, + prctl = 171, + rt_sigreturn = 172, + rt_sigaction = 173, + rt_sigprocmask = 174, + rt_sigpending = 175, + rt_sigtimedwait = 176, + rt_sigqueueinfo = 177, + rt_sigsuspend = 178, + pread64 = 179, + pwrite64 = 180, + chown = 181, + getcwd = 182, + capget = 183, + capset = 184, + sigaltstack = 185, + sendfile = 186, + getpmsg = 187, + putpmsg = 188, + vfork = 189, + ugetrlimit = 190, + readahead = 191, + pciconfig_read = 198, + pciconfig_write = 199, + pciconfig_iobase = 200, + multiplexer = 201, + getdents64 = 202, + pivot_root = 203, + madvise = 205, + mincore = 206, + gettid = 207, + tkill = 208, + setxattr = 209, + lsetxattr = 210, + fsetxattr = 211, + getxattr = 212, + lgetxattr = 213, + fgetxattr = 214, + listxattr = 215, + llistxattr = 216, + flistxattr = 217, + removexattr = 218, + lremovexattr = 219, + fremovexattr = 220, + futex = 221, + sched_setaffinity = 222, + sched_getaffinity = 223, + tuxcall = 225, + io_setup = 227, + io_destroy = 228, + io_getevents = 229, + io_submit = 230, + io_cancel = 231, + set_tid_address = 232, + fadvise64 = 233, + exit_group = 234, + lookup_dcookie = 235, + epoll_create = 236, + epoll_ctl = 237, + epoll_wait = 238, + remap_file_pages = 239, + timer_create = 240, + timer_settime = 241, + timer_gettime = 242, + timer_getoverrun = 243, + timer_delete = 244, + clock_settime = 245, + clock_gettime = 246, + clock_getres = 247, + clock_nanosleep = 248, + swapcontext = 249, + tgkill = 250, + utimes = 251, + statfs64 = 252, + fstatfs64 = 253, + rtas = 255, + sys_debug_setcontext = 256, + migrate_pages = 258, + mbind = 259, + get_mempolicy = 260, + set_mempolicy = 261, + mq_open = 262, + mq_unlink = 263, + mq_timedsend = 264, + mq_timedreceive = 265, + mq_notify = 266, + mq_getsetattr = 267, + kexec_load = 268, + add_key = 269, + request_key = 270, + keyctl = 271, + waitid = 272, + ioprio_set = 273, + ioprio_get = 274, + inotify_init = 275, + inotify_add_watch = 276, + inotify_rm_watch = 277, + spu_run = 278, + spu_create = 279, + pselect6 = 280, + ppoll = 281, + unshare = 282, + splice = 283, + tee = 284, + vmsplice = 285, + openat = 286, + mkdirat = 287, + mknodat = 288, + fchownat = 289, + futimesat = 290, + newfstatat = 291, + unlinkat = 292, + renameat = 293, + linkat = 294, + symlinkat = 295, + readlinkat = 296, + fchmodat = 297, + faccessat = 298, + get_robust_list = 299, + set_robust_list = 300, + move_pages = 301, + getcpu = 302, + epoll_pwait = 303, + utimensat = 304, + signalfd = 305, + timerfd_create = 306, + eventfd = 307, + sync_file_range2 = 308, + fallocate = 309, + subpage_prot = 310, + timerfd_settime = 311, + timerfd_gettime = 312, + signalfd4 = 313, + eventfd2 = 314, + epoll_create1 = 315, + dup3 = 316, + pipe2 = 317, + inotify_init1 = 318, + perf_event_open = 319, + preadv = 320, + pwritev = 321, + rt_tgsigqueueinfo = 322, + fanotify_init = 323, + fanotify_mark = 324, + prlimit64 = 325, + socket = 326, + bind = 327, + connect = 328, + listen = 329, + accept = 330, + getsockname = 331, + getpeername = 332, + socketpair = 333, + send = 334, + sendto = 335, + recv = 336, + recvfrom = 337, + shutdown = 338, + setsockopt = 339, + getsockopt = 340, + sendmsg = 341, + recvmsg = 342, + recvmmsg = 343, + accept4 = 344, + name_to_handle_at = 345, + open_by_handle_at = 346, + clock_adjtime = 347, + syncfs = 348, + sendmmsg = 349, + setns = 350, + process_vm_readv = 351, + process_vm_writev = 352, + finit_module = 353, + kcmp = 354, + sched_setattr = 355, + sched_getattr = 356, + renameat2 = 357, + seccomp = 358, + getrandom = 359, + memfd_create = 360, + bpf = 361, + execveat = 362, + switch_endian = 363, + userfaultfd = 364, + membarrier = 365, + mlock2 = 378, + copy_file_range = 379, + preadv2 = 380, + pwritev2 = 381, + kexec_file_load = 382, + statx = 383, + pkey_alloc = 384, + pkey_free = 385, + pkey_mprotect = 386, + rseq = 387, + io_pgetevents = 388, + semtimedop = 392, + semget = 393, + semctl = 394, + shmget = 395, + shmctl = 396, + shmat = 397, + shmdt = 398, + msgget = 399, + msgsnd = 400, + msgrcv = 401, + msgctl = 402, + pidfd_send_signal = 424, + io_uring_setup = 425, + io_uring_enter = 426, + io_uring_register = 427, + open_tree = 428, + move_mount = 429, + fsopen = 430, + fsconfig = 431, + fsmount = 432, + fspick = 433, + pidfd_open = 434, + clone3 = 435, + openat2 = 437, + pidfd_getfd = 438, + + _, +}; + +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o40000; +pub const O_NOFOLLOW = 0o100000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o400000; +pub const O_LARGEFILE = 0o200000; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_RDLCK = 0; +pub const F_WRLCK = 1; +pub const F_UNLCK = 2; + +pub const LOCK_SH = 1; +pub const LOCK_EX = 2; +pub const LOCK_UN = 8; +pub const LOCK_NB = 4; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +/// stack-like segment +pub const MAP_GROWSDOWN = 0x0100; + +/// ETXTBSY +pub const MAP_DENYWRITE = 0x0800; + +/// mark it as an executable +pub const MAP_EXECUTABLE = 0x1000; + +/// pages are locked +pub const MAP_LOCKED = 0x0080; + +/// don't check for reservations +pub const MAP_NORESERVE = 0x0040; + +pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; +pub const VDSO_CGT_VER = "LINUX_2.6.15"; + +pub const Flock = extern struct { + l_type: i16, + l_whence: i16, + l_start: off_t, + l_len: off_t, + l_pid: pid_t, + __unused: [4]u8, +}; + +pub const msghdr = extern struct { + msg_name: ?*sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec, + msg_iovlen: usize, + msg_control: ?*c_void, + msg_controllen: usize, + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + msg_name: ?*const sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec_const, + msg_iovlen: usize, + msg_control: ?*c_void, + msg_controllen: usize, + msg_flags: i32, +}; + +pub const blksize_t = i64; +pub const nlink_t = u64; +pub const time_t = i64; +pub const mode_t = u32; +pub const off_t = i64; +pub const ino_t = u64; +pub const dev_t = u64; +pub const blkcnt_t = i64; + +/// Renamed to Stat to not conflict with the stat function. +/// atime, mtime, and ctime have functions to return `timespec`, +/// because although this is a POSIX API, the layout and names of +/// the structs are inconsistent across operating systems, and +/// in C, macros are used to hide the differences. Here we use +/// methods to accomplish this. +pub const Stat = extern struct { + dev: dev_t, + ino: ino_t, + nlink: nlink_t, + mode: mode_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + size: off_t, + blksize: blksize_t, + blocks: blkcnt_t, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]u64, + + pub fn atime(self: Stat) timespec { + return self.atim; + } + + pub fn mtime(self: Stat) timespec { + return self.mtim; + } + + pub fn ctime(self: Stat) timespec { + return self.ctim; + } +}; + +pub const timespec = extern struct { + tv_sec: time_t, + tv_nsec: isize, +}; + +pub const timeval = extern struct { + tv_sec: isize, + tv_usec: isize, +}; + +pub const timezone = extern struct { + tz_minuteswest: i32, + tz_dsttime: i32, +}; + +pub const greg_t = u64; +pub const gregset_t = [48]greg_t; +pub const fpregset_t = [33]f64; + +/// The position of the vscr register depends on endianness. +/// On C, macros are used to change vscr_word's offset to +/// account for this. Here we'll just define vscr_word_le +/// and vscr_word_be. Code must take care to use the correct one. +pub const vrregset = extern struct { + vrregs: [32][4]u32 align(16), + vscr_word_le: u32, + _pad1: [2]u32, + vscr_word_be: u32, + vrsave: u32, + _pad2: [3]u32 +}; +pub const vrregset_t = vrregset; + +pub const mcontext_t = extern struct { + __unused: [4]u64, + signal: i32, + _pad0: i32, + handler: u64, + oldmask: u64, + regs: ?*c_void, + gp_regs: gregset_t, + fp_regs: fpregset_t, + v_regs: *vrregset_t, + vmx_reserve: [34+34+32+1]i64, +}; + +pub const ucontext_t = extern struct { + flags: u32, + link: *ucontext_t, + stack: stack_t, + sigmask: sigset_t, + mcontext: mcontext_t, +}; + +pub const Elf_Symndx = u32; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 3b8df3d173..67c6fc5d31 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -20,6 +20,7 @@ pub usingnamespace switch (builtin.arch) { .arm => @import("linux/arm-eabi.zig"), .riscv64 => @import("linux/riscv64.zig"), .mips, .mipsel => @import("linux/mips.zig"), + .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"), else => struct {}, }; pub usingnamespace @import("bits.zig"); diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig new file mode 100644 index 0000000000..337a6aa30a --- /dev/null +++ b/lib/std/os/linux/powerpc64.zig @@ -0,0 +1,127 @@ +usingnamespace @import("../bits.zig"); + +pub fn syscall0(number: SYS) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall1(number: SYS, arg1: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4), + [arg5] "{r7}" (arg5) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall6( + number: SYS, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4), + [arg5] "{r7}" (arg5), + [arg6] "{r8}" (arg6) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +/// This matches the libc clone function. +pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; + +pub const restore = restore_rt; + +pub fn restore_rt() callconv(.Naked) void { + return asm volatile ("sc" + : + : [number] "{r0}" (@enumToInt(SYS.rt_sigreturn)) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index 8cba45d4b3..9c79bc3a96 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -48,7 +48,7 @@ const TLSVariant = enum { }; const tls_variant = switch (builtin.arch) { - .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel => TLSVariant.VariantI, + .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, .x86_64, .i386 => TLSVariant.VariantII, else => @compileError("undefined tls_variant for this architecture"), }; @@ -72,12 +72,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) { // make the generated code more efficient const tls_tp_offset = switch (builtin.arch) { - .mips, .mipsel => 0x7000, + .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x7000, else => 0, }; const tls_dtv_offset = switch (builtin.arch) { - .mips, .mipsel => 0x8000, + .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x8000, .riscv32, .riscv64 => 0x800, else => 0, }; @@ -160,6 +160,13 @@ pub fn setThreadPointer(addr: usize) void { const rc = std.os.linux.syscall1(.set_thread_area, addr); assert(rc == 0); }, + .powerpc, .powerpc64, .powerpc64le => { + asm volatile ( + \\ mr 13, %[addr] + : + : [addr] "r" (addr) + ); + }, else => @compileError("Unsupported architecture"), } } From 15371775d18e6425d1528643cedb70d6f0b7e6ea Mon Sep 17 00:00:00 2001 From: Shawn Anastasio Date: Wed, 3 Jun 2020 20:55:33 -0500 Subject: [PATCH 2/4] Implement clone() for powerpc64{,le} Implementation borrowed from musl, as most (all?) of the other ones seem to be. --- lib/std/special/c.zig | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index c769bc358b..13012e16a3 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -389,6 +389,61 @@ fn clone() callconv(.Naked) void { \\ syscall ); }, + + .powerpc64, .powerpc64le => { + asm volatile ( + \\ # store non-volatile regs r30, r31 on stack in order to put our + \\ # start func and its arg there + \\ stwu 30, -16(1) + \\ stw 31, 4(1) + \\ # save r3 (func) into r30, and r6(arg) into r31 + \\ mr 30, 3 + \\ mr 31, 6 + \\ # create initial stack frame for new thread + \\ clrrwi 4, 4, 4 + \\ li 0, 0 + \\ stwu 0, -16(4) + \\ #move c into first arg + \\ mr 3, 5 + \\ mr 5, 7 + \\ mr 6, 8 + \\ mr 7, 9 + \\ # move syscall number into r0 + \\ li 0, 120 + \\ sc + + \\ # check for syscall error + \\ bns+ 1f # jump to label 1 if no summary overflow. + \\ #else + \\ neg 3, 3 #negate the result (errno) + \\1: + \\ # compare sc result with 0 + \\ cmpwi cr7, 3, 0 + + \\ # if not 0, jump to end + \\ bne cr7, 2f + + \\ #else: we're the child + \\ #call funcptr: move arg (d) into r3 + \\ mr 3, 31 + \\ #move r30 (funcptr) into CTR reg + \\ mtctr 30 + \\ # call CTR reg + \\ bctrl + \\ # mov SYS_exit into r0 (the exit param is already in r3) + \\ li 0, 1 + \\ sc + + \\2: + \\ # restore stack + \\ lwz 30, 0(1) + \\ lwz 31, 4(1) + \\ addi 1, 1, 16 + + \\ blr + ); + }, + else => @compileError("Implement clone() for this arch."), } } From 8574861ca0bc5e8103c27e3c78866e3a4eb56f98 Mon Sep 17 00:00:00 2001 From: Shawn Anastasio Date: Wed, 1 Jul 2020 16:12:27 -0500 Subject: [PATCH 3/4] Implement required ABI bits for powerpc{,64,64le} --- src/analyze.cpp | 3 ++- src/target.cpp | 11 ++++++++--- src/target.hpp | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 9062c1fb13..72762f4227 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1003,7 +1003,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { g->zig_target->arch == ZigLLVM_x86_64 || target_is_arm(g->zig_target) || target_is_riscv(g->zig_target) || - target_is_wasm(g->zig_target)) + target_is_wasm(g->zig_target) || + target_is_ppc(g->zig_target)) { X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval; diff --git a/src/target.cpp b/src/target.cpp index 73c0924ab8..a4cb03aabc 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -853,6 +853,9 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { case ZigLLVM_riscv32: case ZigLLVM_riscv64: case ZigLLVM_mipsel: + case ZigLLVM_ppc: + case ZigLLVM_ppc64: + case ZigLLVM_ppc64le: return "sp"; case ZigLLVM_wasm32: @@ -879,7 +882,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { case ZigLLVM_msp430: case ZigLLVM_nvptx: case ZigLLVM_nvptx64: - case ZigLLVM_ppc64le: case ZigLLVM_r600: case ZigLLVM_renderscript32: case ZigLLVM_renderscript64: @@ -893,8 +895,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { case ZigLLVM_tce: case ZigLLVM_tcele: case ZigLLVM_xcore: - case ZigLLVM_ppc: - case ZigLLVM_ppc64: case ZigLLVM_ve: zig_panic("TODO populate this table with stack pointer register name for this CPU architecture"); } @@ -1318,6 +1318,11 @@ bool target_is_mips(const ZigTarget *target) { target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el; } +bool target_is_ppc(const ZigTarget *target) { + return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 || + target->arch == ZigLLVM_ppc64le; +} + unsigned target_fn_align(const ZigTarget *target) { return 16; } diff --git a/src/target.hpp b/src/target.hpp index 898fa90203..9a8e79de97 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -95,6 +95,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type); bool target_is_arm(const ZigTarget *target); bool target_is_mips(const ZigTarget *target); +bool target_is_ppc(const ZigTarget *target); bool target_allows_addr_zero(const ZigTarget *target); bool target_has_valgrind_support(const ZigTarget *target); bool target_os_is_darwin(Os os); From 51fcf949f97d068e917c0c3301ba63a4a305ab6e Mon Sep 17 00:00:00 2001 From: Shawn Anastasio Date: Wed, 1 Jul 2020 16:13:14 -0500 Subject: [PATCH 4/4] Implement std.start for powerpc64le This is a bit hacky since we end up doing more than just grabbing the stack pointer in the inline assembly block. Ideally _start would be implemented in pure asm for powerpc64le, but this will do for now. Still to be implemented is powerpc, powerpc64, and powerpc64 (ELFv2) support. The latter will just require correctly determing target ABI for powerpc64 and enabling the existing powerpc64le implementation for it. --- lib/std/start.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/std/start.zig b/lib/std/start.zig index 604c22101c..0af7ea6407 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -116,6 +116,21 @@ fn _start() callconv(.Naked) noreturn { : [argc] "=r" (-> [*]usize) ); }, + .powerpc64le => { + // Before returning the stack pointer, we have to set up a backchain + // and a few other registers required by the ELFv2 ABI. + // TODO: Support powerpc64 (big endian) on ELFv2. + starting_stack_ptr = asm ( + \\ mr 4, 1 + \\ subi 1, 1, 32 + \\ li 5, 0 + \\ std 5, 0(1) + \\ mr %[argc], 4 + : [argc] "=r" (-> [*]usize) + : + : "r4", "r5" + ); + }, else => @compileError("unsupported arch"), } // If LLVM inlines stack variables into _start, they will overwrite