feat: POSIX libc surface, native binutils (as/ld/ar run on MontaukOS)
Grow the Montauk libc enough to cross-build binutils 2.43.1 with --host=x86_64-montauk. gas, ld, ar, nm, objcopy, objdump, readelf, ranlib, strip and friends now link as native ET_EXEC Montauk binaries (staged stripped in toolchain/native/, not yet shipped in the image). New libc surface: full Linux errno and signal sets, O_* flags with real O_EXCL/O_APPEND semantics, unlink/rmdir/dup/dup2/getpid/_exit, kill (SYS_KILL), fcntl, fileno/fdopen, putc/getchar/rewind, ctime/asctime, strtoll/strtoull/atoll, bsearch, mkstemp/mktemp, realpath (lexical, drive-prefix aware), mbstowcs/mblen, chmod/fchmod/ umask/utime no-ops (VFS has no modes or settable times), full struct stat with fake inodes, sscanf field widths (bounded conversions), SCN*/PRI* completions, wait/waitpid over SYS_WAITPID, and new headers sys/wait.h, sys/param.h, utime.h, wchar.h, memory.h. fork/exec/pipe are declared but fail with ENOSYS: binutils never spawns, and real process plumbing is the posix_spawn milestone, which needs kernel support (exit status reporting, fd redirection). TCC's montauk_compat.h shims (unlink, chmod, execvp, realpath, fdopen, strtoll, strtoull) are retired in favor of the libc versions. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -9,18 +9,48 @@ extern "C" {
|
||||
|
||||
extern int errno;
|
||||
|
||||
#define ENOENT 2
|
||||
#define EIO 5
|
||||
#define ENOMEM 12
|
||||
#define EACCES 13
|
||||
#define EINVAL 22
|
||||
#define ERANGE 34
|
||||
#define ENOSYS 38
|
||||
#define EISDIR 21
|
||||
#define ENOTDIR 20
|
||||
#define EEXIST 17
|
||||
#define EBADF 9
|
||||
#define EPERM 1
|
||||
/* Linux errno numbering. */
|
||||
#define EPERM 1
|
||||
#define ENOENT 2
|
||||
#define ESRCH 3
|
||||
#define EINTR 4
|
||||
#define EIO 5
|
||||
#define ENXIO 6
|
||||
#define E2BIG 7
|
||||
#define ENOEXEC 8
|
||||
#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 EXDEV 18
|
||||
#define ENODEV 19
|
||||
#define ENOTDIR 20
|
||||
#define EISDIR 21
|
||||
#define EINVAL 22
|
||||
#define ENFILE 23
|
||||
#define EMFILE 24
|
||||
#define ENOTTY 25
|
||||
#define EFBIG 27
|
||||
#define ENOSPC 28
|
||||
#define ESPIPE 29
|
||||
#define EROFS 30
|
||||
#define EMLINK 31
|
||||
#define EPIPE 32
|
||||
#define EDOM 33
|
||||
#define ERANGE 34
|
||||
#define EDEADLK 35
|
||||
#define ENAMETOOLONG 36
|
||||
#define ENOLCK 37
|
||||
#define ENOSYS 38
|
||||
#define ENOTEMPTY 39
|
||||
#define ELOOP 40
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
#define EOVERFLOW 75
|
||||
#define ETIMEDOUT 110
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -7,13 +7,27 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define O_RDONLY 0
|
||||
#define O_WRONLY 1
|
||||
#define O_RDWR 2
|
||||
#define O_CREAT 0x40
|
||||
#define O_TRUNC 0x200
|
||||
#define O_RDONLY 0
|
||||
#define O_WRONLY 1
|
||||
#define O_RDWR 2
|
||||
#define O_ACCMODE 3
|
||||
#define O_CREAT 0x40
|
||||
#define O_EXCL 0x80
|
||||
#define O_TRUNC 0x200
|
||||
#define O_APPEND 0x400
|
||||
#define O_NONBLOCK 0x800
|
||||
#define O_CLOEXEC 0x80000
|
||||
|
||||
#define F_DUPFD 0
|
||||
#define F_GETFD 1
|
||||
#define F_SETFD 2
|
||||
#define F_GETFL 3
|
||||
#define F_SETFL 4
|
||||
|
||||
#define FD_CLOEXEC 1
|
||||
|
||||
int open(const char *path, int flags, ...);
|
||||
int fcntl(int fd, int cmd, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -23,5 +23,38 @@
|
||||
#define PRIX16 "X"
|
||||
#define PRIX32 "X"
|
||||
#define PRIX64 "lX"
|
||||
#define PRIo8 "o"
|
||||
#define PRIo16 "o"
|
||||
#define PRIo32 "o"
|
||||
#define PRIo64 "lo"
|
||||
|
||||
#define PRIdPTR "ld"
|
||||
#define PRIiPTR "li"
|
||||
#define PRIuPTR "lu"
|
||||
#define PRIxPTR "lx"
|
||||
#define PRIXPTR "lX"
|
||||
#define PRIdMAX "ld"
|
||||
#define PRIuMAX "lu"
|
||||
#define PRIxMAX "lx"
|
||||
|
||||
#define SCNd8 "d"
|
||||
#define SCNd16 "d"
|
||||
#define SCNd32 "d"
|
||||
#define SCNd64 "ld"
|
||||
#define SCNi8 "i"
|
||||
#define SCNi16 "i"
|
||||
#define SCNi32 "i"
|
||||
#define SCNi64 "li"
|
||||
#define SCNu8 "u"
|
||||
#define SCNu16 "u"
|
||||
#define SCNu32 "u"
|
||||
#define SCNu64 "lu"
|
||||
#define SCNx8 "x"
|
||||
#define SCNx16 "x"
|
||||
#define SCNx32 "x"
|
||||
#define SCNx64 "lx"
|
||||
#define SCNdPTR "ld"
|
||||
#define SCNuPTR "lu"
|
||||
#define SCNxPTR "lx"
|
||||
|
||||
#endif /* _LIBC_INTTYPES_H */
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _LIBC_MEMORY_H
|
||||
#define _LIBC_MEMORY_H
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Traditional alias for string.h. */
|
||||
#include <string.h>
|
||||
|
||||
#endif /* _LIBC_MEMORY_H */
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -10,7 +12,26 @@ extern "C" {
|
||||
typedef int sig_atomic_t;
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
#define SIGINT 2
|
||||
/* Linux signal numbering. Only SIGINT is ever delivered today; the
|
||||
rest exist so hosted code can name them. */
|
||||
#define SIGHUP 1
|
||||
#define SIGINT 2
|
||||
#define SIGQUIT 3
|
||||
#define SIGILL 4
|
||||
#define SIGTRAP 5
|
||||
#define SIGABRT 6
|
||||
#define SIGBUS 7
|
||||
#define SIGFPE 8
|
||||
#define SIGKILL 9
|
||||
#define SIGUSR1 10
|
||||
#define SIGSEGV 11
|
||||
#define SIGUSR2 12
|
||||
#define SIGPIPE 13
|
||||
#define SIGALRM 14
|
||||
#define SIGTERM 15
|
||||
#define SIGCHLD 17
|
||||
#define SIGCONT 18
|
||||
#define SIGSTOP 19
|
||||
|
||||
#define SIG_DFL ((sighandler_t)0)
|
||||
#define SIG_IGN ((sighandler_t)1)
|
||||
@@ -18,6 +39,7 @@ typedef void (*sighandler_t)(int);
|
||||
|
||||
sighandler_t signal(int sig, sighandler_t handler);
|
||||
int raise(int sig);
|
||||
int kill(pid_t pid, int sig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ extern FILE *stdin;
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
|
||||
int putc(int c, FILE *stream);
|
||||
void rewind(FILE *stream);
|
||||
int getchar(void);
|
||||
int fileno(FILE *stream);
|
||||
FILE *fdopen(int fd, const char *mode);
|
||||
|
||||
int printf(const char *fmt, ...);
|
||||
int fprintf(FILE *stream, const char *fmt, ...);
|
||||
int sprintf(char *str, const char *fmt, ...);
|
||||
|
||||
@@ -49,10 +49,20 @@ int unsetenv(const char *name);
|
||||
int putenv(char *string);
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t size,
|
||||
int (*compar)(const void *, const void *));
|
||||
int (*compar)(const void *, const void *));
|
||||
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int (*compar)(const void *, const void *));
|
||||
|
||||
long strtol(const char *nptr, char **endptr, int base);
|
||||
unsigned long strtoul(const char *nptr, char **endptr, int base);
|
||||
long long strtoll(const char *nptr, char **endptr, int base);
|
||||
unsigned long long strtoull(const char *nptr, char **endptr, int base);
|
||||
long long atoll(const char *nptr);
|
||||
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);
|
||||
int mblen(const char *s, size_t n);
|
||||
double strtod(const char *nptr, char **endptr);
|
||||
float strtof(const char *nptr, char **endptr);
|
||||
long double strtold(const char *nptr, char **endptr);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef _LIBC_SYS_PARAM_H
|
||||
#define _LIBC_SYS_PARAM_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
#define MAXPATHLEN 4096
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
|
||||
#endif /* _LIBC_SYS_PARAM_H */
|
||||
@@ -12,19 +12,54 @@ extern "C" {
|
||||
#define S_IFMT 0170000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFLNK 0120000
|
||||
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISFIFO(mode) (0)
|
||||
#define S_ISSOCK(mode) (0)
|
||||
#define S_ISBLK(mode) (0)
|
||||
|
||||
/* Permission bits are accepted and preserved by the API for POSIX
|
||||
compatibility, but the Montauk VFS does not store them. */
|
||||
#define S_IRWXU 0700
|
||||
#define S_IRUSR 0400
|
||||
#define S_IWUSR 0200
|
||||
#define S_IXUSR 0100
|
||||
#define S_IRWXG 0070
|
||||
#define S_IRGRP 0040
|
||||
#define S_IWGRP 0020
|
||||
#define S_IXGRP 0010
|
||||
#define S_IRWXO 0007
|
||||
#define S_IROTH 0004
|
||||
#define S_IWOTH 0002
|
||||
#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;
|
||||
};
|
||||
|
||||
int mkdir(const char *path, unsigned int mode);
|
||||
int stat(const char *path, struct stat *buf);
|
||||
int fstat(int fd, struct stat *buf);
|
||||
int mkdir(const char *path, unsigned int mode);
|
||||
int stat(const char *path, struct stat *buf);
|
||||
int fstat(int fd, struct stat *buf);
|
||||
int lstat(const char *path, struct stat *buf);
|
||||
int chmod(const char *path, mode_t mode);
|
||||
int fchmod(int fd, mode_t mode);
|
||||
mode_t umask(mode_t mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _LIBC_SYS_WAIT_H
|
||||
#define _LIBC_SYS_WAIT_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Status decoding. The Montauk kernel does not yet report exit codes
|
||||
through SYS_WAITPID, so waited children always decode as exit 0. */
|
||||
#define WIFEXITED(s) (((s) & 0x7F) == 0)
|
||||
#define WEXITSTATUS(s) (((s) >> 8) & 0xFF)
|
||||
#define WIFSIGNALED(s) (0)
|
||||
#define WTERMSIG(s) (0)
|
||||
#define WIFSTOPPED(s) (0)
|
||||
#define WSTOPSIG(s) (0)
|
||||
|
||||
#define WNOHANG 1
|
||||
#define WUNTRACED 2
|
||||
|
||||
pid_t wait(int *status);
|
||||
pid_t waitpid(pid_t pid, int *status, int options);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBC_SYS_WAIT_H */
|
||||
@@ -34,6 +34,9 @@ struct tm *localtime(const time_t *timer);
|
||||
time_t mktime(struct tm *tm);
|
||||
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
|
||||
|
||||
char *asctime(const struct tm *tm);
|
||||
char *ctime(const time_t *timep);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
|
||||
#define F_OK 0
|
||||
#define X_OK 1
|
||||
#define W_OK 2
|
||||
@@ -22,6 +27,19 @@ int chdir(const char *path);
|
||||
char *getcwd(char *buf, size_t size);
|
||||
int access(const char *path, int mode);
|
||||
int isatty(int fd);
|
||||
int unlink(const char *path);
|
||||
int rmdir(const char *path);
|
||||
int dup(int fd);
|
||||
int dup2(int oldfd, int newfd);
|
||||
pid_t getpid(void);
|
||||
void _exit(int status) __attribute__((noreturn));
|
||||
pid_t fork(void);
|
||||
int execv(const char *path, char *const argv[]);
|
||||
int execve(const char *path, char *const argv[], char *const envp[]);
|
||||
int execvp(const char *file, char *const argv[]);
|
||||
int pipe(int fds[2]);
|
||||
|
||||
extern char **environ;
|
||||
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef _LIBC_UTIME_H
|
||||
#define _LIBC_UTIME_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
|
||||
/* Accepted for POSIX compatibility; the Montauk VFS does not support
|
||||
setting file times. */
|
||||
int utime(const char *path, const struct utimbuf *times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBC_UTIME_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef _LIBC_WCHAR_H
|
||||
#define _LIBC_WCHAR_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned int wint_t;
|
||||
|
||||
#define WEOF ((wint_t)-1)
|
||||
|
||||
/* Byte-oriented C locale only: one byte, one character. */
|
||||
size_t mbstowcs(wchar_t *dst, const char *src, size_t n);
|
||||
int mblen(const char *s, size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBC_WCHAR_H */
|
||||
Reference in New Issue
Block a user