mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 08:08:04 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb19e172da | ||
|
|
df648fb174 | ||
|
|
9a6af92bed | ||
|
|
6ab01716ce | ||
|
|
21093044c0 | ||
|
|
b8a9fbbd01 | ||
|
|
81ce2e4cbc | ||
|
|
07db3004d6 | ||
|
|
b0566348b2 | ||
|
|
8fb24a8f88 | ||
|
|
a4b455185b | ||
|
|
6cb0354e19 | ||
|
|
b580080af1 | ||
|
|
8b33204f37 | ||
|
|
94bab1618d | ||
|
|
cafea9a0a5 | ||
|
|
16099801cc | ||
|
|
4cd02c29ed | ||
|
|
5ae2554c10 | ||
|
|
531ac85923 | ||
|
|
8d9fcb5e5a | ||
|
|
aa37a327ea | ||
|
|
c4205f8305 | ||
|
|
b3fb6cff43 | ||
|
|
2e5f662dfe | ||
|
|
5e7137097d | ||
|
|
f224a55d57 | ||
|
|
0c51995b2b | ||
|
|
a9f23ccd17 | ||
|
|
57d1bf7a9c | ||
|
|
ce17ed60df | ||
|
|
d27a47b0e2 | ||
|
|
390335eb45 | ||
|
|
492a8f4f53 | ||
|
|
636bc4007b | ||
|
|
b09096691a | ||
|
|
91de6f1f5d | ||
|
|
fad1279c61 | ||
|
|
c0eacf2eb1 | ||
|
|
c60b150fcf | ||
|
|
80ec6c9283 | ||
|
|
2d93788ce3 | ||
|
|
15548b523c | ||
|
|
412a200ae4 | ||
|
|
44a463e4d2 | ||
|
|
0de6a08988 | ||
|
|
a334f9cc33 | ||
|
|
3315b6ef11 | ||
|
|
e93c8c4f8f | ||
|
|
0e49bed660 |
No files matched your search
+2
-1
@@ -1,7 +1,8 @@
|
||||
# -*- conf -*-
|
||||
|
||||
/o
|
||||
/.prompt.jtlp
|
||||
/cosmocc
|
||||
/.cosmocc
|
||||
|
||||
# TODO: Find some way to have Python write to o/
|
||||
__pycache__
|
||||
|
||||
+32
-14
@@ -2,23 +2,41 @@
|
||||
|
||||
We'd love to accept your patches! Please read this guide first.
|
||||
|
||||
## Identity Disclosure
|
||||
|
||||
This project does not accept anonymous contributions. Justine Tunney
|
||||
won't merge pull requests from strangers. In order to change the Cosmo
|
||||
codebase, and have your changes be upstreamed, she has to know who you
|
||||
are. You're encouraged to disclose your full name and email address to
|
||||
the public too, by including them in your git commit messages; however
|
||||
that's not a requirement; as we're happy to respect the wishes of
|
||||
contributors who prefer to remain anonymous to the public.
|
||||
|
||||
## Copyright Assignment
|
||||
|
||||
Please send an email to Justine Tunney <jtunney@gmail.com> stating that
|
||||
you intend to assign her the copyright to the changes you contribute to
|
||||
Cosmopolitan. Please use the same email address you use for git commits
|
||||
which should only contain original source code from you or other people
|
||||
who are also assigning copyright. Please note that, if you're employed,
|
||||
you may need to get your employer's approval beforehand. If you can not
|
||||
assign copyright due to local laws, then you may alternatively consider
|
||||
disclaiming it using the language in [Unlicense](https://unlicense.org)
|
||||
or [CC-0](http://creativecommons.org/share-your-work/public-domain/cc0)
|
||||
The first time you send a pull request, you need to send an email to
|
||||
Justine Tunney <jtunney@gmail.com> stating that you intend to assign her
|
||||
the copyright to the changes you contribute to Cosmopolitan. This only
|
||||
applies to the code you *choose* to contribute. It only has to happen
|
||||
once. The email should be sent from an email address associated with
|
||||
your identity. Your email should link to your pull request.
|
||||
|
||||
This is important because we can't produce 12kb single-file executables
|
||||
that comply with license requirements if we have to embed lots of them.
|
||||
Although that's less of an issue depending on the purpose of the files.
|
||||
For example, ownership is much less of a concern in the unit test files
|
||||
so you're encouraged to put your copyright on those, provided it's ISC.
|
||||
Please note that in order to give Justine the copyright, it has to be
|
||||
yours to give in the first place. If you're employed, then you should
|
||||
get your employer's approval to do this beforehand. Even with big
|
||||
companies like Google, this process is quick and painless. Usually we
|
||||
see employers granting authorization in less than one day.
|
||||
|
||||
If you live in a country that doesn't recognize one's ability to assign
|
||||
copyright, then you may alternatively consider disclaiming it using the
|
||||
language in [Unlicense](https://unlicense.org) or
|
||||
[CC-0](http://creativecommons.org/share-your-work/public-domain/cc0).
|
||||
|
||||
If you're checking-in third party code, then you need to have headers at
|
||||
the top of each source file (but never header files) documenting its
|
||||
owners and the code should go in the `third_party/` folder. Every third
|
||||
party project should have a `README.cosmo` file that documents its
|
||||
provenance as well as any local changes you've made.
|
||||
|
||||
## Style Guide
|
||||
|
||||
|
||||
@@ -73,10 +73,13 @@ MODE := $(m)
|
||||
endif
|
||||
endif
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell pwd)
|
||||
|
||||
# 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)),)
|
||||
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
|
||||
$(warning wsl2 interop is enabled)
|
||||
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
|
||||
endif
|
||||
@@ -89,14 +92,33 @@ ifeq ($(MAKE_VERSION), 3.81)
|
||||
$(error please use build/bootstrap/make.com)
|
||||
endif
|
||||
|
||||
# provide instructions to non-linux users on unbundling gcc
|
||||
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 please run tool/cosmocc/fetch.sh)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
LC_ALL = C
|
||||
SOURCE_DATE_EPOCH = 0
|
||||
|
||||
ARFLAGS = rcsD
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
|
||||
AR = build/bootstrap/ar.com
|
||||
CP = build/bootstrap/cp.com
|
||||
RM = build/bootstrap/rm.com -f
|
||||
GZIP = build/bootstrap/gzip.com
|
||||
ECHO = build/bootstrap/echo.com
|
||||
CHMOD = build/bootstrap/chmod.com
|
||||
TOUCH = build/bootstrap/touch.com
|
||||
PKG = build/bootstrap/package.com
|
||||
MKDEPS = build/bootstrap/mkdeps.com
|
||||
ZIPOBJ = build/bootstrap/zipobj.com
|
||||
ZIPCOPY = build/bootstrap/zipcopy.com
|
||||
PECHECK = build/bootstrap/pecheck.com
|
||||
FIXUPOBJ = build/bootstrap/fixupobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
|
||||
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
# the default build modes is empty string
|
||||
# on x86_64 hosts, MODE= is the same as MODE=x86_64
|
||||
@@ -110,6 +132,44 @@ MODE := aarch64
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu win10 openbsd netbsd
|
||||
endif
|
||||
|
||||
ZIPOBJ_FLAGS += -a$(ARCH)
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
COSMOCC = .cosmocc/3.2
|
||||
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
|
||||
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.2 28b48682595f0f46b45ab381118cdffdabc8fcfa29aa54e301fe6ffe35269f5e)
|
||||
|
||||
AS = $(TOOLCHAIN)as
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
CXX = $(TOOLCHAIN)g++
|
||||
CXXFILT = $(TOOLCHAIN)c++filt
|
||||
LD = $(TOOLCHAIN)ld.bfd
|
||||
NM = $(TOOLCHAIN)nm
|
||||
GCC = $(TOOLCHAIN)gcc
|
||||
STRIP = $(TOOLCHAIN)strip
|
||||
OBJCOPY = $(TOOLCHAIN)objcopy
|
||||
OBJDUMP = $(TOOLCHAIN)objdump
|
||||
ifneq ($(wildcard $(PWD)/$(TOOLCHAIN)addr2line),)
|
||||
ADDR2LINE = $(PWD)/$(TOOLCHAIN)addr2line
|
||||
else
|
||||
ADDR2LINE = $(TOOLCHAIN)addr2line
|
||||
endif
|
||||
|
||||
# primary build rules
|
||||
all: o
|
||||
o: o/$(MODE)
|
||||
@@ -138,7 +198,7 @@ $(warning please run ape/apeinstall.sh if you intend to use landlock make)
|
||||
$(shell sleep .5)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
ifneq ($(TOOLCHAIN),)
|
||||
.STRICT = 1
|
||||
endif
|
||||
endif
|
||||
@@ -149,8 +209,8 @@ endif
|
||||
libc/stdbool.h \
|
||||
libc/disclaimer.inc \
|
||||
rwc:/dev/shm \
|
||||
rx:cosmocc \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
r:build/portcosmo.h \
|
||||
/proc/stat \
|
||||
rw:/dev/null \
|
||||
@@ -189,7 +249,6 @@ include libc/calls/BUILD.mk #─┐
|
||||
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
|
||||
include third_party/nsync/BUILD.mk # │ You can issue system calls
|
||||
include libc/runtime/BUILD.mk # │
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include libc/crt/BUILD.mk # │
|
||||
include third_party/dlmalloc/BUILD.mk #─┘
|
||||
include libc/mem/BUILD.mk #─┐
|
||||
@@ -224,7 +283,10 @@ include third_party/stb/BUILD.mk # │
|
||||
include third_party/mbedtls/BUILD.mk # │
|
||||
include third_party/ncurses/BUILD.mk # │
|
||||
include third_party/readline/BUILD.mk # │
|
||||
include third_party/libunwind/BUILD.mk # |
|
||||
include third_party/libcxxabi/BUILD.mk # |
|
||||
include third_party/libcxx/BUILD.mk # │
|
||||
include third_party/double-conversion/BUILD.mk # │
|
||||
include third_party/pcre/BUILD.mk # │
|
||||
include third_party/less/BUILD.mk # │
|
||||
include net/https/BUILD.mk # │
|
||||
@@ -268,6 +330,7 @@ include third_party/python/BUILD.mk
|
||||
include tool/build/BUILD.mk
|
||||
include tool/curl/BUILD.mk
|
||||
include third_party/qemu/BUILD.mk
|
||||
include third_party/libcxxabi/test/BUILD.mk
|
||||
include examples/BUILD.mk
|
||||
include examples/pyapp/BUILD.mk
|
||||
include examples/pylife/BUILD.mk
|
||||
@@ -380,6 +443,8 @@ COSMOPOLITAN_OBJECTS = \
|
||||
LIBC_TIME \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_LIBUNWIND \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
@@ -449,12 +514,14 @@ COSMOPOLITAN_H_PKGS = \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
COSMOCC_PKGS = \
|
||||
$(COSMOPOLITAN_H_PKGS) \
|
||||
THIRD_PARTY_AARCH64 \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LIBCXXABI \
|
||||
THIRD_PARTY_INTEL
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
@@ -479,18 +546,15 @@ 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$@ build/bootstrap/rollup.com @$< >>$@
|
||||
|
||||
o/cosmopolitan.html: private .UNSANDBOXED = 1
|
||||
o/cosmopolitan.html: \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
|
||||
$(SRCS) \
|
||||
$(filter-out %.cc,$(SRCS)) \
|
||||
$(HDRS)
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
|
||||
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))))
|
||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
|
||||
-fno-common -include libc/integral/normalize.inc -o $@ \
|
||||
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
|
||||
|
||||
@@ -76,18 +76,7 @@ make install
|
||||
## 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
|
||||
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
|
||||
```
|
||||
platforms. The Makefile will download cosmocc automatically.
|
||||
|
||||
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
|
||||
@@ -103,7 +92,7 @@ guaranteed to be compatible and furthermore includes our extensions for
|
||||
doing build system sandboxing.
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make -j8
|
||||
build/bootstrap/make.com -j8
|
||||
o//examples/hello.com
|
||||
```
|
||||
|
||||
@@ -114,7 +103,7 @@ depends on core LIBC packages.
|
||||
|
||||
```sh
|
||||
rm -rf o//libc o//test
|
||||
o//third_party/gcc/bin/make o//test/posix/signal_test.com
|
||||
build/bootstrap/make.com o//test/posix/signal_test.com
|
||||
o//test/posix/signal_test.com
|
||||
```
|
||||
|
||||
@@ -123,21 +112,21 @@ 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
|
||||
o//third_party/gcc/bin/make o//test/posix
|
||||
build/bootstrap/make.com 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
|
||||
o//third_party/gcc/bin/make m=tiny
|
||||
build/bootstrap/make.com m=tiny
|
||||
```
|
||||
|
||||
You can furthermore cut out the bloat of other operating systems, and
|
||||
have Cosmopolitan become much more similar to Musl Libc.
|
||||
|
||||
```sh
|
||||
o//third_party/gcc/bin/make m=tinylinux
|
||||
build/bootstrap/make.com m=tinylinux
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
|
||||
+70
-80
@@ -103,36 +103,39 @@ struct Syslib {
|
||||
char *(*dlerror)(void);
|
||||
};
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define EM_AARCH64 183
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_ENTRY 9
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_HWCAP 16
|
||||
#define AT_HWCAP2 16
|
||||
#define AT_SECURE 23
|
||||
#define AT_RANDOM 25
|
||||
#define AT_EXECFN 31
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define EM_AARCH64 183
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
#define AT_ENTRY 9
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_HWCAP 16
|
||||
#define AT_HWCAP2 16
|
||||
#define AT_SECURE 23
|
||||
#define AT_RANDOM 25
|
||||
#define AT_EXECFN 31
|
||||
|
||||
#define AUXV_WORDS 29
|
||||
#define AUXV_WORDS 31
|
||||
|
||||
/* from the xnu codebase */
|
||||
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
|
||||
@@ -322,17 +325,7 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
if (!access(ps->path, X_OK)) {
|
||||
if (ps->indirect) {
|
||||
ps->namelen -= 4;
|
||||
ps->path[pathlen + ps->namelen] = 0;
|
||||
if (access(ps->path, X_OK) < 0) {
|
||||
Pexit(ps->path, -errno, "access(X_OK)");
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return !access(ps->path, X_OK);
|
||||
}
|
||||
|
||||
static char SearchPath(struct PathSearcher *ps) {
|
||||
@@ -358,12 +351,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||
ps->path[0] = 0;
|
||||
|
||||
/* paths are always 100% taken literally when a slash exists
|
||||
$ ape foo/bar.com arg1 arg2 */
|
||||
if (memchr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* we don't run files in the current directory
|
||||
$ ape foo/bar.com arg1 arg2
|
||||
we don't run files in the current directory
|
||||
$ ape foo.com arg1 arg2
|
||||
unless $PATH has an empty string entry, e.g.
|
||||
$ expert PATH=":/bin"
|
||||
@@ -371,8 +360,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||
however we will execute this
|
||||
$ ape - foo.com foo.com arg1 arg2
|
||||
because cosmo's execve needs it */
|
||||
if (ps->literally && AccessCommand(ps, 0)) {
|
||||
return 1;
|
||||
if (ps->literally || memchr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* otherwise search for name on $PATH */
|
||||
@@ -382,7 +371,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||
static char *Commandv(struct PathSearcher *ps, const char *name,
|
||||
const char *syspath) {
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
ps->name = name;
|
||||
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (FindCommand(ps)) {
|
||||
return ps->path;
|
||||
@@ -861,25 +851,27 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||
auxv[7] = ebuf->ehdr.e_entry;
|
||||
auxv[8] = AT_PAGESZ;
|
||||
auxv[9] = pagesz;
|
||||
auxv[10] = AT_UID;
|
||||
auxv[11] = getuid();
|
||||
auxv[12] = AT_EUID;
|
||||
auxv[13] = geteuid();
|
||||
auxv[14] = AT_GID;
|
||||
auxv[15] = getgid();
|
||||
auxv[16] = AT_EGID;
|
||||
auxv[17] = getegid();
|
||||
auxv[18] = AT_HWCAP;
|
||||
auxv[19] = 0xffb3ffffu;
|
||||
auxv[20] = AT_HWCAP2;
|
||||
auxv[21] = 0x181;
|
||||
auxv[22] = AT_SECURE;
|
||||
auxv[23] = issetugid();
|
||||
auxv[24] = AT_RANDOM;
|
||||
auxv[25] = (long)M->rando;
|
||||
auxv[26] = AT_EXECFN;
|
||||
auxv[27] = (long)execfn;
|
||||
auxv[28] = 0;
|
||||
auxv[10] = AT_FLAGS;
|
||||
auxv[11] = M->ps.literally ? AT_FLAGS_PRESERVE_ARGV0 : 0;
|
||||
auxv[12] = AT_UID;
|
||||
auxv[13] = getuid();
|
||||
auxv[14] = AT_EUID;
|
||||
auxv[15] = geteuid();
|
||||
auxv[16] = AT_GID;
|
||||
auxv[17] = getgid();
|
||||
auxv[18] = AT_EGID;
|
||||
auxv[19] = getegid();
|
||||
auxv[20] = AT_HWCAP;
|
||||
auxv[21] = 0xffb3ffffu;
|
||||
auxv[22] = AT_HWCAP2;
|
||||
auxv[23] = 0x181;
|
||||
auxv[24] = AT_SECURE;
|
||||
auxv[25] = issetugid();
|
||||
auxv[26] = AT_RANDOM;
|
||||
auxv[27] = (long)M->rando;
|
||||
auxv[28] = AT_EXECFN;
|
||||
auxv[29] = (long)execfn;
|
||||
auxv[30] = 0;
|
||||
|
||||
/* we're now ready to load */
|
||||
Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path);
|
||||
@@ -891,7 +883,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
struct ApeLoader *M;
|
||||
long *sp, *sp2, *auxv;
|
||||
union ElfEhdrBuf *ebuf;
|
||||
char *p, *pe, *exe, *prog, *execfn, *shell;
|
||||
char *p, *pe, *exe, *prog, *execfn;
|
||||
|
||||
/* allocate loader memory in program's arg block */
|
||||
n = sizeof(struct ApeLoader);
|
||||
@@ -954,12 +946,16 @@ int main(int argc, char **argv, char **envp) {
|
||||
M->lib.dlerror = dlerror;
|
||||
|
||||
/* getenv("_") is close enough to at_execfn */
|
||||
execfn = argc > 0 ? argv[0] : 0;
|
||||
execfn = 0;
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
||||
execfn = envp[i] + 2;
|
||||
}
|
||||
}
|
||||
prog = GetEnv(envp + i + 1, "executable_path");
|
||||
if (!execfn) {
|
||||
execfn = prog;
|
||||
}
|
||||
|
||||
/* sneak the system five abi back out of args */
|
||||
sp = (long *)(argv - 1);
|
||||
@@ -981,8 +977,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
sp = sp2;
|
||||
|
||||
/* interpret command line arguments */
|
||||
if ((M->ps.indirect = argc > 0 ? GetIndirectOffset(argv[0]) : 0)) {
|
||||
/* if argv[0] is $prog.ape, then we strip off the .ape and run
|
||||
if ((M->ps.indirect = GetIndirectOffset(prog))) {
|
||||
/* if called as $prog.ape, then strip off the .ape and run the
|
||||
$prog. This allows you to use symlinks to trick the OS when
|
||||
a native executable is required. For example, let's say you
|
||||
want to use the APE binary /opt/cosmos/bin/bash as a system
|
||||
@@ -991,13 +987,7 @@ int main(int argc, char **argv, char **envp) {
|
||||
but it will if you say:
|
||||
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
||||
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
||||
M->ps.literally = 0;
|
||||
if (*argv[0] == '-' && (shell = GetEnv(envp, "SHELL")) &&
|
||||
!StrCmp(argv[0] + 1, BaseName(shell))) {
|
||||
execfn = prog = shell;
|
||||
} else {
|
||||
prog = (char *)sp[1];
|
||||
}
|
||||
M->ps.literally = 1;
|
||||
argc = sp[0];
|
||||
argv = (char **)(sp + 1);
|
||||
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
@@ -1011,7 +1001,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"
|
||||
" ($0 = PROG.ape) [ARGV1,ARGV2,...]\n"
|
||||
" PROG.ape [ARGV1,ARGV2,...]\n"
|
||||
"actually portable executable loader silicon 1.10\n"
|
||||
"copyrights 2023 justine alexandra roberts tunney\n"
|
||||
"https://justine.lol/ape.html\n");
|
||||
|
||||
+58
-33
@@ -10,73 +10,98 @@ if [ ! -f ape/loader.c ]; then
|
||||
cd "$COSMO" || exit
|
||||
fi
|
||||
|
||||
if [ -x build/bootstrap/make.com ]; then
|
||||
MAKE=build/bootstrap/make.com
|
||||
else
|
||||
MAKE=make
|
||||
fi
|
||||
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
elif command -v doas >/dev/null 2>&1; then
|
||||
SUDO=doas
|
||||
else
|
||||
echo "need root or sudo" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
if command -v install >/dev/null 2>&1; then
|
||||
if [ x"$(uname -s)" = xLinux ]; then
|
||||
INSTALL="install -o root -g root -m 755"
|
||||
else
|
||||
INSTALL="install -o root -g wheel -m 755"
|
||||
fi
|
||||
else
|
||||
INSTALL="cp -f"
|
||||
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
|
||||
if [ x"$(uname -s)" = xDarwin ] && [ x"$(uname -m)" = xarm64 ]; then
|
||||
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
|
||||
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
|
||||
trap 'rm "$TMPDIR/ape.$$"' 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
|
||||
echo "$SUDO $INSTALL $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
|
||||
$SUDO $INSTALL "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ x"$(uname -m)" = xarm64 ] || [ x"$(uname -m)" = xaarch64 ]; then
|
||||
MODE=aarch64
|
||||
EXT=elf
|
||||
BEXT=aarch64
|
||||
elif [ x"$(uname -m)" = xx86_64 ]; then
|
||||
MODE=
|
||||
if [ x"$(uname -s)" = xDarwin ]; then
|
||||
EXT=macho
|
||||
else
|
||||
EXT=elf
|
||||
fi
|
||||
BEXT=$EXT
|
||||
else
|
||||
echo "unsupported architecture $(uname -m)" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# INSTALL APE LOADER SYSTEMWIDE
|
||||
|
||||
if [ -f o/depend ] && make -j8 o//ape; then
|
||||
if [ -f o/$MODE/depend ] && $MAKE -j8 o/$MODE/ape; then
|
||||
echo "successfully recompiled ape loader" >&2
|
||||
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
|
||||
elif [ -x o/$MODE/ape/ape.$EXT ]; 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
|
||||
mkdir -p o/$MODE/ape || exit
|
||||
cp -af build/bootstrap/ape.$BEXT o/$MODE/ape/ape.$EXT || exit
|
||||
else
|
||||
echo "no cosmopolitan libc repository here" >&2
|
||||
echo "fetching ape loader from justine.lol" >&2
|
||||
mkdir -p o//ape || exit
|
||||
echo "fetching ape loader from justine.lol" >&2
|
||||
mkdir -p o/$MODE/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
|
||||
wget -qO o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || 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
|
||||
curl -Rso o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
|
||||
fi
|
||||
chmod +x o//ape/ape.elf || exit
|
||||
chmod +x o//ape/ape.macho || exit
|
||||
chmod +x o/$MODE/ape/ape.$EXT || 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
|
||||
if ! [ /usr/bin/ape -nt o/$MODE/ape/ape.$EXT ]; then
|
||||
echo >&2
|
||||
echo "installing o/$MODE/ape/ape.$EXT to /usr/bin/ape" >&2
|
||||
echo "$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape" >&2
|
||||
$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape || exit
|
||||
echo "done" >&2
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
+6
-1
@@ -11,8 +11,13 @@ fi
|
||||
|
||||
if [ "$UID" = "0" ]; then
|
||||
SUDO=
|
||||
else
|
||||
elif command -v sudo >/dev/null 2>&1; then
|
||||
SUDO=sudo
|
||||
elif command -v doas >/dev/null 2>&1; then
|
||||
SUDO=doas
|
||||
else
|
||||
echo "need root or sudo" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
{
|
||||
|
||||
+58
-72
@@ -113,41 +113,44 @@
|
||||
#define EXTERN_C
|
||||
#endif
|
||||
|
||||
#define O_RDONLY 0
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_FIXED 16
|
||||
#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096)
|
||||
#define MAP_NORESERVE (IsLinux() ? 16384 : 0)
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define EM_NEXGEN32E 62
|
||||
#define EM_AARCH64 183
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_EXECFN_LINUX 31
|
||||
#define AT_EXECFN_NETBSD 2014
|
||||
#define X_OK 1
|
||||
#define XCR0_SSE 2
|
||||
#define XCR0_AVX 4
|
||||
#define PR_SET_MM 35
|
||||
#define PR_SET_MM_EXE_FILE 13
|
||||
#define O_RDONLY 0
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_FIXED 16
|
||||
#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096)
|
||||
#define MAP_NORESERVE (IsLinux() ? 16384 : 0)
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define EM_NEXGEN32E 62
|
||||
#define EM_AARCH64 183
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_FLAGS 8
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
#define AT_EXECFN_LINUX 31
|
||||
#define AT_EXECFN_NETBSD 2014
|
||||
#define X_OK 1
|
||||
#define XCR0_SSE 2
|
||||
#define XCR0_AVX 4
|
||||
#define PR_SET_MM 35
|
||||
#define PR_SET_MM_EXE_FILE 13
|
||||
|
||||
#define READ32(S) \
|
||||
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
|
||||
@@ -572,39 +575,15 @@ static char SearchPath(struct PathSearcher *ps) {
|
||||
}
|
||||
}
|
||||
|
||||
static char FindCommand(struct PathSearcher *ps) {
|
||||
ps->path[0] = 0;
|
||||
|
||||
/* paths are always 100% taken literally when a slash exists
|
||||
$ ape foo/bar.com arg1 arg2 */
|
||||
if (MemChr(ps->name, '/', ps->namelen)) {
|
||||
return AccessCommand(ps, 0);
|
||||
}
|
||||
|
||||
/* we don't run files in the current directory
|
||||
$ ape foo.com arg1 arg2
|
||||
unless $PATH has an empty string entry, e.g.
|
||||
$ expert PATH=":/bin"
|
||||
$ ape foo.com arg1 arg2
|
||||
however we will execute this
|
||||
$ ape - foo.com foo.com arg1 arg2
|
||||
because cosmo's execve needs it */
|
||||
if (ps->literally && AccessCommand(ps, 0)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* otherwise search for name on $PATH */
|
||||
return SearchPath(ps);
|
||||
}
|
||||
|
||||
static char *Commandv(struct PathSearcher *ps, int os, char *name,
|
||||
const char *syspath, int may_path_search) {
|
||||
if (!may_path_search) return name;
|
||||
const char *syspath) {
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
|
||||
ps->os = os;
|
||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||
if (FindCommand(ps)) {
|
||||
ps->path[0] = 0;
|
||||
if (SearchPath(ps)) {
|
||||
return ps->path;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -897,7 +876,7 @@ __attribute__((__noreturn__)) static void ShowUsage(int os, int fd, int rc) {
|
||||
"NAME\n"
|
||||
"\n"
|
||||
" actually portable executable loader version " APE_VERSION_STR "\n"
|
||||
" copyright 2023 justine alexandra roberts tunney\n"
|
||||
" copyrights 2024 justine alexandra roberts tunney\n"
|
||||
" https://justine.lol/ape.html\n"
|
||||
"\n"
|
||||
"USAGE\n"
|
||||
@@ -913,10 +892,10 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
char dl) {
|
||||
int rc, n;
|
||||
unsigned i;
|
||||
char literally;
|
||||
const char *ape;
|
||||
int c, fd, os, argc;
|
||||
struct ApeLoader *M;
|
||||
char arg0, literally;
|
||||
unsigned long pagesz;
|
||||
union ElfEhdrBuf *ebuf;
|
||||
long *auxv, *ap, *endp, *sp2;
|
||||
@@ -961,11 +940,15 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
|
||||
/* detect netbsd and find end of words */
|
||||
pagesz = 0;
|
||||
arg0 = 0;
|
||||
for (ap = auxv; ap[0]; ap += 2) {
|
||||
if (ap[0] == AT_PAGESZ) {
|
||||
pagesz = ap[1];
|
||||
} else if (SupportsNetbsd() && !os && ap[0] == AT_EXECFN_NETBSD) {
|
||||
os = NETBSD;
|
||||
} else if (SupportsLinux() && ap[0] == AT_FLAGS) {
|
||||
// TODO(mrdomino): maybe set/insert this when we are called as "ape -".
|
||||
arg0 = !!(ap[1] & AT_FLAGS_PRESERVE_ARGV0);
|
||||
}
|
||||
}
|
||||
if (!pagesz) {
|
||||
@@ -979,8 +962,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
}
|
||||
|
||||
/* we can load via shell, shebang, or binfmt_misc */
|
||||
int may_path_search = 1;
|
||||
if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
if (arg0) {
|
||||
literally = 1;
|
||||
prog = (char *)sp[2];
|
||||
argc = sp[2] = sp[0] - 2;
|
||||
argv = (char **)((sp += 2) + 1);
|
||||
} else if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||
/* if the first argument is a hyphen then we give the user the
|
||||
power to change argv[0] or omit it entirely. most operating
|
||||
systems don't permit the omission of argv[0] but we do, b/c
|
||||
@@ -988,12 +975,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
prog = (char *)sp[3];
|
||||
argc = sp[3] = sp[0] - 3;
|
||||
argv = (char **)((sp += 3) + 1);
|
||||
may_path_search = 0;
|
||||
} else if (argc < 2) {
|
||||
ShowUsage(os, 2, 1);
|
||||
} else {
|
||||
if (argv[1][0] == '-') {
|
||||
rc = !(argv[1][1] == 'h' && !argv[1][2]) || !StrCmp(argv[1] + 1, "-help");
|
||||
rc = !((argv[1][1] == 'h' && !argv[1][2]) ||
|
||||
!StrCmp(argv[1] + 1, "-help"));
|
||||
ShowUsage(os, 1 + rc, rc);
|
||||
}
|
||||
prog = (char *)sp[2];
|
||||
@@ -1029,8 +1016,7 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
|
||||
}
|
||||
|
||||
/* resolve path of executable and read its first page */
|
||||
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH"),
|
||||
may_path_search))) {
|
||||
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH")))) {
|
||||
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
|
||||
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
|
||||
Pexit(os, exe, fd, "open");
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -53,91 +53,6 @@
|
||||
# OVERRIDE_FOO set ~/.cosmo.mk and target-specific (use rarely)
|
||||
#
|
||||
|
||||
LC_ALL = C
|
||||
SOURCE_DATE_EPOCH = 0
|
||||
|
||||
ARFLAGS = rcsD
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
CLANG = clang
|
||||
TMPDIR = o/tmp
|
||||
|
||||
AR = build/bootstrap/ar.com
|
||||
CP = build/bootstrap/cp.com
|
||||
RM = build/bootstrap/rm.com -f
|
||||
GZIP = build/bootstrap/gzip.com
|
||||
ECHO = build/bootstrap/echo.com
|
||||
CHMOD = build/bootstrap/chmod.com
|
||||
TOUCH = build/bootstrap/touch.com
|
||||
PKG = build/bootstrap/package.com
|
||||
MKDEPS = build/bootstrap/mkdeps.com
|
||||
ZIPOBJ = build/bootstrap/zipobj.com
|
||||
ZIPCOPY = build/bootstrap/zipcopy.com
|
||||
PECHECK = build/bootstrap/pecheck.com
|
||||
FIXUPOBJ = build/bootstrap/fixupobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell build/bootstrap/pwd.com)
|
||||
|
||||
IGNORE := $(shell $(MKDIR) $(TMPDIR))
|
||||
|
||||
ifneq ($(findstring aarch64,$(MODE)),)
|
||||
ARCH = aarch64
|
||||
HOSTS ?= pi studio freebsdarm
|
||||
else
|
||||
ARCH = x86_64
|
||||
HOSTS ?= freebsd rhel7 xnu win10 openbsd netbsd
|
||||
endif
|
||||
|
||||
ZIPOBJ_FLAGS += -a$(ARCH)
|
||||
|
||||
ifeq ($(PREFIX),)
|
||||
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
ifeq ($(ARCH),x86_64)
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-cosmo-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
|
||||
endif
|
||||
endif # ($(ARCH),x86_64))
|
||||
ifeq ($(ARCH),aarch64)
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/aarch64-linux-cosmo-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/aarch64-linux-cosmo-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
PREFIX = o/third_party/gcc/bin/aarch64-linux-musl-
|
||||
endif
|
||||
endif # ($(ARCH),aarch64)
|
||||
endif # ($(USE_SYSTEM_TOOLCHAIN),)
|
||||
endif # ($(PREFIX),)
|
||||
|
||||
AS = $(PREFIX)as
|
||||
CC = $(PREFIX)gcc
|
||||
CXX = $(PREFIX)g++
|
||||
CXXFILT = $(PREFIX)c++filt
|
||||
LD = $(PREFIX)ld.bfd
|
||||
NM = $(PREFIX)nm
|
||||
GCC = $(PREFIX)gcc
|
||||
STRIP = $(PREFIX)strip
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
ifneq ($(wildcard $(PWD)/$(PREFIX)addr2line),)
|
||||
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
|
||||
else
|
||||
ADDR2LINE = $(PREFIX)addr2line
|
||||
endif
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
||||
ifeq ($(LANDLOCKMAKE_VERSION),)
|
||||
TMPSAFE = $(join $(TMPDIR),$(subst /,_,$@)).tmp
|
||||
else
|
||||
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/bin/sh
|
||||
# cosmocc downloader script
|
||||
# https://justine.lol/cosmo3/#install
|
||||
# https://github.com/jart/cosmopolitan/blob/master/tool/cosmocc/README.md
|
||||
|
||||
# collect arguments
|
||||
OUTPUT_DIR=${1:?OUTPUT_DIR}
|
||||
COSMOCC_VERSION=${2:?COSMOCC_VERSION}
|
||||
COSMOCC_SHA256SUM=${3:?COSMOCC_SHA256SUM}
|
||||
URL1="https://github.com/jart/cosmopolitan/releases/download/${COSMOCC_VERSION}/cosmocc-${COSMOCC_VERSION}.zip"
|
||||
URL2="https://cosmo.zip/pub/cosmocc/cosmocc-${COSMOCC_VERSION}.zip"
|
||||
|
||||
# helper function
|
||||
abort() {
|
||||
printf '%s\n' "download terminated." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# exit if already downloaded
|
||||
# we need it because directory timestamps work wierdly
|
||||
OUTPUT_DIR=${OUTPUT_DIR%/}
|
||||
if [ -d "${OUTPUT_DIR}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# find commands we need to securely download cosmocc
|
||||
if ! UNZIP=$(command -v unzip 2>/dev/null); then
|
||||
printf '%s\n' "$0: fatal error: you need the unzip command" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/unzip and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
# can use system sha256sum
|
||||
true
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
sha256sum() {
|
||||
shasum -a 256 "$@"
|
||||
}
|
||||
else
|
||||
if [ ! -f build/sha256sum.c ]; then
|
||||
printf '%s\n' "$0: fatal error: you need to install sha256sum" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
if ! SHA256SUM=$(command -v "$PWD/o/build/sha256sum" 2>/dev/null); then
|
||||
if ! CC=$(command -v "$CC" 2>/dev/null); then
|
||||
if ! CC=$(command -v cc 2>/dev/null); then
|
||||
if ! CC=$(command -v cosmocc 2>/dev/null); then
|
||||
printf '%s\n' "$0: fatal error: you need to install either sha256sum, cc, or cosmocc" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
mkdir -p o/build || abort
|
||||
SHA256SUM="$PWD/o/build/sha256sum"
|
||||
printf '%s\n' "${CC} -w -O2 -o ${SHA256SUM} build/sha256sum.c" >&2
|
||||
"${CC}" -w -O2 -o "${SHA256SUM}.$$" build/sha256sum.c || abort
|
||||
mv -f "${SHA256SUM}.$$" "${SHA256SUM}" || abort
|
||||
fi
|
||||
sha256sum() {
|
||||
"${SHA256SUM}" "$@"
|
||||
}
|
||||
fi
|
||||
if WGET=$(command -v wget 2>/dev/null); then
|
||||
DOWNLOAD=$WGET
|
||||
DOWNLOAD_ARGS=-O
|
||||
elif CURL=$(command -v curl 2>/dev/null); then
|
||||
DOWNLOAD=$CURL
|
||||
DOWNLOAD_ARGS=-fLo
|
||||
else
|
||||
printf '%s\n' "$0: fatal error: you need to install either wget or curl" >&2
|
||||
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/wget and put it on the system path" >&2
|
||||
abort
|
||||
fi
|
||||
|
||||
# create temporary output directory
|
||||
OLDPWD=$PWD
|
||||
OUTPUT_TMP="${OUTPUT_DIR}.tmp.$$/"
|
||||
mkdir -p "${OUTPUT_TMP}" || abort
|
||||
cd "${OUTPUT_TMP}"
|
||||
die() {
|
||||
cd "${OLDPWD}"
|
||||
rm -rf "${OUTPUT_TMP}"
|
||||
abort
|
||||
}
|
||||
|
||||
# download cosmocc toolchain
|
||||
# multiple urls avoids outages and national firewalls
|
||||
if ! "${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL1}"; then
|
||||
rm -f cosmocc.zip
|
||||
"${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL2}" || die
|
||||
fi
|
||||
printf '%s\n' "${COSMOCC_SHA256SUM} *cosmocc.zip" >cosmocc.zip.sha256sum
|
||||
sha256sum -c cosmocc.zip.sha256sum || die
|
||||
"${UNZIP}" cosmocc.zip || die
|
||||
rm -f cosmocc.zip cosmocc.zip.sha256sum
|
||||
|
||||
# commit output directory
|
||||
cd "${OLDPWD}" || die
|
||||
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
|
||||
+1
-1
@@ -66,7 +66,7 @@ set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
|
||||
# struct WorstSoftwareEver;
|
||||
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
|
||||
|
||||
exec $TAGS \
|
||||
build/run $TAGS \
|
||||
-e \
|
||||
--langmap=c:.c.h \
|
||||
--exclude=libc/nt/struct/imagefileheader.internal.h \
|
||||
|
||||
+8
-8
@@ -6,14 +6,14 @@ if [ -n "$OBJDUMP" ]; then
|
||||
fi
|
||||
|
||||
find_objdump() {
|
||||
if [ -x o/third_party/gcc/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=o/third_party/gcc/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x o/third_party/gcc/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=o/third_party/gcc/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/o/third_party/gcc/bin/$1-linux-musl-objdump"
|
||||
if [ -x .cosmocc/3.2/bin/$1-linux-cosmo-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.2/bin/$1-linux-cosmo-objdump
|
||||
elif [ -x .cosmocc/3.2/bin/$1-linux-musl-objdump ]; then
|
||||
OBJDUMP=.cosmocc/3.2/bin/$1-linux-musl-objdump
|
||||
elif [ -x "$COSMO/.cosmocc/3.2/bin/$1-linux-cosmo-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.2/bin/$1-linux-cosmo-objdump"
|
||||
elif [ -x "$COSMO/.cosmocc/3.2/bin/$1-linux-musl-objdump" ]; then
|
||||
OBJDUMP="$COSMO/.cosmocc/3.2/bin/$1-linux-musl-objdump"
|
||||
else
|
||||
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
|
||||
exit 1
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#!/bin/sh
|
||||
if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
|
||||
if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then
|
||||
make -j8 o/third_party/qemu/qemu-aarch64
|
||||
fi
|
||||
exec o/third_party/qemu/qemu-aarch64 "$@"
|
||||
UNAMEM=$(uname -m)
|
||||
UNAMES=$(uname -s)
|
||||
if [ x"$UNAMES" = x"Darwin" ] && [ x"$UNAMEM" = x"arm64" ]; then
|
||||
exec ape "$@"
|
||||
else
|
||||
exec "$@"
|
||||
fi
|
||||
@@ -0,0 +1,443 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 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 <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// this file should not have dependencies, because everything will be
|
||||
// re-downloaded if the o/tool/sha256sum artifact becomes invalidated
|
||||
|
||||
#define PROG "sha256sum"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: " PROG " [-?hbctw] [PATH...]\n\
|
||||
-h help\n\
|
||||
-c check mode\n\
|
||||
-b binary mode\n\
|
||||
-t textual mode\n\
|
||||
-w warning mode\n"
|
||||
|
||||
#define ROTR(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
|
||||
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
|
||||
#define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
|
||||
#define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
|
||||
|
||||
struct Sha256Ctx {
|
||||
uint8_t data[64];
|
||||
uint32_t datalen;
|
||||
uint64_t bitlen;
|
||||
uint32_t state[8];
|
||||
};
|
||||
|
||||
static const uint32_t kSha256Tab[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, //
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, //
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, //
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, //
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, //
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, //
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, //
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, //
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, //
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, //
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, //
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, //
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, //
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, //
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, //
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, //
|
||||
};
|
||||
|
||||
static bool g_warn;
|
||||
static char g_mode;
|
||||
static bool g_check;
|
||||
static int g_mismatches;
|
||||
|
||||
static void Sha256Transform(uint32_t state[8], const uint8_t data[64]) {
|
||||
unsigned i;
|
||||
uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64];
|
||||
for (i = 0; i < 16; ++i, data += 4) {
|
||||
m[i] = (uint32_t)data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
}
|
||||
for (; i < 64; ++i) {
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + EP1(e) + CH(e, f, g) + kSha256Tab[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
static void Sha256Init(struct Sha256Ctx *ctx) {
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
static void Sha256Update(struct Sha256Ctx *ctx, const uint8_t *data,
|
||||
long size) {
|
||||
long i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Sha256Final(struct Sha256Ctx *ctx, uint8_t *hash) {
|
||||
long i;
|
||||
i = ctx->datalen;
|
||||
ctx->data[i++] = 0x80;
|
||||
if (ctx->datalen < 56) {
|
||||
memset(ctx->data + i, 0, 56 - i);
|
||||
} else {
|
||||
memset(ctx->data + i, 0, 64 - i);
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
Sha256Transform(ctx->state, ctx->data);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static char *FormatUint32(char *p, uint32_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
do {
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
p[i] = '\0';
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
static char *FormatInt32(char *p, int32_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint32_t)x;
|
||||
return FormatUint32(p, x);
|
||||
}
|
||||
|
||||
static size_t StrCat(char *dst, const char *src, size_t dsize) {
|
||||
size_t m, n = dsize;
|
||||
const char *p = dst;
|
||||
const char *q = src;
|
||||
while (n-- != 0 && *dst != '\0') dst++;
|
||||
m = dst - p;
|
||||
n = dsize - m;
|
||||
if (n-- == 0) {
|
||||
return m + strlen(src);
|
||||
}
|
||||
while (*src != '\0') {
|
||||
if (n != 0) {
|
||||
*dst++ = *src;
|
||||
n--;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
return m + (src - q);
|
||||
}
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
g_mode = ' ';
|
||||
while ((opt = getopt(argc, argv, "?hbctw")) != -1) {
|
||||
switch (opt) {
|
||||
case 'w':
|
||||
g_warn = true;
|
||||
break;
|
||||
case 'c':
|
||||
g_check = true;
|
||||
break;
|
||||
case 't':
|
||||
g_mode = ' ';
|
||||
break;
|
||||
case 'b':
|
||||
g_mode = '*';
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
(void)write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
(void)write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Write(int fd, const char *s, ...) {
|
||||
va_list va;
|
||||
char buf[512];
|
||||
buf[0] = 0;
|
||||
va_start(va, s);
|
||||
do {
|
||||
StrCat(buf, s, sizeof(buf));
|
||||
} while ((s = va_arg(va, const char *)));
|
||||
va_end(va);
|
||||
(void)write(fd, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static bool IsModeCharacter(char c) {
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '*':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSupportedPath(const char *path) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
switch (path[i]) {
|
||||
case 0:
|
||||
if (i) return true;
|
||||
// fallthrough
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\\':
|
||||
Write(2, PROG, ": ", path, ": unsupported path\n", NULL);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetDigest(const char *path, FILE *f, uint8_t digest[32]) {
|
||||
size_t got;
|
||||
uint8_t buf[512];
|
||||
struct Sha256Ctx ctx;
|
||||
Sha256Init(&ctx);
|
||||
while ((got = fread(buf, 1, sizeof(buf), f))) {
|
||||
Sha256Update(&ctx, buf, got);
|
||||
}
|
||||
if (ferror(f)) {
|
||||
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
|
||||
return false;
|
||||
}
|
||||
Sha256Final(&ctx, digest);
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *CopyHex(char *s, const void *p, size_t n) {
|
||||
const char *d, *e;
|
||||
for (d = (const char *)p, e = d + n; d < e; ++d) {
|
||||
*s++ = "0123456789abcdef"[(*d >> 4) & 15];
|
||||
*s++ = "0123456789abcdef"[(*d >> 0) & 15];
|
||||
}
|
||||
*s = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
static bool ProduceDigest(const char *path, FILE *f) {
|
||||
char hexdigest[65];
|
||||
char mode[2] = {g_mode};
|
||||
unsigned char digest[32];
|
||||
if (!IsSupportedPath(path)) return false;
|
||||
if (!GetDigest(path, f, digest)) return false;
|
||||
CopyHex(hexdigest, digest, 32);
|
||||
Write(1, hexdigest, " ", mode, path, "\n", NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *Chomp(char *line) {
|
||||
size_t i;
|
||||
if (line) {
|
||||
for (i = strlen(line); i--;) {
|
||||
if (line[i] == '\r' || line[i] == '\n') {
|
||||
line[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
static int HexToInt(int c) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckDigests(const char *path, FILE *f) {
|
||||
FILE *f2;
|
||||
bool k = true;
|
||||
int a, b, i, line;
|
||||
const char *path2, *status;
|
||||
uint8_t wantdigest[32], gotdigest[32];
|
||||
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
|
||||
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
|
||||
if (!*Chomp(buf)) continue;
|
||||
for (p = buf, i = 0; i < 32; ++i) {
|
||||
if ((a = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
if ((b = HexToInt(*p++ & 255)) == -1) goto InvalidLine;
|
||||
wantdigest[i] = a << 4 | b;
|
||||
}
|
||||
if (*p++ != ' ') goto InvalidLine;
|
||||
if (!IsModeCharacter(*p++)) goto InvalidLine;
|
||||
path2 = p;
|
||||
if (!*path2) goto InvalidLine;
|
||||
if (!IsSupportedPath(path2)) continue;
|
||||
if ((f2 = fopen(path2, "rb"))) {
|
||||
if (GetDigest(path2, f2, gotdigest)) {
|
||||
if (!memcmp(wantdigest, gotdigest, 32)) {
|
||||
status = "OK";
|
||||
} else {
|
||||
status = "FAILED";
|
||||
++g_mismatches;
|
||||
k = false;
|
||||
}
|
||||
Write(1, path2, ": ", status, "\n", NULL);
|
||||
} else {
|
||||
k = false;
|
||||
}
|
||||
fclose(f2);
|
||||
} else {
|
||||
Write(2, PROG, ": ", path2, ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
continue;
|
||||
InvalidLine:
|
||||
if (g_warn) {
|
||||
char linestr[12];
|
||||
FormatInt32(linestr, line + 1);
|
||||
Write(2, PROG, ": ", path, ":", linestr, ": ",
|
||||
"improperly formatted checksum line", "\n", NULL);
|
||||
}
|
||||
}
|
||||
if (ferror(f)) {
|
||||
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
static bool Process(const char *path, FILE *f) {
|
||||
if (g_check) {
|
||||
return CheckDigests(path, f);
|
||||
} else {
|
||||
return ProduceDigest(path, f);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
FILE *f;
|
||||
bool k = true;
|
||||
GetOpts(argc, argv);
|
||||
if (optind == argc) {
|
||||
f = stdin;
|
||||
k &= Process("-", f);
|
||||
} else {
|
||||
for (i = optind; i < argc; ++i) {
|
||||
if ((f = fopen(argv[i], "rb"))) {
|
||||
k &= Process(argv[i], f);
|
||||
fclose(f);
|
||||
} else {
|
||||
Write(2, PROG, ": ", argv[i], ": ", strerror(errno), "\n", NULL);
|
||||
k = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g_mismatches) {
|
||||
char ibuf[12];
|
||||
FormatInt32(ibuf, g_mismatches);
|
||||
Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n",
|
||||
NULL);
|
||||
}
|
||||
return !k;
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
@@ -285,7 +285,7 @@ int main(int argc, char *argv[]) {
|
||||
// print all the ips that 0.0.0.0 would bind
|
||||
// Cosmo's GetHostIps() API is much easier than ioctl(SIOCGIFCONF)
|
||||
uint32_t *hostips;
|
||||
for (hostips = _gc(GetHostIps()), i = 0; hostips[i]; ++i) {
|
||||
for (hostips = gc(GetHostIps()), i = 0; hostips[i]; ++i) {
|
||||
kprintf("listening on http://%hhu.%hhu.%hhu.%hhu:%hu\n", hostips[i] >> 24,
|
||||
hostips[i] >> 16, hostips[i] >> 8, hostips[i], PORT);
|
||||
}
|
||||
@@ -339,7 +339,7 @@ int main(int argc, char *argv[]) {
|
||||
unassert(!pthread_attr_setguardsize(&attr, pagesz));
|
||||
unassert(!pthread_attr_setsigmask_np(&attr, &block));
|
||||
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));
|
||||
pthread_t *th = _gc(calloc(threads, sizeof(pthread_t)));
|
||||
pthread_t *th = gc(calloc(threads, sizeof(pthread_t)));
|
||||
for (i = 0; i < threads; ++i) {
|
||||
int rc;
|
||||
++a_workers;
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ void List(const char *path) {
|
||||
if (strcmp(path, ".") == 0) {
|
||||
vpath = "";
|
||||
} else if (!endswith(path, "/")) {
|
||||
vpath = _gc(xasprintf("%s/", path));
|
||||
vpath = gc(xasprintf("%s/", path));
|
||||
} else {
|
||||
vpath = path;
|
||||
}
|
||||
|
||||
+4
-4
@@ -80,10 +80,10 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
|
||||
DescribeFileType(st->st_mode), "owner id", st->st_uid, "group id",
|
||||
st->st_gid, "flags", st->st_flags, "gen", st->st_gen,
|
||||
"device id (if special)", st->st_rdev, "block size", st->st_blksize,
|
||||
"access time", _gc(xiso8601(&st->st_atim)), "modified time",
|
||||
_gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
|
||||
_gc(xiso8601(&st->st_ctim)), "birthtime",
|
||||
_gc(xiso8601(&st->st_birthtim)));
|
||||
"access time", gc(xiso8601(&st->st_atim)), "modified time",
|
||||
gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
|
||||
gc(xiso8601(&st->st_ctim)), "birthtime",
|
||||
gc(xiso8601(&st->st_birthtim)));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alg.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
@@ -33,11 +33,27 @@
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static int Atoi(const char *str) {
|
||||
int c;
|
||||
unsigned x = 0;
|
||||
if (!*str) return -1;
|
||||
while ((c = *str++)) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
x *= 10;
|
||||
x += c - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||
int flags) {
|
||||
|
||||
// handle special files
|
||||
if (startswith(path, "/dev/")) {
|
||||
int fd;
|
||||
if (!strcmp(path + 5, "tty")) {
|
||||
return sys_fstat_nt_special(kFdConsole, st);
|
||||
} else if (!strcmp(path + 5, "null")) {
|
||||
@@ -48,6 +64,8 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
|
||||
return sys_fstat_nt(STDOUT_FILENO, st);
|
||||
} else if (!strcmp(path + 5, "stderr")) {
|
||||
return sys_fstat_nt(STDERR_FILENO, st);
|
||||
} else if (startswith(path + 5, "fd/") && (fd = Atoi(path + 8)) != -1) {
|
||||
return sys_fstat_nt(fd, st);
|
||||
} else {
|
||||
return enoent();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/libgen.h"
|
||||
#include "libc/intrin/getenv.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
@@ -180,10 +181,10 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
empty string to obviate the TOCTOU problem between loader and binary.
|
||||
*/
|
||||
if (!(b = DevFd()) ||
|
||||
0 != strncmp(b, __program_executable_name, StrlenDevFd()) ||
|
||||
!__program_executable_name[StrlenDevFd()] ||
|
||||
__program_executable_name[StrlenDevFd()] == '.' ||
|
||||
strchr(__program_executable_name + StrlenDevFd(), '/')) {
|
||||
0 != strncmp(b, __program_executable_name, (n = StrlenDevFd())) ||
|
||||
!__program_executable_name[n] ||
|
||||
__program_executable_name[n] == '.' ||
|
||||
strchr(__program_executable_name + n, '/')) {
|
||||
goto UseEmpty;
|
||||
}
|
||||
}
|
||||
@@ -224,8 +225,7 @@ static inline void InitProgramExecutableNameImpl(void) {
|
||||
}
|
||||
|
||||
// try argv[0], then argv[0].com, then $_, then $_.com.
|
||||
if (TryPath(__argv[0], 1) ||
|
||||
TryPath(__getenv(__envp, "_").s, 1)) {
|
||||
if (TryPath(__argv[0], 1) || TryPath(__getenv(__envp, "_").s, 1)) {
|
||||
goto UseBuf;
|
||||
}
|
||||
|
||||
@@ -261,5 +261,6 @@ static void InitProgramExecutableName(void) {
|
||||
*/
|
||||
char *GetProgramExecutableName(void) {
|
||||
cosmo_once(&g_prog.once, InitProgramExecutableName);
|
||||
STRACE("GetProgramExecutableName() → %#s", __program_executable_name);
|
||||
return __program_executable_name;
|
||||
}
|
||||
@@ -88,12 +88,14 @@ static ssize_t GetDevUrandom(char *p, size_t n) {
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
fd = sys_openat(AT_FDCWD, "/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
|
||||
if (fd != -1) {
|
||||
rc = sys_read(fd, p, n);
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
#include "libc/errno.h"
|
||||
|
||||
/**
|
||||
* Returns true if process is running under qemu-x86_64 or qemu-x86_64.
|
||||
* Returns true if process is running under qemu-x86_64 or qemu-aarch64.
|
||||
*/
|
||||
int IsQemu(void) {
|
||||
// qemu doesn't validate the advice argument
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
int madvise(void *addr, size_t length, int advice) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(addr, length)) {
|
||||
rc = efault();
|
||||
rc = enomem();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_madvise(addr, length, advice);
|
||||
} else {
|
||||
|
||||
+19
-1
@@ -181,10 +181,25 @@ static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
|
||||
}
|
||||
}
|
||||
|
||||
static int Atoi(const char *str) {
|
||||
int c;
|
||||
unsigned x = 0;
|
||||
if (!*str) return -1;
|
||||
while ((c = *str++)) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
x *= 10;
|
||||
x += c - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
int fd, oldfd;
|
||||
BLOCK_SIGNALS;
|
||||
__fds_lock();
|
||||
if (!(flags & _O_CREAT)) mode = 0;
|
||||
@@ -200,6 +215,9 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDOUT_FILENO);
|
||||
} else if (!strcmp(file + 5, "stderr")) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, STDERR_FILENO);
|
||||
} else if (startswith(file + 5, "fd/") &&
|
||||
(oldfd = Atoi(file + 8)) != -1) {
|
||||
rc = sys_open_nt_dup(fd, flags, mode, oldfd);
|
||||
} else {
|
||||
rc = enoent();
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ int _mkstemp(char *, int);
|
||||
* On newer Linux only (c. 2013) it's possible to turn the anonymous
|
||||
* returned file back into a real file, by doing this:
|
||||
*
|
||||
* linkat(AT_FDCWD, _gc(xasprintf("/proc/self/fd/%d", fd)),
|
||||
* linkat(AT_FDCWD, gc(xasprintf("/proc/self/fd/%d", fd)),
|
||||
* AT_FDCWD, "real.txt", AT_SYMLINK_FOLLOW)
|
||||
*
|
||||
* On the New Technology, temporary files created by this function
|
||||
|
||||
+11
-2
@@ -8,8 +8,13 @@ LIBC_DLOPEN = $(LIBC_DLOPEN_A_DEPS) $(LIBC_DLOPEN_A)
|
||||
LIBC_DLOPEN_A = o/$(MODE)/libc/dlopen/dlopen.a
|
||||
LIBC_DLOPEN_A_FILES := $(wildcard libc/dlopen/*)
|
||||
LIBC_DLOPEN_A_HDRS = $(filter %.h,$(LIBC_DLOPEN_A_FILES))
|
||||
LIBC_DLOPEN_A_SRCS = $(filter %.c,$(LIBC_DLOPEN_A_FILES))
|
||||
LIBC_DLOPEN_A_OBJS = $(LIBC_DLOPEN_A_SRCS:%.c=o/$(MODE)/%.o)
|
||||
LIBC_DLOPEN_A_SRCS_C = $(filter %.c,$(LIBC_DLOPEN_A_FILES))
|
||||
LIBC_DLOPEN_A_SRCS_S = $(filter %.S,$(LIBC_DLOPEN_A_FILES))
|
||||
LIBC_DLOPEN_A_SRCS = $(LIBC_DLOPEN_A_SRCS_C) $(LIBC_DLOPEN_A_SRCS_S)
|
||||
|
||||
LIBC_DLOPEN_A_OBJS = \
|
||||
$(LIBC_DLOPEN_A_SRCS_C:%.c=o/$(MODE)/%.o) \
|
||||
$(LIBC_DLOPEN_A_SRCS_S:%.S=o/$(MODE)/%.o)
|
||||
|
||||
LIBC_DLOPEN_A_CHECKS = \
|
||||
$(LIBC_DLOPEN_A).pkg \
|
||||
@@ -45,6 +50,10 @@ $(LIBC_DLOPEN_A_OBJS): private \
|
||||
-Wframe-larger-than=4096 \
|
||||
-Walloca-larger-than=4096
|
||||
|
||||
# these assembly files are safe to build on aarch64
|
||||
o/$(MODE)/libc/dlopen/foreign_tramp.o: libc/dlopen/foreign_tramp.S
|
||||
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
|
||||
|
||||
LIBC_DLOPEN_LIBS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)))
|
||||
LIBC_DLOPEN_SRCS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_DLOPEN_HDRS = $(foreach x,$(LIBC_DLOPEN_ARTIFACTS),$($(x)_HDRS))
|
||||
|
||||
@@ -20,6 +20,7 @@ int dlclose(void *);
|
||||
char *cosmo_dlerror(void);
|
||||
void *cosmo_dlopen(const char *, int);
|
||||
void *cosmo_dlsym(void *, const char *);
|
||||
void *cosmo_dltramp(void *);
|
||||
int cosmo_dlclose(void *);
|
||||
#endif
|
||||
|
||||
|
||||
+91
-63
@@ -18,6 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
@@ -45,6 +46,7 @@
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/proc/posix_spawn.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/syslib.internal.h"
|
||||
#include "libc/serialize.h"
|
||||
@@ -116,7 +118,7 @@ struct Loaded {
|
||||
Elf64_Phdr ph[25];
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
atomic_uint once;
|
||||
bool is_supported;
|
||||
struct CosmoTib *tib;
|
||||
@@ -125,9 +127,10 @@ static struct {
|
||||
int (*dlclose)(void *);
|
||||
char *(*dlerror)(void);
|
||||
jmp_buf jb;
|
||||
} foreign;
|
||||
} __foreign;
|
||||
|
||||
long __sysv2nt14();
|
||||
long foreign_tramp();
|
||||
|
||||
static _Thread_local char dlerror_buf[128];
|
||||
|
||||
@@ -156,28 +159,6 @@ static int is_file_newer_than(const char *path, const char *other) {
|
||||
return timespec_cmp(st1.st_mtim, st2.st_mtim) > 0;
|
||||
}
|
||||
|
||||
// on system five we sadly need this brutal trampoline
|
||||
// todo(jart): add tls trampoline to sigaction() handlers
|
||||
// todo(jart): morph binary to get tls from host c library
|
||||
static long foreign_tramp(long a, long b, long c, long d, long e,
|
||||
long func(long, long, long, long, long, double,
|
||||
double, double, double, double, double),
|
||||
double A, double B, double C, double D, double E,
|
||||
double F) {
|
||||
long res;
|
||||
BLOCK_SIGNALS;
|
||||
#ifdef __x86_64__
|
||||
struct CosmoTib *tib = __get_tls();
|
||||
__set_tls(foreign.tib);
|
||||
#endif
|
||||
res = func(a, b, c, d, e, A, B, C, D, E, F);
|
||||
#ifdef __x86_64__
|
||||
__set_tls(tib);
|
||||
#endif
|
||||
ALLOW_SIGNALS;
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned elf2prot(unsigned x) {
|
||||
unsigned r = 0;
|
||||
if (x & PF_R) r += PROT_READ;
|
||||
@@ -308,11 +289,11 @@ static long *push_strs(long *sp, char **list, int count) {
|
||||
}
|
||||
|
||||
static wontreturn dontinstrument void foreign_helper(void **p) {
|
||||
foreign.dlopen = p[0];
|
||||
foreign.dlsym = p[1];
|
||||
foreign.dlclose = p[2];
|
||||
foreign.dlerror = p[3];
|
||||
longjmp(foreign.jb, 1);
|
||||
__foreign.dlopen = p[0];
|
||||
__foreign.dlsym = p[1];
|
||||
__foreign.dlclose = p[2];
|
||||
__foreign.dlerror = p[3];
|
||||
_longjmp(__foreign.jb, 1);
|
||||
}
|
||||
|
||||
static dontinline void elf_exec(const char *file, char **envp) {
|
||||
@@ -515,11 +496,13 @@ static uint8_t *movimm(uint8_t p[static 16], int reg, uint64_t val) {
|
||||
static void *foreign_thunk_sysv(void *func) {
|
||||
uint8_t *code, *p;
|
||||
#ifdef __x86_64__
|
||||
// movabs $func,%r9
|
||||
// it is no longer needed
|
||||
if (1) return func;
|
||||
// movabs $func,%rax
|
||||
// movabs $foreign_tramp,%r10
|
||||
// jmp *%r10
|
||||
if (!(p = code = foreign_alloc(23))) return 0; // 10 + 10 + 3 = 23
|
||||
p = movimm(p, 9, (uintptr_t)func);
|
||||
p = movimm(p, 0, (uintptr_t)func);
|
||||
p = movimm(p, 10, (uintptr_t)foreign_tramp);
|
||||
*p++ = 0x41;
|
||||
*p++ = 0xff;
|
||||
@@ -527,7 +510,7 @@ static void *foreign_thunk_sysv(void *func) {
|
||||
#elif defined(__aarch64__)
|
||||
__jit_begin();
|
||||
if ((p = code = foreign_alloc(36))) {
|
||||
p = movimm(p, 5, (uintptr_t)func);
|
||||
p = movimm(p, 8, (uintptr_t)func);
|
||||
p = movimm(p, 10, (uintptr_t)foreign_tramp);
|
||||
*(uint32_t *)p = 0xd61f0140; // br x10
|
||||
__clear_cache(code, p + 4);
|
||||
@@ -636,7 +619,15 @@ static dontinline bool foreign_compile(char exe[hasatleast PATH_MAX]) {
|
||||
}
|
||||
int pid, ws;
|
||||
char *args[] = {
|
||||
"cc", "-pie", "-fPIC", src, "-o", tmp, IsNetbsd() ? 0 : "-ldl", 0,
|
||||
"cc",
|
||||
"-pie",
|
||||
"-fPIC",
|
||||
src,
|
||||
"-o",
|
||||
tmp,
|
||||
IsLinux() ? "-Wl,-z,execstack" : "-DIGNORE",
|
||||
IsNetbsd() ? 0 : "-ldl",
|
||||
0,
|
||||
};
|
||||
errno_t err = posix_spawnp(&pid, args[0], NULL, NULL, args, environ);
|
||||
if (err) {
|
||||
@@ -671,19 +662,19 @@ static bool foreign_setup(void) {
|
||||
#ifdef __x86_64__
|
||||
struct CosmoTib *cosmo_tib = __get_tls();
|
||||
#endif
|
||||
if (!setjmp(foreign.jb)) {
|
||||
if (!setjmp(__foreign.jb)) {
|
||||
elf_exec(exe, environ);
|
||||
return false; // if elf_exec() returns, it failed
|
||||
}
|
||||
#ifdef __x86_64__
|
||||
foreign.tib = __get_tls();
|
||||
__foreign.tib = __get_tls();
|
||||
__set_tls(cosmo_tib);
|
||||
#endif
|
||||
foreign.dlopen = foreign_thunk_sysv(foreign.dlopen);
|
||||
foreign.dlsym = foreign_thunk_sysv(foreign.dlsym);
|
||||
foreign.dlclose = foreign_thunk_sysv(foreign.dlclose);
|
||||
foreign.dlerror = foreign_thunk_sysv(foreign.dlerror);
|
||||
foreign.is_supported = true;
|
||||
__foreign.dlopen = foreign_thunk_sysv(__foreign.dlopen);
|
||||
__foreign.dlsym = foreign_thunk_sysv(__foreign.dlsym);
|
||||
__foreign.dlclose = foreign_thunk_sysv(__foreign.dlclose);
|
||||
__foreign.dlerror = foreign_thunk_sysv(__foreign.dlerror);
|
||||
__foreign.is_supported = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -693,8 +684,8 @@ static void foreign_once(void) {
|
||||
|
||||
static bool foreign_init(void) {
|
||||
bool res;
|
||||
cosmo_once(&foreign.once, foreign_once);
|
||||
if (!(res = foreign.is_supported)) {
|
||||
cosmo_once(&__foreign.once, foreign_once);
|
||||
if (!(res = __foreign.is_supported)) {
|
||||
dlerror_set("dlopen() isn't supported on this platform");
|
||||
}
|
||||
return res;
|
||||
@@ -740,14 +731,13 @@ static void *dlopen_nt(const char *path, int mode) {
|
||||
|
||||
static void *dlsym_nt(void *handle, const char *name) {
|
||||
void *x64_abi_func;
|
||||
void *sysv_abi_func = 0;
|
||||
if ((x64_abi_func = GetProcAddress((uintptr_t)handle, name))) {
|
||||
sysv_abi_func = foreign_thunk_nt(x64_abi_func);
|
||||
return x64_abi_func;
|
||||
} else {
|
||||
dlerror_set("symbol not found: ");
|
||||
strlcat(dlerror_buf, name, sizeof(dlerror_buf));
|
||||
return 0;
|
||||
}
|
||||
return sysv_abi_func;
|
||||
}
|
||||
|
||||
static void *dlopen_silicon(const char *path, int mode) {
|
||||
@@ -792,13 +782,10 @@ static void *dlopen_silicon(const char *path, int mode) {
|
||||
* WARNING: Our API uses a different naming because cosmo_dlopen() lacks
|
||||
* many of the features one would reasonably expect from a UNIX dlopen()
|
||||
* implementation; and we don't want to lead ./configure scripts astray.
|
||||
* You're limited to 5 integral function parameters maximum. Calling an
|
||||
* imported function currently goes much slower than a normal function
|
||||
* call. You can't pass callback function pointers to foreign libraries
|
||||
* safely. Foreign libraries also can't link symbols defined by your
|
||||
* executable; that means using this for high-level language plugins is
|
||||
* completely out of the question. What cosmo_dlopen() can do is help
|
||||
* you talk to GPU and GUI libraries like CUDA and SDL.
|
||||
* Foreign libraries also can't link symbols defined by your executable,
|
||||
* which means using this for high-level language plugins is completely
|
||||
* out of the question. What cosmo_dlopen() can do is help you talk to
|
||||
* GPU and GUI libraries like CUDA and SDL.
|
||||
*
|
||||
* @param mode is a bitmask that can contain:
|
||||
* - `RTLD_LOCAL` (default)
|
||||
@@ -812,6 +799,7 @@ static void *dlopen_silicon(const char *path, int mode) {
|
||||
void *cosmo_dlopen(const char *path, int mode) {
|
||||
void *res;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
if (IsWindows()) {
|
||||
res = dlopen_nt(path, mode);
|
||||
} else if (IsXnuSilicon()) {
|
||||
@@ -824,10 +812,11 @@ void *cosmo_dlopen(const char *path, int mode) {
|
||||
dlerror_set("dlopen() isn't supported on OpenBSD yet");
|
||||
res = 0;
|
||||
} else if (foreign_init()) {
|
||||
res = foreign.dlopen(path, mode);
|
||||
res = __foreign.dlopen(path, mode);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
STRACE("dlopen(%#s, %d) → %p% m", path, mode, res);
|
||||
return res;
|
||||
@@ -836,8 +825,26 @@ void *cosmo_dlopen(const char *path, int mode) {
|
||||
/**
|
||||
* Obtains address of symbol from dynamic shared object.
|
||||
*
|
||||
* On Windows you can only use this to lookup function addresses.
|
||||
* Returned functions are trampolined to conform to System V ABI.
|
||||
* WARNING: You almost always want to say this:
|
||||
*
|
||||
* pFunction = cosmo_dltramp(cosmo_dlsym(dso, "function"));
|
||||
*
|
||||
* That will generate code at runtime for automatically translating to
|
||||
* Microsoft's x64 calling convention when appropriate. However the
|
||||
* automated solution doesn't always work. For example, the prototype:
|
||||
*
|
||||
* void func(int, float);
|
||||
*
|
||||
* Won't be translated correctly, due to the differences in ABI. We're
|
||||
* able to smooth over most of them, but that's just one of several
|
||||
* examples where we can't. A good rule of thumb is:
|
||||
*
|
||||
* - More than four float/double args is problematic
|
||||
* - Having both integral and floating point parameters is bad
|
||||
*
|
||||
* For those kinds of functions, you need to translate the ABI by hand.
|
||||
* This can be accomplished using the GCC `__ms_abi__` attribute, where
|
||||
* you'd have two function pointer types branched upon `IsWindows()`.
|
||||
*
|
||||
* @param handle was opened by dlopen()
|
||||
* @return address of symbol, or NULL w/ dlerror()
|
||||
@@ -847,16 +854,12 @@ void *cosmo_dlsym(void *handle, const char *name) {
|
||||
if (IsWindows()) {
|
||||
func = dlsym_nt(handle, name);
|
||||
} else if (IsXnuSilicon()) {
|
||||
if ((func = __syslib->__dlsym(handle, name))) {
|
||||
func = foreign_thunk_sysv(func);
|
||||
}
|
||||
func = __syslib->__dlsym(handle, name);
|
||||
} else if (IsXnu()) {
|
||||
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
|
||||
func = 0;
|
||||
} else if (foreign_init()) {
|
||||
if ((func = foreign.dlsym(handle, name))) {
|
||||
func = foreign_thunk_sysv(func);
|
||||
}
|
||||
func = __foreign.dlsym(handle, name);
|
||||
} else {
|
||||
func = 0;
|
||||
}
|
||||
@@ -864,6 +867,17 @@ void *cosmo_dlsym(void *handle, const char *name) {
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trampolines foreign function pointer so it can be called safely.
|
||||
*/
|
||||
void *cosmo_dltramp(void *foreign_func) {
|
||||
if (!IsWindows()) {
|
||||
return foreign_thunk_sysv(foreign_func);
|
||||
} else {
|
||||
return foreign_thunk_nt(foreign_func);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes dynamic shared object.
|
||||
*
|
||||
@@ -880,7 +894,7 @@ int cosmo_dlclose(void *handle) {
|
||||
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
|
||||
res = -1;
|
||||
} else if (foreign_init()) {
|
||||
res = foreign.dlclose(handle);
|
||||
res = __foreign.dlclose(handle);
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
@@ -898,7 +912,7 @@ char *cosmo_dlerror(void) {
|
||||
} else if (IsWindows() || IsXnu()) {
|
||||
res = dlerror_buf;
|
||||
} else if (foreign_init()) {
|
||||
res = foreign.dlerror();
|
||||
res = __foreign.dlerror();
|
||||
res = dlerror_set(res);
|
||||
} else {
|
||||
res = dlerror_buf;
|
||||
@@ -906,3 +920,17 @@ char *cosmo_dlerror(void) {
|
||||
STRACE("dlerror() → %#s", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
static textstartup void dlopen_init() {
|
||||
if (IsLinux() || IsFreebsd()) {
|
||||
// switch from %fs to %gs for tls
|
||||
struct CosmoTib *tib = __get_tls();
|
||||
__morph_tls();
|
||||
__set_tls(tib);
|
||||
}
|
||||
}
|
||||
const void *const dlopen_ctor[] initarray = {
|
||||
dlopen_init,
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,236 @@
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│ vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2024 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/macros.internal.h"
|
||||
|
||||
#define SIZE 0x0200
|
||||
#define SKEW 0x10
|
||||
|
||||
foreign_tramp:
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
sub $SIZE,%rsp
|
||||
|
||||
// save vector arguments
|
||||
movdqu %xmm0,-0x10(%rbp)
|
||||
movdqu %xmm1,-0x20(%rbp)
|
||||
movdqu %xmm2,-0x30(%rbp)
|
||||
movdqu %xmm3,-0x40(%rbp)
|
||||
movdqu %xmm4,-0x50(%rbp)
|
||||
movdqu %xmm5,-0x60(%rbp)
|
||||
movdqu %xmm6,-0x70(%rbp)
|
||||
movdqu %xmm7,-0x80(%rbp)
|
||||
|
||||
// save register arguments
|
||||
mov %rdi,-0x88(%rbp)
|
||||
mov %rsi,-0x90(%rbp)
|
||||
mov %rdx,-0x98(%rbp)
|
||||
mov %rcx,-0xa0(%rbp)
|
||||
mov %r8,-0xa8(%rbp)
|
||||
mov %r9,-0xb0(%rbp)
|
||||
|
||||
// save function pointer
|
||||
mov %rax,-0xb8(%rbp)
|
||||
|
||||
// block signals
|
||||
call __sig_block
|
||||
mov %rax,-0xc0(%rbp)
|
||||
|
||||
// switch to foreign tls
|
||||
mov %fs:0,%rax
|
||||
mov %rax,-0xc8(%rbp)
|
||||
mov __foreign+8(%rip),%rdi
|
||||
call __set_tls
|
||||
|
||||
// move stack arguments
|
||||
movdqu SKEW+0x00(%rbp),%xmm0
|
||||
movdqu SKEW+0x10(%rbp),%xmm1
|
||||
movdqu SKEW+0x20(%rbp),%xmm2
|
||||
movdqu SKEW+0x30(%rbp),%xmm3
|
||||
movdqu SKEW+0x40(%rbp),%xmm4
|
||||
movdqu SKEW+0x50(%rbp),%xmm5
|
||||
movdqu SKEW+0x60(%rbp),%xmm6
|
||||
movdqu SKEW+0x70(%rbp),%xmm7
|
||||
movdqu %xmm0,-SIZE+0x00(%rbp)
|
||||
movdqu %xmm1,-SIZE+0x10(%rbp)
|
||||
movdqu %xmm2,-SIZE+0x20(%rbp)
|
||||
movdqu %xmm3,-SIZE+0x30(%rbp)
|
||||
movdqu %xmm4,-SIZE+0x40(%rbp)
|
||||
movdqu %xmm5,-SIZE+0x50(%rbp)
|
||||
movdqu %xmm6,-SIZE+0x60(%rbp)
|
||||
movdqu %xmm7,-SIZE+0x70(%rbp)
|
||||
movdqu SKEW+0x80(%rbp),%xmm0
|
||||
movdqu SKEW+0x90(%rbp),%xmm1
|
||||
movdqu SKEW+0xa0(%rbp),%xmm2
|
||||
movdqu SKEW+0xb0(%rbp),%xmm3
|
||||
movdqu SKEW+0xc0(%rbp),%xmm4
|
||||
movdqu SKEW+0xd0(%rbp),%xmm5
|
||||
movdqu SKEW+0xe0(%rbp),%xmm6
|
||||
movdqu SKEW+0xf0(%rbp),%xmm7
|
||||
movdqu %xmm0,-SIZE+0x80(%rbp)
|
||||
movdqu %xmm1,-SIZE+0x90(%rbp)
|
||||
movdqu %xmm2,-SIZE+0xa0(%rbp)
|
||||
movdqu %xmm3,-SIZE+0xb0(%rbp)
|
||||
movdqu %xmm4,-SIZE+0xc0(%rbp)
|
||||
movdqu %xmm5,-SIZE+0xd0(%rbp)
|
||||
movdqu %xmm6,-SIZE+0xe0(%rbp)
|
||||
movdqu %xmm7,-SIZE+0xf0(%rbp)
|
||||
|
||||
// restore vector arguments
|
||||
movdqu -0x10(%rbp),%xmm0
|
||||
movdqu -0x20(%rbp),%xmm1
|
||||
movdqu -0x30(%rbp),%xmm2
|
||||
movdqu -0x40(%rbp),%xmm3
|
||||
movdqu -0x50(%rbp),%xmm4
|
||||
movdqu -0x60(%rbp),%xmm5
|
||||
movdqu -0x70(%rbp),%xmm6
|
||||
movdqu -0x80(%rbp),%xmm7
|
||||
|
||||
// restore register arguments
|
||||
mov -0x88(%rbp),%rdi
|
||||
mov -0x90(%rbp),%rsi
|
||||
mov -0x98(%rbp),%rdx
|
||||
mov -0xa0(%rbp),%rcx
|
||||
mov -0xa8(%rbp),%r8
|
||||
mov -0xb0(%rbp),%r9
|
||||
|
||||
// call function
|
||||
mov -0xb8(%rbp),%rax
|
||||
call *%rax
|
||||
|
||||
// save function result
|
||||
movdqu %xmm0,-0x10(%rbp)
|
||||
movdqu %xmm1,-0x20(%rbp)
|
||||
mov %rax,-0x28(%rbp)
|
||||
mov %rdx,-0x30(%rbp)
|
||||
|
||||
// restore tls
|
||||
mov -0xc8(%rbp),%rdi
|
||||
call __set_tls
|
||||
|
||||
// unblock signals
|
||||
mov -0xc0(%rbp),%rdi
|
||||
call __sig_unblock
|
||||
|
||||
// restore function result
|
||||
mov -0x28(%rbp),%rax
|
||||
mov -0x30(%rbp),%rdx
|
||||
movdqu -0x10(%rbp),%xmm0
|
||||
movdqu -0x20(%rbp),%xmm1
|
||||
|
||||
add $SIZE,%rsp
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
stp x29,x30,[sp,-0x100]!
|
||||
mov x29,sp
|
||||
|
||||
// save vector arguments
|
||||
stp q0,q1,[sp,0x10]
|
||||
stp q2,q3,[sp,0x30]
|
||||
stp q4,q5,[sp,0x50]
|
||||
stp q6,q7,[sp,0x70]
|
||||
|
||||
// save register arguments
|
||||
stp x0,x1,[sp,0x90]
|
||||
stp x2,x3,[sp,0xa0]
|
||||
stp x4,x5,[sp,0xb0]
|
||||
stp x6,x7,[sp,0xc0]
|
||||
|
||||
// save function pointer
|
||||
str x8,[sp,0xd0]
|
||||
|
||||
// block signals
|
||||
bl __sig_block
|
||||
str x0,[sp,0xd8]
|
||||
|
||||
// move stack arguments
|
||||
sub sp,sp,#0x100
|
||||
ldp q0,q1,[sp,SIZE+0x00]
|
||||
ldp q2,q3,[sp,SIZE+0x20]
|
||||
ldp q4,q5,[sp,SIZE+0x40]
|
||||
ldp q6,q7,[sp,SIZE+0x60]
|
||||
stp q0,q1,[sp,0x00]
|
||||
stp q2,q3,[sp,0x20]
|
||||
stp q4,q5,[sp,0x40]
|
||||
stp q6,q7,[sp,0x60]
|
||||
ldp q0,q1,[sp,SIZE+0x80]
|
||||
ldp q2,q3,[sp,SIZE+0xa0]
|
||||
ldp q4,q5,[sp,SIZE+0xc0]
|
||||
ldp q6,q7,[sp,SIZE+0xe0]
|
||||
stp q0,q1,[sp,0x80]
|
||||
stp q2,q3,[sp,0xa0]
|
||||
stp q4,q5,[sp,0xc0]
|
||||
stp q6,q7,[sp,0xe0]
|
||||
|
||||
// restore vector arguments
|
||||
ldp q0,q1,[sp,0x100+0x10]
|
||||
ldp q2,q3,[sp,0x100+0x30]
|
||||
ldp q4,q5,[sp,0x100+0x50]
|
||||
ldp q6,q7,[sp,0x100+0x70]
|
||||
|
||||
// restore register arguments
|
||||
ldp x0,x1,[sp,0x100+0x90]
|
||||
ldp x2,x3,[sp,0x100+0xa0]
|
||||
ldp x4,x5,[sp,0x100+0xb0]
|
||||
ldp x6,x7,[sp,0x100+0xc0]
|
||||
|
||||
// call function
|
||||
ldr x8,[sp,0x100+0xd0]
|
||||
blr x8
|
||||
add sp,sp,#0x100
|
||||
|
||||
// save vector results
|
||||
stp q0,q1,[sp,0x10]
|
||||
stp q2,q3,[sp,0x30]
|
||||
stp q4,q5,[sp,0x50]
|
||||
stp q6,q7,[sp,0x70]
|
||||
|
||||
// save register results
|
||||
stp x0,x1,[sp,0x90]
|
||||
stp x2,x3,[sp,0xa0]
|
||||
stp x4,x5,[sp,0xb0]
|
||||
stp x6,x7,[sp,0xc0]
|
||||
|
||||
// unblock signals
|
||||
ldr x0,[sp,0xd8]
|
||||
bl __sig_unblock
|
||||
|
||||
// restore vector results
|
||||
ldp q0,q1,[sp,0x10]
|
||||
ldp q2,q3,[sp,0x30]
|
||||
ldp q4,q5,[sp,0x50]
|
||||
ldp q6,q7,[sp,0x70]
|
||||
|
||||
// restore register results
|
||||
ldp x0,x1,[sp,0x90]
|
||||
ldp x2,x3,[sp,0xa0]
|
||||
ldp x4,x5,[sp,0xb0]
|
||||
ldp x6,x7,[sp,0xc0]
|
||||
|
||||
ldp x29,x30,[sp],0x100
|
||||
ret
|
||||
|
||||
#endif // __x86_64__
|
||||
|
||||
.endfn foreign_tramp,globl
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#define __COSMOPOLITAN_MAJOR__ 3
|
||||
#define __COSMOPOLITAN_MINOR__ 2
|
||||
#define __COSMOPOLITAN_PATCH__ 0
|
||||
#define __COSMOPOLITAN_PATCH__ 4
|
||||
#define __COSMOPOLITAN__ \
|
||||
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
|
||||
__COSMOPOLITAN_PATCH__)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describebacktrace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
@@ -27,3 +29,14 @@ dontinstrument void __stracef(const char *fmt, ...) {
|
||||
kvprintf(fmt, v);
|
||||
va_end(v);
|
||||
}
|
||||
|
||||
#if IsModeDbg()
|
||||
void report_cancellation_point(void) {
|
||||
kprintf("error: cancelable raw system call not annotated in wrapper\n"
|
||||
"choice #1 use BLOCK_CANCELATION / ALLOW_CANCELATION\n"
|
||||
"choice #2 use BEGIN_CANCELATION_POINT / END_CANCELATION_POINT\n"
|
||||
"backtrace: %s\n",
|
||||
DescribeBacktrace(__builtin_frame_address(0)));
|
||||
__builtin_trap();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│ vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2024 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/macros.internal.h"
|
||||
|
||||
// we can't allow ftrace here since ftrace needs tls
|
||||
sys_set_tls:
|
||||
mov __NR_set_tls(%rip),%eax
|
||||
syscall
|
||||
ret
|
||||
.endfn sys_set_tls,globl
|
||||
@@ -1,5 +1,5 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
@@ -16,8 +16,6 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/cxaatexit.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
int __cxa_thread_atexit(void *fun, void *arg, void *dso_symbol) {
|
||||
return __cxa_thread_atexit_impl(fun, arg, dso_symbol);
|
||||
}
|
||||
char __tls_morphed;
|
||||
@@ -25,9 +25,9 @@
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define ADDR2LINE "o/third_party/gcc/bin/x86_64-linux-musl-addr2line"
|
||||
#define ADDR2LINE "cosmocc/3.2/bin/x86_64-linux-musl-addr2line"
|
||||
#elif defined(__aarch64__)
|
||||
#define ADDR2LINE "o/third_party/gcc/bin/aarch64-linux-musl-addr2line"
|
||||
#define ADDR2LINE "cosmocc/3.2/bin/aarch64-linux-musl-addr2line"
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
#include "libc/macros.internal.h"
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
__funline unsigned long __strlen(const char *s) {
|
||||
forceinline unsigned long __strlen(const char *s) {
|
||||
unsigned long n = 0;
|
||||
while (*s++) ++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
__funline int __strcmp(const char *l, const char *r) {
|
||||
forceinline int __strcmp(const char *l, const char *r) {
|
||||
size_t i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
__funline char *__stpcpy(char *d, const char *s) {
|
||||
forceinline char *__stpcpy(char *d, const char *s) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
if (!(d[i] = s[i])) {
|
||||
@@ -24,7 +24,7 @@ __funline char *__stpcpy(char *d, const char *s) {
|
||||
}
|
||||
}
|
||||
|
||||
__funline void *__repstosb(void *di, char al, size_t cx) {
|
||||
forceinline void *__repstosb(void *di, char al, size_t cx) {
|
||||
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
asm("rep stosb"
|
||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
@@ -40,7 +40,7 @@ __funline void *__repstosb(void *di, char al, size_t cx) {
|
||||
#endif
|
||||
}
|
||||
|
||||
__funline void *__repmovsb(void *di, const void *si, size_t cx) {
|
||||
forceinline void *__repmovsb(void *di, const void *si, size_t cx) {
|
||||
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
asm("rep movsb"
|
||||
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
@@ -57,7 +57,7 @@ __funline void *__repmovsb(void *di, const void *si, size_t cx) {
|
||||
#endif
|
||||
}
|
||||
|
||||
__funline void *__mempcpy(void *d, const void *s, size_t n) {
|
||||
forceinline void *__mempcpy(void *d, const void *s, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
((char *)d)[i] = ((const char *)s)[i];
|
||||
@@ -66,7 +66,7 @@ __funline void *__mempcpy(void *d, const void *s, size_t n) {
|
||||
return (char *)d + n;
|
||||
}
|
||||
|
||||
__funline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
|
||||
forceinline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
|
||||
char t;
|
||||
size_t i, a, b;
|
||||
i = 0;
|
||||
@@ -85,22 +85,22 @@ __funline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
|
||||
return p + i;
|
||||
}
|
||||
|
||||
__funline char *__intcpy(char p[hasatleast 21], int64_t x) {
|
||||
forceinline char *__intcpy(char p[hasatleast 21], int64_t x) {
|
||||
if (x < 0) *p++ = '-', x = -(uint64_t)x;
|
||||
return __uintcpy(p, x);
|
||||
}
|
||||
|
||||
__funline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
|
||||
forceinline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
|
||||
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
__funline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
|
||||
forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
|
||||
return __fixcpy(p, x, ROUNDUP(x ? (__builtin_clzll(x) ^ 63) + 1 : 1, 4));
|
||||
}
|
||||
|
||||
__funline const void *__memchr(const void *s, unsigned char c, size_t n) {
|
||||
forceinline const void *__memchr(const void *s, unsigned char c, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (((const unsigned char *)s)[i] == c) {
|
||||
@@ -110,7 +110,7 @@ __funline const void *__memchr(const void *s, unsigned char c, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__funline char *__strstr(const char *haystack, const char *needle) {
|
||||
forceinline char *__strstr(const char *haystack, const char *needle) {
|
||||
size_t i;
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
@@ -123,8 +123,8 @@ __funline char *__strstr(const char *haystack, const char *needle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__funline char16_t *__strstr16(const char16_t *haystack,
|
||||
const char16_t *needle) {
|
||||
forceinline char16_t *__strstr16(const char16_t *haystack,
|
||||
const char16_t *needle) {
|
||||
size_t i;
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
@@ -137,21 +137,21 @@ __funline char16_t *__strstr16(const char16_t *haystack,
|
||||
return 0;
|
||||
}
|
||||
|
||||
__funline const char *__strchr(const char *s, unsigned char c) {
|
||||
forceinline const char *__strchr(const char *s, unsigned char c) {
|
||||
for (;; ++s) {
|
||||
if ((*s & 255) == c) return s;
|
||||
if (!*s) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
__funline unsigned long __atoul(const char *p) {
|
||||
forceinline unsigned long __atoul(const char *p) {
|
||||
int c;
|
||||
unsigned long x = 0;
|
||||
while ('0' <= (c = *p++) && c <= '9') x *= 10, x += c - '0';
|
||||
return x;
|
||||
}
|
||||
|
||||
__funline long __atol(const char *p) {
|
||||
forceinline long __atol(const char *p) {
|
||||
int s = *p;
|
||||
unsigned long x;
|
||||
if (s == '-' || s == '+') ++p;
|
||||
@@ -160,7 +160,7 @@ __funline long __atol(const char *p) {
|
||||
return x;
|
||||
}
|
||||
|
||||
__funline void *__memset(void *a, int c, unsigned long n) {
|
||||
forceinline void *__memset(void *a, int c, unsigned long n) {
|
||||
char *d = a;
|
||||
unsigned long i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
@@ -170,7 +170,7 @@ __funline void *__memset(void *a, int c, unsigned long n) {
|
||||
return d;
|
||||
}
|
||||
|
||||
__funline void *__memcpy(void *a, const void *b, unsigned long n) {
|
||||
forceinline void *__memcpy(void *a, const void *b, unsigned long n) {
|
||||
char *d = a;
|
||||
unsigned long i;
|
||||
const char *s = b;
|
||||
@@ -181,7 +181,7 @@ __funline void *__memcpy(void *a, const void *b, unsigned long n) {
|
||||
return d;
|
||||
}
|
||||
|
||||
__funline void *__memmove(void *a, const void *b, unsigned long n) {
|
||||
forceinline void *__memmove(void *a, const void *b, unsigned long n) {
|
||||
char *d = a;
|
||||
unsigned long i;
|
||||
const char *s = b;
|
||||
|
||||
@@ -95,6 +95,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||
flockfile(f);
|
||||
strace_enabled(-1);
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
|
||||
// We display TIMESTAMP.MICROS normally. However, when we log multiple
|
||||
// times in the same second, we display TIMESTAMP+DELTAMICROS instead.
|
||||
@@ -136,6 +137,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
|
||||
_Exit(22);
|
||||
}
|
||||
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
strace_enabled(+1);
|
||||
funlockfile(f);
|
||||
|
||||
+2
-47
@@ -39,7 +39,7 @@ static void TeardownGc(void) {
|
||||
if (__tls_enabled) {
|
||||
t = __get_tls();
|
||||
if ((g = t->tib_garbages)) {
|
||||
// exit() currently doesn't use _gclongjmp() like pthread_exit()
|
||||
// exit() currently doesn't use gclongjmp() like pthread_exit()
|
||||
// so we need to run the deferred functions manually.
|
||||
while (g->i) {
|
||||
--g->i;
|
||||
@@ -88,7 +88,7 @@ static void DeferFunction(struct StackFrame *frame, void *fn, void *arg) {
|
||||
frame->addr = (intptr_t)__gc;
|
||||
}
|
||||
|
||||
// the gnu extension macros for _gc / _defer point here
|
||||
// the gnu extension macros for gc / defer point here
|
||||
void __defer(void *rbp, void *fn, void *arg) {
|
||||
struct StackFrame *f, *frame = rbp;
|
||||
f = __builtin_frame_address(0);
|
||||
@@ -96,48 +96,3 @@ void __defer(void *rbp, void *fn, void *arg) {
|
||||
unassert(PointerNotOwnedByParentStackFrame(f, frame, arg));
|
||||
DeferFunction(frame, fn, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory when function returns.
|
||||
*
|
||||
* This garbage collector overwrites the return address on the stack so
|
||||
* that the RET instruction calls a trampoline which calls free(). It's
|
||||
* loosely analogous to Go's defer keyword rather than a true cycle gc.
|
||||
*
|
||||
* const char *s = _gc(strdup("hello"));
|
||||
* puts(s);
|
||||
*
|
||||
* This macro is equivalent to:
|
||||
*
|
||||
* _defer(free, ptr)
|
||||
*
|
||||
* @warning do not return a gc()'d pointer
|
||||
* @warning do not realloc() with gc()'d pointer
|
||||
* @warning be careful about static keyword due to impact of inlining
|
||||
* @note you should use -fno-omit-frame-pointer
|
||||
*/
|
||||
void *(_gc)(void *thing) {
|
||||
struct StackFrame *frame;
|
||||
frame = __builtin_frame_address(0);
|
||||
DeferFunction(frame->next, _weakfree, thing);
|
||||
return thing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls fn(arg) when function returns.
|
||||
*
|
||||
* This garbage collector overwrites the return address on the stack so
|
||||
* that the RET instruction calls a trampoline which calls free(). It's
|
||||
* loosely analogous to Go's defer keyword rather than a true cycle gc.
|
||||
*
|
||||
* @warning do not return a gc()'d pointer
|
||||
* @warning do not realloc() with gc()'d pointer
|
||||
* @warning be careful about static keyword due to impact of inlining
|
||||
* @note you should use -fno-omit-frame-pointer
|
||||
*/
|
||||
void *(_defer)(void *fn, void *arg) {
|
||||
struct StackFrame *frame;
|
||||
frame = __builtin_frame_address(0);
|
||||
DeferFunction(frame->next, fn, arg);
|
||||
return arg;
|
||||
}
|
||||
+15
-17
@@ -1,25 +1,23 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_MEM_GC_H_
|
||||
#define COSMOPOLITAN_LIBC_MEM_GC_H_
|
||||
#ifdef _COSMO_SOURCE
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void *_gc(void *);
|
||||
void *_defer(void *, void *);
|
||||
void __defer(void *, void *, void *);
|
||||
void _gclongjmp(void *, int) dontthrow wontreturn;
|
||||
void _gc_free(void *);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define _gc(THING) _defer((void *)_gc_free, (void *)(THING))
|
||||
#define _defer(FN, ARG) \
|
||||
({ \
|
||||
autotype(ARG) Arg = (ARG); \
|
||||
/* prevent weird opts like tail call */ \
|
||||
asm volatile("" : "+g"(Arg) : : "memory"); \
|
||||
__defer(__builtin_frame_address(0), FN, Arg); \
|
||||
asm volatile("" : "+g"(Arg) : : "memory"); \
|
||||
Arg; \
|
||||
void _gc_free(void *) libcesque;
|
||||
void __defer(void *, void *, void *) libcesque;
|
||||
void gclongjmp(void *, int) libcesque wontreturn;
|
||||
#define gc(THING) defer((void *)_gc_free, (void *)(THING))
|
||||
#define _gc(THING) defer((void *)_gc_free, (void *)(THING))
|
||||
#define defer(FN, ARG) \
|
||||
({ \
|
||||
autotype(ARG) Arg = (ARG); \
|
||||
/* prevent weird opts like tail call */ \
|
||||
__asm__ volatile("" : "+g"(Arg) : : "memory"); \
|
||||
__defer(__builtin_frame_address(0), FN, Arg); \
|
||||
__asm__ volatile("" : "+g"(Arg) : : "memory"); \
|
||||
Arg; \
|
||||
})
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* _COSMO_SOURCE */
|
||||
#endif /* COSMOPOLITAN_LIBC_MEM_GC_H_ */
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_
|
||||
#include "libc/mem/gc.h"
|
||||
|
||||
#define gc(THING) _gc(THING)
|
||||
#define defer(FN, ARG) _defer(FN, ARG)
|
||||
#define gclongjmp(JB, ARG) _gclongjmp(JB, ARG)
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_ */
|
||||
@@ -30,7 +30,7 @@
|
||||
// @see examples/ctrlc.c
|
||||
// @noreturn
|
||||
.ftrace1
|
||||
_gclongjmp:
|
||||
gclongjmp:
|
||||
.ftrace2
|
||||
#ifdef __x86_64__
|
||||
push %rbp
|
||||
@@ -65,4 +65,4 @@ _gclongjmp:
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif /* __x86_64__ */
|
||||
.endfn _gclongjmp,globl
|
||||
.endfn gclongjmp,globl
|
||||
@@ -23,11 +23,12 @@
|
||||
// @param rdi points to the jmp_buf
|
||||
// @param esi is returned by setjmp() invocation (coerced nonzero)
|
||||
// @noreturn
|
||||
// @see _gclongjmp()
|
||||
// @see gclongjmp()
|
||||
// @see siglongjmp()
|
||||
.ftrace1
|
||||
longjmp:
|
||||
.ftrace2
|
||||
_longjmp:
|
||||
#ifdef __x86_64__
|
||||
mov %esi,%eax
|
||||
test %eax,%eax
|
||||
@@ -42,13 +43,13 @@ longjmp:
|
||||
mov 48(%rdi),%r15
|
||||
jmp *56(%rdi)
|
||||
#elif defined(__aarch64__)
|
||||
ldp x19,x20,[x0,#0]
|
||||
ldp x21,x22,[x0,#16]
|
||||
ldp x29,x30,[x0,#0]
|
||||
ldp x2,x22,[x0,#16]
|
||||
ldp x23,x24,[x0,#32]
|
||||
ldp x25,x26,[x0,#48]
|
||||
ldp x27,x28,[x0,#64]
|
||||
ldp x29,x30,[x0,#80]
|
||||
ldr x2,[x0,#104]
|
||||
ldp x19,x20,[x0,#80]
|
||||
ldr x21,[x0,#104]
|
||||
mov sp,x2
|
||||
ldp d8 ,d9,[x0,#112]
|
||||
ldp d10,d11,[x0,#128]
|
||||
@@ -61,5 +62,5 @@ longjmp:
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
.endfn longjmp,globl
|
||||
.alias longjmp,_longjmp
|
||||
.endfn _longjmp,globl
|
||||
.alias longjmp,siglongjmp
|
||||
@@ -25,10 +25,11 @@
|
||||
// @returnstwice
|
||||
// @assume system five nexgen32e abi conformant
|
||||
// @note code built w/ microsoft abi compiler can't call this
|
||||
// @see longjmp(), _gclongjmp()
|
||||
// @see longjmp(), gclongjmp()
|
||||
.ftrace1
|
||||
setjmp:
|
||||
.ftrace2
|
||||
_setjmp:
|
||||
#ifdef __x86_64__
|
||||
lea 8(%rsp),%rax
|
||||
mov %rax,(%rdi)
|
||||
@@ -43,14 +44,14 @@ setjmp:
|
||||
xor %eax,%eax
|
||||
ret
|
||||
#elif defined(__aarch64__)
|
||||
stp x19,x20,[x0,#0]
|
||||
stp x21,x22,[x0,#16]
|
||||
mov x2,sp
|
||||
stp x29,x30,[x0,#0]
|
||||
stp x2,x22,[x0,#16]
|
||||
stp x23,x24,[x0,#32]
|
||||
stp x25,x26,[x0,#48]
|
||||
stp x27,x28,[x0,#64]
|
||||
stp x29,x30,[x0,#80]
|
||||
mov x2,sp
|
||||
str x2,[x0,#104]
|
||||
stp x19,x20,[x0,#80]
|
||||
str x21,[x0,#104]
|
||||
stp d8,d9,[x0,#112]
|
||||
stp d10,d11,[x0,#128]
|
||||
stp d12,d13,[x0,#144]
|
||||
@@ -60,5 +61,5 @@ setjmp:
|
||||
#else
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
.endfn _setjmp,globl
|
||||
.endfn setjmp,globl
|
||||
.alias setjmp,_setjmp
|
||||
@@ -58,6 +58,7 @@ static bool IsApeFile(const char *path) {
|
||||
} else {
|
||||
bool res = false;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
int fd;
|
||||
char buf[8];
|
||||
int flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC;
|
||||
@@ -65,6 +66,7 @@ static bool IsApeFile(const char *path) {
|
||||
res = sys_pread(fd, buf, 8, 0, 0) == 8 && IsApeLoadable(buf);
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
return res;
|
||||
}
|
||||
|
||||
+6
-6
@@ -201,14 +201,14 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
}
|
||||
if (!__isfdkind(fd, kFdZip)) {
|
||||
bool memfdReq;
|
||||
BEGIN_CANCELATION_POINT;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
memfdReq = ((rc = fcntl(fd, F_GETFD)) != -1) && (rc & FD_CLOEXEC) &&
|
||||
IsAPEFd(fd);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
END_CANCELATION_POINT;
|
||||
if (rc == -1) {
|
||||
break;
|
||||
} else if (!memfdReq) {
|
||||
@@ -221,13 +221,13 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
}
|
||||
int newfd;
|
||||
char *path = alloca(PATH_MAX);
|
||||
BEGIN_CANCELATION_POINT;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
newfd = fd_to_mem_fd(fd, path);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
END_CANCELATION_POINT;
|
||||
if (newfd == -1) {
|
||||
break;
|
||||
}
|
||||
@@ -242,13 +242,13 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
if (!savedErr) {
|
||||
savedErr = errno;
|
||||
}
|
||||
BEGIN_CANCELATION_POINT;
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
strace_enabled(-1);
|
||||
close(newfd);
|
||||
strace_enabled(+1);
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
END_CANCELATION_POINT;
|
||||
} while (0);
|
||||
if (savedErr) {
|
||||
errno = savedErr;
|
||||
|
||||
+39
-11
@@ -48,6 +48,7 @@
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/stdalign.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/arch.h"
|
||||
#include "libc/sysv/consts/clone.h"
|
||||
#include "libc/sysv/consts/futex.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
@@ -63,6 +64,9 @@
|
||||
#define kMaxThreadIds 32768
|
||||
#define kMinThreadId 262144
|
||||
|
||||
#define AMD64_SET_FSBASE 129
|
||||
#define AMD64_SET_GSBASE 131
|
||||
|
||||
#define __NR_thr_new 455
|
||||
#define __NR_clone_linux 56
|
||||
#define __NR__lwp_create 309
|
||||
@@ -90,6 +94,7 @@ struct CloneArgs {
|
||||
void *arg;
|
||||
};
|
||||
|
||||
int sys_set_tls();
|
||||
int __stack_call(void *, int, long, long, int (*)(void *, int), void *);
|
||||
|
||||
static struct CloneArgs *AllocateCloneArgs(char *stk, size_t stksz) {
|
||||
@@ -390,14 +395,14 @@ static int CloneNetbsd(int (*func)(void *, int), char *stk, size_t stksz,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// FREE BESIYATA DISHMAYA
|
||||
|
||||
void bone(struct CloneArgs *wt) {
|
||||
*wt->ztid = 0;
|
||||
}
|
||||
|
||||
static wontreturn void FreebsdThreadMain(void *p) {
|
||||
struct CloneArgs *wt = p;
|
||||
#ifdef __aarch64__
|
||||
asm volatile("mov\tx28,%0" : /* no outputs */ : "r"(wt->tls));
|
||||
#elif defined(__x86_64__)
|
||||
if (__tls_morphed) {
|
||||
sys_set_tls(AMD64_SET_GSBASE, wt->tls);
|
||||
}
|
||||
#endif
|
||||
*wt->ctid = wt->tid;
|
||||
wt->func(wt->arg, wt->tid);
|
||||
@@ -534,6 +539,13 @@ static errno_t CloneSilicon(int (*fn)(void *, int), char *stk, size_t stksz,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GNU/SYSTEMD
|
||||
|
||||
struct LinuxCloneArgs {
|
||||
int (*func)(void *, int);
|
||||
void *arg;
|
||||
char *tls;
|
||||
int ctid;
|
||||
};
|
||||
|
||||
int sys_clone_linux(int flags, // rdi
|
||||
long sp, // rsi
|
||||
int *ptid, // rdx
|
||||
@@ -542,24 +554,40 @@ int sys_clone_linux(int flags, // rdi
|
||||
void *func, // r9
|
||||
void *arg); // 8(rsp)
|
||||
|
||||
static int LinuxThreadEntry(void *arg, int tid) {
|
||||
struct LinuxCloneArgs *wt = arg;
|
||||
sys_set_tls(ARCH_SET_GS, wt->tls);
|
||||
return wt->func(wt->arg, tid);
|
||||
}
|
||||
|
||||
static int CloneLinux(int (*func)(void *arg, int rc), char *stk, size_t stksz,
|
||||
int flags, void *arg, void *tls, int *ptid, int *ctid) {
|
||||
int rc;
|
||||
long sp;
|
||||
struct LinuxCloneArgs *wt;
|
||||
sp = (intptr_t)(stk + stksz);
|
||||
if (~flags & CLONE_CHILD_SETTID) {
|
||||
flags |= CLONE_CHILD_SETTID;
|
||||
sp -= sizeof(int);
|
||||
sp = sp & -alignof(int);
|
||||
ctid = (int *)sp;
|
||||
sp -= 8; // experiment
|
||||
}
|
||||
sp -= sizeof(struct LinuxCloneArgs);
|
||||
// align the stack
|
||||
#ifdef __aarch64__
|
||||
sp = sp & -128; // for kernel 4.6 and earlier
|
||||
#else
|
||||
sp = sp & -16;
|
||||
#endif
|
||||
wt = (struct LinuxCloneArgs *)sp;
|
||||
#ifdef __x86_64__
|
||||
if ((flags & CLONE_SETTLS) && __tls_morphed) {
|
||||
flags &= ~CLONE_SETTLS;
|
||||
wt->arg = arg;
|
||||
wt->tls = tls;
|
||||
wt->func = func;
|
||||
func = LinuxThreadEntry;
|
||||
arg = wt;
|
||||
}
|
||||
#endif
|
||||
if (~flags & CLONE_CHILD_SETTID) {
|
||||
flags |= CLONE_CHILD_SETTID;
|
||||
ctid = &wt->ctid;
|
||||
}
|
||||
if ((rc = sys_clone_linux(flags, sp, ptid, ctid, tls, func, arg)) >= 0) {
|
||||
// clone() is documented as setting ptid before return
|
||||
return 0;
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "libc/atomic.h"
|
||||
#include "libc/cxxabi.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/limits.h"
|
||||
#include "third_party/nsync/futex.internal.h"
|
||||
|
||||
// This file contains C++ ABI support functions for one time
|
||||
// constructors as defined in the "Run-time ABI for the ARM Architecture"
|
||||
// section 4.4.2
|
||||
//
|
||||
// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for
|
||||
// one time construction:
|
||||
//
|
||||
// ARM C++ ABI defines the LSB of guard variable should be tested
|
||||
// by compiler-generated code before calling __cxa_guard_acquire et al.
|
||||
//
|
||||
// The Itanium/x86 C++ ABI defines the low-order _byte_ should be
|
||||
// tested instead.
|
||||
//
|
||||
// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit
|
||||
// aligned for x86.
|
||||
//
|
||||
// Reference documentation:
|
||||
//
|
||||
// section 3.2.3 of ARM IHI 0041C (for ARM)
|
||||
// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86).
|
||||
//
|
||||
// There is no C++ ABI available for other ARCH. But the gcc source
|
||||
// shows all other ARCH follow the definition of Itanium/x86 C++ ABI.
|
||||
|
||||
// The Itanium/x86 C++ ABI (used by all architectures that aren't ARM32)
|
||||
// mandates guard variables are 64-bit aligned, 64-bit values. The least
|
||||
// significant byte is tested by the compiler-generated code before it's
|
||||
// calling __cxa_guard_acquire.
|
||||
union CxaGuardValue {
|
||||
atomic_int state;
|
||||
int64_t aligner;
|
||||
};
|
||||
|
||||
// Set construction state values according to reference documentation. 0
|
||||
// is the initialization value. Arm requires ((*gv & 1) == 1) after
|
||||
// __cxa_guard_release, ((*gv & 3) == 0) after __cxa_guard_abort. X86
|
||||
// requires first byte not modified by __cxa_guard_acquire, first byte
|
||||
// is non-zero after __cxa_guard_release.
|
||||
#define CONSTRUCTION_NOT_YET_STARTED 0
|
||||
#define CONSTRUCTION_COMPLETE 1
|
||||
#define CONSTRUCTION_UNDERWAY_WITHOUT_WAITER 0x100
|
||||
#define CONSTRUCTION_UNDERWAY_WITH_WAITER 0x200
|
||||
|
||||
int __cxa_guard_acquire(union CxaGuardValue *gv) {
|
||||
int old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
|
||||
while (true) {
|
||||
if (old_value == CONSTRUCTION_COMPLETE) {
|
||||
// A load_acquire operation is needed before exiting with COMPLETE
|
||||
// state, as we must ensure that all the stores performed by the
|
||||
// construction function are observable on this CPU after we exit.
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
return 0;
|
||||
} else if (old_value == CONSTRUCTION_NOT_YET_STARTED) {
|
||||
if (!atomic_compare_exchange_weak_explicit(
|
||||
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITHOUT_WAITER,
|
||||
memory_order_relaxed, memory_order_relaxed)) {
|
||||
continue;
|
||||
}
|
||||
// The acquire fence may not be needed. But as described in section 3.3.2
|
||||
// of the Itanium C++ ABI specification, it probably has to behave like
|
||||
// the acquisition of a mutex, which needs an acquire fence.
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
return 1;
|
||||
} else if (old_value == CONSTRUCTION_UNDERWAY_WITHOUT_WAITER) {
|
||||
if (!atomic_compare_exchange_weak_explicit(
|
||||
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITH_WAITER,
|
||||
memory_order_relaxed, memory_order_relaxed)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nsync_futex_wait_(&gv->state, CONSTRUCTION_UNDERWAY_WITH_WAITER, 0, 0);
|
||||
old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
void __cxa_guard_release(union CxaGuardValue *gv) {
|
||||
// Release fence is used to make all stores performed by the construction
|
||||
// function visible in other threads.
|
||||
int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_COMPLETE,
|
||||
memory_order_release);
|
||||
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
|
||||
nsync_futex_wake_(&gv->state, INT_MAX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void __cxa_guard_abort(union CxaGuardValue *gv) {
|
||||
// Release fence is used to make all stores performed by the construction
|
||||
// function visible in other threads.
|
||||
int old_value = atomic_exchange_explicit(
|
||||
&gv->state, CONSTRUCTION_NOT_YET_STARTED, memory_order_release);
|
||||
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
|
||||
nsync_futex_wake_(&gv->state, INT_MAX, 0);
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/cxxabi.h"
|
||||
#include "libc/intrin/cxaatexit.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
@@ -36,13 +37,24 @@
|
||||
* @noreturn
|
||||
*/
|
||||
wontreturn void exit(int exitcode) {
|
||||
const uintptr_t *p;
|
||||
STRACE("exit(%d)", exitcode);
|
||||
|
||||
// call thread local c++ object destructors
|
||||
if (_weaken(__cxa_thread_finalize)) {
|
||||
_weaken(__cxa_thread_finalize)();
|
||||
}
|
||||
|
||||
// call atexit() and __cxa_atexit() destructors
|
||||
if (_weaken(__cxa_finalize)) {
|
||||
_weaken(__cxa_finalize)(NULL);
|
||||
}
|
||||
|
||||
// call __destructor__ and finiarray destructors
|
||||
const uintptr_t *p;
|
||||
for (p = __fini_array_end; p > __fini_array_start;) {
|
||||
((void (*)(void))(*--p))();
|
||||
}
|
||||
|
||||
// terminate process
|
||||
_Exit(exitcode);
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||
@@ -55,11 +55,13 @@ privileged void __morph_tls(void) {
|
||||
// address 0x30 was promised to us, according to Go team
|
||||
// https://github.com/golang/go/issues/23617
|
||||
dis = 0x30;
|
||||
} else {
|
||||
} else if (IsWindows()) {
|
||||
// MSVC __declspec(thread) generates binary code for this
|
||||
// %gs:0x1480 abi. So long as TlsAlloc() isn't called >64
|
||||
// times we should be good.
|
||||
dis = 0x1480 + __tls_index * 8;
|
||||
} else {
|
||||
dis = 0;
|
||||
}
|
||||
|
||||
// iterate over modifiable code looking for 9 byte instruction
|
||||
@@ -112,6 +114,7 @@ privileged void __morph_tls(void) {
|
||||
}
|
||||
}
|
||||
|
||||
__tls_morphed = 1;
|
||||
__morph_end();
|
||||
#endif
|
||||
}
|
||||
@@ -136,7 +136,7 @@ long __get_minsigstksz(void) pureconst;
|
||||
void __get_main_stack(void **, size_t *, int *);
|
||||
long __get_safe_size(long, long);
|
||||
char *__get_tmpdir(void);
|
||||
__funline int __trace_disabled(int x) {
|
||||
forceinline int __trace_disabled(int x) {
|
||||
return 0;
|
||||
}
|
||||
#ifndef FTRACE
|
||||
|
||||
@@ -26,19 +26,23 @@
|
||||
#include "libc/thread/tls.h"
|
||||
#include "libc/thread/tls2.internal.h"
|
||||
|
||||
#define AMD64_SET_FSBASE 129
|
||||
#define AMD64_SET_GSBASE 131
|
||||
|
||||
int sys_set_tls();
|
||||
|
||||
textstartup void __set_tls(struct CosmoTib *tib) {
|
||||
// we can't allow --ftrace here because cosmo_dlopen() calls this
|
||||
// function to fix the tls register, and ftrace needs it unbroken
|
||||
dontinstrument textstartup void __set_tls(struct CosmoTib *tib) {
|
||||
tib = __adj_tls(tib);
|
||||
#ifdef __x86_64__
|
||||
// ask the operating system to change the x86 segment register
|
||||
if (IsWindows()) {
|
||||
npassert(0 <= __tls_index && __tls_index < 64);
|
||||
asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tib));
|
||||
} else if (IsFreebsd()) {
|
||||
sys_set_tls(129 /*AMD64_SET_FSBASE*/, tib);
|
||||
sys_set_tls(__tls_morphed ? AMD64_SET_GSBASE : AMD64_SET_FSBASE, tib);
|
||||
} else if (IsLinux()) {
|
||||
sys_set_tls(ARCH_SET_FS, tib);
|
||||
sys_set_tls(__tls_morphed ? ARCH_SET_GS : ARCH_SET_FS, tib);
|
||||
} else if (IsNetbsd()) {
|
||||
// netbsd has sysarch(X86_SET_FSBASE) but we can't use that because
|
||||
// signal handlers will cause it to be reset due to not setting the
|
||||
|
||||
@@ -96,7 +96,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
|
||||
* since it'll not only ensure stack overflows are detected, it
|
||||
* will also trigger the stack to grow down safely.
|
||||
*/
|
||||
__funline void CheckLargeStackAllocation(void *p, ssize_t n) {
|
||||
forceinline void CheckLargeStackAllocation(void *p, ssize_t n) {
|
||||
for (; n > 0; n -= 4096) {
|
||||
((char *)p)[n - 1] = 0;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_
|
||||
|
||||
#define UNW_TDEP_CURSOR_LEN 127
|
||||
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef enum {
|
||||
_URC_NO_REASON = 0,
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_FATAL_PHASE2_ERROR = 2,
|
||||
_URC_FATAL_PHASE1_ERROR = 3,
|
||||
_URC_NORMAL_STOP = 4,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8
|
||||
} _Unwind_Reason_Code;
|
||||
|
||||
typedef uint64_t unw_word_t;
|
||||
|
||||
typedef struct unw_cursor {
|
||||
unw_word_t opaque[UNW_TDEP_CURSOR_LEN];
|
||||
} unw_cursor_t;
|
||||
|
||||
struct _Unwind_Context {
|
||||
unw_cursor_t cursor;
|
||||
int end_of_stack;
|
||||
};
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
|
||||
void *);
|
||||
|
||||
uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
|
||||
uintptr_t _Unwind_GetIP(struct _Unwind_Context *);
|
||||
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
|
||||
void *_Unwind_FindEnclosingFunction(void *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_ */
|
||||
@@ -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/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -45,7 +46,9 @@ int getentropy(void *p, size_t n) {
|
||||
rc = 0;
|
||||
} else {
|
||||
BLOCK_SIGNALS;
|
||||
BLOCK_CANCELATION;
|
||||
if (__getrandom(p, n, 0) != n) notpossible;
|
||||
ALLOW_CANCELATION;
|
||||
ALLOW_SIGNALS;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
* On newer Linux only (c. 2013) it's possible to turn the anonymous
|
||||
* returned file back into a real file, by doing this:
|
||||
*
|
||||
* linkat(AT_FDCWD, _gc(xasprintf("/proc/self/fd/%d", fileno(f))),
|
||||
* linkat(AT_FDCWD, gc(xasprintf("/proc/self/fd/%d", fileno(f))),
|
||||
* AT_FDCWD, "real.txt", AT_SYMLINK_FOLLOW)
|
||||
*
|
||||
* On the New Technology, temporary files created by this function
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/macros.internal.h"
|
||||
.scall sys_set_tls,0x13d1490a5300309e,4095,3,165,globl,hidden
|
||||
@@ -1725,6 +1725,7 @@ syscon nr __NR_ioperm 0x00ad 0x0fff 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_init_module 0x00af 0x0069 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_delete_module 0x00b0 0x006a 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_gettid 0x00ba 0x00b2 0x100001b 0xfff 432 299 311 0xfff # TODO(jart): thread_self_trap vs. gettid?
|
||||
syscon nr __NR_set_tls 0x009e 0xfff 0x3000003 0xfff 0x00a5 0x0149 0x13d 0xfff
|
||||
syscon nr __NR_readahead 0x00bb 0x00d5 0xfff 0xfff 0xfff 0xfff 0xfff 0xfff
|
||||
syscon nr __NR_setxattr 0x00bc 0x0005 0x20000ec 0x00ec 0xfff 0xfff 0x177 0xfff
|
||||
syscon nr __NR_fsetxattr 0x00be 0x0007 0x20000ed 0x00ed 0xfff 0xfff 0x179 0xfff
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon nr,__NR_set_tls,0x009e,0xfff,0x3000003,0xfff,0x00a5,0x0149,0x13d,0xfff
|
||||
@@ -4,13 +4,15 @@
|
||||
/*
|
||||
* integral getauxval() keys
|
||||
*/
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_ENTRY 9
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
#define AT_ENTRY 9
|
||||
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
||||
@@ -201,7 +201,6 @@ scall sys_modify_ldt 0xfffffffffffff09a 0xfff globl # no wrapper
|
||||
scall sys_pivot_root 0xfffffffffffff09b 0x029 globl hidden
|
||||
#scall prctl 0xfffffffffffff09d 0x0a7 globl # wrapped manually
|
||||
scall sys_arch_prctl 0x0a50a50a5ffff09e 0xfff globl hidden # sysarch() on bsd
|
||||
scall sys_set_tls 0x13d1490a5300309e 0xfff globl hidden # arch_prctl on linux, sysarch on freebsd, _lwp_setprivate on netbsd, __set_tcb on openbsd, _lwp_setprivate on netbsd, thread_fast_set_cthread_self on xnu
|
||||
scall sys_adjtimex 0xfffffffffffff09f 0x0ab globl # no wrapper
|
||||
scall sys_swapon 0xffffff05520550a7 0x0e0 globl # no wrapper
|
||||
scall sys_swapoff 0xffffff1a8ffff0a8 0x0e1 globl # no wrapper
|
||||
|
||||
@@ -116,11 +116,11 @@ void _pthread_unref(struct PosixThread *);
|
||||
void _pthread_unwind(struct PosixThread *);
|
||||
void _pthread_zombify(struct PosixThread *);
|
||||
|
||||
__funline pureconst struct PosixThread *_pthread_self(void) {
|
||||
forceinline pureconst struct PosixThread *_pthread_self(void) {
|
||||
return (struct PosixThread *)__get_tls()->tib_pthread;
|
||||
}
|
||||
|
||||
__funline void _pthread_ref(struct PosixThread *pt) {
|
||||
forceinline void _pthread_ref(struct PosixThread *pt) {
|
||||
atomic_fetch_add_explicit(&pt->pt_refs, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ static errno_t _pthread_cancel_everyone(void) {
|
||||
* Consider using Cosmopolitan Libc's garbage collector since it will be
|
||||
* executed when a thread exits due to a cancelation.
|
||||
*
|
||||
* void *p = _gc(malloc(123));
|
||||
* void *p = gc(malloc(123));
|
||||
* read(0, p, 123);
|
||||
*
|
||||
* It's possible to put a thread in asynchronous cancelation mode with
|
||||
|
||||
@@ -84,8 +84,8 @@ void _pthread_unkey(struct CosmoTib *tib) {
|
||||
* the callback function that was supplied to pthread_create(). This may
|
||||
* be used if the thread wishes to exit at any other point in the thread
|
||||
* lifecycle, in which case this function is responsible for ensuring we
|
||||
* invoke _gc(), _defer(), and pthread_cleanup_push() callbacks, as well
|
||||
* as pthread_key_create() destructors.
|
||||
* invoke gc(), _defer(), and pthread_cleanup_push() callbacks, and also
|
||||
* pthread_key_create() destructors.
|
||||
*
|
||||
* If the current thread is an orphaned thread, or is the main thread
|
||||
* when no other threads were created, then this will terminated your
|
||||
|
||||
+2
-1
@@ -42,6 +42,7 @@ struct CosmoTib {
|
||||
};
|
||||
|
||||
extern int __threaded;
|
||||
extern char __tls_morphed;
|
||||
extern unsigned __tls_index;
|
||||
|
||||
char *_mktls(struct CosmoTib **);
|
||||
@@ -64,7 +65,7 @@ void __set_tls(struct CosmoTib *);
|
||||
*
|
||||
* This can't be used in privileged functions.
|
||||
*/
|
||||
__funline pureconst struct CosmoTib *__get_tls(void) {
|
||||
forceinline pureconst struct CosmoTib *__get_tls(void) {
|
||||
#ifdef __chibicc__
|
||||
return 0;
|
||||
#elif __x86_64__
|
||||
|
||||
@@ -11,10 +11,14 @@ COSMOPOLITAN_C_START_
|
||||
* This should be favored over __get_tls() for .privileged code that
|
||||
* can't be self-modified by __enable_tls().
|
||||
*/
|
||||
__funline struct CosmoTib *__get_tls_privileged(void) {
|
||||
forceinline struct CosmoTib *__get_tls_privileged(void) {
|
||||
char *tib, *lin = (char *)0x30;
|
||||
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd() || IsMetal()) {
|
||||
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
|
||||
if (!__tls_morphed) {
|
||||
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
|
||||
} else {
|
||||
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
|
||||
}
|
||||
} else {
|
||||
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
|
||||
if (IsWindows()) {
|
||||
@@ -24,14 +28,14 @@ __funline struct CosmoTib *__get_tls_privileged(void) {
|
||||
return (struct CosmoTib *)tib;
|
||||
}
|
||||
|
||||
__funline struct CosmoTib *__get_tls_win32(void) {
|
||||
forceinline struct CosmoTib *__get_tls_win32(void) {
|
||||
char *tib, *lin = (char *)0x30;
|
||||
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
|
||||
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
|
||||
return (struct CosmoTib *)tib;
|
||||
}
|
||||
|
||||
__funline void __set_tls_win32(void *tls) {
|
||||
forceinline void __set_tls_win32(void *tls) {
|
||||
asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tls));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/libgen.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "net/https/https.h"
|
||||
|
||||
bool ChainCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *parent) {
|
||||
|
||||
@@ -37,8 +37,8 @@ struct Cert FinishCertificate(struct Cert *ca, mbedtls_x509write_cert *wcert,
|
||||
if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) {
|
||||
FATALF("generate key (grep -0x%04x)", -rc);
|
||||
}
|
||||
LogCertificate(_gc(xasprintf("generated %s certificate",
|
||||
mbedtls_pk_get_name(&cert->pk))),
|
||||
cert);
|
||||
LogCertificate(
|
||||
gc(xasprintf("generated %s certificate", mbedtls_pk_get_name(&cert->pk))),
|
||||
cert);
|
||||
return (struct Cert){cert, key};
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/intrin/bsr.h"
|
||||
#include "libc/intrin/hilbert.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
@@ -49,6 +48,7 @@
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
@@ -815,13 +815,13 @@ void *ListenWorker(void *arg) {
|
||||
void *HttpWorker(void *arg) {
|
||||
struct Client client;
|
||||
int id = (intptr_t)arg;
|
||||
char *msgbuf = _gc(xmalloc(MSG_BUF));
|
||||
char *msgbuf = gc(xmalloc(MSG_BUF));
|
||||
char *inbuf = NewSafeBuffer(INBUF_SIZE);
|
||||
char *outbuf = NewSafeBuffer(OUTBUF_SIZE);
|
||||
struct HttpMessage *msg = _gc(xcalloc(1, sizeof(struct HttpMessage)));
|
||||
struct HttpMessage *msg = gc(xcalloc(1, sizeof(struct HttpMessage)));
|
||||
|
||||
BlockSignals();
|
||||
pthread_setname_np(pthread_self(), _gc(xasprintf("HTTP%d", id)));
|
||||
pthread_setname_np(pthread_self(), gc(xasprintf("HTTP%d", id)));
|
||||
|
||||
// connection loop
|
||||
while (GetClient(&g_clients, &client)) {
|
||||
@@ -1761,7 +1761,7 @@ void *ClaimWorker(void *arg) {
|
||||
long processed;
|
||||
sqlite3_stmt *stmt;
|
||||
bool warmedup = false;
|
||||
struct Claim *v = _gc(xcalloc(BATCH_MAX, sizeof(struct Claim)));
|
||||
struct Claim *v = gc(xcalloc(BATCH_MAX, sizeof(struct Claim)));
|
||||
BlockSignals();
|
||||
pthread_setname_np(pthread_self(), "ClaimWorker");
|
||||
LOG("%P ClaimWorker started\n");
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/hyperion.h"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "dsp/core/q.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "libc/fmt/bing.internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "dsp/core/half.h"
|
||||
#include "libc/fmt/bing.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
|
||||
@@ -38,7 +38,7 @@ void SetUpOnce(void) {
|
||||
|
||||
void Make(const char *path, int mode) {
|
||||
int fd, n = lemur64() & 0xfffff;
|
||||
char *data = _gc(malloc(n));
|
||||
char *data = gc(malloc(n));
|
||||
rngset(data, n, lemur64, -1);
|
||||
ASSERT_NE(-1, (fd = creat(path, mode)));
|
||||
ASSERT_SYS(0, n, write(fd, data, n));
|
||||
@@ -77,8 +77,8 @@ TEST(copy_file_range, test) {
|
||||
size_t n, m;
|
||||
Make("foo", 0644);
|
||||
Copy("foo", "bar");
|
||||
p = _gc(xslurp("foo", &n));
|
||||
q = _gc(xslurp("bar", &m));
|
||||
p = gc(xslurp("foo", &n));
|
||||
q = gc(xslurp("bar", &m));
|
||||
ASSERT_EQ(n, m);
|
||||
ASSERT_EQ(0, memcmp(p, q, n));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2024 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 │
|
||||
@@ -19,75 +19,48 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/ftw.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
const char *prog;
|
||||
char tmpdir[PATH_MAX];
|
||||
char binpath[PATH_MAX];
|
||||
|
||||
bool IsDirectory(const char *path) {
|
||||
int e;
|
||||
bool res;
|
||||
struct stat st;
|
||||
e = errno;
|
||||
res = stat(path, &st) != -1 && S_ISDIR(st.st_mode);
|
||||
errno = e;
|
||||
return res;
|
||||
void SetUpOnce(void) {
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
}
|
||||
|
||||
void Execute(char *argv[]) {
|
||||
int ws;
|
||||
if (!vfork()) {
|
||||
execv(argv[0], argv);
|
||||
_Exit(127);
|
||||
}
|
||||
wait(&ws);
|
||||
if (!WIFEXITED(ws) || WEXITSTATUS(ws)) {
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": command failed\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
TEST(devfd, test) {
|
||||
// TODO: What is up with this mysterious ENOENT error?
|
||||
// The code appears like it should support this.
|
||||
if (IsFreebsd()) return;
|
||||
char buf[8] = {0};
|
||||
struct stat st[2] = {0};
|
||||
ASSERT_SYS(0, 0, xbarf("hello.txt", "bone", -1));
|
||||
ASSERT_SYS(0, 3, open("hello.txt", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, open("/dev/fd/3", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, read(4, buf, 7));
|
||||
ASSERT_STREQ("bone", buf);
|
||||
ASSERT_SYS(0, 0, fstat(3, st));
|
||||
ASSERT_SYS(0, 0, fstat(4, st + 1));
|
||||
ASSERT_EQ(0, memcmp(st, st + 1, sizeof(struct stat)));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
int Visit(const char *fpath, const struct stat *sb, int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
if (tflag == FTW_F && endswith(fpath, ".gz")) {
|
||||
Execute((char *[]){"build/bootstrap/gzip.com", "-d", (char *)fpath, 0});
|
||||
strcpy(binpath, fpath);
|
||||
binpath[strlen(binpath) - 3] = 0;
|
||||
chmod(binpath, 0755);
|
||||
} else if (tflag == FTW_F && endswith(fpath, ".sym")) {
|
||||
strcpy(binpath, fpath);
|
||||
binpath[strlen(binpath) - 4] = 0;
|
||||
symlink(xslurp(fpath, 0), binpath);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsLinux()) return 0;
|
||||
prog = argv[0];
|
||||
if (!prog) prog = "unbundle";
|
||||
if (IsDirectory("o/third_party/gcc")) return 0;
|
||||
makedirs("o/third_party", 0755);
|
||||
FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid());
|
||||
Execute(
|
||||
(char *[]){"build/bootstrap/cp.com", "-r", "third_party/gcc", tmpdir, 0});
|
||||
if (nftw(tmpdir, Visit, 20, 0) == -1) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": nftw failed: ", stderr);
|
||||
fputs(_strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
rename(tmpdir, "o/third_party/gcc");
|
||||
TEST(devfd, not_DEV_FD_STAT_BROKEN) {
|
||||
// fstat() and stat() are inconsistent on bsd systems
|
||||
// with xnu it only appears to be st_dev that differs
|
||||
if (IsBsd()) return;
|
||||
char buf[8] = {0};
|
||||
struct stat st[2] = {0};
|
||||
ASSERT_SYS(0, 0, xbarf("hello.txt", "bone", -1));
|
||||
ASSERT_SYS(0, 3, open("hello.txt", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, open("/dev/fd/3", O_RDONLY));
|
||||
ASSERT_SYS(0, 4, read(4, buf, 7));
|
||||
ASSERT_STREQ("bone", buf);
|
||||
ASSERT_SYS(0, 0, fstat(3, st));
|
||||
ASSERT_SYS(0, 0, stat("/dev/fd/3", st + 1));
|
||||
ASSERT_EQ(0, memcmp(st, st + 1, sizeof(struct stat)));
|
||||
ASSERT_SYS(0, 0, close(4));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/safemacros.internal.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/nexgen32e/vendor.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "libc/fmt/libgen.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
@@ -34,14 +35,16 @@
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
static char *self;
|
||||
static bool skiptests;
|
||||
static bool loaded, skiptests, skiparg0;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
self = GetProgramExecutableName();
|
||||
testlib_enable_tmp_setup_teardown();
|
||||
if (IsMetal()) {
|
||||
skiptests = true;
|
||||
} else if (IsOpenbsd() || (IsXnu() && !IsXnuSilicon())) {
|
||||
} else if (IsWindows()) {
|
||||
/* do all tests */
|
||||
} else if (!loaded) {
|
||||
ASSERT_STRNE(self, "");
|
||||
ASSERT_SYS(0, 3, open(self, O_RDONLY));
|
||||
char buf[8];
|
||||
@@ -50,15 +53,23 @@ void SetUpOnce(void) {
|
||||
if (READ64LE(buf) != READ64LE("MZqFpD='") &&
|
||||
READ64LE(buf) != READ64LE("jartsr='") &&
|
||||
READ64LE(buf) != READ64LE("APEDBG='")) {
|
||||
fprintf(stderr,
|
||||
"we appear to be running as an assimilated binary on OpenBSD or "
|
||||
"x86_64 XNU;\nGetProgramExecutableName is unreliable here\n");
|
||||
skiptests = true;
|
||||
// GetProgramExecutableName does not work reliably for assimilated
|
||||
// OpenBSD or XNU binaries.
|
||||
skiptests = IsOpenbsd() || (IsXnu() && !IsXnuSilicon());
|
||||
}
|
||||
} else {
|
||||
skiparg0 = !(getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
|
||||
}
|
||||
fprintf(stderr, loaded ? "loaded\n" : "not loaded\n");
|
||||
if (skiptests) {
|
||||
fprintf(stderr, "skipping most GetProgramExecutableName tests\n");
|
||||
} else if (skiparg0) {
|
||||
fprintf(stderr, "skipping argv[0] tests\n");
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void Child(int argc, char *argv[]) {
|
||||
loaded = !!__program_executable_name;
|
||||
if (argc >= 2 && !strcmp(argv[1], "Child")) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
@@ -72,14 +83,10 @@ __attribute__((__constructor__)) static void Child(int argc, char *argv[]) {
|
||||
if (strcmp(argv[2], GetProgramExecutableName())) {
|
||||
exit(123);
|
||||
}
|
||||
if (!IsXnuSilicon()) exit(0);
|
||||
/* TODO(mrdomino): argv[0] tests only pass on XnuSilicon right now because
|
||||
__sys_execve fails there, so the ape loader is used.
|
||||
the correct check is "we have been invoked either as an
|
||||
assimilated binary or via the ape loader, and not via a
|
||||
raw __sys_execve." */
|
||||
if (strcmp(argv[3], argv[0])) {
|
||||
exit(124);
|
||||
if (argc >= 4) {
|
||||
if (strcmp(argv[3], argv[0])) {
|
||||
exit(124);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@@ -98,7 +105,8 @@ TEST(GetProgramExecutableName, ofThisFile) {
|
||||
TEST(GetProgramExecutableName, nullEnv) {
|
||||
if (skiptests) return;
|
||||
SPAWN(fork);
|
||||
execve(self, (char *[]){self, "Child", self, self, 0}, (char *[]){0});
|
||||
execve(self, (char *[]){self, "Child", self, skiparg0 ? 0 : self, 0},
|
||||
(char *[]){0});
|
||||
abort();
|
||||
EXITS(0);
|
||||
}
|
||||
@@ -106,7 +114,8 @@ TEST(GetProgramExecutableName, nullEnv) {
|
||||
TEST(GetProramExecutableName, weirdArgv0NullEnv) {
|
||||
if (skiptests) return;
|
||||
SPAWN(fork);
|
||||
execve(self, (char *[]){"hello", "Child", self, "hello", 0}, (char *[]){0});
|
||||
execve(self, (char *[]){"hello", "Child", self, skiparg0 ? 0 : "hello", 0},
|
||||
(char *[]){0});
|
||||
abort();
|
||||
EXITS(0);
|
||||
}
|
||||
@@ -133,11 +142,12 @@ TEST(GetProgramExecutableName, movedSelf) {
|
||||
ASSERT_NE(NULL, getcwd(buf, BUFSIZ - 5));
|
||||
stpcpy(buf + strlen(buf), "/test");
|
||||
SPAWN(fork);
|
||||
execve(buf, (char *[]){"hello", "Child", buf, "hello", 0}, (char *[]){0});
|
||||
execve(buf, (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0},
|
||||
(char *[]){0});
|
||||
abort();
|
||||
EXITS(0);
|
||||
SPAWN(fork);
|
||||
execve("./test", (char *[]){"hello", "Child", buf, "hello", 0},
|
||||
execve("./test", (char *[]){"hello", "Child", buf, skiparg0 ? 0 : "hello", 0},
|
||||
(char *[]){0});
|
||||
abort();
|
||||
EXITS(0);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
@@ -30,6 +29,7 @@
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/serialize.h"
|
||||
#include "libc/stdio/lcg.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
@@ -70,7 +70,7 @@ void *TortureWorker(void *arg) {
|
||||
TEST(getrandom, test) {
|
||||
int i, n = 999;
|
||||
double e, w = 7.7;
|
||||
char *buf = _gc(calloc(1, n));
|
||||
char *buf = gc(calloc(1, n));
|
||||
ASSERT_SYS(0, 0, getrandom(0, 0, 0));
|
||||
ASSERT_SYS(0, n, getrandom(buf, n, 0));
|
||||
ASSERT_SYS(EFAULT, -1, getrandom(0, n, 0));
|
||||
@@ -92,7 +92,7 @@ TEST(getrandom, test2) {
|
||||
double e, w = 7.7;
|
||||
struct sigaction sa;
|
||||
int i, k, m, n = 999;
|
||||
char *buf = _gc(calloc(1, n));
|
||||
char *buf = gc(calloc(1, n));
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = OnSig;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/proc/ntspawn.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/proc/ntspawn.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#if SupportsWindows()
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
@@ -96,7 +96,7 @@ TEST(poll, testNegativeOneFd_isIgnored) {
|
||||
EXPECT_SYS(0, 0, poll(fds, ARRAYLEN(fds), 1));
|
||||
EXPECT_STREQ("fd:-1 revents:<TODO:kPollNames>\n"
|
||||
"fd:3 revents:<TODO:kPollNames>\n",
|
||||
_gc(FormatPollFd(&fds[0])));
|
||||
gc(FormatPollFd(&fds[0])));
|
||||
ASSERT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
Loaded 100 of 536 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user