Commit a preview of osx386 and osxppc as new platforms.
authorGeorge Koehler <xkernigh@netscape.net>
Sun, 2 Oct 2016 18:58:05 +0000 (14:58 -0400)
committerGeorge Koehler <xkernigh@netscape.net>
Sun, 2 Oct 2016 18:58:05 +0000 (14:58 -0400)
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

51 files changed:
build.lua
plat/osx/cvmach/build.lua [new file with mode: 0644]
plat/osx/cvmach/cvmach.c [new file with mode: 0644]
plat/osx/include/ack/config.h [new file with mode: 0644]
plat/osx/include/sys/mman.h [new file with mode: 0644]
plat/osx/include/sys/types.h [new file with mode: 0644]
plat/osx/include/unistd.h [new file with mode: 0644]
plat/osx/libsys/brk.c [new file with mode: 0644]
plat/osx/libsys/creat.c [new file with mode: 0644]
plat/osx/libsys/isatty.c [new file with mode: 0644]
plat/osx/libsys/signal.c [new file with mode: 0644]
plat/osx386/boot.s [new file with mode: 0644]
plat/osx386/build-pkg.lua [new file with mode: 0644]
plat/osx386/build-tools.lua [new file with mode: 0644]
plat/osx386/descr [new file with mode: 0644]
plat/osx386/include/build.lua [new file with mode: 0644]
plat/osx386/libsys/_exit.s [new file with mode: 0644]
plat/osx386/libsys/build.lua [new file with mode: 0644]
plat/osx386/libsys/close.s [new file with mode: 0644]
plat/osx386/libsys/getpid.s [new file with mode: 0644]
plat/osx386/libsys/gettimeofday.s [new file with mode: 0644]
plat/osx386/libsys/ioctl.s [new file with mode: 0644]
plat/osx386/libsys/kill.s [new file with mode: 0644]
plat/osx386/libsys/lseek.s [new file with mode: 0644]
plat/osx386/libsys/mmap.s [new file with mode: 0644]
plat/osx386/libsys/mprotect.s [new file with mode: 0644]
plat/osx386/libsys/open.s [new file with mode: 0644]
plat/osx386/libsys/read.s [new file with mode: 0644]
plat/osx386/libsys/set_errno.s [new file with mode: 0644]
plat/osx386/libsys/sigaction.s [new file with mode: 0644]
plat/osx386/libsys/write.s [new file with mode: 0644]
plat/osxppc/boot.s [new file with mode: 0644]
plat/osxppc/build-pkg.lua [new file with mode: 0644]
plat/osxppc/build-tools.lua [new file with mode: 0644]
plat/osxppc/descr [new file with mode: 0644]
plat/osxppc/include/build.lua [new file with mode: 0644]
plat/osxppc/libsys/_exit.s [new file with mode: 0644]
plat/osxppc/libsys/build.lua [new file with mode: 0644]
plat/osxppc/libsys/close.s [new file with mode: 0644]
plat/osxppc/libsys/getpid.s [new file with mode: 0644]
plat/osxppc/libsys/gettimeofday.s [new file with mode: 0644]
plat/osxppc/libsys/ioctl.s [new file with mode: 0644]
plat/osxppc/libsys/kill.s [new file with mode: 0644]
plat/osxppc/libsys/lseek.s [new file with mode: 0644]
plat/osxppc/libsys/mmap.s [new file with mode: 0644]
plat/osxppc/libsys/mprotect.s [new file with mode: 0644]
plat/osxppc/libsys/open.s [new file with mode: 0644]
plat/osxppc/libsys/read.s [new file with mode: 0644]
plat/osxppc/libsys/set_errno.s [new file with mode: 0644]
plat/osxppc/libsys/sigaction.s [new file with mode: 0644]
plat/osxppc/libsys/write.s [new file with mode: 0644]

index 05a4eaf..65ae6cb 100644 (file)
--- 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 (file)
index 0000000..ae4a18e
--- /dev/null
@@ -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 (file)
index 0000000..12a4869
--- /dev/null
@@ -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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <out.h>
+/* Can't find #include <object.h>*/
+
+/* 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<num> <inputfile> <outputfile>\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 (file)
index 0000000..af4a90e
--- /dev/null
@@ -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 (file)
index 0000000..5a844c4
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <sys/types.h>
+
+#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 (file)
index 0000000..a9fb632
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <stddef.h> /* 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 (file)
index 0000000..24eaf4e
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <sys/types.h>
+
+/*
+ * 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 <time.h> */
+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 (file)
index 0000000..a732cac
--- /dev/null
@@ -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 <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+
+/*
+ * 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 (file)
index 0000000..df2c822
--- /dev/null
@@ -0,0 +1,6 @@
+#include <fcntl.h>
+
+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 (file)
index 0000000..1da6509
--- /dev/null
@@ -0,0 +1,7 @@
+#include <sys/ioctl.h>
+
+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 (file)
index 0000000..0c1e126
--- /dev/null
@@ -0,0 +1,16 @@
+#include <signal.h>
+
+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 (file)
index 0000000..0db4bc7
--- /dev/null
@@ -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 (file)
index 0000000..8c129c8
--- /dev/null
@@ -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 (file)
index 0000000..097cb94
--- /dev/null
@@ -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 (file)
index 0000000..f1ba978
--- /dev/null
@@ -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 (file)
index 0000000..420518f
--- /dev/null
@@ -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 (file)
index 0000000..80d3013
--- /dev/null
@@ -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 (file)
index 0000000..a5356ee
--- /dev/null
@@ -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 (file)
index 0000000..295b90a
--- /dev/null
@@ -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 (file)
index 0000000..150791b
--- /dev/null
@@ -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 (file)
index 0000000..3a4c222
--- /dev/null
@@ -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 (file)
index 0000000..5b13e2c
--- /dev/null
@@ -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 (file)
index 0000000..8fdce95
--- /dev/null
@@ -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 (file)
index 0000000..22543b2
--- /dev/null
@@ -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 (file)
index 0000000..e39ea77
--- /dev/null
@@ -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 (file)
index 0000000..641173a
--- /dev/null
@@ -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 (file)
index 0000000..154c005
--- /dev/null
@@ -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 (file)
index 0000000..ccd3f81
--- /dev/null
@@ -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 (file)
index 0000000..ff08234
--- /dev/null
@@ -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 (file)
index 0000000..2909cbe
--- /dev/null
@@ -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 (file)
index 0000000..a32d4d7
--- /dev/null
@@ -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 (file)
index 0000000..a1ee671
--- /dev/null
@@ -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 (file)
index 0000000..d6f6d55
--- /dev/null
@@ -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 (file)
index 0000000..d19d25e
--- /dev/null
@@ -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 (file)
index 0000000..3ee0175
--- /dev/null
@@ -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 (file)
index 0000000..375c995
--- /dev/null
@@ -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 (file)
index 0000000..6ffe502
--- /dev/null
@@ -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 (file)
index 0000000..a595ed0
--- /dev/null
@@ -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 (file)
index 0000000..a799b5e
--- /dev/null
@@ -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 (file)
index 0000000..36525cf
--- /dev/null
@@ -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 (file)
index 0000000..c01bf5b
--- /dev/null
@@ -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 (file)
index 0000000..685ba84
--- /dev/null
@@ -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 (file)
index 0000000..4c7d556
--- /dev/null
@@ -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 (file)
index 0000000..129b08a
--- /dev/null
@@ -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 (file)
index 0000000..f2ec5e2
--- /dev/null
@@ -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 (file)
index 0000000..fbea702
--- /dev/null
@@ -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 (file)
index 0000000..1d066c7
--- /dev/null
@@ -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 (file)
index 0000000..849da59
--- /dev/null
@@ -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 (file)
index 0000000..e406865
--- /dev/null
@@ -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 (file)
index 0000000..f330c88
--- /dev/null
@@ -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 (file)
index 0000000..48f59cd
--- /dev/null
@@ -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