diff --git a/README.md b/README.md index f74b1513a..3af2cab2f 100644 --- a/README.md +++ b/README.md @@ -200,23 +200,42 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000' ### Linux -Linux systems with WINE installed might have issues running APE programs -if WINE is registered with `binnfmt_misc`. To work around this, you need -to remove WINE from `binfmt_misc`. You could also disable `binfmt_misc` -entirely. +Some Linux systems are configured to launch MZ executables under WINE. +Other distros configure their stock installs so that APE programs will +print "run-detectors: unable to find an interpreter". For example: +```sh +jart@ubuntu:~$ wget https://cosmo.zip/pub/cosmos/bin/dash +jart@ubuntu:~$ chmod +x dash +jart@ubuntu:~$ ./dash +run-detectors: unable to find an interpreter for ./dash ``` -sudo sh -c 'echo 0 > /proc/sys/fs/binfmt_misc/status' + +You can fix that by registering APE with `binfmt_misc`: + +```sh +sudo wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf +sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" +sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" +``` + +You should be good now. APE will not only work, it'll launch executables +400µs faster now too. However if things still didn't work out, it's also +possible to disable `binfmt_misc` as follows: + +```sh +sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli' # remove Ubuntu's MZ interpreter +sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status' # remove ALL binfmt_misc entries ``` ### WSL It's normally unsafe to use APE in a WSL environment, because it tries -to run them as WIN32 binaries within the WSL environment. In order to -make it safe to use Cosmopolitan software on WSL, you have to run: +to run MZ executables as WIN32 binaries within the WSL environment. In +order to make it safe to use Cosmopolitan software on WSL, run this: ```sh -sh -c "echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop" +sudo sh -c "echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop" ``` ## Discord Chatroom diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 39dc047a1..350fc9f8e 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -32,6 +32,15 @@ _apple: mov $_HOSTXNU,%cl .endfn _apple,weak,hidden #endif +#if SupportsWindows() && defined(__x86_64__) && !IsTiny() +// implements all win32 apis on non-windows hosts +// it is just enough code to get a good backtrace +__oops_win32: + ud2 + nop + .endfn __oops_win32 +#endif + // System Five userspace program entrypoint. // // @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..] @@ -76,7 +85,6 @@ _start: // make win32 imps crash .weak ape_idata_iat .weak ape_idata_iatend - .weak __oops_win32 ezlea __oops_win32,ax ezlea ape_idata_iat,di ezlea ape_idata_iatend,cx diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 121978bd3..1ab8f350c 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -23,7 +23,6 @@ #include "libc/intrin/nomultics.internal.h" #include "libc/intrin/weaken.h" #include "libc/limits.h" -#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nt/console.h" @@ -45,7 +44,6 @@ #include "libc/sock/internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/prot.h" - #ifdef __x86_64__ #define abi __msabi textwindows dontinstrument @@ -55,6 +53,7 @@ __msabi extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW; __msabi extern typeof(DuplicateHandle) *const __imp_DuplicateHandle; __msabi extern typeof(FreeEnvironmentStrings) *const __imp_FreeEnvironmentStringsW; __msabi extern typeof(GetConsoleMode) *const __imp_GetConsoleMode; +__msabi extern typeof(GetCurrentDirectory) *const __imp_GetCurrentDirectoryW; __msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId; __msabi extern typeof(GetEnvironmentStrings) *const __imp_GetEnvironmentStringsW; __msabi extern typeof(GetEnvironmentVariable) *const __imp_GetEnvironmentVariableW; @@ -67,6 +66,7 @@ __msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP; __msabi extern typeof(SetEnvironmentVariable) *const __imp_SetEnvironmentVariableW; __msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle; __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; +__msabi extern typeof(WriteFile) *const __imp_WriteFile; // clang-format on void cosmo(int, char **, char **, long (*)[2]) wontreturn; @@ -88,9 +88,33 @@ __funline char16_t *MyCommandLine(void) { return cmd; } -// implements all win32 apis on non-windows hosts -static abi long __oops_win32(void) { - notpossible; +static abi char16_t *StrStr(const char16_t *haystack, const char16_t *needle) { + size_t i; + for (;;) { + for (i = 0;; ++i) { + if (!needle[i]) return (/*unconst*/ char16_t *)haystack; + if (!haystack[i]) break; + if (needle[i] != haystack[i]) break; + } + if (!*haystack++) break; + } + return 0; +} + +static abi void PrintError(const char *s, size_t n) { +#define PrintError(s) PrintError(s, sizeof(s) - 1) + __imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), s, n, 0, 0); +} + +// detect the unholiest of environments +static abi bool32 IsWslChimera(void) { + char16_t path[PATH_MAX]; + return __imp_GetCurrentDirectoryW(PATH_MAX, path) && // + path[0] == '\\' && // + path[1] == '\\' && // + path[2] == 'w' && // + path[3] == 's' && // + path[4] == 'l'; } // returns true if utf-8 path is a win32-style path that exists @@ -239,12 +263,17 @@ abi int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, extern char os asm("__hostos"); os = _HOSTWINDOWS; // madness https://news.ycombinator.com/item?id=21019722 kStartTsc = rdtsc(); + if (!IsTiny() && IsWslChimera()) { + PrintError("error: APE is running on WIN32 inside WSL. You need to run: " + "sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop'\n"); + return 77 << 8; // exit(77) + } __umask = 077; __pid = __imp_GetCurrentProcessId(); cmdline = MyCommandLine(); #ifdef SYSDEBUG // sloppy flag-only check for early initialization - if (__strstr16(cmdline, u"--strace")) ++__strace; + if (StrStr(cmdline, u"--strace")) ++__strace; #endif if (_weaken(WinSockInit)) { _weaken(WinSockInit)(); diff --git a/tool/cosmocc/README.md b/tool/cosmocc/README.md index 690d2597a..a247a1a57 100644 --- a/tool/cosmocc/README.md +++ b/tool/cosmocc/README.md @@ -93,14 +93,30 @@ If you use zsh and have trouble running APE programs try `sh -c ./prog` or simply upgrade to zsh 5.9+ (since we patched it two years ago). The same is the case for Python `subprocess`, old versions of fish, etc. +If you're on Linux, then `binfmt_misc` might try to run APE programs +under WINE, or say "run-detectors: unable to find an interpreter". You +can fix that by running these commands: + +```sh +sudo wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf +sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" +sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" +``` + On Apple Silicon, `aarch64-unknown-cosmo-cc` produces ELF binaries. If -you build a hello world program, then you need to say `ape ./hello` to -run it. Note this isn't an issue for `cosmocc` which will wrap the ELF -program in a shell script that'll compile your APE loader automatically -as needed. This also isn't an issue if your login shell was built using -Cosmopolitan Libc, e.g. because -Cosmo's `execve()` implementation will seamlessly launch ELF files via -your APE Loader. +you build a hello world program, then you need to say `ape ./hello`. If +you don't have an `ape` command then run `cc -o ape bin/ape-m1.c` which +should be moved to `/usr/local/bin/ape`. Your APE interpreter might +already exist under a path like `$TMPDIR/.ape-1.9`. It's important to +note this is only a gotcha for the cross compiler. Your `cosmocc` +compiler wraps the actual ELF binaries with a shell script that'll +extract and compile an APE loader automatically, as needed. This also +isn't an issue if your login shell was built using Cosmopolitan Libc, +e.g. . That's because Cosmo's +`execve()` implementation will automatically react to `ENOEXEC` from the +kernel by re-launching the program under `/usr/local/bin/ape`. Lastly +note that all other platforms that aren't Apple Arm64 use `/usr/bin/ape` +as the hard-coded canonical interpreter path. On Windows, you need a shell in order to run the shell script wrappers from this toolchain. It's recommended that you download Cosmos binaries diff --git a/tool/cosmocc/package.sh b/tool/cosmocc/package.sh index 64443f46d..911940f3d 100755 --- a/tool/cosmocc/package.sh +++ b/tool/cosmocc/package.sh @@ -122,9 +122,9 @@ cp -f o/x86_64/ape/ape-no-modify-self.o "$OUTDIR/x86_64-linux-cosmo/lib/" cp -f ape/ape-m1.c "$OUTDIR/bin/" cp -af tool/cosmocc/bin/* "$OUTDIR/bin/" -cp -f o/x86_64/ape/ape.elf "$OUTDIR/bin/" -cp -f o/x86_64/ape/ape.macho "$OUTDIR/bin/" -cp -f o/aarch64/ape/ape.elf "$OUTDIR/bin/ape.aarch64" +cp -f o/x86_64/ape/ape.elf "$OUTDIR/bin/ape-x86_64.elf" +cp -f o/x86_64/ape/ape.macho "$OUTDIR/bin/ape-x86_64.macho" +cp -f o/aarch64/ape/ape.elf "$OUTDIR/bin/ape-aarch64.elf" for x in assimilate march-native mktemper fixupobj zipcopy apelink pecheck mkdeps zipobj; do o//tool/build/apelink.com \ -l o/x86_64/ape/ape.elf \