Compare commits

...
50 Commits
Author SHA1 Message Date
Justine Tunney cb19e172da Release Cosmopolitan v3.2.4 2024-01-08 19:37:59 -08:00
Jōshin df648fb174 Revert apeinstall.sh binfmt flags (#1072)
The P flag breaks backwards compatibility with older binaries. The idea
is to revert this commit after that break has been resolved.
2024-01-08 14:21:21 -08:00
Justine Tunney 9a6af92bed Fix libcxxabi tests in MODE=tiny and MODE=rel
See #1076
2024-01-08 13:49:06 -08:00
Justine Tunney 6ab01716ce Fix aarch64 setjmp abi
We now store values in jmp_buf where the compiler wants them to be. This
fixes code that calls __builtin_setjmp() and __builtin_longjmp() such as
libunwind. All libcxxabi tests are now passing on ARM64.

See #1076
2024-01-08 13:26:28 -08:00
Justine Tunney 21093044c0 Rebuild build/bootstrap/chmod.com 2024-01-08 12:22:12 -08:00
Justine Tunney b8a9fbbd01 Review catch_multi_level_pointer test failure
This test was was failing on GitHub Actions because GA uses Linux and
Linux supports resource usage accounting. Cosmo's compile.com program
imposes CPU, memory and file size limits on both the compiler and the
test programs themselves.

See #1076
2024-01-08 12:10:29 -08:00
Justine Tunney 81ce2e4cbc Call thread finalizers on exit()
While we don't call POSIX thread key destructors from exit(), we do need
to call these, since C++ uses it for TLS object destructors.

See #1076
2024-01-08 11:45:02 -08:00
Justine Tunney 07db3004d6 Disable libcxxabi/test/guard_threaded_test
It works, but exceeds the CPU quota granted to tests, by a lot.
2024-01-08 11:19:09 -08:00
Trung Nguyen b0566348b2 third_party/libcxxabi: Add test suite (#1076)
Added the `libcxxabi` test suite as found in LLVM 17.0.6.

Some tests that do not apply to the current configuration of
comsopolitan are not added. These include:
- `backtrace_test`, `forced_unwind*`: Use unwind function unsupported in
SjLj mode.
- `noexception*`: Designed to test `libcxxabi` in no exceptions mode.

Some tests are added but not enabled due to bugs specific to GCC or
cosmopolitan. These are clearly indicated in the `BUILD.mk` file.
2024-01-08 10:50:06 -08:00
Justine Tunney 8fb24a8f88 Turn exceptions back off by default 2024-01-08 10:47:42 -08:00
Justine Tunney a4b455185b Bring back gc() function
Renaming gc() to _gc() was a mistake since the better thing to do is put
it behind the _COSMO_SOURCE macro. We need this change because I haven't
wanted to use my amazing garbage collector ever since we renamed it. You
now need to define _COSMO_SOURCE yourself when using amalgamation header
and cosmocc users need to pass the -mcosmo flag to get the gc() function

Some other issues relating to cancelation have been fixed along the way.
We're also now putting cosmocc in a folder named `.cosmocc` so it can be
more safely excluded by grep --exclude-dir=.cosmocc --exclude-dir=o etc.
2024-01-08 10:26:28 -08:00
Jōshin 6cb0354e19 mkofs improvements
- Always use $PWD/o. if it doesn't exist, say how to create it.

- return 2 on unsupported platforms.
2024-01-08 17:23:09 +00:00
Trung Nguyen b580080af1 tool/cosmocc: Allow exceptions and rtti (#1074)
With `libunwind` and `libcxxabi` included in `libcosmo`, we can now
allow users to build C++ applications with exceptions and RTTI enabled.

The default is still disabling these two to avoid bloating the binary.

Closes #1065
2024-01-08 08:47:53 -08:00
Trung Nguyen 8b33204f37 Add LLVM libcxxabi (#1063)
* third_party: Add libcxxabi

Added libcxxabi from LLVM 17.0.6
The library implements the Itanium C++ exception handling ABI.

* third_party/libcxxabi: Enable __cxa_thread_atexit

Enable `__cxa_thread_atexit` from libcxxabi.
`__cxa_thread_atexit_impl` is still implemented by the cosmo libc.
The original `__cxa_thread_atexit` has been removed.

* third_party/libcxx: Build with exceptions

Build libcxx with exceptions enabled.

- Removed `_LIBCPP_NO_EXCEPTIONS` from `__config`.
- Switched the exception implementation to `libcxxabi`. These two files
are taken from the same `libcxx` version as mentioned in `README.cosmo`.
- Removed `new_handler_fallback` in favor of `libcxxabi` implementation.
- Enable `-fexceptions` and `-frtti` for `libcxx`.
- Removed `THIRD_PARTY_LIBCXX` dependency from `libcxxabi` and
`libunwind`. These libraries do not use any runtime `libcxx` functions,
just headers.

* libc: Remove remaining redundant cxa functions

- `__cxa_pure_virtual` in `libcxxabi` is also a stub similar to the
existing one.
- `__cxa_guard_*` from `libcxxabi` is used instead of the ones from
Android.

Now there should be no more duplicate implementations.
`__cxa_thread_atexit_impl`, `__cxa_atexit`, and related supporting
functions, are still left to other libraries as in `libcxxabi`.

`libcxxabi` is also now added to `cosmopolitan.a` to make up for the
removed functions.

Affected in-tree libraries (`third_party/double-conversion`) have been
updated.
2024-01-08 08:45:10 -08:00
Trung Nguyen 94bab1618d Add fixes to libunwind (#1069) 2024-01-08 08:31:13 -08:00
Jōshin cafea9a0a5 Flesh out tool/zsh/mkofs
It now prevents double-mounting.

Also adds vim filetype modelines.
2024-01-08 05:18:18 +00:00
Jōshin 16099801cc zsh mkofs tool 2024-01-08 03:43:09 +00:00
Justine Tunney 4cd02c29ed Release Cosmopolitan v3.2.3 2024-01-07 12:39:09 -08:00
Justine Tunney 5ae2554c10 Have cosmo_dlopen() request -z execstack on Linux
The AMD HIP SDK for Linux ships prebuilt DSOs with an RWX PT_GNU_STACK
since old versions of GCC made it nearly impossible to build artifacts
where that wasn't the case, however modern glibc systems will flat out
refuse to link RWX DSOs from an execuatble that uses PT_GNU_STACK = RW
2024-01-07 11:37:18 -08:00
Justine Tunney 531ac85923 Disable Python test_resource
It fails strangely on some Linux systems due to constraints imposed by
the build system. We'll try to learn more about this later on.
2024-01-07 11:36:31 -08:00
Jōshin 8d9fcb5e5a Fix ape-m1.c usage
It's not about `$0` anymore.
2024-01-07 10:35:50 -05:00
Jōshin aa37a327ea Make $prog.ape more reliable on Apple Silicon (#1071)
Now it doesn't matter what argv `$prog.ape` is invoked with. We just get
our executable path the Apple way.
2024-01-07 07:13:20 -08:00
Justine Tunney c4205f8305 Remove lingering dlopen thunk 2024-01-07 02:14:41 -08:00
Justine Tunney b3fb6cff43 Add /dev/fd support to Windows
GNU bash needs this functionality, otherwise it can't do <(cmd...).
2024-01-06 18:20:21 -08:00
Jōshin 2e5f662dfe mmake: different cosmocc regime
Now that cosmocc is unpacked into a version-specific directory under
cosmocc/, it makes more sense to put the versions in /opt/cosmocc and
maintain a symlink to the currently active one.
2024-01-06 19:14:13 -05:00
Justine Tunney 5e7137097d Make breaking change to cosmo_dlsym()
The cosmo_dlsym() function now returns the raw function address. You
need to call cosmo_dltramp() on the result, to make it safe to call.
This change is important, because cosmo_dltramp() magic can't always
work; for some tricky functions, you need to translate ABIs by hand.
2024-01-06 15:45:26 -08:00
Justine Tunney f224a55d57 Fix MODE=dbg build
Fixes #1067
2024-01-06 15:22:19 -08:00
Justine Tunney 0c51995b2b Add missing sha256sum.c file 2024-01-06 14:47:14 -08:00
Jōshin a9f23ccd17 Fix download-cosmocc.sh on Mac (#1066)
shasum behaves enough like sha256sum to work in this case.
2024-01-06 14:46:31 -08:00
Justine Tunney 57d1bf7a9c Clarify CONTRIBUTING.md 2024-01-06 14:18:01 -08:00
Justine Tunney ce17ed60df Support -MF and -MT in cosmocc 2024-01-06 12:10:06 -08:00
Jōshin d27a47b0e2 Bugfix: ape --help should exit 0 (#1060) 2024-01-06 12:07:32 -08:00
Jōshin 390335eb45 apeinstall/uninstall.sh can use doas (#1062) 2024-01-06 12:06:21 -08:00
Jōshin 492a8f4f53 Fix make o/aarch64/ape on aarch64 (#1064) 2024-01-06 11:42:39 -08:00
Jōshin 636bc4007b Enable argv[0] tests in more places (#1061)
Now we do them for assimilated binaries (except on OpenBSD or XNU
non-Silicon), for XnuSilicon, and for binaries with the preserve-
argv[0] auxv flag set. We check whether to pass the argv[0] value
at the test site rather than the Child site. We move a lot of the
test initialization into Child in the non-child case, in order to
get at the pre-init value of `__program_executable_name`. Finally,
we print out info about what we are skipping.
2024-01-06 11:42:03 -08:00
Trung Nguyen b09096691a third_party: Add libunwind (#1053)
Added libunwind from LLVM 17.0.6.
The library includes functions required for C++ exception handling.
2024-01-06 15:04:30 +07:00
Justine Tunney 91de6f1f5d Release Cosmopolitan 3.2.2 2024-01-05 21:00:22 -08:00
Justine Tunney fad1279c61 Make cosmo_dlopen() safer and faster
If cosmo_dlopen() is linked on AMD64 then the runtime will switch to
using %gs for thread-local storage. This eliminates the need for the
imported symbol trampoline. It's now safer to pass function pointers
back and forth with imported libraries. Your program gets recompiled
at runtime to make it happen and the overhead is a few milliseconds.
2024-01-05 20:42:19 -08:00
Jōshin c0eacf2eb1 clang-format 2024-01-05 23:21:52 -05:00
Justine Tunney c60b150fcf Release Cosmopolitan v3.2.1 2024-01-05 15:36:57 -08:00
Jōshin 80ec6c9283 Try to detect kernel version for P flag (#1059) 2024-01-05 15:19:46 -08:00
Justine Tunney 2d93788ce3 Fix --ftrace with cosmo_dlopen()
This change ensures function call logging won't crash the process when
cosmo_dlopen() is called.
2024-01-05 15:13:07 -08:00
Jōshin 15548b523c Cleanup apeinstall.sh (#1057) 2024-01-05 13:45:14 -08:00
Jōshin 412a200ae4 Support binfmt_misc P flag in APE loader (#1058)
This allows ape to automatically preserve `argv[0]` [as of Linux kernel
5.12][0] if the [binfmt_misc][1] registration contains the P flag.

This also removes may_path_search, which was identical to the literally
flag in usage. As a result, FindCommand is subsumed into Commandv.

[0]: https://patchew.org/QEMU/[email protected]/
[1]: https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html
2024-01-05 12:35:01 -08:00
Justine Tunney 44a463e4d2 Invent *cosmo_dltramp() function 2024-01-05 09:11:51 -08:00
Justine Tunney 0de6a08988 Upgrade mono repo to cosmocc 3.2
The toolchain will now be downloaded going forward from multiple pinned
URLs which have shasums. Either wget or curl must be installed.

This change unblocks #1053
2024-01-05 08:02:04 -08:00
Paul Kulchenko a334f9cc33 Update redbean ProgramDirectory to return a list of previously set directories (#1021) 2024-01-05 02:17:55 -08:00
Jōshin 3315b6ef11 Store StrlenDevFd in n (#1056) 2024-01-04 23:17:37 -05:00
Justine Tunney e93c8c4f8f Fix typo 2024-01-04 13:59:36 -08:00
Justine Tunney 0e49bed660 Support 40 cosmo_dlopen() function parameters
Our dynamic linking implementation is now able to support functions with
dozens of parameters. In addition to having extra integral arguments you
can now pass vector registers using intrinsic types. Lastly, you can now
return multiple values, which is useful for functions returning structs.
2024-01-04 13:41:26 -08:00
536 changed files with 78375 additions and 21708 deletions

No files matched your search

+2 -1
View File
@@ -1,7 +1,8 @@
# -*- conf -*-
/o
/.prompt.jtlp
/cosmocc
/.cosmocc
# TODO: Find some way to have Python write to o/
__pycache__
+32 -14
View File
@@ -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
+81 -17
View File
@@ -73,10 +73,13 @@ MODE := $(m)
endif
endif
COMMA := ,
PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran build/bootstrap/make.com, in which case make's working directory is in wsl
# - user ran make, in which case cocmd.com's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(shell pwd)),)
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
$(warning wsl2 interop is enabled)
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
endif
@@ -89,14 +92,33 @@ ifeq ($(MAKE_VERSION), 3.81)
$(error please use build/bootstrap/make.com)
endif
# provide instructions to non-linux users on unbundling gcc
ifeq ($(TOOLCHAIN),) # if TOOLCHAIN isn't defined
ifeq ("$(wildcard o/third_party/gcc/bin/x86_64-linux-cosmo-*)","") # if our gcc isn't unbundled
ifneq ($(UNAME_M)-$(UNAME_S), x86_64-Linux) # if this is not amd64 linux
$(error please run tool/cosmocc/fetch.sh)
endif
endif
endif
LC_ALL = C
SOURCE_DATE_EPOCH = 0
ARFLAGS = rcsD
ZFLAGS ?=
XARGS ?= xargs -P4 -rs8000
DOT ?= dot
CLANG = clang
TMPDIR = o/tmp
AR = build/bootstrap/ar.com
CP = build/bootstrap/cp.com
RM = build/bootstrap/rm.com -f
GZIP = build/bootstrap/gzip.com
ECHO = build/bootstrap/echo.com
CHMOD = build/bootstrap/chmod.com
TOUCH = build/bootstrap/touch.com
PKG = build/bootstrap/package.com
MKDEPS = build/bootstrap/mkdeps.com
ZIPOBJ = build/bootstrap/zipobj.com
ZIPCOPY = build/bootstrap/zipcopy.com
PECHECK = build/bootstrap/pecheck.com
FIXUPOBJ = build/bootstrap/fixupobj.com
MKDIR = build/bootstrap/mkdir.com -p
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
IGNORE := $(shell $(MKDIR) $(TMPDIR))
# the default build modes is empty string
# on x86_64 hosts, MODE= is the same as MODE=x86_64
@@ -110,6 +132,44 @@ MODE := aarch64
endif
endif
ifneq ($(findstring aarch64,$(MODE)),)
ARCH = aarch64
HOSTS ?= pi studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu win10 openbsd netbsd
endif
ZIPOBJ_FLAGS += -a$(ARCH)
IGNORE := $(shell $(MKDIR) $(TMPDIR))
export ADDR2LINE
export LC_ALL
export MKDIR
export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
COSMOCC = .cosmocc/3.2
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.2 28b48682595f0f46b45ab381118cdffdabc8fcfa29aa54e301fe6ffe35269f5e)
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
CXX = $(TOOLCHAIN)g++
CXXFILT = $(TOOLCHAIN)c++filt
LD = $(TOOLCHAIN)ld.bfd
NM = $(TOOLCHAIN)nm
GCC = $(TOOLCHAIN)gcc
STRIP = $(TOOLCHAIN)strip
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
ifneq ($(wildcard $(PWD)/$(TOOLCHAIN)addr2line),)
ADDR2LINE = $(PWD)/$(TOOLCHAIN)addr2line
else
ADDR2LINE = $(TOOLCHAIN)addr2line
endif
# primary build rules
all: o
o: o/$(MODE)
@@ -138,7 +198,7 @@ $(warning please run ape/apeinstall.sh if you intend to use landlock make)
$(shell sleep .5)
endif
endif
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
ifneq ($(TOOLCHAIN),)
.STRICT = 1
endif
endif
@@ -149,8 +209,8 @@ endif
libc/stdbool.h \
libc/disclaimer.inc \
rwc:/dev/shm \
rx:cosmocc \
rx:build/bootstrap \
rx:o/third_party/gcc \
r:build/portcosmo.h \
/proc/stat \
rw:/dev/null \
@@ -189,7 +249,6 @@ include libc/calls/BUILD.mk #─┐
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
include third_party/nsync/BUILD.mk # │ You can issue system calls
include libc/runtime/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │
include libc/crt/BUILD.mk # │
include third_party/dlmalloc/BUILD.mk #─┘
include libc/mem/BUILD.mk #─┐
@@ -224,7 +283,10 @@ include third_party/stb/BUILD.mk # │
include third_party/mbedtls/BUILD.mk # │
include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include third_party/libcxx/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │
include third_party/pcre/BUILD.mk # │
include third_party/less/BUILD.mk # │
include net/https/BUILD.mk # │
@@ -268,6 +330,7 @@ include third_party/python/BUILD.mk
include tool/build/BUILD.mk
include tool/curl/BUILD.mk
include third_party/qemu/BUILD.mk
include third_party/libcxxabi/test/BUILD.mk
include examples/BUILD.mk
include examples/pyapp/BUILD.mk
include examples/pylife/BUILD.mk
@@ -380,6 +443,8 @@ COSMOPOLITAN_OBJECTS = \
LIBC_TIME \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB_GZ \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
LIBC_STDIO \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
@@ -449,12 +514,14 @@ COSMOPOLITAN_H_PKGS = \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
THIRD_PARTY_REGEX
COSMOCC_PKGS = \
$(COSMOPOLITAN_H_PKGS) \
THIRD_PARTY_AARCH64 \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_INTEL
o/$(MODE)/cosmopolitan.a: \
@@ -479,18 +546,15 @@ o/cosmopolitan.h: o/cosmopolitan.h.txt \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_INCS))
@$(ECHO) '#ifndef __STRICT_ANSI__' >$@
@$(ECHO) '#define _COSMO_SOURCE' >>$@
@$(ECHO) '#endif' >>$@
@$(COMPILE) -AROLLUP -T$@ build/bootstrap/rollup.com @$< >>$@
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
$(SRCS) \
$(filter-out %.cc,$(SRCS)) \
$(HDRS)
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))))
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
-fno-common -include libc/integral/normalize.inc -o $@ \
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
+6 -17
View File
@@ -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
View File
@@ -103,36 +103,39 @@ struct Syslib {
char *(*dlerror)(void);
};
#define ELFCLASS32 1
#define ELFDATA2LSB 1
#define EM_AARCH64 183
#define ET_EXEC 2
#define ET_DYN 3
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define EI_CLASS 4
#define EI_DATA 5
#define PF_X 1
#define PF_W 2
#define PF_R 4
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_ENTRY 9
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_HWCAP 16
#define AT_HWCAP2 16
#define AT_SECURE 23
#define AT_RANDOM 25
#define AT_EXECFN 31
#define ELFCLASS32 1
#define ELFDATA2LSB 1
#define EM_AARCH64 183
#define ET_EXEC 2
#define ET_DYN 3
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define EI_CLASS 4
#define EI_DATA 5
#define PF_X 1
#define PF_W 2
#define PF_R 4
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
#define AT_ENTRY 9
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_HWCAP 16
#define AT_HWCAP2 16
#define AT_SECURE 23
#define AT_RANDOM 25
#define AT_EXECFN 31
#define AUXV_WORDS 29
#define AUXV_WORDS 31
/* from the xnu codebase */
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
@@ -322,17 +325,7 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
memmove(ps->path + pathlen, ps->name, ps->namelen);
ps->path[pathlen + ps->namelen] = 0;
if (!access(ps->path, X_OK)) {
if (ps->indirect) {
ps->namelen -= 4;
ps->path[pathlen + ps->namelen] = 0;
if (access(ps->path, X_OK) < 0) {
Pexit(ps->path, -errno, "access(X_OK)");
}
}
return 1;
}
return 0;
return !access(ps->path, X_OK);
}
static char SearchPath(struct PathSearcher *ps) {
@@ -358,12 +351,8 @@ static char FindCommand(struct PathSearcher *ps) {
ps->path[0] = 0;
/* paths are always 100% taken literally when a slash exists
$ ape foo/bar.com arg1 arg2 */
if (memchr(ps->name, '/', ps->namelen)) {
return AccessCommand(ps, 0);
}
/* we don't run files in the current directory
$ ape foo/bar.com arg1 arg2
we don't run files in the current directory
$ ape foo.com arg1 arg2
unless $PATH has an empty string entry, e.g.
$ expert PATH=":/bin"
@@ -371,8 +360,8 @@ static char FindCommand(struct PathSearcher *ps) {
however we will execute this
$ ape - foo.com foo.com arg1 arg2
because cosmo's execve needs it */
if (ps->literally && AccessCommand(ps, 0)) {
return 1;
if (ps->literally || memchr(ps->name, '/', ps->namelen)) {
return AccessCommand(ps, 0);
}
/* otherwise search for name on $PATH */
@@ -382,7 +371,8 @@ static char FindCommand(struct PathSearcher *ps) {
static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
ps->name = name;
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (FindCommand(ps)) {
return ps->path;
@@ -861,25 +851,27 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
auxv[7] = ebuf->ehdr.e_entry;
auxv[8] = AT_PAGESZ;
auxv[9] = pagesz;
auxv[10] = AT_UID;
auxv[11] = getuid();
auxv[12] = AT_EUID;
auxv[13] = geteuid();
auxv[14] = AT_GID;
auxv[15] = getgid();
auxv[16] = AT_EGID;
auxv[17] = getegid();
auxv[18] = AT_HWCAP;
auxv[19] = 0xffb3ffffu;
auxv[20] = AT_HWCAP2;
auxv[21] = 0x181;
auxv[22] = AT_SECURE;
auxv[23] = issetugid();
auxv[24] = AT_RANDOM;
auxv[25] = (long)M->rando;
auxv[26] = AT_EXECFN;
auxv[27] = (long)execfn;
auxv[28] = 0;
auxv[10] = AT_FLAGS;
auxv[11] = M->ps.literally ? AT_FLAGS_PRESERVE_ARGV0 : 0;
auxv[12] = AT_UID;
auxv[13] = getuid();
auxv[14] = AT_EUID;
auxv[15] = geteuid();
auxv[16] = AT_GID;
auxv[17] = getgid();
auxv[18] = AT_EGID;
auxv[19] = getegid();
auxv[20] = AT_HWCAP;
auxv[21] = 0xffb3ffffu;
auxv[22] = AT_HWCAP2;
auxv[23] = 0x181;
auxv[24] = AT_SECURE;
auxv[25] = issetugid();
auxv[26] = AT_RANDOM;
auxv[27] = (long)M->rando;
auxv[28] = AT_EXECFN;
auxv[29] = (long)execfn;
auxv[30] = 0;
/* we're now ready to load */
Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path);
@@ -891,7 +883,7 @@ int main(int argc, char **argv, char **envp) {
struct ApeLoader *M;
long *sp, *sp2, *auxv;
union ElfEhdrBuf *ebuf;
char *p, *pe, *exe, *prog, *execfn, *shell;
char *p, *pe, *exe, *prog, *execfn;
/* allocate loader memory in program's arg block */
n = sizeof(struct ApeLoader);
@@ -954,12 +946,16 @@ int main(int argc, char **argv, char **envp) {
M->lib.dlerror = dlerror;
/* getenv("_") is close enough to at_execfn */
execfn = argc > 0 ? argv[0] : 0;
execfn = 0;
for (i = 0; envp[i]; ++i) {
if (envp[i][0] == '_' && envp[i][1] == '=') {
execfn = envp[i] + 2;
}
}
prog = GetEnv(envp + i + 1, "executable_path");
if (!execfn) {
execfn = prog;
}
/* sneak the system five abi back out of args */
sp = (long *)(argv - 1);
@@ -981,8 +977,8 @@ int main(int argc, char **argv, char **envp) {
sp = sp2;
/* interpret command line arguments */
if ((M->ps.indirect = argc > 0 ? GetIndirectOffset(argv[0]) : 0)) {
/* if argv[0] is $prog.ape, then we strip off the .ape and run
if ((M->ps.indirect = GetIndirectOffset(prog))) {
/* if called as $prog.ape, then strip off the .ape and run the
$prog. This allows you to use symlinks to trick the OS when
a native executable is required. For example, let's say you
want to use the APE binary /opt/cosmos/bin/bash as a system
@@ -991,13 +987,7 @@ int main(int argc, char **argv, char **envp) {
but it will if you say:
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
and then use #!/opt/cosmos/bin/bash.ape instead. */
M->ps.literally = 0;
if (*argv[0] == '-' && (shell = GetEnv(envp, "SHELL")) &&
!StrCmp(argv[0] + 1, BaseName(shell))) {
execfn = prog = shell;
} else {
prog = (char *)sp[1];
}
M->ps.literally = 1;
argc = sp[0];
argv = (char **)(sp + 1);
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
@@ -1011,7 +1001,7 @@ int main(int argc, char **argv, char **envp) {
} else if (argc < 2) {
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
" ape - PROG [ARGV0,ARGV1,...]\n"
" ($0 = PROG.ape) [ARGV1,ARGV2,...]\n"
" PROG.ape [ARGV1,ARGV2,...]\n"
"actually portable executable loader silicon 1.10\n"
"copyrights 2023 justine alexandra roberts tunney\n"
"https://justine.lol/ape.html\n");
+58 -33
View File
@@ -10,73 +10,98 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x build/bootstrap/make.com ]; then
MAKE=build/bootstrap/make.com
else
MAKE=make
fi
if [ "$(id -u)" -eq 0 ]; then
SUDO=
else
elif command -v sudo >/dev/null 2>&1; then
SUDO=sudo
elif command -v doas >/dev/null 2>&1; then
SUDO=doas
else
echo "need root or sudo" >&2
exit
fi
if command -v install >/dev/null 2>&1; then
if [ x"$(uname -s)" = xLinux ]; then
INSTALL="install -o root -g root -m 755"
else
INSTALL="install -o root -g wheel -m 755"
fi
else
INSTALL="cp -f"
fi
echo "Actually Portable Executable (APE) Installer" >&2
echo "Author: Justine Tunney <[email protected]>" >&2
# special installation process for apple silicon
if [ "$(uname -s)" = "Darwin" ] && [ "$(uname -m)" = "arm64" ]; then
if [ x"$(uname -s)" = xDarwin ] && [ x"$(uname -m)" = xarm64 ]; then
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
trap 'rm "$TMPDIR/ape.$$"' EXIT
if [ ! -d /usr/local/bin ]; then
echo "$SUDO mkdir -p /usr/local/bin" >&2
$SUDO mkdir -p /usr/local/bin || exit
fi
echo "$SUDO mv -f $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
$SUDO mv -f "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
echo "$SUDO $INSTALL $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
$SUDO $INSTALL "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
exit
fi
if [ x"$(uname -m)" = xarm64 ] || [ x"$(uname -m)" = xaarch64 ]; then
MODE=aarch64
EXT=elf
BEXT=aarch64
elif [ x"$(uname -m)" = xx86_64 ]; then
MODE=
if [ x"$(uname -s)" = xDarwin ]; then
EXT=macho
else
EXT=elf
fi
BEXT=$EXT
else
echo "unsupported architecture $(uname -m)" >&2
exit
fi
################################################################################
# INSTALL APE LOADER SYSTEMWIDE
if [ -f o/depend ] && make -j8 o//ape; then
if [ -f o/$MODE/depend ] && $MAKE -j8 o/$MODE/ape; then
echo "successfully recompiled ape loader" >&2
elif [ -x o//ape/ape.elf ] && [ -x o//ape/ape.macho ]; then
elif [ -x o/$MODE/ape/ape.$EXT ]; then
echo "using ape loader you compiled earlier" >&2
elif [ -d build/bootstrap ]; then
# if make isn't being used then it's unlikely the user changed the sources
# in that case the prebuilt binaries should be completely up-to-date
echo "using prebuilt ape loader from cosmo repo" >&2
mkdir -p o//ape || exit
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
mkdir -p o/$MODE/ape || exit
cp -af build/bootstrap/ape.$BEXT o/$MODE/ape/ape.$EXT || exit
else
echo "no cosmopolitan libc repository here" >&2
echo "fetching ape loader from justine.lol" >&2
mkdir -p o//ape || exit
echo "fetching ape loader from justine.lol" >&2
mkdir -p o/$MODE/ape || exit
if command -v wget >/dev/null 2>&1; then
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
wget -qO o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
else
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
curl -Rso o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
fi
chmod +x o//ape/ape.elf || exit
chmod +x o//ape/ape.macho || exit
chmod +x o/$MODE/ape/ape.$EXT || exit
fi
if [ "$(uname -s)" = "Darwin" ]; then
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
echo >&2
echo "installing o//ape/ape.macho to /usr/bin/ape" >&2
echo "$SUDO cp -f o//ape/ape.macho /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
echo "done" >&2
fi
else
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
echo >&2
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
echo "done" >&2
fi
if ! [ /usr/bin/ape -nt o/$MODE/ape/ape.$EXT ]; then
echo >&2
echo "installing o/$MODE/ape/ape.$EXT to /usr/bin/ape" >&2
echo "$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape" >&2
$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape || exit
echo "done" >&2
fi
################################################################################
+6 -1
View File
@@ -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
View File
@@ -113,41 +113,44 @@
#define EXTERN_C
#endif
#define O_RDONLY 0
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_FIXED 16
#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096)
#define MAP_NORESERVE (IsLinux() ? 16384 : 0)
#define ELFCLASS32 1
#define ELFDATA2LSB 1
#define EM_NEXGEN32E 62
#define EM_AARCH64 183
#define ET_EXEC 2
#define ET_DYN 3
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define EI_CLASS 4
#define EI_DATA 5
#define PF_X 1
#define PF_W 2
#define PF_R 4
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_EXECFN_LINUX 31
#define AT_EXECFN_NETBSD 2014
#define X_OK 1
#define XCR0_SSE 2
#define XCR0_AVX 4
#define PR_SET_MM 35
#define PR_SET_MM_EXE_FILE 13
#define O_RDONLY 0
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_FIXED 16
#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096)
#define MAP_NORESERVE (IsLinux() ? 16384 : 0)
#define ELFCLASS32 1
#define ELFDATA2LSB 1
#define EM_NEXGEN32E 62
#define EM_AARCH64 183
#define ET_EXEC 2
#define ET_DYN 3
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define EI_CLASS 4
#define EI_DATA 5
#define PF_X 1
#define PF_W 2
#define PF_R 4
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_FLAGS 8
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
#define AT_EXECFN_LINUX 31
#define AT_EXECFN_NETBSD 2014
#define X_OK 1
#define XCR0_SSE 2
#define XCR0_AVX 4
#define PR_SET_MM 35
#define PR_SET_MM_EXE_FILE 13
#define READ32(S) \
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
@@ -572,39 +575,15 @@ static char SearchPath(struct PathSearcher *ps) {
}
}
static char FindCommand(struct PathSearcher *ps) {
ps->path[0] = 0;
/* paths are always 100% taken literally when a slash exists
$ ape foo/bar.com arg1 arg2 */
if (MemChr(ps->name, '/', ps->namelen)) {
return AccessCommand(ps, 0);
}
/* we don't run files in the current directory
$ ape foo.com arg1 arg2
unless $PATH has an empty string entry, e.g.
$ expert PATH=":/bin"
$ ape foo.com arg1 arg2
however we will execute this
$ ape - foo.com foo.com arg1 arg2
because cosmo's execve needs it */
if (ps->literally && AccessCommand(ps, 0)) {
return 1;
}
/* otherwise search for name on $PATH */
return SearchPath(ps);
}
static char *Commandv(struct PathSearcher *ps, int os, char *name,
const char *syspath, int may_path_search) {
if (!may_path_search) return name;
const char *syspath) {
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
if (ps->literally || MemChr(ps->name, '/', ps->namelen)) return name;
ps->os = os;
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
if (FindCommand(ps)) {
ps->path[0] = 0;
if (SearchPath(ps)) {
return ps->path;
} else {
return 0;
@@ -897,7 +876,7 @@ __attribute__((__noreturn__)) static void ShowUsage(int os, int fd, int rc) {
"NAME\n"
"\n"
" actually portable executable loader version " APE_VERSION_STR "\n"
" copyright 2023 justine alexandra roberts tunney\n"
" copyrights 2024 justine alexandra roberts tunney\n"
" https://justine.lol/ape.html\n"
"\n"
"USAGE\n"
@@ -913,10 +892,10 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
char dl) {
int rc, n;
unsigned i;
char literally;
const char *ape;
int c, fd, os, argc;
struct ApeLoader *M;
char arg0, literally;
unsigned long pagesz;
union ElfEhdrBuf *ebuf;
long *auxv, *ap, *endp, *sp2;
@@ -961,11 +940,15 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
/* detect netbsd and find end of words */
pagesz = 0;
arg0 = 0;
for (ap = auxv; ap[0]; ap += 2) {
if (ap[0] == AT_PAGESZ) {
pagesz = ap[1];
} else if (SupportsNetbsd() && !os && ap[0] == AT_EXECFN_NETBSD) {
os = NETBSD;
} else if (SupportsLinux() && ap[0] == AT_FLAGS) {
// TODO(mrdomino): maybe set/insert this when we are called as "ape -".
arg0 = !!(ap[1] & AT_FLAGS_PRESERVE_ARGV0);
}
}
if (!pagesz) {
@@ -979,8 +962,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
}
/* we can load via shell, shebang, or binfmt_misc */
int may_path_search = 1;
if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
if (arg0) {
literally = 1;
prog = (char *)sp[2];
argc = sp[2] = sp[0] - 2;
argv = (char **)((sp += 2) + 1);
} else if ((literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
/* if the first argument is a hyphen then we give the user the
power to change argv[0] or omit it entirely. most operating
systems don't permit the omission of argv[0] but we do, b/c
@@ -988,12 +975,12 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
prog = (char *)sp[3];
argc = sp[3] = sp[0] - 3;
argv = (char **)((sp += 3) + 1);
may_path_search = 0;
} else if (argc < 2) {
ShowUsage(os, 2, 1);
} else {
if (argv[1][0] == '-') {
rc = !(argv[1][1] == 'h' && !argv[1][2]) || !StrCmp(argv[1] + 1, "-help");
rc = !((argv[1][1] == 'h' && !argv[1][2]) ||
!StrCmp(argv[1] + 1, "-help"));
ShowUsage(os, 1 + rc, rc);
}
prog = (char *)sp[2];
@@ -1029,8 +1016,7 @@ EXTERN_C __attribute__((__noreturn__)) void ApeLoader(long di, long *sp,
}
/* resolve path of executable and read its first page */
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH"),
may_path_search))) {
if (!(exe = Commandv(&M->ps, os, prog, GetEnv(envp, "PATH")))) {
Pexit(os, prog, 0, "not found (maybe chmod +x or ./ needed)");
} else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) {
Pexit(os, exe, fd, "open");
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-85
View File
@@ -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
+101
View File
@@ -0,0 +1,101 @@
#!/bin/sh
# cosmocc downloader script
# https://justine.lol/cosmo3/#install
# https://github.com/jart/cosmopolitan/blob/master/tool/cosmocc/README.md
# collect arguments
OUTPUT_DIR=${1:?OUTPUT_DIR}
COSMOCC_VERSION=${2:?COSMOCC_VERSION}
COSMOCC_SHA256SUM=${3:?COSMOCC_SHA256SUM}
URL1="https://github.com/jart/cosmopolitan/releases/download/${COSMOCC_VERSION}/cosmocc-${COSMOCC_VERSION}.zip"
URL2="https://cosmo.zip/pub/cosmocc/cosmocc-${COSMOCC_VERSION}.zip"
# helper function
abort() {
printf '%s\n' "download terminated." >&2
exit 1
}
# exit if already downloaded
# we need it because directory timestamps work wierdly
OUTPUT_DIR=${OUTPUT_DIR%/}
if [ -d "${OUTPUT_DIR}" ]; then
exit 0
fi
# find commands we need to securely download cosmocc
if ! UNZIP=$(command -v unzip 2>/dev/null); then
printf '%s\n' "$0: fatal error: you need the unzip command" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/unzip and put it on the system path" >&2
abort
fi
if command -v sha256sum >/dev/null 2>&1; then
# can use system sha256sum
true
elif command -v shasum >/dev/null 2>&1; then
sha256sum() {
shasum -a 256 "$@"
}
else
if [ ! -f build/sha256sum.c ]; then
printf '%s\n' "$0: fatal error: you need to install sha256sum" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
abort
fi
if ! SHA256SUM=$(command -v "$PWD/o/build/sha256sum" 2>/dev/null); then
if ! CC=$(command -v "$CC" 2>/dev/null); then
if ! CC=$(command -v cc 2>/dev/null); then
if ! CC=$(command -v cosmocc 2>/dev/null); then
printf '%s\n' "$0: fatal error: you need to install either sha256sum, cc, or cosmocc" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
abort
fi
fi
fi
mkdir -p o/build || abort
SHA256SUM="$PWD/o/build/sha256sum"
printf '%s\n' "${CC} -w -O2 -o ${SHA256SUM} build/sha256sum.c" >&2
"${CC}" -w -O2 -o "${SHA256SUM}.$$" build/sha256sum.c || abort
mv -f "${SHA256SUM}.$$" "${SHA256SUM}" || abort
fi
sha256sum() {
"${SHA256SUM}" "$@"
}
fi
if WGET=$(command -v wget 2>/dev/null); then
DOWNLOAD=$WGET
DOWNLOAD_ARGS=-O
elif CURL=$(command -v curl 2>/dev/null); then
DOWNLOAD=$CURL
DOWNLOAD_ARGS=-fLo
else
printf '%s\n' "$0: fatal error: you need to install either wget or curl" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/wget and put it on the system path" >&2
abort
fi
# create temporary output directory
OLDPWD=$PWD
OUTPUT_TMP="${OUTPUT_DIR}.tmp.$$/"
mkdir -p "${OUTPUT_TMP}" || abort
cd "${OUTPUT_TMP}"
die() {
cd "${OLDPWD}"
rm -rf "${OUTPUT_TMP}"
abort
}
# download cosmocc toolchain
# multiple urls avoids outages and national firewalls
if ! "${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL1}"; then
rm -f cosmocc.zip
"${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL2}" || die
fi
printf '%s\n' "${COSMOCC_SHA256SUM} *cosmocc.zip" >cosmocc.zip.sha256sum
sha256sum -c cosmocc.zip.sha256sum || die
"${UNZIP}" cosmocc.zip || die
rm -f cosmocc.zip cosmocc.zip.sha256sum
# commit output directory
cd "${OLDPWD}" || die
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
+1 -1
View File
@@ -66,7 +66,7 @@ set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
# struct WorstSoftwareEver;
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
exec $TAGS \
build/run $TAGS \
-e \
--langmap=c:.c.h \
--exclude=libc/nt/struct/imagefileheader.internal.h \
+8 -8
View File
@@ -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
+4 -5
View File
@@ -1,9 +1,8 @@
#!/bin/sh
if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then
make -j8 o/third_party/qemu/qemu-aarch64
fi
exec o/third_party/qemu/qemu-aarch64 "$@"
UNAMEM=$(uname -m)
UNAMES=$(uname -s)
if [ x"$UNAMES" = x"Darwin" ] && [ x"$UNAMEM" = x"arm64" ]; then
exec ape "$@"
else
exec "$@"
fi
+443
View File
@@ -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;
}
+1 -1
View File
@@ -27,7 +27,7 @@
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
+1 -1
View File
@@ -18,7 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/tty/tty.h"
#include "libc/mem/arraylist2.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/x/x.h"
+1 -1
View File
@@ -25,7 +25,7 @@
#include "libc/calls/ucontext.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
+2 -2
View File
@@ -285,7 +285,7 @@ int main(int argc, char *argv[]) {
// print all the ips that 0.0.0.0 would bind
// Cosmo's GetHostIps() API is much easier than ioctl(SIOCGIFCONF)
uint32_t *hostips;
for (hostips = _gc(GetHostIps()), i = 0; hostips[i]; ++i) {
for (hostips = gc(GetHostIps()), i = 0; hostips[i]; ++i) {
kprintf("listening on http://%hhu.%hhu.%hhu.%hhu:%hu\n", hostips[i] >> 24,
hostips[i] >> 16, hostips[i] >> 8, hostips[i], PORT);
}
@@ -339,7 +339,7 @@ int main(int argc, char *argv[]) {
unassert(!pthread_attr_setguardsize(&attr, pagesz));
unassert(!pthread_attr_setsigmask_np(&attr, &block));
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));
pthread_t *th = _gc(calloc(threads, sizeof(pthread_t)));
pthread_t *th = gc(calloc(threads, sizeof(pthread_t)));
for (i = 0; i < threads; ++i) {
int rc;
++a_workers;
+1 -1
View File
@@ -50,7 +50,7 @@ void List(const char *path) {
if (strcmp(path, ".") == 0) {
vpath = "";
} else if (!endswith(path, "/")) {
vpath = _gc(xasprintf("%s/", path));
vpath = gc(xasprintf("%s/", path));
} else {
vpath = path;
}
+4 -4
View File
@@ -80,10 +80,10 @@ void PrintFileMetadata(const char *pathname, struct stat *st) {
DescribeFileType(st->st_mode), "owner id", st->st_uid, "group id",
st->st_gid, "flags", st->st_flags, "gen", st->st_gen,
"device id (if special)", st->st_rdev, "block size", st->st_blksize,
"access time", _gc(xiso8601(&st->st_atim)), "modified time",
_gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
_gc(xiso8601(&st->st_ctim)), "birthtime",
_gc(xiso8601(&st->st_birthtim)));
"access time", gc(xiso8601(&st->st_atim)), "modified time",
gc(xiso8601(&st->st_mtim)), "c[omplicated]time",
gc(xiso8601(&st->st_ctim)), "birthtime",
gc(xiso8601(&st->st_birthtim)));
}
int main(int argc, char *argv[]) {
+1 -1
View File
@@ -128,7 +128,7 @@
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/mem/alloca.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
+18
View File
@@ -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();
}
+7 -6
View File
@@ -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;
}
+2
View File
@@ -88,12 +88,14 @@ static ssize_t GetDevUrandom(char *p, size_t n) {
int fd;
ssize_t rc;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
fd = sys_openat(AT_FDCWD, "/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
if (fd != -1) {
rc = sys_read(fd, p, n);
} else {
rc = -1;
}
ALLOW_CANCELATION;
ALLOW_SIGNALS;
return rc;
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -181,10 +181,25 @@ static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
}
}
static int Atoi(const char *str) {
int c;
unsigned x = 0;
if (!*str) return -1;
while ((c = *str++)) {
if ('0' <= c && c <= '9') {
x *= 10;
x += c - '0';
} else {
return -1;
}
}
return x;
}
textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
int32_t mode) {
int fd;
ssize_t rc;
int fd, oldfd;
BLOCK_SIGNALS;
__fds_lock();
if (!(flags & _O_CREAT)) mode = 0;
@@ -200,6 +215,9 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
rc = sys_open_nt_dup(fd, flags, mode, STDOUT_FILENO);
} else if (!strcmp(file + 5, "stderr")) {
rc = sys_open_nt_dup(fd, flags, mode, STDERR_FILENO);
} else if (startswith(file + 5, "fd/") &&
(oldfd = Atoi(file + 8)) != -1) {
rc = sys_open_nt_dup(fd, flags, mode, oldfd);
} else {
rc = enoent();
}
+1 -1
View File
@@ -53,7 +53,7 @@ int _mkstemp(char *, int);
* On newer Linux only (c. 2013) it's possible to turn the anonymous
* returned file back into a real file, by doing this:
*
* linkat(AT_FDCWD, _gc(xasprintf("/proc/self/fd/%d", fd)),
* linkat(AT_FDCWD, gc(xasprintf("/proc/self/fd/%d", fd)),
* AT_FDCWD, "real.txt", AT_SYMLINK_FOLLOW)
*
* On the New Technology, temporary files created by this function
+11 -2
View File
@@ -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))
+1
View File
@@ -20,6 +20,7 @@ int dlclose(void *);
char *cosmo_dlerror(void);
void *cosmo_dlopen(const char *, int);
void *cosmo_dlsym(void *, const char *);
void *cosmo_dltramp(void *);
int cosmo_dlclose(void *);
#endif
+91 -63
View File
@@ -18,6 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/stat.h"
@@ -45,6 +46,7 @@
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/proc/posix_spawn.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/serialize.h"
@@ -116,7 +118,7 @@ struct Loaded {
Elf64_Phdr ph[25];
};
static struct {
struct {
atomic_uint once;
bool is_supported;
struct CosmoTib *tib;
@@ -125,9 +127,10 @@ static struct {
int (*dlclose)(void *);
char *(*dlerror)(void);
jmp_buf jb;
} foreign;
} __foreign;
long __sysv2nt14();
long foreign_tramp();
static _Thread_local char dlerror_buf[128];
@@ -156,28 +159,6 @@ static int is_file_newer_than(const char *path, const char *other) {
return timespec_cmp(st1.st_mtim, st2.st_mtim) > 0;
}
// on system five we sadly need this brutal trampoline
// todo(jart): add tls trampoline to sigaction() handlers
// todo(jart): morph binary to get tls from host c library
static long foreign_tramp(long a, long b, long c, long d, long e,
long func(long, long, long, long, long, double,
double, double, double, double, double),
double A, double B, double C, double D, double E,
double F) {
long res;
BLOCK_SIGNALS;
#ifdef __x86_64__
struct CosmoTib *tib = __get_tls();
__set_tls(foreign.tib);
#endif
res = func(a, b, c, d, e, A, B, C, D, E, F);
#ifdef __x86_64__
__set_tls(tib);
#endif
ALLOW_SIGNALS;
return res;
}
static unsigned elf2prot(unsigned x) {
unsigned r = 0;
if (x & PF_R) r += PROT_READ;
@@ -308,11 +289,11 @@ static long *push_strs(long *sp, char **list, int count) {
}
static wontreturn dontinstrument void foreign_helper(void **p) {
foreign.dlopen = p[0];
foreign.dlsym = p[1];
foreign.dlclose = p[2];
foreign.dlerror = p[3];
longjmp(foreign.jb, 1);
__foreign.dlopen = p[0];
__foreign.dlsym = p[1];
__foreign.dlclose = p[2];
__foreign.dlerror = p[3];
_longjmp(__foreign.jb, 1);
}
static dontinline void elf_exec(const char *file, char **envp) {
@@ -515,11 +496,13 @@ static uint8_t *movimm(uint8_t p[static 16], int reg, uint64_t val) {
static void *foreign_thunk_sysv(void *func) {
uint8_t *code, *p;
#ifdef __x86_64__
// movabs $func,%r9
// it is no longer needed
if (1) return func;
// movabs $func,%rax
// movabs $foreign_tramp,%r10
// jmp *%r10
if (!(p = code = foreign_alloc(23))) return 0; // 10 + 10 + 3 = 23
p = movimm(p, 9, (uintptr_t)func);
p = movimm(p, 0, (uintptr_t)func);
p = movimm(p, 10, (uintptr_t)foreign_tramp);
*p++ = 0x41;
*p++ = 0xff;
@@ -527,7 +510,7 @@ static void *foreign_thunk_sysv(void *func) {
#elif defined(__aarch64__)
__jit_begin();
if ((p = code = foreign_alloc(36))) {
p = movimm(p, 5, (uintptr_t)func);
p = movimm(p, 8, (uintptr_t)func);
p = movimm(p, 10, (uintptr_t)foreign_tramp);
*(uint32_t *)p = 0xd61f0140; // br x10
__clear_cache(code, p + 4);
@@ -636,7 +619,15 @@ static dontinline bool foreign_compile(char exe[hasatleast PATH_MAX]) {
}
int pid, ws;
char *args[] = {
"cc", "-pie", "-fPIC", src, "-o", tmp, IsNetbsd() ? 0 : "-ldl", 0,
"cc",
"-pie",
"-fPIC",
src,
"-o",
tmp,
IsLinux() ? "-Wl,-z,execstack" : "-DIGNORE",
IsNetbsd() ? 0 : "-ldl",
0,
};
errno_t err = posix_spawnp(&pid, args[0], NULL, NULL, args, environ);
if (err) {
@@ -671,19 +662,19 @@ static bool foreign_setup(void) {
#ifdef __x86_64__
struct CosmoTib *cosmo_tib = __get_tls();
#endif
if (!setjmp(foreign.jb)) {
if (!setjmp(__foreign.jb)) {
elf_exec(exe, environ);
return false; // if elf_exec() returns, it failed
}
#ifdef __x86_64__
foreign.tib = __get_tls();
__foreign.tib = __get_tls();
__set_tls(cosmo_tib);
#endif
foreign.dlopen = foreign_thunk_sysv(foreign.dlopen);
foreign.dlsym = foreign_thunk_sysv(foreign.dlsym);
foreign.dlclose = foreign_thunk_sysv(foreign.dlclose);
foreign.dlerror = foreign_thunk_sysv(foreign.dlerror);
foreign.is_supported = true;
__foreign.dlopen = foreign_thunk_sysv(__foreign.dlopen);
__foreign.dlsym = foreign_thunk_sysv(__foreign.dlsym);
__foreign.dlclose = foreign_thunk_sysv(__foreign.dlclose);
__foreign.dlerror = foreign_thunk_sysv(__foreign.dlerror);
__foreign.is_supported = true;
return true;
}
@@ -693,8 +684,8 @@ static void foreign_once(void) {
static bool foreign_init(void) {
bool res;
cosmo_once(&foreign.once, foreign_once);
if (!(res = foreign.is_supported)) {
cosmo_once(&__foreign.once, foreign_once);
if (!(res = __foreign.is_supported)) {
dlerror_set("dlopen() isn't supported on this platform");
}
return res;
@@ -740,14 +731,13 @@ static void *dlopen_nt(const char *path, int mode) {
static void *dlsym_nt(void *handle, const char *name) {
void *x64_abi_func;
void *sysv_abi_func = 0;
if ((x64_abi_func = GetProcAddress((uintptr_t)handle, name))) {
sysv_abi_func = foreign_thunk_nt(x64_abi_func);
return x64_abi_func;
} else {
dlerror_set("symbol not found: ");
strlcat(dlerror_buf, name, sizeof(dlerror_buf));
return 0;
}
return sysv_abi_func;
}
static void *dlopen_silicon(const char *path, int mode) {
@@ -792,13 +782,10 @@ static void *dlopen_silicon(const char *path, int mode) {
* WARNING: Our API uses a different naming because cosmo_dlopen() lacks
* many of the features one would reasonably expect from a UNIX dlopen()
* implementation; and we don't want to lead ./configure scripts astray.
* You're limited to 5 integral function parameters maximum. Calling an
* imported function currently goes much slower than a normal function
* call. You can't pass callback function pointers to foreign libraries
* safely. Foreign libraries also can't link symbols defined by your
* executable; that means using this for high-level language plugins is
* completely out of the question. What cosmo_dlopen() can do is help
* you talk to GPU and GUI libraries like CUDA and SDL.
* Foreign libraries also can't link symbols defined by your executable,
* which means using this for high-level language plugins is completely
* out of the question. What cosmo_dlopen() can do is help you talk to
* GPU and GUI libraries like CUDA and SDL.
*
* @param mode is a bitmask that can contain:
* - `RTLD_LOCAL` (default)
@@ -812,6 +799,7 @@ static void *dlopen_silicon(const char *path, int mode) {
void *cosmo_dlopen(const char *path, int mode) {
void *res;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
if (IsWindows()) {
res = dlopen_nt(path, mode);
} else if (IsXnuSilicon()) {
@@ -824,10 +812,11 @@ void *cosmo_dlopen(const char *path, int mode) {
dlerror_set("dlopen() isn't supported on OpenBSD yet");
res = 0;
} else if (foreign_init()) {
res = foreign.dlopen(path, mode);
res = __foreign.dlopen(path, mode);
} else {
res = 0;
}
ALLOW_CANCELATION;
ALLOW_SIGNALS;
STRACE("dlopen(%#s, %d) → %p% m", path, mode, res);
return res;
@@ -836,8 +825,26 @@ void *cosmo_dlopen(const char *path, int mode) {
/**
* Obtains address of symbol from dynamic shared object.
*
* On Windows you can only use this to lookup function addresses.
* Returned functions are trampolined to conform to System V ABI.
* WARNING: You almost always want to say this:
*
* pFunction = cosmo_dltramp(cosmo_dlsym(dso, "function"));
*
* That will generate code at runtime for automatically translating to
* Microsoft's x64 calling convention when appropriate. However the
* automated solution doesn't always work. For example, the prototype:
*
* void func(int, float);
*
* Won't be translated correctly, due to the differences in ABI. We're
* able to smooth over most of them, but that's just one of several
* examples where we can't. A good rule of thumb is:
*
* - More than four float/double args is problematic
* - Having both integral and floating point parameters is bad
*
* For those kinds of functions, you need to translate the ABI by hand.
* This can be accomplished using the GCC `__ms_abi__` attribute, where
* you'd have two function pointer types branched upon `IsWindows()`.
*
* @param handle was opened by dlopen()
* @return address of symbol, or NULL w/ dlerror()
@@ -847,16 +854,12 @@ void *cosmo_dlsym(void *handle, const char *name) {
if (IsWindows()) {
func = dlsym_nt(handle, name);
} else if (IsXnuSilicon()) {
if ((func = __syslib->__dlsym(handle, name))) {
func = foreign_thunk_sysv(func);
}
func = __syslib->__dlsym(handle, name);
} else if (IsXnu()) {
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
func = 0;
} else if (foreign_init()) {
if ((func = foreign.dlsym(handle, name))) {
func = foreign_thunk_sysv(func);
}
func = __foreign.dlsym(handle, name);
} else {
func = 0;
}
@@ -864,6 +867,17 @@ void *cosmo_dlsym(void *handle, const char *name) {
return func;
}
/**
* Trampolines foreign function pointer so it can be called safely.
*/
void *cosmo_dltramp(void *foreign_func) {
if (!IsWindows()) {
return foreign_thunk_sysv(foreign_func);
} else {
return foreign_thunk_nt(foreign_func);
}
}
/**
* Closes dynamic shared object.
*
@@ -880,7 +894,7 @@ int cosmo_dlclose(void *handle) {
dlerror_set("dlopen() isn't supported on x86-64 MacOS");
res = -1;
} else if (foreign_init()) {
res = foreign.dlclose(handle);
res = __foreign.dlclose(handle);
} else {
res = -1;
}
@@ -898,7 +912,7 @@ char *cosmo_dlerror(void) {
} else if (IsWindows() || IsXnu()) {
res = dlerror_buf;
} else if (foreign_init()) {
res = foreign.dlerror();
res = __foreign.dlerror();
res = dlerror_set(res);
} else {
res = dlerror_buf;
@@ -906,3 +920,17 @@ char *cosmo_dlerror(void) {
STRACE("dlerror() → %#s", res);
return res;
}
#ifdef __x86_64__
static textstartup void dlopen_init() {
if (IsLinux() || IsFreebsd()) {
// switch from %fs to %gs for tls
struct CosmoTib *tib = __get_tls();
__morph_tls();
__set_tls(tib);
}
}
const void *const dlopen_ctor[] initarray = {
dlopen_init,
};
#endif
+236
View File
@@ -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
+1 -1
View File
@@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 3
#define __COSMOPOLITAN_MINOR__ 2
#define __COSMOPOLITAN_PATCH__ 0
#define __COSMOPOLITAN_PATCH__ 4
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)
+13
View File
@@ -16,6 +16,8 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/dce.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
@@ -27,3 +29,14 @@ dontinstrument void __stracef(const char *fmt, ...) {
kvprintf(fmt, v);
va_end(v);
}
#if IsModeDbg()
void report_cancellation_point(void) {
kprintf("error: cancelable raw system call not annotated in wrapper\n"
"choice #1 use BLOCK_CANCELATION / ALLOW_CANCELATION\n"
"choice #2 use BEGIN_CANCELATION_POINT / END_CANCELATION_POINT\n"
"backtrace: %s\n",
DescribeBacktrace(__builtin_frame_address(0)));
__builtin_trap();
}
#endif
+26
View File
@@ -0,0 +1,26 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
│ vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2024 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/macros.internal.h"
// we can't allow ftrace here since ftrace needs tls
sys_set_tls:
mov __NR_set_tls(%rip),%eax
syscall
ret
.endfn sys_set_tls,globl
@@ -1,5 +1,5 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2023 Justine Alexandra Roberts Tunney │
│ │
@@ -16,8 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/cxaatexit.internal.h"
#include "libc/runtime/internal.h"
int __cxa_thread_atexit(void *fun, void *arg, void *dso_symbol) {
return __cxa_thread_atexit_impl(fun, arg, dso_symbol);
}
char __tls_morphed;
+2 -2
View File
@@ -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 {
+20 -20
View File
@@ -3,19 +3,19 @@
#include "libc/macros.internal.h"
COSMOPOLITAN_C_START_
__funline unsigned long __strlen(const char *s) {
forceinline unsigned long __strlen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
__funline int __strcmp(const char *l, const char *r) {
forceinline int __strcmp(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
__funline char *__stpcpy(char *d, const char *s) {
forceinline char *__stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
@@ -24,7 +24,7 @@ __funline char *__stpcpy(char *d, const char *s) {
}
}
__funline void *__repstosb(void *di, char al, size_t cx) {
forceinline void *__repstosb(void *di, char al, size_t cx) {
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm("rep stosb"
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
@@ -40,7 +40,7 @@ __funline void *__repstosb(void *di, char al, size_t cx) {
#endif
}
__funline void *__repmovsb(void *di, const void *si, size_t cx) {
forceinline void *__repmovsb(void *di, const void *si, size_t cx) {
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
@@ -57,7 +57,7 @@ __funline void *__repmovsb(void *di, const void *si, size_t cx) {
#endif
}
__funline void *__mempcpy(void *d, const void *s, size_t n) {
forceinline void *__mempcpy(void *d, const void *s, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
((char *)d)[i] = ((const char *)s)[i];
@@ -66,7 +66,7 @@ __funline void *__mempcpy(void *d, const void *s, size_t n) {
return (char *)d + n;
}
__funline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
forceinline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
char t;
size_t i, a, b;
i = 0;
@@ -85,22 +85,22 @@ __funline char *__uintcpy(char p[hasatleast 21], uint64_t x) {
return p + i;
}
__funline char *__intcpy(char p[hasatleast 21], int64_t x) {
forceinline char *__intcpy(char p[hasatleast 21], int64_t x) {
if (x < 0) *p++ = '-', x = -(uint64_t)x;
return __uintcpy(p, x);
}
__funline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
forceinline char *__fixcpy(char p[hasatleast 17], uint64_t x, uint8_t k) {
while (k > 0) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
*p = '\0';
return p;
}
__funline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
return __fixcpy(p, x, ROUNDUP(x ? (__builtin_clzll(x) ^ 63) + 1 : 1, 4));
}
__funline const void *__memchr(const void *s, unsigned char c, size_t n) {
forceinline const void *__memchr(const void *s, unsigned char c, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (((const unsigned char *)s)[i] == c) {
@@ -110,7 +110,7 @@ __funline const void *__memchr(const void *s, unsigned char c, size_t n) {
return 0;
}
__funline char *__strstr(const char *haystack, const char *needle) {
forceinline char *__strstr(const char *haystack, const char *needle) {
size_t i;
for (;;) {
for (i = 0;; ++i) {
@@ -123,8 +123,8 @@ __funline char *__strstr(const char *haystack, const char *needle) {
return 0;
}
__funline char16_t *__strstr16(const char16_t *haystack,
const char16_t *needle) {
forceinline char16_t *__strstr16(const char16_t *haystack,
const char16_t *needle) {
size_t i;
for (;;) {
for (i = 0;; ++i) {
@@ -137,21 +137,21 @@ __funline char16_t *__strstr16(const char16_t *haystack,
return 0;
}
__funline const char *__strchr(const char *s, unsigned char c) {
forceinline const char *__strchr(const char *s, unsigned char c) {
for (;; ++s) {
if ((*s & 255) == c) return s;
if (!*s) return 0;
}
}
__funline unsigned long __atoul(const char *p) {
forceinline unsigned long __atoul(const char *p) {
int c;
unsigned long x = 0;
while ('0' <= (c = *p++) && c <= '9') x *= 10, x += c - '0';
return x;
}
__funline long __atol(const char *p) {
forceinline long __atol(const char *p) {
int s = *p;
unsigned long x;
if (s == '-' || s == '+') ++p;
@@ -160,7 +160,7 @@ __funline long __atol(const char *p) {
return x;
}
__funline void *__memset(void *a, int c, unsigned long n) {
forceinline void *__memset(void *a, int c, unsigned long n) {
char *d = a;
unsigned long i;
for (i = 0; i < n; ++i) {
@@ -170,7 +170,7 @@ __funline void *__memset(void *a, int c, unsigned long n) {
return d;
}
__funline void *__memcpy(void *a, const void *b, unsigned long n) {
forceinline void *__memcpy(void *a, const void *b, unsigned long n) {
char *d = a;
unsigned long i;
const char *s = b;
@@ -181,7 +181,7 @@ __funline void *__memcpy(void *a, const void *b, unsigned long n) {
return d;
}
__funline void *__memmove(void *a, const void *b, unsigned long n) {
forceinline void *__memmove(void *a, const void *b, unsigned long n) {
char *d = a;
unsigned long i;
const char *s = b;
+2
View File
@@ -95,6 +95,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
flockfile(f);
strace_enabled(-1);
BLOCK_SIGNALS;
BLOCK_CANCELATION;
// We display TIMESTAMP.MICROS normally. However, when we log multiple
// times in the same second, we display TIMESTAMP+DELTAMICROS instead.
@@ -136,6 +137,7 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
_Exit(22);
}
ALLOW_CANCELATION;
ALLOW_SIGNALS;
strace_enabled(+1);
funlockfile(f);
+2 -47
View File
@@ -39,7 +39,7 @@ static void TeardownGc(void) {
if (__tls_enabled) {
t = __get_tls();
if ((g = t->tib_garbages)) {
// exit() currently doesn't use _gclongjmp() like pthread_exit()
// exit() currently doesn't use gclongjmp() like pthread_exit()
// so we need to run the deferred functions manually.
while (g->i) {
--g->i;
@@ -88,7 +88,7 @@ static void DeferFunction(struct StackFrame *frame, void *fn, void *arg) {
frame->addr = (intptr_t)__gc;
}
// the gnu extension macros for _gc / _defer point here
// the gnu extension macros for gc / defer point here
void __defer(void *rbp, void *fn, void *arg) {
struct StackFrame *f, *frame = rbp;
f = __builtin_frame_address(0);
@@ -96,48 +96,3 @@ void __defer(void *rbp, void *fn, void *arg) {
unassert(PointerNotOwnedByParentStackFrame(f, frame, arg));
DeferFunction(frame, fn, arg);
}
/**
* Frees memory when function returns.
*
* This garbage collector overwrites the return address on the stack so
* that the RET instruction calls a trampoline which calls free(). It's
* loosely analogous to Go's defer keyword rather than a true cycle gc.
*
* const char *s = _gc(strdup("hello"));
* puts(s);
*
* This macro is equivalent to:
*
* _defer(free, ptr)
*
* @warning do not return a gc()'d pointer
* @warning do not realloc() with gc()'d pointer
* @warning be careful about static keyword due to impact of inlining
* @note you should use -fno-omit-frame-pointer
*/
void *(_gc)(void *thing) {
struct StackFrame *frame;
frame = __builtin_frame_address(0);
DeferFunction(frame->next, _weakfree, thing);
return thing;
}
/**
* Calls fn(arg) when function returns.
*
* This garbage collector overwrites the return address on the stack so
* that the RET instruction calls a trampoline which calls free(). It's
* loosely analogous to Go's defer keyword rather than a true cycle gc.
*
* @warning do not return a gc()'d pointer
* @warning do not realloc() with gc()'d pointer
* @warning be careful about static keyword due to impact of inlining
* @note you should use -fno-omit-frame-pointer
*/
void *(_defer)(void *fn, void *arg) {
struct StackFrame *frame;
frame = __builtin_frame_address(0);
DeferFunction(frame->next, fn, arg);
return arg;
}
+15 -17
View File
@@ -1,25 +1,23 @@
#ifndef COSMOPOLITAN_LIBC_MEM_GC_H_
#define COSMOPOLITAN_LIBC_MEM_GC_H_
#ifdef _COSMO_SOURCE
COSMOPOLITAN_C_START_
void *_gc(void *);
void *_defer(void *, void *);
void __defer(void *, void *, void *);
void _gclongjmp(void *, int) dontthrow wontreturn;
void _gc_free(void *);
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define _gc(THING) _defer((void *)_gc_free, (void *)(THING))
#define _defer(FN, ARG) \
({ \
autotype(ARG) Arg = (ARG); \
/* prevent weird opts like tail call */ \
asm volatile("" : "+g"(Arg) : : "memory"); \
__defer(__builtin_frame_address(0), FN, Arg); \
asm volatile("" : "+g"(Arg) : : "memory"); \
Arg; \
void _gc_free(void *) libcesque;
void __defer(void *, void *, void *) libcesque;
void gclongjmp(void *, int) libcesque wontreturn;
#define gc(THING) defer((void *)_gc_free, (void *)(THING))
#define _gc(THING) defer((void *)_gc_free, (void *)(THING))
#define defer(FN, ARG) \
({ \
autotype(ARG) Arg = (ARG); \
/* prevent weird opts like tail call */ \
__asm__ volatile("" : "+g"(Arg) : : "memory"); \
__defer(__builtin_frame_address(0), FN, Arg); \
__asm__ volatile("" : "+g"(Arg) : : "memory"); \
Arg; \
})
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
COSMOPOLITAN_C_END_
#endif /* _COSMO_SOURCE */
#endif /* COSMOPOLITAN_LIBC_MEM_GC_H_ */
-9
View File
@@ -1,9 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_
#define COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_
#include "libc/mem/gc.h"
#define gc(THING) _gc(THING)
#define defer(FN, ARG) _defer(FN, ARG)
#define gclongjmp(JB, ARG) _gclongjmp(JB, ARG)
#endif /* COSMOPOLITAN_LIBC_MEM_GC_INTERNAL_H_ */
+2 -2
View File
@@ -30,7 +30,7 @@
// @see examples/ctrlc.c
// @noreturn
.ftrace1
_gclongjmp:
gclongjmp:
.ftrace2
#ifdef __x86_64__
push %rbp
@@ -65,4 +65,4 @@ _gclongjmp:
#else
#error "unsupported architecture"
#endif /* __x86_64__ */
.endfn _gclongjmp,globl
.endfn gclongjmp,globl
+7 -6
View File
@@ -23,11 +23,12 @@
// @param rdi points to the jmp_buf
// @param esi is returned by setjmp() invocation (coerced nonzero)
// @noreturn
// @see _gclongjmp()
// @see gclongjmp()
// @see siglongjmp()
.ftrace1
longjmp:
.ftrace2
_longjmp:
#ifdef __x86_64__
mov %esi,%eax
test %eax,%eax
@@ -42,13 +43,13 @@ longjmp:
mov 48(%rdi),%r15
jmp *56(%rdi)
#elif defined(__aarch64__)
ldp x19,x20,[x0,#0]
ldp x21,x22,[x0,#16]
ldp x29,x30,[x0,#0]
ldp x2,x22,[x0,#16]
ldp x23,x24,[x0,#32]
ldp x25,x26,[x0,#48]
ldp x27,x28,[x0,#64]
ldp x29,x30,[x0,#80]
ldr x2,[x0,#104]
ldp x19,x20,[x0,#80]
ldr x21,[x0,#104]
mov sp,x2
ldp d8 ,d9,[x0,#112]
ldp d10,d11,[x0,#128]
@@ -61,5 +62,5 @@ longjmp:
#error "unsupported architecture"
#endif
.endfn longjmp,globl
.alias longjmp,_longjmp
.endfn _longjmp,globl
.alias longjmp,siglongjmp
+8 -7
View File
@@ -25,10 +25,11 @@
// @returnstwice
// @assume system five nexgen32e abi conformant
// @note code built w/ microsoft abi compiler can't call this
// @see longjmp(), _gclongjmp()
// @see longjmp(), gclongjmp()
.ftrace1
setjmp:
.ftrace2
_setjmp:
#ifdef __x86_64__
lea 8(%rsp),%rax
mov %rax,(%rdi)
@@ -43,14 +44,14 @@ setjmp:
xor %eax,%eax
ret
#elif defined(__aarch64__)
stp x19,x20,[x0,#0]
stp x21,x22,[x0,#16]
mov x2,sp
stp x29,x30,[x0,#0]
stp x2,x22,[x0,#16]
stp x23,x24,[x0,#32]
stp x25,x26,[x0,#48]
stp x27,x28,[x0,#64]
stp x29,x30,[x0,#80]
mov x2,sp
str x2,[x0,#104]
stp x19,x20,[x0,#80]
str x21,[x0,#104]
stp d8,d9,[x0,#112]
stp d10,d11,[x0,#128]
stp d12,d13,[x0,#144]
@@ -60,5 +61,5 @@ setjmp:
#else
#error "unsupported architecture"
#endif
.endfn _setjmp,globl
.endfn setjmp,globl
.alias setjmp,_setjmp
+2
View File
@@ -58,6 +58,7 @@ static bool IsApeFile(const char *path) {
} else {
bool res = false;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
int fd;
char buf[8];
int flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC;
@@ -65,6 +66,7 @@ static bool IsApeFile(const char *path) {
res = sys_pread(fd, buf, 8, 0, 0) == 8 && IsApeLoadable(buf);
sys_close(fd);
}
ALLOW_CANCELATION;
ALLOW_SIGNALS;
return res;
}
+6 -6
View File
@@ -201,14 +201,14 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
}
if (!__isfdkind(fd, kFdZip)) {
bool memfdReq;
BEGIN_CANCELATION_POINT;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
strace_enabled(-1);
memfdReq = ((rc = fcntl(fd, F_GETFD)) != -1) && (rc & FD_CLOEXEC) &&
IsAPEFd(fd);
strace_enabled(+1);
ALLOW_CANCELATION;
ALLOW_SIGNALS;
END_CANCELATION_POINT;
if (rc == -1) {
break;
} else if (!memfdReq) {
@@ -221,13 +221,13 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
}
int newfd;
char *path = alloca(PATH_MAX);
BEGIN_CANCELATION_POINT;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
strace_enabled(-1);
newfd = fd_to_mem_fd(fd, path);
strace_enabled(+1);
ALLOW_CANCELATION;
ALLOW_SIGNALS;
END_CANCELATION_POINT;
if (newfd == -1) {
break;
}
@@ -242,13 +242,13 @@ int fexecve(int fd, char *const argv[], char *const envp[]) {
if (!savedErr) {
savedErr = errno;
}
BEGIN_CANCELATION_POINT;
BLOCK_SIGNALS;
BLOCK_CANCELATION;
strace_enabled(-1);
close(newfd);
strace_enabled(+1);
ALLOW_CANCELATION;
ALLOW_SIGNALS;
END_CANCELATION_POINT;
} while (0);
if (savedErr) {
errno = savedErr;
+39 -11
View File
@@ -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;
-115
View File
@@ -1,115 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "libc/atomic.h"
#include "libc/cxxabi.h"
#include "libc/intrin/atomic.h"
#include "libc/limits.h"
#include "third_party/nsync/futex.internal.h"
// This file contains C++ ABI support functions for one time
// constructors as defined in the "Run-time ABI for the ARM Architecture"
// section 4.4.2
//
// ARM C++ ABI and Itanium/x86 C++ ABI has different definition for
// one time construction:
//
// ARM C++ ABI defines the LSB of guard variable should be tested
// by compiler-generated code before calling __cxa_guard_acquire et al.
//
// The Itanium/x86 C++ ABI defines the low-order _byte_ should be
// tested instead.
//
// Meanwhile, guard variable are 32bit aligned for ARM, and 64bit
// aligned for x86.
//
// Reference documentation:
//
// section 3.2.3 of ARM IHI 0041C (for ARM)
// section 3.3.2 of the Itanium C++ ABI specification v1.83 (for x86).
//
// There is no C++ ABI available for other ARCH. But the gcc source
// shows all other ARCH follow the definition of Itanium/x86 C++ ABI.
// The Itanium/x86 C++ ABI (used by all architectures that aren't ARM32)
// mandates guard variables are 64-bit aligned, 64-bit values. The least
// significant byte is tested by the compiler-generated code before it's
// calling __cxa_guard_acquire.
union CxaGuardValue {
atomic_int state;
int64_t aligner;
};
// Set construction state values according to reference documentation. 0
// is the initialization value. Arm requires ((*gv & 1) == 1) after
// __cxa_guard_release, ((*gv & 3) == 0) after __cxa_guard_abort. X86
// requires first byte not modified by __cxa_guard_acquire, first byte
// is non-zero after __cxa_guard_release.
#define CONSTRUCTION_NOT_YET_STARTED 0
#define CONSTRUCTION_COMPLETE 1
#define CONSTRUCTION_UNDERWAY_WITHOUT_WAITER 0x100
#define CONSTRUCTION_UNDERWAY_WITH_WAITER 0x200
int __cxa_guard_acquire(union CxaGuardValue *gv) {
int old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
while (true) {
if (old_value == CONSTRUCTION_COMPLETE) {
// A load_acquire operation is needed before exiting with COMPLETE
// state, as we must ensure that all the stores performed by the
// construction function are observable on this CPU after we exit.
atomic_thread_fence(memory_order_acquire);
return 0;
} else if (old_value == CONSTRUCTION_NOT_YET_STARTED) {
if (!atomic_compare_exchange_weak_explicit(
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITHOUT_WAITER,
memory_order_relaxed, memory_order_relaxed)) {
continue;
}
// The acquire fence may not be needed. But as described in section 3.3.2
// of the Itanium C++ ABI specification, it probably has to behave like
// the acquisition of a mutex, which needs an acquire fence.
atomic_thread_fence(memory_order_acquire);
return 1;
} else if (old_value == CONSTRUCTION_UNDERWAY_WITHOUT_WAITER) {
if (!atomic_compare_exchange_weak_explicit(
&gv->state, &old_value, CONSTRUCTION_UNDERWAY_WITH_WAITER,
memory_order_relaxed, memory_order_relaxed)) {
continue;
}
}
nsync_futex_wait_(&gv->state, CONSTRUCTION_UNDERWAY_WITH_WAITER, 0, 0);
old_value = atomic_load_explicit(&gv->state, memory_order_relaxed);
}
}
void __cxa_guard_release(union CxaGuardValue *gv) {
// Release fence is used to make all stores performed by the construction
// function visible in other threads.
int old_value = atomic_exchange_explicit(&gv->state, CONSTRUCTION_COMPLETE,
memory_order_release);
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
nsync_futex_wake_(&gv->state, INT_MAX, 0);
}
}
void __cxa_guard_abort(union CxaGuardValue *gv) {
// Release fence is used to make all stores performed by the construction
// function visible in other threads.
int old_value = atomic_exchange_explicit(
&gv->state, CONSTRUCTION_NOT_YET_STARTED, memory_order_release);
if (old_value == CONSTRUCTION_UNDERWAY_WITH_WAITER) {
nsync_futex_wake_(&gv->state, INT_MAX, 0);
}
}
+13 -1
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/cxxabi.h"
#include "libc/intrin/cxaatexit.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/runtime/internal.h"
@@ -36,13 +37,24 @@
* @noreturn
*/
wontreturn void exit(int exitcode) {
const uintptr_t *p;
STRACE("exit(%d)", exitcode);
// call thread local c++ object destructors
if (_weaken(__cxa_thread_finalize)) {
_weaken(__cxa_thread_finalize)();
}
// call atexit() and __cxa_atexit() destructors
if (_weaken(__cxa_finalize)) {
_weaken(__cxa_finalize)(NULL);
}
// call __destructor__ and finiarray destructors
const uintptr_t *p;
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
// terminate process
_Exit(exitcode);
}
+5 -2
View File
@@ -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
}
+1 -1
View File
@@ -136,7 +136,7 @@ long __get_minsigstksz(void) pureconst;
void __get_main_stack(void **, size_t *, int *);
long __get_safe_size(long, long);
char *__get_tmpdir(void);
__funline int __trace_disabled(int x) {
forceinline int __trace_disabled(int x) {
return 0;
}
#ifndef FTRACE
+8 -4
View File
@@ -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 -1
View File
@@ -96,7 +96,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
* since it'll not only ensure stack overflows are detected, it
* will also trigger the stack to grow down safely.
*/
__funline void CheckLargeStackAllocation(void *p, ssize_t n) {
forceinline void CheckLargeStackAllocation(void *p, ssize_t n) {
for (; n > 0; n -= 4096) {
((char *)p)[n - 1] = 0;
}
-40
View File
@@ -1,40 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_
#define COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_
#define UNW_TDEP_CURSOR_LEN 127
COSMOPOLITAN_C_START_
typedef enum {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
typedef uint64_t unw_word_t;
typedef struct unw_cursor {
unw_word_t opaque[UNW_TDEP_CURSOR_LEN];
} unw_cursor_t;
struct _Unwind_Context {
unw_cursor_t cursor;
int end_of_stack;
};
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
void *);
uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
uintptr_t _Unwind_GetIP(struct _Unwind_Context *);
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
void *_Unwind_FindEnclosingFunction(void *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_RUNTIME_UNWIND_H_ */
+3
View File
@@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
@@ -45,7 +46,9 @@ int getentropy(void *p, size_t n) {
rc = 0;
} else {
BLOCK_SIGNALS;
BLOCK_CANCELATION;
if (__getrandom(p, n, 0) != n) notpossible;
ALLOW_CANCELATION;
ALLOW_SIGNALS;
rc = 0;
}
+1 -1
View File
@@ -42,7 +42,7 @@
* On newer Linux only (c. 2013) it's possible to turn the anonymous
* returned file back into a real file, by doing this:
*
* linkat(AT_FDCWD, _gc(xasprintf("/proc/self/fd/%d", fileno(f))),
* linkat(AT_FDCWD, gc(xasprintf("/proc/self/fd/%d", fileno(f))),
* AT_FDCWD, "real.txt", AT_SYMLINK_FOLLOW)
*
* On the New Technology, temporary files created by this function
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/macros.internal.h"
.scall sys_set_tls,0x13d1490a5300309e,4095,3,165,globl,hidden
+1
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon nr,__NR_set_tls,0x009e,0xfff,0x3000003,0xfff,0x00a5,0x0149,0x13d,0xfff
+9 -7
View File
@@ -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_
-1
View File
@@ -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
+2 -2
View File
@@ -116,11 +116,11 @@ void _pthread_unref(struct PosixThread *);
void _pthread_unwind(struct PosixThread *);
void _pthread_zombify(struct PosixThread *);
__funline pureconst struct PosixThread *_pthread_self(void) {
forceinline pureconst struct PosixThread *_pthread_self(void) {
return (struct PosixThread *)__get_tls()->tib_pthread;
}
__funline void _pthread_ref(struct PosixThread *pt) {
forceinline void _pthread_ref(struct PosixThread *pt) {
atomic_fetch_add_explicit(&pt->pt_refs, 1, memory_order_relaxed);
}
+1 -1
View File
@@ -291,7 +291,7 @@ static errno_t _pthread_cancel_everyone(void) {
* Consider using Cosmopolitan Libc's garbage collector since it will be
* executed when a thread exits due to a cancelation.
*
* void *p = _gc(malloc(123));
* void *p = gc(malloc(123));
* read(0, p, 123);
*
* It's possible to put a thread in asynchronous cancelation mode with
+2 -2
View File
@@ -84,8 +84,8 @@ void _pthread_unkey(struct CosmoTib *tib) {
* the callback function that was supplied to pthread_create(). This may
* be used if the thread wishes to exit at any other point in the thread
* lifecycle, in which case this function is responsible for ensuring we
* invoke _gc(), _defer(), and pthread_cleanup_push() callbacks, as well
* as pthread_key_create() destructors.
* invoke gc(), _defer(), and pthread_cleanup_push() callbacks, and also
* pthread_key_create() destructors.
*
* If the current thread is an orphaned thread, or is the main thread
* when no other threads were created, then this will terminated your
+2 -1
View File
@@ -42,6 +42,7 @@ struct CosmoTib {
};
extern int __threaded;
extern char __tls_morphed;
extern unsigned __tls_index;
char *_mktls(struct CosmoTib **);
@@ -64,7 +65,7 @@ void __set_tls(struct CosmoTib *);
*
* This can't be used in privileged functions.
*/
__funline pureconst struct CosmoTib *__get_tls(void) {
forceinline pureconst struct CosmoTib *__get_tls(void) {
#ifdef __chibicc__
return 0;
#elif __x86_64__
+8 -4
View File
@@ -11,10 +11,14 @@ COSMOPOLITAN_C_START_
* This should be favored over __get_tls() for .privileged code that
* can't be self-modified by __enable_tls().
*/
__funline struct CosmoTib *__get_tls_privileged(void) {
forceinline struct CosmoTib *__get_tls_privileged(void) {
char *tib, *lin = (char *)0x30;
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd() || IsMetal()) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
if (!__tls_morphed) {
asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
}
} else {
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
if (IsWindows()) {
@@ -24,14 +28,14 @@ __funline struct CosmoTib *__get_tls_privileged(void) {
return (struct CosmoTib *)tib;
}
__funline struct CosmoTib *__get_tls_win32(void) {
forceinline struct CosmoTib *__get_tls_win32(void) {
char *tib, *lin = (char *)0x30;
asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory");
tib = *(char **)(tib + 0x1480 + __tls_index * 8);
return (struct CosmoTib *)tib;
}
__funline void __set_tls_win32(void *tls) {
forceinline void __set_tls_win32(void *tls) {
asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tls));
}
+1 -1
View File
@@ -17,7 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/fmt/libgen.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/x/x.h"
+1 -1
View File
@@ -17,7 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/log/log.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "net/https/https.h"
bool ChainCertificate(mbedtls_x509_crt *cert, mbedtls_x509_crt *parent) {
+3 -3
View File
@@ -37,8 +37,8 @@ struct Cert FinishCertificate(struct Cert *ca, mbedtls_x509write_cert *wcert,
if ((rc = mbedtls_pk_check_pair(&cert->pk, key))) {
FATALF("generate key (grep -0x%04x)", -rc);
}
LogCertificate(_gc(xasprintf("generated %s certificate",
mbedtls_pk_get_name(&cert->pk))),
cert);
LogCertificate(
gc(xasprintf("generated %s certificate", mbedtls_pk_get_name(&cert->pk))),
cert);
return (struct Cert){cert, key};
}
+5 -5
View File
@@ -32,7 +32,6 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/atomic.h"
#include "libc/serialize.h"
#include "libc/intrin/bsr.h"
#include "libc/intrin/hilbert.h"
#include "libc/intrin/kprintf.h"
@@ -49,6 +48,7 @@
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/sysconf.h"
#include "libc/serialize.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/sockaddr.h"
@@ -815,13 +815,13 @@ void *ListenWorker(void *arg) {
void *HttpWorker(void *arg) {
struct Client client;
int id = (intptr_t)arg;
char *msgbuf = _gc(xmalloc(MSG_BUF));
char *msgbuf = gc(xmalloc(MSG_BUF));
char *inbuf = NewSafeBuffer(INBUF_SIZE);
char *outbuf = NewSafeBuffer(OUTBUF_SIZE);
struct HttpMessage *msg = _gc(xcalloc(1, sizeof(struct HttpMessage)));
struct HttpMessage *msg = gc(xcalloc(1, sizeof(struct HttpMessage)));
BlockSignals();
pthread_setname_np(pthread_self(), _gc(xasprintf("HTTP%d", id)));
pthread_setname_np(pthread_self(), gc(xasprintf("HTTP%d", id)));
// connection loop
while (GetClient(&g_clients, &client)) {
@@ -1761,7 +1761,7 @@ void *ClaimWorker(void *arg) {
long processed;
sqlite3_stmt *stmt;
bool warmedup = false;
struct Claim *v = _gc(xcalloc(BATCH_MAX, sizeof(struct Claim)));
struct Claim *v = gc(xcalloc(BATCH_MAX, sizeof(struct Claim)));
BlockSignals();
pthread_setname_np(pthread_self(), "ClaimWorker");
LOG("%P ClaimWorker started\n");
+1 -1
View File
@@ -18,7 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/core/core.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/hyperion.h"
+1 -1
View File
@@ -20,7 +20,7 @@
#include "dsp/core/q.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
+1 -1
View File
@@ -23,7 +23,7 @@
#include "libc/fmt/bing.internal.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
+1 -1
View File
@@ -23,7 +23,7 @@
#include "dsp/core/half.h"
#include "libc/fmt/bing.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
+1 -1
View File
@@ -20,7 +20,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/mem/alloca.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
+1 -1
View File
@@ -25,7 +25,7 @@
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/sysconf.h"
#include "libc/stdio/rand.h"
+3 -3
View File
@@ -38,7 +38,7 @@ void SetUpOnce(void) {
void Make(const char *path, int mode) {
int fd, n = lemur64() & 0xfffff;
char *data = _gc(malloc(n));
char *data = gc(malloc(n));
rngset(data, n, lemur64, -1);
ASSERT_NE(-1, (fd = creat(path, mode)));
ASSERT_SYS(0, n, write(fd, data, n));
@@ -77,8 +77,8 @@ TEST(copy_file_range, test) {
size_t n, m;
Make("foo", 0644);
Copy("foo", "bar");
p = _gc(xslurp("foo", &n));
q = _gc(xslurp("bar", &m));
p = gc(xslurp("foo", &n));
q = gc(xslurp("bar", &m));
ASSERT_EQ(n, m);
ASSERT_EQ(0, memcmp(p, q, n));
}
@@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ Copyright 2024 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
@@ -19,75 +19,48 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/ftw.h"
#include "libc/stdio/stdio.h"
#include "libc/intrin/strace.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
const char *prog;
char tmpdir[PATH_MAX];
char binpath[PATH_MAX];
bool IsDirectory(const char *path) {
int e;
bool res;
struct stat st;
e = errno;
res = stat(path, &st) != -1 && S_ISDIR(st.st_mode);
errno = e;
return res;
void SetUpOnce(void) {
testlib_enable_tmp_setup_teardown();
}
void Execute(char *argv[]) {
int ws;
if (!vfork()) {
execv(argv[0], argv);
_Exit(127);
}
wait(&ws);
if (!WIFEXITED(ws) || WEXITSTATUS(ws)) {
fputs(argv[0], stderr);
fputs(": command failed\n", stderr);
exit(1);
}
TEST(devfd, test) {
// TODO: What is up with this mysterious ENOENT error?
// The code appears like it should support this.
if (IsFreebsd()) return;
char buf[8] = {0};
struct stat st[2] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "bone", -1));
ASSERT_SYS(0, 3, open("hello.txt", O_RDONLY));
ASSERT_SYS(0, 4, open("/dev/fd/3", O_RDONLY));
ASSERT_SYS(0, 4, read(4, buf, 7));
ASSERT_STREQ("bone", buf);
ASSERT_SYS(0, 0, fstat(3, st));
ASSERT_SYS(0, 0, fstat(4, st + 1));
ASSERT_EQ(0, memcmp(st, st + 1, sizeof(struct stat)));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
}
int Visit(const char *fpath, const struct stat *sb, int tflag,
struct FTW *ftwbuf) {
if (tflag == FTW_F && endswith(fpath, ".gz")) {
Execute((char *[]){"build/bootstrap/gzip.com", "-d", (char *)fpath, 0});
strcpy(binpath, fpath);
binpath[strlen(binpath) - 3] = 0;
chmod(binpath, 0755);
} else if (tflag == FTW_F && endswith(fpath, ".sym")) {
strcpy(binpath, fpath);
binpath[strlen(binpath) - 4] = 0;
symlink(xslurp(fpath, 0), binpath);
}
return 0;
}
int main(int argc, char *argv[]) {
if (!IsLinux()) return 0;
prog = argv[0];
if (!prog) prog = "unbundle";
if (IsDirectory("o/third_party/gcc")) return 0;
makedirs("o/third_party", 0755);
FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid());
Execute(
(char *[]){"build/bootstrap/cp.com", "-r", "third_party/gcc", tmpdir, 0});
if (nftw(tmpdir, Visit, 20, 0) == -1) {
fputs(prog, stderr);
fputs(": nftw failed: ", stderr);
fputs(_strerdoc(errno), stderr);
fputs("\n", stderr);
exit(1);
}
rename(tmpdir, "o/third_party/gcc");
TEST(devfd, not_DEV_FD_STAT_BROKEN) {
// fstat() and stat() are inconsistent on bsd systems
// with xnu it only appears to be st_dev that differs
if (IsBsd()) return;
char buf[8] = {0};
struct stat st[2] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "bone", -1));
ASSERT_SYS(0, 3, open("hello.txt", O_RDONLY));
ASSERT_SYS(0, 4, open("/dev/fd/3", O_RDONLY));
ASSERT_SYS(0, 4, read(4, buf, 7));
ASSERT_STREQ("bone", buf);
ASSERT_SYS(0, 0, fstat(3, st));
ASSERT_SYS(0, 0, stat("/dev/fd/3", st + 1));
ASSERT_EQ(0, memcmp(st, st + 1, sizeof(struct stat)));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
}
+1 -1
View File
@@ -17,7 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
+1 -1
View File
@@ -23,7 +23,7 @@
#include "libc/errno.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
+1 -1
View File
@@ -22,7 +22,7 @@
#include "libc/fmt/libgen.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/serialize.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
+28 -18
View File
@@ -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);
+3 -3
View File
@@ -22,7 +22,6 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/errno.h"
#include "libc/serialize.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
@@ -30,6 +29,7 @@
#include "libc/mem/mem.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdio/lcg.internal.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
@@ -70,7 +70,7 @@ void *TortureWorker(void *arg) {
TEST(getrandom, test) {
int i, n = 999;
double e, w = 7.7;
char *buf = _gc(calloc(1, n));
char *buf = gc(calloc(1, n));
ASSERT_SYS(0, 0, getrandom(0, 0, 0));
ASSERT_SYS(0, n, getrandom(buf, n, 0));
ASSERT_SYS(EFAULT, -1, getrandom(0, n, 0));
@@ -92,7 +92,7 @@ TEST(getrandom, test2) {
double e, w = 7.7;
struct sigaction sa;
int i, k, m, n = 999;
char *buf = _gc(calloc(1, n));
char *buf = gc(calloc(1, n));
sa.sa_flags = 0;
sa.sa_handler = OnSig;
sigemptyset(&sa.sa_mask);
+1 -1
View File
@@ -20,7 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
+1 -1
View File
@@ -20,7 +20,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/check.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
+1 -1
View File
@@ -18,7 +18,7 @@
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/errno.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/proc/ntspawn.h"
#include "libc/str/str.h"
+1 -1
View File
@@ -16,7 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/proc/ntspawn.h"
#include "libc/runtime/runtime.h"
#include "libc/testlib/testlib.h"
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/testlib/testlib.h"
#if SupportsWindows()
+1 -1
View File
@@ -24,7 +24,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
+1 -1
View File
@@ -21,7 +21,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
+1 -1
View File
@@ -96,7 +96,7 @@ TEST(poll, testNegativeOneFd_isIgnored) {
EXPECT_SYS(0, 0, poll(fds, ARRAYLEN(fds), 1));
EXPECT_STREQ("fd:-1 revents:<TODO:kPollNames>\n"
"fd:3 revents:<TODO:kPollNames>\n",
_gc(FormatPollFd(&fds[0])));
gc(FormatPollFd(&fds[0])));
ASSERT_SYS(0, 0, close(3));
}
+1 -1
View File
@@ -23,7 +23,7 @@
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
Loaded 100 of 536 files, more files were not shown because too many files have changed in this diff. Show more