From 02fb48021773ae40a9781a45649ded39d02d1089 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sun, 2 Oct 2016 14:58:05 -0400 Subject: [PATCH] Commit a preview of osx386 and osxppc as new platforms. These produce Mach-o executables for Mac OS X on Intel or PowerPC processors. Our code generator for PowerPC (mach/powerpc) still has bugs. Some examples seem to run, but startrek crashes. Our code generator for Intel (mach/i386) is better. There is a problem with job control. If you run paranoia or startrek, then suspend the job (^Z) and resume it ('fg' in bash), then read(2) might fail with EINTR. The larger files in this commit are - plat/osx/cvmach/cvmach.c - plat/osx/libsys/brk.c - plat/osx386/libsys/sigaction.s - plat/osxppc/libsys/sigaction.s --- build.lua | 2 + plat/osx/cvmach/build.lua | 17 ++ plat/osx/cvmach/cvmach.c | 418 ++++++++++++++++++++++++++++++ plat/osx/include/ack/config.h | 14 + plat/osx/include/sys/mman.h | 20 ++ plat/osx/include/sys/types.h | 9 + plat/osx/include/unistd.h | 132 ++++++++++ plat/osx/libsys/brk.c | 95 +++++++ plat/osx/libsys/creat.c | 6 + plat/osx/libsys/isatty.c | 7 + plat/osx/libsys/signal.c | 16 ++ plat/osx386/boot.s | 69 +++++ plat/osx386/build-pkg.lua | 24 ++ plat/osx386/build-tools.lua | 9 + plat/osx386/descr | 80 ++++++ plat/osx386/include/build.lua | 24 ++ plat/osx386/libsys/_exit.s | 5 + plat/osx386/libsys/build.lua | 31 +++ plat/osx386/libsys/close.s | 7 + plat/osx386/libsys/getpid.s | 7 + plat/osx386/libsys/gettimeofday.s | 7 + plat/osx386/libsys/ioctl.s | 7 + plat/osx386/libsys/kill.s | 7 + plat/osx386/libsys/lseek.s | 17 ++ plat/osx386/libsys/mmap.s | 20 ++ plat/osx386/libsys/mprotect.s | 7 + plat/osx386/libsys/open.s | 7 + plat/osx386/libsys/read.s | 7 + plat/osx386/libsys/set_errno.s | 6 + plat/osx386/libsys/sigaction.s | 59 +++++ plat/osx386/libsys/write.s | 7 + plat/osxppc/boot.s | 60 +++++ plat/osxppc/build-pkg.lua | 24 ++ plat/osxppc/build-tools.lua | 9 + plat/osxppc/descr | 81 ++++++ plat/osxppc/include/build.lua | 24 ++ plat/osxppc/libsys/_exit.s | 6 + plat/osxppc/libsys/build.lua | 31 +++ plat/osxppc/libsys/close.s | 8 + plat/osxppc/libsys/getpid.s | 7 + plat/osxppc/libsys/gettimeofday.s | 9 + plat/osxppc/libsys/ioctl.s | 10 + plat/osxppc/libsys/kill.s | 9 + plat/osxppc/libsys/lseek.s | 13 + plat/osxppc/libsys/mmap.s | 15 ++ plat/osxppc/libsys/mprotect.s | 10 + plat/osxppc/libsys/open.s | 10 + plat/osxppc/libsys/read.s | 10 + plat/osxppc/libsys/set_errno.s | 7 + plat/osxppc/libsys/sigaction.s | 59 +++++ plat/osxppc/libsys/write.s | 10 + 51 files changed, 1555 insertions(+) create mode 100644 plat/osx/cvmach/build.lua create mode 100644 plat/osx/cvmach/cvmach.c create mode 100644 plat/osx/include/ack/config.h create mode 100644 plat/osx/include/sys/mman.h create mode 100644 plat/osx/include/sys/types.h create mode 100644 plat/osx/include/unistd.h create mode 100644 plat/osx/libsys/brk.c create mode 100644 plat/osx/libsys/creat.c create mode 100644 plat/osx/libsys/isatty.c create mode 100644 plat/osx/libsys/signal.c create mode 100644 plat/osx386/boot.s create mode 100644 plat/osx386/build-pkg.lua create mode 100644 plat/osx386/build-tools.lua create mode 100644 plat/osx386/descr create mode 100644 plat/osx386/include/build.lua create mode 100644 plat/osx386/libsys/_exit.s create mode 100644 plat/osx386/libsys/build.lua create mode 100644 plat/osx386/libsys/close.s create mode 100644 plat/osx386/libsys/getpid.s create mode 100644 plat/osx386/libsys/gettimeofday.s create mode 100644 plat/osx386/libsys/ioctl.s create mode 100644 plat/osx386/libsys/kill.s create mode 100644 plat/osx386/libsys/lseek.s create mode 100644 plat/osx386/libsys/mmap.s create mode 100644 plat/osx386/libsys/mprotect.s create mode 100644 plat/osx386/libsys/open.s create mode 100644 plat/osx386/libsys/read.s create mode 100644 plat/osx386/libsys/set_errno.s create mode 100644 plat/osx386/libsys/sigaction.s create mode 100644 plat/osx386/libsys/write.s create mode 100644 plat/osxppc/boot.s create mode 100644 plat/osxppc/build-pkg.lua create mode 100644 plat/osxppc/build-tools.lua create mode 100644 plat/osxppc/descr create mode 100644 plat/osxppc/include/build.lua create mode 100644 plat/osxppc/libsys/_exit.s create mode 100644 plat/osxppc/libsys/build.lua create mode 100644 plat/osxppc/libsys/close.s create mode 100644 plat/osxppc/libsys/getpid.s create mode 100644 plat/osxppc/libsys/gettimeofday.s create mode 100644 plat/osxppc/libsys/ioctl.s create mode 100644 plat/osxppc/libsys/kill.s create mode 100644 plat/osxppc/libsys/lseek.s create mode 100644 plat/osxppc/libsys/mmap.s create mode 100644 plat/osxppc/libsys/mprotect.s create mode 100644 plat/osxppc/libsys/open.s create mode 100644 plat/osxppc/libsys/read.s create mode 100644 plat/osxppc/libsys/set_errno.s create mode 100644 plat/osxppc/libsys/sigaction.s create mode 100644 plat/osxppc/libsys/write.s diff --git a/build.lua b/build.lua index 05a4eafcd..65ae6cb26 100644 --- a/build.lua +++ b/build.lua @@ -9,6 +9,8 @@ vars.plats = { "linux386", "linux68k", "linuxppc", + "osx386", + "osxppc", "pc86", "rpi", } diff --git a/plat/osx/cvmach/build.lua b/plat/osx/cvmach/build.lua new file mode 100644 index 000000000..ae4a18ecb --- /dev/null +++ b/plat/osx/cvmach/build.lua @@ -0,0 +1,17 @@ +cprogram { + name = "cvmach", + srcs = { "./cvmach.c" }, + deps = { + "h+emheaders", + -- Next line only because object.h includes ansi.h + "modules+headers", + "modules/src/object+lib", + } +} + +installable { + name = "pkg", + map = { + ["$(PLATDEP)/cvmach"] = "+cvmach", + } +} diff --git a/plat/osx/cvmach/cvmach.c b/plat/osx/cvmach/cvmach.c new file mode 100644 index 000000000..12a48696d --- /dev/null +++ b/plat/osx/cvmach/cvmach.c @@ -0,0 +1,418 @@ +/* + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ + +/* + * cvmach.c - convert ack.out to mach-o + * + * Mostly pinched from aelflod (util/amisc/aelflod.c), which pinched + * from the ARM cv (mach/arm/cv/cv.c), which pinched from the m68k2 cv + * (mach/m68k2/cv/cv.c). The code to read ack.out format using + * liboject is pinched from the Xenix i386 cv (mach/i386/cv/cv.c). + */ + +#include +#include +#include +#include +#include + +#include +/* Can't find #include */ + +/* Header and section table of ack.out */ +struct outhead outhead; +struct outsect outsect[S_MAX]; + +int bigendian; /* Emit big-endian Mach-o? */ +int cpu_type; +uint32_t entry; /* Virtual address of entry point */ +uint32_t sz_thread_command; + +char *outputfile = NULL; /* Name of output file, or NULL */ +char *program; /* Name of current program: argv[0] */ +FILE *output; /* Output stream */ +#define writef(a, b, c) fwrite((a), (b), (c), output) + +/* Segment numbers in ack.out */ +enum { + TEXT = 0, + ROM, + DATA, + BSS, + NUM_SEGMENTS +}; + +/* Constants from Mach headers */ +#define MH_MAGIC 0xfeedface +#define MH_EXECUTE 2 +#define LC_SEGMENT 1 +#define LC_UNIXTHREAD 5 + +#define CPU_TYPE_X86 7 +#define CPU_SUBTYPE_X86_ALL 3 +#define x86_THREAD_STATE32 1 +#define x86_THREAD_STATE32_COUNT 16 + +#define CPU_TYPE_POWERPC 18 +#define CPU_SUBTYPE_POWERPC_ALL 0 +#define PPC_THREAD_STATE 1 +#define PPC_THREAD_STATE_COUNT 40 + +#define VM_PROT_NONE 0x0 +#define VM_PROT_READ 0x1 +#define VM_PROT_WRITE 0x2 +#define VM_PROT_EXECUTE 0x4 + +/* sizes of Mach structs */ +#define SZ_MACH_HEADER 28 +#define SZ_SEGMENT_COMMAND 56 +#define SZ_THREAD_COMMAND_BF_STATE 16 + +/* the page size for x86 and PowerPC */ +#define CV_PGSZ 4096 +/* u modulo page size */ +#define pg_mod(u) ((u) & (CV_PGSZ - 1)) +/* u rounded down to whole pages */ +#define pg_trunc(u) ((u) & ~(CV_PGSZ - 1)) + + +void usage(void) +{ + fprintf(stderr, "Usage: %s -m \n", + program); + exit(1); +} + +/* Produce an error message and exit. */ +void fatal(const char* s, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ",program) ; + + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + if (outputfile) + unlink(outputfile); + exit(1); +} + +void rd_fatal(void) +{ + fatal("read error"); +} + +/* Calculate the result of a aligned to b (rounding up if necessary). + * b must be a power of two. */ +uint32_t align(uint32_t a, uint32_t b) +{ + a += b - 1; + return a & ~(b-1); +} + + +/* Writes out a 32-bit value in the appropriate endianness. */ +void emit32(uint32_t value) +{ + unsigned char buffer[4]; + + if (bigendian) + { + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = (value >> 0) & 0xFF; + } + else + { + buffer[3] = (value >> 24) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} + +/* Copies the contents of a section from the input stream + * to the output stream. */ +void emit_section(int section_nr) +{ + struct outsect *section = &outsect[section_nr]; + size_t blocksize; + uint32_t n = section->os_flen; + char buffer[BUFSIZ]; + + rd_outsect(section_nr); + while (n > 0) + { + blocksize = (n > BUFSIZ) ? BUFSIZ : n; + rd_emit(buffer, (long)blocksize); + writef(buffer, 1, blocksize); + n -= blocksize; + } + + /* Zero fill any remaining space. */ + n = section->os_size - section->os_flen; + if (n > 0) + { + memset(buffer, 0, BUFSIZ); + while (n > 0) + { + blocksize = (n > BUFSIZ) ? BUFSIZ : n; + writef(buffer, 1, blocksize); + n -= blocksize; + } + } +} + +void emit_lc_segment(char *name, uint32_t vm_ad, uint32_t vm_sz, + uint32_t f_off, uint32_t f_sz, int prot) +{ + char namebuf[16]; + int flags, maxprot; + + if (prot == VM_PROT_NONE) { + /* special values for __PAGEZERO */ + maxprot = VM_PROT_NONE; + flags = 4; /* NORELOC */ + } else { + maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; + flags = 0; + } + + /* Use strncpy() to pad namebuf with '\0' bytes. */ + strncpy(namebuf, name, sizeof(namebuf)); + + emit32(LC_SEGMENT); /* command */ + emit32(SZ_SEGMENT_COMMAND); /* size of command */ + writef(namebuf, 1, sizeof(namebuf)); + emit32(vm_ad); /* vm address */ + emit32(vm_sz); /* vm size */ + emit32(f_off); /* file offset */ + emit32(f_sz); /* file size */ + emit32(maxprot); /* max protection */ + emit32(prot); /* initial protection */ + emit32(0); /* number of Mach sections */ + emit32(flags); /* flags */ +} + +void emit_lc_unixthread(void) +{ + int i, ireg, ts, ts_count; + + /* + * The thread state has ts_count registers. The ireg'th + * register holds the entry point. We can set other registers + * to zero. At execution time, the kernel will allocate a + * stack and set the stack pointer. + */ + switch (cpu_type) { + case CPU_TYPE_X86: + ireg = 10; /* eip */ + ts = x86_THREAD_STATE32; + ts_count = x86_THREAD_STATE32_COUNT; + break; + case CPU_TYPE_POWERPC: + ireg = 0; /* srr0 */ + ts = PPC_THREAD_STATE; + ts_count = PPC_THREAD_STATE_COUNT; + break; + } + + emit32(LC_UNIXTHREAD); /* command */ + emit32(sz_thread_command); /* size of command */ + emit32(ts); /* thread state */ + emit32(ts_count); /* thread state count */ + for (i = 0; i < ts_count; i++) { + if (i == ireg) + emit32(entry); + else + emit32(0); + } +} + + +int main(int argc, char *argv[]) +{ + uint32_t len2, len3, mach_base, pad, sz_bf_entry, sz_load_cmds; + int cpu_subtype, mflag = 0; + + /* General housecleaning and setup. */ + output = stdout; + program = argv[0]; + + /* Read in and process any flags. */ + while ((argc > 1) && (argv[1][0] == '-')) { + switch (argv[1][1]) { + case 'm': /* machine cpu type */ + mflag = 1; + cpu_type = atoi(&argv[1][2]); + break; + case 'h': /* help */ + default: + usage(); + } + + argv++; + argc--; + } + + if (!mflag) + usage(); + + /* Check cpu type. */ + switch (cpu_type) { + case CPU_TYPE_X86: + bigendian = 0; + cpu_subtype = CPU_SUBTYPE_X86_ALL; + sz_thread_command = 4 * x86_THREAD_STATE32_COUNT; + break; + case CPU_TYPE_POWERPC: + bigendian = 1; + cpu_subtype = CPU_SUBTYPE_POWERPC_ALL; + sz_thread_command = 4 * PPC_THREAD_STATE_COUNT; + break; + default: + /* Can't emit LC_UNIXTHREAD for unknown cpu. */ + fatal("unknown cpu type -m%d", cpu_type); + } + sz_thread_command += SZ_THREAD_COMMAND_BF_STATE; + + /* Process the rest of the arguments. */ + switch (argc) { + case 1: /* No parameters --- read from stdin, write to stdout. */ + rd_fdopen(0); + break; + + case 3: /* Both input and output files specified. */ + output = fopen(argv[2], "w"); + if (!output) + fatal("unable to open output file."); + outputfile = argv[2]; + /* FALLTHROUGH */ + + case 2: /* Input file specified. */ + if (! rd_open(argv[1])) + fatal("unable to open input file."); + break; + + default: + usage(); + } + + rd_ohead(&outhead); + if (BADMAGIC(outhead)) + fatal("Not an ack object file."); + if (outhead.oh_flags & HF_LINK) + fatal("Contains unresolved references."); + if (outhead.oh_nrelo > 0) + fprintf(stderr, "Warning: relocation information present."); + if (outhead.oh_nsect != NUM_SEGMENTS && + outhead.oh_nsect != NUM_SEGMENTS + 1 ) { + fatal("Input file must have %d sections, not %ld\n", + NUM_SEGMENTS, (long)outhead.oh_nsect); + } + + rd_sect(outsect, outhead.oh_nsect); + + /* + * 1st Mach segment: __PAGEZERO + * 2nd Mach segment: __TEXT + * Mach headers and load commands + * ack TEXT + * ack ROM + * 3rd Mach segment: __DATA + * ack DATA + * ack BSS + */ + + /* Find entry point and check that TEXT begins there. */ + mach_base = pg_trunc(outsect[TEXT].os_base); + sz_load_cmds = 3 * SZ_SEGMENT_COMMAND + sz_thread_command; + sz_bf_entry = SZ_MACH_HEADER + sz_load_cmds; + entry = mach_base + sz_bf_entry; + if (entry != outsect[TEXT].os_base) { + fatal("text segment must have base 0x%lx, not 0x%lx\n", + entry, outsect[TEXT].os_base); + } + + /* Check that ROM can follow TEXT in 2nd Mach segment. */ + outsect[TEXT].os_size = + align(outsect[TEXT].os_size, outsect[ROM].os_lign); + if (outsect[ROM].os_base != + outsect[TEXT].os_base + outsect[TEXT].os_size) + fatal("the rom segment must follow the text segment."); + + /* + * Insert padding between ROM and DATA, such that + * pg_mod(len2) == pg_mod(outsect[DATA].os_base) + * + * This will allow us to map the 3rd Mach segment at the + * beginning of a page, such that DATA is at its base. + */ + len2 = sz_bf_entry + outsect[TEXT].os_size + outsect[ROM].os_size; + pad = pg_mod(outsect[DATA].os_base - len2); + outsect[ROM].os_size += pad; + len2 = pg_trunc(len2 + pad); + + /* Check that BSS can follow DATA in 3rd Mach segment. */ + if (outsect[BSS].os_flen != 0) + fatal("the bss space contains initialized data."); + if (outsect[BSS].os_base < + outsect[DATA].os_base + outsect[DATA].os_size) + fatal("the bss segment must follow the data segment."); + + len3 = outsect[BSS].os_base - pg_trunc(outsect[DATA].os_base) + + outsect[BSS].os_size; + + if (outhead.oh_nsect == NUM_SEGMENTS + 1) { + if (outsect[NUM_SEGMENTS].os_base != + outsect[BSS].os_base + outsect[BSS].os_size) + fatal("end segment must follow bss"); + if (outsect[NUM_SEGMENTS].os_size != 0) + fatal("end segment must be empty"); + } + + /* Emit the Mach header. */ + emit32(MH_MAGIC); /* magic */ + emit32(cpu_type); /* cpu type */ + emit32(cpu_subtype); /* cpu subtype */ + emit32(MH_EXECUTE); /* file type */ + emit32(4); /* number of load commands */ + emit32(sz_load_cmds); /* size of load commands */ + emit32(0); /* flags */ + + /* vm address: vm size: + * 1st Mach segment: NULL CV_PGSZ + * 2nd Mach segment: mach_base len2 + * 3rd Mach segment: mach_base+len2 len3 + * + * file offset: file size: + * 2nd Mach segment: 0 len2 + * 3rd Mach segment: len2 DATA os_size + */ + emit_lc_segment("__PAGEZERO", 0 /* NULL */, CV_PGSZ, + 0, 0, VM_PROT_NONE); + emit_lc_segment("__TEXT", mach_base, len2, + 0, len2, VM_PROT_READ | VM_PROT_EXECUTE); + emit_lc_segment("__DATA", mach_base + len2, len3, + len2, outsect[DATA].os_size, VM_PROT_READ | VM_PROT_WRITE); + emit_lc_unixthread(); + + /* Emit non-empty sections. */ + emit_section(TEXT); + emit_section(ROM); + emit_section(DATA); + + if (ferror(output)) + fatal("write error"); + + return 0; +} diff --git a/plat/osx/include/ack/config.h b/plat/osx/include/ack/config.h new file mode 100644 index 000000000..af4a90ed2 --- /dev/null +++ b/plat/osx/include/ack/config.h @@ -0,0 +1,14 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#ifndef _ACK_CONFIG_H +#define _ACK_CONFIG_H + +/* We're providing a time() system call rather than wanting a wrapper around + * gettimeofday() in the libc. */ + +/* #define ACKCONF_TIME_IS_A_SYSCALL */ + +#endif diff --git a/plat/osx/include/sys/mman.h b/plat/osx/include/sys/mman.h new file mode 100644 index 000000000..5a844c4b6 --- /dev/null +++ b/plat/osx/include/sys/mman.h @@ -0,0 +1,20 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include + +#define MAP_FAILED ((void *)-1) + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_PRIVATE 0x0002 +#define MAP_FIXED 0x0010 +#define MAP_ANON 0x1000 + +void *mmap(void *, size_t, int, int, int, off_t); +int mprotect(void *, size_t, int); + +#endif diff --git a/plat/osx/include/sys/types.h b/plat/osx/include/sys/types.h new file mode 100644 index 000000000..a9fb63277 --- /dev/null +++ b/plat/osx/include/sys/types.h @@ -0,0 +1,9 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#include /* for off_t, ptrdiff_t, size_t */ + +typedef int pid_t; +typedef ptrdiff_t ssize_t; + +#endif diff --git a/plat/osx/include/unistd.h b/plat/osx/include/unistd.h new file mode 100644 index 000000000..24eaf4e54 --- /dev/null +++ b/plat/osx/include/unistd.h @@ -0,0 +1,132 @@ +#ifndef _UNISTD_H +#define _UNISTD_H + +#include + +/* + * XXX - The following parts belong in other header files, + * but those headers are including us! + */ + +/* XXX - begin sys/ioctl.h */ + +#define TIOCGETD 0x4004741a + +int ioctl(int, unsigned long, ...); + +/* XXX - end sys/ioctl.h */ + +/* XXX - begin sys/time.h */ + +/* Don't conflict with time_t from */ +typedef long _libsys_time_t; +typedef int suseconds_t; + +struct timeval { + _libsys_time_t tv_sec; + suseconds_t tv_usec; +}; + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +int gettimeofday(struct timeval *, struct timezone *); + +/* XXX - end sys/time.h */ + +/* XXX - begin fcntl.h */ + +/* flags for open() */ +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_NONBLOCK 0x0004 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 + +typedef int mode_t; + +int creat(const char *, mode_t); +int open(const char *, int, ...); + +/* XXX - end fcntl.h */ + +/* XXX - begin signal.h */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGEMT 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGBUS 10 +#define SIGSEGV 11 +#define SIGSYS 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGURG 16 +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGIO 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGINFO 29 +#define SIGUSR1 30 +#define SIGUSR2 31 +#define _NSIG 32 + +/* sa_flags */ +#define SA_RESTART 0x0002 + +typedef void (*sig_t)(int); +#define SIG_DFL ((sig_t)0) +#define SIG_IGN ((sig_t)1) +#define SIG_ERR ((sig_t)-1) + +typedef unsigned int sigset_t; + +struct __siginfo; + +struct sigaction { + union { + void (*__sa_handler)(int); + void (*__sa_sigaction)(int, struct __siginfo *, void *); + } __sigaction_u; + sigset_t sa_mask; + int sa_flags; +}; +#define sa_handler __sigaction_u.__sa_handler +#define sa_sigaction __sigaction_u.__sa_sigaction + +int kill(pid_t, int); +int sigaction(int, const struct sigaction *, struct sigaction *); +sig_t signal(int, sig_t); + +/* XXX - end signal.h */ + +void _exit(int); +int brk(void *); +int close(int); +pid_t getpid(void); +int isatty(int); +off_t lseek(int, off_t, int); +ssize_t read(int, void *, size_t); +void *sbrk(int); +ssize_t write(int, const void *, size_t); + +#endif diff --git a/plat/osx/libsys/brk.c b/plat/osx/libsys/brk.c new file mode 100644 index 000000000..a732cac1c --- /dev/null +++ b/plat/osx/libsys/brk.c @@ -0,0 +1,95 @@ +/* + * This emulates brk() and sbrk() using mmap() and mprotect(). + * + * We reserve exactly SEGMENTSZ bytes of address space by calling + * mmap() with PROT_NONE. Then we allocate pages in our segment by + * calling mprotect() with PROT_READ|PROT_WRITE. + * + * This emulation can't resize its segment. If SEGMENTSZ is too big, + * then programs might run out of address space for other mappings. + */ +#include +#include +#include + +/* + * PAGESZ must be correct for this system! + * SEGMENTSZ must be a multiple of PAGESZ. + */ +#define PAGESZ 0x1000 /* page size for i386, powerpc */ +#define SEGMENTSZ 0x20000000 + +static char *segment; +static char *cbreak; /* current break */ + +static void brk_init(void) +{ + /* + * Try exactly once to reserve our segment. If we fail, then + * segment == MAP_FAILED and we never try again. + */ + if (segment == NULL) { + segment = mmap(NULL, SEGMENTSZ, PROT_NONE, + MAP_PRIVATE|MAP_ANON, -1, 0); + cbreak = segment; + } +} + +static int brk1(char *nbreak) +{ + size_t sz; + char *new, *old; + + sz = (segment == MAP_FAILED) ? 0 : SEGMENTSZ; + if (nbreak < segment || nbreak > segment + sz) { + errno = ENOMEM; + return -1; + } + + /* Round up to page size. */ + old = (char *)(((size_t)cbreak + (PAGESZ-1)) & ~(PAGESZ-1)); + new = (char *)(((size_t)nbreak + (PAGESZ-1)) & ~(PAGESZ-1)); + + if (new > old) { + /* Allocate pages by unprotecting them. */ + if (mprotect(old, new - old, PROT_READ|PROT_WRITE) < 0) { + errno = ENOMEM; + return -1; + } + } else if (new < old) { + /* + * Free pages by using MAP_FIXED to replace the + * mapping. Ignore errors. + */ + mmap(new, old - new, PROT_NONE, + MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0); + } + cbreak = nbreak; + return 0; +} + +int brk(void *addr) +{ + brk_init(); + return brk1(addr); +} + +void *sbrk(int incr) +{ + char *base, *nbreak; + + brk_init(); + base = cbreak; + nbreak = base + incr; + + /* Did base + incr overflow? */ + if ((incr < 0 && nbreak > base) || + (incr > 0 && nbreak < base)) { + errno = ENOMEM; + return (void*)-1; + } + + if (brk1(nbreak) < 0) + return (void*)-1; + return base; +} diff --git a/plat/osx/libsys/creat.c b/plat/osx/libsys/creat.c new file mode 100644 index 000000000..df2c82275 --- /dev/null +++ b/plat/osx/libsys/creat.c @@ -0,0 +1,6 @@ +#include + +int creat(const char *path, mode_t mode) +{ + open(path, O_CREAT | O_TRUNC | O_WRONLY, mode); +} diff --git a/plat/osx/libsys/isatty.c b/plat/osx/libsys/isatty.c new file mode 100644 index 000000000..1da6509df --- /dev/null +++ b/plat/osx/libsys/isatty.c @@ -0,0 +1,7 @@ +#include + +int isatty(int fd) +{ + int line_disc; + return 0 <= ioctl(fd, TIOCGETD, &line_disc); +} diff --git a/plat/osx/libsys/signal.c b/plat/osx/libsys/signal.c new file mode 100644 index 000000000..0c1e12624 --- /dev/null +++ b/plat/osx/libsys/signal.c @@ -0,0 +1,16 @@ +#include + +sig_t signal(int sig, sig_t func) +{ + struct sigaction newsa, oldsa; + int i; + + newsa.sa_handler = func; + newsa.sa_mask = 0; /* empty set */ + newsa.sa_flags = SA_RESTART; + + i = sigaction(sig, &newsa, &oldsa); + if (i < 0) + return SIG_ERR; + return oldsa.sa_handler; +} diff --git a/plat/osx386/boot.s b/plat/osx386/boot.s new file mode 100644 index 000000000..0db4bc715 --- /dev/null +++ b/plat/osx386/boot.s @@ -0,0 +1,69 @@ +! plat/osx386/boot.s + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +begtext: + ! This code is placed at the entry point of the Mach-o + ! executable and is the first thing that runs. + ! + ! On entry, the stack looks like this: + ! + ! sp+.. NULL + ! sp+8+(4*argc) env (X quads) + ! sp+4+(4*argc) NULL + ! sp+4 argv (argc quads) + ! sp argc + ! + ! The ACK actually expects: + ! + ! sp+8 argc + ! sp+4 argv + ! sp env + + mov eax, (esp) ! eax = argc + lea ebx, 4(esp) ! ebx = argv + lea ecx, (esp)(eax*4) + add ecx, 12 ! environ + + push ecx ! environ + push ebx ! argc + push eax ! argv + push eax ! dummy, representing the return argument + xor ebp, ebp + + jmp __m_a_i_n + + ! This provides an emergency exit routine used by EM. + +.define EXIT +.extern EXIT +EXIT: + push 1 + jmp __exit + +.sect rom +begrom: + +.sect .data +begdata: + +! Some magic data. All EM systems need these. + +.sect .bss +begbss: +.define hol0 +.comm hol0, 8 ! line number and filename (for debugging) + +.define _errno +.comm _errno, 4 ! Posix errno storage + +.define .trppc, .ignmask +.comm .trppc, 4 ! ptr to user trap handler +.comm .ignmask, 4 ! user trap ignore mask diff --git a/plat/osx386/build-pkg.lua b/plat/osx386/build-pkg.lua new file mode 100644 index 000000000..8c129c8e7 --- /dev/null +++ b/plat/osx386/build-pkg.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + vars = { plat = "osx386" } +} + +build_plat_libs { + name = "libs", + arch = "i386", + plat = "osx386", +} + +installable { + name = "pkg", + map = { + "+tools", + "+libs", + "./include+pkg", + ["$(PLATIND)/osx386/boot.o"] = "+boot", + ["$(PLATIND)/osx386/libsys.a"] = "./libsys+lib", + } +} diff --git a/plat/osx386/build-tools.lua b/plat/osx386/build-tools.lua new file mode 100644 index 000000000..097cb94d3 --- /dev/null +++ b/plat/osx386/build-tools.lua @@ -0,0 +1,9 @@ +return installable { + name = "tools", + map = { + ["$(PLATIND)/descr/osx386"] = "./descr", + "plat/linux386+tools", + "plat/osx/cvmach+pkg", + "util/opt+pkg", + } +} diff --git a/plat/osx386/descr b/plat/osx386/descr new file mode 100644 index 000000000..f1ba978ef --- /dev/null +++ b/plat/osx386/descr @@ -0,0 +1,80 @@ +# plat/osx386/descr + +var w=4 +var wa=4 +var p={w} +var pa={w} +var s=2 +var sa={s} +var l={w} +var la={w} +var f={w} +var fa={w} +var d=8 +var da={d} +var x=8 +var xa={x} +var ARCH=i386 +var PLATFORM=osx386 +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__unix +var ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x1114 +var C_LIB={PLATFORMDIR}/libc-ansi.a +# bitfields reversed for compatibility with (g)cc. +var CC_ALIGN=-Vr +var OLD_C_LIB={C_LIB} +var MACHOPT_F=-m10 +var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr + +# Override the setting in fe so that files compiled for osx386 can see +# the platform-specific headers. + +var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + program {EM}/lib/ack/linux386/ncg + mapflag -gdb GF=-gdb + args {GF?} < + stdout + need .e +end +name as + from .s.so + to .o + program {EM}/lib/ack/linux386/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib/ack/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -fp FLOATS={EM}/{LIB}fp + args {ALIGN} {SEPID?} \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.mod={PLATFORMDIR}/modula2.o) \ + ({RTS}:.p={PLATFORMDIR}/pascal.o) \ + -o > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .exe + program {EM}/lib/ack/cvmach + args -m7 < > + outfile osx386.exe +end diff --git a/plat/osx386/include/build.lua b/plat/osx386/include/build.lua new file mode 100644 index 000000000..420518f66 --- /dev/null +++ b/plat/osx386/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "plat/osx/include/"..h + packagemap["$(PLATIND)/osx386/include/"..h] = "plat/osx/include/"..h +end + +addheader("ack/config.h") +addheader("sys/mman.h") +addheader("sys/types.h") +addheader("unistd.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} diff --git a/plat/osx386/libsys/_exit.s b/plat/osx386/libsys/_exit.s new file mode 100644 index 000000000..80d30134b --- /dev/null +++ b/plat/osx386/libsys/_exit.s @@ -0,0 +1,5 @@ +.sect .text +.define __exit +__exit: + mov eax, 1 + int 0x80 diff --git a/plat/osx386/libsys/build.lua b/plat/osx386/libsys/build.lua new file mode 100644 index 000000000..a5356ee6c --- /dev/null +++ b/plat/osx386/libsys/build.lua @@ -0,0 +1,31 @@ +acklibrary { + name = "lib", + srcs = { + "./_exit.s", + "./close.s", + "./getpid.s", + "./gettimeofday.s", + "./ioctl.s", + "./kill.s", + "./lseek.s", + "./mmap.s", + "./mprotect.s", + "./open.s", + "./read.s", + "./set_errno.s", + "./sigaction.s", + "./write.s", + "plat/linux/libsys/errno.s", + "plat/osx/libsys/brk.c", + "plat/osx/libsys/creat.c", + "plat/osx/libsys/isatty.c", + "plat/osx/libsys/signal.c", + }, + deps = { + "lang/cem/libcc.ansi/headers+headers", + "plat/osx386/include+headers", + }, + vars = { + plat = "osx386" + } +} diff --git a/plat/osx386/libsys/close.s b/plat/osx386/libsys/close.s new file mode 100644 index 000000000..295b90ad1 --- /dev/null +++ b/plat/osx386/libsys/close.s @@ -0,0 +1,7 @@ +.sect .text +.define _close +_close: + mov eax, 6 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/getpid.s b/plat/osx386/libsys/getpid.s new file mode 100644 index 000000000..150791bb4 --- /dev/null +++ b/plat/osx386/libsys/getpid.s @@ -0,0 +1,7 @@ +.sect .text +.define _getpid +_getpid: + mov eax, 20 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/gettimeofday.s b/plat/osx386/libsys/gettimeofday.s new file mode 100644 index 000000000..3a4c2229f --- /dev/null +++ b/plat/osx386/libsys/gettimeofday.s @@ -0,0 +1,7 @@ +.sect .text +.define _gettimeofday +_gettimeofday: + mov eax, 116 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/ioctl.s b/plat/osx386/libsys/ioctl.s new file mode 100644 index 000000000..5b13e2cfb --- /dev/null +++ b/plat/osx386/libsys/ioctl.s @@ -0,0 +1,7 @@ +.sect .text +.define _ioctl +_ioctl: + mov eax, 54 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/kill.s b/plat/osx386/libsys/kill.s new file mode 100644 index 000000000..8fdce95fd --- /dev/null +++ b/plat/osx386/libsys/kill.s @@ -0,0 +1,7 @@ +.sect .text +.define _kill +_kill: + mov eax, 37 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/lseek.s b/plat/osx386/libsys/lseek.s new file mode 100644 index 000000000..22543b2eb --- /dev/null +++ b/plat/osx386/libsys/lseek.s @@ -0,0 +1,17 @@ +.sect .text +.define _lseek +_lseek: + ! ack passes 4-byte off_t, but system call takes 8-byte off_t + mov eax, esp + push 12(eax) ! whence + push 0 ! offset (high long) + push 8(eax) ! offset (low long) + push 4(eax) ! fd + call 1f + add esp, 16 + ret +1: + mov eax, 199 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/mmap.s b/plat/osx386/libsys/mmap.s new file mode 100644 index 000000000..e39ea777a --- /dev/null +++ b/plat/osx386/libsys/mmap.s @@ -0,0 +1,20 @@ +.sect .text +.define _mmap +_mmap: + ! ack passes 4-byte off_t, but system call takes 8-byte off_t + mov eax, esp + push 0 ! offset (high long) + push 24(eax) ! offset (low long) + push 20(eax) ! fd + push 16(eax) ! flags + push 12(eax) ! protection + push 8(eax) ! length + push 4(eax) ! address + call 1f + add esp, 28 + ret +1: + mov eax, 197 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/mprotect.s b/plat/osx386/libsys/mprotect.s new file mode 100644 index 000000000..641173a16 --- /dev/null +++ b/plat/osx386/libsys/mprotect.s @@ -0,0 +1,7 @@ +.sect .text +.define _mprotect +_mprotect: + mov eax, 74 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/open.s b/plat/osx386/libsys/open.s new file mode 100644 index 000000000..154c00506 --- /dev/null +++ b/plat/osx386/libsys/open.s @@ -0,0 +1,7 @@ +.sect .text +.define _open +_open: + mov eax, 5 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/read.s b/plat/osx386/libsys/read.s new file mode 100644 index 000000000..ccd3f8162 --- /dev/null +++ b/plat/osx386/libsys/read.s @@ -0,0 +1,7 @@ +.sect .text +.define _read +_read: + mov eax, 3 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/set_errno.s b/plat/osx386/libsys/set_errno.s new file mode 100644 index 000000000..ff0823483 --- /dev/null +++ b/plat/osx386/libsys/set_errno.s @@ -0,0 +1,6 @@ +.sect .text +.define .set_errno +.set_errno: + mov (_errno), eax + mov eax, -1 + ret diff --git a/plat/osx386/libsys/sigaction.s b/plat/osx386/libsys/sigaction.s new file mode 100644 index 000000000..2909cbe02 --- /dev/null +++ b/plat/osx386/libsys/sigaction.s @@ -0,0 +1,59 @@ +! OS X, unlike FreeBSD, requires us to provide our own signal +! trampoline. We must change the new action from a struct sigaction +! to a bigger struct that includes the trampoline. + +.sect .text +.define _sigaction +_sigaction: + mov eax, esp + mov ebx, 8(esp) ! ebx = ptr to new action + cmp ebx, 0 + je 1f + ! push bigger struct + push 8(ebx) ! sa_flags + push 4(ebx) ! sa_mask + push trampoline ! sa_tramp + push 0(ebx) ! sa_handler + mov ebx, esp + jmp 2f +1: + sub esp, 16 +2: + push 12(eax) ! ptr to old action + push ebx ! ptr to bigger struct + push 4(eax) ! sig + call 3f + add esp, 28 + ret +3: + mov eax, 46 + int 0x80 + jb .set_errno + ret + +trampoline: + ! 4(esp) = handler + ! 8(esp) = info style + ! 12(esp) = sig + ! 16(esp) = info + ! 20(esp) = context + + ! Call handler(sig, info, context) + mov eax, esp + push 20(eax) + push 16(eax) + push 12(eax) + call 4(eax) + add esp, 12 + + ! Return from trampoline. + mov eax, esp + push 8(eax) ! info style + push 20(eax) ! context + sub esp, 4 + mov eax, 184 ! sigreturn + int 0x80 + + ! Only if sigreturn() fails: + mov eax, 1 ! exit + int 0x80 diff --git a/plat/osx386/libsys/write.s b/plat/osx386/libsys/write.s new file mode 100644 index 000000000..a32d4d78a --- /dev/null +++ b/plat/osx386/libsys/write.s @@ -0,0 +1,7 @@ +.sect .text +.define _write +_write: + mov eax, 4 + int 0x80 + jb .set_errno + ret diff --git a/plat/osxppc/boot.s b/plat/osxppc/boot.s new file mode 100644 index 000000000..a1ee67166 --- /dev/null +++ b/plat/osxppc/boot.s @@ -0,0 +1,60 @@ +! boot.s for osx386 + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +begtext: + ! This code is placed at the entry point of the Mach-o + ! executable and is the first thing that runs. + ! + ! On entry, the stack looks like this: + ! + ! sp+... NULL + ! sp+8+(4*argc) env (X quads) + ! sp+4+(4*argc) NULL + ! sp+4 argv (argc quads) + ! sp argc + ! + ! The ACK actually expects: + ! + ! sp+8 argc + ! sp+4 ptr to argv + ! sp ptr to env + + lwz r3, 0(sp) ! r3 = argc + addi r4, sp, 4 ! r4 = argv + rlwinm r5, r3, 32-2, 2, 31 ! shift left 2 bits + add r5, r5, r4 + addi r5, r5, 8 ! r5 = env + + stwu r5, -4(sp) + stwu r4, -4(sp) + stwu r3, -4(sp) + + b __m_a_i_n + +.sect rom +begrom: + +.sect .data +begdata: + +! Some magic data. All EM systems need these. + +.sect .bss +begbss: +.define hol0 +.comm hol0, 8 ! line number and filename (for debugging) + +.define _errno +.comm _errno, 4 ! Posix errno storage + +.define .trppc, .ignmask +.comm .trppc, 4 ! ptr to user trap handler +.comm .ignmask, 4 ! user trap ignore mask diff --git a/plat/osxppc/build-pkg.lua b/plat/osxppc/build-pkg.lua new file mode 100644 index 000000000..d6f6d5558 --- /dev/null +++ b/plat/osxppc/build-pkg.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + vars = { plat = "osxppc" } +} + +build_plat_libs { + name = "libs", + arch = "powerpc", + plat = "osxppc", +} + +installable { + name = "pkg", + map = { + "+tools", + "+libs", + "./include+pkg", + ["$(PLATIND)/osxppc/boot.o"] = "+boot", + ["$(PLATIND)/osxppc/libsys.a"] = "./libsys+lib", + } +} diff --git a/plat/osxppc/build-tools.lua b/plat/osxppc/build-tools.lua new file mode 100644 index 000000000..d19d25e19 --- /dev/null +++ b/plat/osxppc/build-tools.lua @@ -0,0 +1,9 @@ +return installable { + name = "tools", + map = { + ["$(PLATIND)/descr/osxppc"] = "./descr", + "plat/linuxppc+tools", + "plat/osx/cvmach+pkg", + "util/opt+pkg", + } +} diff --git a/plat/osxppc/descr b/plat/osxppc/descr new file mode 100644 index 000000000..3ee01752d --- /dev/null +++ b/plat/osxppc/descr @@ -0,0 +1,81 @@ +# plat/osxppc/descr + +var w=4 +var wa=4 +var p={w} +var pa={w} +var s=2 +var sa={s} +var l={w} +var la={w} +var f={w} +var fa={w} +var d=8 +var da={d} +var x=8 +var xa={x} +var ARCH=powerpc +var PLATFORM=osxppc +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__unix +var ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x1174 +var C_LIB={PLATFORMDIR}/libc-ansi.a +# bitfields reversed for compatibility with (g)cc. +# XXX this is from linux386, might be wrong for osxppc +var CC_ALIGN=-Vr +var OLD_C_LIB={C_LIB} +var MACHOPT_F=-m10 +# var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr + +# Override the setting in fe so that files compiled for osxppc can see +# the platform-specific headers. + +var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + program {EM}/lib/ack/linuxppc/ncg + mapflag -gdb GF=-gdb + args {GF?} < + stdout + need .e +end +name as + from .s.so + to .o + program {EM}/lib/ack/linuxppc/as + args - -o > < + prep cond +end +name led + from .o.a + to .out + program {EM}/lib/ack/em_led + mapflag -l* LNAME={PLATFORMDIR}/lib* + mapflag -fp FLOATS={EM}/{LIB}fp + args {ALIGN} {SEPID?} \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \ + ({RTS}:.mod={PLATFORMDIR}/modula2.o) \ + ({RTS}:.p={PLATFORMDIR}/pascal.o) \ + -o > < \ + (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \ + (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \ + {FLOATS?} \ + (.e:{TAIL}={PLATFORMDIR}/libem.a \ + {PLATFORMDIR}/libsys.a \ + {PLATFORMDIR}/libend.a) + linker +end +name cv + from .out + to .exe + program {EM}/lib/ack/cvmach + args -m18 < > + outfile osxppc.exe +end diff --git a/plat/osxppc/include/build.lua b/plat/osxppc/include/build.lua new file mode 100644 index 000000000..375c99535 --- /dev/null +++ b/plat/osxppc/include/build.lua @@ -0,0 +1,24 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "plat/osx/include/"..h + packagemap["$(PLATIND)/osxppc/include/"..h] = "plat/osx/include/"..h +end + +addheader("ack/config.h") +addheader("sys/mman.h") +addheader("sys/types.h") +addheader("unistd.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} diff --git a/plat/osxppc/libsys/_exit.s b/plat/osxppc/libsys/_exit.s new file mode 100644 index 000000000..6ffe502d5 --- /dev/null +++ b/plat/osxppc/libsys/_exit.s @@ -0,0 +1,6 @@ +.sect .text +.define __exit +__exit: + addi r0, r0, 1 ! _exit + lwz r3, 0(sp) ! status + sc 0 diff --git a/plat/osxppc/libsys/build.lua b/plat/osxppc/libsys/build.lua new file mode 100644 index 000000000..a595ed0fa --- /dev/null +++ b/plat/osxppc/libsys/build.lua @@ -0,0 +1,31 @@ +acklibrary { + name = "lib", + srcs = { + "./_exit.s", + "./close.s", + "./getpid.s", + "./gettimeofday.s", + "./ioctl.s", + "./kill.s", + "./lseek.s", + "./mmap.s", + "./mprotect.s", + "./open.s", + "./read.s", + "./set_errno.s", + "./sigaction.s", + "./write.s", + "plat/linuxppc/libsys/trap.s", + "plat/osx/libsys/brk.c", + "plat/osx/libsys/creat.c", + "plat/osx/libsys/isatty.c", + "plat/osx/libsys/signal.c", + }, + deps = { + "lang/cem/libcc.ansi/headers+headers", + "plat/osxppc/include+headers", + }, + vars = { + plat = "osxppc" + } +} diff --git a/plat/osxppc/libsys/close.s b/plat/osxppc/libsys/close.s new file mode 100644 index 000000000..a799b5e9d --- /dev/null +++ b/plat/osxppc/libsys/close.s @@ -0,0 +1,8 @@ +.sect .text +.define _close +_close: + addi r0, r0, 6 ! close + lwz r3, 0(sp) ! fd + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/getpid.s b/plat/osxppc/libsys/getpid.s new file mode 100644 index 000000000..36525cf43 --- /dev/null +++ b/plat/osxppc/libsys/getpid.s @@ -0,0 +1,7 @@ +.sect .text +.define _getpid +_getpid: + addi r0, r0, 20 ! getpid + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/gettimeofday.s b/plat/osxppc/libsys/gettimeofday.s new file mode 100644 index 000000000..c01bf5bae --- /dev/null +++ b/plat/osxppc/libsys/gettimeofday.s @@ -0,0 +1,9 @@ +.sect .text +.define _gettimeofday +_gettimeofday: + addi r0, r0, 116 ! gettimeofday + lwz r3, 0(sp) ! timeval pointer + lwz r4, 4(sp) ! timezone pointer + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/ioctl.s b/plat/osxppc/libsys/ioctl.s new file mode 100644 index 000000000..685ba8499 --- /dev/null +++ b/plat/osxppc/libsys/ioctl.s @@ -0,0 +1,10 @@ +.sect .text +.define _ioctl +_ioctl: + addi r0, r0, 54 ! ioctl + lwz r3, 0(sp) ! fd + lwz r4, 4(sp) ! command + lwz r5, 8(sp) ! argument pointer + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/kill.s b/plat/osxppc/libsys/kill.s new file mode 100644 index 000000000..4c7d5566f --- /dev/null +++ b/plat/osxppc/libsys/kill.s @@ -0,0 +1,9 @@ +.sect .text +.define _kill +_kill: + addi r0, r0, 37 ! kill + lwz r3, 0(sp) ! pid + lwz r4, 4(sp) ! signal + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/lseek.s b/plat/osxppc/libsys/lseek.s new file mode 100644 index 000000000..129b08a8d --- /dev/null +++ b/plat/osxppc/libsys/lseek.s @@ -0,0 +1,13 @@ +.sect .text +.define _lseek +_lseek: + addi r0, r0, 199 ! lseek + lwz r3, 0(sp) ! fd + ! ack passes 4-byte off_t, but system call takes 8-byte off_t + addi r4, r0, 0 ! offset (high word) + lwz r5, 4(sp) ! offset (low word) + lwz r6, 8(sp) ! whence + sc 0 + b .set_errno + or r3, r4, r4 ! return offset (low word) + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/mmap.s b/plat/osxppc/libsys/mmap.s new file mode 100644 index 000000000..f2ec5e28b --- /dev/null +++ b/plat/osxppc/libsys/mmap.s @@ -0,0 +1,15 @@ +.sect .text +.define _mmap +_mmap: + addi r0, r0, 197 ! mmap + lwz r3, 0(sp) ! address + lwz r4, 4(sp) ! length + lwz r5, 8(sp) ! protection + lwz r6, 12(sp) ! flags + lwz r7, 16(sp) ! fd + ! ack passes 4-byte off_t, but system call takes 8-byte off_t + addi r8, r0, 0 ! offset (high word) + lwz r9, 20(sp) ! offset (low word) + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/mprotect.s b/plat/osxppc/libsys/mprotect.s new file mode 100644 index 000000000..fbea70251 --- /dev/null +++ b/plat/osxppc/libsys/mprotect.s @@ -0,0 +1,10 @@ +.sect .text +.define _mprotect +_mprotect: + addi r0, r0, 74 ! mprotect + lwz r3, 0(sp) ! address + lwz r4, 4(sp) ! length + lwz r5, 8(sp) ! protection + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/open.s b/plat/osxppc/libsys/open.s new file mode 100644 index 000000000..1d066c7ad --- /dev/null +++ b/plat/osxppc/libsys/open.s @@ -0,0 +1,10 @@ +.sect .text +.define _open +_open: + addi r0, r0, 5 ! open + lwz r3, 0(sp) ! path + lwz r4, 4(sp) ! flags + lwz r5, 8(sp) ! mode + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/read.s b/plat/osxppc/libsys/read.s new file mode 100644 index 000000000..849da5932 --- /dev/null +++ b/plat/osxppc/libsys/read.s @@ -0,0 +1,10 @@ +.sect .text +.define _read +_read: + addi r0, r0, 3 ! read + lwz r3, 0(sp) ! fd + lwz r4, 4(sp) ! buffer + lwz r5, 8(sp) ! buffer size + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/set_errno.s b/plat/osxppc/libsys/set_errno.s new file mode 100644 index 000000000..e406865a6 --- /dev/null +++ b/plat/osxppc/libsys/set_errno.s @@ -0,0 +1,7 @@ +.sect .text +.define .set_errno +.set_errno: + li32 r10, _errno + stw r3, 0(r10) ! set errno + addi r3, r0, -1 ! return -1 + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/sigaction.s b/plat/osxppc/libsys/sigaction.s new file mode 100644 index 000000000..f330c88a5 --- /dev/null +++ b/plat/osxppc/libsys/sigaction.s @@ -0,0 +1,59 @@ +#define IFTRUE 12 +#define ALWAYS 20 +#define EQ 2 + +! OS X, unlike FreeBSD, requires us to provide our own signal +! trampoline. We must change the new action from a struct sigaction +! to a bigger struct that includes the trampoline. + +.sect .text +.define _sigaction +_sigaction: + addi r0, r0, 46 ! sigaction + lwz r3, 0(sp) ! sig + lwz r4, 4(sp) ! ptr to new action + lwz r5, 8(sp) ! ptr to old action + or. r6, r4, r4 + bc IFTRUE, EQ, 1f ! skip if new action is NULL + + ! We may use the "red zone" from -224(sp) to 0(sp). + addi r4, sp, -16 ! r4 = bigger struct + lwz r7, 0(r6) + stw r7, 0(r4) ! sa_handler + li32 r7, trampoline + stw r7, 4(r4) ! sa_tramp + lwz r7, 4(r6) + stw r7, 8(r4) ! sa_mask + lwz r7, 8(r6) + stw r7, 12(r4) ! sa_flags +1: + sc 0 + b .set_errno + bclr 20, 0, 0 + +trampoline: + ! r3 = handler + ! r4 = info style + ! r5 = sig + ! r6 = info + ! r7 = context + or r31, r4, r4 ! ack preserves r30, r31 + or r30, r7, r7 + + ! Call handler(sig, info, context). + mtspr ctr, r3 + stwu r7, -4(sp) ! ack expects arguments on stack + stwu r6, -4(sp) + stwu r5, -4(sp) + bcctrl ALWAYS, 0, 0 + + ! Return from trampoline. + addi r0, r0, 184 ! sigreturn + or r3, r30, r30 ! context + or r4, r31, r31 ! info style + sc 0 + ori r0, r0, 0 ! nop + + ! Only if sigreturn() fails: + addi r0, r0, 1 ! exit + sc 0 diff --git a/plat/osxppc/libsys/write.s b/plat/osxppc/libsys/write.s new file mode 100644 index 000000000..48f59cd72 --- /dev/null +++ b/plat/osxppc/libsys/write.s @@ -0,0 +1,10 @@ +.sect .text +.define _write +_write: + addi r0, r0, 4 ! write + lwz r3, 0(sp) ! fd + lwz r4, 4(sp) ! buffer + lwz r5, 8(sp) ! buffer size + sc 0 + b .set_errno + bclr 20, 0, 0