mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-08 01:58:20 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
@@ -1,6 +1,7 @@
|
||||
# -*- conf -*-
|
||||
|
||||
/o
|
||||
/cosmocc
|
||||
/.prompt.jtlp
|
||||
|
||||
# TODO: Find some way to have Python write to o/
|
||||
|
||||
+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 \
|
||||
@@ -268,6 +328,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/libunwind/BUILD.mk
|
||||
include examples/BUILD.mk
|
||||
include examples/pyapp/BUILD.mk
|
||||
include examples/pylife/BUILD.mk
|
||||
|
||||
@@ -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");
|
||||
|
||||
+69
-37
@@ -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
|
||||
|
||||
################################################################################
|
||||
@@ -112,13 +137,20 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||
echo done >&2
|
||||
fi
|
||||
|
||||
uname_r="$(uname -r)"
|
||||
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
|
||||
FLAGS=FP
|
||||
else
|
||||
FLAGS=F
|
||||
fi
|
||||
|
||||
echo >&2
|
||||
echo registering APE with binfmt_misc >&2
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
||||
+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.
@@ -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
|
||||
+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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+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();
|
||||
}
|
||||
|
||||
+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
|
||||
|
||||
|
||||
+88
-63
@@ -45,6 +45,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 +117,7 @@ struct Loaded {
|
||||
Elf64_Phdr ph[25];
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
atomic_uint once;
|
||||
bool is_supported;
|
||||
struct CosmoTib *tib;
|
||||
@@ -125,9 +126,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 +158,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 +288,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 +495,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 +509,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 +618,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 +661,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 +683,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 +730,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 +781,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)
|
||||
@@ -824,7 +810,7 @@ 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;
|
||||
}
|
||||
@@ -836,8 +822,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 +851,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 +864,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 +891,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 +909,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 +917,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__ 3
|
||||
#define __COSMOPOLITAN__ \
|
||||
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
|
||||
__COSMOPOLITAN_PATCH__)
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,21 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/internal.h"
|
||||
|
||||
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 {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
.ftrace1
|
||||
longjmp:
|
||||
.ftrace2
|
||||
_longjmp:
|
||||
#ifdef __x86_64__
|
||||
mov %esi,%eax
|
||||
test %eax,%eax
|
||||
@@ -61,5 +62,5 @@ longjmp:
|
||||
#error "unsupported architecture"
|
||||
#endif
|
||||
.endfn longjmp,globl
|
||||
.alias longjmp,_longjmp
|
||||
.endfn _longjmp,globl
|
||||
.alias longjmp,siglongjmp
|
||||
+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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -42,6 +42,7 @@ struct CosmoTib {
|
||||
};
|
||||
|
||||
extern int __threaded;
|
||||
extern char __tls_morphed;
|
||||
extern unsigned __tls_index;
|
||||
|
||||
char *_mktls(struct CosmoTib **);
|
||||
|
||||
@@ -14,7 +14,11 @@ COSMOPOLITAN_C_START_
|
||||
__funline 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()) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Vendored
+1
@@ -17,6 +17,7 @@ o/$(MODE)/third_party: \
|
||||
o/$(MODE)/third_party/hiredis \
|
||||
o/$(MODE)/third_party/less \
|
||||
o/$(MODE)/third_party/libcxx \
|
||||
o/$(MODE)/third_party/libunwind \
|
||||
o/$(MODE)/third_party/linenoise \
|
||||
o/$(MODE)/third_party/lua \
|
||||
o/$(MODE)/third_party/lz4cli \
|
||||
|
||||
Vendored
+1
@@ -85,6 +85,7 @@ $(THIRD_PARTY_BASH_OBJS): private \
|
||||
-Wno-missing-braces \
|
||||
-Wno-unused-label \
|
||||
-Wno-unused-value \
|
||||
-Wno-return-type \
|
||||
-Wno-parentheses \
|
||||
-fportcosmo
|
||||
|
||||
|
||||
Vendored
+1
@@ -13,3 +13,4 @@ ORIGIN
|
||||
LOCAL CHANGES
|
||||
|
||||
- Force disable mkfifo() code
|
||||
- Added runtime check for broken BSD /dev/fd stuff
|
||||
Vendored
+2
-2
@@ -542,7 +542,7 @@
|
||||
#define HAVE_HASH_BANG_EXEC 1
|
||||
|
||||
/* Define if you have the /dev/fd devices to map open files into the file system. */
|
||||
/* #define HAVE_DEV_FD 1 */
|
||||
#define HAVE_DEV_FD 1
|
||||
|
||||
/* Defined to /dev/fd or /proc/self/fd (linux). */
|
||||
#define DEV_FD_PREFIX "/dev/fd/"
|
||||
@@ -1160,7 +1160,7 @@
|
||||
|
||||
/* #undef GETCWD_BROKEN */
|
||||
|
||||
/* #undef DEV_FD_STAT_BROKEN */
|
||||
#define DEV_FD_STAT_BROKEN
|
||||
|
||||
/* An array implementation that prioritizes speed (O(1) access) over space,
|
||||
in array2.c */
|
||||
|
||||
Vendored
+7
-3
@@ -1,3 +1,4 @@
|
||||
#include "libc/dce.h"
|
||||
/* eaccess.c - eaccess replacement for the shell, plus other access functions. */
|
||||
|
||||
/* Copyright (C) 2006-2020 Free Software Foundation, Inc.
|
||||
@@ -93,7 +94,8 @@ sh_stat (path, finfo)
|
||||
{
|
||||
/* If stating /dev/fd/n doesn't produce the same results as fstat of
|
||||
FD N, then define DEV_FD_STAT_BROKEN */
|
||||
#if !defined (HAVE_DEV_FD) || defined (DEV_FD_STAT_BROKEN)
|
||||
//#if !defined (HAVE_DEV_FD) || defined (DEV_FD_STAT_BROKEN)
|
||||
if (IsBsd()) {//[jart]
|
||||
intmax_t fd;
|
||||
int r;
|
||||
|
||||
@@ -105,7 +107,8 @@ sh_stat (path, finfo)
|
||||
}
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
#else
|
||||
//#else
|
||||
} else {//[jart]
|
||||
/* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
|
||||
trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
|
||||
On most systems, with the notable exception of linux, this is
|
||||
@@ -114,7 +117,8 @@ sh_stat (path, finfo)
|
||||
strcpy (pbuf, DEV_FD_PREFIX);
|
||||
strcat (pbuf, path + 8);
|
||||
return (stat (pbuf, finfo));
|
||||
#endif /* !HAVE_DEV_FD */
|
||||
//#endif /* !HAVE_DEV_FD */
|
||||
}//[jart]
|
||||
}
|
||||
#if !defined (HAVE_DEV_STDIN)
|
||||
else if (STREQN (path, "/dev/std", 8))
|
||||
|
||||
Vendored
-17107
File diff suppressed because it is too large.
Load diff
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
DESCRIPTION
|
||||
|
||||
Cosmopolitan GCC
|
||||
Prebuilt x86_64-linux binaries
|
||||
An APE-friendly C/C++ compiler
|
||||
|
||||
LICENSE
|
||||
|
||||
GPLv3 and other licenses (see LICENSE.txt)
|
||||
|
||||
ORIGIN
|
||||
|
||||
@ahgamut's musl-cross-make fork
|
||||
https://github.com/ahgamut/musl-cross-make/
|
||||
e58abc1110b335a3341e8ad5821ad8e3880d9bb2
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
ahgamut's musl-cross-make fork includes a 2kLOC patch that modifies
|
||||
GCC so it'll compile C code like `switch(errno){case EINVAL: etc.}`
|
||||
see third_party/gcc/portcosmo.patch for GCC 11.2.0 for our changes
|
||||
|
||||
NOTES
|
||||
|
||||
These binaries were compiled by Justine Tunney. You have the freedom
|
||||
to obtain the original source source code, apply our patch, and enjoy
|
||||
all the freedoms promised to you by the GNU General Public License.
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-ar
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-as
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
ld.bfd
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-nm
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-objcopy
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-objdump
|
||||
@@ -1 +0,0 @@
|
||||
../../bin/aarch64-linux-musl-strip
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1 +0,0 @@
|
||||
aarch64-linux-musl-g++
|
||||
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../aarch64-linux-musl/bin/ld.bfd
|
||||
@@ -1 +0,0 @@
|
||||
../aarch64-linux-musl/bin/ld.bfd
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1 +0,0 @@
|
||||
x86_64-linux-musl-g++
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../x86_64-linux-musl/bin/ld.bfd
|
||||
@@ -1 +0,0 @@
|
||||
../x86_64-linux-musl/bin/ld.bfd
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Vendored
-97
@@ -1,97 +0,0 @@
|
||||
#
|
||||
# config.mak.dist - sample musl-cross-make configuration
|
||||
#
|
||||
# Copy to config.mak and edit as desired.
|
||||
#
|
||||
|
||||
# There is no default TARGET; you must select one here or on the make
|
||||
# command line. Some examples:
|
||||
|
||||
# TARGET = i486-linux-musl
|
||||
TARGET = aarch64-linux-musl
|
||||
# TARGET = arm-linux-musleabi
|
||||
# TARGET = arm-linux-musleabihf
|
||||
# TARGET = sh2eb-linux-muslfdpic
|
||||
# TARGET = powerpc64le-linux-musl
|
||||
# TARGET = aarch64-linux-musl
|
||||
|
||||
# By default, cross compilers are installed to ./output under the top-level
|
||||
# musl-cross-make directory and can later be moved wherever you want them.
|
||||
# To install directly to a specific location, set it here. Multiple targets
|
||||
# can safely be installed in the same location. Some examples:
|
||||
|
||||
OUTPUT = /opt/cross11portcosmo
|
||||
# OUTPUT = /usr/local
|
||||
|
||||
# By default, latest supported release versions of musl and the toolchain
|
||||
# components are used. You can override those here, but the version selected
|
||||
# must be supported (under hashes/ and patches/) to work. For musl, you
|
||||
# can use "git-refname" (e.g. git-master) instead of a release. Setting a
|
||||
# blank version for gmp, mpc, mpfr and isl will suppress download and
|
||||
# in-tree build of these libraries and instead depend on pre-installed
|
||||
# libraries when available (isl is optional and not set by default).
|
||||
# Setting a blank version for linux will suppress installation of kernel
|
||||
# headers, which are not needed unless compiling programs that use them.
|
||||
|
||||
BINUTILS_VER = 2.35.2
|
||||
GCC_VER = 11.2.0
|
||||
# MUSL_VER = git-master
|
||||
# GMP_VER =
|
||||
# MPC_VER =
|
||||
# MPFR_VER =
|
||||
# ISL_VER =
|
||||
# LINUX_VER =
|
||||
|
||||
# By default source archives are downloaded with wget. curl is also an option.
|
||||
|
||||
# DL_CMD = wget -c -O
|
||||
# DL_CMD = curl -C - -L -o
|
||||
|
||||
# Check sha-1 hashes of downloaded source archives. On gnu systems this is
|
||||
# usually done with sha1sum.
|
||||
|
||||
# SHA1_CMD = sha1sum -c
|
||||
# SHA1_CMD = sha1 -c
|
||||
# SHA1_CMD = shasum -a 1 -c
|
||||
|
||||
# Something like the following can be used to produce a static-linked
|
||||
# toolchain that's deployable to any system with matching arch, using
|
||||
# an existing musl-targeted cross compiler. This only works if the
|
||||
# system you build on can natively (or via binfmt_misc and qemu) run
|
||||
# binaries produced by the existing toolchain (in this example, i486).
|
||||
|
||||
# MUSL_CONFIG += --enable-debug
|
||||
# MUSL_CONFIG += CFLAGS="-Os -fno-omit-frame-pointer -fno-optimize-sibling-calls -mno-omit-leaf-frame-pointer"
|
||||
MUSL_CONFIG += CFLAGS="-Os"
|
||||
|
||||
COMMON_CONFIG += CC="/opt/cross/bin/x86_64-linux-musl-gcc -static --static"
|
||||
COMMON_CONFIG += CXX="/opt/cross/bin/x86_64-linux-musl-g++ -static --static"
|
||||
# COMMON_CONFIG += CC="gcc -static --static"
|
||||
# COMMON_CONFIG += CXX="g++ -static --static"
|
||||
|
||||
# Recommended options for smaller build for deploying binaries:
|
||||
|
||||
COMMON_CONFIG += CFLAGS="-Os -g0"
|
||||
COMMON_CONFIG += CXXFLAGS="-Os -g0"
|
||||
COMMON_CONFIG += LDFLAGS="-s"
|
||||
|
||||
# Options you can add for faster/simpler build at the expense of features:
|
||||
|
||||
COMMON_CONFIG += --disable-nls
|
||||
GCC_CONFIG += --disable-libquadmath --disable-decimal-float
|
||||
GCC_CONFIG += --disable-libitm
|
||||
GCC_CONFIG += --disable-fixed-point
|
||||
GCC_CONFIG += --disable-lto
|
||||
|
||||
# By default C and C++ are the only languages enabled, and these are
|
||||
# the only ones tested and known to be supported. You can uncomment the
|
||||
# following and add other languages if you want to try getting them to
|
||||
# work too.
|
||||
|
||||
GCC_CONFIG += --enable-languages=c,c++ #--enable-plugin
|
||||
|
||||
# You can keep the local build path out of your toolchain binaries and
|
||||
# target libraries with the following, but then gdb needs to be told
|
||||
# where to look for source files.
|
||||
|
||||
# COMMON_CONFIG += --with-debug-prefix-map=$(CURDIR)=
|
||||
Whitespace-only changes.
@@ -1 +0,0 @@
|
||||
../../../../bin/aarch64-linux-musl-as
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../../x86_64-linux-musl/bin/ld.bfd
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../../bin/aarch64-linux-musl-ld.bfd
|
||||
@@ -1 +0,0 @@
|
||||
../../../../bin/aarch64-linux-musl-ld.bfd
|
||||
@@ -1 +0,0 @@
|
||||
../../../../bin/x86_64-linux-musl-as
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
-1910
File diff suppressed because it is too large.
Load diff
Loaded 100 of 147 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user