From 642e9cb91a5ea672b7d3df602be6f9bf1b2e40c0 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 26 Jul 2024 05:10:25 -0700 Subject: [PATCH] Introduce cosmocc flags -mdbg -mtiny -moptlinux The cosmocc.zip toolchain will now include four builds of the libcosmo.a runtime libraries. You can pass the -mdbg flag if you want to debug your cosmopolitan runtime. You can pass the -moptlinux flag if you don't want windows code lurking in your binary. See tool/cosmocc/README.md for more details on how these flags may be used and their important implications. --- build/config.mk | 36 ++++++++++-- libc/calls/tcflush.c | 6 +- libc/dlopen/dlopen.c | 2 + libc/intrin/cp.c | 9 ++- libc/log/oncrash_arm64.c | 3 +- libc/nexgen32e/nt2sysv.h | 4 ++ libc/proc/posix_spawn.c | 12 +++- libc/runtime/clone.c | 2 + libc/runtime/stack.h | 4 ++ libc/sysv/BUILD.mk | 2 +- libc/sysv/sysv.c | 6 +- libc/tinymath/powl.c | 2 +- test/ctl/string_bench.cc | 47 ++++++++------- test/tool/viz/lib/fun_test.c | 2 +- third_party/nsync/futex.c | 4 ++ third_party/python/BUILD.mk | 2 + tool/build/compile.c | 4 ++ tool/build/pledge.c | 4 ++ tool/cosmocc/README.md | 110 +++++++++++++++++++++++++++++++++++ tool/cosmocc/bin/cosmocc | 56 ++++++++++++++---- tool/cosmocc/bin/cosmocross | 48 ++++++++++++--- tool/cosmocc/package.sh | 95 ++++++++++++++++++++++++++++++ 22 files changed, 404 insertions(+), 56 deletions(-) diff --git a/build/config.mk b/build/config.mk index 81ee8b711..4fe9d362b 100644 --- a/build/config.mk +++ b/build/config.mk @@ -102,6 +102,19 @@ CONFIG_CCFLAGS += -O3 -fmerge-all-constants CONFIG_COPTS += -mred-zone TARGET_ARCH ?= -march=native endif +ifeq ($(MODE), x86_64-optlinux) +CONFIG_OFLAGS ?= -g -ggdb +CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1 +CONFIG_CCFLAGS += -O3 -fmerge-all-constants +CONFIG_COPTS += -mred-zone +TARGET_ARCH ?= -march=native +endif +ifeq ($(MODE), aarch64-optlinux) +CONFIG_OFLAGS ?= -g -ggdb +CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1 +CONFIG_CCFLAGS += -O3 -fmerge-all-constants +CONFIG_COPTS += -mred-zone +endif # Release Mode # @@ -136,8 +149,21 @@ endif ifeq ($(MODE), dbg) ENABLE_FTRACE = 1 CONFIG_OFLAGS ?= -g -ggdb -CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline +OVERRIDE_CFLAGS += -O0 +OVERRIDE_CXXFLAGS += -O0 +CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable +CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG +CONFIG_COPTS += -fsanitize=undefined +OVERRIDE_CCFLAGS += -fno-pie +QUOTA ?= -C64 -L300 +endif +ifeq ($(MODE), x86_64-dbg) +ENABLE_FTRACE = 1 +CONFIG_OFLAGS ?= -g -ggdb +OVERRIDE_CFLAGS += -O0 +OVERRIDE_CXXFLAGS += -O0 +CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable +CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG CONFIG_COPTS += -fsanitize=undefined OVERRIDE_CCFLAGS += -fno-pie QUOTA ?= -C64 -L300 @@ -145,8 +171,10 @@ endif ifeq ($(MODE), aarch64-dbg) ENABLE_FTRACE = 1 CONFIG_OFLAGS ?= -g -ggdb -CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline -fdce +OVERRIDE_CFLAGS += -O0 -fdce +OVERRIDE_CXXFLAGS += -O0 -fdce +CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable +CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG CONFIG_COPTS += -fsanitize=undefined QUOTA ?= -C64 -L300 endif diff --git a/libc/calls/tcflush.c b/libc/calls/tcflush.c index 3802897b6..e9a171b20 100644 --- a/libc/calls/tcflush.c +++ b/libc/calls/tcflush.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" -#include "libc/intrin/fds.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-nt.internal.h" @@ -25,6 +24,7 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/fds.h" #include "libc/intrin/strace.h" #include "libc/mem/alloca.h" #include "libc/nt/comms.h" @@ -52,6 +52,7 @@ static const char *DescribeFlush(char buf[12], int action) { } static dontinline textwindows int sys_tcflush_nt(int fd, int queue) { +#ifdef __x86_64__ if (!sys_isatty(fd)) { return -1; // ebadf, enotty } @@ -59,6 +60,9 @@ static dontinline textwindows int sys_tcflush_nt(int fd, int queue) { return 0; // windows console output is never buffered } return FlushConsoleInputBytes(); +#else + return enosys(); +#endif } /** diff --git a/libc/dlopen/dlopen.c b/libc/dlopen/dlopen.c index 99c648776..84f6d0083 100644 --- a/libc/dlopen/dlopen.c +++ b/libc/dlopen/dlopen.c @@ -557,7 +557,9 @@ static void *foreign_thunk_nt(void *func) { // movabs $tramp,%r10 code[14] = 0x49; code[15] = 0xba; +#ifdef __x86_64__ WRITE64LE(code + 16, (uintptr_t)__sysv2nt14); +#endif // jmp *%r10 code[24] = 0x41; code[25] = 0xff; diff --git a/libc/intrin/cp.c b/libc/intrin/cp.c index 5f4061033..d65670cee 100644 --- a/libc/intrin/cp.c +++ b/libc/intrin/cp.c @@ -18,6 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/blockcancel.internal.h" #include "libc/calls/cp.internal.h" +#include "libc/intrin/describebacktrace.h" +#include "libc/intrin/kprintf.h" +#include "libc/nexgen32e/stackframe.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/thread/posixthread.internal.h" @@ -46,7 +49,11 @@ void end_cancelation_point(int state) { } } -void report_cancelation_point(void) { +void report_cancelation_point(int sysv_ordinal, int xnu_ordinal) { + char bt[160]; + struct StackFrame *bp = __builtin_frame_address(0); + kprintf("error: report_cancelation_point(%#x, %#x) %s\n", sysv_ordinal, + xnu_ordinal, (DescribeBacktrace)(bt, bp)); __builtin_trap(); } diff --git a/libc/log/oncrash_arm64.c b/libc/log/oncrash_arm64.c index 83a347a75..d22062c71 100644 --- a/libc/log/oncrash_arm64.c +++ b/libc/log/oncrash_arm64.c @@ -266,7 +266,8 @@ static relegated void __oncrash_impl(int sig, siginfo_t *si, ucontext_t *ctx) { if (j) Append(b, " "); Append(b, "%s%016lx%s x%d%s", ColorRegister(r), - ctx->uc_mcontext.regs[r], reset, r, r == 8 || r == 9 ? " " : ""); + ((uint64_t *)ctx->uc_mcontext.regs)[r], reset, r, + r == 8 || r == 9 ? " " : ""); } Append(b, "\n"); } diff --git a/libc/nexgen32e/nt2sysv.h b/libc/nexgen32e/nt2sysv.h index 4b9373325..6afb40234 100644 --- a/libc/nexgen32e/nt2sysv.h +++ b/libc/nexgen32e/nt2sysv.h @@ -7,6 +7,10 @@ * * This macro should be used when specifying callbacks in the WIN32 API. */ +#ifdef __x86_64__ #define NT2SYSV(FUNCTION) TRAMPOLINE(FUNCTION, __nt2sysv) +#else +#define NT2SYSV(FUNCTION) FUNCTION +#endif #endif /* COSMOPOLITAN_LIBC_NEXGEN32E_NT2SYSV_H_ */ diff --git a/libc/proc/posix_spawn.c b/libc/proc/posix_spawn.c index a7209abac..467c791be 100644 --- a/libc/proc/posix_spawn.c +++ b/libc/proc/posix_spawn.c @@ -22,7 +22,6 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/state.internal.h" -#include "libc/intrin/fds.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rlimit.internal.h" #include "libc/calls/struct/rusage.internal.h" @@ -39,6 +38,7 @@ #include "libc/intrin/bsf.h" #include "libc/intrin/describeflags.h" #include "libc/intrin/dll.h" +#include "libc/intrin/fds.h" #include "libc/intrin/strace.h" #include "libc/intrin/weaken.h" #include "libc/mem/alloca.h" @@ -95,6 +95,10 @@ #define CLOSER_CONTAINER(e) DLL_CONTAINER(struct Closer, elem, e) +static atomic_bool has_vfork; // i.e. not qemu/wsl/xnu/openbsd + +#ifdef __x86_64__ + struct Closer { int64_t handle; struct Dll elem; @@ -106,8 +110,6 @@ struct SpawnFds { struct Dll *closers; }; -static atomic_bool has_vfork; // i.e. not qemu/wsl/xnu/openbsd - static textwindows int64_t spawnfds_handle(struct SpawnFds *fds, int fd) { if (__is_cloexec(fds->p + fd)) return -1; @@ -429,6 +431,8 @@ static textwindows dontinline errno_t posix_spawn_nt( return err; } +#endif // __x86_64__ + /** * Spawns process, the POSIX way, e.g. * @@ -482,8 +486,10 @@ errno_t posix_spawn(int *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { +#ifdef __x86_64__ if (IsWindows()) return posix_spawn_nt(pid, path, file_actions, attrp, argv, envp); +#endif int pfds[2]; bool use_pipe; volatile int status = 0; diff --git a/libc/runtime/clone.c b/libc/runtime/clone.c index 46347d47b..1da1ffc03 100644 --- a/libc/runtime/clone.c +++ b/libc/runtime/clone.c @@ -589,7 +589,9 @@ int sys_clone_linux(int flags, // rdi static int LinuxThreadEntry(void *arg, int tid) { struct LinuxCloneArgs *wt = arg; +#if defined(__x86_64__) sys_set_tls(ARCH_SET_GS, wt->tls); +#endif return wt->func(wt->arg, tid); } diff --git a/libc/runtime/stack.h b/libc/runtime/stack.h index 8a8c5d934..87dcd2440 100644 --- a/libc/runtime/stack.h +++ b/libc/runtime/stack.h @@ -6,7 +6,11 @@ /** * Returns preferred size and alignment of thread stack. */ +#ifndef MODE_DBG #define GetStackSize() 81920 +#else +#define GetStackSize() 163840 +#endif /** * Returns preferred stack guard size. diff --git a/libc/sysv/BUILD.mk b/libc/sysv/BUILD.mk index ec1b3b1fb..f9bd91985 100644 --- a/libc/sysv/BUILD.mk +++ b/libc/sysv/BUILD.mk @@ -88,7 +88,7 @@ o/$(MODE)/libc/sysv/sysret.o: private \ ifeq ($(ARCH),aarch64) o/$(MODE)/libc/sysv/sysv.o: private \ - CFLAGS += \ + OVERRIDE_CFLAGS += \ -ffixed-x0 \ -ffixed-x1 \ -ffixed-x2 \ diff --git a/libc/sysv/sysv.c b/libc/sysv/sysv.c index afb3496b8..8c78202bf 100644 --- a/libc/sysv/sysv.c +++ b/libc/sysv/sysv.c @@ -37,7 +37,7 @@ register long freebsd_ordinal asm("x9"); register long xnu_ordinal asm("x16"); register long cosmo_tls_register asm("x28"); -void report_cancelation_point(void); +void report_cancelation_point(int, int); dontinline long systemfive_cancel(void) { return _weaken(_pthread_cancel_ack)(); @@ -58,9 +58,9 @@ dontinline long systemfive_cancellable(void) { return systemfive_cancel(); } #if IsModeDbg() - if (!(pth->pt_flags & PT_INCANCEL)) { + if (!(pth->pt_flags & PT_INCANCEL) && !(pth->pt_flags & PT_NOCANCEL)) { if (_weaken(report_cancelation_point)) { - _weaken(report_cancelation_point)(); + _weaken(report_cancelation_point)(sysv_ordinal, xnu_ordinal); } __builtin_trap(); } diff --git a/libc/tinymath/powl.c b/libc/tinymath/powl.c index 3ed4cd9e4..0e015082d 100644 --- a/libc/tinymath/powl.c +++ b/libc/tinymath/powl.c @@ -930,7 +930,7 @@ powl(long double x, long double y) z = one - (r - z); o.value = z; j = o.parts32.mswhi; - j += (n << 16); + j += (int32_t)((uint32_t)n << 16); // TODO(jart): why ubsan if ((j >> 16) <= 0) z = scalbnl (z, n); /* subnormal output */ else diff --git a/test/ctl/string_bench.cc b/test/ctl/string_bench.cc index b7b30c935..c14c83927 100644 --- a/test/ctl/string_bench.cc +++ b/test/ctl/string_bench.cc @@ -18,6 +18,7 @@ #include "ctl/string.h" #include "ctl/utility.h" +#include "libc/dce.h" #include "libc/mem/leaks.h" #include "libc/calls/struct/timespec.h" @@ -43,103 +44,109 @@ const char* big_c = "aaaaaaaaaaaaaaaaaaaaaaaa"; const char* small_c = "aaaaaaaaaaaaaaaaaaaaaaa"; +#if IsModeDbg() +#define ITERATIONS 1000 // because qemu in dbg mode is very slow +#else +#define ITERATIONS 1000000 +#endif + int main() { const ctl::string_view big(big_c), small(small_c); - BENCH(10000000, 1, { + BENCH(ITERATIONS * 10, 1, { ctl::string s; s.append("hello "); s.append("world"); }); - BENCH(1000000, 8, { + BENCH(ITERATIONS, 8, { ctl::string s; for (int i = 0; i < 8; ++i) { s.append('a'); } }); - BENCH(1000000, 16, { + BENCH(ITERATIONS, 16, { ctl::string s; for (int i = 0; i < 16; ++i) { s.append('a'); } }); - BENCH(1000000, 23, { + BENCH(ITERATIONS, 23, { ctl::string s; for (int i = 0; i < 23; ++i) { s.append('a'); } }); - BENCH(1000000, 24, { + BENCH(ITERATIONS, 24, { ctl::string s; for (int i = 0; i < 24; ++i) { s.append('a'); } }); - BENCH(1000000, 32, { + BENCH(ITERATIONS, 32, { ctl::string s; for (int i = 0; i < 32; ++i) { s.append('a'); } }); - BENCH(1000000, 1, { ctl::string s(small_c); }); + BENCH(ITERATIONS, 1, { ctl::string s(small_c); }); - BENCH(1000000, 1, { ctl::string s(small); }); + BENCH(ITERATIONS, 1, { ctl::string s(small); }); { ctl::string small_copy("hello world"); - BENCH(1000000, 1, { ctl::string s2(small_copy); }); + BENCH(ITERATIONS, 1, { ctl::string s2(small_copy); }); } - BENCH(1000000, 1, { + BENCH(ITERATIONS, 1, { ctl::string s(small); ctl::string s2(ctl::move(s)); }); - BENCH(1000000, 1, { + BENCH(ITERATIONS, 1, { ctl::string s(small); ctl::string s2(s); }); - BENCH(1000000, 1, { ctl::string s(big_c); }); + BENCH(ITERATIONS, 1, { ctl::string s(big_c); }); - BENCH(1000000, 1, { ctl::string s(big); }); + BENCH(ITERATIONS, 1, { ctl::string s(big); }); { ctl::string big_copy(big); - BENCH(1000000, 1, { ctl::string s2(big_copy); }); + BENCH(ITERATIONS, 1, { ctl::string s2(big_copy); }); } - BENCH(1000000, 1, { + BENCH(ITERATIONS, 1, { ctl::string s(big); ctl::string s2(ctl::move(s)); }); - BENCH(1000000, 1, { + BENCH(ITERATIONS, 1, { ctl::string s(big); ctl::string s2(s); }); - BENCH(1000000, 1, { ctl::string s(23, 'a'); }); + BENCH(ITERATIONS, 1, { ctl::string s(23, 'a'); }); - BENCH(1000000, 1, { ctl::string s(24, 'a'); }); + BENCH(ITERATIONS, 1, { ctl::string s(24, 'a'); }); { ctl::string s(5, 'a'); - BENCH(1000000, 1, { ctl::string_view s2(s); }); + BENCH(ITERATIONS, 1, { ctl::string_view s2(s); }); } { ctl::string big_trunc(48, 'a'); big_trunc.resize(4); - BENCH(1000000, 1, { ctl::string s(big_trunc); }); + BENCH(ITERATIONS, 1, { ctl::string s(big_trunc); }); } CheckForMemoryLeaks(); diff --git a/test/tool/viz/lib/fun_test.c b/test/tool/viz/lib/fun_test.c index dc5340631..11315a9dc 100644 --- a/test/tool/viz/lib/fun_test.c +++ b/test/tool/viz/lib/fun_test.c @@ -212,7 +212,7 @@ void ExpandLuminosityRange(unsigned n, unsigned char *Y) { } TEST(ExpandLuminosityRange, test) { - unsigned char Y[32]; + _Alignas(16) unsigned char Y[32]; Y[0] = 0; ExpandLuminosityRange(16, Y); EXPECT_EQ(0, Y[0]); diff --git a/third_party/nsync/futex.c b/third_party/nsync/futex.c index 9a0f264a5..ce34af900 100644 --- a/third_party/nsync/futex.c +++ b/third_party/nsync/futex.c @@ -152,6 +152,7 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare, const struct timespec *timeout, struct PosixThread *pt, sigset_t waitmask) { +#ifdef __x86_64__ int sig; bool32 ok; struct timespec deadline, wait, now; @@ -203,6 +204,9 @@ static int nsync_futex_wait_win32_ (atomic_int *w, int expect, char pshare, ASSERT (GetLastError () == ETIMEDOUT); } } +#else + return 0; +#endif /* __x86_64__ */ } static struct timespec *nsync_futex_timeout_ (struct timespec *memory, diff --git a/third_party/python/BUILD.mk b/third_party/python/BUILD.mk index 1fe2638b9..84a2c278e 100644 --- a/third_party/python/BUILD.mk +++ b/third_party/python/BUILD.mk @@ -34,6 +34,7 @@ THIRD_PARTY_PYTHON_CHECKS = \ # TODO: Deal with aarch64 under qemu not making execve() easy. ifneq ($(MODE), dbg) +ifneq ($(MODE), x86_64-dbg) ifeq ($(ARCH), x86_64) ifneq ($(UNAME_S), Windows) THIRD_PARTY_PYTHON_CHECKS += \ @@ -41,6 +42,7 @@ THIRD_PARTY_PYTHON_CHECKS += \ endif endif endif +endif ################################################################################ # STAGE ONE - BOOTSTRAPPING PYTHON diff --git a/tool/build/compile.c b/tool/build/compile.c index 68cc4c9ee..62c44d41c 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -516,7 +516,11 @@ void AddArg(char *actual) { } static int GetBaseCpuFreqMhz(void) { +#ifdef __x86_64__ return KCPUIDS(16H, EAX) & 0x7fff; +#else + return 0; +#endif } void PlanResource(int resource, struct rlimit rlim) { diff --git a/tool/build/pledge.c b/tool/build/pledge.c index e7335b92d..f77306629 100644 --- a/tool/build/pledge.c +++ b/tool/build/pledge.c @@ -373,7 +373,11 @@ int SetLimit(int r, long lo, long hi) { } static int GetBaseCpuFreqMhz(void) { +#ifdef __x86_64__ return KCPUIDS(16H, EAX) & 0x7fff; +#else + return 0; +#endif } int SetCpuLimit(int secs) { diff --git a/tool/cosmocc/README.md b/tool/cosmocc/README.md index 489cee109..762fbcac6 100644 --- a/tool/cosmocc/README.md +++ b/tool/cosmocc/README.md @@ -142,6 +142,116 @@ and AARCH64, which is K8 and ARMv8.0. You can pass architecture specific flags to use newer ISAs by using the `-Xx86_64` and `-Xaarch64` prefixes like `-Xx86_64-mssse3` and `-Xaarch64-march=armv8.2-a+dotprod`. +## Flags + +The following supplemental flags are defined by cosmocc: + +- `-mcosmo` causes `_COSMO_SOURCE` to be defined. This has a similar + effect to defining `_GNU_SOURCE`. When you use this flag, many + non-standard GNU, BSD, and Cosmo Libc APIs will become visible in + headers, e.g. `stdlib.h` will now define `ShowCrashReports()`. + Including `cosmo.h` has a similar effect, however it's recommended + that any program that uses cosmo-specific APIs pass this flag. + +- `-mdbg` may be passed when linking programs. It has the same effect as + `export MODE=dbg` in that it will cause an alternative build of the + Cosmopolitan Libc runtime to be linked that was built with `-O0 -g`. + Under the normal build mode, `--ftrace` output is oftentimes missing + important pieces of the puzzle due to inlining. This mode makes it + more comprehensible. It's also the only way to make using GDB to + troubleshoot issues inside Cosmo Libc work reliably. Please be warned + that this flag may enable some heavyweight runtime checks. For + example, mmap() will become O(n) rather than O(logn) in an effort to + spot data structure corruption. Lastly, the linked Cosmo runtime was + compiled with `-fsanitize=undefined` (UBSAN) although you still need + to pass that flag too if you want it for your own code. + +- `-mtiny` may be passed when linking programs. It has the same effect + as `export MODE=tiny` in that it will cause an alternative build of + the Cosmopolitan Libc runtime to be linked that's optimized for code + size. In the normal build mode, the smallest possible binary size will + be on the order of hundreds of kb, due to heavyweight features like + `--ftrace` and `--strace` being part of the mandatory runtime. Those + features don't exist in the tiny runtime, which should produce ~147kb + fat binaries and ~36kb x86-only binaries. You may also use this flag + when compiling objects. Since there's no function tracing, using this + will eliminate the NOPs that get inserted into the prologues of your + functions to make them hookable, which also greatly reduces code size. + Please note that this does not specify an `-O` flag, so you may want + to pass `-Os` too. Please note that this mode is granted leeway to + trade away performance whenever possible. Functions like memmove() + will stop using fancy vectorization which can dramatically decrease + the performance of certain use cases. malloc() will stop using cookies + which add bloat but are considered important by some people for both + security and reporting errors on corruption. APIs will also begin + refraining from detecting usage errors that are the fault of the + caller, so this mode isn't recommended for development. + +- `-moptlinux` uses the optimized Linux-only version of Cosmopolitan + Libc runtime libraries. Your program will only be able to run on + Linux. The runtime is compiled at `-O3` although it still supports AMD + K8+ (c. 2003). Optimizations like red zone that wouldn't otherwise be + possible are enabled. Function call tracing and system call logging is + disabled. All the Windows polyfills go away and your binaries will be + significantly tinier. The `cosmocc` compiler will generate a shell + script with the magic `jartsr='` so you won't get unwanted attention + from Windows virus scanners. You're even allowed to use flags like + `-fomit-frame-pointer` when you use this mode. Users report optlinux + has helped them make the Python interpreter 5% faster, like distros, + optlinux will salt the earth if it gains a 1% advantage on benchmark + games. Therefore this mode gives you an apples-to-apples comparison + between cosmocc versus the gcc/clang configs used by linux distros. + +## Raw Toolchains + +The `cosmocc` and `cosmoar` programs use shell script magic to run both +toolchains under the hood. Sometimes this magic doesn't work when you're +building software that needs to do things like run the C preprocessor in +aarch64 mode. In such cases, cosmocc provides x86\_64 and aarch64 only +toolchains which give you more power and control over your builds. + +- `x86_64-unknown-cosmo-cc`, `x86_64-unknown-cosmo-c++`, and + `x86_64-linux-cosmo-as` let you build multi-OS programs that only run + on x86\_64. You'll need this if you want to compile complex projects + like Emacs and OpenSSL. These are shell scripts that help you make + sure your software is compiled with the correct set of flags. + +- `aarch64-unknown-cosmo-cc`, `aarch64-unknown-cosmo-c++`, and + `aarch64-linux-cosmo-as` let you build multi-OS programs that only run + on ARM64. You'll need this if you want to compile complex projects + like Emacs and OpenSSL. These are shell scripts that help you make + sure your software is compiled with the correct set of flags. + +- `aarch64-linux-cosmo-cc`, `aarch64-linux-cosmo-c++`, + `aarch64-linux-cosmo-as`, and `aarch64-linux-cosmo-ld` are the actual + compiler executables. Using these grants full control over your + compiler and maximum performance. This is the approach favored for + instance by the Cosmopolitan Mono Repo's Makefile. If you use these, + then you should have zero expectation of support, because you'll be + assuming all responsibility for knowing about all the ABI-related + flags your Cosmopolitan runtime requires. + +When you use the "unknown" OS compilers, they'll link ELF executables +which embed an APE program image. This is so it's possible to have DWARF +debugging data. If you say: + +``` +x86_64-unknown-cosmo-cc -Os -mtiny -o hello hello.c +./hello +x86_64-linux-cosmo-objcopy -SO binary hello hello.com +./hello.com +``` + +Then you can unwap the raw stripped APE executable and get a much +smaller file than you otherwise would using the `-s` flag. + +If you compile your software twice, using both the x86\_64 and aarch64 +compilers, then it's possible to link the two binaries into a single fat +binary yourself via the `apelink` program. To understand how this +process works, it works best if you use the `BUILDLOG` variable, to see +how the shell script wrappers are doing it. You can also consult the +build configs of the ahgamut/superconfigure project on GitHub. + ## Troubleshooting Your `cosmocc` compiler runs a number commands under the hood. If diff --git a/tool/cosmocc/bin/cosmocc b/tool/cosmocc/bin/cosmocc index 748b98d7e..5032bf7f6 100755 --- a/tool/cosmocc/bin/cosmocc +++ b/tool/cosmocc/bin/cosmocc @@ -156,6 +156,15 @@ for x; do elif [ x"$x" = x"-mcosmo" ]; then MCOSMO=1 continue + elif [ x"$x" = x"-mdbg" ]; then + MODE=dbg + continue + elif [ x"$x" = x"-mtiny" ]; then + MODE=tiny + continue + elif [ x"$x" = x"-moptlinux" ]; then + MODE=optlinux + continue elif [ x"$x" = x"-fomit-frame-pointer" ]; then # Quoth Apple: "The frame pointer register must always address a # valid frame record. Some functions — such as leaf functions or @@ -243,10 +252,10 @@ LDFLAGS="-static -nostdlib -no-pie -fuse-ld=bfd -Wl,-z,noexecstack -Wl,-z,norelr PRECIOUS="-fno-omit-frame-pointer" # these features screw with backtraces so avoid them -if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ]; then +if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ] && [ x"$MODE" != x"optlinux" ]; then CFLAGS="$CFLAGS -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer" fi -if [ x"$OPT" != x"-O3" ]; then +if [ x"$OPT" != x"-O3" ] && [ x"$MODE" != x"optlinux" ]; then CFLAGS="$CFLAGS -fno-schedule-insns2" fi @@ -261,19 +270,39 @@ else CFLAGS="$CFLAGS -Wno-implicit-int" fi -CRT_X86_64="$BIN/../x86_64-linux-cosmo/lib/ape.o $BIN/../x86_64-linux-cosmo/lib/crt.o" -CPPFLAGS_X86_64="$CPPFLAGS -mno-red-zone" +if [ x"$MODE" = x"dbg" ]; then + LIB_X86_64="$BIN/../x86_64-linux-cosmo/lib/dbg" + LIB_AARCH64="$BIN/../aarch64-linux-cosmo/lib/dbg" +elif [ x"$MODE" = x"tiny" ]; then + LIB_X86_64="$BIN/../x86_64-linux-cosmo/lib/tiny" + LIB_AARCH64="$BIN/../aarch64-linux-cosmo/lib/tiny" +elif [ x"$MODE" = x"optlinux" ]; then + LIB_X86_64="$BIN/../x86_64-linux-cosmo/lib/optlinux" + LIB_AARCH64="$BIN/../aarch64-linux-cosmo/lib/optlinux" +else + LIB_X86_64="$BIN/../x86_64-linux-cosmo/lib" + LIB_AARCH64="$BIN/../aarch64-linux-cosmo/lib" +fi + +CRT_X86_64="$LIB_X86_64/ape.o $LIB_X86_64/crt.o" +CPPFLAGS_X86_64="$CPPFLAGS" CFLAGS_X86_64="$CFLAGS -mno-tls-direct-seg-refs" -LDFLAGS_X86_64="$LDFLAGS -L$BIN/../x86_64-linux-cosmo/lib -Wl,-T,$BIN/../x86_64-linux-cosmo/lib/ape.lds -Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=16384" +LDFLAGS_X86_64="$LDFLAGS -L$LIB_X86_64 -L$BIN/../x86_64-linux-cosmo/lib -Wl,-T,$LIB_X86_64/ape.lds -Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=16384" LDLIBS_X86_64="-lcosmo" -CRT_AARCH64="$BIN/../aarch64-linux-cosmo/lib/crt.o" +CRT_AARCH64="$LIB_AARCH64/crt.o" CPPFLAGS_AARCH64="$CPPFLAGS -fsigned-char" CFLAGS_AARCH64="$CFLAGS -ffixed-x18 -ffixed-x28 -mno-outline-atomics" -LDFLAGS_AARCH64="$LDFLAGS -L$BIN/../aarch64-linux-cosmo/lib -Wl,-T,$BIN/../aarch64-linux-cosmo/lib/aarch64.lds -Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384" +LDFLAGS_AARCH64="$LDFLAGS -L$LIB_AARCH64 -L$BIN/../aarch64-linux-cosmo/lib -Wl,-T,$LIB_AARCH64/aarch64.lds -Wl,-z,common-page-size=16384 -Wl,-z,max-page-size=16384" LDLIBS_AARCH64="-lcosmo" -if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ]; then +SUPPORT_VECTOR=-1 +if [ x"$MODE" = x"optlinux" ]; then + CPPFLAGS_X86_64="$CPPFLAGS_X86_64 -mno-red-zone" + SUPPORT_VECTOR=linux +fi + +if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ] && [ x"$MODE" != x"optlinux" ]; then CFLAGS_X86_64="${CFLAGS_X86_64} -fpatchable-function-entry=18,16 -fno-inline-functions-called-once -DFTRACE -DSYSDEBUG" CFLAGS_AARCH64="${CFLAGS_AARCH64} -fpatchable-function-entry=7,6 -fno-inline-functions-called-once -DFTRACE -DSYSDEBUG" fi @@ -526,6 +555,7 @@ fi set -- \ "$BIN/apelink" \ + -V "$SUPPORT_VECTOR" \ -l "$BIN/ape-x86_64.elf" \ -l "$BIN/ape-aarch64.elf" \ -M "$BIN/ape-m1.c" \ @@ -536,10 +566,12 @@ set -- \ log_command "$@" "$@" || Exit -set -- \ -"$BIN/pecheck" "$OUTPUT" -log_command "$@" -"$@" || Exit +if [ x"$MODE" != "optlinux" ]; then + set -- \ + "$BIN/pecheck" "$OUTPUT" + log_command "$@" + "$@" || Exit +fi if [ $INTENT = ld ] && [ $SAVE_TEMPS -eq 0 ]; then mv -f "$OUTPUT_X86_64" "${OUTPUT%.com}.com.dbg" || Exit diff --git a/tool/cosmocc/bin/cosmocross b/tool/cosmocc/bin/cosmocross index 894d7b421..1536318ee 100755 --- a/tool/cosmocc/bin/cosmocross +++ b/tool/cosmocc/bin/cosmocross @@ -59,13 +59,33 @@ if [ x"$ARCH" = x"$PROG" ]; then fatal_error "cosmocross must be run via cross compiler" fi +for x; do + if [ x"$x" = x"-mtiny" ]; then + MODE=tiny + elif [ x"$x" = x"-mdbg" ]; then + MODE=dbg + elif [ x"$x" = x"-moptlinux" ]; then + MODE=optlinux + fi +done + +if [ x"$MODE" = x"dbg" ]; then + LIB="$BIN/../$ARCH-linux-cosmo/lib/dbg" +elif [ x"$MODE" = x"tiny" ]; then + LIB="$BIN/../$ARCH-linux-cosmo/lib/tiny" +elif [ x"$MODE" = x"optlinux" ]; then + LIB="$BIN/../$ARCH-linux-cosmo/lib/optlinux" +else + LIB="$BIN/../$ARCH-linux-cosmo/lib" +fi + CC="$BIN/$ARCH-linux-cosmo-gcc" -CRT="$BIN/../$ARCH-linux-cosmo/lib/crt.o" +CRT="$LIB/crt.o" LDLIBS="-lcosmo" if [ -z "$COSMOS" ]; then - LDFLAGS="$LDFLAGS -L$BIN/../$ARCH-linux-cosmo/lib" + LDFLAGS="$LDFLAGS -L$LIB -L$BIN/../$ARCH-linux-cosmo/lib" else - LDFLAGS="$LDFLAGS -L$COSMOS/lib -L$BIN/../$ARCH-linux-cosmo/lib" + LDFLAGS="$LDFLAGS -L$COSMOS/lib -L$LIB -L$BIN/../$ARCH-linux-cosmo/lib" CPPFLAGS="$CPPFLAGS -I$COSMOS/include" fi if [ x"$PROG" != x"${PROG%++}" ]; then @@ -80,16 +100,20 @@ fi PAGESZ=4096 if [ x"$ARCH" = x"x86_64" ]; then OBJCOPYFLAGS="-S -O binary" - CRT="$BIN/../$ARCH-linux-cosmo/lib/ape-no-modify-self.o $CRT" - CPPFLAGS="$CPPFLAGS -mno-red-zone" + CRT="$LIB/ape-no-modify-self.o $CRT" CFLAGS="$CFLAGS -mno-tls-direct-seg-refs" - LDFLAGS="$LDFLAGS -Wl,-T,$BIN/../$ARCH-linux-cosmo/lib/ape.lds" + LDFLAGS="$LDFLAGS -Wl,-T,$LIB/ape.lds" + if [ x"$MODE" = x"optlinux" ]; then + CPPFLAGS="$CPPFLAGS -mred-zone" + else + CPPFLAGS="$CPPFLAGS -mno-red-zone" + fi elif [ x"$ARCH" = x"aarch64" ]; then OBJCOPYFLAGS="-S" PAGESZ=16384 CPPFLAGS="$CPPFLAGS -fsigned-char" CFLAGS="$CFLAGS -ffixed-x18 -ffixed-x28 -mno-outline-atomics" - LDFLAGS="$LDFLAGS -Wl,-T,$BIN/../$ARCH-linux-cosmo/lib/aarch64.lds" + LDFLAGS="$LDFLAGS -Wl,-T,$LIB/aarch64.lds" else fatal_error "$ARCH: unsupported architecture" fi @@ -142,6 +166,12 @@ for x; do elif [ x"$x" = x"-mcosmo" ]; then CPPFLAGS="$CPPFLAGS -D_COSMO_SOURCE" continue + elif [ x"$x" = x"-mdbg" ]; then + continue + elif [ x"$x" = x"-mtiny" ]; then + continue + elif [ x"$x" = x"-moptlinux" ]; then + continue elif [ x"$x" != x"${x#-o}" ]; then OUTPUT=${x#-o} elif [ x"$x" = x"-fpic" ]; then @@ -189,6 +219,7 @@ fi # support --ftrace unless optimizing for size if [ x"$OPT" != x"-Os" ] && # $OPT != -Os + [ x"$MODE" != x"optlinux" ] && # $MODE not optlinux [ x"${MODE%tiny}" = x"${MODE}" ]; then # $MODE not in (tiny, aarch64-tiny) if [ x"$ARCH" = x"x86_64" ]; then CFLAGS="$CFLAGS -fpatchable-function-entry=18,16 -fno-inline-functions-called-once" @@ -199,10 +230,11 @@ fi # maximize frame pointers unless optimizing for size if [ x"$OPT" != x"-Os" ] && # $OPT != "-Os" + [ x"$MODE" != x"optlinux" ] && # $MODE not optlinux [ x"$MODE" != x"${MODE%tiny}" ]; then # endswith($MODE, "tiny") CFLAGS="$CFLAGS -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer" fi -if [ x"$OPT" != x"-O3" ]; then +if [ x"$OPT" != x"-O3" ] && [ x"$MODE" != x"optlinux" ]; then CFLAGS="$CFLAGS -fno-schedule-insns2" fi diff --git a/tool/cosmocc/package.sh b/tool/cosmocc/package.sh index 59b2dc44d..9d6881ebe 100755 --- a/tool/cosmocc/package.sh +++ b/tool/cosmocc/package.sh @@ -61,6 +61,42 @@ make -j64 m=$AMD64 \ o/$AMD64/third_party/make/make.dbg \ o/$AMD64/third_party/ctags/ctags.dbg +make -j64 m=$AMD64-tiny \ + o/cosmocc.h.txt \ + o/$AMD64-tiny/ape/ape.lds \ + o/$AMD64-tiny/libc/crt/crt.o \ + o/$AMD64-tiny/ape/ape.elf \ + o/$AMD64-tiny/ape/ape.macho \ + o/$AMD64-tiny/ape/ape.o \ + o/$AMD64-tiny/ape/ape-copy-self.o \ + o/$AMD64-tiny/ape/ape-no-modify-self.o \ + o/$AMD64-tiny/cosmopolitan.a \ + o/$AMD64-tiny/third_party/libcxx/libcxx.a \ + +make -j64 m=$AMD64-dbg \ + o/cosmocc.h.txt \ + o/$AMD64-dbg/ape/ape.lds \ + o/$AMD64-dbg/libc/crt/crt.o \ + o/$AMD64-dbg/ape/ape.elf \ + o/$AMD64-dbg/ape/ape.macho \ + o/$AMD64-dbg/ape/ape.o \ + o/$AMD64-dbg/ape/ape-copy-self.o \ + o/$AMD64-dbg/ape/ape-no-modify-self.o \ + o/$AMD64-dbg/cosmopolitan.a \ + o/$AMD64-dbg/third_party/libcxx/libcxx.a \ + +make TARGET_ARCH= -j64 m=$AMD64-optlinux \ + o/cosmocc.h.txt \ + o/$AMD64-optlinux/ape/ape.lds \ + o/$AMD64-optlinux/libc/crt/crt.o \ + o/$AMD64-optlinux/ape/ape.elf \ + o/$AMD64-optlinux/ape/ape.macho \ + o/$AMD64-optlinux/ape/ape.o \ + o/$AMD64-optlinux/ape/ape-copy-self.o \ + o/$AMD64-optlinux/ape/ape-no-modify-self.o \ + o/$AMD64-optlinux/cosmopolitan.a \ + o/$AMD64-optlinux/third_party/libcxx/libcxx.a \ + make -j64 m=$ARM64 \ o/$ARM64/ape/ape.elf \ o/$ARM64/ape/aarch64.lds \ @@ -95,6 +131,33 @@ make -j64 m=$ARM64 \ o/$ARM64/third_party/make/make.dbg \ o/$ARM64/third_party/ctags/ctags.dbg +make -j64 m=$ARM64-tiny \ + o/$ARM64-tiny/ape/ape.elf \ + o/$ARM64-tiny/ape/aarch64.lds \ + o/$ARM64-tiny/libc/crt/crt.o \ + o/$ARM64-tiny/ape/ape-copy-self.o \ + o/$ARM64-tiny/ape/ape-no-modify-self.o \ + o/$ARM64-tiny/cosmopolitan.a \ + o/$ARM64-tiny/third_party/libcxx/libcxx.a \ + +make -j64 m=$ARM64-dbg \ + o/$ARM64-dbg/ape/ape.elf \ + o/$ARM64-dbg/ape/aarch64.lds \ + o/$ARM64-dbg/libc/crt/crt.o \ + o/$ARM64-dbg/ape/ape-copy-self.o \ + o/$ARM64-dbg/ape/ape-no-modify-self.o \ + o/$ARM64-dbg/cosmopolitan.a \ + o/$ARM64-dbg/third_party/libcxx/libcxx.a \ + +make -j64 m=$ARM64-optlinux \ + o/$ARM64-optlinux/ape/ape.elf \ + o/$ARM64-optlinux/ape/aarch64.lds \ + o/$ARM64-optlinux/libc/crt/crt.o \ + o/$ARM64-optlinux/ape/ape-copy-self.o \ + o/$ARM64-optlinux/ape/ape-no-modify-self.o \ + o/$ARM64-optlinux/cosmopolitan.a \ + o/$ARM64-optlinux/third_party/libcxx/libcxx.a \ + mkdir -p "$OUTDIR/bin/" cp tool/cosmocc/README.md "$OUTDIR/" cp tool/cosmocc/LICENSE.* "$OUTDIR/" @@ -155,19 +218,51 @@ cd "$OLD" for arch in $AMD64 $ARM64; do mkdir -p "$OUTDIR/$arch-linux-cosmo/lib/" + mkdir -p "$OUTDIR/$arch-linux-cosmo/lib/dbg" + mkdir -p "$OUTDIR/$arch-linux-cosmo/lib/tiny" + mkdir -p "$OUTDIR/$arch-linux-cosmo/lib/optlinux" + cp -f o/$arch/libc/crt/crt.o "$OUTDIR/$arch-linux-cosmo/lib/" + cp -f o/$arch-dbg/libc/crt/crt.o "$OUTDIR/$arch-linux-cosmo/lib/dbg/" + cp -f o/$arch-tiny/libc/crt/crt.o "$OUTDIR/$arch-linux-cosmo/lib/tiny/" + cp -f o/$arch-optlinux/libc/crt/crt.o "$OUTDIR/$arch-linux-cosmo/lib/optlinux/" + cp -f o/$arch/cosmopolitan.a "$OUTDIR/$arch-linux-cosmo/lib/libcosmo.a" + cp -f o/$arch-dbg/cosmopolitan.a "$OUTDIR/$arch-linux-cosmo/lib/dbg/libcosmo.a" + cp -f o/$arch-tiny/cosmopolitan.a "$OUTDIR/$arch-linux-cosmo/lib/tiny/libcosmo.a" + cp -f o/$arch-optlinux/cosmopolitan.a "$OUTDIR/$arch-linux-cosmo/lib/optlinux/libcosmo.a" + cp -f o/$arch/third_party/libcxx/libcxx.a "$OUTDIR/$arch-linux-cosmo/lib/" + cp -f o/$arch-dbg/third_party/libcxx/libcxx.a "$OUTDIR/$arch-linux-cosmo/lib/dbg/" + cp -f o/$arch-tiny/third_party/libcxx/libcxx.a "$OUTDIR/$arch-linux-cosmo/lib/tiny/" + cp -f o/$arch-optlinux/third_party/libcxx/libcxx.a "$OUTDIR/$arch-linux-cosmo/lib/optlinux/" + for lib in c dl gcc_s m crypt pthread resolv rt dl unwind gomp stdc++; do printf '\041\074\141\162\143\150\076\012' >"$OUTDIR/$arch-linux-cosmo/lib/lib$lib.a" done mkdir -p "$OUTDIR/lib/gcc/" touch "$OUTDIR/lib/gcc/libgomp.spec" # needed if user passes -fopenmp but not -lgomp done + cp -f o/$AMD64/ape/ape.o "$OUTDIR/x86_64-linux-cosmo/lib/" +cp -f o/$AMD64-dbg/ape/ape.o "$OUTDIR/x86_64-linux-cosmo/lib/dbg/" +cp -f o/$AMD64-tiny/ape/ape.o "$OUTDIR/x86_64-linux-cosmo/lib/tiny/" +cp -f o/$AMD64-optlinux/ape/ape.o "$OUTDIR/x86_64-linux-cosmo/lib/optlinux/" + cp -f o/$AMD64/ape/ape.lds "$OUTDIR/x86_64-linux-cosmo/lib/" +cp -f o/$AMD64-dbg/ape/ape.lds "$OUTDIR/x86_64-linux-cosmo/lib/dbg/" +cp -f o/$AMD64-tiny/ape/ape.lds "$OUTDIR/x86_64-linux-cosmo/lib/tiny/" +cp -f o/$AMD64-optlinux/ape/ape.lds "$OUTDIR/x86_64-linux-cosmo/lib/optlinux/" + cp -f o/$ARM64/ape/aarch64.lds "$OUTDIR/aarch64-linux-cosmo/lib/" +cp -f o/$ARM64-dbg/ape/aarch64.lds "$OUTDIR/aarch64-linux-cosmo/lib/dbg/" +cp -f o/$ARM64-tiny/ape/aarch64.lds "$OUTDIR/aarch64-linux-cosmo/lib/tiny/" +cp -f o/$ARM64-optlinux/ape/aarch64.lds "$OUTDIR/aarch64-linux-cosmo/lib/optlinux/" + cp -f o/$AMD64/ape/ape-no-modify-self.o "$OUTDIR/x86_64-linux-cosmo/lib/" +cp -f o/$AMD64-dbg/ape/ape-no-modify-self.o "$OUTDIR/x86_64-linux-cosmo/lib/dbg/" +cp -f o/$AMD64-tiny/ape/ape-no-modify-self.o "$OUTDIR/x86_64-linux-cosmo/lib/tiny/" +cp -f o/$AMD64-optlinux/ape/ape-no-modify-self.o "$OUTDIR/x86_64-linux-cosmo/lib/optlinux/" cp -f ape/ape-m1.c "$OUTDIR/bin/" cp -af tool/cosmocc/bin/* "$OUTDIR/bin/"