"linux386",
"linux68k",
"linuxppc",
+ "osx386",
+ "osxppc",
"pc86",
"rpi",
}
--- /dev/null
+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",
+ }
+}
--- /dev/null
+/*
+ * (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;
+}
--- /dev/null
+/* $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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#include <fcntl.h>
+
+int creat(const char *path, mode_t mode)
+{
+ open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
+}
--- /dev/null
+#include <sys/ioctl.h>
+
+int isatty(int fd)
+{
+ int line_disc;
+ return 0 <= ioctl(fd, TIOCGETD, &line_disc);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+! 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
--- /dev/null
+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",
+ }
+}
--- /dev/null
+return installable {
+ name = "tools",
+ map = {
+ ["$(PLATIND)/descr/osx386"] = "./descr",
+ "plat/linux386+tools",
+ "plat/osx/cvmach+pkg",
+ "util/opt+pkg",
+ }
+}
--- /dev/null
+# 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
--- /dev/null
+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
+}
--- /dev/null
+.sect .text
+.define __exit
+__exit:
+ mov eax, 1
+ int 0x80
--- /dev/null
+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"
+ }
+}
--- /dev/null
+.sect .text
+.define _close
+_close:
+ mov eax, 6
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _getpid
+_getpid:
+ mov eax, 20
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _gettimeofday
+_gettimeofday:
+ mov eax, 116
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _ioctl
+_ioctl:
+ mov eax, 54
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _kill
+_kill:
+ mov eax, 37
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.sect .text
+.define _mprotect
+_mprotect:
+ mov eax, 74
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _open
+_open:
+ mov eax, 5
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define _read
+_read:
+ mov eax, 3
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+.sect .text
+.define .set_errno
+.set_errno:
+ mov (_errno), eax
+ mov eax, -1
+ ret
--- /dev/null
+! 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
--- /dev/null
+.sect .text
+.define _write
+_write:
+ mov eax, 4
+ int 0x80
+ jb .set_errno
+ ret
--- /dev/null
+! 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
--- /dev/null
+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",
+ }
+}
--- /dev/null
+return installable {
+ name = "tools",
+ map = {
+ ["$(PLATIND)/descr/osxppc"] = "./descr",
+ "plat/linuxppc+tools",
+ "plat/osx/cvmach+pkg",
+ "util/opt+pkg",
+ }
+}
--- /dev/null
+# 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
--- /dev/null
+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
+}
--- /dev/null
+.sect .text
+.define __exit
+__exit:
+ addi r0, r0, 1 ! _exit
+ lwz r3, 0(sp) ! status
+ sc 0
--- /dev/null
+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"
+ }
+}
--- /dev/null
+.sect .text
+.define _close
+_close:
+ addi r0, r0, 6 ! close
+ lwz r3, 0(sp) ! fd
+ sc 0
+ b .set_errno
+ bclr 20, 0, 0
--- /dev/null
+.sect .text
+.define _getpid
+_getpid:
+ addi r0, r0, 20 ! getpid
+ sc 0
+ b .set_errno
+ bclr 20, 0, 0
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+.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
--- /dev/null
+#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
--- /dev/null
+.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