diff --git a/.gitignore b/.gitignore index c884c28..ddc551c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ programs/lib/bearssl ramdisk.tar PLANS/.mcp.json toolchain/native/ +toolchain/native-gcc/ diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 8b459f9..8d0afdc 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 18 +#define MONTAUK_BUILD_NUMBER 19 diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 9cea8c1..d12b293 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -405,6 +405,26 @@ ifneq ($(wildcard $(NATIVE_BIN)/as),) cp -r ../toolchain/local/x86_64-montauk/include/c++ $(BINDIR)/sdk/include/c++ ../toolchain/local/bin/x86_64-montauk-gcc -O2 ../toolchain/files/tls-test.c -o $(BINDIR)/sdk/bin/tls-test.elf ../toolchain/local/bin/x86_64-montauk-g++ -O2 ../toolchain/files/cxx-test.cpp -o $(BINDIR)/sdk/bin/cxx-test.elf +ifneq ($(wildcard ../toolchain/native-gcc/sdk/bin/gcc),) + cp ../toolchain/native-gcc/sdk/bin/gcc $(BINDIR)/sdk/bin/gcc.elf + cp ../toolchain/native-gcc/sdk/bin/g++ $(BINDIR)/sdk/bin/g++.elf + cp ../toolchain/native-gcc/sdk/bin/cpp $(BINDIR)/sdk/bin/cpp.elf + mkdir -p $(BINDIR)/sdk/libexec/gcc/x86_64-montauk/14.2.0 + cp ../toolchain/native-gcc/sdk/libexec/gcc/x86_64-montauk/14.2.0/cc1 \ + ../toolchain/native-gcc/sdk/libexec/gcc/x86_64-montauk/14.2.0/cc1plus \ + ../toolchain/native-gcc/sdk/libexec/gcc/x86_64-montauk/14.2.0/collect2 \ + $(BINDIR)/sdk/libexec/gcc/x86_64-montauk/14.2.0/ + cp -r ../toolchain/native-gcc/sdk/lib/gcc $(BINDIR)/sdk/lib/gcc + cp ../toolchain/local/lib/gcc/x86_64-montauk/14.2.0/libgcc.a \ + ../toolchain/local/lib/gcc/x86_64-montauk/14.2.0/crtbegin.o \ + ../toolchain/local/lib/gcc/x86_64-montauk/14.2.0/crtend.o \ + $(BINDIR)/sdk/lib/gcc/x86_64-montauk/14.2.0/ + cp ../toolchain/native/sdk/bin/ld $(BINDIR)/sdk/libexec/gcc/x86_64-montauk/14.2.0/ld + mkdir -p $(BINDIR)/tmp + printf 'scratch space for compiler intermediates\n' > $(BINDIR)/tmp/readme.txt +else + @echo "devkit: toolchain/native-gcc/ not built; skipping native GCC" +endif else @echo "devkit: toolchain/native/ not built; skipping native dev tools" endif diff --git a/programs/include/libc/ctype.h b/programs/include/libc/ctype.h index efca6ed..46606a2 100644 --- a/programs/include/libc/ctype.h +++ b/programs/include/libc/ctype.h @@ -16,6 +16,9 @@ int islower(int c); int isprint(int c); int ispunct(int c); int isxdigit(int c); + +#define isascii(c) (((c) & ~0x7F) == 0) +#define toascii(c) ((c) & 0x7F) int iscntrl(int c); int isgraph(int c); int toupper(int c); diff --git a/programs/include/libc/stdio.h b/programs/include/libc/stdio.h index 24b7489..a3c9dfd 100644 --- a/programs/include/libc/stdio.h +++ b/programs/include/libc/stdio.h @@ -1,6 +1,12 @@ #ifndef _LIBC_STDIO_H #define _LIBC_STDIO_H +/* Conventional guard marker: packages like GMP sniff the libc's stdio + include-guard name to detect that FILE is available. */ +#ifndef _STDIO_H +#define _STDIO_H 1 +#endif + #pragma once #include diff --git a/programs/include/libc/stdlib.h b/programs/include/libc/stdlib.h index 54d8a30..3c8f5d1 100644 --- a/programs/include/libc/stdlib.h +++ b/programs/include/libc/stdlib.h @@ -62,6 +62,8 @@ int mkstemp(char *template_); char *mktemp(char *template_); char *realpath(const char *path, char *resolved); size_t mbstowcs(wchar_t *dst, const char *src, size_t n); +#define MB_CUR_MAX 1 + int mblen(const char *s, size_t n); int mbtowc(wchar_t *pwc, const char *s, size_t n); int wctomb(char *s, wchar_t wc); diff --git a/programs/include/libc/sys/mman.h b/programs/include/libc/sys/mman.h new file mode 100644 index 0000000..b5aa231 --- /dev/null +++ b/programs/include/libc/sys/mman.h @@ -0,0 +1,41 @@ +#ifndef _LIBC_SYS_MMAN_H +#define _LIBC_SYS_MMAN_H + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Anonymous-memory mmap over SYS_ALLOC. SYS_ALLOC returns + * page-aligned process memory, which is exactly what callers like + * GCC's page allocator need. File-backed mappings are not + * supported and fail with ENODEV. +*/ + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS + +#define MAP_FAILED ((void *)-1) + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + long offset); +int munmap(void *addr, size_t length); +int mprotect(void *addr, size_t length, int prot); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBC_SYS_MMAN_H */ diff --git a/programs/include/libc/sys/stat.h b/programs/include/libc/sys/stat.h index e25d3f5..34b30e0 100644 --- a/programs/include/libc/sys/stat.h +++ b/programs/include/libc/sys/stat.h @@ -39,18 +39,18 @@ extern "C" { #define S_IXOTH 0001 struct stat { - unsigned long st_dev; - unsigned long st_ino; - mode_t st_mode; - unsigned long st_nlink; - uid_t st_uid; - gid_t st_gid; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; }; int mkdir(const char *path, unsigned int mode); diff --git a/programs/include/libc/sys/types.h b/programs/include/libc/sys/types.h index 7d14c01..5cb4582 100644 --- a/programs/include/libc/sys/types.h +++ b/programs/include/libc/sys/types.h @@ -21,6 +21,13 @@ typedef unsigned int mode_t; typedef unsigned int uid_t; typedef unsigned int gid_t; typedef long time_t; +typedef unsigned long ino_t; +typedef unsigned long dev_t; +typedef unsigned long nlink_t; +typedef long blkcnt_t; +typedef long blksize_t; +typedef long suseconds_t; +typedef int clockid_t; #ifdef __cplusplus } diff --git a/programs/include/libc/unistd.h b/programs/include/libc/unistd.h index 2cfa39e..2217bbd 100644 --- a/programs/include/libc/unistd.h +++ b/programs/include/libc/unistd.h @@ -39,6 +39,14 @@ int execve(const char *path, char *const argv[], char *const envp[]); int execvp(const char *file, char *const argv[]); int pipe(int fds[2]); long pathconf(const char *path, int name); +int getpagesize(void); +long sysconf(int name); + +/* sysconf() names (Linux numbering). */ +#define _SC_OPEN_MAX 4 +#define _SC_PAGESIZE 30 +#define _SC_PAGE_SIZE 30 +#define _SC_NPROCESSORS_ONLN 84 /* pathconf() names (Linux numbering). */ #define _PC_LINK_MAX 0 diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index 8d3c821..f763c1d 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -2286,7 +2287,7 @@ int stat(const char *path, struct stat *buf) { int h = (int)_zos_syscall1(SYS_OPEN, (long)path); if (h >= 0) { buf->st_mode = S_IFREG; - buf->st_size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)h); + buf->st_size = (off_t)_zos_syscall1(SYS_GETSIZE, (long)h); _zos_syscall1(SYS_CLOSE, (long)h); /* No inodes in the VFS API: derive a stable id from the path so that distinct paths compare as distinct files. */ @@ -2297,7 +2298,7 @@ int stat(const char *path, struct stat *buf) { buf->st_ino = ino | 1; buf->st_nlink = 1; buf->st_blksize = 4096; - buf->st_blocks = (buf->st_size + 511) / 512; + buf->st_blocks = (blkcnt_t)((buf->st_size + 511) / 512); return 0; } @@ -2318,13 +2319,13 @@ int fstat(int fd, struct stat *buf) { } memset(buf, 0, sizeof(*buf)); buf->st_mode = S_IFREG; - buf->st_size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd); + buf->st_size = (off_t)_zos_syscall1(SYS_GETSIZE, (long)fd); /* Handles do not map back to paths, so fake a per-handle inode in a range disjoint from the path hashes used by stat(). */ buf->st_ino = 0x4000000000000000UL + (unsigned long)fd; buf->st_nlink = 1; buf->st_blksize = 4096; - buf->st_blocks = (buf->st_size + 511) / 512; + buf->st_blocks = (blkcnt_t)((buf->st_size + 511) / 512); return 0; } @@ -3711,6 +3712,57 @@ int kill(pid_t pid, int sig) { return 0; } +int getpagesize(void) { + return 4096; +} + +long sysconf(int name) { + switch (name) { + case 4: /* _SC_OPEN_MAX */ + return 64; + case 30: /* _SC_PAGESIZE */ + return 4096; + case 84: /* _SC_NPROCESSORS_ONLN */ + return 1; + default: + errno = EINVAL; + return -1; + } +} + +/* Anonymous mappings only: SYS_ALLOC hands back zeroed page-aligned + memory and SYS_FREE releases it. Length is remembered by the kernel + per allocation, so munmap ignores its length argument. */ +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + long offset) { + (void)addr; (void)prot; (void)offset; + if (length == 0 || fd != -1 || !(flags & MAP_ANONYMOUS)) { + errno = ENODEV; + return MAP_FAILED; + } + void *p = (void *)_zos_syscall1(SYS_ALLOC, (long)length); + if (p == NULL) { + errno = ENOMEM; + return MAP_FAILED; + } + return p; +} + +int munmap(void *addr, size_t length) { + (void)length; + if (addr == NULL || addr == MAP_FAILED) { + errno = EINVAL; + return -1; + } + _zos_syscall1(SYS_FREE, (long)addr); + return 0; +} + +int mprotect(void *addr, size_t length, int prot) { + (void)addr; (void)length; (void)prot; + return 0; /* page protections are not adjustable from userspace */ +} + long pathconf(const char *path, int name) { (void)path; switch (name) { diff --git a/programs/lib/libc/obj/libc.o b/programs/lib/libc/obj/libc.o index 68c9965..821c9fb 100644 Binary files a/programs/lib/libc/obj/libc.o and b/programs/lib/libc/obj/libc.o differ diff --git a/toolchain/README.md b/toolchain/README.md index 8d2f6b4..d299721 100644 --- a/toolchain/README.md +++ b/toolchain/README.md @@ -80,6 +80,44 @@ make install-strip-gas install-strip-ld install-strip-binutils \ DESTDIR=$PWD/../../native ``` +## Native GCC (runs on MontaukOS) + +GCC itself cross-builds for the montauk host (build dir +toolchain/build/gcc-native, install DESTDIR toolchain/native-gcc): + +```bash +../../src/gcc-14.2.0/configure \ + --build=x86_64-pc-linux-gnu --host=x86_64-montauk \ + --target=x86_64-montauk --prefix=/sdk \ + --with-native-system-header-dir=/sdk/include \ + --with-build-sysroot=$PWD/../../sysroot \ + --enable-languages=c,c++ --disable-nls --disable-shared \ + --disable-multilib --disable-gcov --disable-lto --disable-plugin \ + --disable-bootstrap --disable-fixincludes --with-newlib \ + --enable-initfini-array --disable-wchar_t --disable-libstdcxx-pch \ + --with-gnu-as --with-gnu-ld +ac_cv_c_bigendian=no make -j$(nproc) all-gcc +make install-gcc DESTDIR=$PWD/../../native-gcc +``` + +Host-build gotchas, in the order they bite: +- The bundled gmp/mpfr/mpc/isl/gettext carry their own config.sub + copies; overwrite each with the patched top-level one. +- Remove the src tree's gettext symlink (--disable-nls does not skip + it, and its gnulib needs more locale surface than the libc has). +- gmp.h sniffs the libc's stdio include-guard name to detect FILE; + the Montauk stdio.h defines the conventional _STDIO_H marker. +- The gcc subdir configure cannot run host binaries to probe + endianness; preset ac_cv_c_bigendian=no. +- The build sysroot needs an sdk -> usr symlink so + --with-native-system-header-dir=/sdk/include resolves at build time. + +The devkit target ships gcc/g++/cpp as .elf in 0:/sdk/bin, cc1 + +cc1plus + collect2 (and a copy of ld for collect2's search) under +0:/sdk/libexec/gcc/x86_64-montauk/14.2.0, libgcc.a + crtbegin/crtend +under 0:/sdk/lib/gcc/x86_64-montauk/14.2.0, and a 0:/tmp scratch dir +for driver intermediates. + Notes: - Build only `all-gas all-ld all-binutils`. gprof needs fscanf with %[] scansets (not in the Montauk libc); gold and gprofng are