// SPDX-License-Identifier: Apache-2.0 // SchOS — first-party userland runtime: _start entry and exit. #include "types.h" #include "user.h" extern void _xv6_exit(void); void exit(void) { _xv6_exit(); for (;;); } /* _start lives in lib/start.S — it must read incoming registers, which * cannot be expressed portably in C. See that file. */ // The four the compiler is allowed to call without being asked. // // A freestanding build gets no libc, but it does not get a compiler that // promises never to *call* one: the C standard lets an implementation emit // calls to memcpy, memmove, memset and memcmp for things that look nothing // like a function call. A struct assignment is the common one -- // // *out = in; /* struct pciuser_info, 96 bytes */ // // -- which gcc unrolled into stores and clang turned into `call memcpy`, so // ldlsd linked for months and then did not, on a machine where nothing about // it had changed except which compiler ran. The fix is not to avoid struct // assignment; it is to provide the four functions, because the compiler is // within its rights either way. // // Deliberately simple. These are not the hot path of anything here, and a // clever one risks being turned back into a call to itself. void * memcpy(void *dst, const void *src, unsigned long n) { unsigned char *d = dst; const unsigned char *s = src; while (n--) *d++ = *s++; return dst; } void * memmove(void *dst, const void *src, unsigned long n) { unsigned char *d = dst; const unsigned char *s = src; if (d == s || n == 0) return dst; // Backwards when they overlap the wrong way, which is the whole reason // this is not memcpy. if (d < s) { while (n--) *d++ = *s++; } else { d += n; s += n; while (n--) *--d = *--s; } return dst; } void * memset(void *dst, int c, unsigned long n) { unsigned char *d = dst; while (n--) *d++ = (unsigned char)c; return dst; } int memcmp(const void *a, const void *b, unsigned long n) { const unsigned char *p = a, *q = b; while (n--) { if (*p != *q) return *p - *q; p++; q++; } return 0; } void __stack_chk_fail(void) { _xv6_exit(); for (;;); } // exec() without an environment. // // The syscall is execve, three arguments, because that is what Linux numbers // 59 and what musl calls. The two-argument spelling stays because most of // cmd/ has no environment to pass and should not have to say so -- but it // says so *here*, explicitly, rather than leaving %rdx to chance. int exec(char *path, char **argv) { return execve(path, argv, 0); }