From 02fb48021773ae40a9781a45649ded39d02d1089 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sun, 2 Oct 2016 14:58:05 -0400 Subject: [PATCH 01/40] 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 From 7f94e971fd5f967e5efe58cd107625f4caad1e88 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 8 Nov 2016 15:22:09 -0500 Subject: [PATCH 02/40] Remove trailing whitespace in plat/osx* Also fix a comment. --- plat/osx/cvmach/cvmach.c | 10 +++++----- plat/osx/include/ack/config.h | 2 +- plat/osx386/boot.s | 14 +++++++------- plat/osxppc/boot.s | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/plat/osx/cvmach/cvmach.c b/plat/osx/cvmach/cvmach.c index 12a48696d..f223fa6f7 100644 --- a/plat/osx/cvmach/cvmach.c +++ b/plat/osx/cvmach/cvmach.c @@ -115,13 +115,13 @@ 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; @@ -136,7 +136,7 @@ void emit32(uint32_t value) buffer[1] = (value >> 8) & 0xFF; buffer[0] = (value >> 0) & 0xFF; } - + writef(buffer, 1, sizeof(buffer)); } @@ -177,7 +177,7 @@ void emit_lc_segment(char *name, uint32_t vm_ad, uint32_t vm_sz, { char namebuf[16]; int flags, maxprot; - + if (prot == VM_PROT_NONE) { /* special values for __PAGEZERO */ maxprot = VM_PROT_NONE; @@ -247,7 +247,7 @@ int main(int argc, char *argv[]) /* 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]) { diff --git a/plat/osx/include/ack/config.h b/plat/osx/include/ack/config.h index af4a90ed2..9f58a3941 100644 --- a/plat/osx/include/ack/config.h +++ b/plat/osx/include/ack/config.h @@ -8,7 +8,7 @@ /* 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/osx386/boot.s b/plat/osx386/boot.s index 0db4bc715..f3ad75fd2 100644 --- a/plat/osx386/boot.s +++ b/plat/osx386/boot.s @@ -26,28 +26,28 @@ begtext: ! 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: @@ -66,4 +66,4 @@ begbss: .define .trppc, .ignmask .comm .trppc, 4 ! ptr to user trap handler -.comm .ignmask, 4 ! user trap ignore mask +.comm .ignmask, 4 ! user trap ignore mask diff --git a/plat/osxppc/boot.s b/plat/osxppc/boot.s index a1ee67166..f99e70e2d 100644 --- a/plat/osxppc/boot.s +++ b/plat/osxppc/boot.s @@ -1,4 +1,4 @@ -! boot.s for osx386 +! boot.s for osxppc ! Declare segments (the order is important). @@ -30,13 +30,13 @@ begtext: 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 + 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 @@ -57,4 +57,4 @@ begbss: .define .trppc, .ignmask .comm .trppc, 4 ! ptr to user trap handler -.comm .ignmask, 4 ! user trap ignore mask +.comm .ignmask, 4 ! user trap ignore mask From ed7fb69f7953a071c62b44e0593b101691111a44 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 8 Nov 2016 15:35:02 -0500 Subject: [PATCH 03/40] Add the missing return in plat/osx/libsys/creat.c Before now, it might have worked by accident if the return value from open() stayed in the function return area. --- plat/osx/libsys/creat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/osx/libsys/creat.c b/plat/osx/libsys/creat.c index df2c82275..3a350e357 100644 --- a/plat/osx/libsys/creat.c +++ b/plat/osx/libsys/creat.c @@ -2,5 +2,5 @@ int creat(const char *path, mode_t mode) { - open(path, O_CREAT | O_TRUNC | O_WRONLY, mode); + return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode); } From 0d0495e818d840d89bb025415fc18e0ed9d8d4a6 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 8 Nov 2016 17:13:51 -0500 Subject: [PATCH 04/40] Install only 1 copy, not 2 copies, of osx headers. Before this commit, the headers in plat/osx/include got installed twice into PLATIND/osx386/include and PLATIND/osxppc/include. This commit installs them once into PLATIND/osx/include and changes both descr files to find them. Several rules in lang/ depend on plat/osx386/include+headers or plat/osxppc/include+headers. They each become a simplerule that depends on plat/osx/include+headers. --- plat/osx/include/build.lua | 24 ++++++++++++++++++++++++ plat/osx386/build-pkg.lua | 2 +- plat/osx386/descr | 2 +- plat/osx386/include/build.lua | 27 +++++---------------------- plat/osxppc/build-pkg.lua | 2 +- plat/osxppc/descr | 2 +- plat/osxppc/include/build.lua | 27 +++++---------------------- 7 files changed, 38 insertions(+), 48 deletions(-) create mode 100644 plat/osx/include/build.lua diff --git a/plat/osx/include/build.lua b/plat/osx/include/build.lua new file mode 100644 index 000000000..7eb73f3aa --- /dev/null +++ b/plat/osx/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)/osx/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/build-pkg.lua b/plat/osx386/build-pkg.lua index 8c129c8e7..6dfe1561c 100644 --- a/plat/osx386/build-pkg.lua +++ b/plat/osx386/build-pkg.lua @@ -17,7 +17,7 @@ installable { map = { "+tools", "+libs", - "./include+pkg", + "plat/osx/include+pkg", ["$(PLATIND)/osx386/boot.o"] = "+boot", ["$(PLATIND)/osx386/libsys.a"] = "./libsys+lib", } diff --git a/plat/osx386/descr b/plat/osx386/descr index f1ba978ef..e404e7a34 100644 --- a/plat/osx386/descr +++ b/plat/osx386/descr @@ -29,7 +29,7 @@ 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 +var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi name be from .m.g diff --git a/plat/osx386/include/build.lua b/plat/osx386/include/build.lua index 420518f66..164e2b44a 100644 --- a/plat/osx386/include/build.lua +++ b/plat/osx386/include/build.lua @@ -1,24 +1,7 @@ -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 { +simplerule { name = "headers", - hdrs = headermap -} - -installable { - name = "pkg", - map = packagemap + deps = { "plat/osx/include+headers" }, + ins = {}, + outs = {}, + commands = {}, } diff --git a/plat/osxppc/build-pkg.lua b/plat/osxppc/build-pkg.lua index d6f6d5558..c94ad6ef0 100644 --- a/plat/osxppc/build-pkg.lua +++ b/plat/osxppc/build-pkg.lua @@ -17,7 +17,7 @@ installable { map = { "+tools", "+libs", - "./include+pkg", + "plat/osx/include+pkg", ["$(PLATIND)/osxppc/boot.o"] = "+boot", ["$(PLATIND)/osxppc/libsys.a"] = "./libsys+lib", } diff --git a/plat/osxppc/descr b/plat/osxppc/descr index 3ee01752d..7e8770428 100644 --- a/plat/osxppc/descr +++ b/plat/osxppc/descr @@ -30,7 +30,7 @@ var MACHOPT_F=-m10 # 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 +var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi name be from .m.g diff --git a/plat/osxppc/include/build.lua b/plat/osxppc/include/build.lua index 375c99535..164e2b44a 100644 --- a/plat/osxppc/include/build.lua +++ b/plat/osxppc/include/build.lua @@ -1,24 +1,7 @@ -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 { +simplerule { name = "headers", - hdrs = headermap -} - -installable { - name = "pkg", - map = packagemap + deps = { "plat/osx/include+headers" }, + ins = {}, + outs = {}, + commands = {}, } From 6e31d46d6f353931d192d1a4dd3277f332cbc980 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 19 Nov 2016 19:23:42 -0500 Subject: [PATCH 05/40] Fix my typo to put symbol "begrom" in correct section. --- plat/osx386/boot.s | 2 +- plat/osxppc/boot.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plat/osx386/boot.s b/plat/osx386/boot.s index f3ad75fd2..932a716e9 100644 --- a/plat/osx386/boot.s +++ b/plat/osx386/boot.s @@ -48,7 +48,7 @@ EXIT: push 1 jmp __exit -.sect rom +.sect .rom begrom: .sect .data diff --git a/plat/osxppc/boot.s b/plat/osxppc/boot.s index f99e70e2d..e96198eb4 100644 --- a/plat/osxppc/boot.s +++ b/plat/osxppc/boot.s @@ -39,7 +39,7 @@ begtext: b __m_a_i_n -.sect rom +.sect .rom begrom: .sect .data From 88c2ea63aa5ea3d4ca5b8e17067fceb377270f03 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sun, 20 Nov 2016 11:38:16 -0500 Subject: [PATCH 06/40] Use uint32_t in util/led/main.c This uses uint32_t for the base, file offset, and alignment of each section, to be consistent with the usage of uint32_t in h/out.h Also declare setbit() as static. --- util/led/main.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/util/led/main.c b/util/led/main.c index 426438ec6..7b0fced7a 100644 --- a/util/led/main.c +++ b/util/led/main.c @@ -11,6 +11,7 @@ static char rcsid[] = "$Id$"; */ #include +#include #include #include "const.h" #include "debug.h" @@ -29,15 +30,16 @@ int Verbose = 0; static initializations(); static first_pass(); -static long number(); -static setlign(); -static setbase(); +static uint32_t number(const char *); +static void setlign(int, uint32_t); +static void setbase(int, uint32_t); static struct outname *makename(); static pass1(); static evaluate(); static norm_commons(); static complete_sections(); static change_names(); +static bool setbit(); static bool tstbit(); static second_pass(); static pass2(); @@ -249,12 +251,11 @@ first_pass(argv) * else if it starts with 0, it's octal, * else it's decimal. */ -static long -number(s) - register char *s; +static uint32_t +number(const char *s) { register int digit; - register long value = 0; + register uint32_t value = 0; register int radix = 10; if (*s == '0') { @@ -289,22 +290,17 @@ number(s) * not. Only one base may be given. The same applies for alignments. */ static char basemap[MAXSECT / WIDTH]; -static long sect_base[MAXSECT]; +static uint32_t sect_base[MAXSECT]; static char lignmap[MAXSECT / WIDTH]; -static long sect_lign[MAXSECT]; +static uint32_t sect_lign[MAXSECT]; -/* /* * Set the alignment of section `sectno' to `lign', if this doesn't * conflict with earlier alignment. */ -static -setlign(sectno, lign) - register int sectno; - register long lign; +static void +setlign(int sectno, uint32_t lign) { - extern bool setbit(); - if (setbit(sectno, lignmap) && sect_lign[sectno] != lign) fatal("section has different alignments"); if (lign == (long)0) @@ -316,13 +312,9 @@ setlign(sectno, lign) * Set the base of section `sectno' to `base', if no other base has been * given yet. */ -static -setbase(sectno, base) - register int sectno; - register long base; +static void +setbase(int sectno, uint32_t base) { - extern bool setbit(); - if (setbit(sectno, basemap) && sect_base[sectno] != base) fatal("section has different bases"); sect_base[sectno] = base; @@ -457,8 +449,8 @@ struct orig relorig[MAXSECT]; static complete_sections() { - register long base = 0; - register long foff; + register uint32_t base = 0; + register uint32_t foff; register struct outsect *sc; register int sectindex; From 19310d2521ddf88e896ecf9c4ee5a1fe7fe9aab8 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 22 Nov 2016 11:13:14 -0500 Subject: [PATCH 07/40] Make possible to #include . This header declares functions in libobject. Our programs never included object.h, but called functions in libobject without declaring them. So, our build system never put object.h in the include path; any #include would fail to find the header. With this commit, a program may #include if it has modules/src/object+lib in its deps. Declare structs in object.h so we can use them in prototypes without gcc warning, "'struct whatever' declared inside parameter list". Remove inclusion of ansi.h from object.h. Programs would need to depend on modules+headers to get ansi.h in the include path. --- modules/src/object/build.lua | 1 + modules/src/object/object.h | 72 +++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/modules/src/object/build.lua b/modules/src/object/build.lua index c30c7e54a..6a8bea04e 100644 --- a/modules/src/object/build.lua +++ b/modules/src/object/build.lua @@ -1,6 +1,7 @@ clibrary { name = "lib", srcs = { "./*.c" }, + hdrs = { "./object.h" }, deps = { "modules+headers", "h+local", diff --git a/modules/src/object/object.h b/modules/src/object/object.h index 68a5ea99f..d6c218a2a 100644 --- a/modules/src/object/object.h +++ b/modules/src/object/object.h @@ -4,42 +4,46 @@ * See the copyright notice in the ACK home directory, in the file "Copyright". */ -#include - #ifndef __OBJECT_INCLUDED__ #define __OBJECT_INCLUDED__ -_PROTOTYPE(int wr_open, (char *f)); -_PROTOTYPE(void wr_close, (void)); -_PROTOTYPE(void wr_ohead, (struct outhead *h)); -_PROTOTYPE(void wr_sect, (struct outsect *s, unsigned int c)); -_PROTOTYPE(void wr_outsect, (int sectno)); -_PROTOTYPE(void wr_emit, (char *b, long c)); -_PROTOTYPE(void wr_putc, (int c)); -_PROTOTYPE(void wr_relo, (struct outrelo *r, unsigned int c)); -_PROTOTYPE(void wr_name, (struct outname *n, unsigned int c)); -_PROTOTYPE(void wr_string, (char *s, long c)); -_PROTOTYPE(void wr_arhdr, (int fd, struct ar_hdr *a)); -_PROTOTYPE(void wr_ranlib, (int fd, struct ranlib *r, long cnt)); -_PROTOTYPE(void wr_int2, (int fd, int i)); -_PROTOTYPE(void wr_long, (int fd, long l)); -_PROTOTYPE(void wr_bytes, (int fd, char *buf, long l)); -_PROTOTYPE(int rd_open, (char *f)); -_PROTOTYPE(int rd_fdopen, (int f)); -_PROTOTYPE(void rd_close, (void)); -_PROTOTYPE(void rd_ohead, (struct outhead *h)); -_PROTOTYPE(void rd_sect, (struct outsect *s, unsigned int c)); -_PROTOTYPE(void rd_outsect, (int sectno)); -_PROTOTYPE(void rd_emit, (char *b, long c)); -_PROTOTYPE(void rd_relo, (struct outrelo *r, unsigned int c)); -_PROTOTYPE(void rd_rew_relo, (struct outhead *head)); -_PROTOTYPE(void rd_name, (struct outname *n, unsigned int c)); -_PROTOTYPE(void rd_string, (char *s, long c)); -_PROTOTYPE(int rd_arhdr, (int fd, struct ar_hdr *a)); -_PROTOTYPE(void rd_ranlib, (int fd, struct ranlib *r, long cnt)); -_PROTOTYPE(int rd_int2, (int fd)); -_PROTOTYPE(long rd_long, (int fd)); -_PROTOTYPE(void rd_bytes, (int fd, char *buf, long l)); -_PROTOTYPE(int rd_fd, (void)); +struct ar_hdr; +struct outhead; +struct outrelo; +struct outsect; +struct ranlib; + +int wr_open(char *f); +void wr_close(void); +void wr_ohead(struct outhead *h); +void wr_sect(struct outsect *s, unsigned int c); +void wr_outsect(int sectno); +void wr_emit(char *b, long c); +void wr_putc(int c); +void wr_relo(struct outrelo *r, unsigned int c); +void wr_name(struct outname *n, unsigned int c); +void wr_string(char *s, long c); +void wr_arhdr(int fd, struct ar_hdr *a); +void wr_ranlib(int fd, struct ranlib *r, long cnt); +void wr_int2(int fd, int i); +void wr_long(int fd, long l); +void wr_bytes(int fd, char *buf, long l); +int rd_open(char *f); +int rd_fdopen(int f); +void rd_close(void); +void rd_ohead(struct outhead *h); +void rd_sect(struct outsect *s, unsigned int c); +void rd_outsect(int sectno); +void rd_emit(char *b, long c); +void rd_relo(struct outrelo *r, unsigned int c); +void rd_rew_relo(struct outhead *head); +void rd_name(struct outname *n, unsigned int c); +void rd_string(char *s, long c); +int rd_arhdr(int fd, struct ar_hdr *a); +void rd_ranlib(int fd, struct ranlib *r, long cnt); +int rd_int2(int fd); +long rd_long(int fd); +void rd_bytes(int fd, char *buf, long l); +int rd_fd(void); #endif /* __OBJECT_INCLUDED__ */ From 98f2273d97b85f55aa950b1d439714c054cf2d32 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 22 Nov 2016 17:16:30 -0500 Subject: [PATCH 08/40] Teach cvmach to emit the symbol table. This preserves the name and value of every symbol. The type and other info of a symbol might be lost. In gdb, one can now "disas main" or "disas '.ret'" to disassemble functions by name. Most symbols are in sections, so I also teach cvmach to emit the Mach section headers. The entry point in plat/osx*/descr moves down to make room for the section headers and LC_SYMTAB. I fix some bugs in calculations of cvmach. They were wrong if ROM had a greater alignment than TEXT, or if DATA did not start on a page boundary. I introduce machseg[] to simplify the mess of variables in main(). I declare most functions as static. Also, cvmach becomes the first program to #include . --- plat/osx/cvmach/build.lua | 2 - plat/osx/cvmach/cvmach.c | 418 ++++++++++++++++++++++++++++++-------- plat/osx386/descr | 2 +- plat/osxppc/descr | 2 +- 4 files changed, 332 insertions(+), 92 deletions(-) diff --git a/plat/osx/cvmach/build.lua b/plat/osx/cvmach/build.lua index ae4a18ecb..8076546c1 100644 --- a/plat/osx/cvmach/build.lua +++ b/plat/osx/cvmach/build.lua @@ -3,8 +3,6 @@ cprogram { srcs = { "./cvmach.c" }, deps = { "h+emheaders", - -- Next line only because object.h includes ansi.h - "modules+headers", "modules/src/object+lib", } } diff --git a/plat/osx/cvmach/cvmach.c b/plat/osx/cvmach/cvmach.c index f223fa6f7..0b5b6bf80 100644 --- a/plat/osx/cvmach/cvmach.c +++ b/plat/osx/cvmach/cvmach.c @@ -4,12 +4,12 @@ */ /* - * cvmach.c - convert ack.out to mach-o + * 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). + * libobject is pinched from the Xenix i386 cv (mach/i386/cv/cv.c). */ #include @@ -19,11 +19,12 @@ #include #include -/* Can't find #include */ +#include /* Header and section table of ack.out */ struct outhead outhead; struct outsect outsect[S_MAX]; +uint32_t ack_off_char; /* Offset of string table in ack.out */ int bigendian; /* Emit big-endian Mach-o? */ int cpu_type; @@ -48,6 +49,7 @@ enum { #define MH_MAGIC 0xfeedface #define MH_EXECUTE 2 #define LC_SEGMENT 1 +#define LC_SYMTAB 2 #define LC_UNIXTHREAD 5 #define CPU_TYPE_X86 7 @@ -68,7 +70,10 @@ enum { /* sizes of Mach structs */ #define SZ_MACH_HEADER 28 #define SZ_SEGMENT_COMMAND 56 +#define SZ_SECTION_HEADER 68 +#define SZ_SYMTAB_COMMAND 24 #define SZ_THREAD_COMMAND_BF_STATE 16 +#define SZ_NLIST 12 /* the page size for x86 and PowerPC */ #define CV_PGSZ 4096 @@ -76,9 +81,33 @@ enum { #define pg_mod(u) ((u) & (CV_PGSZ - 1)) /* u rounded down to whole pages */ #define pg_trunc(u) ((u) & ~(CV_PGSZ - 1)) +/* u rounded up to whole pages */ +#define pg_round(u) pg_trunc((u) + (CV_PGSZ - 1)) + +const char zero_pg[CV_PGSZ] = { 0 }; + +/* + * machseg[0]: __PAGEZERO with address 0, size CV_PGSZ + * machseg[1]: __TEXT for ack TEXT, ROM + * machseg[2]: __DATA for ack DATA, BSS + */ +struct { + const char *ms_name; + uint32_t ms_vmaddr; + uint32_t ms_vmsize; + uint32_t ms_fileoff; + uint32_t ms_filesize; + uint32_t ms_prot; + uint32_t ms_nsects; +} machseg[3] = { + "__PAGEZERO", 0, CV_PGSZ, 0, 0, VM_PROT_NONE, 0, + "__TEXT", 0, 0, 0, 0, VM_PROT_READ | VM_PROT_EXECUTE, 2, + "__DATA", 0, 0, 0, 0, VM_PROT_READ | VM_PROT_WRITE, 2, +}; -void usage(void) +static void +usage(void) { fprintf(stderr, "Usage: %s -m \n", program); @@ -86,7 +115,8 @@ void usage(void) } /* Produce an error message and exit. */ -void fatal(const char* s, ...) +static void +fatal(const char* s, ...) { va_list ap; @@ -103,22 +133,54 @@ void fatal(const char* s, ...) exit(1); } -void rd_fatal(void) +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) +/* Returns n such that 2**n == a. */ +static uint32_t +log2u(uint32_t a) { - a += b - 1; - return a & ~(b-1); + uint32_t n = 0; + while (a) { + a >>= 1; + n++; + } + return n - 1; } +/* Writes a byte. */ +static void +emit8(uint8_t value) +{ + writef(&value, 1, 1); +} + +/* Writes out a 16-bit value in the appropriate endianness. */ +static void +emit16(uint16_t value) +{ + unsigned char buffer[2]; + + if (bigendian) + { + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = (value >> 0) & 0xFF; + } + else + { + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} /* Writes out a 32-bit value in the appropriate endianness. */ -void emit32(uint32_t value) +static void +emit32(uint32_t value) { unsigned char buffer[4]; @@ -142,7 +204,8 @@ void emit32(uint32_t value) /* Copies the contents of a section from the input stream * to the output stream. */ -void emit_section(int section_nr) +static void +emit_section(int section_nr) { struct outsect *section = &outsect[section_nr]; size_t blocksize; @@ -160,50 +223,114 @@ void emit_section(int section_nr) /* Zero fill any remaining space. */ n = section->os_size - section->os_flen; - if (n > 0) + while (n > 0) { - memset(buffer, 0, BUFSIZ); - while (n > 0) - { - blocksize = (n > BUFSIZ) ? BUFSIZ : n; - writef(buffer, 1, blocksize); - n -= blocksize; - } + blocksize = (n > sizeof(zero_pg)) ? sizeof(zero_pg) : n; + writef(zero_pg, 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) +static void +emit_lc_segment(int i) { - char namebuf[16]; + uint32_t sz; int flags, maxprot; + char namebuf[16]; - if (prot == VM_PROT_NONE) { + if (i == 0) { /* special values for __PAGEZERO */ maxprot = VM_PROT_NONE; - flags = 4; /* NORELOC */ + flags = 4; /* SG_NORELOC */ } else { maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; flags = 0; } + /* + * The size of this command includes the size of its section + * headers, see emit_section_header(). + */ + sz = SZ_SEGMENT_COMMAND + machseg[i].ms_nsects * SZ_SECTION_HEADER; + /* Use strncpy() to pad namebuf with '\0' bytes. */ - strncpy(namebuf, name, sizeof(namebuf)); + strncpy(namebuf, machseg[i].ms_name, sizeof(namebuf)); emit32(LC_SEGMENT); /* command */ - emit32(SZ_SEGMENT_COMMAND); /* size of command */ + emit32(sz); /* 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(machseg[i].ms_vmaddr); /* vm address */ + emit32(machseg[i].ms_vmsize); /* vm size */ + emit32(machseg[i].ms_fileoff); /* file offset */ + emit32(machseg[i].ms_filesize); /* file size */ emit32(maxprot); /* max protection */ - emit32(prot); /* initial protection */ - emit32(0); /* number of Mach sections */ + emit32(machseg[i].ms_prot); /* initial protection */ + emit32(machseg[i].ms_nsects); /* number of Mach sections */ emit32(flags); /* flags */ } -void emit_lc_unixthread(void) +static void +emit_section_header(int ms, const char *name, int os) +{ + uint32_t fileoff, flags; + char namebuf[16]; + + switch (os) { + case TEXT: + /* S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS */ + flags = 0x80000400; + break; + case BSS: + flags = 0x1; /* S_ZEROFILL */ + break; + default: + flags = 0x0; /* S_REGULAR */ + break; + } + + if (os == BSS) + fileoff = 0; + else + fileoff = machseg[ms].ms_fileoff + + (outsect[os].os_base - machseg[ms].ms_vmaddr); + + /* name of Mach section */ + strncpy(namebuf, name, sizeof(namebuf)); + writef(namebuf, 1, sizeof(namebuf)); + /* name of Mach segment */ + strncpy(namebuf, machseg[ms].ms_name, sizeof(namebuf)); + writef(namebuf, 1, sizeof(namebuf)); + emit32(outsect[os].os_base); /* vm address */ + emit32(outsect[os].os_size); /* vm size */ + emit32(fileoff); /* file offset */ + emit32(log2u(outsect[os].os_lign)); /* alignment */ + emit32(0); /* offset of relocations */ + emit32(0); /* number of relocations */ + emit32(flags); /* flags */ + emit32(0); /* reserved */ + emit32(0); /* reserved */ +} + +static void +emit_lc_symtab(void) +{ + uint32_t off1, off2; + + /* Symbol table will be at next page after machseg[2]. */ + off1 = pg_round(machseg[2].ms_fileoff + machseg[2].ms_filesize); + /* String table will be after symbol table. */ + off2 = off1 + 12 * outhead.oh_nname; + + emit32(LC_SYMTAB); /* command */ + emit32(SZ_SYMTAB_COMMAND); /* size of command */ + emit32(off1); /* offset of symbol table */ + emit32(outhead.oh_nname); /* number of symbols */ + emit32(off2); /* offset of string table */ + emit32(1 + outhead.oh_nchar); /* size of string table */ +} + +static void +emit_lc_unixthread(void) { int i, ireg, ts, ts_count; @@ -238,10 +365,111 @@ void emit_lc_unixthread(void) } } - -int main(int argc, char *argv[]) +static void +emit_symbol(struct outname *np) { - uint32_t len2, len3, mach_base, pad, sz_bf_entry, sz_load_cmds; + uint32_t soff; + uint8_t type; + uint8_t sect; + uint16_t desc; + + if (np->on_type & S_STB) { + /* stab for debugger */ + type = np->on_type >> 8; + desc = np->on_desc; + } else { + desc = 0; + + switch (np->on_type & S_TYP) { + case S_UND: + type = 0x0; /* N_UNDF */ + break; + case S_ABS: + type = 0x2; /* N_ABS */ + break; + default: + type = 0xe; /* N_SECT */ + break; + } + + if (np->on_type & S_EXT) + type |= 0x1; /* N_EXT */ + } + + switch (np->on_type & S_TYP) { + case S_MIN + TEXT: + sect = 1; + break; + case S_MIN + ROM: + sect = 2; + break; + case S_MIN + DATA: + sect = 3; + break; + case S_MIN + BSS: + case S_MIN + NUM_SEGMENTS: + sect = 4; + break; + default: + sect = 0; /* NO_SECT */ + break; + } + + /* + * To find the symbol's name, ack.out uses an offset from the + * beginning of the file, but Mach-o uses an offset into the + * string table. Both formats use offset 0 for a symbol with + * no name. We will prepend a '\0' at offset 0, so every + * named symbol needs + 1. + */ + if (np->on_foff) + soff = np->on_foff - ack_off_char + 1; + else + soff = 0; + + emit32(soff); + emit8(type); + emit8(sect); + emit16(desc); + emit32(np->on_valu); +} + +static void +emit_symtab(void) +{ + struct outname *names, *np; + int i; + char *chars; + + /* Using calloc(a, b) to check if a * b would overflow. */ + names = calloc(outhead.oh_nname, sizeof(struct outname)); + if (!names) + fatal("out of memory"); + chars = malloc(outhead.oh_nchar); + if (!names || !chars) + fatal("out of memory"); + rd_name(names, outhead.oh_nname); + rd_string(chars, outhead.oh_nchar); + + ack_off_char = OFF_CHAR(outhead); + + /* Emit each symbol entry. */ + for (i = 0, np = names; i < outhead.oh_nname; i++, np++) + emit_symbol(np); + + /* + * Emit the string table. The first character of a Mach-o + * string table must be '\0', so we prepend a '\0'. + */ + emit8(0); + writef(chars, 1, outhead.oh_nchar); +} + + +int +main(int argc, char *argv[]) +{ + uint32_t end, pad[3], sz, sz_load_cmds; int cpu_subtype, mflag = 0; /* General housecleaning and setup. */ @@ -323,54 +551,62 @@ int main(int argc, char *argv[]) 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 + * machseg[1] will start at a page boundary and include the + * Mach header and load commands before ack TEXT and ROM. + * + * Find our entry point (immediately after the load commands) + * and check that TEXT begins there. */ - - /* 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; + machseg[1].ms_vmaddr = pg_trunc(outsect[TEXT].os_base); + sz_load_cmds = 3 * SZ_SEGMENT_COMMAND + 4 * SZ_SECTION_HEADER + + SZ_SYMTAB_COMMAND + sz_thread_command; + entry = machseg[1].ms_vmaddr + SZ_MACH_HEADER + sz_load_cmds; if (entry != outsect[TEXT].os_base) { - fatal("text segment must have base 0x%lx, not 0x%lx\n", - entry, outsect[TEXT].os_base); + fatal("text segment must have base 0x%lx, not 0x%lx" + "\n\t(suggest em_led -b0:0x%lx)", + (unsigned long)entry, + (unsigned long)outsect[TEXT].os_base, + (unsigned long)entry); } - /* 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) + /* Pad for alignment between TEXT and ROM. */ + sz = outsect[ROM].os_base - outsect[TEXT].os_base; + pad[0] = sz - outsect[TEXT].os_size; + if (sz < outsect[TEXT].os_size || pad[0] >= outsect[ROM].os_lign) 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) + * Pad between ROM and DATA such that we can map machseg[2] at + * a page boundary with DATA at its correct base address. * - * This will allow us to map the 3rd Mach segment at the - * beginning of a page, such that DATA is at its base. + * For example, if ROM ends at 0x2bed and DATA begins at + * 0x3000, then we pad to the page boundary. If ROM ends at + * 0x2bed and DATA begins at 0x3bf0, then pad = 3 and we map + * the page twice, at both 0x2000 and 0x3000. */ - 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); + end = outsect[ROM].os_base + outsect[ROM].os_size; + pad[1] = pg_mod(outsect[DATA].os_base - end); + + sz = end - machseg[1].ms_vmaddr; + machseg[1].ms_vmsize = machseg[1].ms_filesize = sz; + machseg[2].ms_vmaddr = pg_trunc(outsect[DATA].os_base); + machseg[2].ms_fileoff = pg_trunc(sz + pad[1]); + if (machseg[2].ms_vmaddr < end && + machseg[2].ms_vmaddr >= machseg[1].ms_vmaddr) + fatal("the data and rom segments are too close." + "\n\t(suggest em_led -a2:%d)", (int)CV_PGSZ); - /* 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) + sz = outsect[BSS].os_base - outsect[DATA].os_base; + if (sz < outsect[DATA].os_size || + sz - outsect[DATA].os_size >= outsect[BSS].os_lign) fatal("the bss segment must follow the data segment."); - len3 = outsect[BSS].os_base - pg_trunc(outsect[DATA].os_base) + - outsect[BSS].os_size; + end = outsect[DATA].os_base + outsect[DATA].os_size; + machseg[2].ms_filesize = end - machseg[2].ms_vmaddr; + end = outsect[BSS].os_base + outsect[BSS].os_size; + machseg[2].ms_vmsize = end - machseg[2].ms_vmaddr; if (outhead.oh_nsect == NUM_SEGMENTS + 1) { if (outsect[NUM_SEGMENTS].os_base != @@ -380,37 +616,43 @@ int main(int argc, char *argv[]) fatal("end segment must be empty"); } + /* + * Pad to page boundary between BSS and symbol table. + * + * Also, some versions of Mac OS X refuse to load any + * executable smaller than 4096 bytes (1 page). + */ + pad[2] = pg_mod(-(uint32_t)machseg[2].ms_filesize); + /* 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(5); /* 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_segment(0); + emit_lc_segment(1); + emit_section_header(1, "__text", TEXT); + emit_section_header(1, "__rom", ROM); + emit_lc_segment(2); + emit_section_header(2, "__data", DATA); + emit_section_header(2, "__bss", BSS); + emit_lc_symtab(); emit_lc_unixthread(); /* Emit non-empty sections. */ emit_section(TEXT); + writef(zero_pg, 1, pad[0]); emit_section(ROM); + writef(zero_pg, 1, pad[1]); emit_section(DATA); + writef(zero_pg, 1, pad[2]); + emit_symtab(); + if (ferror(output)) fatal("write error"); diff --git a/plat/osx386/descr b/plat/osx386/descr index e404e7a34..9e4cf2577 100644 --- a/plat/osx386/descr +++ b/plat/osx386/descr @@ -18,7 +18,7 @@ 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 ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x123c var C_LIB={PLATFORMDIR}/libc-ansi.a # bitfields reversed for compatibility with (g)cc. var CC_ALIGN=-Vr diff --git a/plat/osxppc/descr b/plat/osxppc/descr index 7e8770428..130d2bd25 100644 --- a/plat/osxppc/descr +++ b/plat/osxppc/descr @@ -18,7 +18,7 @@ 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 ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x129c var C_LIB={PLATFORMDIR}/libc-ansi.a # bitfields reversed for compatibility with (g)cc. # XXX this is from linux386, might be wrong for osxppc From b6b707d9df40d8bdebce51281d610f264f03e0d9 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 23 Nov 2016 13:25:55 -0500 Subject: [PATCH 09/40] Make working gettimeofday() for Mac OS X. The system call puts the time in a pair of registers, not in the timeval structure. Add code to move the time to the structure, so programs see the correct time, not garbage. This fixes our example programs that use the time as a random seed. --- plat/osx386/libsys/gettimeofday.s | 11 +++++++++++ plat/osxppc/libsys/gettimeofday.s | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/plat/osx386/libsys/gettimeofday.s b/plat/osx386/libsys/gettimeofday.s index 3a4c2229f..43aff5fa9 100644 --- a/plat/osx386/libsys/gettimeofday.s +++ b/plat/osx386/libsys/gettimeofday.s @@ -1,7 +1,18 @@ +! The system call checks the timeval pointer but doesn't store the +! time there. If the pointer wasn't NULL, then the system call +! returns the time in a pair of registers. + .sect .text .define _gettimeofday _gettimeofday: mov eax, 116 int 0x80 jb .set_errno + mov ebx, 4(esp) ! timeval pointer + test ebx, ebx + je 1f + mov 0(ebx), eax ! seconds + mov 4(ebx), edx ! microseconds +1: + mov eax, 0 ! return 0 ret diff --git a/plat/osxppc/libsys/gettimeofday.s b/plat/osxppc/libsys/gettimeofday.s index c01bf5bae..178d17fdd 100644 --- a/plat/osxppc/libsys/gettimeofday.s +++ b/plat/osxppc/libsys/gettimeofday.s @@ -1,9 +1,19 @@ +! The system call checks the timeval pointer but doesn't store the +! time there. If the pointer wasn't NULL, then the system call +! returns the time in a pair of registers. + .sect .text .define _gettimeofday _gettimeofday: addi r0, r0, 116 ! gettimeofday lwz r3, 0(sp) ! timeval pointer lwz r4, 4(sp) ! timezone pointer + or. r5, r3, r3 sc 0 b .set_errno + bc 12, 2, 1f ! beq 1f + stw r3, 0(r5) ! seconds + stw r4, 4(r5) ! microseconds +1: + addi r3, r0, 0 ! return 0 bclr 20, 0, 0 From 466bc555fe1f9ce2686091367faabba97033c766 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Mon, 28 Nov 2016 14:32:49 -0500 Subject: [PATCH 10/40] Add getdirentries() and stat() for Mac OS X. Also add fstat() and lstat(). I don't #define the constants for st_mode or d_type, but I provide enough to get the block size of a file and to list the names in a directory. Some fields of struct stat get truncated, see XXX in plat/osx/include/sys/stat.h. In struct dirent, the inode field might be d_ino or d_fileno. I picked d_ino because Apple's sys/dirent.h uses d_ino (but Apple's manual pages use d_fileno). --- plat/osx/include/build.lua | 2 ++ plat/osx/include/sys/dirent.h | 17 +++++++++++ plat/osx/include/sys/stat.h | 49 ++++++++++++++++++++++++++++++ plat/osx/include/sys/types.h | 12 ++++++-- plat/osx/include/unistd.h | 7 +++-- plat/osx386/libsys/build.lua | 4 +++ plat/osx386/libsys/fstat.s | 7 +++++ plat/osx386/libsys/getdirentries.s | 7 +++++ plat/osx386/libsys/lstat.s | 7 +++++ plat/osx386/libsys/stat.s | 7 +++++ plat/osxppc/libsys/build.lua | 4 +++ plat/osxppc/libsys/fstat.s | 9 ++++++ plat/osxppc/libsys/getdirentries.s | 11 +++++++ plat/osxppc/libsys/lstat.s | 9 ++++++ plat/osxppc/libsys/stat.s | 9 ++++++ 15 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 plat/osx/include/sys/dirent.h create mode 100644 plat/osx/include/sys/stat.h create mode 100644 plat/osx386/libsys/fstat.s create mode 100644 plat/osx386/libsys/getdirentries.s create mode 100644 plat/osx386/libsys/lstat.s create mode 100644 plat/osx386/libsys/stat.s create mode 100644 plat/osxppc/libsys/fstat.s create mode 100644 plat/osxppc/libsys/getdirentries.s create mode 100644 plat/osxppc/libsys/lstat.s create mode 100644 plat/osxppc/libsys/stat.s diff --git a/plat/osx/include/build.lua b/plat/osx/include/build.lua index 7eb73f3aa..ff7c87a4d 100644 --- a/plat/osx/include/build.lua +++ b/plat/osx/include/build.lua @@ -9,7 +9,9 @@ local function addheader(h) end addheader("ack/config.h") +addheader("sys/dirent.h") addheader("sys/mman.h") +addheader("sys/stat.h") addheader("sys/types.h") addheader("unistd.h") diff --git a/plat/osx/include/sys/dirent.h b/plat/osx/include/sys/dirent.h new file mode 100644 index 000000000..073c84588 --- /dev/null +++ b/plat/osx/include/sys/dirent.h @@ -0,0 +1,17 @@ +#ifndef _SYS_DIRENT_H +#define _SYS_DIRENT_H + +#include + +struct dirent { + ino_t d_ino; + unsigned short d_reclen; + unsigned char d_type; + unsigned char d_namlen; +#define MAXNAMLEN 255 + char d_name[MAXNAMLEN + 1]; +}; + +int getdirentries(int, char *, int, long *); + +#endif diff --git a/plat/osx/include/sys/stat.h b/plat/osx/include/sys/stat.h new file mode 100644 index 000000000..6cb24902f --- /dev/null +++ b/plat/osx/include/sys/stat.h @@ -0,0 +1,49 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include +#include /* for timespec */ + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + /* + * XXX - We don't have 64-bit integers, so we only expose the + * lower 32 bits of 64-bit fields. We insert dummy fields for + * the higher 32 bits. + */ +#if defined(__i386) + off_t st_size; + off_t _st_size_hi; + blkcnt_t st_blocks; + blkcnt_t _st_blkcnt_hi; +#elif defined(__powerpc) + off_t _st_size_hi; + off_t st_size; + blkcnt_t _st_blkcnt_hi; + blkcnt_t st_blkcnt; +#else +#error unknown arch +#endif + blksize_t st_blksize; + unsigned int st_flags; + unsigned int st_gen; + unsigned int _st_spare[5]; +}; + +int fstat(int, struct stat *); +int lstat(const char *, struct stat *); +int stat(const char *, struct stat *); + +#endif diff --git a/plat/osx/include/sys/types.h b/plat/osx/include/sys/types.h index a9fb63277..b4561b7b3 100644 --- a/plat/osx/include/sys/types.h +++ b/plat/osx/include/sys/types.h @@ -3,7 +3,15 @@ #include /* for off_t, ptrdiff_t, size_t */ -typedef int pid_t; -typedef ptrdiff_t ssize_t; +typedef int blkcnt_t; /* XXX should have 64 bits */ +typedef int blksize_t; +typedef int dev_t; +typedef unsigned int gid_t; +typedef unsigned int ino_t; +typedef unsigned short mode_t; +typedef unsigned short nlink_t; +typedef int pid_t; +typedef ptrdiff_t ssize_t; +typedef unsigned int uid_t; #endif diff --git a/plat/osx/include/unistd.h b/plat/osx/include/unistd.h index 24eaf4e54..320db4a86 100644 --- a/plat/osx/include/unistd.h +++ b/plat/osx/include/unistd.h @@ -22,6 +22,11 @@ int ioctl(int, unsigned long, ...); typedef long _libsys_time_t; typedef int suseconds_t; +struct timespec { + _libsys_time_t tv_sec; + long tv_nsec; +}; + struct timeval { _libsys_time_t tv_sec; suseconds_t tv_usec; @@ -48,8 +53,6 @@ int gettimeofday(struct timeval *, struct timezone *); #define O_TRUNC 0x0400 #define O_EXCL 0x0800 -typedef int mode_t; - int creat(const char *, mode_t); int open(const char *, int, ...); diff --git a/plat/osx386/libsys/build.lua b/plat/osx386/libsys/build.lua index a5356ee6c..b3a04c8e7 100644 --- a/plat/osx386/libsys/build.lua +++ b/plat/osx386/libsys/build.lua @@ -3,17 +3,21 @@ acklibrary { srcs = { "./_exit.s", "./close.s", + "./fstat.s", + "./getdirentries.s", "./getpid.s", "./gettimeofday.s", "./ioctl.s", "./kill.s", "./lseek.s", + "./lstat.s", "./mmap.s", "./mprotect.s", "./open.s", "./read.s", "./set_errno.s", "./sigaction.s", + "./stat.s", "./write.s", "plat/linux/libsys/errno.s", "plat/osx/libsys/brk.c", diff --git a/plat/osx386/libsys/fstat.s b/plat/osx386/libsys/fstat.s new file mode 100644 index 000000000..1b49ae0b7 --- /dev/null +++ b/plat/osx386/libsys/fstat.s @@ -0,0 +1,7 @@ +.sect .text +.define _fstat +_fstat: + mov eax, 189 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/getdirentries.s b/plat/osx386/libsys/getdirentries.s new file mode 100644 index 000000000..9c59c627c --- /dev/null +++ b/plat/osx386/libsys/getdirentries.s @@ -0,0 +1,7 @@ +.sect .text +.define _getdirentries +_getdirentries: + mov eax, 196 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/lstat.s b/plat/osx386/libsys/lstat.s new file mode 100644 index 000000000..a492cc3cb --- /dev/null +++ b/plat/osx386/libsys/lstat.s @@ -0,0 +1,7 @@ +.sect .text +.define _lstat +_lstat: + mov eax, 190 + int 0x80 + jb .set_errno + ret diff --git a/plat/osx386/libsys/stat.s b/plat/osx386/libsys/stat.s new file mode 100644 index 000000000..858d84db0 --- /dev/null +++ b/plat/osx386/libsys/stat.s @@ -0,0 +1,7 @@ +.sect .text +.define _stat +_stat: + mov eax, 188 + int 0x80 + jb .set_errno + ret diff --git a/plat/osxppc/libsys/build.lua b/plat/osxppc/libsys/build.lua index a595ed0fa..2accf6eb7 100644 --- a/plat/osxppc/libsys/build.lua +++ b/plat/osxppc/libsys/build.lua @@ -3,17 +3,21 @@ acklibrary { srcs = { "./_exit.s", "./close.s", + "./fstat.s", + "./getdirentries.s", "./getpid.s", "./gettimeofday.s", "./ioctl.s", "./kill.s", "./lseek.s", + "./lstat.s", "./mmap.s", "./mprotect.s", "./open.s", "./read.s", "./set_errno.s", "./sigaction.s", + "./stat.s", "./write.s", "plat/linuxppc/libsys/trap.s", "plat/osx/libsys/brk.c", diff --git a/plat/osxppc/libsys/fstat.s b/plat/osxppc/libsys/fstat.s new file mode 100644 index 000000000..d641cbd91 --- /dev/null +++ b/plat/osxppc/libsys/fstat.s @@ -0,0 +1,9 @@ +.sect .text +.define _fstat +_fstat: + addi r0, r0, 189 ! fstat + lwz r3, 0(sp) ! fd + lwz r4, 4(sp) ! stat pointer + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/getdirentries.s b/plat/osxppc/libsys/getdirentries.s new file mode 100644 index 000000000..d038c5977 --- /dev/null +++ b/plat/osxppc/libsys/getdirentries.s @@ -0,0 +1,11 @@ +.sect .text +.define _getdirentries +_getdirentries: + addi r0, r0, 196 ! getdirentries + lwz r3, 0(sp) ! fd + lwz r4, 4(sp) ! buffer + lwz r5, 8(sp) ! buffer size + lwz r6, 12(sp) ! base pointer + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/lstat.s b/plat/osxppc/libsys/lstat.s new file mode 100644 index 000000000..24d7c44ab --- /dev/null +++ b/plat/osxppc/libsys/lstat.s @@ -0,0 +1,9 @@ +.sect .text +.define _lstat +_lstat: + addi r0, r0, 190 ! lstat + lwz r3, 0(sp) ! path + lwz r4, 4(sp) ! stat pointer + sc 0 + b .set_errno + bclr 20, 0, 0 diff --git a/plat/osxppc/libsys/stat.s b/plat/osxppc/libsys/stat.s new file mode 100644 index 000000000..ab8422cda --- /dev/null +++ b/plat/osxppc/libsys/stat.s @@ -0,0 +1,9 @@ +.sect .text +.define _stat +_stat: + addi r0, r0, 188 ! stat + lwz r3, 0(sp) ! path + lwz r4, 4(sp) ! stat pointer + sc 0 + b .set_errno + bclr 20, 0, 0 From 0c2b6f523cf39338570f4e7752c48d7b46ddcb0b Mon Sep 17 00:00:00 2001 From: George Koehler Date: Mon, 28 Nov 2016 20:58:51 -0500 Subject: [PATCH 11/40] Enable top and make other tweaks in plat/osxppc/descr David Given made top for PowerPC. Copy the asopt phase (running top) from linuxppc to osxppc. Remove CC_ALIGN=-Vr to become compatible with Apple's gcc. Apple uses left adjustment for bitfields; the first bitfield is on the left side (the big end), not the right side. Remove unused variables C_LIB and OLD_C_LIB; the file libc-ansi.a doesn't exist. Change MACHOPT_F from -m10 to -m3. This means to use no more than 3 adds and shifts to optimize a multiply by a constant. I pick -m3 because -m4 can use too many instructions. At -m4, the compiler rewrites n * 14 as s = n << 1 (s << 3) + (0 - s) This means (n * 16 - n * 2), but even at ack -O6, the compiler doesn't rewrite (a + (0 - b)) as (a - b). The compiler emits 5 instructions: 2 of rlinmw for 2 left shifts, then addi to load 0 in a register, subf to subtract from that 0, then add. These 5 instructions cost 5 cycles on the MPC7450, using the cycle counts from mach/powerpc/ncg/table. At -m3, (n * 14) becomes 2 instructions: addi to load 14 in a register and mullw to multiply. This also costs 5 cycles (because mullw costs 4 cycles), but uses less space. --- plat/osxppc/descr | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/plat/osxppc/descr b/plat/osxppc/descr index 130d2bd25..2a6d47871 100644 --- a/plat/osxppc/descr +++ b/plat/osxppc/descr @@ -19,12 +19,7 @@ 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:0x129c -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 MACHOPT_F=-m3 # var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr # Override the setting in fe so that files compiled for osxppc can see @@ -41,6 +36,15 @@ name be stdout need .e end +name asopt + from .s + to .so + program {EM}/lib/ack/linuxppc/top + args + optimizer + stdin + stdout +end name as from .s.so to .o From 543bbcb9ab02a9195271c524733f24621ee37bf3 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 30 Nov 2016 14:33:40 -0500 Subject: [PATCH 12/40] Declare raise() for Mac OS X. This prevents the warning, "implicit declaration of function raise", in programs that call raise(). I forgot to declare it because the function raise() is in libc but the declaration goes in libsys. --- plat/osx/include/unistd.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plat/osx/include/unistd.h b/plat/osx/include/unistd.h index 320db4a86..bafa2a6c4 100644 --- a/plat/osx/include/unistd.h +++ b/plat/osx/include/unistd.h @@ -120,6 +120,8 @@ int kill(pid_t, int); int sigaction(int, const struct sigaction *, struct sigaction *); sig_t signal(int, sig_t); +int raise(int); /* in libc */ + /* XXX - end signal.h */ void _exit(int); From 8ef7c31089631537b5d74c74bbefe5560211029f Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 30 Nov 2016 15:29:19 -0500 Subject: [PATCH 13/40] Write a powerpc.descr for ego and use it with osxppc. No change to linuxppc and qemuppc. They continue to run ego without any descr file. I copied m68020.descr to powerpc.descr and changed some numbers. My numbers are guesses; I know little about PowerPC cycle counts, and almost nothing about ego. This powerpc.descr causes most of the example programs to shrink in size (without descr -> with descr): 65429 -> 57237 hilo_b.osxppc -8192 36516 -> 32420 hilo_c.osxppc -4096 55782 -> 51686 hilo_mod.osxppc -4096 20096 -> 20096 hilo_p.osxppc 0 8813 -> 8813 mandelbrot_c.osxppc 0 93355 -> 89259 paranoia_c.osxppc -4096 92751 -> 84559 startrek_c.osxppc -8192 (Each file has 2 Mach segments, then a symbol table. Each segment takes a multiple of 4096 bytes. When the code shrinks, we lose a multiple of 4096 bytes.) I used "ack -mosxppc -O6 -c.so" to examine the assembly code for hilo.mod and mandelbrot.c, both without and with descr. This reveals optimizations made only with descr, from 2 ego phases: SP (stack pollution) and RA (register allocation). In hilo.mod, SP deletes some instructions that remove items from the stack. These items get removed when the function returns. In both hilo.mod and mandelbrot.c, RA moves some values into local variables, so ncg can make them into register variables. This shrinks code size, probably because register variables get preserved across function calls. More values stay in registers, and ncg emits shorter code. I believe that the ego descr file uses (time,space) tuples but the ncg table uses (space,time) tuples. This is confusing. Perhaps I am wrong, and some or all tuples are backwards. My time values are the cycle counts in latency from the MPC7450 Reference Manual (but not including complications like "store serialization"). In powerpc.descr, I give the cost for saving and restoring registers as if I was using chains of stw and lwz instructions. Actually ncg uses single stmw and lmw instructions with at least 2 instructions. The (time,space) for stmw and lmw would be much less than the (time,space) for chains of stw and lwz. But this ignores the pipeline of the MPC7450. The chains of stw and lwz may run faster than stmw and lmw in the pipeline, because the throughput may be better than the latency. By using the wrong values for (time,space), I'm trying to tell ego that stmw and lmw are not better than chains of stw and lwz. --- plat/osxppc/descr | 2 +- util/ego/descr/build.lua | 1 + util/ego/descr/powerpc.descr | 118 +++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 util/ego/descr/powerpc.descr diff --git a/plat/osxppc/descr b/plat/osxppc/descr index 2a6d47871..1aa615965 100644 --- a/plat/osxppc/descr +++ b/plat/osxppc/descr @@ -20,7 +20,7 @@ var PLATFORMDIR={EM}/share/ack/{PLATFORM} var CPP_F=-D__unix var ALIGN=-a0:4 -a1:4 -a2:4096 -a3:4 -b0:0x129c var MACHOPT_F=-m3 -# var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr +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. diff --git a/util/ego/descr/build.lua b/util/ego/descr/build.lua index 034ffa3ce..e9a008cc5 100644 --- a/util/ego/descr/build.lua +++ b/util/ego/descr/build.lua @@ -22,6 +22,7 @@ end build_descr("i386") build_descr("i86") build_descr("m68020") +build_descr("powerpc") installable { name = "pkg", diff --git a/util/ego/descr/powerpc.descr b/util/ego/descr/powerpc.descr new file mode 100644 index 000000000..5138cc44b --- /dev/null +++ b/util/ego/descr/powerpc.descr @@ -0,0 +1,118 @@ +wordsize: 4 +pointersize: 4 +%%RA +general registers: 19 +address registers: 0 +floating point registers: 0 +use general as pointer: yes + +register score parameters: + local variable: + (2 cases) + pointer,general + (1 size) + default -> (3,4) + general,general + (1 size) + default -> (3,4) + address of local variable: + (2 cases) + pointer,general + (1 size) + default -> (0,0) + general,general + (1 size) + default -> (0,0) + constant: + (2 sizes) + fitbyte -> (-1,-1) + default -> (-1,-1) + double constant: + (1 size) + default -> (-1,-1) + address of global variable: + (1 size) + default -> (2,8) + address of procedure: + (1 size) + default -> (-1,-1) + +opening cost parameters: + local variable: + (2 cases) + pointer + (1 size) + default -> (3,4) + general + (1 size) + default -> (3,4) + address of local variable: + (2 cases) + pointer + (1 size) + default -> (1,4) + general + (1 size) + general -> (1,4) + constant: + (2 sizes) + fitbyte -> (1000,1000) + default -> (1000,1000) + double constant: + (1 size) + default -> (1000,1000) + address of global variable: + (1 size) + default -> (2,8) + address of procedure: + (1 size) + default -> (1000,1000) + +register save costs: + (21 cases) + 0 -> (0,0) + 1 -> (6,8) + 2 -> (12,16) + 3 -> (18,24) + 4 -> (24,32) + 5 -> (30,40) + 6 -> (36,48) + 7 -> (42,56) + 8 -> (48,64) + 9 -> (54,72) + 10 -> (60,80) + 11 -> (66,88) + 12 -> (72,96) + 13 -> (78,104) + 14 -> (84,112) + 15 -> (90,120) + 16 -> (96,128) + 17 -> (102,136) + 18 -> (108,144) + 19 -> (114,152) + 0 -> (0,0) +%%UD +access costs of global variables: + (1 size) + default -> (5,12) +access costs of local variables: + (1 size) + default -> (3,4) +%%SR +overflow harmful?: no +array bound harmful?: yes +reduce sli if shift count larger than: 0 +%%CS +#include "em_mnem.h" +first time then space: +addressing modes: op_ads op_adp op_lof op_ldf op_loi op_dch op_lpb -1 + op_ads op_adp op_lof op_ldf op_loi op_dch op_lpb -1 +cheap operations: op_cii op_ciu op_cui op_cuu op_cmi op_cmu op_cmp -1 + op_cii op_ciu op_cui op_cuu op_cmi op_cmu op_cmp -1 +lexical tresholds: 1 1 +indirection limit: 8 +do not eliminate sli if index on shiftcounts: -1 + -1 +forbidden operators: -1 -1 +%%SP +global stack pollution allowed?: yes From e06b1fa05e0d587a1ab20256f8b8b753266135c9 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 2 Dec 2016 18:04:06 -0500 Subject: [PATCH 14/40] Write a manual page for cvmach(6). This manual is in the new mdoc(7) format. All existing ack manuals use the old man(7) format. This might be a problem if someone can't display mdoc(7) files. The build system doesn't install the cvmach(6) manual; that might happen later. The current build system installs manuals in two different places, and doesn't install some manuals, so I don't know what to do. --- plat/osx/cvmach/cvmach.6 | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 plat/osx/cvmach/cvmach.6 diff --git a/plat/osx/cvmach/cvmach.6 b/plat/osx/cvmach/cvmach.6 new file mode 100644 index 000000000..30d4aa2d7 --- /dev/null +++ b/plat/osx/cvmach/cvmach.6 @@ -0,0 +1,96 @@ +.Dd December 2, 2016 +.Dt CVMACH 6 +.Os +.Sh NAME +.Nm cvmach +.Nd convert an executable file from ack.out to Mach-o +.Sh SYNOPSIS +.Cm ~em/lib/ack/cvmach +.Fl m Ns Ar number +.Oo +.Ar infile +.Op Ar outfile +.Oc +.Sh DESCRIPTION +The +.Nm +utility converts an executable file from +.Xr ack.out 5 +format to Mach-object format. +It can produce Mach-o executables for Mac OS X. +If the +.Ar infile +or +.Ar outfile +are not given, then +.Nm +reads from standard input or writes to standard output. +.Pp +The option is required: +.Bl -tag -width Ds +.It Fl m Ns Ar number +Sets the CPU type in the Mach header. +This must be +.Fl m Ns Cm 7 +for Intel i386 or +.Fl m Ns Cm 18 +for PowerPC. +.Nm +doesn't know how to make Mach-o files for other CPU types. +.El +.Pp +The input file must have four segments: +TEXT, ROM, DATA and BSS, in that order. +.Nm +converts them into four Mach sections in two Mach segments. +TEXT and ROM go in the RX segment (Read and eXecute). +DATA and BSS go in the RW segment (Read and Write). +.Nm +sets the page protection so programs can't write the RX segment, +and can't execute the RW segment. +The program will begin execution at the beginning of TEXT. +.Pp +.Nm +also converts the symbol table. +.Sh DIAGNOSTICS +.Bl -diag +.It text segment must have base 0x%lx, not 0x%lx +TEXT must begin immediately after the Mach header and load commands. +The message gives the correct +.Ar base . +Relinking the program with +.Cm em_led Fl b Ns 0: Ns Ar base +would fix it. +.It the %s segment must follow the %s segment. +TEXT and ROM must be continuous in memory, because +.Nm +maps them in the same Mach segment. +Likewise, DATA and BSS must be contiguous. +There may be a small gap between TEXT and ROM, or between DATA and +BSS, only if the gap is necessary to align ROM or BSS. +.It the data and rom segments are too close. +DATA and ROM must not share a page in memory, because +.Nm +maps them in different Mach segments, with different page protections. +The page size for i386 and PowerPC is 4096 or 0x1000 bytes. +For example, if ROM ends at address 0x2bed, +then DATA may not begin at 0x2bf0, because +.Nm +can't put the page from 0x2000 to 0x2fff in both Mach segments. +Relinking the program with +.Cm em_led Fl a Ns 2:4096 +would fix it. +.It the bss space contains initialized data. +BSS must not contain initialized data, because +.Nm +converts it to a zero-fill section. +.El +.Sh CAVEATS +Mac OS X 10.4 for PowerPC does not protect pages against execution. +All mapped pages are executable, whether or not the execute bit is set +in the page protection. +.Nm +can't prevent the execution of the RW segment. +.Sh BUGS +The symbol conversion preserves the name and value of each symbol, but +may lose other information, such as the symbol type. From 25e159c930d2b95371be23dfe7365545338ec51a Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 3 Dec 2016 17:07:51 -0500 Subject: [PATCH 15/40] Remove bad overflow check from plat/osx/libsys/brk.c If I want to check for overflow, then I should check it before I do base + incr, not after. Now that I have no check, I am passing the overflowed base + incr to brk1(), where it will probably fail the nbreak < segment check. --- plat/osx/libsys/brk.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/plat/osx/libsys/brk.c b/plat/osx/libsys/brk.c index a732cac1c..9b58ca1d8 100644 --- a/plat/osx/libsys/brk.c +++ b/plat/osx/libsys/brk.c @@ -76,20 +76,11 @@ int brk(void *addr) void *sbrk(int incr) { - char *base, *nbreak; + char *base; 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) + if (brk1(base + incr) < 0) return (void*)-1; return base; } From 355cc06fff7bbf2590c39b5f1802f49cb490c02f Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 3 Dec 2016 17:17:44 -0500 Subject: [PATCH 16/40] Write README files for osx386 and osxppc. --- plat/osx386/README | 25 +++++++++++ plat/osxppc/README | 110 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 plat/osx386/README create mode 100644 plat/osxppc/README diff --git a/plat/osx386/README b/plat/osx386/README new file mode 100644 index 000000000..8c34134ff --- /dev/null +++ b/plat/osx386/README @@ -0,0 +1,25 @@ +The osx386 platform +=================== + + ack -mosx386 ... + +This platform produces Mach-o executables for Intel Mac OS X. These +are 32-bit executables using our i386 code generator. + +See ../osxppc/README, because our osx386 platform has many of the same +limitations and bugs as our osxppc platform. + + +Bugs +---- + +Some programs can't read the tty after using job control to suspend +and resume the program (with ^Z and "fg" in bash). The read(2) system +call fails with EINTR. In ACK's stdio (in libc), the error is sticky, +so all reads fail. In Apple's stdio, the error is not sticky, and +only the next read fails. The EINTR seems to happen only on Intel Mac +OS X, and not on other platforms. + + +George Koehler +2016-12-03 diff --git a/plat/osxppc/README b/plat/osxppc/README new file mode 100644 index 000000000..dd9a4d49c --- /dev/null +++ b/plat/osxppc/README @@ -0,0 +1,110 @@ +The osxppc platform +=================== + + ack -mosxppc ... + +This platform produces Mach-o executables for PowerPC Mac OS X. You +can run them from the command line in the Terminal. + +You *can't* link to libraries from other compilers. These static +executables don't use the dynamic linker. They don't load Apple's +libraries, so they can't call Carbon or Cocoa. + +The executables use BSD system calls to interact with your Mac. Our +libsys provides only a few system calls, enough to run a few demo +programs, but not much else. Check the header files in ../osx/include +for the available system calls. + + +Bugs +---- + +ACK didn't run on Mac OS X when this platform was added. The only way +to run ack -mosxppc was as a cross compiler from another operating +system. + +ACK doesn't have 64-bit integers, but Mac OS X uses 64-bit integers in +its system calls. Our libsys converts between 32-bit and 64-bit +integers by setting the high bits to zero, or discarding the high +bits. This affects lseek() and stat(). They report the wrong values +for file sizes and offsets beyond 4 gigabytes. + +Our PowerPC code generator is new and probably has bugs. Its stack +layout and calling conventions are not compatible with other +compilers. It passes all function arguments on the stack, which is +slower than passing them in registers. + + +Example +------- +Compile something: + + ack -mosxppc -O6 -o paranoia examples/paranoia.c + +The executable has a symbol table. If you have Apple's Xcode, try + + nm -g paranoia # to list the global symbols + otool -hl paranoia # to check the Mach header and load commands + gdb paranoia # to debug it + +Within gdb, commands like "gdb main" and "gdb '.ret'" can disassemble +functions. Backtraces don't work, because our stack layout is not the +same as Apple's. + + +Other hints +----------- + +PowerPC Macs became obsolete after Apple's transition to Intel. Mac +OS X 10.5 Leopard was the last version to run on PowerPC. The older +Mac OS X 10.4 Tiger was the last version to include Classic for +running Mac OS 9 programs. Our ack -mosxppc began to produce +executables in 2016, about 7 years after Apple released Mac OS X 10.6 +Snow Leopard for Intel only. + +Apple's Xcode included tools like gcc and gdb. It also had manual +pages for some system calls, like getdirentries(2). Some system calls +are like FreeBSD, some are unique to OS X. If you want to learn how +to call write(2) or sigaction(2), then a manual page from another BSD +or Linux might be enough. + +Xcode 2.5 was the last version to run on Tiger. The "Xcode 2.5 +Developer Tools" were a 902.9 MB download from Apple. As of 2016, the +download required an Apple ID and was available at: + + https://developer.apple.com/download/more/ + +Older versions of Xcode came with Mac OS X. If your version of OS X +came with your Mac, /Applications/Installers might contain an Xcode +installer. If you upgraded OS X, your install DVD might have Xcode. + +The source code at https://opensource.apple.com/ might reveal more +about system calls. For 10.4.11.ppc, the kernel is in xnu-792.24.17, +and Libc is in Libc-391.2.10. These files might help: + + xnu*/bsd/kern/syscalls.master + master list of BSD system calls + xnu*/osfmk/kern/syscall_sw.c + master list of Mach traps + xnu*/bsd/kern/mach_loader.c + details about loading Mach-o executables + xnu*/bsd/dev/ppc/unix_signal.c + details about sending signals to processes + xnu*/bsd/sys/*.h + headers that Xcode installs as /usr/include/sys/*.h + xnu*/bsd/man/man2/*.2 + manual pages that Xcode installs as /usr/share/man/man2/*.2 + Libc*/ppc/sys/SYS.h + Libc*/ppc/sys/*.s + assembly code (in gas syntax) for making system calls + +The 10.4.11.ppc sources are wrong for Intel; use 10.4.11.x86 or 10.5 +or newer. 10.5 moved SYS.h to xnu*/libsyscall/custom/SYS.h + +The kernel maps a common page into every process, and Apple's Libc +uses the common page to speed up system calls like gettimeofday(2). +Our libsys does not use the common page. + + +George Koehler +2016-12-03 From 969e98b82de338ea54c7490dee5171415f54148c Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 3 Dec 2016 17:52:24 -0500 Subject: [PATCH 17/40] Create Mach-o files with mode 0777 to allow executing them. Until now, I was always doing chmod +x before running my files on the Mac. Now files get created +x. There's no change when overwriting an existing file. I needed to gmake clean my build to remove the example programs without +x, so cvmach can create them with +x. --- plat/osx/cvmach/cvmach.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plat/osx/cvmach/cvmach.c b/plat/osx/cvmach/cvmach.c index 0b5b6bf80..5f8315ddd 100644 --- a/plat/osx/cvmach/cvmach.c +++ b/plat/osx/cvmach/cvmach.c @@ -12,6 +12,7 @@ * libobject is pinched from the Xenix i386 cv (mach/i386/cv/cv.c). */ +#include #include #include #include @@ -470,7 +471,7 @@ int main(int argc, char *argv[]) { uint32_t end, pad[3], sz, sz_load_cmds; - int cpu_subtype, mflag = 0; + int cpu_subtype, fd, mflag = 0; /* General housecleaning and setup. */ output = stdout; @@ -520,7 +521,11 @@ main(int argc, char *argv[]) break; case 3: /* Both input and output files specified. */ - output = fopen(argv[2], "w"); + /* Use mode 0777 to allow executing the output file. */ + fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0777); + if (fd < 0) + fatal("unable to open output file."); + output = fdopen(fd, "w"); if (!output) fatal("unable to open output file."); outputfile = argv[2]; From c5aff6fc2e6f452d5b313b95c77836cebeeff83c Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 5 Dec 2016 20:33:26 +0100 Subject: [PATCH 18/40] Change dependency from simplerule{} with a dependency but no outputs to an installable; otherwise, the dependency would be built, but the result wouldn't get added to the header path and so wouldn't be seen. --- plat/osx386/include/build.lua | 7 ++----- plat/osxppc/include/build.lua | 9 +++------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/plat/osx386/include/build.lua b/plat/osx386/include/build.lua index 164e2b44a..2f80c1257 100644 --- a/plat/osx386/include/build.lua +++ b/plat/osx386/include/build.lua @@ -1,7 +1,4 @@ -simplerule { +installable { name = "headers", - deps = { "plat/osx/include+headers" }, - ins = {}, - outs = {}, - commands = {}, + map = { "plat/osx/include+pkg" } } diff --git a/plat/osxppc/include/build.lua b/plat/osxppc/include/build.lua index 164e2b44a..2058eb2cc 100644 --- a/plat/osxppc/include/build.lua +++ b/plat/osxppc/include/build.lua @@ -1,7 +1,4 @@ -simplerule { +installable { name = "headers", - deps = { "plat/osx/include+headers" }, - ins = {}, - outs = {}, - commands = {}, -} + map = { "plat/osx/include+pkg" } +} \ No newline at end of file From c569ca15d8d6db8eebe275d7fb376a203557e0ce Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 5 Dec 2016 21:05:24 +0100 Subject: [PATCH 19/40] Clean up how the language libraries refer to plat headers; they should be using the +pkg forms of the rules and getting the headers via the paths in descr, rather than depending on the +headers version. --- lang/basic/lib/build.lua | 4 ++-- lang/cem/libcc.ansi/build.lua | 4 ++-- lang/m2/libm2/build.lua | 4 ++-- lang/pc/libpc/build.lua | 4 ++-- plat/osx386/include/build.lua | 2 +- plat/osx386/libsys/build.lua | 2 +- plat/osxppc/include/build.lua | 2 +- plat/osxppc/libsys/build.lua | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lang/basic/lib/build.lua b/lang/basic/lib/build.lua index 71710a542..cff3b57ca 100644 --- a/lang/basic/lib/build.lua +++ b/lang/basic/lib/build.lua @@ -10,8 +10,8 @@ for _, plat in ipairs(vars.plats) do hdrs = {}, -- must be empty deps = { "h+emheaders", - "lang/cem/libcc.ansi/headers+headers", - "plat/"..plat.."/include+headers", + "lang/cem/libcc.ansi/headers+pkg", + "plat/"..plat.."/include+pkg", }, vars = { plat = plat } } diff --git a/lang/cem/libcc.ansi/build.lua b/lang/cem/libcc.ansi/build.lua index 601a50de4..20591f803 100644 --- a/lang/cem/libcc.ansi/build.lua +++ b/lang/cem/libcc.ansi/build.lua @@ -51,8 +51,8 @@ for _, plat in ipairs(vars.plats) do }, hdrs = {}, -- must be empty deps = { - "lang/cem/libcc.ansi/headers+headers", - "plat/"..plat.."/include+headers", + "lang/cem/libcc.ansi/headers+pkg", + "plat/"..plat.."/include+pkg", "./malloc/malloc.h", "./math/localmath.h", "./stdio/loc_incl.h", diff --git a/lang/m2/libm2/build.lua b/lang/m2/libm2/build.lua index d0861b966..a1a9e5c0a 100644 --- a/lang/m2/libm2/build.lua +++ b/lang/m2/libm2/build.lua @@ -29,8 +29,8 @@ for _, plat in ipairs(vars.plats) do }, hdrs = {}, -- must be empty deps = { - "lang/cem/libcc.ansi/headers+headers", - "plat/"..plat.."/include+headers", + "lang/cem/libcc.ansi/headers+pkg", + "plat/"..plat.."/include+pkg", "h+emheaders", }, vars = { plat = plat } diff --git a/lang/pc/libpc/build.lua b/lang/pc/libpc/build.lua index 7845991e5..215f0c745 100644 --- a/lang/pc/libpc/build.lua +++ b/lang/pc/libpc/build.lua @@ -17,8 +17,8 @@ for _, plat in ipairs(vars.plats) do }, hdrs = {}, -- must be empty deps = { - "lang/cem/libcc.ansi/headers+headers", - "plat/"..plat.."/include+headers", + "lang/cem/libcc.ansi/headers+pkg", + "plat/"..plat.."/include+pkg", "h+emheaders", }, vars = { plat = plat } diff --git a/plat/osx386/include/build.lua b/plat/osx386/include/build.lua index 2f80c1257..c2a1050c2 100644 --- a/plat/osx386/include/build.lua +++ b/plat/osx386/include/build.lua @@ -1,4 +1,4 @@ installable { - name = "headers", + name = "pkg", map = { "plat/osx/include+pkg" } } diff --git a/plat/osx386/libsys/build.lua b/plat/osx386/libsys/build.lua index b3a04c8e7..23e491f7a 100644 --- a/plat/osx386/libsys/build.lua +++ b/plat/osx386/libsys/build.lua @@ -27,7 +27,7 @@ acklibrary { }, deps = { "lang/cem/libcc.ansi/headers+headers", - "plat/osx386/include+headers", + "plat/osx386/include+pkg", }, vars = { plat = "osx386" diff --git a/plat/osxppc/include/build.lua b/plat/osxppc/include/build.lua index 2058eb2cc..0fe204ece 100644 --- a/plat/osxppc/include/build.lua +++ b/plat/osxppc/include/build.lua @@ -1,4 +1,4 @@ installable { - name = "headers", + name = "pkg", map = { "plat/osx/include+pkg" } } \ No newline at end of file diff --git a/plat/osxppc/libsys/build.lua b/plat/osxppc/libsys/build.lua index 2accf6eb7..072730b7a 100644 --- a/plat/osxppc/libsys/build.lua +++ b/plat/osxppc/libsys/build.lua @@ -27,7 +27,7 @@ acklibrary { }, deps = { "lang/cem/libcc.ansi/headers+headers", - "plat/osxppc/include+headers", + "plat/osxppc/include+pkg", }, vars = { plat = "osxppc" From 3fe285f8f8fcff0fd32de4c971400503d72158e0 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 5 Dec 2016 21:06:38 +0100 Subject: [PATCH 20/40] Fix some shell issues that would occasionally cause hangs if no tests failed. --- first/testsummary.sh | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/first/testsummary.sh b/first/testsummary.sh index 6301cb977..6c2d3e39a 100755 --- a/first/testsummary.sh +++ b/first/testsummary.sh @@ -3,9 +3,15 @@ echo "" succeeding="$(find "$@" -size 0)" notsucceeding="$(find "$@" ! -size 0)" -skipped="$(grep -l @@SKIPPED $notsucceeding)" -timedout="$(grep -l @@TIMEDOUT $notsucceeding)" -failed="$(grep -l @@FAIL $notsucceeding)" +if [ "$notsucceeding" != "" ]; then + skipped="$(grep -l @@SKIPPED $notsucceeding)" + timedout="$(grep -l @@TIMEDOUT $notsucceeding)" + failed="$(grep -l @@FAIL $notsucceeding)" +else + skipped= + timedout= + failed= +fi for a in $failed $timedout; do echo "**** $a" @@ -13,11 +19,11 @@ for a in $failed $timedout; do echo "" done -echo "$(echo $succeeding | wc -w) tests passed" -echo "$(echo $notsucceeding | wc -w) tests failed to pass" -echo "$(echo $skipped | wc -w) were skipped (see build log for details)" -echo "$(echo $timedout | wc -w) timed out" -echo "$(echo $failed | wc -w) failed" +echo "$(echo "$succeeding" | wc -w) tests passed" +echo "$(echo "$notsucceeding" | wc -w) tests failed to pass" +echo "$(echo "$skipped" | wc -w) were skipped (see build log for details)" +echo "$(echo "$timedout" | wc -w) timed out" +echo "$(echo "$failed" | wc -w) failed" echo "" if [ "$failed" != "" -o "$timedout" != "" ]; then From 6cbea83f7f969910b97e283297a83979634da190 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Mon, 5 Dec 2016 20:13:29 -0500 Subject: [PATCH 21/40] Don't share as, ncg, top between Linux and Mac OS X. Telling osx386 and osxppc to build and run their own tools, not to reuse the tools from linux386 and linuxppc. This wastes time to build identical tools, but it removes some bogus dependencies. OS X tools had wrongly depended on Linux descr files and aelflod; now they don't. Discussion in https://github.com/davidgiven/ack/pull/23 --- plat/osx386/build-tools.lua | 15 ++++++++++++++- plat/osx386/descr | 4 ++-- plat/osxppc/build-tools.lua | 21 ++++++++++++++++++++- plat/osxppc/descr | 6 +++--- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/plat/osx386/build-tools.lua b/plat/osx386/build-tools.lua index 097cb94d3..a1a9a8e2b 100644 --- a/plat/osx386/build-tools.lua +++ b/plat/osx386/build-tools.lua @@ -1,8 +1,21 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "i386", +} + +build_ncg { + name = "ncg", + arch = "i386", +} + return installable { name = "tools", map = { + ["$(PLATDEP)/osx386/as"] = "+as", + ["$(PLATDEP)/osx386/ncg"] = "+ncg", ["$(PLATIND)/descr/osx386"] = "./descr", - "plat/linux386+tools", "plat/osx/cvmach+pkg", "util/opt+pkg", } diff --git a/plat/osx386/descr b/plat/osx386/descr index 9e4cf2577..a6f021878 100644 --- a/plat/osx386/descr +++ b/plat/osx386/descr @@ -34,7 +34,7 @@ var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - program {EM}/lib/ack/linux386/ncg + program {EM}/lib/ack/{PLATFORM}/ncg mapflag -gdb GF=-gdb args {GF?} < stdout @@ -43,7 +43,7 @@ end name as from .s.so to .o - program {EM}/lib/ack/linux386/as + program {EM}/lib/ack/{PLATFORM}/as args - -o > < prep cond end diff --git a/plat/osxppc/build-tools.lua b/plat/osxppc/build-tools.lua index d19d25e19..eddeea85a 100644 --- a/plat/osxppc/build-tools.lua +++ b/plat/osxppc/build-tools.lua @@ -1,8 +1,27 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "powerpc", +} + +build_ncg { + name = "ncg", + arch = "powerpc", +} + +build_top { + name = "top", + arch = "powerpc", +} + return installable { name = "tools", map = { + ["$(PLATDEP)/osxppc/as"] = "+as", + ["$(PLATDEP)/osxppc/ncg"] = "+ncg", + ["$(PLATDEP)/osxppc/top"] = "+top", ["$(PLATIND)/descr/osxppc"] = "./descr", - "plat/linuxppc+tools", "plat/osx/cvmach+pkg", "util/opt+pkg", } diff --git a/plat/osxppc/descr b/plat/osxppc/descr index 1aa615965..f659ff0ef 100644 --- a/plat/osxppc/descr +++ b/plat/osxppc/descr @@ -30,7 +30,7 @@ var C_INCLUDES=-I{EM}/share/ack/osx/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - program {EM}/lib/ack/linuxppc/ncg + program {EM}/lib/ack/{PLATFORM}/ncg mapflag -gdb GF=-gdb args {GF?} < stdout @@ -39,7 +39,7 @@ end name asopt from .s to .so - program {EM}/lib/ack/linuxppc/top + program {EM}/lib/ack/{PLATFORM}/top args optimizer stdin @@ -48,7 +48,7 @@ end name as from .s.so to .o - program {EM}/lib/ack/linuxppc/as + program {EM}/lib/ack/{PLATFORM}/as args - -o > < prep cond end From 55e24e1f24b932592ba3b24c8e97c3410c1a9d8b Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 6 Dec 2016 21:45:20 +0100 Subject: [PATCH 22/40] inn was assuming that bitfields were arrays of bytes, when actually they're arrays of words (which makes the LSB move on big-endian systems). --- mach/powerpc/libem/inn.s | 6 +++--- tests/plat/inn_e.e | 27 ++++++++++----------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mach/powerpc/libem/inn.s b/mach/powerpc/libem/inn.s index f5ae4c63e..9770ac094 100644 --- a/mach/powerpc/libem/inn.s +++ b/mach/powerpc/libem/inn.s @@ -13,10 +13,10 @@ lwz r4, 4(sp) /* r4 = bit number */ addi r5, sp, 8 /* r5 = base address of bit set */ - srawi r6, r4, 3 /* r6 = byte address into set */ - andi. r7, r4, 7 /* r7 = bit within byte */ + rlwinm r6, r4, 29, 3, 29 /* r6 = byte index of word in set */ + andi. r7, r4, 31 /* r7 = bit within word */ - lbzx r8, r5, r6 /* r8 = individual byte from set */ + lwzx r8, r5, r6 /* r8 = individual byte from set */ sraw r8, r8, r7 rlwinm r8, r8, 0, 31, 31 diff --git a/tests/plat/inn_e.e b/tests/plat/inn_e.e index 7d27abf42..a5aee02f5 100644 --- a/tests/plat/inn_e.e +++ b/tests/plat/inn_e.e @@ -7,10 +7,10 @@ /* Test non-existent bit */ .1 - rom 0I1, 0I1, 0I1, 0I1 + rom 0I4 loe .1 loc 1 /* bit number */ - inn EM_WSIZE + inn 4 zeq *1 loc __LINE__ @@ -21,9 +21,12 @@ /* Test existent bit */ .2 - rom 2I1, 0I1, 0I1, 0I1 + rom 16384 +.21 + rom 14 /* to defeat constant folding */ + loe .2 - loc 1 /* bit number */ + loe .21 /* bit number */ inn EM_WSIZE zne *2 @@ -35,10 +38,9 @@ /* Test non-existent high bit */ .3 - rom 0I1, 0I1, 0I1, 0I1 - rom 0I1, 0I1, 0I1, 0I1 + rom 0, 0 .31 - rom (EM_WSIZE*8)+1 /* to defeat constant folding */ + rom 8 /* to defeat constant folding */ lae .3 loi EM_WSIZE*2 @@ -54,16 +56,7 @@ /* Test existent high bit */ .4 -#if EM_WSIZE == 2 - rom 0I1, 0I1 - rom 2I1, 0I1 -#elif EM_WSIZE == 4 - rom 0I1, 0I1, 0I1, 0I1 - rom 2I1, 0I1, 0I1, 0I1 -#else - #error Unknown word size -#endif - + rom 0, 2 .41 rom (EM_WSIZE*8)+1 /* to defeat constant folding */ From cc3d72e884848fce02ad44277924d9eecce14ff0 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 6 Dec 2016 22:05:14 +0100 Subject: [PATCH 23/40] Fix redirection so stray stderr output from qemu doesn't cause mysterious test failures. --- tests/plat/testdriver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/plat/testdriver.sh b/tests/plat/testdriver.sh index 5e8e5b899..384c83b47 100755 --- a/tests/plat/testdriver.sh +++ b/tests/plat/testdriver.sh @@ -27,7 +27,7 @@ get_test_output() { qemu-system-ppc) img="-kernel $img" ;; esac - $timeoutprog -t $timeout -- $method -nographic $img 2>&1 > $result + $timeoutprog -t $timeout -- $method -nographic $img > $result 2>&1 ;; qemu-*) @@ -37,7 +37,7 @@ get_test_output() { exit 0 fi - $method $img 2>&1 > $result + $method $img > $result 2>&1 ;; *) From 67e7d226ad15464ed9133810defa474cc021627e Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 6 Dec 2016 22:06:17 +0100 Subject: [PATCH 24/40] Disable qemuppc tests; turns out qemu-system-ppc won't load more than the first 4kB of a kernel... --- build.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.lua b/build.lua index 6364e5f75..91415d689 100644 --- a/build.lua +++ b/build.lua @@ -18,7 +18,7 @@ vars.plats = { vars.plats_with_tests = { "linux386", "linuxppc", - "qemuppc", + -- "qemuppc", FIXME: disable until we figure out why qemu won't run binaries bigger than 4kB "pc86", } From 1039c0a7473ff5f6bf03ace435ca6ecc46edb060 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 6 Dec 2016 22:07:22 +0100 Subject: [PATCH 25/40] Add a test for #22. --- tests/plat/{_dummy.c => _dummy_e.c} | 0 tests/plat/bugs/bug-22-inn_mod.mod | 26 ++++++++++++++++++++++++++ tests/plat/build.lua | 9 +++++---- 3 files changed, 31 insertions(+), 4 deletions(-) rename tests/plat/{_dummy.c => _dummy_e.c} (100%) create mode 100644 tests/plat/bugs/bug-22-inn_mod.mod diff --git a/tests/plat/_dummy.c b/tests/plat/_dummy_e.c similarity index 100% rename from tests/plat/_dummy.c rename to tests/plat/_dummy_e.c diff --git a/tests/plat/bugs/bug-22-inn_mod.mod b/tests/plat/bugs/bug-22-inn_mod.mod new file mode 100644 index 000000000..8f3a2d00a --- /dev/null +++ b/tests/plat/bugs/bug-22-inn_mod.mod @@ -0,0 +1,26 @@ +MODULE test; +FROM InOut IMPORT WriteLn, WriteString; + +TYPE charset = SET OF CHAR; + +PROCEDURE Space(c: CHAR): BOOLEAN; +BEGIN + RETURN c IN charset{' ', 11C, 12C, 15C} +END Space; + +BEGIN + IF Space('a') THEN + WriteString("@@FAIL 1"); + WriteLn; + END; + IF NOT Space(' ') THEN + WriteString("@@FAIL 2"); + WriteLn; + END; + IF NOT Space(12C) THEN + WriteString("@@FAIL 3"); + WriteLn; + END; + WriteString("@@FINISHED"); + WriteLn; +END test. \ No newline at end of file diff --git a/tests/plat/build.lua b/tests/plat/build.lua index f5885a190..d8362b3a0 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -11,7 +11,8 @@ definerule("plat_testsuite", local testfiles = filenamesof( "tests/plat/*.c", "tests/plat/*.e", - "tests/plat/*.p" + "tests/plat/*.p", + "tests/plat/bugs/*.mod" ) acklibrary { @@ -23,8 +24,8 @@ definerule("plat_testsuite", local tests = {} for _, f in ipairs(testfiles) do - local fs = replace(basename(f), "%..$", "") - local _, _, lang = fs:find("_(.)$") + local fs = replace(basename(f), "%.[^.]+$", "") + local _, _, lang = fs:find("_([^_]+)$") if not lang then lang = "e" end @@ -49,7 +50,7 @@ definerule("plat_testsuite", "util/build+testrunner" }, commands = { - "(%{ins[2]} "..e.method.." %{ins[1]} 5 %{ins[3]} || echo FAILED) 2>&1 > %{outs}", + "(%{ins[2]} "..e.method.." %{ins[1]} 5 %{ins[3]} || echo FAILED) > %{outs}", } } end From b8c921ca70c17a51b74e39d11974e130c32ed409 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 7 Dec 2016 17:28:00 -0500 Subject: [PATCH 26/40] Allow mfspr, mtspr with a register number. PowerPC has a few hundred special-purpose registers. The assembler had only accepted the names "xer", "lr", "ctr". Most programs use only those three SPRs. If I add more names, they would almost never get used, and they might conflict with labels. I want to use "mfspr r3, 0x3f0" and "mtspr 0x3f0, r3" in plat/qemu/boot.s to access register hid0 from supervisor mode. --- mach/powerpc/as/mach2.c | 2 +- mach/powerpc/as/mach4.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mach/powerpc/as/mach2.c b/mach/powerpc/as/mach2.c index 96d6690df..480c5faa3 100644 --- a/mach/powerpc/as/mach2.c +++ b/mach/powerpc/as/mach2.c @@ -88,4 +88,4 @@ %type c %type e16 u8 u7 u6 u5 u4 u2 u1 -%type nb ds bda bdl lia lil +%type nb ds bda bdl lia lil spr_num diff --git a/mach/powerpc/as/mach4.c b/mach/powerpc/as/mach4.c index 3f79ca86c..e1fb3fdf0 100644 --- a/mach/powerpc/as/mach4.c +++ b/mach/powerpc/as/mach4.c @@ -34,7 +34,7 @@ operation | OP_RT_RA_RB_C c GPR ',' GPR ',' GPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); } | OP_RT_RA_SI GPR ',' GPR ',' e16 { emit4($1 | ($2<<21) | ($4<<16) | $6); } | OP_RT_RA_SI_addic c GPR ',' GPR ',' e16 { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); } - | OP_RT_SPR GPR ',' SPR { emit4($1 | ($2<<21) | ($4<<11)); } + | OP_RT_SPR GPR ',' spr_num { emit4($1 | ($2<<21) | ($4<<11)); } | OP_RS_FXM u7 ',' GPR { emit4($1 | ($4<<21) | ($2<<12)); } | OP_RS_RA_C c GPR ',' GPR { emit4($1 | $2 | ($5<<21) | ($3<<16)); } | OP_RS_RA_D GPR ',' e16 '(' GPR ')' { emit4($1 | ($2<<21) | ($6<<16) | $4); } @@ -53,7 +53,7 @@ operation | OP_RS_RA_SH_ME6_SH_C c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); } | OP_RS_RA_SH5_C c GPR ',' GPR ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); } | OP_RS_RA_SH6_C c GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | (($7&0x20)>>4)); } - | OP_RS_SPR SPR ',' GPR { emit4($1 | ($4<<21) | ($2<<11)); } + | OP_RS_SPR spr_num ',' GPR { emit4($1 | ($4<<21) | ($2<<11)); } | OP_TO_RA_RB u5 ',' GPR ',' GPR { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); } | OP_TO_RA_SI u5 ',' GPR ',' e16 { emit4($1 | ($2<<21) | ($4<<16) | $6); } | OP_LEV u7 { emit4($1 | ($2<<5)); } @@ -237,4 +237,14 @@ lia $$ = target & 0x03FFFFFD; } ; - + +spr_num + : SPR { $$ = $1; } + | absexp + { + if (($1 < 0) || ($1 > 0x3ff)) + serror("spr number out of range"); + /* mfspr, mtspr swap the low and high 5 bits */ + $$ = ($1 >> 5) | (($1 & 0x1f) << 5); + } + ; From d94ea4c508269b6c9ba4f3f4abb25c615acddd60 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Wed, 7 Dec 2016 18:11:12 -0500 Subject: [PATCH 27/40] Teach qemuppc to halt the cpu on _exit(). Without this, qemu-system-ppc spins the host cpu until I close its window. I assume the default G3 emulation. The emulator yields the host cpu if I set certain flags in hid0 then msr. The hid0 flag can be any of DOZE, NAP, SLEEP, so I just set all 3. I encode mfmsr and mtmsr with .data4, because our assembler doesn't know instructions for supervisor mode. Also move some common symbols from .rom to .bss. Our assembler puts common symbols in any section. Also clean up the file. Delete a comment about linuxppc that is wrong here. Delete redundant .extern because .define is the same. --- plat/qemuppc/boot.s | 47 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s index 2dd9a4c5c..1100f3883 100644 --- a/plat/qemuppc/boot.s +++ b/plat/qemuppc/boot.s @@ -13,22 +13,14 @@ .sect .text begtext: - ! This code is placed at the beginning of the ELF executable and is the - ! first thing that runs. + ! This code is the first thing that runs. The booloader + ! passes the Open Firmware pointer in r5. ! - ! On entry, the stack looks like this: + ! We keep the bootloader's stack. The ACK expects: ! - ! sp+... NULL - ! sp+8+(4*argc) env (X quads) - ! sp+4+(4*argc) NULL - ! sp+4 argv (argc quads) + ! sp+8 environment pointer + ! sp+4 argv as a pointer ! sp argc - ! - ! The ACK actually expects: - ! - ! sp+8 argc - ! sp+4 ptr to argv - ! sp ptr to env li32 r3, __openfirmware_ptr stw r5, 0(r3) @@ -47,15 +39,23 @@ begtext: ! falls through .define __exit -.extern __exit .define EXIT -.extern EXIT __exit: EXIT: - b EXIT + ! Halt the CPU. This code halts the default G3 emulation of + ! qemu-system-ppc. It's wrong for some other CPU models. +#define hid0 0x3f0 +#define mfmsr(r) [[31<<26]|[[r]<<21]|0x0a6] +#define mtmsr(r) [[31<<26]|[[r]<<21]|0x124] + mfspr r3, hid0 + oris r3, r3, 0x00e0 ! set DOZE, NAP, SLEEP + mtspr hid0, r3 ! in hid0 + .data4 mfmsr(3) + oris r3, r3, 0x0004 ! set POW + .data4 mtmsr(3) ! in msr0 + b EXIT ! If we failed to halt, then spin. .define _openfirmware_call -.extern _openfirmware_call _openfirmware_call: lwz r3, 0(sp) li32 r4, __openfirmware_ptr @@ -66,15 +66,10 @@ _openfirmware_call: ! Define symbols at the beginning of our various segments, so that we can find ! them. (Except .text, which has already been done.) -.sect .data; begdata: .sect .rom; begrom: +.sect .data; begdata: .sect .bss; begbss: -! Some magic data. All EM systems need these. - -.define _errno -.comm _errno, 4 ! Posix errno storage - ! The argv and env arrays. .sect .rom @@ -82,6 +77,12 @@ argv: .data4 exename, 0 envp: .data4 0 exename: .asciz 'qemuppc.img' +! Some magic data. All EM systems need these. + +.sect .bss +.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 From df86e3b84f38ad8b6882ee6139a3e0926c4f7f71 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 16:04:21 -0500 Subject: [PATCH 28/40] Fix typo: msr0 should be msr. --- plat/qemuppc/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/qemuppc/boot.s b/plat/qemuppc/boot.s index 1100f3883..ac3227dc9 100644 --- a/plat/qemuppc/boot.s +++ b/plat/qemuppc/boot.s @@ -52,7 +52,7 @@ EXIT: mtspr hid0, r3 ! in hid0 .data4 mfmsr(3) oris r3, r3, 0x0004 ! set POW - .data4 mtmsr(3) ! in msr0 + .data4 mtmsr(3) ! in msr b EXIT ! If we failed to halt, then spin. .define _openfirmware_call From 244e554f2f592094bed0a5eea11229e33465c79b Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 16:36:42 -0500 Subject: [PATCH 29/40] Remove trailing whitespace in mach/powerpc/ncg/table --- mach/powerpc/ncg/table | 366 ++++++++++++++++++++--------------------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 77fdaedf1..1d2c5516e 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -48,12 +48,12 @@ PROPERTIES FSREG /* any allocatable single-precision FPR */ SPR /* any SPR */ CR /* any CR */ - + GPR0 GPRSP GPRFP GPR3 GPR4 GPR5 GPR6 GPR7 GPR8 GPR9 GPR10 GPR11 GPR12 GPR13 GPR14 GPR15 GPR16 GPR17 GPR18 GPR19 GPR20 GPR21 GPR22 GPR23 GPR24 GPR25 GPR26 GPR27 GPR28 GPR29 GPR30 GPR31 - + CR0 CR1 FPR0 FPR1 FPR2 FPR3 FPR4 FPR5 FPR6 FPR7 @@ -64,7 +64,7 @@ PROPERTIES REGISTERS /* Reverse order to encourage ncg to allocate them from r31 down */ - + R31("r31") : GPR, REG, GPR31 regvar. R30("r30") : GPR, REG, GPR30 regvar. R29("r29") : GPR, REG, GPR29 regvar. @@ -195,17 +195,17 @@ TOKENS SUM_RIS = { GPR reg; INT offhi; } 4. SUM_RC = { GPR reg; INT off; } 4. SUM_RR = { GPR reg1; GPR reg2; } 4. - + TRISTATE_RC_S = { GPR reg; INT val; } 4. TRISTATE_RC_U = { GPR reg; INT val; } 4. TRISTATE_RR_S = { GPR reg1; GPR reg2; } 4. TRISTATE_RR_U = { GPR reg1; GPR reg2; } 4. - + TRISTATE_FF = { FPR reg1; FPR reg2; } 4. - + SEX_B = { GPR reg; } 4. SEX_H = { GPR reg; } 4. - + IND_RC_B = { GPR reg; INT off; } 4. IND_RR_B = { GPR reg1; GPR reg2; } 4. IND_RC_H = { GPR reg; INT off; } 4. @@ -216,9 +216,9 @@ TOKENS IND_RR_W = { GPR reg1; GPR reg2; } 4. IND_RC_D = { GPR reg; INT off; } 8. IND_RR_D = { GPR reg1; GPR reg2; } 8. - + NOT_R = { GPR reg; } 4. - + AND_RR = { GPR reg1; GPR reg2; } 4. OR_RR = { GPR reg1; GPR reg2; } 4. OR_RIS = { GPR reg; INT valhi; } 4. @@ -241,12 +241,12 @@ SETS CONST_8000 + CONST_8001_FFFF + CONST_HZ + CONST_HL. SUM_ALL = SUM_RC + SUM_RR. - + TRISTATE_ALL = TRISTATE_RC_S + TRISTATE_RC_U + TRISTATE_RR_S + TRISTATE_RR_U + TRISTATE_FF. - + SEX_ALL = SEX_B + SEX_H. - + LOGICAL_ALL = NOT_R + AND_RR + OR_RR + OR_RC + XOR_RR + XOR_RC. @@ -371,7 +371,7 @@ INSTRUCTIONS comment "!" LABEL:ro cost(0, 0). - + MOVES from GPR to GPR @@ -381,12 +381,12 @@ MOVES /* GPRE exists solely to allow us to use regvar() (which can only be used in an expression) as a register constant. */ - + from GPR to GPRE gen COMMENT("move GPR->GPRE") or %2.reg, %1, %1 - + /* Constants */ from CONST_ALL smalls(%val) to GPR @@ -406,19 +406,19 @@ MOVES gen COMMENT("move LABEL->GPR") li32 %2, {LABEL, %1.adr} - + /* Sign extension */ from SEX_B to GPR gen COMMENT("move SEX_B->GPR") extsb %2, %1.reg - + from SEX_H to GPR gen COMMENT("move SEX_H->GPR") extsh %2, %1.reg - + /* Register + something */ from SUM_RIS to GPR @@ -575,38 +575,38 @@ MOVES from TRISTATE_RR_S to CR0 gen cmp %2, {CONST, 0}, %1.reg1, %1.reg2 - + from TRISTATE_RR_U to CR0 gen cmpl %2, {CONST, 0}, %1.reg1, %1.reg2 - + from TRISTATE_RC_S to CR0 gen COMMENT("move TRISTATE_RC_S->CR0 large") move {CONST, %1.val}, RSCRATCH cmp %2, {CONST, 0}, %1.reg, RSCRATCH - + from TRISTATE_RC_U smallu(%val) to CR0 gen COMMENT("move TRISTATE_RC_U->CR0 small") cmpli %2, {CONST, 0}, %1.reg, {CONST, %1.val} - + from TRISTATE_RC_U to CR0 gen COMMENT("move TRISTATE_RC_U->CR0") move {CONST, %1.val}, RSCRATCH cmpl %2, {CONST, 0}, %1.reg, RSCRATCH - + from TRISTATE_FF to CR0 gen COMMENT("move TRISTATE_FF->CR0") fcmpo %2, %1.reg1, %1.reg2 - + from GPR to CR0 gen COMMENT("move GPR->CR0") orX RSCRATCH, %1, %1 /* alas, can't call test */ - + from TRISTATE_RR_S + TRISTATE_RC_S + TRISTATE_FF to GPR gen COMMENT("move TRISTATE_R*_S->GPR") @@ -671,9 +671,9 @@ MOVES gen move %1, %2.reg - + TESTS - + to test GPR gen orX RSCRATCH, %1, %1 @@ -709,36 +709,36 @@ STACKINGRULES COMMENT("stack SEX_B") extsb RSCRATCH, %1.reg stwu RSCRATCH, {GPRINDIRECT, SP, 0-4} - + from SEX_H to STACK gen COMMENT("stack SEX_H") extsh RSCRATCH, %1.reg stwu RSCRATCH, {GPRINDIRECT, SP, 0-4} - + from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL to STACK gen COMMENT("stack SUM_ALL + TRISTATE_ALL + LOGICAL_ALL") move %1, RSCRATCH stwu RSCRATCH, {GPRINDIRECT, SP, 0-4} - + from IND_ALL_BHW to STACK gen COMMENT("stack IND_ALL_BHW") move %1, RSCRATCH stwu RSCRATCH, {GPRINDIRECT, SP, 0-4} - + from IND_ALL_D to STACK gen COMMENT("stack IND_ALL_D") move %1, FSCRATCH stfdu FSCRATCH, {GPRINDIRECT, SP, 0-8} - + from FREG to STACK gen COMMENT("stack FPR") stfdu %1, {GPRINDIRECT, SP, 0-8} - + from FSREG to STACK gen COMMENT("stack FSREG") @@ -761,14 +761,14 @@ COERCIONS COMMENT("coerce CONST_ALL->REG") move %1, %a yields %a - + from LABEL uses REG gen COMMENT("coerce LABEL->REG") move %1, %a yields %a - + from STACK uses REG gen @@ -792,32 +792,32 @@ COERCIONS COMMENT("coerce SEX_B->REG") extsb %a, %1.reg yields %a - + from SEX_H uses REG gen COMMENT("coerce SEX_H->REG") extsh %a, %1.reg yields %a - + from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL uses REG gen move %1, %a yields %a - + from FSREG uses FSREG gen fmr %a, %1 yields %a - + from FREG uses FREG gen fmr %a, %1 yields %a - + from STACK uses FREG gen @@ -884,17 +884,17 @@ PATTERNS yields %1 %1 with FSREG yields %1 %1 - + pat dup $1==INT64 /* Duplicate double-word on top of stack */ with REG REG yields %2 %1 %2 %1 with FREG yields %1 %1 - + pat exg $1==INT32 /* Exchange top two words on stack */ with REG REG yields %1 %2 - + pat stl lol $1==$2 /* Store then load local */ leaving dup 4 @@ -910,13 +910,13 @@ PATTERNS dup INT32 lal $1 sti $2 - + pat ste loe $1==$2 /* Store then load external */ leaving dup 4 ste $1 - - + + /* Type conversions */ pat loc loc cii loc loc cii $1==$4 && $2==$5 /* madness, generated by the C compiler */ @@ -924,19 +924,19 @@ PATTERNS loc $1 loc $2 cii - + pat loc loc cii loc loc cii $2==INT32 && $5==INT32 && $4<$2 /* madness, generated by the C compiler */ leaving loc $4 loc $5 cii - + pat loc loc ciu /* signed X -> unsigned X */ leaving loc $1 loc $2 cuu - + pat loc loc cuu $1==$2 /* unsigned X -> unsigned X */ /* nop */ @@ -945,25 +945,25 @@ PATTERNS pat loc loc cui $1==$2 /* unsigned X -> signed X */ /* nop */ - + pat loc loc cui $1==INT8 && $2==INT32 /* unsigned char -> signed int */ /* nop */ - + pat loc loc cui $1==INT16 && $2==INT32 /* unsigned short -> signed int */ /* nop */ - + pat loc loc cii $1==INT8 && $2==INT32 /* signed char -> signed int */ with GPR yields {SEX_B, %1} - + pat loc loc cii $1==2 && $2==4 /* signed char -> signed short */ with GPR yields {SEX_H, %1} - - - - + + + + /* Local variables */ pat lal smalls($1) /* Load address of local */ @@ -975,7 +975,7 @@ PATTERNS pat lol inreg($1)>0 /* Load from local */ yields {LOCAL, $1} - + pat lol /* Load from local */ leaving lal $1 @@ -985,34 +985,34 @@ PATTERNS leaving lal $1 loi INT32*2 - + pat stl inreg($1)>0 /* Store to local */ with CONST_ALL + LABEL + GPR + OP_ALL_W kills regvar($1), LOCAL %off==$1 gen move %1, {GPRE, regvar($1)} - + pat stl /* Store to local */ leaving lal $1 sti INT32 - + pat sdl /* Store double-word to local */ leaving lal $1 sti INT32*2 - + pat lil inreg($1)>0 /* Load from indirected local */ uses REG gen lwz %a, {GPRINDIRECT, regvar($1), 0} yields %a - + pat lil /* Load from indirected local */ leaving lol $1 loi INT32 - + pat sil /* Save to indirected local */ leaving lol $1 @@ -1022,14 +1022,14 @@ PATTERNS leaving loc 0 stl $1 - + pat inl /* Increment local */ leaving lol $1 loc 1 adi 4 stl $1 - + pat del /* Decrement local */ leaving lol $1 @@ -1039,14 +1039,14 @@ PATTERNS /* Global variables */ - + pat lpi /* Load address of external function */ leaving lae $1 - + pat lae /* Load address of external */ yields {LABEL, $1} - + pat loe /* Load word external */ leaving lae $1 @@ -1056,36 +1056,36 @@ PATTERNS leaving lae $1 sti INT32 - + pat lde /* Load double-word external */ leaving lae $1 loi INT64 - + pat sde /* Store double-word external */ leaving lae $1 sti INT64 - + pat zre /* Zero external */ leaving loc 0 ste $1 - + pat ine /* Increment external */ uses REG={LABEL, $1}, REG gen lwz %b, {GPRINDIRECT, %a, 0} addi %b, %b, {CONST, 1} stw %b, {GPRINDIRECT, %a, 0} - + pat dee /* Decrement external */ uses REG={LABEL, $1}, REG gen lwz %b, {GPRINDIRECT, %a, 0} addi %b, %b, {CONST, 0-1} stw %b, {GPRINDIRECT, %a, 0} - + /* Structures */ @@ -1094,22 +1094,22 @@ PATTERNS leaving adp $1 loi INT32 - + pat ldf /* Load double-word offsetted */ leaving adp $1 loi INT64 - + pat stf /* Store word offsetted */ leaving adp $1 sti INT32 - + pat sdf /* Store double-word offsetted */ leaving adp $1 sti INT64 - + /* Loads and stores */ @@ -1159,7 +1159,7 @@ PATTERNS leaving loc $1 los INT32 - + pat los /* Load arbitrary size */ with GPR3 GPR4 STACK kills ALL @@ -1288,17 +1288,17 @@ PATTERNS kills ALL gen bl {LABEL, ".sts"} - + /* Arithmetic wrappers */ pat ads $1==4 /* Add var to pointer */ leaving adi $1 - + pat sbs $1==4 /* Subtract var from pointer */ leaving sbi $1 - + pat adp /* Add constant to pointer */ leaving loc $1 @@ -1307,41 +1307,41 @@ PATTERNS pat adu /* Add unsigned */ leaving adi $1 - + pat sbu /* Subtract unsigned */ leaving sbi $1 - + pat inc /* Add 1 */ leaving loc 1 adi 4 - + pat dec /* Subtract 1 */ leaving loc 1 sbi 4 - + pat loc mlu $2==2 /* Unsigned multiply by constant */ leaving loc $1 mli 4 - + pat mlu /* Unsigned multiply by var */ leaving mli $1 - + pat loc slu /* Shift left unsigned by constant amount */ leaving loc $1 sli $2 - + pat slu /* Shift left unsigned by variable amount */ leaving sli $1 - - + + /* Word arithmetic */ pat adi $1==4 /* Add word (second + top) */ @@ -1389,21 +1389,21 @@ PATTERNS gen neg %a, %1 yields %a - + pat mli $1==4 /* Multiply word (second * top) */ with REG REG uses reusing %2, REG gen mullw %a, %2, %1 yields %a - + pat dvi $1==4 /* Divide word (second / top) */ with REG REG uses reusing %2, REG gen divw %a, %2, %1 yields %a - + pat dvu $1==4 /* Divide unsigned word (second / top) */ with REG REG uses reusing %2, REG @@ -1419,7 +1419,7 @@ PATTERNS mullw %a, %a, %1 subf %a, %a, %2 yields %a - + pat rmu $1==4 /* Remainder unsigned word (second % top) */ with REG REG uses REG @@ -1527,7 +1527,7 @@ PATTERNS with STACK gen bl {LABEL, ".xor"} - + pat com $1==INT32 /* NOT word */ with AND_RR uses REG @@ -1546,12 +1546,12 @@ PATTERNS yields %a with GPR yields {NOT_R, %1} - + pat com !defined($1) /* NOT set */ with STACK gen bl {LABEL, ".com"} - + pat sli $1==4 /* Shift left (second << top) */ with CONST_ALL GPR uses reusing %2, REG @@ -1563,7 +1563,7 @@ PATTERNS gen slw %a, %2, %1 yields %a - + pat sri $1==4 /* Shift right signed (second >> top) */ with CONST_ALL GPR uses reusing %2, REG @@ -1587,7 +1587,7 @@ PATTERNS gen srw %a, %2, %1 yields %a - + /* Arrays */ @@ -1597,19 +1597,19 @@ PATTERNS gen bl {LABEL, ".aar4"} yields R3 - + pat lae lar $2==INT32 && nicesize(rom($1, 3)) /* Load array */ leaving lae $1 aar INT32 loi rom($1, 3) - + pat lar $1==INT32 /* Load array */ with GPR3 GPR4 GPR5 STACK kills ALL gen bl {LABEL, ".lar4"} - + pat lae sar $2==INT32 && nicesize(rom($1, 3)) /* Store array */ leaving lae $1 @@ -1621,10 +1621,10 @@ PATTERNS kills ALL gen bl {LABEL, ".sar4"} - - + + /* Sets */ pat set defined($1) /* Create word with set bit */ @@ -1632,12 +1632,12 @@ PATTERNS loc 1 exg INT32 sli INT32 - + pat set !defined($1) /* Create structure with set bit (variable) */ with GPR3 GPR4 STACK gen bl {LABEL, ".set"} - + pat inn /* Test for set bit */ with STACK kills ALL @@ -1646,9 +1646,9 @@ PATTERNS li32 %a, {CONST, $1} stwu %a, {GPRINDIRECT, SP, 0-4} bl {LABEL, ".inn"} - - - + + + /* Boolean resolutions */ pat teq /* top = (top == 0) */ @@ -1660,7 +1660,7 @@ PATTERNS move {LABEL, ".teq_table"}, %a lwzx %a, %a, RSCRATCH yields %a - + pat tne /* top = (top != 0) */ with TRISTATE_ALL + GPR uses reusing %1, REG @@ -1670,7 +1670,7 @@ PATTERNS move {LABEL, ".tne_table"}, %a lwzx %a, %a, RSCRATCH yields %a - + pat tlt /* top = (top < 0) */ with TRISTATE_ALL + GPR uses reusing %1, REG @@ -1680,7 +1680,7 @@ PATTERNS move {LABEL, ".tlt_table"}, %a lwzx %a, %a, RSCRATCH yields %a - + pat tle /* top = (top <= 0) */ with TRISTATE_ALL + GPR uses reusing %1, REG @@ -1690,7 +1690,7 @@ PATTERNS move {LABEL, ".tle_table"}, %a lwzx %a, %a, RSCRATCH yields %a - + pat tgt /* top = (top > 0) */ with TRISTATE_ALL + GPR uses reusing %1, REG @@ -1710,7 +1710,7 @@ PATTERNS move {LABEL, ".tge_table"}, %a lwzx %a, %a, RSCRATCH yields %a - + @@ -1726,7 +1726,7 @@ PATTERNS leaving cmi INT32 zeq $1 - + pat zne /* Branch if signed top != 0 */ with TRISTATE_ALL+GPR STACK gen @@ -1737,7 +1737,7 @@ PATTERNS leaving cmi INT32 zne $1 - + pat zgt /* Branch if signed top > 0 */ with TRISTATE_ALL+GPR STACK gen @@ -1748,7 +1748,7 @@ PATTERNS leaving cmi INT32 zgt $1 - + pat zge /* Branch if signed top >= 0 */ with TRISTATE_ALL+GPR STACK gen @@ -1759,7 +1759,7 @@ PATTERNS leaving cmi INT32 zge $1 - + pat zlt /* Branch if signed top < 0 */ with TRISTATE_ALL+GPR STACK gen @@ -1770,7 +1770,7 @@ PATTERNS leaving cmi INT32 zlt $1 - + pat zle /* Branch if signed top >= 0 */ with TRISTATE_ALL+GPR STACK gen @@ -1781,7 +1781,7 @@ PATTERNS leaving cmi INT32 zle $1 - + /* Compare and jump */ @@ -1790,23 +1790,23 @@ PATTERNS yields {TRISTATE_RC_S, %2, %1.val} with GPR GPR yields {TRISTATE_RR_S, %2, %1} - + pat cmu /* Unsigned tristate compare */ with CONST_ALL GPR yields {TRISTATE_RC_U, %2, %1.val} with GPR GPR yields {TRISTATE_RR_U, %2, %1} - + pat cmp /* Compare pointers */ leaving cmu INT32 - + pat cms $1==INT32 /* Compare blocks (word sized) */ leaving cmi INT32 - - - + + + /* Other branching and labelling */ @@ -1814,31 +1814,31 @@ PATTERNS gen labeldef $1 yields R3 - + pat lab topeltsize($1)==4 && fallthrough($1) with GPR3 gen labeldef $1 yields %1 - + pat lab topeltsize($1)!=4 with STACK kills ALL gen labeldef $1 - + pat bra topeltsize($1)==4 /* Unconditional jump with TOS GPRister */ with GPR3 STACK gen b {LABEL, $1} - + pat bra topeltsize($1)!=4 /* Unconditional jump without TOS GPRister */ with STACK gen b {LABEL, $1} - - - + + + /* Miscellaneous */ pat cal /* Call procedure */ @@ -1853,18 +1853,18 @@ PATTERNS gen mtspr CTR, %1 bcctrl ALWAYS, {CONST, 0}, {CONST, 0} - + pat lfr $1==INT32 /* Load function result, word */ yields R3 - + pat lfr $1==INT64 /* Load function result, double-word */ yields R4 R3 - + pat ret $1==0 /* Return from procedure */ gen return b {LABEL, ".ret"} - + pat ret $1==INT32 /* Return from procedure, word */ with GPR3 gen @@ -1887,7 +1887,7 @@ PATTERNS stwu %1, {GPRINDIRECT, SP, 0-4} bl {LABEL, "_memmove"} addi SP, SP, {CONST, 12} - + pat bls /* Block move variable length */ with GPR GPR GPR STACK gen @@ -1896,18 +1896,18 @@ PATTERNS stwu %2, {GPRINDIRECT, SP, 0-4} bl {LABEL, "_memmove"} addi SP, SP, {CONST, 12} - + pat csa /* Array-lookup switch */ with STACK gen b {LABEL, ".csa"} - + pat csb /* Table-lookup switch */ with STACK gen b {LABEL, ".csb"} - + /* EM specials */ @@ -1915,7 +1915,7 @@ PATTERNS leaving lae $1 ste "hol0+4" - + pat lin /* Set current line number */ leaving loc $1 @@ -1924,37 +1924,37 @@ PATTERNS pat lni /* Increment line number */ leaving ine "hol0" - + pat lim /* Load EM trap ignore mask */ leaving lde ".ignmask" - + pat sim /* Store EM trap ignore mask */ leaving ste ".ignmask" - + pat trp /* Raise EM trap */ with GPR3 gen bl {LABEL, ".trap"} - + pat sig /* Set trap handler */ leaving ste ".trppc" - + pat rtt /* Return from trap */ leaving ret 0 - + pat lxl $1==0 /* Load FP */ leaving lor 0 - + pat lxl $1==1 /* Load caller's FP */ leaving lxl 0 dch - + pat dch /* FP -> caller FP */ with GPR uses reusing %1, REG @@ -1965,12 +1965,12 @@ PATTERNS pat lpb /* Convert FP to argument address */ leaving adp EM_BSIZE - + pat lxa /* Load caller's SP */ leaving lxl $1 lpb - + pat gto /* longjmp */ uses REG gen @@ -1986,27 +1986,27 @@ PATTERNS gen move FP, %a yields %a - + pat lor $1==1 /* Load SP */ uses REG gen move SP, %a yields %a - + pat lor $1==2 /* Load HP */ leaving loe ".reghp" - + pat str $1==0 /* Store FP */ with GPR gen move %1, FP - + pat str $1==1 /* Store SP */ with GPR gen move %1, SP - + pat str $1==2 /* Store HP */ leaving ste ".reghp" @@ -2032,39 +2032,39 @@ PATTERNS with GPR STACK gen move {SUM_RR, SP, %1}, SP - + pat asp /* Adjust stack by constant amount */ leaving loc $1 ass - - - + + + /* Floating point support */ /* All very cheap and nasty --- this needs to be properly integrated into * the code generator. ncg doesn't like having separate FPU registers. */ /* Single-precision */ - + pat zrf $1==INT32 /* Push zero */ leaving loe ".fs_00000000" - + pat adf $1==INT32 /* Add single */ with FSREG FSREG uses reusing %1, FSREG gen fadds %a, %2, %1 yields %a - + pat sbf $1==INT32 /* Subtract single */ with FSREG FSREG uses reusing %1, FSREG gen fsubs %a, %2, %1 yields %a - + pat mlf $1==INT32 /* Multiply single */ with FSREG FSREG uses reusing %1, FSREG @@ -2089,56 +2089,56 @@ PATTERNS pat cmf $1==INT32 /* Compare single */ with FSREG FSREG yields {TRISTATE_FF, %2.1, %1.1} - + pat loc loc cff $1==INT32 && $2==INT64 /* Convert single to double */ with FSREG yields %1.1 - + pat loc loc cfu $1==INT32 && $2==INT32 /* Convert single to unsigned int */ with STACK gen bl {LABEL, ".cfu4"} - + pat loc loc cfi $1==INT32 && $2==INT32 /* Convert single to signed int */ with STACK gen bl {LABEL, ".cfi4"} - + pat loc loc cif $1==INT32 && $2==INT32 /* Convert integer to single */ with STACK gen bl {LABEL, ".cif4"} - + pat loc loc cuf $1==INT32 && $2==INT32 /* Convert unsigned int to single */ with STACK gen bl {LABEL, ".cuf4"} - + pat fef $1==INT32 /* Split single */ with STACK gen bl {LABEL, ".fef4"} - + /* Double-precision */ - + pat zrf $1==INT64 /* Push zero */ leaving lde ".fd_00000000" - + pat adf $1==INT64 /* Add double */ with FREG FREG uses FREG gen fadd %a, %2, %1 yields %a - + pat sbf $1==INT64 /* Subtract double */ with FREG FREG uses FREG gen fsub %a, %2, %1 yields %a - + pat mlf $1==INT64 /* Multiply double */ with FREG FREG uses reusing %1, FREG @@ -2163,30 +2163,30 @@ PATTERNS pat cmf $1==INT64 /* Compare double */ with FREG FREG yields {TRISTATE_FF, %2, %1} - + pat loc loc cff $1==INT64 && $2==INT32 /* Convert double to single */ with FREG uses reusing %1, FSREG gen frsp %a, %1 yields %a - + pat loc loc cfu $1==INT64 && $2==INT32 /* Convert double to unsigned int */ with STACK gen bl {LABEL, ".cfu8"} - + pat loc loc cfi $1==INT64 && $2==INT32 /* Convert double to signed int */ with STACK gen bl {LABEL, ".cfi8"} - + pat loc loc cif $1==INT32 && $2==INT64 /* Convert integer to double */ with STACK kills ALL gen bl {LABEL, ".cif8"} - + pat loc loc cuf $1==INT32 && $2==INT64 /* Convert unsigned int to double */ with STACK gen From 805883e3772410f1b57cb9d73bfffd42b5adfedf Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 16:58:47 -0500 Subject: [PATCH 30/40] Fill in a hint for enabling the COMMENT macro. If you want to enable comments in the .s file, change #define COMMENT(n) /* comment {LABEL, n} */ to #define COMMENT(n) comment {LABEL, n} --- mach/powerpc/ncg/table | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 1d2c5516e..1f2232c3b 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -10,7 +10,7 @@ INT64 = 8 FP_OFFSET = 0 /* Offset of saved FP relative to our FP */ PC_OFFSET = 4 /* Offset of saved PC relative to our FP */ -#define COMMENT(n) /* noop */ +#define COMMENT(n) /* comment {LABEL, n} */ #define nicesize(x) ((x)==INT8 || (x)==INT16 || (x)==INT32 || (x)==INT64) From 5bd0ad42692cab2932e0496849a95bf080512651 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 17:00:56 -0500 Subject: [PATCH 31/40] Remove the bogus rules for 'lor 2' and 'str 2'. These instructions would load or store the EM heap pointer. They don't work. Programs must use brk() or sbrk() in libsys. The last file to use 'lor 2' and 'str 2' was lang/pc/libpc/sav.e in the Pascal library. Commit c084f9f deleted the file, so we no longer need rules 'lor 2' or 'str 2' to build the ACK. --- mach/powerpc/ncg/table | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 1f2232c3b..9d12698e5 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -1993,10 +1993,6 @@ PATTERNS move SP, %a yields %a - pat lor $1==2 /* Load HP */ - leaving - loe ".reghp" - pat str $1==0 /* Store FP */ with GPR gen @@ -2007,10 +2003,6 @@ PATTERNS gen move %1, SP - pat str $1==2 /* Store HP */ - leaving - ste ".reghp" - pat loc ass $1==4 /* Drop 4 bytes from stack */ with exact GPR /* nop */ From 17211eef475fcf91cda493c968c0565798f413a4 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 17:32:42 -0500 Subject: [PATCH 32/40] Fix ass to match the EM spec. The spec says, "ASS w: Adjust the stack pointer by w-byte integer". The w argument "can either be given as argument or on top of the stack." Therefore, 'ass 4' would pop the 4-byte integer from the stack, but 'ass' would pop the size w from the stack, then pop the w-byte integer. PowerPC ncg wrongly implemented 'ass' as if it was 'ass 4'. Fix it to accept only 'ass 4'. --- mach/powerpc/ncg/table | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 9d12698e5..cf3de92fd 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -2003,14 +2003,14 @@ PATTERNS gen move %1, SP - pat loc ass $1==4 /* Drop 4 bytes from stack */ + pat loc ass $1==4 && $2==4 /* Drop 4 bytes from stack */ with exact GPR /* nop */ with STACK gen addi SP, SP, {CONST, 4} - pat ass /* Adjust stack by variable amount */ + pat ass $1==4 /* Adjust stack by variable amount */ with CONST2 STACK gen move {SUM_RC, SP, %1.val}, SP @@ -2028,7 +2028,7 @@ PATTERNS pat asp /* Adjust stack by constant amount */ leaving loc $1 - ass + ass 4 From 436114fce4fd0ba6b27adae2c583ae2f259fcfe2 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 18:40:14 -0500 Subject: [PATCH 33/40] Add a move from CONST smalls(%val) to GPR. This allows 'move {CONST, $1}, R3' with a small enough $1 to emit one instruction (addi) instead of two instructions (addis, ori). The CONST token confusingly isn't in the CONST_ALL set. --- mach/powerpc/ncg/table | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index cf3de92fd..d8b8082c7 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -389,7 +389,7 @@ MOVES /* Constants */ - from CONST_ALL smalls(%val) to GPR + from CONST_ALL + CONST smalls(%val) to GPR gen COMMENT("move CONST_ALL->GPR smalls") addi %2, R0, {CONST, %1.val} From fcda786fe98b7d944622043de36ff8f702626543 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Fri, 9 Dec 2016 19:49:50 -0500 Subject: [PATCH 34/40] Add some missing clauses to los, sts, aar, inn, cmi, cmu. We only implement 'los 4', 'sts 4', 'cmi 4', 'cmu 4', not for sizes other than 4. Add clause $1==4. We only implement inn when defined($1). The rule for aar needs 'kills ALL' because it kills many registers, like other rules that call libem. --- mach/powerpc/ncg/table | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index d8b8082c7..a6859ca14 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -1160,7 +1160,7 @@ PATTERNS loc $1 los INT32 - pat los /* Load arbitrary size */ + pat los $1==INT32 /* Load arbitrary size */ with GPR3 GPR4 STACK kills ALL gen @@ -1283,7 +1283,7 @@ PATTERNS loc $1 sts INT32 - pat sts /* Store arbitrary size */ + pat sts $1==INT32 /* Store arbitrary size */ with GPR3 GPR4 STACK kills ALL gen @@ -1594,6 +1594,7 @@ PATTERNS pat aar $1==INT32 /* Index array */ with GPR3 GPR4 GPR5 + kills ALL gen bl {LABEL, ".aar4"} yields R3 @@ -1638,7 +1639,7 @@ PATTERNS gen bl {LABEL, ".set"} - pat inn /* Test for set bit */ + pat inn defined($1) /* Test for set bit */ with STACK kills ALL uses REG @@ -1785,13 +1786,13 @@ PATTERNS /* Compare and jump */ - pat cmi /* Signed tristate compare */ + pat cmi $1==INT32 /* Signed tristate compare */ with CONST_ALL GPR yields {TRISTATE_RC_S, %2, %1.val} with GPR GPR yields {TRISTATE_RR_S, %2, %1} - pat cmu /* Unsigned tristate compare */ + pat cmu $1==INT32 /* Unsigned tristate compare */ with CONST_ALL GPR yields {TRISTATE_RC_U, %2, %1.val} with GPR GPR From 8605a2fcfc0439aeb92f75a66664a9fa885e5000 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 10 Dec 2016 12:23:07 -0500 Subject: [PATCH 35/40] Add Modula-2 set operations to PowerPC ncg. This provides and, ior, xor, com, zer, set, cms when defined($1) and ior, set when !defined($1). I don't provide the other operations !defined($1) because our Modula-2 compiler hasn't used them. I wrote a Modula-2 example in https://gist.github.com/kernigh/add79662bb3c63ffb7c46d01dc8ae788 Put a dummy comment in mach/powerpc/libem/build.lua so git checkout will touch that file. Without the touch, the build system doesn't see the new *.s files. --- mach/powerpc/libem/and.s | 24 +++++++++++++++ mach/powerpc/libem/build.lua | 2 +- mach/powerpc/libem/cms.s | 32 ++++++++++++++++++++ mach/powerpc/libem/com.s | 20 +++++++++++++ mach/powerpc/libem/ior.s | 24 +++++++++++++++ mach/powerpc/libem/set.s | 29 ++++++++++++++++++ mach/powerpc/libem/xor.s | 24 +++++++++++++++ mach/powerpc/libem/zer.s | 21 +++++++++++++ mach/powerpc/ncg/table | 57 ++++++++++++++++++++++++++++-------- 9 files changed, 220 insertions(+), 13 deletions(-) create mode 100644 mach/powerpc/libem/and.s create mode 100644 mach/powerpc/libem/cms.s create mode 100644 mach/powerpc/libem/com.s create mode 100644 mach/powerpc/libem/ior.s create mode 100644 mach/powerpc/libem/set.s create mode 100644 mach/powerpc/libem/xor.s create mode 100644 mach/powerpc/libem/zer.s diff --git a/mach/powerpc/libem/and.s b/mach/powerpc/libem/and.s new file mode 100644 index 000000000..4a1a81c04 --- /dev/null +++ b/mach/powerpc/libem/and.s @@ -0,0 +1,24 @@ +#include "powerpc.h" + +.sect .text + +! Set intersection. +! Stack: ( b a -- a*b ) +! With r3 = size of set + +.define .and +.and: + mr r4, sp ! r4 = ptr to set a + add r5, sp, r3 ! r5 = ptr to set b + rlwinm r6, r3, 30, 2, 31 + mtspr ctr, r6 ! ctr = r3 / 4 +1: + lwz r7, 0(r4) + lwz r8, 0(r5) + and r8, r7, r8 ! intersection of words + stw r8, 0(r5) + addi r4, r4, 4 + addi r5, r5, 4 + bc DNZ, 0, 1b ! loop ctr times + add sp, sp, r3 + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/build.lua b/mach/powerpc/libem/build.lua index 318be381d..786be4e11 100644 --- a/mach/powerpc/libem/build.lua +++ b/mach/powerpc/libem/build.lua @@ -7,7 +7,7 @@ for _, plat in ipairs(vars.plats) do acklibrary { name = "lib_"..plat, srcs = { - "./*.s", + "./*.s", -- zer.s "./*.e", }, vars = { plat = plat }, diff --git a/mach/powerpc/libem/cms.s b/mach/powerpc/libem/cms.s new file mode 100644 index 000000000..53cb65691 --- /dev/null +++ b/mach/powerpc/libem/cms.s @@ -0,0 +1,32 @@ +#include "powerpc.h" + +.sect .text + +! Compare sets a, b. +! Stack: ( b a -- ) +! With r3 = size of each set +! Yields r3 = 0 if equal, nonzero if not equal + +.define .cms +.cms: + mr r4, sp ! r4 = ptr to set a + add r5, sp, r3 ! r5 = ptr to set b + mr r6, r3 ! r6 = size + rlwinm r3, r3, 30, 2, 31 + mtspr ctr, r3 ! ctr = size / 4 +1: + lwz r7, 0(r4) + lwz r8, 0(r5) + cmp cr0, 0, r7, r8 ! compare words in sets + addi r4, r4, 4 + addi r5, r5, 4 + bc IFFALSE, EQ, 2f ! branch if not equal + bc DNZ, 0, 1b ! loop ctr times + addi r3, r0, 0 ! equal: return 0 + b 3f +2: + addi r3, r0, 1 ! not equal: return 1 +3: + rlwinm r6, r6, 1, 0, 30 ! r6 = size * 2 + add sp, sp, r6 ! remove sets from stack + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/com.s b/mach/powerpc/libem/com.s new file mode 100644 index 000000000..8b7082332 --- /dev/null +++ b/mach/powerpc/libem/com.s @@ -0,0 +1,20 @@ +#include "powerpc.h" + +.sect .text + +! Set complement. +! Stack: ( a -- ~a ) +! With r3 = size of set + +.define .com +.com: + mr r4, sp ! r4 = pointer to set a + rlwinm r5, r3, 30, 2, 31 + mtspr ctr, r5 ! ctr = r3 / 4 +1: + lwz r6, 0(r4) + nor r6, r6, r6 ! complement of word + stw r6, 0(r4) + addi r4, r4, 4 + bc DNZ, 0, 1b ! loop ctr times + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/ior.s b/mach/powerpc/libem/ior.s new file mode 100644 index 000000000..61e099934 --- /dev/null +++ b/mach/powerpc/libem/ior.s @@ -0,0 +1,24 @@ +#include "powerpc.h" + +.sect .text + +! Set union. +! Stack: ( b a -- a+b ) +! With r3 = size of set + +.define .ior +.ior: + mr r4, sp ! r4 = ptr to set a + add r5, sp, r3 ! r5 = ptr to set b + rlwinm r6, r3, 30, 2, 31 + mtspr ctr, r6 ! ctr = r3 / 4 +1: + lwz r7, 0(r4) + lwz r8, 0(r5) + or r8, r7, r8 ! union of words + stw r8, 0(r5) + addi r4, r4, 4 + addi r5, r5, 4 + bc DNZ, 0, 1b ! loop ctr times + add sp, sp, r3 + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/set.s b/mach/powerpc/libem/set.s new file mode 100644 index 000000000..18ad877e8 --- /dev/null +++ b/mach/powerpc/libem/set.s @@ -0,0 +1,29 @@ +#include "powerpc.h" + +.sect .text + +! Create singleton set. +! Stack: ( -- set ) +! With r3 = size of set, r4 = bit number + +.define .set +.set: + rlwinm r7, r3, 30, 2, 31 + neg r5, r3 + add sp, sp, r5 ! allocate set + mr r6, sp ! r6 = ptr to set + mtspr ctr, r7 ! ctr = r3 / 4 +1: + rlwinm. r7, r4, 0, 0, 26 ! r7 = r4 & ~31 + bc IFTRUE, EQ, 2f ! branch if r4 in 0..31 + addi r5, r0, 0 ! no bit, word is zero + b 3f +2: + addi r5, r0, 1 + slw r5, r5, r4 ! yes bit, set bit in word +3: + stw r5, 0(r6) ! store word in set + addi r4, r4, -32 + addi r6, r6, 4 + bc DNZ, 0, 1b ! loop ctr times + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/xor.s b/mach/powerpc/libem/xor.s new file mode 100644 index 000000000..9d4bc76b9 --- /dev/null +++ b/mach/powerpc/libem/xor.s @@ -0,0 +1,24 @@ +#include "powerpc.h" + +.sect .text + +! Set symmetric difference. +! Stack: ( b a -- a/b ) +! With r3 = size of set + +.define .xor +.xor: + mr r4, sp ! r4 = ptr to set a + add r5, sp, r3 ! r5 = ptr to set b + rlwinm r6, r3, 30, 2, 31 + mtspr ctr, r6 ! ctr = r3 / 4 +1: + lwz r7, 0(r4) + lwz r8, 0(r5) + xor r8, r7, r8 ! symmetric difference of words + stw r8, 0(r5) + addi r4, r4, 4 + addi r5, r5, 4 + bc DNZ, 0, 1b ! loop ctr times + add sp, sp, r3 + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/libem/zer.s b/mach/powerpc/libem/zer.s new file mode 100644 index 000000000..ba978ba3e --- /dev/null +++ b/mach/powerpc/libem/zer.s @@ -0,0 +1,21 @@ +#include "powerpc.h" + +.sect .text + +! Create empty set. +! Stack: ( -- set ) +! With r3 = size of set + +.define .zer +.zer: + rlwinm r7, r3, 30, 2, 31 + addi r4, r0, 0 ! r4 = zero + neg r5, r3 + add sp, sp, r5 ! allocate set + mr r6, sp ! r6 = ptr to set + mtspr ctr, r7 ! ctr = r3 / 4 +1: + stw r4, 0(r6) ! store zero in set + addi r6, r6, 4 + bc DNZ, 0, 1b ! loop ctr times + bclr ALWAYS, 0, 0 diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index a6859ca14..adb0db2c8 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -1463,9 +1463,11 @@ PATTERNS andisX %a, %2, {CONST, hi(%1.val)} yields %a - pat and !defined($1) /* AND set */ + pat and defined($1) /* AND set */ with STACK + kills ALL gen + move {CONST, $1}, R3 bl {LABEL, ".and"} pat ior $1==4 /* OR word */ @@ -1498,8 +1500,17 @@ PATTERNS uses reusing %2, REG={OR_RIS, %2, hi(%1.val)} yields {OR_RC, %2, lo(%1.val)} - pat ior !defined($1) /* OR set */ + pat ior defined($1) /* OR set */ with STACK + kills ALL + gen + move {CONST, $1}, R3 + bl {LABEL, ".ior"} + + /* OR set (variable), used in lang/m2/libm2/LtoUset.e */ + pat ior !defined($1) + with GPR3 STACK + kills ALL gen bl {LABEL, ".ior"} @@ -1523,9 +1534,11 @@ PATTERNS uses reusing %2, REG={XOR_RIS, %2, hi(%1.val)} yields {XOR_RC, %2, lo(%1.val)} - pat xor !defined($1) /* XOR set */ + pat xor defined($1) /* XOR set */ with STACK + kills ALL gen + move {CONST, $1}, R3 bl {LABEL, ".xor"} pat com $1==INT32 /* NOT word */ @@ -1547,11 +1560,23 @@ PATTERNS with GPR yields {NOT_R, %1} - pat com !defined($1) /* NOT set */ + pat com defined($1) /* NOT set */ with STACK gen + move {CONST, $1}, R3 bl {LABEL, ".com"} + pat zer $1==4 /* Push zero */ + leaving + loc 0 + + pat zer defined($1) /* Create empty set */ + with STACK + kills ALL + gen + move {CONST, $1}, R3 + bl {LABEL, ".zer"} + pat sli $1==4 /* Shift left (second << top) */ with CONST_ALL GPR uses reusing %2, REG @@ -1625,17 +1650,19 @@ PATTERNS - /* Sets */ - pat set defined($1) /* Create word with set bit */ - leaving - loc 1 - exg INT32 - sli INT32 + pat set defined($1) /* Create singleton set */ + with GPR4 STACK + kills ALL + gen + move {CONST, $1}, R3 + bl {LABEL, ".set"} - pat set !defined($1) /* Create structure with set bit (variable) */ + /* Create set (variable), used in lang/m2/libm2/LtoUset.e */ + pat set !defined($1) with GPR3 GPR4 STACK + kills ALL gen bl {LABEL, ".set"} @@ -1649,7 +1676,6 @@ PATTERNS bl {LABEL, ".inn"} - /* Boolean resolutions */ pat teq /* top = (top == 0) */ @@ -1806,6 +1832,13 @@ PATTERNS leaving cmi INT32 + pat cms defined($1) + with STACK + kills ALL + gen + move {CONST, $1}, R3 + bl {LABEL, ".cms"} + yields R3 From 62edb906418a3121604d988a68c4b954d4a2f01b Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 11 Dec 2016 23:06:37 +0100 Subject: [PATCH 36/40] Convert the inn test to work with the test library and not import InOut; it now runs on qemuppc again. Reenable qemuppc tests. --- build.lua | 2 +- tests/plat/bugs/bug-22-inn_mod.mod | 14 +++++--------- tests/plat/build.lua | 5 ++++- tests/plat/lib/Test.def | 6 ++++++ tests/plat/lib/build.lua | 7 ------- 5 files changed, 16 insertions(+), 18 deletions(-) create mode 100644 tests/plat/lib/Test.def delete mode 100644 tests/plat/lib/build.lua diff --git a/build.lua b/build.lua index 91415d689..6364e5f75 100644 --- a/build.lua +++ b/build.lua @@ -18,7 +18,7 @@ vars.plats = { vars.plats_with_tests = { "linux386", "linuxppc", - -- "qemuppc", FIXME: disable until we figure out why qemu won't run binaries bigger than 4kB + "qemuppc", "pc86", } diff --git a/tests/plat/bugs/bug-22-inn_mod.mod b/tests/plat/bugs/bug-22-inn_mod.mod index 8f3a2d00a..53fe93568 100644 --- a/tests/plat/bugs/bug-22-inn_mod.mod +++ b/tests/plat/bugs/bug-22-inn_mod.mod @@ -1,5 +1,5 @@ MODULE test; -FROM InOut IMPORT WriteLn, WriteString; +FROM Test IMPORT fail, finished; TYPE charset = SET OF CHAR; @@ -10,17 +10,13 @@ END Space; BEGIN IF Space('a') THEN - WriteString("@@FAIL 1"); - WriteLn; + fail(1); END; IF NOT Space(' ') THEN - WriteString("@@FAIL 2"); - WriteLn; + fail(2); END; IF NOT Space(12C) THEN - WriteString("@@FAIL 3"); - WriteLn; + fail(3); END; - WriteString("@@FINISHED"); - WriteLn; + finished; END test. \ No newline at end of file diff --git a/tests/plat/build.lua b/tests/plat/build.lua index d8362b3a0..3f43fb95b 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -18,7 +18,10 @@ definerule("plat_testsuite", acklibrary { name = "lib", srcs = { "tests/plat/lib/test.c" }, - hdrs = { "tests/plat/lib/test.h" }, + hdrs = { + "tests/plat/lib/test.h", + "tests/plat/lib/Test.def" + }, vars = { plat = e.plat }, } diff --git a/tests/plat/lib/Test.def b/tests/plat/lib/Test.def new file mode 100644 index 000000000..cab31f2e8 --- /dev/null +++ b/tests/plat/lib/Test.def @@ -0,0 +1,6 @@ +(*$Foreign*) +DEFINITION MODULE Test; + PROCEDURE finished(); + PROCEDURE writehex(code: LONGINT); + PROCEDURE fail(code: LONGINT); +END Test. diff --git a/tests/plat/lib/build.lua b/tests/plat/lib/build.lua deleted file mode 100644 index be9928c84..000000000 --- a/tests/plat/lib/build.lua +++ /dev/null @@ -1,7 +0,0 @@ -include("plat/build.lua") - -acklibrary { - name = "lib", - srcs = { "./test.c" }, - hdrs = { "./test.h" }, -} From 2874806048fb0d2efb9a0e7383b4de30c3988c1c Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 13 Dec 2016 15:54:38 -0500 Subject: [PATCH 37/40] Tweak man syntax in aelflod.1 and aslod.1 Put end of sentence at end of line. This is roff(7) syntax so the formatter can make spacing between sentences. Use the macro .PP to break paragraphs. Use bold for the command name in SYNOPSIS, to match other ack manuals. --- util/amisc/aelflod.1 | 26 ++++++++++++++------------ util/amisc/aslod.1 | 10 +++++----- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1 index 24001ba2d..00cd62220 100644 --- a/util/amisc/aelflod.1 +++ b/util/amisc/aelflod.1 @@ -1,25 +1,27 @@ -.TH ASLOD 1 "$Revision$" +.TH AELFLOD 1 "$Revision$" .SH NAME aelflod \- ACK ELF loader .SH SYNOPSIS -aelflod [-h] [-v] inputfile outputfile +.B aelflod +[-h] [-v] inputfile outputfile .SH DESCRIPTION .I aelflod converts an absolute ack.out file into a simple binary memory -dump wrapped up in an ELF executable. It is suitable for producing -executables for operating systems such as Linux. - +dump wrapped up in an ELF executable. +It is suitable for producing executables for operating systems +such as Linux. +.PP The input file must contain exactly four segments: TEXT, ROM, DATA and BSS, in that order, all occupying contiguous memory. The file must have all references resolved and be linked to a -fixed address. The fixed address must be at least 0x54 bytes -greater than a page boundary, in order to make room for the ELF -header itself. - +fixed address. +The fixed address must be at least 0x54 bytes greater than a +page boundary, in order to make room for the ELF header itself. +.PP aelflod will write out an ELF header followed by each segment, in order, ensuring that enough padding is inserted between each segment -to keep the offsets correct. The created executable will contain just -one rwx segment, and no sections. - +to keep the offsets correct. +The created executable will contain just one rwx segment, and no +sections. .SH "SEE ALSO" ack.out(5) diff --git a/util/amisc/aslod.1 b/util/amisc/aslod.1 index a786b13e6..f81590739 100644 --- a/util/amisc/aslod.1 +++ b/util/amisc/aslod.1 @@ -2,19 +2,19 @@ .SH NAME aslod \- ACK simple loader .SH SYNOPSIS -aslod [-h] [-v] inputfile outputfile +.B aslod +[-h] [-v] inputfile outputfile .SH DESCRIPTION .I aslod -converts an absolute ack.out file into a simple binary memory -dump. It is suitable for producing RAM images, executables for +converts an absolute ack.out file into a simple binary memory dump. +It is suitable for producing RAM images, executables for simple operating systems such as CP/M, DOS, etc. - +.PP The input file must contain exactly four segments: TEXT, ROM, DATA and BSS, in that order, all occupying contiguous memory. The file must have all references resolved and be linked to a fixed address. aslod will dump the segments, in order, such that the first byte of TEXT is at offset 0 in the file (regardless of where it is in memory). - .SH "SEE ALSO" ack.out(5) From 8280ca8745af514236f3dd24b52f404bfe2bcf09 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 13 Dec 2016 16:02:38 -0500 Subject: [PATCH 38/40] In aslod, remove some unused m68k2 stuff. --- util/amisc/aslod.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/util/amisc/aslod.c b/util/amisc/aslod.c index afc8f8c3e..72fbc8ce4 100644 --- a/util/amisc/aslod.c +++ b/util/amisc/aslod.c @@ -45,12 +45,6 @@ FILE* output; /* Output stream */ #define readf(a, b, c) fread((a), (b), (int)(c), input) #define writef(a, b, c) fwrite((a), (b), (int)(c), output) -/* Output file definitions and such */ - -#define HDR_LENGTH 32 - -char hdr[HDR_LENGTH] ; - bool verbose = false; /* Segment numbers understood by aslod. */ @@ -63,14 +57,6 @@ enum { NUM_SEGMENTS }; -#define N_EXT 040 -#define N_UNDEF 00 -#define N_ABS 01 -#define N_TEXT 02 -#define N_DATA 03 -#define N_BSS 04 -#define N_FN 037 - /* Produce an error message and exit. */ void fatal(const char* s, ...) From 5cf2a684384c17880e63c478eff78d756b9041ca Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 13 Dec 2016 16:41:22 -0500 Subject: [PATCH 39/40] Teach aelflod to write the ELF symbol table. Convert each ack.out symbol to ELF, preserving its name and value, and some but not all other symbol info. The ELF symbol table comes with ELF section headers. If the input file has no symbols (ack -Rled-s), then the output file has no ELF section headers. Append the symbol table and section headers to the ELF file. Linux ignores this appended info when it execs the file. The info might pollute the last page of the ELF segment, but Linux clears this pollution. Tools like nm and gdb can read the ELF symbol table. I include code to translate debugger symbols to an ELF .stab section. I did not test this code, because I did not find a platform that can put S_STB symbols in the ack.out file. --- util/amisc/aelflod.c | 448 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 412 insertions(+), 36 deletions(-) diff --git a/util/amisc/aelflod.c b/util/amisc/aelflod.c index e3692ac01..d5a9c0df3 100644 --- a/util/amisc/aelflod.c +++ b/util/amisc/aelflod.c @@ -35,10 +35,14 @@ int elfabi = 3; /* abi = Linux */ int elfmachine = 3; /* machine = EM_386 */ /* Header and section table of an ack object file. */ - + struct outhead outhead; struct outsect outsect[S_MAX]; +struct outname* outname = NULL; char* stringarea; +uint32_t ack_off_char; +int nstab = 0; /* S_STB symbol count */ +int nsym = 0; /* other symbol count */ char* outputfile = NULL; /* Name of output file, or NULL */ char* program; /* Name of current program: argv[0] */ @@ -49,23 +53,30 @@ FILE* output; /* Output stream */ #define readf(a, b, c) fread((a), (b), (int)(c), input) #define writef(a, b, c) fwrite((a), (b), (int)(c), output) -/* Header and program header table of an ELF object file. */ +/* Contents of an ELF object file. */ #define ELF_HEADER_SIZE 0x34 #define PROGRAM_HEADER_SIZE 0x20 #define PROGRAM_HEADER_COUNT 1 -unsigned long codeoffset; +#define SECTION_HEADER_SIZE 0x28 +#define STAB_SYMBOL_SIZE 12 +#define ELF_SYMBOL_SIZE 16 + +uint32_t code_offset; /* ELF segment */ +uint32_t stab_offset; /* Debugger symbol table */ +uint32_t symtab_offset; /* ELF symbol table */ +uint32_t strtab_offset; /* String table */ +uint32_t shstrtab_offset; /* Section header string table */ +uint32_t sh_offset; /* ELF section headers */ + +int sh_count = 0; /* Number of ELF sections */ +int shstrtab_nr = 0; /* Section number of .shstrtab */ +int shstrtab_size; const char elf_le_ident_string[] = { 0x7F, 'E', 'L', 'F' }; -/* Output file definitions and such */ - -#define HDR_LENGTH 32 - -char hdr[HDR_LENGTH] ; - bool verbose = false; /* Segment numbers understood by aelflod. */ @@ -78,13 +89,33 @@ enum { NUM_SEGMENTS }; -#define N_EXT 040 -#define N_UNDEF 00 -#define N_ABS 01 -#define N_TEXT 02 -#define N_DATA 03 -#define N_BSS 04 -#define N_FN 037 +/* + * ELF section numbers count up in the order that we write the ELF + * section headers. If we have no debugger symbols, we will skip + * .stab and .stabstr, then subtract 2 from all later numbers. + */ +enum { + N_UNDEF = 0, + N_TEXT, + N_RODATA, + N_DATA, + N_BSS, + N_STAB, + N_STABSTR, + N_SYMTAB, + N_STRTAB, + N_SHSTRTAB, + NUM_ELF_SECTIONS, +}; +const char shstrtab[] = + "\0.text\0.rodata\0.data\0.bss\0.stab\0.stabstr\0" + ".symtab\0.strtab\0.shstrtab"; + /* Compiler appends one more "\0". */ +const int sh_name[] = { + /* Index of each name in shstrtab: */ + 0, 1, 7, 15, 21, 26, 32, + 41, 49, 57, +}; /* Produce an error message and exit. */ @@ -121,6 +152,80 @@ int follows(struct outsect* pa, struct outsect* pb) return (pa->os_base >= align(pb->os_base+pb->os_size, pa->os_lign)); } +/* Convert a symbol's name index from ack.out to ELF. */ + +uint32_t cvname(struct outname* n) +{ + if (n->on_foff) { + /* ack.out: offset from beginning of file + * ELF: index in string table + * the + 1 because we prepend a '\0' */ + return n->on_foff - ack_off_char + 1; + } else + return 0; /* no name */ +} + +/* Convert a symbol's type and binding from ack.out to ELF. */ + +int cvinfo(struct outname* n) +{ + int bind, type; + + switch (n->on_type & S_ETC) { + case S_SCT: + type = 3; /* STT_SECTION */ + break; + case S_FIL: + case S_MOD: + type = 4; /* STT_FILE */ + break; + default: + switch (n->on_type & S_TYP) { + case S_MIN + TEXT: + type = 2; /* STT_FUNC */ + break; + case S_MIN + ROM: + case S_MIN + DATA: + case S_MIN + BSS: + case S_MIN + NUM_SEGMENTS: + type = 1; /* STT_OBJECT */ + break; + default: + type = 0; /* STT_NOTYPE */ + break; + } + break; + } + + if (n->on_type & S_EXT) + bind = 1; /* STB_GLOBAL */ + else + bind = 0; /* STB_LOCAL */ + + return (bind << 4) | type; +} + +/* Convert a symbol's section index from ack.out to ELF. */ + +int cvsect(struct outname* n) +{ + switch (n->on_type & S_TYP) { + case S_ABS: + return 0xfff1; /* SHN_ABS */ + case S_MIN + TEXT: + return N_TEXT; + case S_MIN + ROM: + return N_RODATA; + case S_MIN + DATA: + return N_DATA; + case S_MIN + BSS: + case S_MIN + NUM_SEGMENTS: + return N_BSS; + default: + return N_UNDEF; + } +} + /* Writes a byte. */ void emit8(unsigned char value) @@ -220,6 +325,188 @@ void emitphdr(unsigned long address, unsigned long filesize, fileoffset += filesize; } +/* The next few functions write parts of the symbol table. */ + +void emit_stab(void) +{ + struct outname* n; + int i; + + for (i = 0; i < outhead.oh_nname; i++) { + n = &outname[i]; + if (n->on_type & S_STB) { + emit32(cvname(n)); /* name index */ + emit8(n->on_type >> 8); /* type */ + emit8(cvsect(n)); /* section */ + emit16(n->on_desc); /* desc */ + emit32(n->on_valu); /* value */ + } + } +} + +void emit_symtab(void) +{ + struct outname* n; + int i; + + for (i = 0; i < outhead.oh_nname; i++) { + n = &outname[i]; + if (!(n->on_type & S_STB)) { + emit32(cvname(n)); /* name index */ + emit32(n->on_valu); /* value */ + emit32(0); /* size = unknown */ + emit8(cvinfo(n)); /* info */ + emit8(0); /* other */ + emit16(cvsect(n)); /* section */ + } + } +} + +void emit_strtab(void) +{ + /* We prepend a '\0' because ELF uses offset 0 for symbols + * without a name. */ + emit8('\0'); + writef(stringarea, outhead.oh_nchar, 1); +} + +void emit_shstrtab(void) +{ + if (nstab) { + writef(shstrtab, sizeof(shstrtab), 1); + } else { + /* Skip .stab and .stabstr */ + int i = sh_name[N_SYMTAB]; + writef(shstrtab, sh_name[N_STAB], 1); + writef(shstrtab + i, sizeof(shstrtab) - i, 1); + } +} + +/* Writes out an ELF section header. */ + +void emit_sh(int i) +{ + uint32_t name, type, flags, addr, offset, size, addralign, + link, entsize; + + /* If no debugger symbols, skip .stab and .stabstr */ + if (nstab == 0 && (i == N_STAB || i == N_STABSTR)) + return; + + name = sh_name[i]; + if (nstab == 0 && i >= N_STAB) + name -= (sh_name[N_SYMTAB] - sh_name[N_STAB]); + + switch (i) { + case N_TEXT: + case N_RODATA: + case N_DATA: + case N_STAB: + type = 1; /* SHT_PROGBITS */ + break; + case N_BSS: + type = 8; /* SHT_NOBITS */ + break; + case N_SYMTAB: + type = 2; /* SHT_SYMTAB */ + break; + case N_STABSTR: + case N_STRTAB: + type = 3; /* SHT_STRTAB */ + break; + default: + type = 0; /* SHT_NULL */ + break; + } + + switch (i) { + case N_TEXT: + flags = 4|2; /* SHF_EXECINSTR|SHF_ALLOC */ + addr = outsect[TEXT].os_base; + offset = code_offset; + size = outsect[TEXT].os_size; + addralign = outsect[TEXT].os_lign; + break; + case N_RODATA: + flags = 2; /* SHF_ALLOC */ + addr = outsect[ROM].os_base; + offset = code_offset + outsect[TEXT].os_size; + size = outsect[ROM].os_size; + addralign = outsect[ROM].os_lign; + break; + case N_DATA: + flags = 2|1; /* SHF_ALLOC|SHF_WRITE */ + addr = outsect[DATA].os_base; + offset = code_offset + outsect[TEXT].os_size + + outsect[ROM].os_size; + size = outsect[DATA].os_size; + addralign = outsect[DATA].os_lign; + break; + case N_BSS: + flags = 2|1; /* SHF_ALLOC|SHF_WRITE */ + addr = outsect[BSS].os_base; + offset = code_offset + outsect[TEXT].os_size + + outsect[ROM].os_size + outsect[DATA].os_size; + size = outsect[BSS].os_size; + addralign = outsect[BSS].os_lign; + break; + default: + flags = addr = offset = size = addralign = 0; + break; + } + + entsize = 0; + switch (i) { + case N_STAB: + offset = stab_offset; + size = STAB_SYMBOL_SIZE * nstab; + entsize = STAB_SYMBOL_SIZE; + break; + case N_SYMTAB: + offset = symtab_offset; + size = ELF_SYMBOL_SIZE * nsym; + entsize = ELF_SYMBOL_SIZE; + break; + case N_STABSTR: + case N_STRTAB: + /* .stabstr, .strtab share the string area */ + offset = strtab_offset; + /* the + 1 because we prepend a '\0' */ + size = 1 + outhead.oh_nchar; + break; + case N_SHSTRTAB: + offset = shstrtab_offset; + size = shstrtab_size; + break; + } + + /* Link .stab to .stabstr and .symtab to .strtab */ + switch (i) { + case N_STAB: + link = N_STABSTR; + break; + case N_SYMTAB: + link = N_STRTAB; + if (nstab == 0) + link -= 2; + break; + default: + link = 0; + break; + } + + emit32(name); + emit32(type); + emit32(flags); + emit32(addr); + emit32(offset); + emit32(size); + emit32(link); + emit32(0); /* info */ + emit32(addralign); + emit32(entsize); +} + /* Macros from modules/src/object/obj.h */ #define Xchar(ch) ((ch) & 0377) #define uget2(c) (Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8)) @@ -264,6 +551,57 @@ int rsect(FILE* f, struct outsect* sect) return 1 ; } +/* + * Read the ack.out symbol table and string area. Count symbols. + * Seek back to the current file position. + */ +int rnames(FILE* f) +{ + long told; + int i; + + /* If no symbols, then do nothing successfully. */ + if (outhead.oh_nname == 0) + return 1; + + /* Seek to the symbol table. */ + told = ftell(f); + if (told == -1) + return 0; + ack_off_char = OFF_CHAR(outhead); /* for cvname() */ + if (fseek(f, OFF_NAME(outhead), SEEK_SET)) + return 0; + + /* Using calloc(a, b) to check if a * b would overflow. */ + outname = calloc(outhead.oh_nname, sizeof(outname[0])); + if (outname == NULL) + fatal("out of memory."); + for (i = 0; i < outhead.oh_nname; i++) { + char buf[SZ_NAME], *c; + if (fread(buf, SZ_NAME, 1, f) != 1) + return 0; + c = buf; + outname[i].on_foff = get4(c); c += 4; + outname[i].on_type = uget2(c); c += 2; + outname[i].on_desc = uget2(c); c += 2; + outname[i].on_valu = get4(c); + if (outname[i].on_type & S_STB) + nstab++; + else + nsym++; + } + + stringarea = malloc(outhead.oh_nchar); + if (stringarea == NULL) + fatal("out of memory."); + if (fread(stringarea, outhead.oh_nchar, 1, f) != 1) + return 0; + + if (fseek(f, told, SEEK_SET)) + return 0; + return 1; +} + int main(int argc, char* argv[]) { /* General housecleaning and setup. */ @@ -287,7 +625,7 @@ int main(int argc, char* argv[]) break; case 'h': - fprintf(stderr, "%s: Syntax: aelflod [-a] [-b] [-h] [-l]\n\t[-m] \n", + fprintf(stderr, "%s: Syntax: aelflod [-a] [-b] [-h] [-l]\n\t[-m] [-v] \n", program); exit(0); @@ -360,6 +698,11 @@ int main(int argc, char* argv[]) } } + /* Read the symbol table, then seek back to the section data. */ + + if (!rnames(input)) + fatal("failed to read symbol table."); + /* A few checks */ if (outsect[BSS].os_flen != 0) @@ -387,8 +730,8 @@ int main(int argc, char* argv[]) /* Ensure the base address doesn't overlap the file header. */ - codeoffset = outsect[TEXT].os_base & 0x1FFF; - if (codeoffset < (ELF_HEADER_SIZE + PROGRAM_HEADER_SIZE*PROGRAM_HEADER_COUNT)) + code_offset = outsect[TEXT].os_base & 0x1FFF; + if (code_offset < (ELF_HEADER_SIZE + PROGRAM_HEADER_SIZE*PROGRAM_HEADER_COUNT)) fatal("base address too small --- overlaps ELF header"); /* Rationalise the memory sizes. */ @@ -398,6 +741,30 @@ int main(int argc, char* argv[]) outsect[DATA].os_size = outsect[BSS ].os_base - outsect[DATA].os_base; outsect[BSS ].os_size = align(outsect[BSS].os_size, outsect[BSS].os_lign); + stab_offset = code_offset + outsect[TEXT].os_size + + outsect[ROM].os_size + outsect[DATA].os_size; + + /* If we have symbols, then calculate some offsets. */ + + if (outhead.oh_nname) { + sh_count = NUM_ELF_SECTIONS; + shstrtab_nr = N_SHSTRTAB; + shstrtab_size = sizeof(shstrtab); + if (nstab == 0) { + /* Skip .stab and .stabstr */ + sh_count -= 2; + shstrtab_nr -= 2; + shstrtab_size -= + (sh_name[N_SYMTAB] - sh_name[N_STAB]); + } + + symtab_offset = stab_offset + STAB_SYMBOL_SIZE * nstab; + strtab_offset = symtab_offset + ELF_SYMBOL_SIZE * nsym; + /* the + 1 because we prepend a '\0' */ + shstrtab_offset = strtab_offset + 1 + outhead.oh_nchar; + sh_offset = shstrtab_offset + shstrtab_size; + } + /* Write out the ELF file header. */ writef(elf_le_ident_string, 4, 1); @@ -414,33 +781,29 @@ int main(int argc, char* argv[]) emit32(1); /* ELF version again */ emit32(outsect[TEXT].os_base); /* entry point */ emit32(ELF_HEADER_SIZE); /* program header offset */ - emit32(0); /* section header offset */ + emit32(sh_offset); /* section header offset */ emit32(0); /* flags */ emit16(ELF_HEADER_SIZE); /* elf header size */ emit16(PROGRAM_HEADER_SIZE); /* program header entry size */ emit16(1); /* number of program header entries */ - emit16(0x28); /* section header entry size */ - emit16(0); /* number of section header entries */ - emit16(0); /* section header string table index = SHN_UNDEF */ + emit16(SECTION_HEADER_SIZE); /* section header entry size */ + emit16(sh_count); /* number of section header entries */ + emit16(shstrtab_nr); /* section header string table index */ /* Write out a single rwx section for the entire program. */ { - unsigned long filelength = codeoffset + - outsect[TEXT].os_size + - outsect[ROM].os_size + - outsect[DATA].os_size; - - unsigned long memlength = filelength + - outsect[BSS].os_size; - - emitphdr(outsect[TEXT].os_base & ~0x1FFF, filelength, memlength, - 0, 4|2|1); + uint32_t filelength = stab_offset; + uint32_t memlength = filelength + outsect[BSS].os_size; + + emitphdr(outsect[TEXT].os_base & ~0x1FFF, + filelength, memlength, 0, 4|2|1); } /* Write padding until the code start. */ - - fseek(output, codeoffset, SEEK_SET); + + if (fseek(output, code_offset, SEEK_SET)) + fatal("output seek error"); /* Write out the actual data. */ @@ -448,6 +811,19 @@ int main(int argc, char* argv[]) emits(&outsect[ROM]); emits(&outsect[DATA]); + /* Write out the symbol table and section headers. */ + + if (outhead.oh_nname) { + int i; + if (nstab) + emit_stab(); + emit_symtab(); + emit_strtab(); + emit_shstrtab(); + for (i = 0; i < NUM_ELF_SECTIONS; i++) + emit_sh(i); + } + if (ferror(output)) fatal("output write error"); if (outputfile) @@ -459,7 +835,7 @@ int main(int argc, char* argv[]) { uint32_t ss = 0; printf(" address length\n"); - printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, codeoffset); + printf(" ehdr : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base & ~0x1FFF, code_offset); printf(" text : %08"PRIx32" %08"PRIx32"\n", outsect[TEXT].os_base, outsect[TEXT].os_size); printf(" rom : %08"PRIx32" %08"PRIx32"\n", outsect[ROM].os_base, outsect[ROM].os_size); printf(" data : %08"PRIx32" %08"PRIx32"\n", outsect[DATA].os_base, outsect[DATA].os_size); From 7e39a821f4338d8f6114f87fbe447aadc370968a Mon Sep 17 00:00:00 2001 From: George Koehler Date: Tue, 13 Dec 2016 17:22:45 -0500 Subject: [PATCH 40/40] Update aelflod.1 to describe options, mention symbol table. --- util/amisc/aelflod.1 | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1 index 00cd62220..808b95429 100644 --- a/util/amisc/aelflod.1 +++ b/util/amisc/aelflod.1 @@ -3,7 +3,7 @@ aelflod \- ACK ELF loader .SH SYNOPSIS .B aelflod -[-h] [-v] inputfile outputfile +[-a\fInumber\fP] [-b] [-h] [-l] [-m\fInumber\fP] [-v] inputfile outputfile .SH DESCRIPTION .I aelflod converts an absolute ack.out file into a simple binary memory @@ -11,6 +11,32 @@ dump wrapped up in an ELF executable. It is suitable for producing executables for operating systems such as Linux. .PP +.I aelflod +accepts the following flags: +.TP +.BI \-a number +Set the ABI in the ELF header to \fInumber\fP. +The default value is \fI3\fP for Linux. +.TP +.B \-b +Write a big-endian ELF file. +.TP +.B \-h +Print a help message and exit. +.TP +.B \-l +Write a little-endian ELF file. +This is the default. +.TP +.BI \-m number +Set the machine type in the ELF header to \fInumber\fP. +The default value is \fI3\fP for Intel 386 (i386). +Other values are \fI4\fP for Motorola 68000 (m68k) +and \fI20\fP for PowerPC. +.TP +.B \-v +Be verbose. +.PP The input file must contain exactly four segments: TEXT, ROM, DATA and BSS, in that order, all occupying contiguous memory. The file must have all references resolved and be linked to a @@ -18,10 +44,15 @@ fixed address. The fixed address must be at least 0x54 bytes greater than a page boundary, in order to make room for the ELF header itself. .PP -aelflod will write out an ELF header followed by each segment, in -order, ensuring that enough padding is inserted between each segment +.I aelflod +will write out an ELF header followed by each segment, in order, +ensuring that enough padding is inserted between each segment to keep the offsets correct. -The created executable will contain just one rwx segment, and no -sections. +The created executable will contain just one ELF segment mapped rwx. +.PP +If the input file has symbols, then +.I aelflod +will convert the symbol table to ELF. +The output file has ELF section headers if and only if it has symbols. .SH "SEE ALSO" ack.out(5)