mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-07 17:22:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69faf1b403 | ||
|
|
e4dea37b8e | ||
|
|
0c89516ac5 | ||
|
|
3e6d536822 | ||
|
|
dbd8176ea8 | ||
|
|
545a8f4cb0 | ||
|
|
f7cfe03888 | ||
|
|
2c1efd3d78 | ||
|
|
3ac473df3b | ||
|
|
8caf1b48a9 | ||
|
|
72ac5f18d9 | ||
|
|
2c9d2943d6 | ||
|
|
32b97f2d25 | ||
|
|
529cb4817c | ||
|
|
7a9e176ecf | ||
|
|
68c7c9c1e0 | ||
|
|
7010a8081e | ||
|
|
665747a319 | ||
|
|
e05933c641 | ||
|
|
8f5e516b39 | ||
|
|
8318d67503 | ||
|
|
1351d3cede | ||
|
|
dffee606cf | ||
|
|
ddc08dc974 | ||
|
|
e4584ace81 | ||
|
|
3a470ed356 | ||
|
|
9f9aec013a | ||
|
|
eea601f346 | ||
|
|
1c2e7c1333 | ||
|
|
0283f2772c | ||
|
|
751d20d98d | ||
|
|
3b15d31247 | ||
|
|
f047172bd3 | ||
|
|
5d5b282d12 | ||
|
|
25a892d6ae | ||
|
|
d1e764b3cf | ||
|
|
5c1fdc9819 | ||
|
|
f25beb341c | ||
|
|
bed77186c3 | ||
|
|
bcf268adf8 | ||
|
|
0863427b3a | ||
|
|
f7cad70da1 | ||
|
|
48bd3d85df | ||
|
|
bd56a9cf51 | ||
|
|
c6d3802d3a | ||
|
|
95124cacbe | ||
|
|
b320321319 | ||
|
|
291103ad8d | ||
|
|
3802428026 | ||
|
|
d0ad2694ed | ||
|
|
7138399f96 | ||
|
|
cdbd10c9d0 | ||
|
|
afbef6c361 | ||
|
|
3d3cdcf276 | ||
|
|
d2f49ca175 | ||
|
|
241f949540 | ||
|
|
15af5c2d7e | ||
|
|
b8d1377ae1 | ||
|
|
ea28f93a26 | ||
|
|
5330442d85 | ||
|
|
cc3e3de044 | ||
|
|
ac125d3e1f | ||
|
|
956e68be59 | ||
|
|
d71da7fc72 | ||
|
|
e961385e55 | ||
|
|
736fdb757a | ||
|
|
dd83db9567 | ||
|
|
23d812f116 | ||
|
|
c39eb244d4 | ||
|
|
f63c4d4f52 | ||
|
|
b893479417 | ||
|
|
d02cba2451 | ||
|
|
4cf987ddb1 | ||
|
|
20c794a353 | ||
|
|
4f100d2aad | ||
|
|
a12ad17291 | ||
|
|
653c7b2f87 | ||
|
|
d7917ea076 | ||
|
|
585c86e2a4 | ||
|
|
48e260e653 | ||
|
|
aa106c9356 | ||
|
|
5e8c928f1a | ||
|
|
1eb6484c9c | ||
|
|
a46ec61787 | ||
|
|
024be3b009 | ||
|
|
6ca5ab4680 | ||
|
|
55d5d6bbc0 | ||
|
|
d259e573b6 | ||
|
|
7b284f6bda | ||
|
|
b0e3d89942 | ||
|
|
0b1acce680 | ||
|
|
fadb64a2bf | ||
|
|
a1e1e821cb | ||
|
|
2af7c802b6 | ||
|
|
3b791d2f44 | ||
|
|
b4084dd6c6 | ||
|
|
ee82f90bba | ||
|
|
a699cda5c8 | ||
|
|
f86ffa1a25 | ||
|
|
a09f62141d | ||
|
|
ed17d3008b | ||
|
|
062b2d776e |
No files matched your search
@@ -73,8 +73,16 @@ MODE := $(m)
|
||||
endif
|
||||
endif
|
||||
|
||||
UNAME_M = $(shell uname -m)
|
||||
UNAME_S = $(shell uname -s)
|
||||
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
|
||||
# - user ran build/bootstrap/make.com, in which case make's working directory is in wsl
|
||||
# - user ran make, in which case cocmd.com's working directory is in wsl
|
||||
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(shell pwd)),)
|
||||
$(warning wsl2 interop is enabled)
|
||||
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
|
||||
endif
|
||||
|
||||
UNAME_M := $(shell uname -m)
|
||||
UNAME_S := $(shell uname -s)
|
||||
|
||||
# apple still distributes a 17 year old version of gnu make
|
||||
ifeq ($(MAKE_VERSION), 3.81)
|
||||
@@ -85,7 +93,7 @@ endif
|
||||
ifeq ($(TOOLCHAIN),) # if TOOLCHAIN isn't defined
|
||||
ifeq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") # if our gcc isn't unbundled
|
||||
ifneq ($(UNAME_M)-$(UNAME_S), x86_64-Linux) # if this is not amd64 linux
|
||||
$(error you need to download https://justine.lol/cosmocc-0.0.12.zip and unzip it inside the cosmo directory)
|
||||
$(error you need to download https://cosmo.zip/pub/cosmocc/cosmocc-0.0.18.zip and unzip it inside the cosmo directory)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -170,19 +178,22 @@ include third_party/puff/puff.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/vga/vga.mk #─┘
|
||||
include libc/vga/vga.mk # │
|
||||
include libc/irq/irq.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include third_party/nsync/nsync.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include third_party/double-conversion/dc.mk # │ You can issue system calls
|
||||
include libc/irq/irq.mk # ├──SYSTEMS RUNTIME
|
||||
include third_party/nsync/nsync.mk # │ You can issue system calls
|
||||
include libc/runtime/runtime.mk # │
|
||||
include third_party/double-conversion/dc.mk # │
|
||||
include libc/crt/crt.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||
include libc/mem/mem.mk #─┐
|
||||
include third_party/gdtoa/gdtoa.mk # ├──DYNAMIC RUNTIME
|
||||
include third_party/nsync/mem/mem.mk # │ You can now use stdio
|
||||
include libc/proc/proc.mk # │ You can now use threads
|
||||
include libc/thread/thread.mk # │ You can now use processes
|
||||
include tool/hello/hello.mk # │ You can finally call malloc()
|
||||
include libc/dlopen/dlopen.mk # │ You can now use processes
|
||||
include libc/thread/thread.mk # │ You can finally call malloc()
|
||||
include tool/hello/hello.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include libc/time/time.mk # │
|
||||
@@ -218,6 +229,7 @@ include third_party/nsync/testing/testing.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include tool/args/args.mk
|
||||
include test/posix/test.mk
|
||||
include test/tool/args/test.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
@@ -326,7 +338,7 @@ o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(
|
||||
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x)))) $(INCS) $(INCS)
|
||||
$(file >$@,$(INCS))
|
||||
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
|
||||
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
|
||||
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -s -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
|
||||
|
||||
o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||
@@ -371,9 +383,11 @@ COSMOPOLITAN_OBJECTS = \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_RUNTIME \
|
||||
THIRD_PARTY_NSYNC \
|
||||
LIBC_ELF \
|
||||
LIBC_IRQ \
|
||||
LIBC_CALLS \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_VGA \
|
||||
@@ -398,13 +412,14 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NEXGEN32E
|
||||
|
||||
COSMOPOLITAN_HEADERS = \
|
||||
COSMOPOLITAN_H_PKGS = \
|
||||
APE \
|
||||
LIBC \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
@@ -429,21 +444,41 @@ COSMOPOLITAN_HEADERS = \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
COSMOCC_PKGS = \
|
||||
$(COSMOPOLITAN_H_PKGS) \
|
||||
THIRD_PARTY_AARCH64 \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_INTEL
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
|
||||
|
||||
o/cosmopolitan.h: \
|
||||
o/$(MODE)/tool/build/rollup.com \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_INCS))
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
|
||||
COSMOCC_HDRS = \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOCC_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOCC_PKGS),$($(x)_INCS))
|
||||
|
||||
o/cosmocc.h.txt: Makefile
|
||||
$(file >$@, $(call uniq,$(COSMOCC_HDRS)))
|
||||
|
||||
COSMOPOLITAN_H_ROOT_HDRS = \
|
||||
libc/integral/normalize.inc \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
|
||||
|
||||
o/cosmopolitan.h.txt: Makefile
|
||||
$(file >$@, $(call uniq,$(COSMOPOLITAN_H_ROOT_HDRS)))
|
||||
|
||||
o/cosmopolitan.h: o/cosmopolitan.h.txt \
|
||||
$(wildcard libc/integral/*) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
|
||||
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
|
||||
@$(ECHO) '#ifndef __STRICT_ANSI__' >$@
|
||||
@$(ECHO) '#define _COSMO_SOURCE' >>$@
|
||||
@$(ECHO) '#endif' >>$@
|
||||
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >>$@
|
||||
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup.com @$< >>$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
|
||||
@@ -19,22 +19,17 @@ libc](https://justine.lol/cosmopolitan/index.html) website. We also have
|
||||
|
||||
## Getting Started
|
||||
|
||||
It's recommended that Cosmopolitan be installed to `/opt/cosmo` and
|
||||
`/opt/cosmos` on your computer. The first has the monorepo. The second
|
||||
contains your non-monorepo artifacts.
|
||||
You can start by obtaining a release of our `cosmocc` compiler from
|
||||
<https://cosmo.zip/pub/cosmocc/>.
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /opt
|
||||
sudo chmod 1777 /opt
|
||||
git clone https://github.com/jart/cosmopolitan /opt/cosmo
|
||||
export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"
|
||||
echo 'PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"' >>~/.profile
|
||||
ape-install # optionally install a faster systemwide ape loader
|
||||
cosmocc --update # pull cosmo and rebuild toolchain
|
||||
mkdir -p cosmocc
|
||||
cd cosmocc
|
||||
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
|
||||
unzip cosmocc.zip
|
||||
```
|
||||
|
||||
You've now successfully installed your very own cosmos. Now let's build
|
||||
an example program:
|
||||
Here's an example program we can write:
|
||||
|
||||
```c
|
||||
// hello.c
|
||||
@@ -45,26 +40,11 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
To compile the program, you can run the `cosmocc` command. It's
|
||||
important to give it an output path that ends with `.com` so the output
|
||||
format will be Actually Portable Executable. When this happens, a
|
||||
concomitant debug binary is created automatically too.
|
||||
It can be compiled as follows:
|
||||
|
||||
```sh
|
||||
cosmocc -o hello.com hello.c
|
||||
./hello.com
|
||||
./hello.com.dbg
|
||||
```
|
||||
|
||||
You can use the `cosmocc` toolchain to build conventional open source
|
||||
projects which use autotools. This strategy normally works:
|
||||
|
||||
```sh
|
||||
export CC=cosmocc
|
||||
export CXX=cosmoc++
|
||||
./configure --prefix=/opt/cosmos
|
||||
make -j
|
||||
make install
|
||||
cosmocc -o hello hello.c
|
||||
./hello
|
||||
```
|
||||
|
||||
The Cosmopolitan Libc runtime links some heavyweight troubleshooting
|
||||
@@ -72,445 +52,119 @@ features by default, which are very useful for developers and admins.
|
||||
Here's how you can log system calls:
|
||||
|
||||
```sh
|
||||
./hello.com --strace
|
||||
./hello --strace
|
||||
```
|
||||
|
||||
Here's how you can get a much more verbose log of function calls:
|
||||
|
||||
```sh
|
||||
./hello.com --ftrace
|
||||
./hello --ftrace
|
||||
```
|
||||
|
||||
If you don't want rich runtime features like the above included, and you
|
||||
just want libc, and you want smaller simpler programs. In that case, you
|
||||
can consider using `MODE=tiny`, which is preconfigured by the repo in
|
||||
[build/config.mk](build/config.mk). Using this mode is much more
|
||||
effective at reducing binary footprint than the `-Os` flag alone. You
|
||||
can change your build mode by doing the following:
|
||||
You can use the Cosmopolitan's toolchain to build conventional open
|
||||
source projects which use autotools. This strategy normally works:
|
||||
|
||||
```sh
|
||||
export MODE=tiny
|
||||
cosmocc --update
|
||||
```
|
||||
|
||||
We can also make our program slightly smaller by using the system call
|
||||
interface directly, which is fine, since Cosmopolitan polyfills these
|
||||
interfaces across platforms, including Windows. For example:
|
||||
|
||||
```c
|
||||
// hello2.c
|
||||
#include <unistd.h>
|
||||
int main() {
|
||||
write(1, "hello world\n", 12);
|
||||
}
|
||||
```
|
||||
|
||||
Once compiled, your APE binary should be ~36kb in size.
|
||||
|
||||
```sh
|
||||
export MODE=tiny
|
||||
cosmocc -Os -o hello2.com hello2.c
|
||||
./hello2.com
|
||||
```
|
||||
|
||||
But let's say you only care about your binaries running on Linux and you
|
||||
don't want to use up all this additional space for platforms like WIN32.
|
||||
In that case, you can try `MODE=tinylinux` for example which will create
|
||||
executables more on the order of 8kb (similar to Musl Libc).
|
||||
|
||||
```sh
|
||||
export MODE=tinylinux
|
||||
cosmocc --update
|
||||
cosmocc -Os -o hello2.com hello2.c
|
||||
./hello2.com # <-- actually an ELF executable
|
||||
```
|
||||
|
||||
## ARM
|
||||
|
||||
Cosmo supports cross-compiling binaries for machines with ARM
|
||||
microprocessors. For example:
|
||||
|
||||
```sh
|
||||
make -j8 m=aarch64 o/aarch64/third_party/ggml/llama.com
|
||||
make -j8 m=aarch64-tiny o/aarch64-tiny/third_party/ggml/llama.com
|
||||
```
|
||||
|
||||
That'll produce ELF executables that run natively on two operating
|
||||
systems: Linux Arm64 (e.g. Raspberry Pi) and MacOS Arm64 (i.e. Apple
|
||||
Silicon), thus giving you full performance. The catch is you have to
|
||||
compile these executables on an x86_64-linux machine. The second catch
|
||||
is that MacOS needs a little bit of help understanding the ELF format.
|
||||
To solve that, we provide a tiny APE loader you can use on M1 machines.
|
||||
|
||||
```sh
|
||||
scp ape/ape-m1.c macintosh:
|
||||
scp o/aarch64/third_party/ggml/llama.com macintosh:
|
||||
ssh macintosh
|
||||
xcode-install
|
||||
cc -o ape ape-m1.c
|
||||
sudo cp ape /usr/local/bin/ape
|
||||
```
|
||||
|
||||
You can run your ELF AARCH64 executable on Apple Silicon as follows:
|
||||
|
||||
```sh
|
||||
ape ./llama.com
|
||||
```
|
||||
|
||||
If you want to run the `MODE=aarch64` unit tests, you need to have
|
||||
qemu-aarch64 installed as a binfmt_misc interpreter. It needs to be a
|
||||
static binary if you want it to work with Landlock Make's security. You
|
||||
can use the build included in our `third_party/qemu/` folder.
|
||||
|
||||
```
|
||||
doas cp o/third_party/qemu/qemu-aarch64 /usr/bin/qemu-aarch64
|
||||
doas sh -c "echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64:CF' > /proc/sys/fs/binfmt_misc/register"
|
||||
make -j8 m=aarch64
|
||||
```
|
||||
|
||||
Please note that the qemu-aarch64 binfmt_misc interpreter installation
|
||||
process is *essential* for being able to use the `aarch64-unknown-cosmo`
|
||||
toolchain to build fat APE binaries on your x86-64 machine.
|
||||
|
||||
## AMD64 + ARM64 fat APE binaries
|
||||
|
||||
If you've setup the qemu binfmt_misc interpreter, then you can can use
|
||||
cosmo's toolchains to build fat ape binaries. It works by compiling your
|
||||
program twice, so you can have a native build for both architectures in
|
||||
the same file. The two programs are merged together by apelink.com which
|
||||
also embeds multiple copies of APE loader and multiple symbols tables.
|
||||
|
||||
The easiest way to build fat APE is using `fatcosmocc`. This compiler
|
||||
works by creating a concomitant `.aarch64/foo.o` for every `foo.o` you
|
||||
compile. The only exception is the C preprocessor mode, which actually
|
||||
runs x86-64 GCC except with macros like `__x86_64__` undefined.
|
||||
|
||||
This toolchain works great for C projects that are written in a portable
|
||||
way and don't produce architecture-specific artifacts. One example of a
|
||||
large project that can be easily built is GNU coreutils.
|
||||
|
||||
```sh
|
||||
cd coreutils
|
||||
fatcosmocc --update ||exit
|
||||
./configure CC=fatcosmocc \
|
||||
AR=fatcosmoar \
|
||||
INSTALL=$(command -v fatcosmoinstall) \
|
||||
--prefix=/opt/cosmos \
|
||||
--disable-nls \
|
||||
--disable-dependency-tracking \
|
||||
--disable-silent-rules
|
||||
make -j8
|
||||
```
|
||||
|
||||
You'll then have a bunch of files like `src/ls` which are fat ape
|
||||
binaries. If you want to run them on Windows, then you simply need to
|
||||
rename the file so that it has the `.com` suffix. Better yet, consider
|
||||
making that a symlink (a.k.a. reparse point). The biggest gotcha with
|
||||
`fatcosmocc` though is ensuring builds don't strip binaries. For
|
||||
example, Linux's `install -s` command actually understands Windows'
|
||||
Portable Executable format well enough to remove the MS-DOS stub, which
|
||||
is where the APE shell script is stored. You need to ensure that
|
||||
`fatcosmoinstall` is used instead. Especially if your project needs to
|
||||
install the libraries built by `fatacosmoar` into `/opt/cosmos`.
|
||||
|
||||
## Advanced Fat APE Builds
|
||||
|
||||
Once you get seriously involved in creating fat APE builds of software
|
||||
you're going to eventually outgrow `fatcosmocc`. One example is Emacs
|
||||
which is trickier to build, because it produces architecture-specific
|
||||
files, and it also depends on shared files, e.g. zoneinfo. Since we like
|
||||
having everything in a neat little single-file executable container that
|
||||
doesn't need an "installation wizard", this tutorial will explain how we
|
||||
manage to accomplish that.
|
||||
|
||||
What you're going to do is, instead of using `fatcosmocc`, you're going
|
||||
to use both the `x86_64-unknown-cosmo-cc` and `aarch64-unknown-cosmo-cc`
|
||||
toolchains independently, and then run `apelink` and `zip` to manually
|
||||
build the final files. But there's a few tricks to learn first.
|
||||
|
||||
The first trick is to create a symlink on your system called `/zip`.
|
||||
Cosmopolitan Libc normally uses that as a synthetic folder that lets you
|
||||
access the assets in your zip executable. But since that's a read-only
|
||||
file system, your build system should use the normal one.
|
||||
|
||||
```sh
|
||||
doas ln -sf /opt/cosmos /zip
|
||||
```
|
||||
|
||||
Now create a file named `rebuild-fat.sh` which runs the build twice:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
set -ex
|
||||
export MODE=aarch64
|
||||
export COSMOS=/opt/cosmos/aarch64
|
||||
rebuild-cosmos.sh aarch64
|
||||
export MODE=
|
||||
export COSMOS=/opt/cosmos/x86_64
|
||||
rebuild-cosmos.sh x86_64
|
||||
wall.com 'finished building'
|
||||
```
|
||||
|
||||
Then create a second file `rebuild-cosmos.sh` which runs your build:
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
ARCH=${1:-x86_64}
|
||||
export COSMO=${COSMO:-/opt/cosmo}
|
||||
export COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
|
||||
export AS=$(command -v $ARCH-unknown-cosmo-as) || exit
|
||||
export CC=$(command -v $ARCH-unknown-cosmo-cc) || exit
|
||||
export CXX=$(command -v $ARCH-unknown-cosmo-c++) || exit
|
||||
export AR=$(command -v $ARCH-unknown-cosmo-ar) || exit
|
||||
export STRIP=$(command -v $ARCH-unknown-cosmo-strip) || exit
|
||||
export INSTALL=$(command -v $ARCH-unknown-cosmo-install) || exit
|
||||
export OBJCOPY=$(command -v $ARCH-unknown-cosmo-objcopy) || exit
|
||||
export OBJDUMP=$(command -v $ARCH-unknown-cosmo-objdump) || exit
|
||||
export ADDR2LINE=$(command -v $ARCH-unknown-cosmo-addr2line) || exit
|
||||
|
||||
$CC --update
|
||||
|
||||
export COSMOPOLITAN_DISABLE_ZIPOS=1
|
||||
|
||||
cd ~/vendor/zlib
|
||||
./configure --prefix=$COSMOS --static
|
||||
make clean
|
||||
make -j
|
||||
make install
|
||||
|
||||
cd ~/vendor/ncurses-6.4
|
||||
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH --disable-shared
|
||||
make clean
|
||||
make -j
|
||||
make install
|
||||
|
||||
cd ~/vendor/readline-8.2
|
||||
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH --disable-shared
|
||||
make uninstall || true
|
||||
make clean
|
||||
make -j
|
||||
make install
|
||||
|
||||
# NOTES:
|
||||
# 1. You'll need to patch enum { FOO = x } that fails to build into a #define FOO
|
||||
# 2. You'll need to patch configure.ac so it DOES NOT define USABLE_FIONREAD to 1
|
||||
# 2. You'll need to patch configure.ac so it DOES NOT define INTERRUPT_INPUT to 1
|
||||
cd ~/vendor/emacs-28.2
|
||||
./configure --prefix=$COSMOS --sysconfdir=/zip --datarootdir=/zip/share --exec-prefix=/zip/$ARCH \
|
||||
--without-x --with-threads --without-gnutls --disable-silent-rules --with-file-notification=no
|
||||
make uninstall || true
|
||||
make clean
|
||||
export CC=x86_64-unknown-cosmo-cc
|
||||
export CXX=x86_64-unknown-cosmo-c++
|
||||
./configure --prefix=/opt/cosmos/x86_64
|
||||
make -j
|
||||
make install
|
||||
```
|
||||
|
||||
Once you've completed this build process, you'll have the ELF files
|
||||
`/opt/cosmos/x86_64/bin/emacs` and `/opt/cosmos/aarch64/bin/emacs`. Your
|
||||
next move is to combine them into a single pristine `emacs.com` file.
|
||||
## Cosmopolitan Source Builds
|
||||
|
||||
Cosmopolitan can be compiled from source on any of our supported
|
||||
platforms. First, you need to download or clone the repository. If
|
||||
you're not using x86-64 Linux then you'll need cosmocc too.
|
||||
|
||||
```sh
|
||||
cd /zip
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
mkdir -p /opt/cosmos/bin
|
||||
apelink \
|
||||
-o /opt/cosmos/bin/emacs.com \
|
||||
-l "$COSMO/o//ape/ape.elf" \
|
||||
-l "$COSMO/o/aarch64/ape/ape.elf" \
|
||||
-M "$COSMO/ape/ape-m1.c" \
|
||||
/opt/cosmos/x86_64/bin/emacs \
|
||||
/opt/cosmos/aarch64/bin/emacs
|
||||
cd /zip
|
||||
zip -r /opt/cosmos/bin/emacs.com \
|
||||
aarch64/libexec \
|
||||
x86_64/libexec \
|
||||
share/terminfo \
|
||||
$(find share/emacs -type f |
|
||||
grep -v '\.el.gz$' |
|
||||
grep -v refcards |
|
||||
grep -v images)
|
||||
git clone https://github.com/jart/cosmopolitan cosmo
|
||||
cd cosmo
|
||||
mkdir -p o/third_party/gcc
|
||||
pushd o/third_party/gcc
|
||||
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
|
||||
unzip cosmocc.zip
|
||||
popd
|
||||
```
|
||||
|
||||
You can now scp your `emacs.com` build to seven operating systems for
|
||||
two distinct kinds of microprocessors without any dependencies. All the
|
||||
LISP, zoneinfo, and termcap files it needs are stored inside the ZIP
|
||||
structure of the binary, which has performance that's equivalent to the
|
||||
Linux filesystem (even though it decompresses artifacts on the fly!) For
|
||||
this reason, you might actually find that fat APE Emacs goes faster if
|
||||
you're using an operating system like Windows where files are go slow.
|
||||
|
||||
If you like to use Vim instead of Emacs, then you can build that too.
|
||||
However Vim's build system makes it a bit harder, since it's configured
|
||||
to always strip binaries. The `apelink` program needs the symbol tables
|
||||
to still be there when it creates the fat version. Otherwise tools like
|
||||
`--ftrace` won't work.
|
||||
|
||||
## Monolithic Source Builds
|
||||
|
||||
Cosmopolitan can be compiled from source on any Linux distro. First, you
|
||||
need to download or clone the repository.
|
||||
It's recommended that you install a systemwide APE Loader. This command
|
||||
requires `sudo` access to copy the `ape` command to a system folder and
|
||||
register with binfmt_misc on Linux, for even more performance.
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
|
||||
tar xf cosmopolitan.tar.gz # see releases page
|
||||
cd cosmopolitan
|
||||
ape/apeinstall.sh
|
||||
```
|
||||
|
||||
This will build the entire repository and run all the tests:
|
||||
You can now build the mono repo with any modern version of GNU Make. To
|
||||
make life easier, we've included one in the cosmocc toolchain, which is
|
||||
guaranteed to be compatible and furthermore includes our extensions for
|
||||
doing build system sandboxing.
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com
|
||||
o//third_party/gcc/bin/make -j8
|
||||
o//examples/hello.com
|
||||
find o -name \*.com | xargs ls -rShal | less
|
||||
```
|
||||
|
||||
If you get an error running make.com then it's probably because you have
|
||||
WINE installed to `binfmt_misc`. You can fix that by installing the the
|
||||
APE loader as an interpreter. It'll improve build performance too!
|
||||
|
||||
```sh
|
||||
bin/ape-install
|
||||
```
|
||||
|
||||
Since the Cosmopolitan repository is very large, you might only want to
|
||||
build a particular thing. Cosmopolitan's build config does a good job at
|
||||
having minimal deterministic builds. For example, if you wanted to build
|
||||
only hello.com then you could do that as follows:
|
||||
build one particular thing. Here's an example of a target that can be
|
||||
compiled relatively quickly, which is a simple POSIX test that only
|
||||
depends on core LIBC packages.
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com o//examples/hello.com
|
||||
rm -rf o//libc o//test
|
||||
o//third_party/gcc/bin/make o//test/posix/signal_test.com
|
||||
o//test/posix/signal_test.com
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
list out each individual one. You can do that by asking make to build a
|
||||
directory name. For example, if you wanted to build only the targets and
|
||||
subtargets of the chibicc package including its tests, you would say:
|
||||
list out each individual one. For example if you wanted to build and run
|
||||
all the unit tests in the `TEST_POSIX` package, you could say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com o//third_party/chibicc
|
||||
o//third_party/chibicc/chibicc.com --help
|
||||
o//third_party/gcc/bin/make o//test/posix
|
||||
```
|
||||
|
||||
Cosmopolitan provides a variety of build modes. For example, if you want
|
||||
really tiny binaries (as small as 12kb in size) then you'd say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com m=tiny
|
||||
o//third_party/gcc/bin/make m=tiny
|
||||
```
|
||||
|
||||
Here's some other build modes you can try:
|
||||
You can furthermore cut out the bloat of other operating systems, and
|
||||
have Cosmopolitan become much more similar to Musl Libc.
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com m=dbg # asan + ubsan + debug
|
||||
build/bootstrap/make.com m=asan # production memory safety
|
||||
build/bootstrap/make.com m=opt # -march=native optimizations
|
||||
build/bootstrap/make.com m=rel # traditional release binaries
|
||||
build/bootstrap/make.com m=optlinux # optimal linux-only performance
|
||||
build/bootstrap/make.com m=fastbuild # build 28% faster w/o debugging
|
||||
build/bootstrap/make.com m=tinylinux # tiniest linux-only 4kb binaries
|
||||
o//third_party/gcc/bin/make m=tinylinux
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
|
||||
## Cosmopolitan Amalgamation
|
||||
## Debugging
|
||||
|
||||
Another way to use Cosmopolitan is via our amalgamated release, where
|
||||
we've combined everything into a single static archive and a single
|
||||
header file. If you're doing your development work on Linux or BSD then
|
||||
you need just five files to get started. Here's what you do on Linux:
|
||||
To print a log of system calls to stderr:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-3.0.zip
|
||||
unzip cosmopolitan-amalgamation-3.0.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
||||
-o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds -Wl,--gc-sections \
|
||||
-Wl,-z,common-page-size=0x1000 -Wl,-z,max-page-size=0x1000 \
|
||||
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
|
||||
objcopy -S -O binary hello.com.dbg hello.com
|
||||
cosmocc -o hello hello.c
|
||||
./hello --strace
|
||||
```
|
||||
|
||||
You now have a portable program.
|
||||
To print a log of function calls to stderr:
|
||||
|
||||
```sh
|
||||
./hello.com
|
||||
bash -c './hello.com' # older zsh/fish workaround (patched in zsh 5.9 and fish 3.3.0)
|
||||
cosmocc -o hello hello.c
|
||||
./hello --ftrace
|
||||
```
|
||||
|
||||
If `./hello.com` executed on Linux throws an error about not finding an
|
||||
interpreter, it should be fixed by running the following command (although
|
||||
note that it may not survive a system restart):
|
||||
Both strace and ftrace use the unbreakable kprintf() facility, which is
|
||||
able to be sent to a file by setting an environment variable.
|
||||
|
||||
```sh
|
||||
sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
|
||||
export KPRINTF_LOG=log
|
||||
./hello --strace
|
||||
```
|
||||
|
||||
If the same command produces puzzling errors on WSL or WINE when using
|
||||
Redbean 2.x, they may be fixed by disabling binfmt_misc:
|
||||
|
||||
```sh
|
||||
sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status'
|
||||
```
|
||||
|
||||
Since we used the `ape-no-modify-self.o` bootloader (rather than
|
||||
`ape.o`) your executable will not modify itself when it's run. What
|
||||
it'll instead do, is extract a 4kb program (the [APE loader](https://justine.lol/apeloader/))
|
||||
to `${TMPDIR:-${HOME:-.}}` that maps your program into memory without
|
||||
needing to copy it. The APE loader must be in an executable location
|
||||
(e.g. not stored on a `noexec` mount) for it to run. See below for
|
||||
alternatives:
|
||||
|
||||
It's possible to install the APE loader systemwide as follows.
|
||||
|
||||
```sh
|
||||
# System-Wide APE Install
|
||||
# for Linux, Darwin, and BSDs
|
||||
# 1. Copies APE Loader to /usr/bin/ape
|
||||
# 2. Registers w/ binfmt_misc too if Linux
|
||||
bin/ape-install
|
||||
|
||||
# System-Wide APE Uninstall
|
||||
# for Linux, Darwin, and BSDs
|
||||
bin/ape-uninstall
|
||||
```
|
||||
|
||||
It's also possible to convert APE binaries into the system-local format
|
||||
by using the `--assimilate` flag. Please note that if binfmt_misc is in
|
||||
play, you'll need to unregister it temporarily before doing this, since
|
||||
the assimilate feature is part of the shell script header.
|
||||
|
||||
```sh
|
||||
$ file hello.com
|
||||
hello.com: DOS/MBR boot sector
|
||||
./hello.com --assimilate
|
||||
$ file hello.com
|
||||
hello.com: ELF 64-bit LSB executable
|
||||
```
|
||||
|
||||
Now that you're up and running with Cosmopolitan Libc and APE, here's
|
||||
some of the most important troubleshooting tools APE offers that you
|
||||
should know, in case you encounter any issues:
|
||||
|
||||
```sh
|
||||
./hello.com --strace # log system calls to stderr
|
||||
./hello.com --ftrace # log function calls to stderr
|
||||
```
|
||||
|
||||
Do you love tiny binaries? If so, you may not be happy with Cosmo adding
|
||||
heavyweight features like tracing to your binaries by default. In that
|
||||
case, you may want to consider using our build system:
|
||||
|
||||
```sh
|
||||
make m=tiny
|
||||
```
|
||||
|
||||
Which will cause programs such as `hello.com` and `life.com` to shrink
|
||||
from 60kb in size to about 16kb. There's also a prebuilt amalgamation
|
||||
online <https://justine.lol/cosmopolitan/cosmopolitan-tiny.zip> hosted
|
||||
on our download page <https://justine.lol/cosmopolitan/download.html>.
|
||||
|
||||
## GDB
|
||||
|
||||
Here's the recommended `~/.gdbinit` config:
|
||||
@@ -542,39 +196,52 @@ You normally run the `.com.dbg` file under gdb. If you need to debug the
|
||||
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
```
|
||||
|
||||
## Alternative Development Environments
|
||||
## Platform Notes
|
||||
|
||||
### MacOS
|
||||
### Shells
|
||||
|
||||
If you're developing on MacOS you can install the GNU compiler
|
||||
collection for x86_64-elf via homebrew:
|
||||
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.
|
||||
|
||||
### Linux
|
||||
|
||||
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
|
||||
brew install x86_64-elf-gcc
|
||||
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
|
||||
```
|
||||
|
||||
Then in the above scripts just replace `gcc` and `objcopy` with
|
||||
`x86_64-elf-gcc` and `x86_64-elf-objcopy` to compile your APE binary.
|
||||
|
||||
### Windows
|
||||
|
||||
If you're developing on Windows then you need to download an
|
||||
x86_64-pc-linux-gnu toolchain beforehand. See the [Compiling on
|
||||
Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
|
||||
tutorial. It's needed because the ELF object format is what makes
|
||||
universal binaries possible.
|
||||
|
||||
Cosmopolitan officially only builds on Linux. However, one highly
|
||||
experimental (and currently broken) thing you could try, is building the
|
||||
entire cosmo repository from source using the cross9 toolchain.
|
||||
You can fix that by registering APE with `binfmt_misc`:
|
||||
|
||||
```sh
|
||||
mkdir -p o/third_party
|
||||
rm -rf o/third_party/gcc
|
||||
wget https://justine.lol/linux-compiler-on-windows/cross9.zip
|
||||
unzip cross9.zip
|
||||
mv cross9 o/third_party/gcc
|
||||
build/bootstrap/make.com
|
||||
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 MZ executables as WIN32 binaries within the WSL environment. In
|
||||
order to make it safe to use Cosmopolitan software on WSL, run this:
|
||||
|
||||
```sh
|
||||
sudo sh -c "echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop"
|
||||
```
|
||||
|
||||
## Discord Chatroom
|
||||
|
||||
+184
-192
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libkern/OSCacheControl.h>
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/uio.h>
|
||||
@@ -34,7 +36,7 @@
|
||||
|
||||
#define pagesz 16384
|
||||
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
|
||||
#define SYSLIB_VERSION 5
|
||||
#define SYSLIB_VERSION 8
|
||||
|
||||
struct Syslib {
|
||||
int magic;
|
||||
@@ -60,7 +62,7 @@ struct Syslib {
|
||||
/* v2 (2023-09-10) */
|
||||
pthread_t (*pthread_self)(void);
|
||||
void (*dispatch_release)(dispatch_semaphore_t);
|
||||
int (*raise)(int);
|
||||
long (*raise)(int);
|
||||
int (*pthread_join)(pthread_t, void **);
|
||||
void (*pthread_yield_np)(void);
|
||||
int pthread_stack_min;
|
||||
@@ -91,6 +93,11 @@ struct Syslib {
|
||||
long (*sem_trywait)(int *);
|
||||
long (*getrlimit)(int, struct rlimit *);
|
||||
long (*setrlimit)(int, const struct rlimit *);
|
||||
// v6 (2023-11-03)
|
||||
void *(*dlopen)(const char *, int);
|
||||
void *(*dlsym)(void *, const char *);
|
||||
int (*dlclose)(void *);
|
||||
char *(*dlerror)(void);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
@@ -225,60 +232,6 @@ static const char *BaseName(const char *s) {
|
||||
return b;
|
||||
}
|
||||
|
||||
static void Bzero(void *a, unsigned long n) {
|
||||
long z;
|
||||
char *p, *e;
|
||||
p = (char *)a;
|
||||
e = p + n;
|
||||
z = 0;
|
||||
while (p + sizeof(z) <= e) {
|
||||
__builtin_memcpy(p, &z, sizeof(z));
|
||||
p += sizeof(z);
|
||||
}
|
||||
while (p < e) {
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *MemChr(const char *s, unsigned char c, unsigned long n) {
|
||||
for (; n; --n, ++s) {
|
||||
if ((*s & 255) == c) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *MemMove(void *a, const void *b, unsigned long n) {
|
||||
long w;
|
||||
char *d;
|
||||
const char *s;
|
||||
unsigned long i;
|
||||
d = (char *)a;
|
||||
s = (const char *)b;
|
||||
if (d > s) {
|
||||
while (n >= sizeof(w)) {
|
||||
n -= sizeof(w);
|
||||
__builtin_memcpy(&w, s + n, sizeof(n));
|
||||
__builtin_memcpy(d + n, &w, sizeof(n));
|
||||
}
|
||||
while (n--) {
|
||||
d[n] = s[n];
|
||||
}
|
||||
} else {
|
||||
i = 0;
|
||||
while (i + sizeof(w) <= n) {
|
||||
__builtin_memcpy(&w, s + i, sizeof(i));
|
||||
__builtin_memcpy(d + i, &w, sizeof(i));
|
||||
i += sizeof(w);
|
||||
}
|
||||
for (; i < n; ++i) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static char *GetEnv(char **p, const char *s) {
|
||||
unsigned long i, j;
|
||||
if (p) {
|
||||
@@ -361,7 +314,7 @@ __attribute__((__noreturn__)) static void Pexit(const char *c, int failed,
|
||||
static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen + 1 + ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
MemMove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
return !access(ps->path, X_OK);
|
||||
}
|
||||
@@ -390,7 +343,7 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||
|
||||
/* paths are always 100% taken literally when a slash exists
|
||||
$ ape foo/bar.com arg1 arg2 */
|
||||
if (MemChr(ps->name, '/', ps->namelen)) {
|
||||
if (memchr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
@@ -476,6 +429,111 @@ static void pthread_jit_write_protect_np_workaround(int enabled) {
|
||||
Pexit("ape", 0, "failed to set jit write protection");
|
||||
}
|
||||
|
||||
__attribute__((__noinline__)) static long sysret(long rc) {
|
||||
return rc == -1 ? -errno : rc;
|
||||
}
|
||||
|
||||
static long sys_fork(void) {
|
||||
return sysret(fork());
|
||||
}
|
||||
|
||||
static long sys_close(int fd) {
|
||||
return sysret(close(fd));
|
||||
}
|
||||
|
||||
static long sys_raise(int sig) {
|
||||
return sysret(raise(sig));
|
||||
}
|
||||
|
||||
static long sys_pipe(int pfds[2]) {
|
||||
return sysret(pipe(pfds));
|
||||
}
|
||||
|
||||
static long sys_munmap(void *addr, size_t size) {
|
||||
return sysret(munmap(addr, size));
|
||||
}
|
||||
|
||||
static long sys_read(int fd, void *data, size_t size) {
|
||||
return sysret(read(fd, data, size));
|
||||
}
|
||||
|
||||
static long sys_mprotect(void *data, size_t size, int prot) {
|
||||
return sysret(mprotect(data, size, prot));
|
||||
}
|
||||
|
||||
static long sys_sigaltstack(const stack_t *ss, stack_t *oss) {
|
||||
return sysret(sigaltstack(ss, oss));
|
||||
}
|
||||
|
||||
static long sys_getentropy(void *buf, size_t buflen) {
|
||||
return sysret(getentropy(buf, buflen));
|
||||
}
|
||||
|
||||
static long sys_sem_open(const char *name, int oflags, mode_t mode,
|
||||
unsigned value) {
|
||||
return sysret((long)sem_open(name, oflags, mode, value));
|
||||
}
|
||||
|
||||
static long sys_sem_unlink(const char *name) {
|
||||
return sysret(sem_unlink(name));
|
||||
}
|
||||
|
||||
static long sys_sem_close(sem_t *sem) {
|
||||
return sysret(sem_close(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_post(sem_t *sem) {
|
||||
return sysret(sem_post(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_wait(sem_t *sem) {
|
||||
return sysret(sem_wait(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_trywait(sem_t *sem) {
|
||||
return sysret(sem_trywait(sem));
|
||||
}
|
||||
|
||||
static long sys_getrlimit(int which, struct rlimit *rlim) {
|
||||
return sysret(getrlimit(which, rlim));
|
||||
}
|
||||
|
||||
static long sys_setrlimit(int which, const struct rlimit *rlim) {
|
||||
return sysret(setrlimit(which, rlim));
|
||||
}
|
||||
|
||||
static long sys_write(int fd, const void *data, size_t size) {
|
||||
return sysret(write(fd, data, size));
|
||||
}
|
||||
|
||||
static long sys_clock_gettime(int clock, struct timespec *ts) {
|
||||
return sysret(clock_gettime((clockid_t)clock, ts));
|
||||
}
|
||||
|
||||
static long sys_openat(int fd, const char *path, int flags, int mode) {
|
||||
return sysret(openat(fd, path, flags, mode));
|
||||
}
|
||||
|
||||
static long sys_nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
return sysret(nanosleep(req, rem));
|
||||
}
|
||||
|
||||
static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
off_t off) {
|
||||
return sysret((long)mmap(addr, size, prot, flags, fd, off));
|
||||
}
|
||||
|
||||
static long sys_sigaction(int sig, const struct sigaction *act,
|
||||
struct sigaction *oact) {
|
||||
return sysret(sigaction(sig, act, oact));
|
||||
}
|
||||
|
||||
static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, const struct timespec *timeout,
|
||||
const sigset_t *sigmask) {
|
||||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
long *sp, struct ElfEhdr *e,
|
||||
struct ElfPhdr *p,
|
||||
@@ -542,8 +600,8 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
/* choose loading address for dynamic elf executables
|
||||
that maintains relative distances between segments */
|
||||
if (e->e_type == ET_DYN) {
|
||||
rc = (long)mmap(0, virtmax - virtmin, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
rc = sys_mmap(0, virtmax - virtmin, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "pie mmap");
|
||||
dynbase = rc;
|
||||
if (dynbase & (pagesz - 1)) {
|
||||
@@ -593,17 +651,47 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
}
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = (long)mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot1 & PROT_EXEC) {
|
||||
#ifdef SIP_DISABLED
|
||||
// if sip is disabled then we can load the executable segments
|
||||
// off the binary into memory without needing to copy anything
|
||||
// which provides considerably better performance for building
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) {
|
||||
if (rc == -EPERM) {
|
||||
Pexit(exe, rc,
|
||||
"map(exec) failed because SIP (System Integrity Protection) "
|
||||
"is enabled, but APE Loader was compiled with SIP_DISABLED");
|
||||
} else {
|
||||
Pexit(exe, rc, "map(exec) failed");
|
||||
}
|
||||
}
|
||||
#else
|
||||
// the issue is that if sip is enabled then, attempting to map
|
||||
// it with exec permission will cause xnu to phone home a hash
|
||||
// of the entire file to apple intelligence as a one time cost
|
||||
// which is literally minutes for executables holding big data
|
||||
// since there's no public apple api for detecting sip we read
|
||||
// as the default strategy which is slow but it works for both
|
||||
rc = sys_mmap(addr, size, (prot1 = PROT_READ | PROT_WRITE),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap anon");
|
||||
rc = pread(fd, addr, p[i].p_filesz, p[i].p_offset & -pagesz);
|
||||
if (rc != p[i].p_filesz) Pexit(exe, -errno, "prog pread");
|
||||
#endif
|
||||
} else {
|
||||
rc = sys_mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
}
|
||||
if (wipe) memset((void *)(dynbase + a), 0, wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = mprotect(addr, size, prot2);
|
||||
rc = sys_mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = (long)mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
rc = sys_mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
@@ -611,7 +699,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = (long)mmap(addr, size, prot, flags, -1, 0);
|
||||
rc = sys_mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
@@ -708,7 +796,7 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
for (i = 0; i < e->e_phnum;) {
|
||||
if (p[i].p_type == PT_LOAD && !p[i].p_memsz) {
|
||||
if (i + 1 < e->e_phnum) {
|
||||
MemMove(p + i, p + i + 1,
|
||||
memmove(p + i, p + i + 1,
|
||||
(e->e_phnum - (i + 1)) * sizeof(struct ElfPhdr));
|
||||
}
|
||||
--e->e_phnum;
|
||||
@@ -736,7 +824,7 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
p[i].p_memsz = (p[i + 1].p_vaddr + p[i + 1].p_memsz) - p[i].p_vaddr;
|
||||
p[i].p_filesz = (p[i + 1].p_offset + p[i + 1].p_filesz) - p[i].p_offset;
|
||||
if (i + 2 < e->e_phnum) {
|
||||
MemMove(p + i + 1, p + i + 2,
|
||||
memmove(p + i + 1, p + i + 2,
|
||||
(e->e_phnum - (i + 2)) * sizeof(struct ElfPhdr));
|
||||
}
|
||||
--e->e_phnum;
|
||||
@@ -780,107 +868,6 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
Spawn(exe, fd, sp, e, p, &M->lib);
|
||||
}
|
||||
|
||||
__attribute__((__noinline__)) static long sysret(long rc) {
|
||||
return rc == -1 ? -errno : rc;
|
||||
}
|
||||
|
||||
static long sys_fork(void) {
|
||||
return sysret(fork());
|
||||
}
|
||||
|
||||
static long sys_close(int fd) {
|
||||
return sysret(close(fd));
|
||||
}
|
||||
|
||||
static long sys_pipe(int pfds[2]) {
|
||||
return sysret(pipe(pfds));
|
||||
}
|
||||
|
||||
static long sys_munmap(void *addr, size_t size) {
|
||||
return sysret(munmap(addr, size));
|
||||
}
|
||||
|
||||
static long sys_read(int fd, void *data, size_t size) {
|
||||
return sysret(read(fd, data, size));
|
||||
}
|
||||
|
||||
static long sys_mprotect(void *data, size_t size, int prot) {
|
||||
return sysret(mprotect(data, size, prot));
|
||||
}
|
||||
|
||||
static long sys_sigaltstack(const stack_t *ss, stack_t *oss) {
|
||||
return sysret(sigaltstack(ss, oss));
|
||||
}
|
||||
|
||||
static long sys_getentropy(void *buf, size_t buflen) {
|
||||
return sysret(getentropy(buf, buflen));
|
||||
}
|
||||
|
||||
static long sys_sem_open(const char *name, int oflags, mode_t mode,
|
||||
unsigned value) {
|
||||
return sysret((long)sem_open(name, oflags, mode, value));
|
||||
}
|
||||
|
||||
static long sys_sem_unlink(const char *name) {
|
||||
return sysret(sem_unlink(name));
|
||||
}
|
||||
|
||||
static long sys_sem_close(sem_t *sem) {
|
||||
return sysret(sem_close(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_post(sem_t *sem) {
|
||||
return sysret(sem_post(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_wait(sem_t *sem) {
|
||||
return sysret(sem_wait(sem));
|
||||
}
|
||||
|
||||
static long sys_sem_trywait(sem_t *sem) {
|
||||
return sysret(sem_trywait(sem));
|
||||
}
|
||||
|
||||
static long sys_getrlimit(int which, struct rlimit *rlim) {
|
||||
return sysret(getrlimit(which, rlim));
|
||||
}
|
||||
|
||||
static long sys_setrlimit(int which, const struct rlimit *rlim) {
|
||||
return sysret(setrlimit(which, rlim));
|
||||
}
|
||||
|
||||
static long sys_write(int fd, const void *data, size_t size) {
|
||||
return sysret(write(fd, data, size));
|
||||
}
|
||||
|
||||
static long sys_clock_gettime(int clock, struct timespec *ts) {
|
||||
return sysret(clock_gettime((clockid_t)clock, ts));
|
||||
}
|
||||
|
||||
static long sys_openat(int fd, const char *path, int flags, int mode) {
|
||||
return sysret(openat(fd, path, flags, mode));
|
||||
}
|
||||
|
||||
static long sys_nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
return sysret(nanosleep(req, rem));
|
||||
}
|
||||
|
||||
static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
off_t off) {
|
||||
return sysret((long)mmap(addr, size, prot, flags, fd, off));
|
||||
}
|
||||
|
||||
static long sys_sigaction(int sig, const struct sigaction *act,
|
||||
struct sigaction *oact) {
|
||||
return sysret(sigaction(sig, act, oact));
|
||||
}
|
||||
|
||||
static long sys_pselect(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *errorfds, const struct timespec *timeout,
|
||||
const sigset_t *sigmask) {
|
||||
return sysret(pselect(nfds, readfds, writefds, errorfds, timeout, sigmask));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
unsigned i;
|
||||
int c, n, fd, rc;
|
||||
@@ -904,6 +891,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.pthread_jit_write_protect_supported_np =
|
||||
pthread_jit_write_protect_supported_np;
|
||||
M->lib.pthread_jit_write_protect_np = pthread_jit_write_protect_np_workaround;
|
||||
M->lib.sys_icache_invalidate = sys_icache_invalidate;
|
||||
M->lib.pthread_create = pthread_create;
|
||||
M->lib.pthread_exit = pthread_exit;
|
||||
M->lib.pthread_kill = pthread_kill;
|
||||
@@ -915,7 +903,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.dispatch_walltime = dispatch_walltime;
|
||||
M->lib.pthread_self = pthread_self;
|
||||
M->lib.dispatch_release = dispatch_release;
|
||||
M->lib.raise = raise;
|
||||
M->lib.raise = sys_raise;
|
||||
M->lib.pthread_join = pthread_join;
|
||||
M->lib.pthread_yield_np = pthread_yield_np;
|
||||
M->lib.pthread_stack_min = PTHREAD_STACK_MIN;
|
||||
@@ -943,6 +931,10 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.sem_trywait = sys_sem_trywait;
|
||||
M->lib.getrlimit = sys_getrlimit;
|
||||
M->lib.setrlimit = sys_setrlimit;
|
||||
M->lib.dlopen = dlopen;
|
||||
M->lib.dlsym = dlsym;
|
||||
M->lib.dlclose = dlclose;
|
||||
M->lib.dlerror = dlerror;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = argc > 0 ? argv[0] : 0;
|
||||
@@ -956,6 +948,21 @@ int main(int argc, char **argv, char **envp) {
|
||||
sp = (long *)(argv - 1);
|
||||
auxv = (long *)(envp + i + 1);
|
||||
|
||||
/* create new bottom of stack for spawned program
|
||||
system v abi aligns this on a 16-byte boundary
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
memmove(sp2, sp, (auxv - sp) * sizeof(long));
|
||||
argv = (char **)(sp2 + 1);
|
||||
envp = (char **)(sp2 + 1 + argc + 1);
|
||||
auxv = sp2 + (auxv - sp);
|
||||
sp = sp2;
|
||||
|
||||
/* interpret command line arguments */
|
||||
if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
/* if the first argument is a hyphen then we give the user the
|
||||
@@ -968,7 +975,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
} else if (argc < 2) {
|
||||
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
|
||||
" ape - PROG [ARGV0,ARGV1,...]\n"
|
||||
"actually portable executable loader silicon 1.8\n"
|
||||
"actually portable executable loader silicon 1.9\n"
|
||||
"copyright 2023 justine alexandra roberts tunney\n"
|
||||
"https://justine.lol/ape.html\n");
|
||||
_exit(1);
|
||||
@@ -978,21 +985,6 @@ int main(int argc, char **argv, char **envp) {
|
||||
argv = (char **)((sp += 1) + 1);
|
||||
}
|
||||
|
||||
/* create new bottom of stack for spawned program
|
||||
system v abi aligns this on a 16-byte boundary
|
||||
grows down the alloc by poking the guard pages */
|
||||
n = (auxv - sp + AUXV_WORDS + 1) * sizeof(long);
|
||||
sp2 = (long *)__builtin_alloca(n);
|
||||
if ((long)sp2 & 15) ++sp2;
|
||||
for (; n > 0; n -= pagesz) {
|
||||
((char *)sp2)[n - 1] = 0;
|
||||
}
|
||||
MemMove(sp2, sp, (auxv - sp) * sizeof(long));
|
||||
argv = (char **)(sp2 + 1);
|
||||
envp = (char **)(sp2 + 1 + argc + 1);
|
||||
auxv = sp2 + (auxv - sp);
|
||||
sp = sp2;
|
||||
|
||||
/* allocate ephemeral memory for reading file */
|
||||
n = sizeof(union ElfEhdrBuf);
|
||||
ebuf = (union ElfEhdrBuf *)__builtin_alloca(n);
|
||||
@@ -1003,10 +995,10 @@ int main(int argc, char **argv, char **envp) {
|
||||
/* search for executable */
|
||||
if (!(exe = Commandv(&M->ps, prog, GetEnv(envp, "PATH")))) {
|
||||
Pexit(prog, 0, "not found (maybe chmod +x)");
|
||||
} else if ((fd = openat(AT_FDCWD, exe, O_RDONLY)) < 0) {
|
||||
Pexit(exe, -1, "open");
|
||||
} else if ((rc = read(fd, ebuf->buf, sizeof(ebuf->buf))) < 0) {
|
||||
Pexit(exe, -1, "read");
|
||||
} else if ((fd = sys_openat(AT_FDCWD, exe, O_RDONLY, 0)) < 0) {
|
||||
Pexit(exe, fd, "open");
|
||||
} else if ((rc = sys_read(fd, ebuf->buf, sizeof(ebuf->buf))) < 0) {
|
||||
Pexit(exe, rc, "read");
|
||||
} else if ((unsigned long)rc < sizeof(ebuf->ehdr)) {
|
||||
Pexit(exe, 0, "too small");
|
||||
}
|
||||
@@ -1019,8 +1011,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
/* generate some hard random data */
|
||||
if (getentropy(M->rando, sizeof(M->rando))) {
|
||||
Pexit(argv[0], -1, "getentropy");
|
||||
if ((rc = sys_getentropy(M->rando, sizeof(M->rando))) < 0) {
|
||||
Pexit(argv[0], rc, "getentropy");
|
||||
}
|
||||
|
||||
/* ape intended behavior
|
||||
|
||||
@@ -592,7 +592,9 @@ ape_disk:
|
||||
|
||||
#ifdef APE_IS_SHELL_SCRIPT
|
||||
apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.ascii "m=\"$(uname -m)\"\n"
|
||||
.ascii "m=$(/bin/uname -m 2>/dev/null) || "
|
||||
.ascii "m=$(/usr/bin/uname -m 2>/dev/null) || "
|
||||
.ascii "m=x86_64\n"
|
||||
|
||||
.ascii "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]; then\n"
|
||||
// Until all operating systems can be updated to support APE,
|
||||
@@ -615,15 +617,15 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.ascii APE_VERSION_STR
|
||||
.ascii "\"\n"
|
||||
.ascii "[ -x \"$t\" ] || {\n"
|
||||
.ascii "mkdir -p \"${t%/*}\" &&\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
|
||||
.ascii "/bin/mkdir -p \"${t%/*}\" &&\n"
|
||||
.ascii "/bin/dd if=\"$o\" of=\"$t.$$\" skip="
|
||||
.shstub ape_loader_dd_skip,2
|
||||
.ascii " count="
|
||||
.shstub ape_loader_dd_count,2
|
||||
.ascii " bs=64 2>/dev/null\n"
|
||||
#if SupportsXnu()
|
||||
.ascii "[ -d /Applications ] && "
|
||||
.ascii "dd if=\"$t.$$\""
|
||||
.ascii "/bin/dd if=\"$t.$$\""
|
||||
.ascii " of=\"$t.$$\""
|
||||
.ascii " skip=5"
|
||||
.ascii " count=8"
|
||||
@@ -631,8 +633,8 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.ascii " conv=notrunc"
|
||||
.ascii " 2>/dev/null\n"
|
||||
#endif /* SupportsXnu() */
|
||||
.ascii "chmod 755 \"$t.$$\"\n"
|
||||
.ascii "mv -f \"$t.$$\" \"$t\"\n"
|
||||
.ascii "/bin/chmod 755 \"$t.$$\"\n"
|
||||
.ascii "/bin/mv -f \"$t.$$\" \"$t\"\n"
|
||||
.ascii "}\n"
|
||||
.ascii "exec \"$t\" \"$o\" \"$@\"\n"
|
||||
.ascii "}\n"
|
||||
@@ -648,9 +650,9 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.ascii "t=\"${TMPDIR:-${HOME:-.}}/$0\"\n"
|
||||
.ascii "[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n"
|
||||
.ascii "[ x\"$1\" != x--assimilate ] && {\n"
|
||||
.ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n"
|
||||
.ascii "cp -f \"$o\" \"$t.$$\" &&\n"
|
||||
.ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n"
|
||||
.ascii "/bin/mkdir -p \"${t%/*}\" 2>/dev/null\n"
|
||||
.ascii "/bin/cp -f \"$o\" \"$t.$$\" &&\n"
|
||||
.ascii "/bin/mv -f \"$t.$$\" \"$t\" || exit 120\n"
|
||||
.ascii "o=\"$t\"\n"
|
||||
.ascii "}\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
@@ -681,7 +683,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
.ascii "exec 7<&-\n"
|
||||
#if SupportsXnu()
|
||||
.ascii "[ -d /Applications ] && "
|
||||
.ascii "dd if=\"$o\""
|
||||
.ascii "/bin/dd if=\"$o\""
|
||||
.ascii " of=\"$o\""
|
||||
.ascii " bs=8"
|
||||
.ascii " skip="
|
||||
@@ -710,7 +712,9 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
||||
// because they need to be in the first 4096 bytes
|
||||
.section .emushprologue,"a",@progbits
|
||||
emush: .ascii "\n@\n#'\"\n"
|
||||
.ascii "s=\"$(uname -s)\"\n"
|
||||
.ascii "s=$(/bin/uname -s 2>/dev/null) || "
|
||||
.ascii "s=$(/usr/bin/uname -s 2>/dev/null) || "
|
||||
.ascii "s=Darwin\n"
|
||||
// our script is running on a non-x86_64 architecture
|
||||
// 1. `dd` out the appropriate blink vm blob
|
||||
// 2. gunzip the blink virtual machine executable
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define COSMOPOLITAN_APE_APE_H_
|
||||
|
||||
#define APE_VERSION_MAJOR 1
|
||||
#define APE_VERSION_MINOR 8
|
||||
#define APE_VERSION_MINOR 9
|
||||
#define APE_VERSION_STR APE_VERSION_STR_(APE_VERSION_MAJOR, APE_VERSION_MINOR)
|
||||
#define APE_VERSION_NOTE APE_VERSION_NOTE_(APE_VERSION_MAJOR, APE_VERSION_MINOR)
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../bin/ape-install
|
||||
Executable
+148
@@ -0,0 +1,148 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-$m}
|
||||
TMPDIR=${TMPDIR:-/tmp}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
fi
|
||||
|
||||
echo "Actually Portable Executable (APE) Installer" >&2
|
||||
echo "Author: Justine Tunney <[email protected]>" >&2
|
||||
|
||||
# special installation process for apple silicon
|
||||
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
|
||||
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
|
||||
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
|
||||
if [ ! -d /usr/local/bin ]; then
|
||||
echo "$SUDO mkdir -p /usr/local/bin" >&2
|
||||
$SUDO mkdir -p /usr/local/bin || exit
|
||||
fi
|
||||
echo "$SUDO mv -f $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
|
||||
$SUDO mv -f "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
|
||||
exit
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# INSTALL APE LOADER SYSTEMWIDE
|
||||
|
||||
if [ -f o/depend ] && make -j8 o//ape; then
|
||||
echo "successfully recompiled ape loader" >&2
|
||||
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
|
||||
echo "using ape loader you compiled earlier" >&2
|
||||
elif [ -d build/bootstrap ]; then
|
||||
# if make isn't being used then it's unlikely the user changed the sources
|
||||
# in that case the prebuilt binaries should be completely up-to-date
|
||||
echo "using prebuilt ape loader from cosmo repo" >&2
|
||||
mkdir -p o//ape || exit
|
||||
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
|
||||
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
|
||||
else
|
||||
echo "no cosmopolitan libc repository here" >&2
|
||||
echo "fetching ape loader from justine.lol" >&2
|
||||
mkdir -p o//ape || exit
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
else
|
||||
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
fi
|
||||
chmod +x o//ape/ape.elf || exit
|
||||
chmod +x o//ape/ape.macho || exit
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.macho to /usr/bin/ape" >&2
|
||||
echo "$SUDO cp -f o//ape/ape.macho /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
else
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
|
||||
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# REGISTER APE LOADER WITH BINFMT_MISC TOO (LINUX-ONLY)
|
||||
|
||||
if [ x"$(uname -s)" = xLinux ]; then
|
||||
|
||||
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
echo >&2
|
||||
echo it looks like APE is already registered with binfmt_misc >&2
|
||||
echo To reinstall please run ape/apeuninstall.sh first >&2
|
||||
echo please check that it is mapped to ape not /bin/sh >&2
|
||||
echo cat /proc/sys/fs/binfmt_misc/APE >&2
|
||||
cat /proc/sys/fs/binfmt_misc/APE >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! [ -e /proc/sys/fs/binfmt_misc ]; then
|
||||
echo >&2
|
||||
echo loading binfmt_misc into your kernel >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO modprobe binfmt_misc >&2
|
||||
$SUDO modprobe binfmt_misc || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
if ! [ -e /proc/sys/fs/binfmt_misc/register ]; then
|
||||
echo >&2
|
||||
echo mounting binfmt_misc into your kernel >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc >&2
|
||||
$SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo registering APE with binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
echo >&2
|
||||
echo enabling binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' >&2
|
||||
$SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
{
|
||||
echo
|
||||
echo "------------------------------------------------------------------"
|
||||
echo
|
||||
echo "APE INSTALL COMPLETE"
|
||||
echo
|
||||
echo "If you decide to uninstall APE later on"
|
||||
echo "you may do so using ape/apeuninstall.sh"
|
||||
echo
|
||||
echo "Enjoy your APE loader (>'.')>"
|
||||
echo
|
||||
} >&2
|
||||
@@ -1 +0,0 @@
|
||||
../bin/ape-uninstall
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ "$UID" = "0" ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
fi
|
||||
|
||||
{
|
||||
echo
|
||||
echo "APE Uninstaller intends to run (in pseudo-shell)"
|
||||
echo
|
||||
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
|
||||
echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc."
|
||||
echo
|
||||
echo "You may then use ape/apeinstall.sh to reinstall it"
|
||||
echo
|
||||
} >&2
|
||||
|
||||
set -ex
|
||||
for f in /proc/sys/fs/binfmt_misc/APE*; do
|
||||
if [ -f $f ]; then
|
||||
$SUDO sh -c "echo -1 >$f" || exit
|
||||
fi
|
||||
done
|
||||
|
||||
# system installation
|
||||
if [ -f /usr/bin/ape ]; then
|
||||
$SUDO rm -f /usr/bin/ape
|
||||
fi
|
||||
if [ -f /usr/local/bin/ape ]; then
|
||||
$SUDO rm -f /usr/local/bin/ape
|
||||
fi
|
||||
|
||||
# legacy installations
|
||||
rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape"
|
||||
|
||||
# ad-hoc installations
|
||||
for x in .ape \
|
||||
.ape-1.1 \
|
||||
.ape-1.3 \
|
||||
.ape-1.4 \
|
||||
.ape-1.5 \
|
||||
.ape-1.6 \
|
||||
.ape-1.7 \
|
||||
.ape-1.8 \
|
||||
.ape-1.9 \
|
||||
.ape-blink-0.9.2 \
|
||||
.ape-blink-1.0.0; do
|
||||
rm -f \
|
||||
~/$x \
|
||||
/tmp/$x \
|
||||
o/tmp/$x \
|
||||
"${TMPDIR:-/tmp}/$x"
|
||||
done
|
||||
@@ -947,6 +947,11 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
os = OPENBSD;
|
||||
}
|
||||
|
||||
/* xnu passes auxv as an array of strings */
|
||||
if (os == XNU) {
|
||||
*auxv = 0;
|
||||
}
|
||||
|
||||
/* detect netbsd and find end of words */
|
||||
pagesz = 0;
|
||||
for (ap = auxv; ap[0]; ap += 2) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifdef __aarch64__
|
||||
|
||||
_start: mov x1,sp
|
||||
and sp,x1,#-16
|
||||
mov x29,0
|
||||
bl ApeLoader
|
||||
.endfn _start,globl
|
||||
@@ -33,6 +34,7 @@ XnuEntrypoint:
|
||||
mov $_HOSTXNU,%dl // xnu's not unix!
|
||||
ElfEntrypoint:
|
||||
mov %rsp,%rsi // save real stack
|
||||
andq $-16,%rsp // force SSE alignment
|
||||
call ApeLoader
|
||||
.endfn ElfEntrypoint,globl
|
||||
.endfn XnuEntrypoint,globl
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-addr2line"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1 +0,0 @@
|
||||
apecopy
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
|
||||
fatal_error() {
|
||||
echo "$PROG: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
if [ ! -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" ]; then
|
||||
fatal_error "you need to run: aarch64-unknown-cosmo-cc --update"
|
||||
fi
|
||||
|
||||
exec "$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-ar" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-as"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-nm"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objcopy"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-objdump"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-${m:-aarch64}}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos/aarch64}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/aarch64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/aarch64-linux-$BRAND-strip"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: aarch64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
fi
|
||||
|
||||
echo "Actually Portable Executable (APE) Installer" >&2
|
||||
echo "Author: Justine Tunney <[email protected]>" >&2
|
||||
|
||||
################################################################################
|
||||
# INSTALL APE LOADER SYSTEMWIDE
|
||||
|
||||
if [ -f o/depend ] && make -j8 o//ape; then
|
||||
echo "successfully recompiled ape loader" >&2
|
||||
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
|
||||
echo "using ape loader you compiled earlier" >&2
|
||||
elif [ -d build/bootstrap ]; then
|
||||
# if make isn't being used then it's unlikely the user changed the sources
|
||||
# in that case the prebuilt binaries should be completely up-to-date
|
||||
echo "using prebuilt ape loader from cosmo repo" >&2
|
||||
mkdir -p o//ape || exit
|
||||
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
|
||||
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
|
||||
else
|
||||
echo "no cosmopolitan libc repository here" >&2
|
||||
echo "fetching ape loader from justine.lol" >&2
|
||||
mkdir -p o//ape || exit
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
else
|
||||
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
|
||||
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
|
||||
fi
|
||||
chmod +x o//ape/ape.elf || exit
|
||||
chmod +x o//ape/ape.macho || exit
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
|
||||
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
else
|
||||
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
|
||||
echo >&2
|
||||
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
|
||||
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
|
||||
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# REGISTER APE LOADER WITH BINFMT_MISC TOO (LINUX-ONLY)
|
||||
|
||||
if [ x"$(uname -s)" = xLinux ]; then
|
||||
|
||||
if [ -e /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
echo >&2
|
||||
echo it looks like APE is already registered with binfmt_misc >&2
|
||||
echo To reinstall please run ape/apeuninstall.sh first >&2
|
||||
echo please check that it is mapped to ape not /bin/sh >&2
|
||||
echo cat /proc/sys/fs/binfmt_misc/APE >&2
|
||||
cat /proc/sys/fs/binfmt_misc/APE >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! [ -e /proc/sys/fs/binfmt_misc ]; then
|
||||
echo >&2
|
||||
echo loading binfmt_misc into your kernel >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO modprobe binfmt_misc >&2
|
||||
$SUDO modprobe binfmt_misc || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
if ! [ -e /proc/sys/fs/binfmt_misc/register ]; then
|
||||
echo >&2
|
||||
echo mounting binfmt_misc into your kernel >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc >&2
|
||||
$SUDO mount -t binfmt_misc none /proc/sys/fs/binfmt_misc || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo registering APE with binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
echo >&2
|
||||
echo enabling binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo $SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' >&2
|
||||
$SUDO sh -c 'echo 1 >/proc/sys/fs/binfmt_misc/status' || exit
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
{
|
||||
echo
|
||||
echo "------------------------------------------------------------------"
|
||||
echo
|
||||
echo "APE INSTALL COMPLETE"
|
||||
echo
|
||||
echo "If you decide to uninstall APE later on"
|
||||
echo "you may do so using ape/apeuninstall.sh"
|
||||
echo
|
||||
echo "Enjoy your APE loader (>'.')>"
|
||||
echo
|
||||
} >&2
|
||||
@@ -1,60 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ "$UID" = "0" ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
fi
|
||||
|
||||
{
|
||||
echo
|
||||
echo "APE Uninstaller intends to run (in pseudo-shell)"
|
||||
echo
|
||||
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
|
||||
echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc."
|
||||
echo
|
||||
echo "You may then use ape/apeinstall.sh to reinstall it"
|
||||
echo
|
||||
} >&2
|
||||
|
||||
set -ex
|
||||
for f in /proc/sys/fs/binfmt_misc/APE*; do
|
||||
if [ -f $f ]; then
|
||||
$SUDO sh -c "echo -1 >$f" || exit
|
||||
fi
|
||||
done
|
||||
|
||||
# system installation
|
||||
if [ -f /usr/bin/ape ]; then
|
||||
$SUDO rm -f /usr/bin/ape
|
||||
fi
|
||||
|
||||
# legacy installations
|
||||
rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape"
|
||||
|
||||
# ad-hoc installations
|
||||
for x in .ape \
|
||||
.ape-1.1 \
|
||||
.ape-1.3 \
|
||||
.ape-1.4 \
|
||||
.ape-1.5 \
|
||||
.ape-1.6 \
|
||||
.ape-1.7 \
|
||||
.ape-1.8 \
|
||||
.ape-blink-0.9.2 \
|
||||
.ape-blink-1.0.0; do
|
||||
rm -f \
|
||||
~/$x \
|
||||
/tmp/$x \
|
||||
o/tmp/$x \
|
||||
"${TMPDIR:-/tmp}/$x"
|
||||
done
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
#!/bin/sh
|
||||
PROG=${0##*/}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
|
||||
if [ x"$1" = x"--version" ]; then
|
||||
cat <<EOF
|
||||
$PROG 0.1
|
||||
Copyright (c) 2023 Justine Alexandra Roberts Tunney
|
||||
Cosmopolitan Libc and LLVM libcxx/compiler-rt are subject to non-GPL
|
||||
notice licenses, e.g. ISC, MIT, etc. Your compiled programs must embed
|
||||
our copyright notices. This toolchain is configured to do so default.
|
||||
Cosmopolitan comes with absolutely NO WARRANTY of any kind.
|
||||
For more information, see the Cosmopolitan LICENSE files.
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
This launches GNU GCC/Binutils subprocesses, which is free software; see
|
||||
Cosmopolitan's third_party/gcc/ for source code and copying conditions.
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
EOF
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ x"$1" = x"--help" ]; then
|
||||
cat <<EOF
|
||||
Usage: $PROG INPUT OUTPUT
|
||||
Converts an executable linked by cosmocc to the Actually Portable
|
||||
Executable file format. See $PROG --version for other details.
|
||||
EOF
|
||||
exit
|
||||
fi
|
||||
|
||||
fatal_error() {
|
||||
echo "$PROG: fatal error: $1" >&2
|
||||
echo "operation terminated." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
CROSS=1
|
||||
ARCH=${PROG%%-*} # split(prog, '-')[0]
|
||||
if [ x"$ARCH" = x"$PROG" ]; then
|
||||
ARCH=x86_64
|
||||
CROSS=0
|
||||
fi
|
||||
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
MODE=${MODE:-$m}
|
||||
else
|
||||
MODE=${MODE:-${m:-$ARCH}}
|
||||
fi
|
||||
|
||||
if [ $CROSS -eq 0 ]; then
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
else
|
||||
COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
|
||||
fi
|
||||
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
OBJCOPYFLAGS="-S -O binary"
|
||||
elif [ x"$ARCH" = x"aarch64" ]; then
|
||||
OBJCOPYFLAGS="-S"
|
||||
else
|
||||
fatal_error "$ARCH: unsupported architecture"
|
||||
fi
|
||||
|
||||
if [ ! -d "$COSMO" ]; then
|
||||
fatal_error "you need to clone cosmopolitan to your $COSMO directory"
|
||||
fi
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
if [ ! -f "$COSMO/o//tool/build/zipcopy.com" ] ||
|
||||
[ ! -f "$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" ]; then
|
||||
if [ $CROSS -eq 0 ]; then
|
||||
fatal_error "you need to run: cosmocc --update"
|
||||
else
|
||||
fatal_error "you need to run: $ARCH-unknown-cosmo-cosmocc --update"
|
||||
fi
|
||||
fi
|
||||
|
||||
INPUT=$1
|
||||
OUTPUT=$2
|
||||
if [ ! -f "$INPUT" ]; then
|
||||
fatal_error "$INPUT: missing input and output arguments"
|
||||
elif [ ! -f "$INPUT" ]; then
|
||||
fatal_error "$INPUT: no such file"
|
||||
elif [ ! -f "$INPUT" ]; then
|
||||
fatal_error "$INPUT: missing output argument"
|
||||
elif [ x"$INPUT" = x"$OUTPUT" ]; then
|
||||
fatal_error "$INPUT: input and output file can't be the same"
|
||||
fi
|
||||
|
||||
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" \
|
||||
$OBJCOPYFLAGS \
|
||||
"$INPUT" \
|
||||
"$OUTPUT" || exit
|
||||
"$COSMO/o//tool/build/zipcopy.com" \
|
||||
"$INPUT" \
|
||||
"$OUTPUT" || exit
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
exec "$COSMO/o//tool/build/apelink.com" "$@"
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
|
||||
set -- -apifCe "$@"
|
||||
|
||||
if [ -n "$ADDR2LINE" ]; then
|
||||
exec "$ADDR2LINE" "$@"
|
||||
fi
|
||||
|
||||
find_addr2line() {
|
||||
if [ -x o/third_party/gcc/bin/$1-linux-cosmo-addr2line ]; then
|
||||
ADDR2LINE=o/third_party/gcc/bin/$1-linux-cosmo-addr2line
|
||||
elif [ -x o/third_party/gcc/bin/$1-linux-musl-addr2line ]; then
|
||||
ADDR2LINE=o/third_party/gcc/bin/$1-linux-musl-addr2line
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line" ]; then
|
||||
ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-addr2line"
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line" ]; then
|
||||
ADDR2LINE="$COSMO/o/third_party/gcc/bin/$1-linux-musl-addr2line"
|
||||
else
|
||||
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for ARCH in x86_64 aarch64; do
|
||||
find_addr2line $ARCH
|
||||
"$ADDR2LINE" "$@" 2>/dev/null && exit
|
||||
done
|
||||
|
||||
echo "error: addr2line failed" >&2
|
||||
exit 1
|
||||
-381
@@ -1,381 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# cosmopolitan c/c++ compiler
|
||||
#
|
||||
# getting started
|
||||
#
|
||||
# sudo chmod 1777 /opt # sticky bit isn't required
|
||||
# git clone https://github.com/jart/cosmopolitan /opt/cosmo
|
||||
# export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"
|
||||
# echo 'export PATH="/opt/cosmo/bin:/opt/cosmos/bin:$PATH"' >>~/.profile
|
||||
# ape-install # optionally install a faster systemwide ape loader
|
||||
# cosmocc --update # pull and rebuild toolchain artifacts
|
||||
#
|
||||
# getting started synopsis
|
||||
#
|
||||
# cosmocc -o hello.com hello.c
|
||||
# ./foo.com
|
||||
# ./foo.com --strace
|
||||
# ./foo.com --ftrace
|
||||
#
|
||||
# how to build a project like lua 5.4.6
|
||||
#
|
||||
# make all test CC=cosmocc
|
||||
# src/lua -e 'print("hi")'
|
||||
# make install INSTALL_TOP=/opt/cosmos
|
||||
# apecopy src/lua src/lua.com # convert to portable ape binary
|
||||
#
|
||||
# how to cross compile a project like lua 5.4.6
|
||||
#
|
||||
# aarch64-unknown-cosmo-cc --update
|
||||
# make clean all test CC=aarch64-unknown-cosmo-cc AR='aarch64-unknown-cosmo-ar rc' -j8
|
||||
# qemu-aarch64 src/lua -e 'print("hi")'
|
||||
# make install INSTALL_TOP=/opt/cosmos/aarch64
|
||||
#
|
||||
# building in tiny mode
|
||||
#
|
||||
# export MODE=tiny
|
||||
# cosmocc --update
|
||||
# cosmocc -Os -o foo.com foo.c
|
||||
#
|
||||
# building in tiniest mode (linux only)
|
||||
#
|
||||
# export MODE=tinylinux
|
||||
# cosmocc --update
|
||||
# cosmocc -Os -o foo.com foo.c
|
||||
#
|
||||
# hardening programs with memory safety
|
||||
#
|
||||
# export MODE=asan
|
||||
# cosmocc --update
|
||||
# cosmocc -o foo.com foo.c
|
||||
#
|
||||
# detecting this environment
|
||||
#
|
||||
# - `__COSMOCC__` is defined when this compiler is in play
|
||||
# - `__COSMOPOLITAN__` is always defined by Cosmopolitan Libc
|
||||
#
|
||||
# some notes on this compiler
|
||||
#
|
||||
# - the underlying compiler itself is gcc
|
||||
# - we use cosmopoiltan libc rather than glibc
|
||||
# - we use llvm's compiler-rt and libcxx runtimes
|
||||
# - we patched gcc so switch case can have symbols
|
||||
# - our scanf() implementation is somewhat troubled
|
||||
#
|
||||
# compiler flags that aren't supported
|
||||
#
|
||||
# - `-r` partial linking not implemented yet (todo)
|
||||
# - `-S` you need to put your assembly behind #ifdefs instead
|
||||
# - `-fexceptions` cosmopolitan doesn't support c++ exceptions yet
|
||||
# - `-frtti` cosmopolitan doesn't support c++ runtime reflection yet
|
||||
# - `-mred-zone` the system v red zone doesn't exist on windows and metal
|
||||
# - `-fpic`, '-fPIC', `-shared`, `-pie`, etc. no shared object support yet
|
||||
# - `-fsanitize=thread` cosmopolitan doesn't have thread sanitizer runtime yet
|
||||
# - `-fomit-frame-pointer` is partially supported (apple forbids full removal)
|
||||
#
|
||||
# for further details, run `man gcc`
|
||||
|
||||
PROG=${0##*/}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
GCC_VERSION=11.2.0
|
||||
|
||||
if [ "$1" = "--version" ]; then
|
||||
cat <<EOF
|
||||
$PROG (GCC) $GCC_VERSION
|
||||
Copyright (c) 2023 Justine Alexandra Roberts Tunney
|
||||
Cosmopolitan Libc and LLVM libcxx/compiler-rt are subject to non-GPL
|
||||
notice licenses, e.g. ISC, MIT, etc. Your compiled programs must embed
|
||||
our copyright notices. This toolchain is configured to do so default.
|
||||
Cosmopolitan comes with absolutely NO WARRANTY of any kind.
|
||||
For more information, see the Cosmopolitan LICENSE files.
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
This launches GNU GCC/Binutils subprocesses, which is free software; see
|
||||
Cosmopolitan's third_party/gcc/ for source code and copying conditions.
|
||||
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
EOF
|
||||
exit
|
||||
fi
|
||||
|
||||
fatal_error() {
|
||||
echo "$PROG: fatal error: $1" >&2
|
||||
echo "compilation terminated." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_command() {
|
||||
if [ -n "$BUILDLOG" ]; then
|
||||
printf '# %s\n(cd %s; %s)\n' "$ORIGINAL" "$PWD" "$*" >>"$BUILDLOG"
|
||||
fi
|
||||
}
|
||||
|
||||
ORIGINAL="$0 $*"
|
||||
PLATFORM="-D__COSMOPOLITAN__ -D__COSMOCC__"
|
||||
PREDEF="-include libc/integral/normalize.inc"
|
||||
CFLAGS="-fportcosmo -fno-dwarf2-cfi-asm -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-semantic-interposition"
|
||||
CPPFLAGS="-fno-pie -nostdinc -fno-math-errno -iquote $COSMO"
|
||||
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd"
|
||||
APEFLAGS="-Wl,--gc-sections"
|
||||
PRECIOUS="-fno-omit-frame-pointer"
|
||||
|
||||
CROSS=1
|
||||
ARCH=${PROG%%-*} # split(prog, '-')[0]
|
||||
if [ x"$ARCH" = x"$PROG" ]; then
|
||||
ARCH=x86_64
|
||||
CROSS=0
|
||||
fi
|
||||
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
MODE=${MODE:-$m}
|
||||
else
|
||||
MODE=${MODE:-${m:-$ARCH}}
|
||||
fi
|
||||
|
||||
if [ $CROSS -eq 0 ]; then
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
else
|
||||
COSMOS=${COSMOS:-/opt/cosmos/$ARCH}
|
||||
fi
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-gcc"
|
||||
CRT="$COSMO/o/$MODE/libc/crt/crt.o"
|
||||
LDLIBS="$COSMO/o/$MODE/cosmopolitan.a"
|
||||
CPPFLAGS="$CPPFLAGS -isystem $COSMOS/include -isystem $COSMO/libc/isystem"
|
||||
LDFLAGS="$LDFLAGS -L$COSMOS/lib"
|
||||
if [ x"$PROG" != x"${PROG%++}" ]; then
|
||||
CC="$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-g++"
|
||||
CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -fuse-cxa-atexit"
|
||||
LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $LDLIBS"
|
||||
fi
|
||||
|
||||
PAGESZ=4096
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
OBJCOPYFLAGS="-S -O binary"
|
||||
CRT="$COSMO/o/$MODE/ape/ape-no-modify-self.o $CRT"
|
||||
CPPFLAGS="$CPPFLAGS -mno-red-zone"
|
||||
CFLAGS="$CFLAGS -mno-tls-direct-seg-refs"
|
||||
LDFLAGS="$LDFLAGS -Wl,-T,$COSMO/o/$MODE/ape/ape.lds"
|
||||
if [ x"$MODE" = x"aarch64" ]; then
|
||||
fatal_error '$MODE must not be aarch64 when using x86_64 cross compiler'
|
||||
elif [ x"$MODE" != x"${MODE#* }" ]; then
|
||||
fatal_error '$MODE must not contain hyphens when targeting x86_64'
|
||||
fi
|
||||
elif [ x"$ARCH" = x"aarch64" ]; then
|
||||
OBJCOPYFLAGS="-S"
|
||||
PAGESZ=16384
|
||||
CFLAGS="$CFLAGS -ffixed-x18 -ffixed-x28 -mno-outline-atomics"
|
||||
LDFLAGS="$LDFLAGS -Wl,-T,$COSMO/o/$MODE/ape/aarch64.lds"
|
||||
if [ x"$MODE" != x"aarch64" ] && [ x"$MODE" = x"${MODE#aarch64-*}" ]; then
|
||||
fatal_error '$MODE must be either "aarch64" or "aarch64-FOO" when using aarch64 cross compiler'
|
||||
fi
|
||||
else
|
||||
fatal_error "$ARCH: unsupported architecture"
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -Wl,-z,common-page-size=$PAGESZ -Wl,-z,max-page-size=16384"
|
||||
|
||||
if [ ! -d "$COSMO" ]; then
|
||||
fatal_error "you need to clone cosmopolitan to your $COSMO directory"
|
||||
fi
|
||||
|
||||
if [ "$1" = "--update" ]; then
|
||||
cd $COSMO || exit
|
||||
echo "building cosmo host toolchain..." >&2
|
||||
make --silent -j toolchain MODE= ARCH=x86_64 || exit
|
||||
echo "building cosmo target (MODE=$MODE) toolchain..." >&2
|
||||
make --silent -j toolchain MODE="$MODE" || exit
|
||||
echo "setting up your cosmos..." >&2
|
||||
mkdir -p "$COSMOS/lib" || exit
|
||||
for lib in c dl gcc_s m pthread resolv rt dl z stdc++; do
|
||||
if [ ! -f "$COSMOS/lib/lib${lib}.a" ]; then
|
||||
printf '\041\074\141\162\143\150\076\012' >"$COSMOS/lib/lib${lib}.a" || exit
|
||||
fi
|
||||
done
|
||||
echo "successfully updated your cosmo toolchain" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ ! -f "$COSMOS/lib/libc.a" ] ||
|
||||
[ ! -f "$COSMO/o/$MODE/cosmopolitan.a" ]; then
|
||||
fatal_error "you need to run: $PROG --update"
|
||||
fi
|
||||
|
||||
OPT=
|
||||
FIRST=1
|
||||
OUTPUT=
|
||||
SFLAG=0
|
||||
INTENT=ld
|
||||
GOT_SOME=0
|
||||
NEED_OUTPUT=
|
||||
RELOCATABLE=0
|
||||
for x; do
|
||||
if [ $FIRST -eq 1 ]; then
|
||||
set --
|
||||
FIRST=0
|
||||
fi
|
||||
if [ -n "$NEED_OUTPUT" ]; then
|
||||
NEED_OUTPUT=
|
||||
OUTPUT=$x
|
||||
set -- "$@" "$x"
|
||||
continue
|
||||
fi
|
||||
if [ x"$x" = x"-" ] || # is an argument
|
||||
[ x"$x" = x"${x#-*}" ]; then # !startswith(x, "-")
|
||||
GOT_SOME=1
|
||||
elif [ x"$x" = x"-static-libstdc++" ]; then
|
||||
continue
|
||||
elif [ x"$x" = x"-static-libgcc" ]; then
|
||||
continue
|
||||
elif [ x"$x" != x"${x#-O}" ]; then
|
||||
OPT=$x
|
||||
elif [ x"$x" = x"-c" ]; then
|
||||
INTENT=cc
|
||||
elif [ x"$x" = x"-s" ]; then
|
||||
SFLAG=1
|
||||
continue
|
||||
elif [ x"$x" = x"-r" ]; then
|
||||
RELOCATABLE=1
|
||||
elif [ x"$x" = x"-E" ]; then
|
||||
INTENT=cpp
|
||||
elif [ x"$x" = x"-o" ]; then
|
||||
NEED_OUTPUT=1
|
||||
elif [ x"$x" = x"-mcosmo" ]; then
|
||||
CPPFLAGS="$CPPFLAGS -D_COSMO_SOURCE"
|
||||
continue
|
||||
elif [ x"$x" != x"${x#-o}" ]; then
|
||||
OUTPUT=${x#-o}
|
||||
elif [ x"$x" = x"-fpic" ]; then
|
||||
continue
|
||||
elif [ x"$x" = x"-fPIC" ]; then
|
||||
continue
|
||||
elif [ x"$x" = x"-r" ] ||
|
||||
[ x"$x" = x"-pie" ] ||
|
||||
[ x"$x" = x"-frtti" ] ||
|
||||
[ x"$x" = x"-shared" ] ||
|
||||
[ x"$x" = x"-nostdlib" ] ||
|
||||
[ x"$x" = x"-mred-zone" ] ||
|
||||
[ x"$x" = x"-fexceptions" ] ||
|
||||
[ x"$x" = x"-fsanitize=thread" ]; then
|
||||
echo "$PROG: $x not supported" >&2
|
||||
exit 1
|
||||
elif [ x"$x" = x"-fsanitize=all" ] ||
|
||||
[ x"$x" = x"-fsanitize=address" ] ||
|
||||
[ x"$x" = x"-fsanitize=undefined" ]; then
|
||||
echo "$PROG: use cosmo MODE=dbg or MODE=asan rather than passing $x" >&2
|
||||
exit 1
|
||||
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
|
||||
# tail calls — may opt not to create an entry in this list. As a
|
||||
# result, stack traces are always meaningful, even without debug
|
||||
# information."
|
||||
set -- "$@" -momit-leaf-frame-pointer -foptimize-sibling-calls
|
||||
continue
|
||||
elif [ x"$x" != x"${x#-Werror}" ] || \
|
||||
[ x"$x" = x"-pedantic-errors" ]; then
|
||||
# this toolchain is intended for building other people's code
|
||||
# elevating warnings into errors, should only be done by devs
|
||||
continue
|
||||
elif [ x"$x" = x"-march=native" ]; then
|
||||
if [ $CROSS -eq 0 ]; then
|
||||
set -- "$@" $("$COSMO/o//tool/build/march-native.com")
|
||||
else
|
||||
fatal_error "-march=native can't be used when cross compiling"
|
||||
fi
|
||||
continue
|
||||
elif [ x"$x" = x"-dumpversion" ]; then
|
||||
echo $GCC_VERSION
|
||||
exit 0
|
||||
fi
|
||||
set -- "$@" "$x"
|
||||
done
|
||||
|
||||
if [ "$GOT_SOME" -eq 0 ]; then
|
||||
fatal_error "no input files"
|
||||
fi
|
||||
|
||||
if [ $RELOCATABLE -eq 1 ]; then
|
||||
LDFLAGS="$LDFLAGS -r"
|
||||
fi
|
||||
|
||||
if [ x"$MODE" = x"nox87" ]; then
|
||||
CPPFLAGS="$CPPFLAGS -mlong-double-64"
|
||||
fi
|
||||
|
||||
# support --ftrace unless optimizing for size
|
||||
if [ x"$OPT" != x"-Os" ] && # $OPT != -Os
|
||||
[ 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"
|
||||
elif [ x"$ARCH" = x"aarch64" ]; then
|
||||
CFLAGS="$CFLAGS -fpatchable-function-entry=7,6"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ask compiler to generate sanitization code in debug mode
|
||||
if [ x"$MODE" != x"${MODE%*dbg}" ]; then # endswith($MODE, "dbg")
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
|
||||
else
|
||||
CPPFLAGS="$CPPFLAGS -fsanitize=undefined"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ask compiler to generate memory safety code in asan mode
|
||||
if [ x"$MODE" != x"${MODE%*asan}" ]; then # endswith($MODE, "asan")
|
||||
if [ x"$ARCH" = x"x86_64" ]; then
|
||||
CPPFLAGS="$CPPFLAGS -fsanitize=address"
|
||||
else
|
||||
fatal_error "address sanitizer not supported on non-x86 yet"
|
||||
fi
|
||||
fi
|
||||
|
||||
# maximize frame pointers unless optimizing for size
|
||||
if [ x"$OPT" != x"-Os" ] && # $OPT != "-Os"
|
||||
[ x"$MODE" != x"${MODE%tiny}" ]; then # endswith($MODE, "tiny")
|
||||
CFLAGS="$CFLAGS -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer"
|
||||
fi
|
||||
|
||||
if [ $INTENT = cpp ]; then
|
||||
set -- "$CC" $PLATFORM $CPPFLAGS "$@"
|
||||
elif [ $INTENT = cc ]; then
|
||||
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS "$@" $PRECIOUS
|
||||
else
|
||||
set -- "$CC" $PLATFORM $PREDEF $CFLAGS $CPPFLAGS $CRT "$@" $LDFLAGS $LDLIBS $PRECIOUS
|
||||
fi
|
||||
|
||||
log_command "$@"
|
||||
"$@" || exit
|
||||
|
||||
if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then
|
||||
if [ $INTENT = cc ] || [ $INTENT = ld ]; then
|
||||
"$COSMO/o//tool/build/fixupobj.com" \
|
||||
"$OUTPUT" || exit
|
||||
fi
|
||||
if [ $INTENT = ld ]; then
|
||||
if [ x"$OUTPUT" != x"${OUTPUT%.com}" ] ||
|
||||
[ x"$OUTPUT" != x"${OUTPUT%.exe}" ]; then
|
||||
# cosmocc -o foo.com ...
|
||||
# -> foo.com (ape)
|
||||
# -> foo.com.dbg (elf)
|
||||
mv -f "$OUTPUT" "$OUTPUT.dbg" || exit
|
||||
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-objcopy" \
|
||||
$OBJCOPYFLAGS \
|
||||
"$OUTPUT.dbg" \
|
||||
"$OUTPUT" || exit
|
||||
"$COSMO/o//tool/build/zipcopy.com" \
|
||||
"$OUTPUT.dbg" \
|
||||
"$OUTPUT" || exit
|
||||
elif [ $SFLAG -eq 1 ]; then
|
||||
"$COSMO/o/third_party/gcc/bin/$ARCH-linux-$BRAND-strip" \
|
||||
"$OUTPUT" || exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
fatcosmocc
|
||||
@@ -1 +0,0 @@
|
||||
fatcosmoar
|
||||
@@ -1 +0,0 @@
|
||||
fatcosmocc
|
||||
@@ -1 +0,0 @@
|
||||
fatcosmocc
|
||||
@@ -1 +0,0 @@
|
||||
fatcosmoinstall
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-addr2line"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1 +0,0 @@
|
||||
apecopy
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${0##*/}
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
|
||||
fatal_error() {
|
||||
echo "$PROG: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
if [ ! -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" ]; then
|
||||
fatal_error "you need to run: x86_64-unknown-cosmo-cc --update"
|
||||
fi
|
||||
|
||||
exec "$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-ar" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-as"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1 +0,0 @@
|
||||
cosmocc
|
||||
@@ -1 +0,0 @@
|
||||
cosmocc
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-nm"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objcopy"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-objdump"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
MODE=${MODE:-$m}
|
||||
COSMO=${COSMO:-/opt/cosmo}
|
||||
COSMOS=${COSMOS:-/opt/cosmos}
|
||||
|
||||
if [ -x "$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc" ]; then
|
||||
BRAND=musl
|
||||
else
|
||||
BRAND=cosmo
|
||||
fi
|
||||
|
||||
TOOL="$COSMO/o/third_party/gcc/bin/x86_64-linux-$BRAND-strip"
|
||||
|
||||
if [ ! -x "$TOOL" ]; then
|
||||
echo "$0: you need to run: x86_64-unknown-cosmo-cc --update" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$TOOL" "$@"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -222,7 +222,8 @@ DEFAULT_CPPFLAGS += \
|
||||
-D_COSMO_SOURCE \
|
||||
-DMODE='"$(MODE)"' \
|
||||
-nostdinc \
|
||||
-iquote .
|
||||
-iquote. \
|
||||
-isystem libc/isystem
|
||||
|
||||
DEFAULT_CFLAGS = \
|
||||
-std=gnu2x
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/* TODO(jart): DELETE */
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dlopen/dlfcn.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* @fileoverview cosmopolitan dynamic runtime linking demo
|
||||
*
|
||||
* Our cosmo_dlopen() interface currently supports:
|
||||
*
|
||||
* - x86-64 Linux w/ Glibc
|
||||
* - x86-64 Linux w/ Musl Libc
|
||||
* - x86-64 FreeBSD
|
||||
* - x86-64 Windows
|
||||
* - x86-64 NetBSD
|
||||
* - aarch64 Linux w/ Glibc
|
||||
* - aarch64 Linux w/ Musl Libc
|
||||
* - aarch64 MacOS
|
||||
*
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
|
||||
// open the host system's zlib library
|
||||
void *libc = cosmo_dlopen("libz.so", RTLD_LAZY);
|
||||
if (!libc) {
|
||||
tinyprint(2, cosmo_dlerror(), "\n", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// load crc() function address
|
||||
unsigned (*crc32)(unsigned, void *, int) = cosmo_dlsym(libc, "crc32");
|
||||
if (!crc32) {
|
||||
tinyprint(2, cosmo_dlerror(), "\n", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// compute a checksum and print the result
|
||||
char ibuf[12];
|
||||
FormatInt32(ibuf, crc32(0, "hi", 2));
|
||||
tinyprint(1, "crc(hi) = ", ibuf, "\n", NULL);
|
||||
|
||||
// mop up
|
||||
cosmo_dlclose(libc);
|
||||
exit(0);
|
||||
}
|
||||
@@ -43,9 +43,11 @@ EXAMPLES_DIRECTDEPS = \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_CALLS \
|
||||
LIBC_DLOPEN \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_IRQ \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
@@ -91,14 +93,13 @@ EXAMPLES_DIRECTDEPS = \
|
||||
THIRD_PARTY_VQSORT \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_ARGS \
|
||||
TOOL_BUILD_LIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
$(call uniq,$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(EXAMPLES_OBJS): override CFLAGS += -isystem libc/isystem
|
||||
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
+2
-37
@@ -7,8 +7,9 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#ifdef __COSMOCC__
|
||||
#ifndef _COSMO_SOURCE
|
||||
#define _COSMO_SOURCE
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <cosmo.h>
|
||||
#include <errno.h>
|
||||
@@ -22,42 +23,6 @@
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#else
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/pledge.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/limits.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/consts/tcp.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/thread2.h"
|
||||
#include "net/http/http.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @fileoverview greenbean lightweight threaded web server
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#endif
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/hiredis/hiredis.h"
|
||||
|
||||
@@ -62,7 +62,6 @@ Contact: [email protected]\"\n\
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/inttypes.h"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define PARSE_AND_PRINT(type, scan_fmt, print_fmt, str) \
|
||||
do { \
|
||||
type val; int ret; \
|
||||
ret = sscanf(str, scan_fmt, &val); \
|
||||
printf("\"%s\" => " print_fmt " = %d\n", str, val, ret); \
|
||||
} while (0)
|
||||
|
||||
int main()
|
||||
{
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0.3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", ".3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "3715");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "111.11");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-2.22");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "Nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "nAn(2)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-NAN(_asdfZXCV1234_)");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+nan");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "inF");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "iNfINiTy");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "+inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "-inf");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "0X1.BC70A3D70A3D7P+6");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "1.18973e+4932zzz");
|
||||
PARSE_AND_PRINT(float, "%f", "%.10f", " -0.0000000123junk");
|
||||
PARSE_AND_PRINT(float, "%f", "%f", "junk");
|
||||
return 0;
|
||||
}
|
||||
@@ -33,7 +33,6 @@
|
||||
*/
|
||||
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.h"
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/append.h"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
@@ -122,7 +122,6 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
__static_yoink("vga_console");
|
||||
__static_yoink("_idt");
|
||||
__static_yoink("_AcpiMadtFlags");
|
||||
__static_yoink("_AcpiBootFlags");
|
||||
__static_yoink("EfiMain");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
+10
-7
@@ -14,7 +14,8 @@
|
||||
#define _ASSERT_H
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void __assert_fail(const char *, const char *, int) wontreturn relegated;
|
||||
void __assert_fail(const char *, const char *, int);
|
||||
void unassert(const char *, const char *, int);
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(x) ((void)0)
|
||||
@@ -31,12 +32,14 @@ void __assert_fail(const char *, const char *, int) wontreturn relegated;
|
||||
#ifndef NDEBUG
|
||||
#define unassert(x) __assert_macro(x, #x)
|
||||
#define npassert(x) __assert_macro(x, #x)
|
||||
#define __assert_macro(x, s) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
__assert_fail(s, __FILE__, __LINE__); \
|
||||
} \
|
||||
(void)0; \
|
||||
#define __assert_macro(x, s) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
(unassert)(s, __FILE__, __LINE__); \
|
||||
__asm__("nop"); \
|
||||
__builtin_unreachable(); \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#else
|
||||
#define npassert(x) \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,24 +16,13 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/reverse.internal.h"
|
||||
#include "libc/calls/struct/cpuset.h"
|
||||
#include "libc/intrin/popcnt.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 64-bit integer to octal string.
|
||||
* @param a needs at least 24 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
dontinline size_t uint64toarray_radix8(uint64_t i, char a[hasatleast 24]) {
|
||||
size_t j;
|
||||
j = 0;
|
||||
do {
|
||||
a[j++] = i % 8 + '0';
|
||||
i /= 8;
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
reverse(a, j);
|
||||
return j;
|
||||
int CPU_COUNT_S(size_t size, const cpu_set_t *set) {
|
||||
int i, c = 0;
|
||||
for (i = 0; i < size / sizeof(*set->__bits); i++) {
|
||||
c += popcnt(set->__bits[i]);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
/**
|
||||
* Handles assert() failure.
|
||||
@@ -31,8 +32,8 @@ void __assert_fail(const char *expr, const char *file, int line) {
|
||||
char ibuf[12];
|
||||
sigset_t m = __sig_block();
|
||||
FormatInt32(ibuf, line);
|
||||
tinyprint(2, file, ":", ibuf, ": assert(", expr, ") failed (",
|
||||
program_invocation_short_name, " ",
|
||||
tinyprint(2, file, ":", ibuf, ": \e[31;1massert(", expr,
|
||||
") failed\e[0m (cosmoaddr2line ", FindDebugBinary(), " ",
|
||||
DescribeBacktrace(__builtin_frame_address(0)), ")\n", NULL);
|
||||
__sig_unblock(m);
|
||||
abort();
|
||||
|
||||
+10
-7
@@ -158,6 +158,8 @@ int setregid(unsigned, unsigned);
|
||||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(unsigned);
|
||||
int shm_open(const char *, int, unsigned);
|
||||
int shm_unlink(const char *);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
int symlink(const char *, const char *);
|
||||
@@ -166,7 +168,7 @@ int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int unlink(const char *);
|
||||
int unlinkat(int, const char *, int);
|
||||
int usleep(unsigned);
|
||||
int usleep(uint64_t);
|
||||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
@@ -199,7 +201,6 @@ int setresuid(unsigned, unsigned, unsigned);
|
||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||
char *get_current_dir_name(void) __wur;
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
@@ -211,36 +212,38 @@ int madvise(void *, uint64_t, int);
|
||||
#ifdef _COSMO_SOURCE
|
||||
bool32 fdexists(int);
|
||||
bool32 fileexists(const char *);
|
||||
bool32 ischardev(int);
|
||||
bool32 isdirectory(const char *);
|
||||
bool32 isexecutable(const char *);
|
||||
bool32 isregularfile(const char *);
|
||||
bool32 issymlink(const char *);
|
||||
bool32 ischardev(int);
|
||||
char *commandv(const char *, char *, size_t);
|
||||
int __getcwd(char *, size_t);
|
||||
int clone(void *, void *, size_t, int, void *, void *, void *, void *);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int pivot_root(const char *, const char *);
|
||||
int pledge(const char *, const char *);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int sys_iopl(int);
|
||||
int sys_ioprio_get(int, int);
|
||||
int sys_ioprio_set(int, int, int);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_personality(uint64_t);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int sys_personality(uint64_t);
|
||||
int sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int sys_ioprio_get(int, int);
|
||||
int sys_ioprio_set(int, int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, unsigned);
|
||||
int unveil(const char *, const char *);
|
||||
long ptrace(int, ...);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
ssize_t copyfd(int, int, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t tinyprint(int, const char *, ...) nullterminated();
|
||||
void shm_path_np(const char *, char[hasatleast 78]);
|
||||
#endif /* _COSMO_SOURCE */
|
||||
|
||||
int __wifstopped(int) pureconst;
|
||||
|
||||
+4
-2
@@ -99,8 +99,6 @@ o//libc/calls/prctl.o: \
|
||||
# we always want -Os because:
|
||||
# it's early runtime mandatory and quite huge without it
|
||||
o//libc/calls/getcwd.greg.o \
|
||||
o//libc/calls/getcwd-nt.greg.o \
|
||||
o//libc/calls/getcwd-xnu.greg.o \
|
||||
o//libc/calls/statfs2cosmo.o: private \
|
||||
CFLAGS += \
|
||||
-Os
|
||||
@@ -145,6 +143,10 @@ o/$(MODE)/libc/calls/tailcontext.o: libc/calls/tailcontext.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/calls/stackjump.o: libc/calls/stackjump.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
o/$(MODE)/libc/calls/sched_yield.o: libc/calls/sched_yield.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
o/$(MODE)/libc/calls/uname.o: libc/integral/normalize.inc
|
||||
|
||||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
|
||||
@@ -17,14 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows int _check_cancel(void) {
|
||||
int _check_cancel(void) {
|
||||
if (_weaken(_pthread_cancel_ack) && //
|
||||
_pthread_self() && !(_pthread_self()->pt_flags & PT_NOCANCEL) &&
|
||||
atomic_load_explicit(&_pthread_self()->pt_canceled,
|
||||
@@ -33,15 +30,3 @@ textwindows int _check_cancel(void) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
textwindows int _check_signal(bool restartable) {
|
||||
int status;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (!_weaken(__sig_check)) return 0;
|
||||
if (!(status = _weaken(__sig_check)())) return 0;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (status == 2 && restartable) return 0;
|
||||
return eintr();
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
@@ -0,0 +1,35 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
textwindows int _check_signal(bool restartable) {
|
||||
int status;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (!_weaken(__sig_check)) return 0;
|
||||
if (!(status = _weaken(__sig_check)())) return 0;
|
||||
if (_check_cancel() == -1) return -1;
|
||||
if (status == 2 && restartable) return 0;
|
||||
return eintr();
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
+5
-1
@@ -40,7 +40,11 @@ static dontinline int __clk_tck_init(void) {
|
||||
size_t len;
|
||||
struct clockinfo_netbsd clock;
|
||||
if (IsWindows()) {
|
||||
x = 1000;
|
||||
// MSVC defines CLK_TCK as 1000 but 1ms is obviously not the
|
||||
// scheduling quantum Windows actually uses. If we define it
|
||||
// as 30 rather than 1000, then clock_nanosleep is much more
|
||||
// accurately able to predict the duration of its busy waits
|
||||
x = 30;
|
||||
} else if (IsXnu() || IsOpenbsd()) {
|
||||
x = 100;
|
||||
} else if (IsFreebsd()) {
|
||||
|
||||
@@ -25,14 +25,20 @@
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
|
||||
static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real,
|
||||
int64_t real_coarse, int64_t boot) {
|
||||
ts->tv_sec = 0;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
ts->tv_sec = 0;
|
||||
ts->tv_nsec = real;
|
||||
return 0;
|
||||
} else if (clock == CLOCK_REALTIME_COARSE) {
|
||||
ts->tv_nsec = real_coarse;
|
||||
return 0;
|
||||
} else if (clock == CLOCK_MONOTONIC) {
|
||||
ts->tv_sec = 0;
|
||||
ts->tv_nsec = 1;
|
||||
ts->tv_nsec = 10;
|
||||
return 0;
|
||||
} else if (clock == CLOCK_BOOTTIME) {
|
||||
ts->tv_nsec = boot;
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
@@ -40,11 +46,11 @@ static int sys_clock_getres_poly(int clock, struct timespec *ts, int64_t real) {
|
||||
}
|
||||
|
||||
static int sys_clock_getres_nt(int clock, struct timespec *ts) {
|
||||
return sys_clock_getres_poly(clock, ts, 100);
|
||||
return sys_clock_getres_poly(clock, ts, 100, 1000000, 1000000);
|
||||
}
|
||||
|
||||
static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
|
||||
return sys_clock_getres_poly(clock, ts, 1000);
|
||||
return sys_clock_getres_poly(clock, ts, 1000, 1000, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,26 +18,61 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/wintime.internal.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
#define _CLOCK_REALTIME 0
|
||||
#define _CLOCK_MONOTONIC 1
|
||||
#define _CLOCK_REALTIME_COARSE 2
|
||||
#define _CLOCK_BOOTTIME 3
|
||||
|
||||
static struct {
|
||||
uint64_t base;
|
||||
uint64_t freq;
|
||||
} g_winclock;
|
||||
|
||||
textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
|
||||
uint64_t t;
|
||||
struct NtFileTime ft;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (!ts) return 0;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
*ts = FileTimeToTimeSpec(ft);
|
||||
return 0;
|
||||
} else if (clock == CLOCK_MONOTONIC) {
|
||||
if (!ts) return 0;
|
||||
return sys_clock_gettime_mono(ts);
|
||||
} else if (clock == CLOCK_BOOTTIME) {
|
||||
if (ts) *ts = timespec_frommillis(GetTickCount64());
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
switch (clock) {
|
||||
case _CLOCK_REALTIME:
|
||||
if (ts) {
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
*ts = FileTimeToTimeSpec(ft);
|
||||
}
|
||||
return 0;
|
||||
case _CLOCK_REALTIME_COARSE:
|
||||
if (ts) {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
*ts = FileTimeToTimeSpec(ft);
|
||||
}
|
||||
return 0;
|
||||
case _CLOCK_MONOTONIC:
|
||||
if (ts) {
|
||||
QueryPerformanceCounter(&t);
|
||||
t = ((t - g_winclock.base) * 1000000000) / g_winclock.freq;
|
||||
*ts = timespec_fromnanos(t);
|
||||
}
|
||||
return 0;
|
||||
case _CLOCK_BOOTTIME:
|
||||
if (ts) {
|
||||
*ts = timespec_frommillis(GetTickCount64());
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static textstartup void winclock_init() {
|
||||
if (IsWindows()) {
|
||||
QueryPerformanceCounter(&g_winclock.base);
|
||||
QueryPerformanceFrequency(&g_winclock.freq);
|
||||
}
|
||||
}
|
||||
|
||||
const void *const winclock_ctor[] initarray = {
|
||||
winclock_init,
|
||||
};
|
||||
@@ -18,6 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/clktck.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
@@ -108,9 +110,17 @@ static int cosmo_clock_nanosleep(int clock, int flags,
|
||||
}
|
||||
|
||||
// spin through final scheduling quantum
|
||||
do unassert(!clock_gettime(time_clock, &now));
|
||||
while (timespec_cmp(now, deadline) < 0);
|
||||
return 0;
|
||||
int rc = 0;
|
||||
ftrace_enabled(-1);
|
||||
do {
|
||||
if (_check_cancel()) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
unassert(!clock_gettime(time_clock, &now));
|
||||
} while (timespec_cmp(now, deadline) < 0);
|
||||
ftrace_enabled(+1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -37,13 +38,12 @@
|
||||
* @raise EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @raise EINVAL if flags are bad or first is greater than last
|
||||
* @raise EMFILE if a weird race condition happens on Linux
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR possibly on OpenBSD
|
||||
* @raise ENOMEM on Linux maybe
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
(void)err;
|
||||
int rc;
|
||||
BLOCK_CANCELATION;
|
||||
if (first < 0) {
|
||||
// consistent with openbsd
|
||||
// freebsd allows this but it's dangerous
|
||||
@@ -58,6 +58,7 @@ int closefrom(int first) {
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
}
|
||||
+1
-1
@@ -44,7 +44,7 @@ ssize_t copyfd(int in, int out, size_t n) {
|
||||
if (dw != dr) {
|
||||
// POSIX requires atomic IO up to PIPE_BUF
|
||||
// The minimum permissible PIPE_BUF is 512
|
||||
abort();
|
||||
notpossible;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
||||
@@ -91,11 +91,9 @@ textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
|
||||
// Be as generous as possible in sharing file access. Not doing this
|
||||
// you'll quickly find yourself no longer able to administer Windows
|
||||
if (flags & _O_EXCL) {
|
||||
share = kNtFileShareExclusive;
|
||||
} else {
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
}
|
||||
// and we need this to be the case even in O_EXCL mode otherwise the
|
||||
// shm_open_test.c won't behave consistently on Windows like on UNIX
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
|
||||
// These POSIX to WIN32 mappings are relatively straightforward.
|
||||
if (flags & _O_EXCL) {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int sys_faccessat_nt(int dirfd, const char *path, int mode,
|
||||
uint32_t flags) {
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
|
||||
int flags) {
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
/**
|
||||
* Blocks until kernel flushes non-metadata buffers for fd to disk.
|
||||
*
|
||||
* NOTE: For `IsXnu()` it's recommended that `fcntl(F_FULLFSYNC)` be
|
||||
* favored instead of this function, and if that fails, the fallback
|
||||
* path should call `fsync()` see the SQLite codebase. In the future
|
||||
* Cosmopolitan might do this automatically.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EROFS if `fd` is on a read-only filesystem e.g. /zip
|
||||
@@ -37,8 +42,8 @@
|
||||
* @raise EBADF if `fd` isn't an open file
|
||||
* @raise EINTR if signal was delivered
|
||||
* @raise EIO if an i/o error happened
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @see sync(), fsync()
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
|
||||
@@ -20,13 +20,17 @@
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/cosmo.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/tinyelf.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
@@ -38,24 +42,57 @@ static struct {
|
||||
char buf[PATH_MAX];
|
||||
} g_comdbg;
|
||||
|
||||
static const char *kDbgExts[] = {
|
||||
".dbg",
|
||||
".com.dbg",
|
||||
#ifdef __aarch64__
|
||||
".aarch64.elf",
|
||||
#elif defined(__powerpc64__)
|
||||
".ppc64.elf",
|
||||
#endif
|
||||
};
|
||||
|
||||
static int GetElfMachine(void) {
|
||||
#ifdef __x86_64__
|
||||
return EM_NEXGEN32E;
|
||||
#elif defined(__aarch64__)
|
||||
return EM_AARCH64;
|
||||
#elif defined(__powerpc64__)
|
||||
return EM_PPC64;
|
||||
#elif defined(__riscv)
|
||||
return EM_RISCV;
|
||||
#elif defined(__s390x__)
|
||||
return EM_S390;
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool IsMyDebugBinary(const char *path) {
|
||||
void *map;
|
||||
int64_t size;
|
||||
uintptr_t value;
|
||||
bool res = false;
|
||||
int fd, e = errno;
|
||||
struct DirectMap dm;
|
||||
BLOCK_CANCELATION;
|
||||
if ((fd = open(path, O_RDONLY | O_CLOEXEC, 0)) != -1) {
|
||||
// sanity test that this .com.dbg file (1) is an elf image, and (2)
|
||||
// contains the same number of bytes of code as our .com executable
|
||||
// which is currently running in memory.
|
||||
if ((size = lseek(fd, 0, SEEK_END)) != -1 &&
|
||||
(map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
|
||||
if (READ32LE((char *)map) == READ32LE("\177ELF") &&
|
||||
GetElfSymbolValue(map, "_etext", &value)) {
|
||||
(dm = sys_mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)).addr !=
|
||||
MAP_FAILED) {
|
||||
if (READ32LE((char *)dm.addr) == READ32LE("\177ELF") &&
|
||||
((Elf64_Ehdr *)dm.addr)->e_machine == GetElfMachine() &&
|
||||
GetElfSymbolValue(dm.addr, "_etext", &value)) {
|
||||
res = !_etext || value == (uintptr_t)_etext;
|
||||
}
|
||||
munmap(map, size);
|
||||
if (!IsWindows()) {
|
||||
sys_munmap(dm.addr, size);
|
||||
} else {
|
||||
CloseHandle(dm.maphandle);
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
@@ -65,20 +102,21 @@ static bool IsMyDebugBinary(const char *path) {
|
||||
}
|
||||
|
||||
static void FindDebugBinaryInit(void) {
|
||||
char *p = GetProgramExecutableName();
|
||||
size_t n = strlen(p);
|
||||
if ((n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) ||
|
||||
IsMyDebugBinary(p)) {
|
||||
g_comdbg.res = p;
|
||||
} else if (n + 4 < ARRAYLEN(g_comdbg.buf)) {
|
||||
mempcpy(mempcpy(g_comdbg.buf, p, n), ".dbg", 5);
|
||||
const char *comdbg;
|
||||
if ((comdbg = getenv("COMDBG")) && IsMyDebugBinary(comdbg)) {
|
||||
g_comdbg.res = comdbg;
|
||||
return;
|
||||
}
|
||||
char *prog = GetProgramExecutableName();
|
||||
for (int i = 0; i < ARRAYLEN(kDbgExts); ++i) {
|
||||
strlcpy(g_comdbg.buf, prog, sizeof(g_comdbg.buf));
|
||||
strlcat(g_comdbg.buf, kDbgExts[i], sizeof(g_comdbg.buf));
|
||||
if (IsMyDebugBinary(g_comdbg.buf)) {
|
||||
g_comdbg.res = g_comdbg.buf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!g_comdbg.res) {
|
||||
g_comdbg.res = getenv("COMDBG");
|
||||
}
|
||||
g_comdbg.res = prog;
|
||||
}
|
||||
|
||||
/**
|
||||
+1
-1
@@ -37,8 +37,8 @@
|
||||
* @raise EBADF if `fd` isn't an open file
|
||||
* @raise EINTR if signal was delivered
|
||||
* @raise EIO if an i/o error happened
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @see fdatasync()
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
|
||||
// Gets machine state.
|
||||
//
|
||||
// This function goes 14x slower if sigaction() has ever been used to
|
||||
// install a signal handling function. If you don't care about signal
|
||||
// safety and just want fast fibers, then you may override the global
|
||||
// variable `__interruptible` to disable the sigprocmask() calls, for
|
||||
// pure userspace context switching.
|
||||
//
|
||||
// @return 0 on success, or -1 w/ errno
|
||||
// @see makecontext()
|
||||
// @see swapcontext()
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows char *sys_getcwd_nt(char *buf, size_t size) {
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
uint32_t n, i, j;
|
||||
char16_t p[PATH_MAX];
|
||||
if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) {
|
||||
if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) {
|
||||
tprecode16to8(buf, size, p);
|
||||
i = 0;
|
||||
j = 0;
|
||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
||||
// turn c:\... into \c\...
|
||||
p[1] = p[0];
|
||||
p[0] = '\\';
|
||||
} else if (n >= 7 && p[0] == '\\' && p[1] == '\\' && p[2] == '?' &&
|
||||
p[3] == '\\' && isalpha(p[4]) && p[5] == ':' && p[6] == '\\') {
|
||||
// turn \\?\c:\... into \c\...
|
||||
buf[j++] = '/';
|
||||
buf[j++] = p[4];
|
||||
buf[j++] = '/';
|
||||
i += 7;
|
||||
}
|
||||
while (i < n) {
|
||||
x = p[i++] & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
if (i < n) {
|
||||
y = p[i++] & 0xffff;
|
||||
x = MergeUtf16(x, y);
|
||||
} else {
|
||||
x = 0xfffd;
|
||||
}
|
||||
}
|
||||
if (x < 0200) {
|
||||
if (x == '\\') {
|
||||
x = '/';
|
||||
}
|
||||
w = x;
|
||||
} else {
|
||||
w = tpenc(x);
|
||||
}
|
||||
do {
|
||||
if (j < size) {
|
||||
buf[j++] = w;
|
||||
}
|
||||
w >>= 8;
|
||||
} while (w);
|
||||
}
|
||||
if (j < size) {
|
||||
buf[j] = 0;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
erange();
|
||||
return NULL;
|
||||
} else {
|
||||
__winerr();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
+137
-64
@@ -16,81 +16,154 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/stdio/sysparam.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns current working directory, e.g.
|
||||
*
|
||||
* const char *dirname = gc(getcwd(0,0)); // if malloc is linked
|
||||
* const char *dirname = getcwd(alloca(PATH_MAX),PATH_MAX);
|
||||
*
|
||||
* @param buf is where UTF-8 NUL-terminated path string gets written,
|
||||
* which may be NULL to ask this function to malloc a buffer
|
||||
* @param size is number of bytes available in buf, e.g. PATH_MAX+1,
|
||||
* which may be 0 if buf is NULL
|
||||
* @return buf containing system-normative path or NULL w/ errno
|
||||
* @error ERANGE, EINVAL, ENOMEM
|
||||
*/
|
||||
char *getcwd(char *buf, size_t size) {
|
||||
char *p, *r;
|
||||
if (buf) {
|
||||
p = buf;
|
||||
if (!size) {
|
||||
einval();
|
||||
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
||||
return 0;
|
||||
}
|
||||
} else if (_weaken(malloc)) {
|
||||
unassert(!__vforked);
|
||||
if (!size) size = PATH_MAX;
|
||||
if (!(p = _weaken(malloc)(size))) {
|
||||
STRACE("getcwd(%p, %'zu) %m", buf, size);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
STRACE("getcwd() needs buf≠0 or __static_yoink(\"malloc\")");
|
||||
return 0;
|
||||
}
|
||||
*p = '\0';
|
||||
if (!IsWindows()) {
|
||||
if (IsMetal()) {
|
||||
r = size >= 5 ? strcpy(p, "/zip") : 0;
|
||||
} else if (IsXnu()) {
|
||||
r = sys_getcwd_xnu(p, size);
|
||||
} else if (sys_getcwd(p, size) != (void *)-1) {
|
||||
r = p;
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
r = sys_getcwd_nt(p, size);
|
||||
}
|
||||
if (!buf) {
|
||||
if (!r) {
|
||||
if (_weaken(free)) {
|
||||
_weaken(free)(p);
|
||||
}
|
||||
} else {
|
||||
if (_weaken(realloc)) {
|
||||
if ((p = _weaken(realloc)(r, strlen(r) + 1))) {
|
||||
r = p;
|
||||
#define XNU_F_GETPATH 50
|
||||
#define XNU_MAXPATHLEN 1024
|
||||
|
||||
static int sys_getcwd_xnu(char *res, size_t size) {
|
||||
int fd, len, rc = -1;
|
||||
union metastat st[2];
|
||||
char buf[XNU_MAXPATHLEN];
|
||||
if ((fd = __sys_openat_nc(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY, 0)) != -1) {
|
||||
if (__sys_fstat(fd, &st[0]) != -1) {
|
||||
if (st[0].xnu.st_dev && st[0].xnu.st_ino) {
|
||||
if (__sys_fcntl(fd, XNU_F_GETPATH, (uintptr_t)buf) != -1) {
|
||||
if (__sys_fstatat(AT_FDCWD, buf, &st[1], 0) != -1) {
|
||||
if (st[0].xnu.st_dev == st[1].xnu.st_dev &&
|
||||
st[0].xnu.st_ino == st[1].xnu.st_ino) {
|
||||
if ((len = strlen(buf)) < size) {
|
||||
memcpy(res, buf, (rc = len + 1));
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
STRACE("getcwd(%p, %'zu) → %#s", buf, size, r);
|
||||
return r;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sys_getcwd_metal(char *buf, size_t size) {
|
||||
if (size >= 5) {
|
||||
strcpy(buf, "/zip");
|
||||
return 5;
|
||||
} else {
|
||||
return erange();
|
||||
}
|
||||
}
|
||||
|
||||
static inline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
static dontinline textwindows int sys_getcwd_nt(char *buf, size_t size) {
|
||||
|
||||
// get current directory from the system
|
||||
char16_t p16[PATH_MAX];
|
||||
uint32_t n = GetCurrentDirectory(PATH_MAX, p16);
|
||||
if (!n) return eacces(); // system call failed
|
||||
if (n >= PATH_MAX) return erange(); // not enough room?!?
|
||||
|
||||
// convert utf-16 to utf-8
|
||||
// we can't modify `buf` until we're certain of success
|
||||
char p8[PATH_MAX], *p = p8;
|
||||
n = tprecode16to8(p, PATH_MAX, p16).ax;
|
||||
if (n >= PATH_MAX) return erange(); // utf-8 explosion
|
||||
|
||||
// turn \\?\c:\... into c:\...
|
||||
if (p[0] == '\\' && //
|
||||
p[1] == '\\' && //
|
||||
p[2] == '?' && //
|
||||
p[3] == '\\' && //
|
||||
IsAlpha(p[4]) && //
|
||||
p[5] == ':' && //
|
||||
p[6] == '\\') {
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
// turn c:\... into \c\...
|
||||
if (IsAlpha(p[0]) && //
|
||||
p[1] == ':' && //
|
||||
p[2] == '\\') {
|
||||
p[1] = p[0];
|
||||
p[0] = '\\';
|
||||
}
|
||||
|
||||
// we now know the final length
|
||||
// check if the user supplied a buffer large enough
|
||||
if (n >= size) {
|
||||
return erange();
|
||||
}
|
||||
|
||||
// copy bytes converting backslashes to slash
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int c = p[i];
|
||||
if (c == '\\') {
|
||||
c = '/';
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
// return number of bytes including nul
|
||||
buf[n++] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current working directory.
|
||||
*
|
||||
* Cosmo provides this function to address the shortcomings of getcwd().
|
||||
* First, this function doesn't link malloc(). Secondly, this offers the
|
||||
* Linux and NetBSD's getcwd() API across platforms since it's the best.
|
||||
*
|
||||
* @param buf receives utf-8 path and isn't modified on error
|
||||
* @param size is byte capacity of `buf`
|
||||
* @return bytes copied including nul on success, or -1 w/ errno
|
||||
* @raise EACCES if the current directory path couldn't be accessed
|
||||
* @raise ERANGE if `size` wasn't big enough for path and nul byte
|
||||
* @raise EFAULT if `buf` points to invalid memory
|
||||
*/
|
||||
int __getcwd(char *buf, size_t size) {
|
||||
int rc;
|
||||
if (IsLinux() || IsNetbsd()) {
|
||||
rc = sys_getcwd(buf, size);
|
||||
} else if (IsXnu()) {
|
||||
rc = sys_getcwd_xnu(buf, size);
|
||||
} else if (IsWindows()) {
|
||||
rc = sys_getcwd_nt(buf, size);
|
||||
} else if (IsFreebsd() || IsOpenbsd()) {
|
||||
if (sys_getcwd(buf, size) != -1) {
|
||||
rc = strlen(buf) + 1;
|
||||
} else if (SupportsFreebsd() && (errno == ENOMEM || errno == EINVAL)) {
|
||||
rc = erange();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else {
|
||||
rc = sys_getcwd_metal(buf, size);
|
||||
}
|
||||
STRACE("getcwd([%#hhs], %'zu) → %d% m", rc != -1 ? buf : "n/a", size, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -86,8 +86,9 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
if (q[0] == '.' && q[1] == '/') {
|
||||
q += 2;
|
||||
}
|
||||
if (getcwd(p, e - p - 1 - 4)) { // for / and .com
|
||||
while (*p) ++p;
|
||||
int got = __getcwd(p, e - p - 1 - 4); // for / and .com
|
||||
if (got != -1) {
|
||||
p += got - 1;
|
||||
*p++ = '/';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "libc/calls/struct/sigval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdbool.h"
|
||||
|
||||
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
|
||||
|
||||
@@ -31,10 +32,6 @@ int64_t GetConsoleOutputHandle(void);
|
||||
int IsWindowsExecutable(int64_t, const char16_t *);
|
||||
void InterceptTerminalCommands(const char *, size_t);
|
||||
|
||||
forceinline int64_t __getfdhandleactual(int fd) {
|
||||
return g_fds.p[fd].handle;
|
||||
}
|
||||
|
||||
forceinline bool __isfdopen(int fd) {
|
||||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
|
||||
}
|
||||
@@ -50,6 +47,12 @@ int _park_norestart(uint32_t, uint64_t);
|
||||
int _park_restartable(uint32_t, uint64_t);
|
||||
int sys_openat_metal(int, const char *, int, unsigned);
|
||||
|
||||
#ifdef __x86_64__
|
||||
bool __iswsl1(void);
|
||||
#else
|
||||
#define __iswsl1() false
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ */
|
||||
+1
-1
@@ -75,7 +75,7 @@ static int ioctl_default(int fd, unsigned long request, void *arg) {
|
||||
return sys_ioctl(fd, request, arg);
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (g_fds.p[fd].kind == kFdSocket) {
|
||||
handle = __getfdhandleactual(fd);
|
||||
handle = g_fds.p[fd].handle;
|
||||
if ((rc = _weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) {
|
||||
return rc;
|
||||
} else {
|
||||
|
||||
@@ -25,5 +25,6 @@
|
||||
bool IsApeLoadable(char buf[8]) {
|
||||
return READ32LE(buf) == READ32LE("\177ELF") ||
|
||||
READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='");
|
||||
READ64LE(buf) == READ64LE("jartsr='") ||
|
||||
READ64LE(buf) == READ64LE("APEDBG='");
|
||||
}
|
||||
@@ -56,6 +56,6 @@ bool32 ischardev(int fd) {
|
||||
} else {
|
||||
return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) ||
|
||||
(__isfdkind(fd, kFdFile) &&
|
||||
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
|
||||
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,11 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int sys_linkat_nt(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
@@ -74,6 +75,7 @@ textstartup void InitializeMetalFile(void) {
|
||||
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
|
||||
__ape_com_base = copied_base;
|
||||
__ape_com_size = size;
|
||||
KINFOF("%s @ %p,+%#zx", APE_COM_NAME, copied_base, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
|
||||
.init.start 101,_init_metalfile
|
||||
.init.start 102,_init_metalfile
|
||||
push %rdi
|
||||
push %rsi
|
||||
call InitializeMetalFile
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 101,_init_metalfile
|
||||
.init.end 102,_init_metalfile
|
||||
APE_COM_NAME:
|
||||
.endobj APE_COM_NAME,globl,hidden
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int sys_mkdirat_nt(int dirfd, const char *path, uint32_t mode) {
|
||||
char16_t path16[PATH_MAX];
|
||||
|
||||
+26
-25
@@ -16,11 +16,17 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/proc/ntspawn.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define APPEND(c) \
|
||||
@@ -54,6 +60,12 @@ static inline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
static bool LooksLikeCosmoDrivePath(const char *s) {
|
||||
return s[0] == '/' && //
|
||||
IsAlpha(s[1]) && //
|
||||
s[2] == '/';
|
||||
}
|
||||
|
||||
// Converts System V argv to Windows-style command line.
|
||||
//
|
||||
// Escaping is performed and it's designed to round-trip with
|
||||
@@ -68,20 +80,31 @@ static inline int IsAlpha(int c) {
|
||||
// @see libc/runtime/getdosargv.c
|
||||
// @asyncsignalsafe
|
||||
textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||
char *arg;
|
||||
int slashes, n;
|
||||
bool needsquote;
|
||||
size_t i, j, k, s;
|
||||
char argbuf[PATH_MAX];
|
||||
for (k = i = 0; argv[i]; ++i) {
|
||||
if (i) APPEND(u' ');
|
||||
if ((needsquote = NeedsQuotes(argv[i]))) APPEND(u'"');
|
||||
if (LooksLikeCosmoDrivePath(argv[i]) &&
|
||||
strlcpy(argbuf, argv[i], PATH_MAX) < PATH_MAX) {
|
||||
mungentpath(argbuf);
|
||||
arg = argbuf;
|
||||
} else {
|
||||
arg = argv[i];
|
||||
}
|
||||
if ((needsquote = NeedsQuotes(arg))) {
|
||||
APPEND(u'"');
|
||||
}
|
||||
for (slashes = j = 0;;) {
|
||||
wint_t x = argv[i][j++] & 255;
|
||||
wint_t x = arg[j++] & 255;
|
||||
if (x >= 0300) {
|
||||
n = ThomPikeLen(x);
|
||||
x = ThomPikeByte(x);
|
||||
while (--n) {
|
||||
wint_t y;
|
||||
if ((y = argv[i][j++] & 255)) {
|
||||
if ((y = arg[j++] & 255)) {
|
||||
x = ThomPikeMerge(x, y);
|
||||
} else {
|
||||
x = 0;
|
||||
@@ -90,28 +113,6 @@ textwindows int mkntcmdline(char16_t cmdline[32767], char *const argv[]) {
|
||||
}
|
||||
}
|
||||
if (!x) break;
|
||||
if (x == '/' || x == '\\') {
|
||||
if (!i) {
|
||||
// turn / into \ for first argv[i]
|
||||
x = '\\';
|
||||
// turn \c\... into c:\ for first argv[i]
|
||||
if (k == 2 && IsAlpha(cmdline[1]) && cmdline[0] == '\\') {
|
||||
cmdline[0] = cmdline[1];
|
||||
cmdline[1] = ':';
|
||||
}
|
||||
} else {
|
||||
// turn stuff like `less /c/...`
|
||||
// into `less c:/...`
|
||||
// turn stuff like `more <"/c/..."`
|
||||
// into `more <"c:/..."`
|
||||
if (k > 3 && IsAlpha(cmdline[k - 1]) &&
|
||||
(cmdline[k - 2] == '/' || cmdline[k - 2] == '\\') &&
|
||||
(cmdline[k - 3] == '"' || cmdline[k - 3] == ' ')) {
|
||||
cmdline[k - 2] = cmdline[k - 1];
|
||||
cmdline[k - 1] = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x == '\\') {
|
||||
++slashes;
|
||||
} else if (x == '"') {
|
||||
|
||||
Loaded 100 of 742 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user