]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: i686-adros cross-toolchain infrastructure + kernel test expansion
authorTulio A M Mendes <[email protected]>
Sat, 14 Mar 2026 01:19:19 +0000 (22:19 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 14 Mar 2026 01:19:19 +0000 (22:19 -0300)
Toolchain Build System (toolchain/):
- toolchain/build.sh: Automated 5-stage build script
  Stage 1: Binutils 2.42 (i686-adros assembler/linker)
  Stage 2: GCC 13.2 bootstrap (C only, no libc)
  Stage 3: Newlib 4.4.0 (C library with libgloss/adros stubs)
  Stage 4: GCC 13.2 full rebuild (C/C++ with Newlib sysroot)
  Stage 5: Bash 5.2.21 cross-compilation (optional, static)

- toolchain/patches/binutils-adros.patch:
  config.sub, bfd/config.bfd, gas/configure.tgt, ld/configure.tgt
  Adds i686-adros as ELF32 target using i386 backend

- toolchain/patches/gcc-adros.patch:
  config.sub, gcc/config.gcc, gcc/config/i386/adros.h,
  libgcc/config.host, crti-adros.S, crtn-adros.S
  Defines __adros__, __unix__, ELF32 format, crt0.o startup,
  -lc -ladros -lgcc link spec, i386 wchar/size/ptrdiff types

- toolchain/patches/newlib-adros.patch:
  config.sub, newlib/configure.host, newlib/libc/include/sys/config.h,
  libgloss/configure.in, libgloss/adros/configure.in+Makefile.in,
  newlib/libc/sys/adros/ stubs
  SIGNAL_PROVIDED, MALLOC_PROVIDED, HAVE_OPENDIR flags

- toolchain/README.md: Build prerequisites, usage, sysroot layout,
  troubleshooting guide

ulibc Enhancements:
- errno.h: Full POSIX errno set (sorted, no duplicates), matches kernel
- ctype.h: Added iscntrl, isgraph, ispunct, isascii, isblank, toascii
- signal.h: Added SA_RESTART, SA_NOCLDSTOP, SA_NOCLDWAIT, SA_NODEFER,
  SA_RESETHAND, SIG_ERR, sighandler_t typedef, signal() declaration

Kernel Test Expansion:
- fulltest.c: 3 new syscall tests
  - gettimeofday: verify epoch timestamp > 1e9
  - mprotect: brk page, write, mprotect RW, verify success
  - getrlimit/setrlimit: get RLIMIT_NOFILE, set lower, read back, restore
- smoke_test.exp: 3 new patterns (100 total)

100/100 smoke tests pass (11 sec), cppcheck clean.

tests/smoke_test.exp
toolchain/README.md [new file with mode: 0644]
toolchain/build.sh [new file with mode: 0755]
toolchain/patches/binutils-adros.patch [new file with mode: 0644]
toolchain/patches/gcc-adros.patch [new file with mode: 0644]
toolchain/patches/newlib-adros.patch [new file with mode: 0644]
user/fulltest.c
user/ulibc/include/ctype.h
user/ulibc/include/errno.h
user/ulibc/include/signal.h

index 0e241785eefd9090290a2811f0481e13b41990a2..c39fb0459759df0beb59c1251b2a24f160aa00be 100755 (executable)
@@ -139,6 +139,9 @@ set tests {
     {"pipe EOF"            "\\[init\\] pipe EOF OK"}
     {"readdir /proc"       "\\[init\\] readdir /proc OK"}
     {"readdir /bin"        "\\[init\\] readdir /bin OK"}
+    {"gettimeofday"        "\\[init\\] gettimeofday OK"}
+    {"mprotect"            "\\[init\\] mprotect OK"}
+    {"getrlimit/setrlimit" "\\[init\\] getrlimit/setrlimit OK"}
     {"LZ4 Frame decomp"    "\\[INITRD\\] LZ4"}
 }
 
diff --git a/toolchain/README.md b/toolchain/README.md
new file mode 100644 (file)
index 0000000..1ba2954
--- /dev/null
@@ -0,0 +1,118 @@
+# AdrOS Cross-Compilation Toolchain
+
+Build a complete `i686-adros` toolchain: **Binutils → GCC (bootstrap) → Newlib → GCC (full) → Bash**.
+
+## Prerequisites
+
+Install on Ubuntu/Debian:
+```bash
+sudo apt install build-essential texinfo libgmp-dev libmpfr-dev libmpc-dev libisl-dev wget
+```
+
+Install on Fedora:
+```bash
+sudo dnf install gcc gcc-c++ make texinfo gmp-devel mpfr-devel libmpc-devel isl-devel wget
+```
+
+## Quick Build
+
+```bash
+# Build everything (installs to /opt/adros-toolchain by default)
+sudo mkdir -p /opt/adros-toolchain && sudo chown $USER /opt/adros-toolchain
+./toolchain/build.sh
+
+# Or specify a custom prefix
+./toolchain/build.sh --prefix $HOME/adros-toolchain --jobs 8
+
+# Skip Bash if you only need the C compiler
+./toolchain/build.sh --skip-bash
+```
+
+Build takes approximately 20-40 minutes depending on hardware.
+
+## What Gets Built
+
+| Step | Component | Output |
+|------|-----------|--------|
+| 1 | Binutils 2.42 | `i686-adros-ld`, `i686-adros-as`, `i686-adros-objdump`, ... |
+| 2 | GCC 13.2 (bootstrap) | `i686-adros-gcc` (C only, no libc) |
+| 3 | Newlib 4.4.0 | `libc.a`, `libm.a` (installed to sysroot) |
+| 4 | GCC 13.2 (full) | `i686-adros-gcc`, `i686-adros-g++` (C/C++ with Newlib) |
+| 5 | Bash 5.2.21 | Statically linked `bash` binary for AdrOS |
+
+## Usage
+
+```bash
+export PATH=/opt/adros-toolchain/bin:$PATH
+
+# Compile a C program
+i686-adros-gcc -o hello hello.c
+
+# Compile with math library
+i686-adros-gcc -o calc calc.c -lm
+
+# Static linking (default)
+i686-adros-gcc -static -o myapp myapp.c
+```
+
+## Sysroot Layout
+
+```
+/opt/adros-toolchain/i686-adros/
+├── include/        # Newlib + AdrOS headers
+│   ├── stdio.h     # Newlib
+│   ├── stdlib.h    # Newlib
+│   ├── sys/        # Newlib + AdrOS system headers
+│   └── ...
+├── lib/
+│   ├── libc.a      # Newlib C library
+│   ├── libm.a      # Newlib math library
+│   ├── libadros.a  # AdrOS syscall stubs
+│   ├── crt0.o      # C runtime startup
+│   └── libgcc.a    # GCC support library
+└── ...
+```
+
+## AdrOS Target Patches
+
+The `patches/` directory contains diffs that add `i686-adros` as a recognized
+target in each component's build system:
+
+- **`binutils-adros.patch`**: `config.sub`, `bfd/config.bfd`, `gas/configure.tgt`, `ld/configure.tgt`
+- **`gcc-adros.patch`**: `config.sub`, `gcc/config.gcc`, `gcc/config/i386/adros.h`, `libgcc/config.host`, `crti.S`/`crtn.S`
+- **`newlib-adros.patch`**: `config.sub`, `newlib/configure.host`, `newlib/libc/include/sys/config.h`, `libgloss/configure.in`, autoconf files
+
+### Key GCC Target Header (`adros.h`)
+
+Defines for the AdrOS target:
+- `__adros__`, `__AdrOS__`, `__unix__` preprocessor macros
+- ELF32 object format, i386 architecture
+- Startup: `crt0.o` → `_start` → `main()` → `exit()`
+- Links: `-lc -ladros -lgcc`
+
+## Troubleshooting
+
+**"configure: error: cannot compute sizeof..."**
+→ Normal for cross-compilation. The build script passes `--with-newlib` to avoid
+running target executables on the host.
+
+**"crt0.o: No such file"**
+→ Newlib hasn't been built yet. Run the full build script or build Newlib first.
+
+**GCC can't find headers**
+→ Ensure `--with-sysroot` points to the correct sysroot directory.
+
+## Directory Structure
+
+```
+toolchain/
+├── build.sh            # Master build script
+├── README.md           # This file
+├── patches/
+│   ├── binutils-adros.patch
+│   ├── gcc-adros.patch
+│   └── newlib-adros.patch
+├── build/              # (generated) Build directories
+├── src/                # (generated) Downloaded source tarballs
+└── logs/               # (generated) Build logs
+```
diff --git a/toolchain/build.sh b/toolchain/build.sh
new file mode 100755 (executable)
index 0000000..53316fa
--- /dev/null
@@ -0,0 +1,340 @@
+#!/usr/bin/env bash
+#
+# AdrOS Toolchain Builder
+#
+# Builds a complete i686-adros cross-compilation toolchain:
+#   1. Binutils  (assembler, linker)
+#   2. GCC       (bootstrap, C only, no libc headers)
+#   3. Newlib    (C library)
+#   4. GCC       (full rebuild with Newlib sysroot)
+#   5. Bash      (optional, cross-compiled)
+#
+# Usage:
+#   ./toolchain/build.sh [--prefix /opt/adros] [--jobs 4] [--skip-bash]
+#
+# Prerequisites:
+#   - GCC (host), G++, Make, Texinfo, GMP, MPFR, MPC, ISL (dev packages)
+#   - wget or git for downloading sources
+#   - ~4 GB disk space
+#
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+ADROS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+# ---- Defaults ----
+PREFIX="/opt/adros-toolchain"
+TARGET="i686-adros"
+JOBS="$(nproc 2>/dev/null || echo 4)"
+SKIP_BASH=0
+
+# ---- Versions ----
+BINUTILS_VER="2.42"
+GCC_VER="13.2.0"
+NEWLIB_VER="4.4.0.20231231"
+BASH_VER="5.2.21"
+
+BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER}.tar.xz"
+GCC_URL="https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.xz"
+NEWLIB_URL="https://sourceware.org/pub/newlib/newlib-${NEWLIB_VER}.tar.gz"
+BASH_URL="https://ftp.gnu.org/gnu/bash/bash-${BASH_VER}.tar.gz"
+
+# ---- Parse args ----
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        --prefix)  PREFIX="$2"; shift 2 ;;
+        --jobs)    JOBS="$2"; shift 2 ;;
+        --skip-bash) SKIP_BASH=1; shift ;;
+        --help|-h)
+            echo "Usage: $0 [--prefix DIR] [--jobs N] [--skip-bash]"
+            exit 0 ;;
+        *) echo "Unknown option: $1"; exit 1 ;;
+    esac
+done
+
+SYSROOT="${PREFIX}/${TARGET}"
+BUILD_DIR="${ADROS_ROOT}/toolchain/build"
+SRC_DIR="${ADROS_ROOT}/toolchain/src"
+PATCH_DIR="${ADROS_ROOT}/toolchain/patches"
+LOG_DIR="${ADROS_ROOT}/toolchain/logs"
+
+export PATH="${PREFIX}/bin:${PATH}"
+
+msg()  { echo -e "\n\033[1;32m==>\033[0m \033[1m$1\033[0m"; }
+err()  { echo -e "\n\033[1;31m==> ERROR:\033[0m $1" >&2; exit 1; }
+step() { echo -e "  \033[1;34m->\033[0m $1"; }
+
+mkdir -p "$BUILD_DIR" "$SRC_DIR" "$LOG_DIR" "$SYSROOT"
+
+# ---- Download sources ----
+download() {
+    local url="$1" dest="$2"
+    if [[ -f "$dest" ]]; then
+        step "Already downloaded: $(basename "$dest")"
+        return
+    fi
+    step "Downloading $(basename "$dest")..."
+    wget -q --show-progress -O "$dest" "$url"
+}
+
+extract() {
+    local archive="$1" dir="$2"
+    if [[ -d "$dir" ]]; then
+        step "Already extracted: $(basename "$dir")"
+        return
+    fi
+    step "Extracting $(basename "$archive")..."
+    case "$archive" in
+        *.tar.xz) tar xf "$archive" -C "$SRC_DIR" ;;
+        *.tar.gz) tar xzf "$archive" -C "$SRC_DIR" ;;
+        *) err "Unknown archive type: $archive" ;;
+    esac
+}
+
+msg "Downloading sources"
+download "$BINUTILS_URL" "$SRC_DIR/binutils-${BINUTILS_VER}.tar.xz"
+download "$GCC_URL"      "$SRC_DIR/gcc-${GCC_VER}.tar.xz"
+download "$NEWLIB_URL"   "$SRC_DIR/newlib-${NEWLIB_VER}.tar.gz"
+[[ $SKIP_BASH -eq 0 ]] && download "$BASH_URL" "$SRC_DIR/bash-${BASH_VER}.tar.gz"
+
+msg "Extracting sources"
+extract "$SRC_DIR/binutils-${BINUTILS_VER}.tar.xz" "$SRC_DIR/binutils-${BINUTILS_VER}"
+extract "$SRC_DIR/gcc-${GCC_VER}.tar.xz"           "$SRC_DIR/gcc-${GCC_VER}"
+extract "$SRC_DIR/newlib-${NEWLIB_VER}.tar.gz"      "$SRC_DIR/newlib-${NEWLIB_VER}"
+[[ $SKIP_BASH -eq 0 ]] && extract "$SRC_DIR/bash-${BASH_VER}.tar.gz" "$SRC_DIR/bash-${BASH_VER}"
+
+# ---- Apply patches ----
+apply_patch() {
+    local src_dir="$1" patch_file="$2" marker="$1/.adros_patched_$(basename "$2")"
+    if [[ -f "$marker" ]]; then
+        step "Already patched: $(basename "$patch_file")"
+        return
+    fi
+    step "Applying $(basename "$patch_file") to $(basename "$src_dir")..."
+    patch -d "$src_dir" -p1 < "$patch_file"
+    touch "$marker"
+}
+
+msg "Applying AdrOS target patches"
+apply_patch "$SRC_DIR/binutils-${BINUTILS_VER}" "$PATCH_DIR/binutils-adros.patch"
+apply_patch "$SRC_DIR/gcc-${GCC_VER}"           "$PATCH_DIR/gcc-adros.patch"
+apply_patch "$SRC_DIR/newlib-${NEWLIB_VER}"      "$PATCH_DIR/newlib-adros.patch"
+
+# Copy libgloss stubs into Newlib source tree
+if [[ ! -d "$SRC_DIR/newlib-${NEWLIB_VER}/libgloss/adros" ]]; then
+    step "Copying libgloss/adros/ into Newlib source tree..."
+    cp -r "$ADROS_ROOT/newlib/libgloss/adros" "$SRC_DIR/newlib-${NEWLIB_VER}/libgloss/adros"
+fi
+
+# ---- Install sysroot headers ----
+msg "Installing sysroot headers"
+step "Copying ulibc headers to ${SYSROOT}/include..."
+mkdir -p "${SYSROOT}/include/sys" "${SYSROOT}/include/linux"
+cp -r "$ADROS_ROOT/user/ulibc/include/"*.h "${SYSROOT}/include/" 2>/dev/null || true
+cp -r "$ADROS_ROOT/user/ulibc/include/sys/"*.h "${SYSROOT}/include/sys/" 2>/dev/null || true
+cp -r "$ADROS_ROOT/user/ulibc/include/linux/"*.h "${SYSROOT}/include/linux/" 2>/dev/null || true
+
+# Copy kernel headers needed by the toolchain
+step "Copying kernel headers to sysroot..."
+for h in errno.h syscall.h socket.h; do
+    [[ -f "$ADROS_ROOT/include/$h" ]] && cp "$ADROS_ROOT/include/$h" "${SYSROOT}/include/kernel_${h}"
+done
+
+# ==================================================================
+# STEP 1: Build Binutils
+# ==================================================================
+msg "Building Binutils ${BINUTILS_VER}"
+mkdir -p "$BUILD_DIR/binutils"
+cd "$BUILD_DIR/binutils"
+
+if [[ ! -f "$PREFIX/bin/${TARGET}-ld" ]]; then
+    "$SRC_DIR/binutils-${BINUTILS_VER}/configure" \
+        --target="$TARGET" \
+        --prefix="$PREFIX" \
+        --with-sysroot="$SYSROOT" \
+        --disable-nls \
+        --disable-werror \
+        2>&1 | tee "$LOG_DIR/binutils-configure.log"
+
+    make -j"$JOBS" 2>&1 | tee "$LOG_DIR/binutils-build.log"
+    make install    2>&1 | tee "$LOG_DIR/binutils-install.log"
+    step "Binutils installed: ${PREFIX}/bin/${TARGET}-ld"
+else
+    step "Binutils already installed"
+fi
+
+# ==================================================================
+# STEP 2: Build GCC (bootstrap — no libc)
+# ==================================================================
+msg "Building GCC ${GCC_VER} (bootstrap, C only)"
+mkdir -p "$BUILD_DIR/gcc-bootstrap"
+cd "$BUILD_DIR/gcc-bootstrap"
+
+if [[ ! -f "$PREFIX/bin/${TARGET}-gcc" ]]; then
+    "$SRC_DIR/gcc-${GCC_VER}/configure" \
+        --target="$TARGET" \
+        --prefix="$PREFIX" \
+        --with-sysroot="$SYSROOT" \
+        --without-headers \
+        --enable-languages=c \
+        --disable-nls \
+        --disable-shared \
+        --disable-threads \
+        --disable-libssp \
+        --disable-libquadmath \
+        --disable-libgomp \
+        --disable-libatomic \
+        --with-newlib \
+        2>&1 | tee "$LOG_DIR/gcc-bootstrap-configure.log"
+
+    make -j"$JOBS" all-gcc all-target-libgcc \
+        2>&1 | tee "$LOG_DIR/gcc-bootstrap-build.log"
+    make install-gcc install-target-libgcc \
+        2>&1 | tee "$LOG_DIR/gcc-bootstrap-install.log"
+    step "Bootstrap GCC installed: ${PREFIX}/bin/${TARGET}-gcc"
+else
+    step "Bootstrap GCC already installed"
+fi
+
+# ==================================================================
+# STEP 3: Build Newlib
+# ==================================================================
+msg "Building Newlib ${NEWLIB_VER}"
+mkdir -p "$BUILD_DIR/newlib"
+cd "$BUILD_DIR/newlib"
+
+if [[ ! -f "${SYSROOT}/lib/libc.a" ]]; then
+    "$SRC_DIR/newlib-${NEWLIB_VER}/configure" \
+        --target="$TARGET" \
+        --prefix="$PREFIX" \
+        --disable-multilib \
+        --enable-newlib-nano-malloc \
+        --enable-newlib-io-long-long \
+        --enable-newlib-io-c99-formats \
+        --disable-newlib-supplied-syscalls \
+        2>&1 | tee "$LOG_DIR/newlib-configure.log"
+
+    make -j"$JOBS" 2>&1 | tee "$LOG_DIR/newlib-build.log"
+    make install   2>&1 | tee "$LOG_DIR/newlib-install.log"
+    step "Newlib installed to sysroot"
+else
+    step "Newlib already installed"
+fi
+
+# ==================================================================
+# STEP 4: Rebuild GCC (full, with Newlib)
+# ==================================================================
+msg "Rebuilding GCC ${GCC_VER} (full, with Newlib sysroot)"
+mkdir -p "$BUILD_DIR/gcc-full"
+cd "$BUILD_DIR/gcc-full"
+
+# Only rebuild if the full gcc doesn't link against newlib yet
+if [[ ! -f "$BUILD_DIR/gcc-full/.built" ]]; then
+    "$SRC_DIR/gcc-${GCC_VER}/configure" \
+        --target="$TARGET" \
+        --prefix="$PREFIX" \
+        --with-sysroot="$SYSROOT" \
+        --enable-languages=c,c++ \
+        --disable-nls \
+        --disable-shared \
+        --with-newlib \
+        --disable-libssp \
+        --disable-libquadmath \
+        2>&1 | tee "$LOG_DIR/gcc-full-configure.log"
+
+    make -j"$JOBS" 2>&1 | tee "$LOG_DIR/gcc-full-build.log"
+    make install   2>&1 | tee "$LOG_DIR/gcc-full-install.log"
+    touch "$BUILD_DIR/gcc-full/.built"
+    step "Full GCC installed: ${PREFIX}/bin/${TARGET}-g++"
+else
+    step "Full GCC already installed"
+fi
+
+# ==================================================================
+# STEP 5: Cross-compile Bash (optional)
+# ==================================================================
+if [[ $SKIP_BASH -eq 0 ]]; then
+    msg "Cross-compiling Bash ${BASH_VER}"
+    mkdir -p "$BUILD_DIR/bash"
+    cd "$BUILD_DIR/bash"
+
+    if [[ ! -f "$BUILD_DIR/bash/bash" ]]; then
+        # Bash needs a config.cache for cross-compilation
+        cat > config.cache <<'CACHE_EOF'
+ac_cv_func_mmap_fixed_mapped=no
+ac_cv_func_setvbuf_reversed=no
+ac_cv_func_strcoll_works=yes
+ac_cv_func_working_mktime=yes
+ac_cv_type_getgroups=gid_t
+ac_cv_rl_version=8.2
+bash_cv_func_sigsetjmp=present
+bash_cv_func_ctype_nonascii=no
+bash_cv_must_reinstall_sighandlers=no
+bash_cv_func_snprintf=yes
+bash_cv_func_vsnprintf=yes
+bash_cv_printf_a_format=no
+bash_cv_pgrp_pipe=no
+bash_cv_sys_named_pipes=missing
+bash_cv_job_control_missing=present
+bash_cv_sys_siglist=yes
+bash_cv_under_sys_siglist=yes
+bash_cv_opendir_not_robust=no
+bash_cv_ulimit_maxfds=yes
+bash_cv_getenv_redef=yes
+bash_cv_getcwd_malloc=yes
+bash_cv_type_rlimit=long
+bash_cv_type_intmax_t=int
+bash_cv_type_uintmax_t=unsigned
+CACHE_EOF
+
+        "$SRC_DIR/bash-${BASH_VER}/configure" \
+            --host="$TARGET" \
+            --prefix=/usr \
+            --without-bash-malloc \
+            --disable-nls \
+            --cache-file=config.cache \
+            CC="${TARGET}-gcc" \
+            AR="${TARGET}-ar" \
+            RANLIB="${TARGET}-ranlib" \
+            CFLAGS="-Os -static" \
+            LDFLAGS="-static" \
+            2>&1 | tee "$LOG_DIR/bash-configure.log"
+
+        make -j"$JOBS" 2>&1 | tee "$LOG_DIR/bash-build.log"
+        step "Bash built: $BUILD_DIR/bash/bash"
+
+        # Copy to AdrOS initrd
+        if [[ -d "$ADROS_ROOT/iso/boot" ]]; then
+            step "Installing bash to AdrOS filesystem..."
+            mkdir -p "$ADROS_ROOT/iso/bin"
+            cp "$BUILD_DIR/bash/bash" "$ADROS_ROOT/iso/bin/bash"
+        fi
+    else
+        step "Bash already built"
+    fi
+fi
+
+# ==================================================================
+# Summary
+# ==================================================================
+msg "Toolchain build complete!"
+echo ""
+echo "  Prefix:    $PREFIX"
+echo "  Target:    $TARGET"
+echo "  Sysroot:   $SYSROOT"
+echo ""
+echo "  Tools:"
+echo "    ${TARGET}-gcc    — C compiler"
+echo "    ${TARGET}-g++    — C++ compiler"
+echo "    ${TARGET}-ld     — Linker"
+echo "    ${TARGET}-as     — Assembler"
+echo "    ${TARGET}-ar     — Archiver"
+echo "    ${TARGET}-objdump — Disassembler"
+echo ""
+echo "  Usage:"
+echo "    export PATH=${PREFIX}/bin:\$PATH"
+echo "    ${TARGET}-gcc -o hello hello.c"
+echo ""
+if [[ $SKIP_BASH -eq 0 ]]; then
+    echo "  Bash: $BUILD_DIR/bash/bash"
+fi
diff --git a/toolchain/patches/binutils-adros.patch b/toolchain/patches/binutils-adros.patch
new file mode 100644 (file)
index 0000000..fb6e93a
--- /dev/null
@@ -0,0 +1,48 @@
+--- a/config.sub
++++ b/config.sub
+@@ -1749,6 +1749,9 @@
+       -dicos*)
+               os=-dicos
+               ;;
++      -adros*)
++              os=-adros
++              ;;
+       -nacl*)
+               ;;
+       -ios)
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -659,6 +659,11 @@
+     targ_selvecs=
+     targ64_selvecs=x86_64_elf64_vec
+     ;;
++  i[3-7]86-*-adros*)
++    targ_defvec=i386_elf32_vec
++    targ_selvecs=
++    targ64_selvecs=x86_64_elf64_vec
++    ;;
+   i[3-7]86-*-linux-*)
+     targ_defvec=i386_elf32_vec
+     targ_selvecs="iamcu_elf32_vec i386_pei_vec"
+--- a/gas/configure.tgt
++++ b/gas/configure.tgt
+@@ -224,6 +224,7 @@
+   i386-*-*nt*)                                fmt=coff em=pe ;;
+   i386-*-rdos*)                               fmt=elf ;;
+   i386-*-darwin*)                     fmt=macho ;;
++  i386-*-adros*)                      fmt=elf ;;
+
+   ia16-*-elf*)                                fmt=elf ;;
+
+--- a/ld/configure.tgt
++++ b/ld/configure.tgt
+@@ -344,6 +344,9 @@
+                       targ_extra_libpath=$targ_extra_emuls
+                       ;;
+ i[3-7]86-*-linux-*)   targ_emul=elf_i386
++                      ;;
++i[3-7]86-*-adros*)    targ_emul=elf_i386
++                      targ_extra_emuls="elf_i386"
+                       ;;
+ i[3-7]86-*-redox*)    targ_emul=elf_i386
+                       ;;
diff --git a/toolchain/patches/gcc-adros.patch b/toolchain/patches/gcc-adros.patch
new file mode 100644 (file)
index 0000000..e0ee3c8
--- /dev/null
@@ -0,0 +1,145 @@
+--- a/config.sub
++++ b/config.sub
+@@ -1749,6 +1749,9 @@
+       -dicos*)
+               os=-dicos
+               ;;
++      -adros*)
++              os=-adros
++              ;;
+       -nacl*)
+               ;;
+       -ios)
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -1020,6 +1020,12 @@
+ i[34567]86-*-elf*)
+       tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h"
+       ;;
++i[34567]86-*-adros*)
++      tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/adros.h"
++      tmake_file="${tmake_file} i386/t-crtstuff"
++      use_gcc_stdint=wrap
++      default_use_cxa_atexit=yes
++      ;;
+ x86_64-*-elf*)
+       tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h"
+       ;;
+--- /dev/null
++++ b/gcc/config/i386/adros.h
+@@ -0,0 +1,69 @@
++/* Target definitions for i386 AdrOS.
++   Copyright (C) 2024 Free Software Foundation, Inc.
++
++This file is part of GCC.
++
++GCC is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 3, or (at your option)
++any later version.
++
++GCC is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++Under Section 7 of GPL version 3, you are granted additional
++permissions described in the GCC Runtime Library Exception, version
++3.1, as published by the Free Software Foundation.
++
++You should have received a copy of the GNU General Public License and
++a copy of the GCC Runtime Library Exception along with this program;
++see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
++<http://www.gnu.org/licenses/>.  */
++
++/* AdrOS is a 32-bit POSIX-like operating system */
++
++#undef  TARGET_OS_CPP_BUILTINS
++#define TARGET_OS_CPP_BUILTINS()         \
++  do {                                    \
++    builtin_define ("__adros__");         \
++    builtin_define ("__AdrOS__");         \
++    builtin_define ("__unix__");          \
++    builtin_assert ("system=adros");      \
++    builtin_assert ("system=unix");       \
++    builtin_assert ("system=posix");      \
++  } while (0)
++
++/* Use ELF object format */
++#undef  OBJECT_FORMAT_ELF
++#define OBJECT_FORMAT_ELF 1
++
++/* Default to 32-bit */
++#undef  TARGET_64BIT_DEFAULT
++#define TARGET_64BIT_DEFAULT 0
++
++/* Use crt0.o from libgloss/adros */
++#undef  STARTFILE_SPEC
++#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s"
++
++#undef  ENDFILE_SPEC
++#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
++
++/* Link against Newlib's libc and our libgloss stub library */
++#undef  LIB_SPEC
++#define LIB_SPEC "-lc -ladros -lgcc"
++
++/* Dynamic linker — not used yet (static linking only for now) */
++#undef  LINK_SPEC
++#define LINK_SPEC "-m elf_i386 %{shared:-shared} %{static:-static} %{!static: %{rdynamic:-export-dynamic}}"
++
++/* Use Newlib's stdint types */
++#undef  SIZE_TYPE
++#define SIZE_TYPE "unsigned int"
++
++#undef  PTRDIFF_TYPE
++#define PTRDIFF_TYPE "int"
++
++#undef  WCHAR_TYPE
++#define WCHAR_TYPE "int"
++
++#undef  WCHAR_TYPE_SIZE
++#define WCHAR_TYPE_SIZE 32
+--- a/libgcc/config.host
++++ b/libgcc/config.host
+@@ -685,6 +685,10 @@
+ i[34567]86-*-elf*)
+       tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic"
+       ;;
++i[34567]86-*-adros*)
++      tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic"
++      extra_parts="$extra_parts crti.o crtn.o"
++      ;;
+ x86_64-*-elf* | x86_64-*-rtems*)
+       tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic"
+       ;;
+--- /dev/null
++++ b/libgcc/config/i386/crti-adros.S
+@@ -0,0 +1,14 @@
++/* crti.S for AdrOS — .init/.fini prologue */
++      .section .init
++      .global _init
++      .type _init, @function
++_init:
++      push %ebp
++      mov  %esp, %ebp
++
++      .section .fini
++      .global _fini
++      .type _fini, @function
++_fini:
++      push %ebp
++      mov  %esp, %ebp
+--- /dev/null
++++ b/libgcc/config/i386/crtn-adros.S
+@@ -0,0 +1,10 @@
++/* crtn.S for AdrOS — .init/.fini epilogue */
++      .section .init
++      pop %ebp
++      ret
++
++      .section .fini
++      pop %ebp
++      ret
++
++      .section .note.GNU-stack,"",@progbits
diff --git a/toolchain/patches/newlib-adros.patch b/toolchain/patches/newlib-adros.patch
new file mode 100644 (file)
index 0000000..43fafd9
--- /dev/null
@@ -0,0 +1,146 @@
+--- a/config.sub
++++ b/config.sub
+@@ -1749,6 +1749,9 @@
+       -dicos*)
+               os=-dicos
+               ;;
++      -adros*)
++              os=-adros
++              ;;
+       -nacl*)
+               ;;
+       -ios)
+--- a/newlib/configure.host
++++ b/newlib/configure.host
+@@ -243,6 +243,10 @@
+   i[3-7]86-*-rdos*)
+       sys_dir=rdos
+       ;;
++  i[3-7]86-*-adros*)
++      sys_dir=adros
++      newlib_cflags="${newlib_cflags} -DSIGNAL_PROVIDED -DHAVE_OPENDIR -DHAVE_SYSTEM -DMALLOC_PROVIDED"
++      ;;
+   i[3-7]86-*-netware*)
+       ;;
+   m68k-*-netware*)
+--- a/newlib/libc/include/sys/config.h
++++ b/newlib/libc/include/sys/config.h
+@@ -28,6 +28,14 @@
+ #define __DYNAMIC_REENT__
+ #endif
++/* AdrOS target configuration */
++#ifdef __adros__
++#define _READ_WRITE_RETURN_TYPE int
++#define __DYNAMIC_REENT__
++#define HAVE_SYSTEM
++#define HAVE_OPENDIR
++#endif
++
+ /* RTEMS uses Newlib reentrancy, not dynamic */
+ #ifdef __rtems__
+ #define __DYNAMIC_REENT__
+--- /dev/null
++++ b/newlib/libc/sys/adros/Makefile.am
+@@ -0,0 +1,10 @@
++## AdrOS system directory — empty (syscalls are in libgloss/adros)
++AUTOMAKE_OPTIONS = cygnus
++INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
++AM_CCASFLAGS = $(INCLUDES)
++
++noinst_LIBRARIES = lib.a
++lib_a_SOURCES =
++lib_a_CCASFLAGS = $(AM_CCASFLAGS)
++
++ACLOCAL_AMFLAGS = -I ../../..
+--- /dev/null
++++ b/newlib/libc/sys/adros/configure.in
+@@ -0,0 +1,8 @@
++AC_PREREQ(2.59)
++AC_INIT([newlib],[NEWLIB_VERSION])
++AC_CONFIG_SRCDIR([Makefile.am])
++AC_CANONICAL_SYSTEM
++AM_INIT_AUTOMAKE([cygnus])
++AM_MAINTAINER_MODE
++AC_CONFIG_FILES([Makefile])
++AC_OUTPUT
+--- a/libgloss/configure.in
++++ b/libgloss/configure.in
+@@ -100,6 +100,9 @@
+   i[3-7]86-*-elf* | i[3-7]86-*-coff*)
+       AC_CONFIG_SUBDIRS([i386])
+       ;;
++  i[3-7]86-*-adros*)
++      AC_CONFIG_SUBDIRS([adros])
++      ;;
+   m32r-*-*)
+       AC_CONFIG_SUBDIRS([m32r])
+       ;;
+--- /dev/null
++++ b/libgloss/adros/configure.in
+@@ -0,0 +1,21 @@
++dnl AdrOS libgloss configure
++AC_PREREQ(2.59)
++AC_INIT([libgloss-adros],[0.1])
++AC_CANONICAL_SYSTEM
++AM_INIT_AUTOMAKE([cygnus])
++AM_MAINTAINER_MODE
++
++AC_PROG_CC
++AC_PROG_AS
++AC_PROG_AR
++AC_PROG_RANLIB
++AM_PROG_AS
++
++host_makefile_frag=${srcdir}/../config/default.mh
++AC_SUBST(host_makefile_frag)
++
++AC_CONFIG_FILES([Makefile])
++AC_OUTPUT
+--- /dev/null
++++ b/libgloss/adros/Makefile.in
+@@ -0,0 +1,44 @@
++# Makefile for AdrOS libgloss (autotools-generated template)
++
++srcdir = @srcdir@
++VPATH = @srcdir@
++
++prefix = @prefix@
++exec_prefix = @exec_prefix@
++tooldir = $(exec_prefix)/$(target_alias)
++
++INSTALL = @INSTALL@
++INSTALL_PROGRAM = @INSTALL_PROGRAM@
++INSTALL_DATA = @INSTALL_DATA@
++
++CC = @CC@
++AS = @AS@
++AR = @AR@
++RANLIB = @RANLIB@
++
++CFLAGS = -g
++
++BSP = libadros.a
++OBJS = syscalls.o
++CRT0 = crt0.o
++
++all: $(CRT0) $(BSP)
++
++$(BSP): $(OBJS)
++      $(AR) rcs $@ $^
++      $(RANLIB) $@
++
++crt0.o: crt0.S
++      $(CC) $(CFLAGS) -c $< -o $@
++
++syscalls.o: syscalls.c
++      $(CC) $(CFLAGS) -c $< -o $@
++
++install: all
++      $(INSTALL_DATA) $(CRT0) $(tooldir)/lib/$(CRT0)
++      $(INSTALL_DATA) $(BSP) $(tooldir)/lib/$(BSP)
++
++clean:
++      rm -f $(OBJS) $(CRT0) $(BSP)
++
++.PHONY: all install clean
index a1d6e89fa520c4662710f5d3eda1b00b7a54c44c..e0cd5cba4dffd3fdfc3417b05203eb3123a13899 100644 (file)
@@ -142,6 +142,11 @@ enum {
     SYSCALL_POSIX_SPAWN = 96,
     SYSCALL_SETUID = 76,
     SYSCALL_SETGID = 77,
+    SYSCALL_MOUNT  = 126,
+    SYSCALL_GETTIMEOFDAY = 127,
+    SYSCALL_MPROTECT     = 128,
+    SYSCALL_GETRLIMIT    = 129,
+    SYSCALL_SETRLIMIT    = 130,
 };
 
 enum {
@@ -285,6 +290,23 @@ struct timeval {
     uint32_t tv_usec;
 };
 
+struct rlimit {
+    uint32_t rlim_cur;
+    uint32_t rlim_max;
+};
+
+enum {
+    RLIMIT_CPU    = 0,
+    RLIMIT_FSIZE  = 1,
+    RLIMIT_DATA   = 2,
+    RLIMIT_STACK  = 3,
+    RLIMIT_CORE   = 4,
+    RLIMIT_NOFILE = 5,
+    RLIMIT_AS     = 6,
+    RLIMIT_NPROC  = 7,
+    RLIM_INFINITY = 0xFFFFFFFFU,
+};
+
 struct itimerval {
     struct timeval it_interval;
     struct timeval it_value;
@@ -1313,6 +1335,30 @@ static int sys_sigsuspend(const uint32_t* mask) {
     return __syscall_fix(ret);
 }
 
+static int sys_gettimeofday(struct timeval* tv) {
+    int ret;
+    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_GETTIMEOFDAY), "b"(tv), "c"(0) : "memory");
+    return __syscall_fix(ret);
+}
+
+static int sys_mprotect(uintptr_t addr, uint32_t len, uint32_t prot) {
+    int ret;
+    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_MPROTECT), "b"(addr), "c"(len), "d"(prot) : "memory");
+    return __syscall_fix(ret);
+}
+
+static int sys_getrlimit(int resource, struct rlimit* rlim) {
+    int ret;
+    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_GETRLIMIT), "b"(resource), "c"(rlim) : "memory");
+    return __syscall_fix(ret);
+}
+
+static int sys_setrlimit(int resource, const struct rlimit* rlim) {
+    int ret;
+    __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_SETRLIMIT), "b"(resource), "c"(rlim) : "memory");
+    return __syscall_fix(ret);
+}
+
 __attribute__((noreturn)) static void sys_exit(int code) {
     __asm__ volatile(
         "int $0x80\n"
@@ -4177,6 +4223,71 @@ void _start(void) {
         }
     }
 
+    /* ---- gettimeofday test ---- */
+    {
+        struct timeval tv;
+        tv.tv_sec = 0; tv.tv_usec = 0;
+        int r = sys_gettimeofday(&tv);
+        if (r == 0 && tv.tv_sec > 1000000000U) {
+            static const char msg[] = "[init] gettimeofday OK\n";
+            (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+        } else {
+            static const char msg[] = "[init] gettimeofday failed\n";
+            (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+        }
+    }
+
+    /* ---- mprotect test ---- */
+    {
+        /* Test mprotect on heap memory (brk region) — simpler than mmap */
+        uintptr_t old_brk = sys_brk(0);
+        uintptr_t page = (old_brk + 0xFFFU) & ~(uintptr_t)0xFFFU;
+        uintptr_t new_brk = page + 4096;
+        uintptr_t r_brk = sys_brk(new_brk);
+        if (r_brk >= new_brk) {
+            *(volatile uint32_t*)page = 0xDEADBEEF;
+            int r = sys_mprotect(page, 4096, PROT_READ | PROT_WRITE);
+            if (r == 0) {
+                static const char msg[] = "[init] mprotect OK\n";
+                (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+            } else {
+                static const char msg[] = "[init] mprotect call failed\n";
+                (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+            }
+        } else {
+            static const char msg[] = "[init] mprotect brk failed\n";
+            (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+        }
+    }
+
+    /* ---- getrlimit/setrlimit test ---- */
+    {
+        struct rlimit rl;
+        int r = sys_getrlimit(RLIMIT_NOFILE, &rl);
+        if (r == 0 && rl.rlim_cur > 0 && rl.rlim_cur <= 1024) {
+            /* Try setting a lower soft limit */
+            struct rlimit new_rl;
+            new_rl.rlim_cur = rl.rlim_cur / 2;
+            new_rl.rlim_max = rl.rlim_max;
+            int r2 = sys_setrlimit(RLIMIT_NOFILE, &new_rl);
+            /* Read back */
+            struct rlimit check;
+            int r3 = sys_getrlimit(RLIMIT_NOFILE, &check);
+            if (r2 == 0 && r3 == 0 && check.rlim_cur == new_rl.rlim_cur) {
+                static const char msg[] = "[init] getrlimit/setrlimit OK\n";
+                (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+            } else {
+                static const char msg[] = "[init] setrlimit failed\n";
+                (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+            }
+            /* Restore */
+            (void)sys_setrlimit(RLIMIT_NOFILE, &rl);
+        } else {
+            static const char msg[] = "[init] getrlimit failed\n";
+            (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1));
+        }
+    }
+
     // PIE lazy PLT/GOT binding test
     {
         int pid = sys_fork();
index a94095a0d43ec157070ae0304caa1c9e87bea427..5bf1b098fb6b858b08f2f74afbf4503224413c69 100644 (file)
@@ -11,5 +11,11 @@ static inline int isprint(int c) { return c >= 0x20 && c <= 0x7E; }
 static inline int toupper(int c) { return islower(c) ? c - 32 : c; }
 static inline int tolower(int c) { return isupper(c) ? c + 32 : c; }
 static inline int isxdigit(int c) { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
+static inline int iscntrl(int c) { return (c >= 0 && c < 0x20) || c == 0x7F; }
+static inline int isgraph(int c) { return c > 0x20 && c <= 0x7E; }
+static inline int ispunct(int c) { return isgraph(c) && !isalnum(c); }
+static inline int isascii(int c) { return (unsigned)c <= 0x7F; }
+static inline int isblank(int c) { return c == ' ' || c == '\t'; }
+static inline int toascii(int c) { return c & 0x7F; }
 
 #endif
index a069abea18c2d1b02f4fb8f0699b3fc546c52637..688664232b4b55c047de8075be6d3f47ada64904 100644 (file)
@@ -3,29 +3,49 @@
 
 extern int errno;
 
-#define EPERM    1
-#define ENOENT   2
-#define ESRCH    3
-#define EINTR    4
-#define EIO      5
-#define ENXIO    6
-#define EBADF    9
-#define ECHILD  10
-#define EAGAIN  11
-#define ENOMEM  12
-#define EACCES  13
-#define EFAULT  14
-#define EEXIST  17
-#define ENOTDIR 20
-#define EISDIR  21
-#define EINVAL  22
-#define EMFILE  24
-#define ENOSPC  28
-#define EPIPE   32
-#define ENOSYS  38
-#define ENOTEMPTY 39
-#define ENOLCK   37
-#define EWOULDBLOCK EAGAIN
+#define EPERM            1
+#define ENOENT           2
+#define ESRCH            3
+#define EINTR            4
+#define EIO              5
+#define ENXIO            6
+#define E2BIG            7
+#define EBADF            9
+#define ECHILD          10
+#define EAGAIN          11
+#define ENOMEM          12
+#define EACCES          13
+#define EFAULT          14
+#define EBUSY           16
+#define EEXIST          17
+#define ENODEV          19
+#define ENOTDIR         20
+#define EISDIR          21
+#define EINVAL          22
+#define EMFILE          24
+#define ENOTTY          25
+#define ENOSPC          28
+#define ESPIPE          29
+#define EROFS           30
+#define EPIPE           32
+#define ERANGE          34
+#define ENAMETOOLONG    36
+#define ENOLCK          37
+#define ENOSYS          38
+#define ENOTEMPTY       39
+#define ELOOP           40
+#define EAFNOSUPPORT    47
+#define EADDRINUSE      48
+#define ECONNRESET      54
+#define ENOTCONN        57
+#define ETIMEDOUT       60
+#define ECONNREFUSED    61
+#define EOVERFLOW       75
+#define EMSGSIZE        90
+#define ENOPROTOOPT     92
+#define EPROTONOSUPPORT 93
+#define EOPNOTSUPP      95
+#define EWOULDBLOCK     EAGAIN
 
 /* Convert raw syscall return to errno-style */
 static inline int __syscall_ret(int r) {
index ca73c19924c92cee16bbfce4e40868b6371555ef..2fa5951ce87d1de0958225d79473b945b687b4c8 100644 (file)
 #define SIGVTALRM 26
 #define SIGPROF  27
 
-#define SA_SIGINFO 0x00000004U
+#define SA_RESTART  0x10000000U
+#define SA_SIGINFO  0x00000004U
+#define SA_NOCLDSTOP 0x00000001U
+#define SA_NOCLDWAIT 0x00000002U
+#define SA_NODEFER   0x40000000U
+#define SA_RESETHAND 0x80000000U
+
+#define SIG_ERR ((void (*)(int))-1)
+
+typedef void (*sighandler_t)(int);
+sighandler_t signal(int signum, sighandler_t handler);
 
 #define SIG_DFL ((void (*)(int))0)
 #define SIG_IGN ((void (*)(int))1)