Compare commits

...

40 commits

Author SHA1 Message Date
Hugues Morisset
f1e83d5240
Add IPv6 support to getifaddrs() on Linux (#1415)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-05-21 01:20:22 -07:00
Steven Dee (Jōshin)
2fe8338f92
Better mtimes for github workflow build cache (#1421)
Saves and restores mtimes to a file, also covering the `o/` directory to
hopefully preserve make dependency information better.
2025-05-20 22:17:55 -07:00
ShalokShalom
4ca513cba2
Add C++ to README (#1407)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-04-25 15:47:50 -07:00
Steven Dee (Jōshin)
455910e8f2
Make more shared_ptr fixes (#1401)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
* Make refcount reads explicitly atomic
* Consistently put `const` in the same place
* Write the general `operator=` on `weak_ptr`
2025-04-21 05:36:50 -07:00
Steven Dee (Jōshin)
9c68bc19b5
Cache .cosmocc and o for github workflows (#1400)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
Uses GitHub’s actions/cache@v4 to store the cosmocc distribution and the
output directory between runs of the build workflow, with the version of
cosmocc as the cache key.

Upgrades to actions/checkout@v4.
2025-04-17 15:55:27 -07:00
Steven Dee (Jōshin)
66d1050af6
Correctly implement weak_ptr assignment/copy/moves (#1399) 2025-04-17 14:01:20 -07:00
Justine Tunney
fbc4fcbb71
Get GDB working
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
You can now say `gdb hello.com.dbg` and it'll work perfectly.
2025-03-30 15:25:55 -07:00
Steven Dee (Jōshin)
afc986f741
Fix shared_ptr<T>::owner_before (#1390)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
`!(a < b)` is not the same as `b < a`.

I think I originally wrote it this way to avoid making weak_ptr a friend
of shared_ptr, but weak_ptr already is a friend.
2025-03-25 01:49:34 -04:00
Derek
5eb7cd6643
Add support for getcpu() system call to pledge() (#1387)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This fixes redbean Lua tests which were failing with SIGSYS on Linux.
2025-03-21 16:08:25 -07:00
Brett Jia
a8ed4fdd09
Add NetBSD evbarm and fix segfault (#1384)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This change fixes a segmentation fault when comparing loaders that don't
have a target kernel set. Additionally, adds evbarm, which is the output
of uname -m on NetBSD on aarch64.
2025-03-12 17:37:46 -07:00
Brett Jia
7b69652854
Add -k OSNAME flag to apelink (#1383)
Let's say you pass the `-M blink-mips.elf` flag to apelink, so that your
ape binary will bundle a compressed build of blink, and the shell script
will extract that binary and launch your program under it, if running on
a MIPS system. However, for any given microprocessor architecture, we'll
need a separate loader for each operating system. The issue is ELF OSABI
isn't very useful. As an example, SerenityOS and Linux both have SYSV in
the OSABI field. So to tell their binaries apart we'd have to delve into
various other conventions, like special sections and PT_NOTE structures.

To make things simple this change introduces the `-k OS` flag to apelink
which generate shell script content that ensures `OS` matches `uname -s`
before attempting to execute a loader. For example, you could say:

    apelink -k Linux -M blink-linux-arm.elf -M blink-linux-mips.elf \
            -k Darwin -M blink-darwin-ppc.elf \
            ...

To introduce support for old 32-bit architectures on multiple OSes, when
building your cosmo binary.
2025-03-12 13:26:51 -07:00
Leal G.
b235492e71
Add usertrust certificate (#1382)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
Bundle USERTrust CA certificates to /usr/share/ssl/root for TLS verifies
2025-03-11 17:59:34 -07:00
Brett Jia
fc81fd8d16
Support additional architectures in apelink (#1381)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
This updates apelink to support machine architectures not in the source
program input list by adding additional loaders, extracting the correct
one that matches the host uname machine. With this change, blink can be
supplied as the additional loader to run the program in x86_64 VMs. The
change has been verified against blink 1.0, powerpc64le and mips64el in
Docker using QEMU.
2025-03-06 10:26:31 -08:00
Gautham
38930de8e0
Make tool for replacing ELF strings (#1344)
Some checks failed
build / matrix_on_mode () (push) Has been cancelled
build / matrix_on_mode (optlinux) (push) Has been cancelled
build / matrix_on_mode (rel) (push) Has been cancelled
build / matrix_on_mode (tiny) (push) Has been cancelled
build / matrix_on_mode (tinylinux) (push) Has been cancelled
2025-02-08 21:17:42 -08:00
Brett Jia
0e557d041d
Check downloaded gcc/clang checksums (#1367)
Check sha256 checksums of the downloaded gcc and clang toolchains. It'll
allow us to extend trust to external toolchains if building from source.
2025-02-08 17:46:09 -08:00
Brett Jia
1d676b36e6
Make cosmoranlib executable (#1366)
Fixes #1325
2025-02-08 17:38:00 -08:00
Brett Jia
10a92cee94
Support building cosmocc on MacOS (#1365)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
This updates the cosmocc toolchain packaging script to work on MacOS. It
has been tested on GitHub Actions macos-13 (x86_64) and macos-14 (arm64)
runners, and is verified to still work on Ubuntu (GitHub Actions runners
ubuntu-24.04 and ubuntu-24.04-arm). It'll help bring cosmocc to MacPorts
by running the packaging script. We favor `gmake` rather than the `make`
command because it distinguishes GNU Make from BSD Make, and Xcode Make.
Additionally, APE loader from the bootstrapper toolchain is used instead
of a system APE, which may not be available.
2025-02-08 12:45:45 -08:00
A2va
42a9ed0131
Adds some NT functions (#1358) 2025-02-08 08:08:08 -08:00
Björn Buckwalter
12cb0669fb
Clarify unix.mapshared versus file locks (#1355)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
2025-02-08 00:48:38 -08:00
rufeooo
7f6a7d6fff
Fix sigaction example code (#1363)
Some checks are pending
build / matrix_on_mode () (push) Waiting to run
build / matrix_on_mode (optlinux) (push) Waiting to run
build / matrix_on_mode (rel) (push) Waiting to run
build / matrix_on_mode (tiny) (push) Waiting to run
build / matrix_on_mode (tinylinux) (push) Waiting to run
2025-02-07 11:42:47 -08:00
Steven Dee (Jōshin)
9f6bf6ea71
tool/zsh/mkofs: doas 2025-01-13 16:48:55 -08:00
Steven Dee (Jōshin)
102edf4ea2
tool/zsh/mmake: style 2025-01-05 20:53:53 -08:00
Steven Dee (Jōshin)
21968acf99
Standard make path (#1353)
Modifies download-cosmocc.sh to maintain a .cosmocc/current symlink that
always points to the most recently downloaded version of cosmocc. We can
use this to point at a canonical make for a bootstrapped repository. For
first-time builds, we suggest: https://cosmo.zip/pub/cosmos/bin/make and
have updated the docs in a few places to mention this.

Fixes the other part of #1346.
2025-01-05 20:47:34 -08:00
Justine Tunney
98861b23fc
Make some style fixes to prng code 2025-01-05 20:18:05 -08:00
Steven Dee (Jōshin)
dab6d7a345
Resolve multiple definition of __sig (fixes #1346) (#1352) 2025-01-05 19:54:49 -08:00
Justine Tunney
90119c422c
Fix 404 url
Closes #1347
2025-01-05 17:04:37 -08:00
Justine Tunney
5907304049
Release Cosmopolitan v4.0.2 2025-01-05 14:05:49 -08:00
Justine Tunney
035b0e2a62
Attempt to fix MODE=dbg Windows execve() flake 2025-01-05 14:05:49 -08:00
Justine Tunney
7b67b20dae
Fix Windows MODE=tiny breakage 2025-01-05 14:05:49 -08:00
Himanshu Pal
f0b0f926bf
Enable sqlite3 serialization in redbean (#1349)
This fixes a failing demo page, that requires us to enable serialization
in the lsqlite3 library that's used by the redbean server.
2025-01-05 13:59:10 -08:00
Justine Tunney
29eb7e67bb
Fix fork() regression on Windows
Recent optimizations to fork() introduced a regression, that could cause
the subprocess to fail unexpectedly, when TlsAlloc() returns a different
index. This is because we were burning the indexes into the displacement
of x86 opcodes. So when fork() happened and the executable memory copied
it would use the old index. Right now the way this is being solved is to
not copy the executable on fork() and then re-apply code changes. If you
need to be able to preserve self-modified code on fork, reach out and we
can implement a better solution for you. This gets us unblocked quickly.
2025-01-05 09:25:23 -08:00
Justine Tunney
f71f61cd40
Add some temporary logging statements 2025-01-04 23:37:32 -08:00
Justine Tunney
53c6edfd18
Make correction to last change 2025-01-04 21:38:47 -08:00
Justine Tunney
42a3bb729a
Make execve() linger when it can't spoof parent
It's now possible to use execve() when the parent process isn't built by
cosmo. In such cases, the current process will kill all threads and then
linger around, waiting for the newly created process to die, and then we
propagate its exit code to the parent. This should help bazel and others

Allocating private anonymous memory is now 5x faster on Windows. This is
thanks to VirtualAlloc() which is faster than the file mapping APIs. The
fork() function also now goes 30% faster, since we are able to avoid the
VirtualProtect() calls on mappings in most cases now.

Fixes #1253
2025-01-04 21:13:37 -08:00
Justine Tunney
c97a858470
Remove missing definitions 2025-01-04 00:20:45 -08:00
Justine Tunney
4acd12a514
Release Cosmopolitan v4.0.1 2025-01-03 19:51:34 -08:00
Justine Tunney
b734eec836
Test restricting tests to single cpu 2025-01-03 19:51:09 -08:00
Justine Tunney
fe01642a20
Add missing lock to fork() on Windows 2025-01-03 19:01:58 -08:00
Justine Tunney
e939659b70
Fix ordering of pthread_create(pthread_t *thread)
This change fixes a bug where signal_latency_async_test would flake less
than 1/1000 of the time. What was happening was pthread_kill(sender_thr)
would return EFAULT. This was because pthread_create() was not returning
the thread object pointer until after clone() had been called. So it was
actually possible for the main thread to stall after calling clone() and
during that time the receiver would launch and receive a signal from the
sender thread, and then fail when it tried to send a pong. I thought I'd
use a barrier at first, in the test, to synchronize thread creation, but
I firmly believe that pthread_create() was to blame and now that's fixed
2025-01-03 17:34:29 -08:00
Justine Tunney
ed6d133a27
Use tgkill() on Linux and FreeBSD
This eliminates the chance of rare bugs when thread IDs are recycled.
2025-01-03 17:27:13 -08:00
131 changed files with 2247 additions and 1057 deletions

View file

@ -1,5 +1,8 @@
name: build name: build
env:
COSMOCC_VERSION: 3.9.2
on: on:
push: push:
branches: branches:
@ -19,13 +22,48 @@ jobs:
matrix: matrix:
mode: ["", tiny, rel, tinylinux, optlinux] mode: ["", tiny, rel, tinylinux, optlinux]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with:
# Full checkout needed for git-restore-mtime-bare.
fetch-depth: 0
# TODO(jart): fork this action.
- uses: chetan/git-restore-mtime-action@v2
- uses: actions/cache/restore@v4
id: cache
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
restore-keys: |
${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-
${{ env.COSMOCC_VERSION }}-
- name: Restore mtimes
if: steps.cache.outputs.cache-hit == 'true'
run: |
while read mtime file; do
[ -f "$file" ] && touch -d "@$mtime" "$file"
done < o/.mtimes
- name: support ape bins 1 - name: support ape bins 1
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
- name: support ape bins 2 - name: support ape bins 2
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
- name: make matrix - name: make matrix
run: V=0 make -j2 MODE=${{ matrix.mode }} run: V=0 make -j2 MODE=${{ matrix.mode }}
- name: Save mtimes
run: |
find o -type f -exec stat -c "%Y %n" {} \; > o/.mtimes
- uses: actions/cache/save@v4
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}

View file

@ -77,7 +77,8 @@ COMMA := ,
PWD := $(shell pwd) PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether: # detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran build/bootstrap/make, in which case make's working directory is in wsl # - user ran .cosmocc/current/bin/make, in which case make's working directory
# is in wsl
# - user ran make, in which case cocmd's working directory is in wsl # - user ran make, in which case cocmd's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),) ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
$(warning wsl2 interop is enabled) $(warning wsl2 interop is enabled)
@ -89,7 +90,7 @@ UNAME_S := $(shell uname -s)
# apple still distributes a 17 year old version of gnu make # apple still distributes a 17 year old version of gnu make
ifeq ($(MAKE_VERSION), 3.81) ifeq ($(MAKE_VERSION), 3.81)
$(error please use build/bootstrap/make) $(error please use https://cosmo.zip/pub/cosmos/bin/make)
endif endif
LC_ALL = C LC_ALL = C

View file

@ -3,7 +3,7 @@
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml) [![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan # Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C [Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C/C++
a build-once run-anywhere language, like Java, except it doesn't need an a build-once run-anywhere language, like Java, except it doesn't need an
interpreter or virtual machine. Instead, it reconfigures stock GCC and interpreter or virtual machine. Instead, it reconfigures stock GCC and
Clang to output a POSIX-approved polyglot format that runs natively on Clang to output a POSIX-approved polyglot format that runs natively on
@ -87,15 +87,22 @@ ape/apeinstall.sh
``` ```
You can now build the mono repo with any modern version of GNU Make. To You can now build the mono repo with any modern version of GNU Make. To
make life easier, we've included one in the cosmocc toolchain, which is bootstrap your build, you can install Cosmopolitan Make from this site:
guaranteed to be compatible and furthermore includes our extensions for
doing build system sandboxing. https://cosmo.zip/pub/cosmos/bin/make
E.g.:
```sh ```sh
build/bootstrap/make -j8 curl -LO https://cosmo.zip/pub/cosmos/bin/make
./make -j8
o//examples/hello o//examples/hello
``` ```
After you've built the repo once, you can also use the make from your
cosmocc at `.cosmocc/current/bin/make`. You might even prefer to alias
make to `$COSMO/.cosmocc/current/bin/make`.
Since the Cosmopolitan repository is very large, you might only want to Since the Cosmopolitan repository is very large, you might only want to
build one particular thing. Here's an example of a target that can be build one particular thing. Here's an example of a target that can be
compiled relatively quickly, which is a simple POSIX test that only compiled relatively quickly, which is a simple POSIX test that only
@ -103,7 +110,7 @@ depends on core LIBC packages.
```sh ```sh
rm -rf o//libc o//test rm -rf o//libc o//test
build/bootstrap/make o//test/posix/signal_test .cosmocc/current/bin/make o//test/posix/signal_test
o//test/posix/signal_test o//test/posix/signal_test
``` ```
@ -112,21 +119,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: all the unit tests in the `TEST_POSIX` package, you could say:
```sh ```sh
build/bootstrap/make o//test/posix .cosmocc/current/bin/make o//test/posix
``` ```
Cosmopolitan provides a variety of build modes. For example, if you want 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: really tiny binaries (as small as 12kb in size) then you'd say:
```sh ```sh
build/bootstrap/make m=tiny .cosmocc/current/bin/make m=tiny
``` ```
You can furthermore cut out the bloat of other operating systems, and You can furthermore cut out the bloat of other operating systems, and
have Cosmopolitan become much more similar to Musl Libc. have Cosmopolitan become much more similar to Musl Libc.
```sh ```sh
build/bootstrap/make m=tinylinux .cosmocc/current/bin/make m=tinylinux
``` ```
For further details, see [//build/config.mk](build/config.mk). For further details, see [//build/config.mk](build/config.mk).

View file

@ -259,6 +259,9 @@ SECTIONS {
.debug_ranges 0 : { *(.debug_ranges) } .debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) } .debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) } .debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) } .ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) } .note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }

View file

@ -386,6 +386,13 @@ SECTIONS {
_tbss_end = .; _tbss_end = .;
} :Tls } :Tls
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
} :Ram
.data . : { .data . : {
/*BEGIN: Read/Write Data */ /*BEGIN: Read/Write Data */
#if SupportsWindows() #if SupportsWindows()
@ -426,11 +433,6 @@ SECTIONS {
KEEP(*(.dtors)) KEEP(*(.dtors))
__fini_array_end = .; __fini_array_end = .;
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
/*BEGIN: Post-Initialization Read-Only */ /*BEGIN: Post-Initialization Read-Only */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0); . = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*))) KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
@ -439,7 +441,6 @@ SECTIONS {
KEEP(*(.piro.pad.data)) KEEP(*(.piro.pad.data))
*(.igot.plt) *(.igot.plt)
KEEP(*(.dataepilogue)) KEEP(*(.dataepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0); . = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */ /*END: NT FORK COPYING */
_edata = .; _edata = .;
@ -519,6 +520,9 @@ SECTIONS {
.debug_rnglists 0 : { *(.debug_rnglists) } .debug_rnglists 0 : { *(.debug_rnglists) }
.debug_macro 0 : { *(.debug_macro) } .debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) } .debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) } .gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
.GCC.command.line 0 : { *(.GCC.command.line) } .GCC.command.line 0 : { *(.GCC.command.line) }
@ -582,11 +586,11 @@ ape_rom_memsz = ape_rom_filesz;
ape_rom_align = CONSTANT(COMMONPAGESIZE); ape_rom_align = CONSTANT(COMMONPAGESIZE);
ape_rom_rva = RVA(ape_rom_vaddr); ape_rom_rva = RVA(ape_rom_vaddr);
ape_ram_vaddr = ADDR(.data); ape_ram_vaddr = ADDR(.eh_frame);
ape_ram_offset = ape_ram_vaddr - __executable_start; ape_ram_offset = ape_ram_vaddr - __executable_start;
ape_ram_paddr = LOADADDR(.data); ape_ram_paddr = LOADADDR(.eh_frame);
ape_ram_filesz = ADDR(.bss) - ADDR(.data); ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
ape_ram_memsz = _end - ADDR(.data); ape_ram_memsz = _end - ADDR(.eh_frame);
ape_ram_align = CONSTANT(COMMONPAGESIZE); ape_ram_align = CONSTANT(COMMONPAGESIZE);
ape_ram_rva = RVA(ape_ram_vaddr); ape_ram_rva = RVA(ape_ram_vaddr);
@ -596,7 +600,7 @@ ape_stack_offset = 0;
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000; ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz; ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
ape_stack_filesz = 0; ape_stack_filesz = 0;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024; ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 4 * 1024 * 1024;
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr); ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
ape_note_filesz = ape_note_end - ape_note; ape_note_filesz = ape_note_end - ape_note;

View file

@ -10,8 +10,8 @@ if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit cd "$COSMO" || exit
fi fi
if [ -x build/bootstrap/make ]; then if [ -x .cosmocc/current/bin/make ]; then
MAKE=build/bootstrap/make MAKE=.cosmocc/current/bin/make
else else
MAKE=make MAKE=make
fi fi

View file

@ -99,3 +99,8 @@ rm -f cosmocc.zip cosmocc.zip.sha256sum
# commit output directory # commit output directory
cd "${OLDPWD}" || die cd "${OLDPWD}" || die
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
# update current symlink
BASE=$(basename "${OUTPUT_DIR}")
DIR=$(dirname "${OUTPUT_DIR}")
ln -sfn "$BASE" "$DIR/current"

View file

@ -97,12 +97,12 @@ class shared_ref
size_t use_count() const noexcept size_t use_count() const noexcept
{ {
return shared + 1; return __atomic_load_n(&shared, __ATOMIC_RELAXED) + 1;
} }
size_t weak_count() const noexcept size_t weak_count() const noexcept
{ {
return weak; return __atomic_load_n(&weak, __ATOMIC_RELAXED);
} }
private: private:
@ -349,7 +349,7 @@ class shared_ptr
template<typename U> template<typename U>
bool owner_before(const weak_ptr<U>& r) const noexcept bool owner_before(const weak_ptr<U>& r) const noexcept
{ {
return !r.owner_before(*this); return rc < r.rc;
} }
private: private:
@ -382,6 +382,34 @@ class weak_ptr
rc->keep_weak(); rc->keep_weak();
} }
weak_ptr(const weak_ptr& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(const weak_ptr<U>& r) noexcept : p(r.p), rc(r.rc)
{
if (rc)
rc->keep_weak();
}
weak_ptr(weak_ptr&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr(weak_ptr<U>&& r) noexcept : p(r.p), rc(r.rc)
{
r.p = nullptr;
r.rc = nullptr;
}
~weak_ptr() ~weak_ptr()
{ {
if (rc) if (rc)
@ -410,6 +438,19 @@ class weak_ptr
swap(rc, r.rc); swap(rc, r.rc);
} }
weak_ptr& operator=(weak_ptr r) noexcept
{
swap(r);
return *this;
}
template<typename U>
requires __::shared_ptr_compatible<T, U>
weak_ptr& operator=(weak_ptr<U> r) noexcept
{
weak_ptr<T>(move(r)).swap(*this);
}
shared_ptr<T> lock() const noexcept shared_ptr<T> lock() const noexcept
{ {
if (expired()) if (expired())

View file

@ -28,8 +28,8 @@
// @return rdi is rdi+edx // @return rdi is rdi+edx
.text.startup .text.startup
__getntsyspath: __getntsyspath:
push %rbp beg
mov %rsp,%rbp pro
push %rdx push %rdx
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx) movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
sub $40,%rsp sub $40,%rsp
@ -55,6 +55,7 @@ __getntsyspath:
jne 2f jne 2f
movb $'/',-1(%rdi) movb $'/',-1(%rdi)
2: .loop 1b 2: .loop 1b
leave epi
ret ret
end
.endfn __getntsyspath,globl,hidden .endfn __getntsyspath,globl,hidden

View file

@ -114,7 +114,8 @@ static ssize_t GetDevUrandom(char *p, size_t n, unsigned f) {
ssize_t __getrandom(void *p, size_t n, unsigned f) { ssize_t __getrandom(void *p, size_t n, unsigned f) {
ssize_t rc; ssize_t rc;
if (IsWindows()) { if (IsWindows()) {
rc = ProcessPrng(p, n) ? n : __winerr(); ProcessPrng(p, n); // never fails
rc = n;
} else if (have_getrandom) { } else if (have_getrandom) {
if (IsXnu() || IsOpenbsd()) { if (IsXnu() || IsOpenbsd()) {
rc = GetRandomBsd(p, n, GetRandomEntropy); rc = GetRandomBsd(p, n, GetRandomEntropy);
@ -184,9 +185,7 @@ ssize_t __getrandom(void *p, size_t n, unsigned f) {
* @raise EFAULT if the `n` bytes at `p` aren't valid memory * @raise EFAULT if the `n` bytes at `p` aren't valid memory
* @raise EINTR if we needed to block and a signal was delivered instead * @raise EINTR if we needed to block and a signal was delivered instead
* @cancelationpoint * @cancelationpoint
* @asyncsignalsafe
* @restartable * @restartable
* @vforksafe
*/ */
ssize_t getrandom(void *p, size_t n, unsigned f) { ssize_t getrandom(void *p, size_t n, unsigned f) {
ssize_t rc; ssize_t rc;

View file

@ -67,10 +67,9 @@ textstartup void InitializeMetalFile(void) {
size_t size = ROUNDUP(_ezip - __executable_start, 4096); size_t size = ROUNDUP(_ezip - __executable_start, 4096);
// TODO(jart): Restore support for ZIPOS on metal. // TODO(jart): Restore support for ZIPOS on metal.
void *copied_base; void *copied_base;
struct DirectMap dm; void *addr = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
dm = sys_mmap_metal(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0); MAP_SHARED_linux | MAP_ANONYMOUS_linux, -1, 0);
copied_base = dm.addr; copied_base = addr;
npassert(copied_base != (void *)-1); npassert(copied_base != (void *)-1);
memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size); memcpy(copied_base, (void *)(BANE + IMAGE_BASE_PHYSICAL), size);
__ape_com_base = copied_base; __ape_com_base = copied_base;

View file

@ -39,12 +39,15 @@
#include "libc/nt/struct/procthreadattributelist.h" #include "libc/nt/struct/procthreadattributelist.h"
#include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/startupinfoex.h" #include "libc/nt/struct/startupinfoex.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/proc/ntspawn.h" #include "libc/proc/ntspawn.h"
#include "libc/stdalign.h" #include "libc/stdalign.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
struct SpawnBlock { struct SpawnBlock {
char16_t path[PATH_MAX]; char16_t path[PATH_MAX];
char16_t cmdline[32767]; char16_t cmdline[32767];
@ -64,10 +67,12 @@ static textwindows ssize_t ntspawn_read(intptr_t fh, char *buf, size_t len) {
bool ok; bool ok;
uint32_t got; uint32_t got;
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)}; struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)};
ok = (ReadFile(fh, buf, len, 0, &overlap) || ok = overlap.hEvent &&
(ReadFile(fh, buf, len, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) && GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(fh, &overlap, &got, true); GetOverlappedResult(fh, &overlap, &got, true);
CloseHandle(overlap.hEvent); if (overlap.hEvent)
__imp_CloseHandle(overlap.hEvent);
return ok ? got : -1; return ok ? got : -1;
} }
@ -87,7 +92,7 @@ static textwindows int ntspawn2(struct NtSpawnArgs *a, struct SpawnBlock *sb) {
if (fh == -1) if (fh == -1)
return -1; return -1;
ssize_t got = ntspawn_read(fh, p, pe - p); ssize_t got = ntspawn_read(fh, p, pe - p);
CloseHandle(fh); __imp_CloseHandle(fh);
if (got < 3) if (got < 3)
return enoexec(); return enoexec();
pe = p + got; pe = p + got;

View file

@ -49,11 +49,9 @@ int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) {
if ((fd = __reservefd(-1)) == -1) if ((fd = __reservefd(-1)) == -1)
return -1; return -1;
if (!_weaken(calloc) || !_weaken(free)) { if (!_weaken(calloc) || !_weaken(free)) {
struct DirectMap dm; state = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096),
dm = sys_mmap_metal(NULL, ROUNDUP(sizeof(struct MetalFile), 4096), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, -1, 0);
0);
state = dm.addr;
if (state == (void *)-1) if (state == (void *)-1)
return -1; return -1;
} else { } else {

View file

@ -694,6 +694,7 @@ static const uint16_t kPledgeStdio[] = {
__NR_linux_sched_getaffinity, // __NR_linux_sched_getaffinity, //
__NR_linux_sched_setaffinity, // __NR_linux_sched_setaffinity, //
__NR_linux_sigtimedwait, // __NR_linux_sigtimedwait, //
__NR_linux_getcpu, //
}; };
static const uint16_t kPledgeFlock[] = { static const uint16_t kPledgeFlock[] = {

View file

@ -997,8 +997,10 @@ textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
if (f->kind == kFdDevNull) if (f->kind == kFdDevNull)
return 0; return 0;
if (f->kind == kFdDevRandom) if (f->kind == kFdDevRandom) {
return ProcessPrng(data, size) ? size : __winerr(); ProcessPrng(data, size);
return size;
}
if (f->kind == kFdConsole) if (f->kind == kFdConsole)
return ReadFromConsole(f, data, size, waitmask); return ReadFromConsole(f, data, size, waitmask);

View file

@ -423,7 +423,7 @@ static int __sigaction(int sig, const struct sigaction *act,
* } * }
* *
* void ContinueOnCrash(void) { * void ContinueOnCrash(void) {
* struct sigaction sa = {.sa_handler = OnSigSegv, * struct sigaction sa = {.sa_sigaction = OnCrash,
* .sa_flags = SA_SIGINFO | SA_RESETHAND}; * .sa_flags = SA_SIGINFO | SA_RESETHAND};
* sigaction(SIGSEGV, &sa, 0); * sigaction(SIGSEGV, &sa, 0);
* sigaction(SIGFPE, &sa, 0); * sigaction(SIGFPE, &sa, 0);

View file

@ -2,6 +2,9 @@
#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern int sys_getppid_nt_cosmo;
extern int sys_getppid_nt_win32;
bool32 sys_isatty(int); bool32 sys_isatty(int);
int sys_chdir_nt(const char *); int sys_chdir_nt(const char *);
int sys_dup_nt(int, int, int, int); int sys_dup_nt(int, int, int, int);
@ -37,6 +40,7 @@ int sys_unlinkat_nt(int, const char *, int);
int64_t sys_lseek_nt(int, int64_t, int); int64_t sys_lseek_nt(int, int64_t, int);
ssize_t sys_read_nt_impl(int, void *, size_t, int64_t); ssize_t sys_read_nt_impl(int, void *, size_t, int64_t);
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t); ssize_t sys_readlinkat_nt(int, const char *, char *, size_t);
void sys_getppid_nt_wipe(int, int);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ */

View file

@ -80,7 +80,8 @@ textwindows int IsWindowsExecutable(int64_t handle, const char16_t *path) {
uint32_t got; uint32_t got;
BLOCK_SIGNALS; BLOCK_SIGNALS;
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)}; struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0)};
ok = (ReadFile(handle, buf, 2, 0, &overlap) || ok = overlap.hEvent &&
(ReadFile(handle, buf, 2, 0, &overlap) ||
GetLastError() == kNtErrorIoPending) && GetLastError() == kNtErrorIoPending) &&
GetOverlappedResult(handle, &overlap, &got, true); GetOverlappedResult(handle, &overlap, &got, true);
CloseHandle(overlap.hEvent); CloseHandle(overlap.hEvent);

View file

@ -47,7 +47,14 @@ __oops_win32:
// @note ape.S and ape-loader both set RCX to XNU on Darwin // @note ape.S and ape-loader both set RCX to XNU on Darwin
// @noreturn // @noreturn
_start: _start:
#ifdef __x86_64__ .cfi_startproc
#if defined(__x86_64__)
.cfi_undefined rip
#elif defined(__aarch64__)
.cfi_undefined x30
#endif /* __x86_64__ */
#if defined(__x86_64__)
#if SupportsFreebsd() #if SupportsFreebsd()
// detect free besiyata dishmaya // detect free besiyata dishmaya
@ -159,4 +166,5 @@ _start:
#else #else
#error "architecture unsupported" #error "architecture unsupported"
#endif /* __x86_64__ */ #endif /* __x86_64__ */
.cfi_endproc
.endfn _start,weak,hidden .endfn _start,weak,hidden

View file

@ -68,6 +68,7 @@
#define EM_NONE 0 #define EM_NONE 0
#define EM_M32 1 #define EM_M32 1
#define EM_386 3 #define EM_386 3
#define EM_MIPS 8
#define EM_PPC64 21 #define EM_PPC64 21
#define EM_S390 22 #define EM_S390 22
#define EM_ARM 40 #define EM_ARM 40

View file

@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 4 #define __COSMOPOLITAN_MAJOR__ 4
#define __COSMOPOLITAN_MINOR__ 0 #define __COSMOPOLITAN_MINOR__ 0
#define __COSMOPOLITAN_PATCH__ 0 #define __COSMOPOLITAN_PATCH__ 2
#define __COSMOPOLITAN__ \ #define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \ (100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__) __COSMOPOLITAN_PATCH__)

View file

@ -59,7 +59,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § Windows Time // —Quoth MSDN § Windows Time
// //
QueryUnbiasedInterruptTimePrecise(&hectons); QueryUnbiasedInterruptTimePrecise(&hectons);
*ts = timespec_fromnanos(hectons * 100); *ts = WindowsDurationToTimeSpec(hectons);
return 0; return 0;
case _CLOCK_MONOTONIC_COARSE: case _CLOCK_MONOTONIC_COARSE:
// //
@ -83,7 +83,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § QueryUnbiasedInterruptTimePrecise // —Quoth MSDN § QueryUnbiasedInterruptTimePrecise
// //
QueryUnbiasedInterruptTime(&hectons); QueryUnbiasedInterruptTime(&hectons);
*ts = timespec_fromnanos(hectons * 100); *ts = WindowsDurationToTimeSpec(hectons);
return 0; return 0;
case _CLOCK_BOOTTIME: case _CLOCK_BOOTTIME:
// //
@ -95,7 +95,7 @@ textwindows int sys_clock_gettime_nt(int clock, struct timespec *ts) {
// —Quoth MSDN § Interrupt Time // —Quoth MSDN § Interrupt Time
// //
QueryInterruptTimePrecise(&hectons); QueryInterruptTimePrecise(&hectons);
*ts = timespec_fromnanos(hectons * 100); *ts = WindowsDurationToTimeSpec(hectons);
return 0; return 0;
case _CLOCK_PROCESS_CPUTIME_ID: case _CLOCK_PROCESS_CPUTIME_ID:
GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel, GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel,

View file

@ -21,16 +21,15 @@
.privileged .privileged
cosmo_futex_thunk: cosmo_futex_thunk:
beg
pro
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov %rcx,%r10 mov %rcx,%r10
mov __NR_futex,%eax mov __NR_futex,%eax
clc clc
syscall syscall
jnc 1f jnc 1f
neg %eax neg %eax
1: pop %rbp
#elif defined(__aarch64__) #elif defined(__aarch64__)
ldr x7,=__hostos ldr x7,=__hostos
ldr w7,[x7] ldr w7,[x7]
@ -46,5 +45,7 @@ cosmo_futex_thunk:
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif /* __x86_64__ */ #endif /* __x86_64__ */
1: ret 1: epi
ret
end
.endfn cosmo_futex_thunk,globl,hidden .endfn cosmo_futex_thunk,globl,hidden

View file

@ -0,0 +1,32 @@
/*-*- 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 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/intrin/describeflags.h"
#include "libc/macros.h"
#include "libc/nt/enum/memflags.h"
static const struct DescribeFlags kNtAllocationTypeFlags[] = {
{kNtMemCommit, "Commit"}, //
{kNtMemReserve, "Reserve"}, //
{kNtMemReset, "Reset"}, //
};
const char *_DescribeNtAllocationType(char buf[48], uint32_t x) {
return _DescribeFlags(buf, 48, kNtAllocationTypeFlags,
ARRAYLEN(kNtAllocationTypeFlags), "kNtMem", x);
}

View file

@ -29,6 +29,7 @@ const char *_DescribeMapping(char[8], int, int) libcesque;
const char *_DescribeMremapFlags(char[30], int) libcesque; const char *_DescribeMremapFlags(char[30], int) libcesque;
const char *_DescribeMsg(char[16], int) libcesque; const char *_DescribeMsg(char[16], int) libcesque;
const char *_DescribeMsyncFlags(char[48], int) libcesque; const char *_DescribeMsyncFlags(char[48], int) libcesque;
const char *_DescribeNtAllocationType(char[48], uint32_t);
const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque; const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque;
const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque; const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque;
const char *_DescribeNtCreationDisposition(uint32_t) libcesque; const char *_DescribeNtCreationDisposition(uint32_t) libcesque;
@ -87,6 +88,7 @@ const char *_DescribeWhichPrio(char[12], int) libcesque;
#define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x) #define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x)
#define DescribeMsg(x) _DescribeMsg(alloca(16), x) #define DescribeMsg(x) _DescribeMsg(alloca(16), x)
#define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x) #define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x)
#define DescribeNtAllocationType(x) _DescribeNtAllocationType(alloca(48), x)
#define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x) #define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x)
#define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x) #define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x)
#define DescribeNtFileAccessFlags(x) _DescribeNtFileAccessFlags(alloca(512), x) #define DescribeNtFileAccessFlags(x) _DescribeNtFileAccessFlags(alloca(512), x)

View file

@ -19,7 +19,6 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/metalfile.internal.h" #include "libc/calls/metalfile.internal.h"
#include "libc/intrin/directmap.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -32,19 +31,11 @@
static uint64_t sys_mmap_metal_break; static uint64_t sys_mmap_metal_break;
static struct DirectMap bad_mmap(void) { void *sys_mmap_metal(void *vaddr, size_t size, int prot, int flags, int fd,
struct DirectMap res; int64_t off) {
res.addr = (void *)-1;
res.maphandle = -1;
return res;
}
struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
int fd, int64_t off) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
size_t i; size_t i;
struct mman *mm; struct mman *mm;
struct DirectMap res;
uint64_t addr, faddr = 0, page, e, *pte, *fdpte, *pml4t; uint64_t addr, faddr = 0, page, e, *pte, *fdpte, *pml4t;
mm = __get_mm(); mm = __get_mm();
pml4t = __get_pml4t(); pml4t = __get_pml4t();
@ -54,18 +45,18 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
struct Fd *sfd; struct Fd *sfd;
struct MetalFile *file; struct MetalFile *file;
if (off < 0 || fd < 0 || fd >= g_fds.n) if (off < 0 || fd < 0 || fd >= g_fds.n)
return bad_mmap(); return MAP_FAILED;
sfd = &g_fds.p[fd]; sfd = &g_fds.p[fd];
if (sfd->kind != kFdFile) if (sfd->kind != kFdFile)
return bad_mmap(); return MAP_FAILED;
file = (struct MetalFile *)sfd->handle; file = (struct MetalFile *)sfd->handle;
/* TODO: allow mapping partial page at end of file, if file size not /* TODO: allow mapping partial page at end of file, if file size not
* multiple of page size */ * multiple of page size */
if (off > file->size || size > file->size - off) if (off > file->size || size > file->size - off)
return bad_mmap(); return MAP_FAILED;
faddr = (uint64_t)file->base + off; faddr = (uint64_t)file->base + off;
if (faddr % 4096 != 0) if (faddr % 4096 != 0)
return bad_mmap(); return MAP_FAILED;
} }
if (!(flags & MAP_FIXED_linux)) { if (!(flags & MAP_FIXED_linux)) {
if (!addr) { if (!addr) {
@ -88,7 +79,7 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
if ((flags & MAP_ANONYMOUS_linux)) { if ((flags & MAP_ANONYMOUS_linux)) {
page = __new_page(mm); page = __new_page(mm);
if (!page) if (!page)
return bad_mmap(); return MAP_FAILED;
__clear_page(BANE + page); __clear_page(BANE + page);
e = page | PAGE_RSRV | PAGE_U; e = page | PAGE_RSRV | PAGE_U;
if ((prot & PROT_WRITE)) if ((prot & PROT_WRITE))
@ -114,9 +105,7 @@ struct DirectMap sys_mmap_metal(void *vaddr, size_t size, int prot, int flags,
break; break;
} }
} }
res.addr = (void *)addr; return (void *)addr;
res.maphandle = -1;
return res;
} }
#endif /* __x86_64__ */ #endif /* __x86_64__ */

View file

@ -1,122 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/errno.h"
#include "libc/intrin/directmap.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
int flags, int fd, int64_t off) {
int64_t handle;
if (flags & MAP_ANONYMOUS) {
handle = kNtInvalidHandleValue;
} else {
handle = g_fds.p[fd].handle;
}
// mark map handle as inheritable if fork might need it
const struct NtSecurityAttributes *mapsec;
if ((flags & MAP_TYPE) == MAP_SHARED) {
mapsec = &kNtIsInheritable;
} else {
mapsec = 0;
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
int iscow = false;
struct ProtectNt fl;
if (handle != -1) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute};
iscow = true;
} else {
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
fl = (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
}
} else {
unassert(flags & MAP_ANONYMOUS);
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
int e = errno;
struct DirectMap dm;
TryAgain:
if ((dm.maphandle = CreateFileMapping(handle, mapsec, fl.flags1,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
size, addr))) {
uint32_t oldprot;
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot))
return dm;
UnmapViewOfFile(dm.addr);
}
CloseHandle(dm.maphandle);
} else if (!(prot & PROT_EXEC) && //
(fl.flags2 & kNtFileMapExecute) && //
GetLastError() == kNtErrorAccessDenied) {
// your file needs to have been O_CREAT'd with exec `mode` bits in
// order to be mapped with executable permission. we always try to
// get execute permission if the kernel will give it to us because
// win32 would otherwise forbid mprotect() from elevating later on
fl.flags2 &= ~kNtFileMapExecute;
switch (fl.flags1) {
case kNtPageExecuteWritecopy:
fl.flags1 = kNtPageWritecopy;
break;
case kNtPageExecuteReadwrite:
fl.flags1 = kNtPageReadwrite;
break;
case kNtPageExecuteRead:
fl.flags1 = kNtPageReadonly;
break;
default:
__builtin_unreachable();
}
errno = e;
goto TryAgain;
}
dm.maphandle = kNtInvalidHandleValue;
dm.addr = (void *)(intptr_t)-1;
return dm;
}

View file

@ -1,67 +0,0 @@
/*-*- 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 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/directmap.h"
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/errfuns.h"
/**
* Obtains memory mapping directly from system.
*
* The mmap() function needs to track memory mappings in order to
* support Windows NT and Address Sanitizer. That memory tracking can be
* bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle().
*
* @asyncsignalsafe
*/
struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) {
struct DirectMap d;
if ((__virtualsize += size) >= __virtualmax) {
d.maphandle = kNtInvalidHandleValue;
d.addr = (void *)enomem();
} else if (IsXnuSilicon()) {
long p = _sysret(__syslib->__mmap(addr, size, prot, flags, fd, off));
d.maphandle = kNtInvalidHandleValue;
d.addr = (void *)p;
} else if (!IsWindows() && !IsMetal()) {
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
d.maphandle = kNtInvalidHandleValue;
} else if (IsMetal()) {
d = sys_mmap_metal(addr, size, prot, flags, fd, off);
} else {
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
}
if (d.addr == MAP_FAILED)
__virtualsize -= size;
KERNTRACE("sys_mmap(%.12p, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off,
d.addr, d.maphandle);
return d;
}

View file

@ -2,19 +2,7 @@
#define COSMOPOLITAN_LIBC_INTRIN_DIRECTMAP_H_ #define COSMOPOLITAN_LIBC_INTRIN_DIRECTMAP_H_
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
struct ProtectNt { void *sys_mmap_metal(void *, size_t, int, int, int, int64_t) libcesque;
uint32_t flags1;
uint32_t flags2;
};
struct DirectMap {
void *addr;
int64_t maphandle;
};
struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t) libcesque; int sys_munmap_metal(void *, size_t) libcesque;
int __prot2nt(int, int) libcesque; int __prot2nt(int, int) libcesque;

View file

@ -46,14 +46,11 @@
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#define OPEN_MAX 16
#ifdef __x86_64__ #ifdef __x86_64__
__static_yoink("_init_fds"); __static_yoink("_init_fds");
#endif #endif
struct Fds g_fds; struct Fds g_fds;
static struct Fd g_fds_static[OPEN_MAX];
static bool TokAtoi(const char **str, long *res) { static bool TokAtoi(const char **str, long *res) {
int c, d; int c, d;
@ -92,15 +89,9 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
fds = &g_fds; fds = &g_fds;
fds->n = 4; fds->n = 4;
atomic_store_explicit(&fds->f, 3, memory_order_relaxed); atomic_store_explicit(&fds->f, 3, memory_order_relaxed);
if (_weaken(_extend)) {
fds->p = fds->e = (void *)kMemtrackFdsStart; fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->e = fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
_weaken(_extend)(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize); kMemtrackFdsStart + kMemtrackFdsSize);
} else {
fds->p = g_fds_static;
fds->e = g_fds_static + OPEN_MAX;
}
// inherit standard i/o file descriptors // inherit standard i/o file descriptors
if (IsMetal()) { if (IsMetal()) {
@ -154,8 +145,7 @@ textstartup void __init_fds(int argc, char **argv, char **envp) {
break; break;
if (!TokAtoi(&fdspec, &protocol)) if (!TokAtoi(&fdspec, &protocol))
break; break;
if (_weaken(__ensurefds_unlocked)) __ensurefds_unlocked(fd);
_weaken(__ensurefds_unlocked)(fd);
struct Fd *f = fds->p + fd; struct Fd *f = fds->p + fd;
if (f->handle && f->handle != -1 && f->handle != handle) { if (f->handle && f->handle != -1 && f->handle != handle) {
CloseHandle(f->handle); CloseHandle(f->handle);

View file

@ -26,7 +26,9 @@
// @see setcontext() // @see setcontext()
.ftrace1 .ftrace1
getcontext: getcontext:
beg
.ftrace2 .ftrace2
#include "libc/intrin/getcontext.inc" #include "libc/intrin/getcontext.inc"
jmp __getcontextsig jmp __getcontextsig
end
.endfn getcontext,globl .endfn getcontext,globl

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -33,10 +34,14 @@
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/memflags.h" #include "libc/nt/enum/memflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/errors.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/runtime/zipos.internal.h" #include "libc/runtime/zipos.internal.h"
#include "libc/stdckdint.h" #include "libc/stdckdint.h"
#include "libc/stdio/sysparam.h" #include "libc/stdio/sysparam.h"
@ -80,6 +85,11 @@
} while (0) } while (0)
#endif #endif
struct DirectMap {
void *addr;
int64_t hand;
};
int __maps_compare(const struct Tree *ra, const struct Tree *rb) { int __maps_compare(const struct Tree *ra, const struct Tree *rb) {
const struct Map *a = (const struct Map *)MAP_TREE_CONTAINER(ra); const struct Map *a = (const struct Map *)MAP_TREE_CONTAINER(ra);
const struct Map *b = (const struct Map *)MAP_TREE_CONTAINER(rb); const struct Map *b = (const struct Map *)MAP_TREE_CONTAINER(rb);
@ -284,7 +294,6 @@ void __maps_free(struct Map *map) {
&__maps.freed, &tip, ABA(map, TAG(tip) + 1), memory_order_release, &__maps.freed, &tip, ABA(map, TAG(tip) + 1), memory_order_release,
memory_order_relaxed)) memory_order_relaxed))
break; break;
pthread_pause_np();
} }
} }
@ -421,7 +430,7 @@ void __maps_insert(struct Map *map) {
__maps_check(); __maps_check();
} }
// adds interval to rbtree (no sys_mmap) // adds interval to rbtree
bool __maps_track(char *addr, size_t size, int prot, int flags) { bool __maps_track(char *addr, size_t size, int prot, int flags) {
struct Map *map; struct Map *map;
if (!(map = __maps_alloc())) if (!(map = __maps_alloc()))
@ -447,16 +456,132 @@ int __maps_untrack(char *addr, size_t size) {
return rc; return rc;
} }
textwindows dontinline static struct DirectMap sys_mmap_nt(
void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
struct DirectMap dm;
// it's 5x faster
if ((flags & MAP_ANONYMOUS) && (flags & MAP_TYPE) != MAP_SHARED) {
if (!(dm.addr = VirtualAlloc(addr, size, kNtMemReserve | kNtMemCommit,
__prot2nt(prot, false)))) {
dm.addr = MAP_FAILED;
}
dm.hand = MAPS_VIRTUAL;
return dm;
}
int64_t file_handle;
if (flags & MAP_ANONYMOUS) {
file_handle = kNtInvalidHandleValue;
} else {
file_handle = g_fds.p[fd].handle;
}
// mark map handle as inheritable if fork might need it
const struct NtSecurityAttributes *mapsec;
if ((flags & MAP_TYPE) == MAP_SHARED) {
mapsec = &kNtIsInheritable;
} else {
mapsec = 0;
}
// nt will whine under many circumstances if we change the execute bit
// later using mprotect(). the workaround is to always request execute
// and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
int iscow = 0;
int page_flags;
int file_flags;
if (file_handle != -1) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
page_flags = kNtPageExecuteWritecopy;
file_flags = kNtFileMapCopy | kNtFileMapExecute;
iscow = 1;
} else {
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
page_flags = kNtPageExecuteRead;
file_flags = kNtFileMapRead | kNtFileMapExecute;
} else {
page_flags = kNtPageExecuteReadwrite;
file_flags = kNtFileMapWrite | kNtFileMapExecute;
}
}
} else {
page_flags = kNtPageExecuteReadwrite;
file_flags = kNtFileMapWrite | kNtFileMapExecute;
}
int e = errno;
TryAgain:
if ((dm.hand = CreateFileMapping(file_handle, mapsec, page_flags,
(size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.hand, file_flags, off >> 32, off, size,
addr))) {
uint32_t oldprot;
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot))
return dm;
UnmapViewOfFile(dm.addr);
}
CloseHandle(dm.hand);
} else if (!(prot & PROT_EXEC) && //
(file_flags & kNtFileMapExecute) && //
GetLastError() == kNtErrorAccessDenied) {
// your file needs to have been O_CREAT'd with exec `mode` bits in
// order to be mapped with executable permission. we always try to
// get execute permission if the kernel will give it to us because
// win32 would otherwise forbid mprotect() from elevating later on
file_flags &= ~kNtFileMapExecute;
switch (page_flags) {
case kNtPageExecuteWritecopy:
page_flags = kNtPageWritecopy;
break;
case kNtPageExecuteReadwrite:
page_flags = kNtPageReadwrite;
break;
case kNtPageExecuteRead:
page_flags = kNtPageReadonly;
break;
default:
__builtin_unreachable();
}
errno = e;
goto TryAgain;
}
dm.hand = kNtInvalidHandleValue;
dm.addr = (void *)(intptr_t)-1;
return dm;
}
static struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) {
struct DirectMap d;
if (IsXnuSilicon()) {
long p = _sysret(__syslib->__mmap(addr, size, prot, flags, fd, off));
d.hand = kNtInvalidHandleValue;
d.addr = (void *)p;
} else if (IsWindows()) {
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
} else if (IsMetal()) {
d.addr = sys_mmap_metal(addr, size, prot, flags, fd, off);
d.hand = kNtInvalidHandleValue;
} else {
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
d.hand = kNtInvalidHandleValue;
}
return d;
}
struct Map *__maps_alloc(void) { struct Map *__maps_alloc(void) {
struct Map *map; struct Map *map;
uintptr_t tip = atomic_load_explicit(&__maps.freed, memory_order_relaxed); uintptr_t tip = atomic_load_explicit(&__maps.freed, memory_order_relaxed);
while ((map = (struct Map *)PTR(tip))) { while ((map = (struct Map *)PTR(tip)))
if (atomic_compare_exchange_weak_explicit( if (atomic_compare_exchange_weak_explicit(
&__maps.freed, &tip, ABA(map->freed, TAG(tip) + 1), &__maps.freed, &tip, ABA(map->freed, TAG(tip) + 1),
memory_order_acquire, memory_order_relaxed)) memory_order_acquire, memory_order_relaxed))
return map; return map;
pthread_pause_np();
}
// we're creating sudden surprise memory. the user might be in the // we're creating sudden surprise memory. the user might be in the
// middle of carefully planning a fixed memory structure. we don't // middle of carefully planning a fixed memory structure. we don't
// want the system allocator to put our surprise memory inside it, // want the system allocator to put our surprise memory inside it,
@ -466,8 +591,6 @@ struct Map *__maps_alloc(void) {
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (sys.addr == MAP_FAILED) if (sys.addr == MAP_FAILED)
return 0; return 0;
if (IsWindows())
CloseHandle(sys.maphandle);
struct MapSlab *slab = sys.addr; struct MapSlab *slab = sys.addr;
while (!atomic_compare_exchange_weak(&__maps.slabs, &slab->next, slab)) { while (!atomic_compare_exchange_weak(&__maps.slabs, &slab->next, slab)) {
} }
@ -717,7 +840,7 @@ static void *__mmap_impl(char *addr, size_t size, int prot, int flags, int fd,
map->off = off; map->off = off;
map->prot = prot; map->prot = prot;
map->flags = flags; map->flags = flags;
map->hand = res.maphandle; map->hand = res.hand;
if (IsWindows()) { if (IsWindows()) {
map->iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1; map->iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1;
map->readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 && map->readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 &&

View file

@ -19,10 +19,8 @@
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/intrin/maps.h" #include "libc/intrin/maps.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h" #include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -36,28 +34,17 @@ textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int rc = 0; int rc = 0;
__maps_lock(); __maps_lock();
struct Map *next, *map; struct Map *map;
if (!(map = __maps_floor(addr))) if (!(map = __maps_floor(addr)))
map = __maps_first(); map = __maps_first();
for (; map && map->addr <= addr + size; map = next) { for (; map && map->addr <= addr + size; map = __maps_next(map)) {
next = __maps_next(map);
if (!__maps_isalloc(map))
continue;
if (map->flags & MAP_ANONYMOUS) if (map->flags & MAP_ANONYMOUS)
continue; continue; // msync() is about coherency between file and memory
if (MAX(addr, map->addr) >= MIN(addr + size, map->addr + map->size)) char *beg = MAX(addr, map->addr);
char *end = MIN(addr + size, map->addr + map->size);
if (beg >= end)
continue; // didn't overlap mapping continue; // didn't overlap mapping
if (!FlushViewOfFile(beg, end - beg))
// get true size of win32 allocation
size_t allocsize = map->size;
while (next && !__maps_isalloc(next) &&
next->addr + allocsize == next->addr) {
allocsize += next->size;
next = __maps_next(next);
}
// perform the flush
if (!FlushViewOfFile(map->addr, allocsize))
rc = -1; rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC? // TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
} }

View file

@ -68,23 +68,19 @@ int msync(void *addr, size_t size, int flags) {
} else { } else {
sysflags = MS_ASYNC; sysflags = MS_ASYNC;
} }
if (flags & MS_INVALIDATE) { if (flags & MS_INVALIDATE)
sysflags |= MS_INVALIDATE; sysflags |= MS_INVALIDATE;
}
// FreeBSD's manual says "The flags argument was both MS_ASYNC and // FreeBSD's manual says "The flags argument was both MS_ASYNC and
// MS_INVALIDATE. Only one of these flags is allowed." which makes // MS_INVALIDATE. Only one of these flags is allowed." which makes
// following the POSIX recommendation somewhat difficult. // following the POSIX recommendation somewhat difficult.
if (IsFreebsd()) { if (IsFreebsd())
if (sysflags == (MS_ASYNC | MS_INVALIDATE)) { if (sysflags == (MS_ASYNC | MS_INVALIDATE))
sysflags = MS_INVALIDATE; sysflags = MS_INVALIDATE;
}
}
// FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants // FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants
if (IsFreebsd()) { if (IsFreebsd())
sysflags >>= 1; sysflags >>= 1;
}
BEGIN_CANCELATION_POINT; BEGIN_CANCELATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -41,8 +41,6 @@ int sys_munmap(void *p, size_t n) {
} else { } else {
rc = __sys_munmap(p, n); rc = __sys_munmap(p, n);
} }
if (!rc)
__virtualsize -= n;
KERNTRACE("sys_munmap(%p, %'zu) → %d", p, n, rc); KERNTRACE("sys_munmap(%p, %'zu) → %d", p, n, rc);
return rc; return rc;
} }

View file

@ -83,11 +83,11 @@ struct SignalFrame {
}; };
__msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle; __msabi extern typeof(GetStdHandle) *const __imp_GetStdHandle;
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; __msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__msabi extern typeof(VirtualQuery) *const __imp_VirtualQuery; __msabi extern typeof(VirtualQuery) *const __imp_VirtualQuery;
__msabi extern typeof(WriteFile) *const __imp_WriteFile; __msabi extern typeof(WriteFile) *const __imp_WriteFile;
extern pthread_mutex_t __sig_worker_lock; atomic_int __sig_worker_state;
textwindows static bool __sig_ignored_by_default(int sig) { textwindows static bool __sig_ignored_by_default(int sig) {
return sig == SIGURG || // return sig == SIGURG || //
@ -566,7 +566,8 @@ textwindows wontreturn static void __sig_death(int sig, const char *thing) {
// //
forceinline void __sig_reguard(void *page) { forceinline void __sig_reguard(void *page) {
uint32_t old_protect; uint32_t old_protect;
__imp_VirtualProtect((void *)((uintptr_t)page & -__pagesize), __pagesize, __imp_VirtualProtectEx(GetCurrentProcess(),
(void *)((uintptr_t)page & -__pagesize), __pagesize,
kNtPageReadwrite | kNtPageGuard, &old_protect); kNtPageReadwrite | kNtPageGuard, &old_protect);
} }
@ -741,7 +742,8 @@ HAIRY static uint32_t __sig_worker(void *arg) {
STKSZ, PROT_READ | PROT_WRITE, STKSZ, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK); MAP_PRIVATE | MAP_ANONYMOUS | MAP_NOFORK);
for (;;) { for (;;) {
_pthread_mutex_lock(&__sig_worker_lock); // ok sys_execve_nt() might disable this worker
if (~__sig_worker_state & 2) {
// dequeue all pending signals and fire them off. if there's no // dequeue all pending signals and fire them off. if there's no
// thread that can handle them then __sig_generate will requeue // thread that can handle them then __sig_generate will requeue
@ -805,10 +807,12 @@ HAIRY static uint32_t __sig_worker(void *arg) {
} }
_pthread_unref(mark); _pthread_unref(mark);
} }
}
// wait until next scheduler quantum // wait until next scheduler quantum
_pthread_mutex_unlock(&__sig_worker_lock); __sig_worker_state |= 1;
Sleep(POLL_INTERVAL_MS); Sleep(POLL_INTERVAL_MS);
__sig_worker_state &= ~1;
} }
__builtin_unreachable(); __builtin_unreachable();
} }

View file

@ -30,8 +30,6 @@
// usually better that sigprocmask only strace the user is calling it. // usually better that sigprocmask only strace the user is calling it.
// plus, since we have a very specific use case, this code goes faster // plus, since we have a very specific use case, this code goes faster
struct Signals __sig;
sigset_t __sig_block(void) { sigset_t __sig_block(void) {
if (IsWindows() || IsMetal()) { if (IsWindows() || IsMetal()) {
if (__tls_enabled) if (__tls_enabled)

View file

@ -492,7 +492,7 @@ relegated bool TellOpenbsdThisIsStackMemory(void *addr, size_t size) {
// OpenBSD only permits RSP to occupy memory that's been explicitly // OpenBSD only permits RSP to occupy memory that's been explicitly
// defined as stack memory, i.e. `lo <= %rsp < hi` must be the case // defined as stack memory, i.e. `lo <= %rsp < hi` must be the case
relegated errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *attr) { relegated bool FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
// get interval // get interval
uintptr_t lo = (uintptr_t)attr->__stackaddr; uintptr_t lo = (uintptr_t)attr->__stackaddr;
@ -503,15 +503,11 @@ relegated errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *attr) {
hi = hi & -__pagesize; hi = hi & -__pagesize;
// tell os it's stack memory // tell os it's stack memory
errno_t olderr = errno; if (!TellOpenbsdThisIsStackMemory((void *)lo, hi - lo))
if (!TellOpenbsdThisIsStackMemory((void *)lo, hi - lo)) { return false;
errno_t err = errno;
errno = olderr;
return err;
}
// update attributes with usable stack address // update attributes with usable stack address
attr->__stackaddr = (void *)lo; attr->__stackaddr = (void *)lo;
attr->__stacksize = hi - lo; attr->__stacksize = hi - lo;
return 0; return true;
} }

View file

@ -8,7 +8,7 @@ void cosmo_stack_unlock(void);
void cosmo_stack_wipe(void); void cosmo_stack_wipe(void);
bool TellOpenbsdThisIsStackMemory(void *, size_t); bool TellOpenbsdThisIsStackMemory(void *, size_t);
errno_t FixupCustomStackOnOpenbsd(pthread_attr_t *); bool FixupCustomStackOnOpenbsd(pthread_attr_t *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_STACK_H_ */ #endif /* COSMOPOLITAN_LIBC_STACK_H_ */

View file

@ -31,17 +31,17 @@
// @returnstwice // @returnstwice
.ftrace1 .ftrace1
swapcontext: swapcontext:
beg
.ftrace2 .ftrace2
#include "libc/intrin/getcontext.inc" #include "libc/intrin/getcontext.inc"
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp pro
mov %rsp,%rbp cpush %rsi
push %rsi cpush %rsi
push %rsi
call __swapcontextsig call __swapcontextsig
pop %rdi cpop %rdi
pop %rdi cpop %rdi
pop %rbp epi
test %eax,%eax test %eax,%eax
jnz 1f jnz 1f
#elif defined(__aarch64__) #elif defined(__aarch64__)
@ -56,4 +56,5 @@ swapcontext:
#endif #endif
jmp __tailcontext jmp __tailcontext
1: ret 1: ret
end
.endfn swapcontext,globl .endfn swapcontext,globl

View file

@ -24,9 +24,9 @@
// //
// @return 0 on success, or -1 w/ errno // @return 0 on success, or -1 w/ errno
sys_sched_yield: sys_sched_yield:
beg
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp pro
mov %rsp,%rbp
xor %eax,%eax xor %eax,%eax
mov __hostos(%rip),%dl mov __hostos(%rip),%dl
@ -84,13 +84,16 @@ sys_sched_yield:
// fails a positive or negative errno might get returned. // fails a positive or negative errno might get returned.
#endif #endif
9: leave 9: epi
ret ret
#elif defined(__aarch64__) #elif defined(__aarch64__)
stp x29,x30,[sp,-32]! stp x29,x30,[sp,-32]!
mov x29,sp mov x29,sp
.cfi_adjust_cfa_offset 32
.cfi_rel_offset x29,16
.cfi_rel_offset x30,24
mov x3,0 mov x3,0
mov x2,0 mov x2,0
add x4,sp,16 add x4,sp,16
@ -101,10 +104,14 @@ sys_sched_yield:
mov x16,#0x5d // select(0,0,0,0,&blah) for xnu mov x16,#0x5d // select(0,0,0,0,&blah) for xnu
svc 0 svc 0
ldp x29,x30,[sp],32 ldp x29,x30,[sp],32
.cfi_adjust_cfa_offset -32
.cfi_restore x30
.cfi_restore x29
ret ret
#else #else
#error "arch unsupported" #error "arch unsupported"
#endif #endif
end
.endfn sys_sched_yield,globl .endfn sys_sched_yield,globl
.previous .previous

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney Copyright 2024 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,22 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/syscall-nt.internal.h" #include "libc/nt/memory.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/nt/process.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/processbasicinformation.h"
textwindows int sys_getppid_nt(void) { /**
struct NtProcessBasicInformation ProcessInformation; * Allocates memory on The New Technology.
uint32_t gotsize = 0; */
if (!NtError( textwindows void *VirtualAlloc(void *lpAddress, uint64_t dwSize,
NtQueryInformationProcess(GetCurrentProcess(), 0, &ProcessInformation, uint32_t flAllocationType, uint32_t flProtect) {
sizeof(ProcessInformation), &gotsize)) && return VirtualAllocEx(GetCurrentProcess(), lpAddress, dwSize,
gotsize >= sizeof(ProcessInformation) && flAllocationType, flProtect);
ProcessInformation.InheritedFromUniqueProcessId) {
return ProcessInformation.InheritedFromUniqueProcessId;
}
return GetCurrentProcessId();
} }

View file

@ -19,32 +19,23 @@
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.h" #include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/macros.h"
#include "libc/mem/alloca.h"
#include "libc/nt/enum/memflags.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
__msabi extern typeof(VirtualAllocEx) *const __imp_VirtualAllocEx; __msabi extern typeof(VirtualAllocEx) *const __imp_VirtualAllocEx;
static const char *DescribeAllocationType(char buf[48], uint32_t x) { /**
const struct DescribeFlags kAllocationTypeFlags[] = { * Allocates memory on The New Technology.
{kNtMemCommit, "Commit"}, // */
{kNtMemReserve, "Reserve"}, // textwindows void *VirtualAllocEx(int64_t hProcess, void *lpAddress,
{kNtMemReset, "Reset"}, // uint64_t dwSize, uint32_t flAllocationType,
}; uint32_t flProtect) {
return _DescribeFlags(buf, 48, kAllocationTypeFlags,
ARRAYLEN(kAllocationTypeFlags), "kNtMem", x);
}
void *VirtualAllocEx(int64_t hProcess, void *lpAddress, uint64_t dwSize,
uint32_t flAllocationType, uint32_t flProtect) {
void *res = __imp_VirtualAllocEx(hProcess, lpAddress, dwSize, void *res = __imp_VirtualAllocEx(hProcess, lpAddress, dwSize,
flAllocationType, flProtect); flAllocationType, flProtect);
if (!res) if (!res)
__winerr(); __winerr();
NTTRACE("VirtualAllocEx(%ld, %p, %'lu, %s, %s) → %p% m", hProcess, lpAddress, NTTRACE("VirtualAllocEx(%ld, %p, %'lu, %s, %s) → %p% m", hProcess, lpAddress,
dwSize, DescribeAllocationType(alloca(48), flAllocationType), dwSize, DescribeNtAllocationType(flAllocationType),
DescribeNtPageFlags(flProtect), res); DescribeNtPageFlags(flProtect), res);
return res; return res;
} }

View file

@ -19,4 +19,3 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
size_t __virtualmax = -1; size_t __virtualmax = -1;
size_t __virtualsize = 0;

View file

@ -58,9 +58,8 @@ textstartup void *_AcpiOsMapUncachedMemory(uintptr_t phy, size_t n) {
} }
textstartup static void *_AcpiOsAllocatePages(size_t n) { textstartup static void *_AcpiOsAllocatePages(size_t n) {
struct DirectMap dm = sys_mmap_metal(NULL, n, PROT_READ | PROT_WRITE, void *addr = sys_mmap_metal(NULL, n, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void *addr = dm.addr;
if (addr == (void *)-1) if (addr == (void *)-1)
addr = NULL; addr = NULL;
return addr; return addr;

View file

@ -12,6 +12,7 @@
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/ipc.h" #include "libc/nt/ipc.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/nls.h"
#include "libc/nt/paint.h" #include "libc/nt/paint.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/registry.h" #include "libc/nt/registry.h"
@ -1420,6 +1421,15 @@
#define HKEY_CURRENT_CONFIG kNtHkeyCurrentConfig #define HKEY_CURRENT_CONFIG kNtHkeyCurrentConfig
#define HKEY_DYN_DATA kNtHkeyDynData #define HKEY_DYN_DATA kNtHkeyDynData
#define HKEY_CURRENT_USER_LOCAL_SETTINGS kNtHkeyCurrentUserLocalSettings #define HKEY_CURRENT_USER_LOCAL_SETTINGS kNtHkeyCurrentUserLocalSettings
#define KEY_QUERY_VALUE kNtKeyQueryValue
#define KEY_SET_VALUE kNtKeySetValue
#define KEY_CREATE_SUB_KEY kNtKeyCreateSubKey
#define KEY_ENUMERATE_SUB_KEYS kNtKeyEnumerateSubKeys
#define KEY_NOTIFY kNtKeyNotify
#define KEY_CREATE_LINK kNtKeyCreateLink
#define KEY_WOW64_32KEY kNtWow6432Key
#define KEY_WOW64_64KEY kNtWow6464Key
#define KEY_WOW64_RES kNtWow64Res
#define KEY_READ kNtKeyRead #define KEY_READ kNtKeyRead
#define KEY_WRITE kNtKeyWrite #define KEY_WRITE kNtKeyWrite
#define KEY_EXECUTE kNtKeyExecute #define KEY_EXECUTE kNtKeyExecute
@ -4291,6 +4301,13 @@
#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) #define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) #define MAKE_SCODE(sev,fac,code) ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define CP_ACP 0
#define CP_OEMCP 1
#define CP_MACCP 2
#define CP_THREAD_ACP 3
#define CP_SYMBOL 42
#define CP_UTF7 65000
#define CP_UTF8 65001 #define CP_UTF8 65001
#endif /* COSMOPOLITAN_LIBC_COMPAT_INCLUDE_WINDOWS_H_ */ #endif /* COSMOPOLITAN_LIBC_COMPAT_INCLUDE_WINDOWS_H_ */

View file

@ -3,7 +3,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/w.h" #include "libc/sysv/consts/w.h"
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_

View file

@ -158,6 +158,60 @@
.weak \canonical .weak \canonical
.endm .endm
.macro beg
.cfi_startproc
.endm
.macro pro
#if defined(__x86_64__)
push %rbp
.cfi_adjust_cfa_offset 8
.cfi_rel_offset %rbp,0
mov %rsp,%rbp
.cfi_def_cfa_register %rbp
#elif defined(__aarch64__)
stp x29,x30,[sp,-16]!
mov x29,sp
.cfi_adjust_cfa_offset 16
.cfi_rel_offset x29,0
.cfi_rel_offset x30,8
#else
#error "unsupported architecture"
#endif
.endm
.macro epi
#if defined(__x86_64__)
.cfi_def_cfa_register %rsp
leave
.cfi_adjust_cfa_offset -8
.cfi_restore %rbp
#elif defined(__aarch64__)
ldp x29,x30,[sp],#16
.cfi_adjust_cfa_offset -16
.cfi_restore x30
.cfi_restore x29
#else
#error "unsupported architecture"
#endif
.endm
.macro end
.cfi_endproc
.endm
.macro cpush reg:req
push \reg
.cfi_adjust_cfa_offset 8
.cfi_rel_offset \reg,0
.endm
.macro cpop reg:req
pop \reg
.cfi_adjust_cfa_offset -8
.cfi_restore \reg
.endm
#ifdef __aarch64__ #ifdef __aarch64__
.macro jmp dest:req .macro jmp dest:req
b \dest b \dest

View file

@ -7,8 +7,8 @@
// @note public domain // @note public domain
// @see en.wikipedia.org/wiki/Sorting_network // @see en.wikipedia.org/wiki/Sorting_network
djbsort_avx2: djbsort_avx2:
push %rbp beg
mov %rsp,%rbp pro
push %r15 push %r15
push %r14 push %r14
push %r13 push %r13
@ -795,11 +795,13 @@ djbsort_avx2:
pop %r13 pop %r13
pop %r14 pop %r14
pop %r15 pop %r15
pop %rbp epi
ret ret
end
.endfn djbsort_avx2,globl,hidden .endfn djbsort_avx2,globl,hidden
minmax_vector: minmax_vector:
beg
cmp $7,%rdx cmp $7,%rdx
jg .L13 jg .L13
.L2: test %rdx,%rdx .L2: test %rdx,%rdx
@ -838,9 +840,11 @@ minmax_vector:
sub $8,%rdx sub $8,%rdx
jne .L7 jne .L7
ret ret
end
.endfn minmax_vector .endfn minmax_vector
int32_twostages_32: int32_twostages_32:
beg
sub $-128,%rdi sub $-128,%rdi
.L17: lea -128(%rdi),%rax .L17: lea -128(%rdi),%rax
test %rsi,%rsi test %rsi,%rsi
@ -866,13 +870,14 @@ int32_twostages_32:
add $512,%rdi add $512,%rdi
jmp .L17 jmp .L17
.L21: ret .L21: ret
end
.endfn int32_twostages_32 .endfn int32_twostages_32
int32_threestages: int32_threestages:
push %rbp beg
pro
imul $-24,%rdx,%r8 imul $-24,%rdx,%r8
lea 0(,%rdx,8),%rax lea 0(,%rdx,8),%rax
mov %rsp,%rbp
push %r15 push %r15
push %r14 push %r14
push %r13 push %r13
@ -961,11 +966,13 @@ int32_threestages:
pop %r13 pop %r13
pop %r14 pop %r14
pop %r15 pop %r15
pop %rbp epi
ret ret
end
.endfn int32_threestages .endfn int32_threestages
merge16_finish: merge16_finish:
beg
vpminsd %ymm1,%ymm0,%ymm3 vpminsd %ymm1,%ymm0,%ymm3
vpmaxsd %ymm1,%ymm0,%ymm0 vpmaxsd %ymm1,%ymm0,%ymm0
vperm2i128 $32,%ymm0,%ymm3,%ymm2 vperm2i128 $32,%ymm0,%ymm3,%ymm2
@ -994,9 +1001,11 @@ merge16_finish:
.L31: vmovdqu %ymm2,(%rdi) .L31: vmovdqu %ymm2,(%rdi)
vmovdqu %ymm0,32(%rdi) vmovdqu %ymm0,32(%rdi)
ret ret
end
.endfn merge16_finish .endfn merge16_finish
int32_sort_2power: int32_sort_2power:
beg
push %r13 push %r13
lea 16(%rsp),%r13 lea 16(%rsp),%r13
andq $-32,%rsp andq $-32,%rsp
@ -2075,6 +2084,7 @@ int32_sort_2power:
lea -16(%r13),%rsp lea -16(%r13),%rsp
pop %r13 pop %r13
ret ret
end
.endfn int32_sort_2power .endfn int32_sort_2power
.rodata.cst32 .rodata.cst32

View file

@ -32,7 +32,8 @@
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value // @param rax,rdx,xmm0,xmm1,st0,st1 is return value
// @see test/libc/runtime/gc_test.c // @see test/libc/runtime/gc_test.c
.ftrace1 .ftrace1
__gc: .ftrace2 __gc: beg
.ftrace2
#ifdef __x86_64__ #ifdef __x86_64__
@ -47,8 +48,7 @@ __gc: .ftrace2
mov 8(%r8),%r9 mov 8(%r8),%r9
mov 16(%r8),%rdi mov 16(%r8),%rdi
push 24(%r8) push 24(%r8)
push %rbp pro
mov %rsp,%rbp
sub $32,%rsp sub $32,%rsp
mov %rax,-8(%rbp) mov %rax,-8(%rbp)
mov %rdx,-16(%rbp) mov %rdx,-16(%rbp)
@ -57,7 +57,7 @@ __gc: .ftrace2
movdqa -32(%rbp),%xmm0 movdqa -32(%rbp),%xmm0
mov -16(%rbp),%rdx mov -16(%rbp),%rdx
mov -8(%rbp),%rax mov -8(%rbp),%rax
leave epi
ret ret
9: ud2 9: ud2
nop nop
@ -102,4 +102,5 @@ __gc: .ftrace2
#endif /* __x86_64__ */ #endif /* __x86_64__ */
end
.endfn __gc,globl,hidden .endfn __gc,globl,hidden

View file

@ -31,7 +31,9 @@
// @noreturn // @noreturn
.ftrace1 .ftrace1
gclongjmp: gclongjmp:
beg
.ftrace2 .ftrace2
pro
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
@ -65,4 +67,5 @@ gclongjmp:
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif /* __x86_64__ */ #endif /* __x86_64__ */
end
.endfn gclongjmp,globl .endfn gclongjmp,globl

View file

@ -26,7 +26,7 @@
// @see gclongjmp() // @see gclongjmp()
// @see siglongjmp() // @see siglongjmp()
.ftrace1 .ftrace1
longjmp: longjmp:beg
.ftrace2 .ftrace2
_longjmp: _longjmp:
#ifdef __x86_64__ #ifdef __x86_64__
@ -61,6 +61,7 @@ _longjmp:
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif
end
.endfn longjmp,globl .endfn longjmp,globl
.endfn _longjmp,globl .endfn _longjmp,globl
.alias longjmp,siglongjmp .alias longjmp,siglongjmp

View file

@ -30,8 +30,8 @@
// @note slower than __sysv2nt // @note slower than __sysv2nt
// @see NT2SYSV() macro // @see NT2SYSV() macro
__nt2sysv: __nt2sysv:
push %rbp beg
mov %rsp,%rbp pro
sub $256,%rsp sub $256,%rsp
push %rbx push %rbx
push %rdi push %rdi
@ -48,6 +48,7 @@ __nt2sysv:
pop %rsi pop %rsi
pop %rdi pop %rdi
pop %rbx pop %rbx
leave epi
ret ret
end
.endfn __nt2sysv,globl,hidden .endfn __nt2sysv,globl,hidden

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp advapi32,__imp_RegOpenKeyExA,RegOpenKeyExA
.text.windows
.ftrace1
RegOpenKeyExA:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_RegOpenKeyExA(%rip),%rax
jmp __sysv2nt6
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn RegOpenKeyExA,globl
.previous

View file

@ -1,6 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_ #ifndef COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_
#define COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_ #define COSMOPOLITAN_LIBC_NT_ENUM_KEYACCESS_H_
#define kNtKeyQueryValue 0x00000001
#define kNtKeySetValue 0x00000002
#define kNtKeyCreateSubKey 0x00000004
#define kNtKeyEnumerateSubKeys 0x00000008
#define kNtKeyNotify 0x00000010
#define kNtKeyCreateLink 0x00000020
#define kNtWow6432Key 0x00000200
#define kNtWow6464Key 0x00000100
#define kNtWow64Res 0x00000300
#define kNtKeyRead 0x00020019 #define kNtKeyRead 0x00020019
#define kNtKeyWrite 0x00020006 #define kNtKeyWrite 0x00020006
#define kNtKeyExecute 0x00020019 #define kNtKeyExecute 0x00020019

View file

@ -49,6 +49,7 @@ COSMOPOLITAN_C_START_
intptr_t LoadResource(int64_t hModule, int64_t hResInfo); intptr_t LoadResource(int64_t hModule, int64_t hResInfo);
uint32_t SetHandleCount(uint32_t uNumber); uint32_t SetHandleCount(uint32_t uNumber);
uint32_t GetLogicalDrives(void); uint32_t GetLogicalDrives(void);
uint32_t GetLogicalDriveStringsA(uint32_t nBufferLength, char *lpBuffer);
bool32 FlushFileBuffers(int64_t hFile); bool32 FlushFileBuffers(int64_t hFile);
int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess, int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess,
@ -205,6 +206,7 @@ uint32_t GetFinalPathNameByHandle(int64_t hFile, char16_t *out_path,
uint32_t GetFullPathName(const char16_t *lpFileName, uint32_t nBufferLength, uint32_t GetFullPathName(const char16_t *lpFileName, uint32_t nBufferLength,
char16_t *lpBuffer, char16_t **lpFilePart); char16_t *lpBuffer, char16_t **lpFilePart);
uint32_t GetShortPathName(const char16_t *lpszLongPath, char16_t *out_lpszShortPath, uint32_t cchBuffer);
bool32 GetOverlappedResult(int64_t hFile, struct NtOverlapped *lpOverlapped, bool32 GetOverlappedResult(int64_t hFile, struct NtOverlapped *lpOverlapped,
uint32_t *lpNumberOfBytesTransferred, bool32 bWait); uint32_t *lpNumberOfBytesTransferred, bool32 bWait);

19
libc/nt/kernel32/GetACP.S Normal file
View file

@ -0,0 +1,19 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetACP,GetACP
.text.windows
.ftrace1
GetACP:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
sub $32,%rsp
call *__imp_GetACP(%rip)
leave
#elif defined(__aarch64__)
mov x0,#0
#endif
ret
.endfn GetACP,globl
.previous

View file

@ -1,18 +1,18 @@
#include "libc/nt/codegen.h" #include "libc/nt/codegen.h"
.imp kernel32,__imp_VirtualAlloc,VirtualAlloc .imp kernel32,__imp_GetCPInfoExW,GetCPInfoExW
.text.windows .text.windows
.ftrace1 .ftrace1
VirtualAlloc: GetCPInfoEx:
.ftrace2 .ftrace2
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
mov __imp_VirtualAlloc(%rip),%rax mov __imp_GetCPInfoExW(%rip),%rax
jmp __sysv2nt jmp __sysv2nt
#elif defined(__aarch64__) #elif defined(__aarch64__)
mov x0,#0 mov x0,#0
ret ret
#endif #endif
.endfn VirtualAlloc,globl .endfn GetCPInfoEx,globl
.previous .previous

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetLogicalDriveStringsA,GetLogicalDriveStringsA
.text.windows
.ftrace1
GetLogicalDriveStringsA:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_GetLogicalDriveStringsA(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn GetLogicalDriveStringsA,globl
.previous

View file

@ -0,0 +1,19 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetOEMCP,GetOEMCP
.text.windows
.ftrace1
GetOEMCP:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
sub $32,%rsp
call *__imp_GetOEMCP(%rip)
leave
#elif defined(__aarch64__)
mov x0,#0
#endif
ret
.endfn GetOEMCP,globl
.previous

View file

@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_GetShortPathNameW,GetShortPathNameW
.text.windows
.ftrace1
GetShortPathName:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_GetShortPathNameW(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn GetShortPathName,globl
.previous

View file

@ -9,7 +9,6 @@
# KERNEL32.DLL # KERNEL32.DLL
# #
# Name Actual DLL Arity # Name Actual DLL Arity
imp '' CreateDirectoryW kernel32 2 imp '' CreateDirectoryW kernel32 2
imp '' CreateFileA kernel32 7 imp '' CreateFileA kernel32 7
imp '' CreateFileMappingNumaW kernel32 7 imp '' CreateFileMappingNumaW kernel32 7
@ -130,10 +129,12 @@ imp 'GetFileTime' GetFileTime kernel32 4
imp 'GetFileType' GetFileType kernel32 1 imp 'GetFileType' GetFileType kernel32 1
imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 4 imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 4
imp 'GetFullPathName' GetFullPathNameW kernel32 4 imp 'GetFullPathName' GetFullPathNameW kernel32 4
imp 'GetShortPathName' GetShortPathNameW kernel32 3
imp 'GetHandleInformation' GetHandleInformation kernel32 2 imp 'GetHandleInformation' GetHandleInformation kernel32 2
imp 'GetLargestConsoleWindowSize' GetLargestConsoleWindowSize kernel32 1 imp 'GetLargestConsoleWindowSize' GetLargestConsoleWindowSize kernel32 1
imp 'GetLastError' GetLastError kernel32 0 imp 'GetLastError' GetLastError kernel32 0
imp 'GetLogicalDrives' GetLogicalDrives kernel32 0 imp 'GetLogicalDrives' GetLogicalDrives kernel32 0
imp 'GetLogicalDriveStringsA' GetLogicalDriveStringsA kernel32 2
imp 'GetMaximumProcessorCount' GetMaximumProcessorCount kernel32 1 # Windows 7+ imp 'GetMaximumProcessorCount' GetMaximumProcessorCount kernel32 1 # Windows 7+
imp 'GetModuleFileName' GetModuleFileNameW kernel32 3 imp 'GetModuleFileName' GetModuleFileNameW kernel32 3
imp 'GetModuleHandle' GetModuleHandleA kernel32 1 imp 'GetModuleHandle' GetModuleHandleA kernel32 1
@ -187,6 +188,9 @@ imp 'GetVolumeInformationByHandle' GetVolumeInformationByHandleW kernel32
imp 'GetVolumePathName' GetVolumePathNameW kernel32 3 imp 'GetVolumePathName' GetVolumePathNameW kernel32 3
imp 'GetWindowsDirectory' GetWindowsDirectoryW kernel32 2 imp 'GetWindowsDirectory' GetWindowsDirectoryW kernel32 2
imp 'GetWindowsDirectoryA' GetWindowsDirectoryA kernel32 2 imp 'GetWindowsDirectoryA' GetWindowsDirectoryA kernel32 2
imp 'GetOEMCP' GetOEMCP kernel32 0
imp 'GetACP' GetACP kernel32 0
imp 'GetCPInfoEx' GetCPInfoExW kernel32 3
imp 'GlobalAlloc' GlobalAlloc kernel32 2 imp 'GlobalAlloc' GlobalAlloc kernel32 2
imp 'GlobalFree' GlobalFree kernel32 1 imp 'GlobalFree' GlobalFree kernel32 1
imp 'GlobalLock' GlobalLock kernel32 1 imp 'GlobalLock' GlobalLock kernel32 1
@ -303,7 +307,6 @@ imp 'UnlockFile' UnlockFile kernel32 5
imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 2 imp 'UnmapViewOfFile2' UnmapViewOfFile2 kernel32 2
imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 3 imp 'UnmapViewOfFileEx' UnmapViewOfFileEx kernel32 3
imp 'UpdateProcThreadAttribute' UpdateProcThreadAttribute kernel32 7 imp 'UpdateProcThreadAttribute' UpdateProcThreadAttribute kernel32 7
imp 'VirtualAlloc' VirtualAlloc kernel32 4
imp 'VirtualFree' VirtualFree kernel32 3 imp 'VirtualFree' VirtualFree kernel32 3
imp 'VirtualLock' VirtualLock kernel32 2 imp 'VirtualLock' VirtualLock kernel32 2
imp 'VirtualQuery' VirtualQuery kernel32 3 imp 'VirtualQuery' VirtualQuery kernel32 3
@ -358,6 +361,7 @@ imp 'RegLoadKey' RegLoadKeyW advapi32 3
imp 'RegNotifyChangeKeyValue' RegNotifyChangeKeyValue advapi32 5 imp 'RegNotifyChangeKeyValue' RegNotifyChangeKeyValue advapi32 5
imp 'RegOpenCurrentUser' RegOpenCurrentUser advapi32 2 imp 'RegOpenCurrentUser' RegOpenCurrentUser advapi32 2
imp 'RegOpenKeyEx' RegOpenKeyExW advapi32 5 imp 'RegOpenKeyEx' RegOpenKeyExW advapi32 5
imp 'RegOpenKeyExA' RegOpenKeyExA advapi32 5
imp 'RegOpenUserClassesRoot' RegOpenUserClassesRoot advapi32 4 imp 'RegOpenUserClassesRoot' RegOpenUserClassesRoot advapi32 4
imp 'RegOverridePredefKey' RegOverridePredefKey advapi32 2 imp 'RegOverridePredefKey' RegOverridePredefKey advapi32 2
imp 'RegQueryInfoKey' RegQueryInfoKeyW advapi32 12 imp 'RegQueryInfoKey' RegQueryInfoKeyW advapi32 12

35
libc/nt/nls.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef COSMOPOLITAN_LIBC_NT_NLS_H_
#define COSMOPOLITAN_LIBC_NT_NLS_H_
#include "libc/nt/struct/cpinfoex.h"
/* ░░░░
cosmopolitan § new technology » internationalization
*/
COSMOPOLITAN_C_START_
uint32_t GetOEMCP();
uint32_t GetACP();
bool32 GetCPInfoEx(uint32_t CodePage, uint32_t dwFlags, struct NtCpInfoEx *out_lpCPInfoEx) paramsnonnull((3));
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_NT_NLS_H_ */

View file

@ -51,6 +51,8 @@ int RegOpenKey(int64_t hKey, const char16_t *opt_lpSubKey,
int RegOpenKeyEx(int64_t hKey, const char16_t *opt_lpSubKey, int RegOpenKeyEx(int64_t hKey, const char16_t *opt_lpSubKey,
uint32_t opt_ulOptions, int samDesired, int64_t *out_phkResult) uint32_t opt_ulOptions, int samDesired, int64_t *out_phkResult)
paramsnonnull((5)); paramsnonnull((5));
int RegOpenKeyExA(int64_t hKey, const char *opt_lpSubKey, uint32_t opt_ulOptions,
int samDesired, int64_t *out_phkResult) paramsnonnull((5));
int RegCloseKey(int64_t hKey); int RegCloseKey(int64_t hKey);
int RegGetValue(int64_t hkey, const char16_t *opt_lpSubKey, int RegGetValue(int64_t hkey, const char16_t *opt_lpSubKey,

13
libc/nt/struct/cpinfoex.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_
#define COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_
struct NtCpInfoEx {
uint32_t MaxCharSize;
uint8_t DefaultChar[2];
uint8_t LeadByte[12];
char16_t UnicodeDefaultChar;
uint32_t CodePage;
char16_t CodePageName[260];
};
#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_CPINFOEX_H_ */

View file

@ -30,6 +30,7 @@ LIBC_PROC_A_DIRECTDEPS = \
LIBC_MEM \ LIBC_MEM \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \ LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_NT_PSAPI \ LIBC_NT_PSAPI \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_STR \ LIBC_STR \

View file

@ -22,7 +22,6 @@
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/fds.h" #include "libc/intrin/fds.h"
#include "libc/intrin/maps.h" #include "libc/intrin/maps.h"
#include "libc/intrin/strace.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
@ -24,16 +25,23 @@
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/fds.h" #include "libc/intrin/fds.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nt/accounting.h"
#include "libc/nt/enum/processaccess.h" #include "libc/nt/enum/processaccess.h"
#include "libc/nt/enum/startf.h" #include "libc/nt/enum/startf.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/startupinfo.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/proc/describefds.internal.h" #include "libc/proc/describefds.internal.h"
#include "libc/proc/ntspawn.h" #include "libc/proc/ntspawn.h"
@ -41,18 +49,19 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#ifdef __x86_64__ #ifdef __x86_64__
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess; __msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
extern pthread_mutex_t __sig_worker_lock; extern atomic_int __sig_worker_state;
static void sys_execve_nt_abort(sigset_t sigmask) { static void sys_execve_nt_abort(sigset_t sigmask) {
_pthread_unlock(); __sig_worker_state &= ~2;
_pthread_mutex_unlock(&__sig_worker_lock);
__sig_unblock(sigmask); __sig_unblock(sigmask);
} }
@ -61,17 +70,17 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
// execve() needs to be @asyncsignalsafe // execve() needs to be @asyncsignalsafe
sigset_t sigmask = __sig_block(); sigset_t sigmask = __sig_block();
_pthread_mutex_lock(&__sig_worker_lock); // order matters __sig_worker_state |= 2;
_pthread_lock(); // order matters for (;;)
if (__sig_worker_state & 1)
break;
// new process should be a child of our parent // new process should be a child of our parent
int64_t hParentProcess; int64_t hParentProcess =
int ppid = sys_getppid_nt(); sys_getppid_nt_win32
if (!(hParentProcess = OpenProcess( ? OpenProcess(kNtProcessDupHandle | kNtProcessCreateProcess, false,
kNtProcessDupHandle | kNtProcessCreateProcess, false, ppid))) { sys_getppid_nt_win32)
sys_execve_nt_abort(sigmask); : 0;
return -1;
}
// inherit pid // inherit pid
char pidvar[11 + 21]; char pidvar[11 + 21];
@ -81,6 +90,16 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
char maskvar[6 + 21]; char maskvar[6 + 21];
FormatUint64(stpcpy(maskvar, "_MASK="), sigmask); FormatUint64(stpcpy(maskvar, "_MASK="), sigmask);
// inherit parent process id
char ppidvar[12 + 21 + 1 + 21 + 1], *p = ppidvar;
p = stpcpy(p, "_COSMO_PPID=");
if (hParentProcess) {
p = FormatUint64(p, sys_getppid_nt_win32);
*p++ = ':';
p = FormatUint64(p, __pid);
setenv("_COSMO_PPID", ppidvar, true);
}
// define stdio handles for the spawned subprocess // define stdio handles for the spawned subprocess
struct NtStartupInfo si = { struct NtStartupInfo si = {
.cb = sizeof(struct NtStartupInfo), .cb = sizeof(struct NtStartupInfo),
@ -94,13 +113,22 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
} }
} }
// which process is responsible for spawning the child?
int64_t hCreatorProcess;
if (hParentProcess) {
hCreatorProcess = hParentProcess;
} else {
hCreatorProcess = GetCurrentProcess();
}
// pass serialized file descriptor table in environment // pass serialized file descriptor table in environment
char *fdspec; char *fdspec;
int64_t *lpExplicitHandles; int64_t *lpExplicitHandles;
uint32_t dwExplicitHandleCount; uint32_t dwExplicitHandleCount;
if (!(fdspec = __describe_fds(g_fds.p, g_fds.n, &si, hParentProcess, if (!(fdspec = __describe_fds(g_fds.p, g_fds.n, &si, hCreatorProcess,
&lpExplicitHandles, &dwExplicitHandleCount))) { &lpExplicitHandles, &dwExplicitHandleCount))) {
CloseHandle(hParentProcess); if (hParentProcess)
__imp_CloseHandle(hParentProcess);
sys_execve_nt_abort(sigmask); sys_execve_nt_abort(sigmask);
return -1; return -1;
} }
@ -114,12 +142,14 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
// launch the process // launch the process
struct NtProcessInformation pi; struct NtProcessInformation pi;
int rc = ntspawn(&(struct NtSpawnArgs){ int rc = ntspawn(&(struct NtSpawnArgs){
AT_FDCWD, program, argv, envp, (char *[]){fdspec, maskvar, pidvar, 0}, 0, AT_FDCWD, program, argv, envp,
0, hParentProcess, lpExplicitHandles, dwExplicitHandleCount, &si, &pi}); (char *[]){fdspec, maskvar, pidvar, ppidvar, 0}, 0, 0, hCreatorProcess,
__undescribe_fds(hParentProcess, lpExplicitHandles, dwExplicitHandleCount); lpExplicitHandles, dwExplicitHandleCount, &si, &pi});
__undescribe_fds(hCreatorProcess, lpExplicitHandles, dwExplicitHandleCount);
if (rc == -1) { if (rc == -1) {
free(fdspec); free(fdspec);
CloseHandle(hParentProcess); if (hParentProcess)
__imp_CloseHandle(hParentProcess);
sys_execve_nt_abort(sigmask); sys_execve_nt_abort(sigmask);
if (GetLastError() == kNtErrorSharingViolation) { if (GetLastError() == kNtErrorSharingViolation) {
return etxtbsy(); return etxtbsy();
@ -128,10 +158,12 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
} }
} }
// check if parent spoofing worked
if (hParentProcess) {
// give child to libc/proc/proc.c worker thread in parent // give child to libc/proc/proc.c worker thread in parent
int64_t handle; int64_t handle;
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, &handle, if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess,
0, false, kNtDuplicateSameAccess)) { &handle, 0, false, kNtDuplicateSameAccess)) {
unassert(!(handle & 0xFFFFFFFFFF000000)); unassert(!(handle & 0xFFFFFFFFFF000000));
__imp_TerminateProcess(-1, 0x23000000u | handle); __imp_TerminateProcess(-1, 0x23000000u | handle);
} else { } else {
@ -142,4 +174,40 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
__builtin_unreachable(); __builtin_unreachable();
} }
// we couldn't reparent the new process
STRACE("warning: execve() lingering due to non-cosmo parent process");
// terminate other threads
_pthread_lock();
struct Dll *e;
struct PosixThread *me = _pthread_self();
for (e = dll_first(_pthread_list); e; e = dll_next(_pthread_list, e)) {
struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
if (pt == me)
continue;
TerminateThread(
atomic_load_explicit(&pt->tib->tib_syshand, memory_order_relaxed),
SIGKILL);
}
// wait for child to terminate and propagate exit code
for (;;) {
uint32_t status;
WaitForSingleObject(pi.hProcess, -1u);
GetExitCodeProcess(pi.hProcess, &status);
if (status != kNtStillActive) {
if ((status & 0xFF000000u) == 0x23000000u) {
// handle child execve()
__imp_CloseHandle(pi.hProcess);
pi.hProcess = status & 0x00FFFFFF;
} else {
// handle child _Exit()
if (status == 0xc9af3d51u)
status = kNtStillActive;
TerminateThisProcess(status);
}
}
}
}
#endif /* __x86_64__ */ #endif /* __x86_64__ */

View file

@ -57,11 +57,6 @@
* compiled by MSVC or Cygwin is launched instead, then only the stdio * compiled by MSVC or Cygwin is launched instead, then only the stdio
* file descriptors can be passed along. * file descriptors can be passed along.
* *
* On Windows, the parent process must be a cosmo program. If you're
* calling execve() from a program that wasn't launched by cosmopolitan
* bash, or some similar program, then ask yourself if what you really
* want is to either (a) call fork() first, or (b) use posix_spawn().
*
* On Windows, `argv` and `envp` can't contain binary strings. They need * On Windows, `argv` and `envp` can't contain binary strings. They need
* to be valid UTF-8 in order to round-trip the WIN32 API, without being * to be valid UTF-8 in order to round-trip the WIN32 API, without being
* corrupted. * corrupted.

View file

@ -44,8 +44,9 @@
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
@ -89,6 +90,7 @@ textwindows static void sys_fork_nt_child(void) {
// setup runtime // setup runtime
__klog_handle = 0; __klog_handle = 0;
__tls_index = __imp_TlsAlloc(); __tls_index = __imp_TlsAlloc();
__morph_tls();
__set_tls_win32(__winmain_tib); __set_tls_win32(__winmain_tib);
__tls_enabled = true; __tls_enabled = true;
@ -211,8 +213,6 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
// let's go // let's go
bool ok = true; bool ok = true;
uint32_t child_old_protect;
uint32_t parent_old_protect;
// copy memory manager maps // copy memory manager maps
for (struct MapSlab *slab = for (struct MapSlab *slab =
@ -225,11 +225,12 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
} }
// copy private memory maps // copy private memory maps
int alloc_prot = -1;
for (struct Map *map = __maps_first(); map; map = __maps_next(map)) { for (struct Map *map = __maps_first(); map; map = __maps_next(map)) {
if ((map->flags & MAP_TYPE) == MAP_SHARED) if ((map->flags & MAP_TYPE) == MAP_SHARED)
continue; continue; // shared memory doesn't need to be copied to subprocess
if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) != MAP_FILE) if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) != MAP_FILE)
continue; continue; // ignore things like signal worker stack memory
if (__maps_isalloc(map)) { if (__maps_isalloc(map)) {
size_t allocsize = map->size; size_t allocsize = map->size;
for (struct Map *m2 = __maps_next(map); m2; m2 = __maps_next(m2)) { for (struct Map *m2 = __maps_next(map); m2; m2 = __maps_next(m2)) {
@ -240,22 +241,44 @@ textwindows static int sys_fork_nt_parent(uint32_t dwCreationFlags) {
} }
} }
if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) == MAP_FILE) { if ((map->flags & MAP_NOFORK) && (map->flags & MAP_TYPE) == MAP_FILE) {
// portable executable segment
if (map->prot & PROT_EXEC)
// TODO(jart): write a __remorph_tls() function
continue;
if (!(map->prot & PROT_WRITE)) {
uint32_t child_old_protect;
ok = ok && !!VirtualProtectEx(procinfo.hProcess, map->addr, allocsize, ok = ok && !!VirtualProtectEx(procinfo.hProcess, map->addr, allocsize,
kNtPageReadwrite, &child_old_protect); kNtPageReadwrite, &child_old_protect);
alloc_prot = PROT_READ | PROT_WRITE;
} else { } else {
alloc_prot = map->prot;
}
} else {
// private mapping
uint32_t page_flags;
if (!(alloc_prot & PROT_WRITE)) {
page_flags = kNtPageReadwrite;
alloc_prot = PROT_READ | PROT_WRITE;
} else {
page_flags = __prot2nt(alloc_prot, false);
}
ok = ok && !!VirtualAllocEx(procinfo.hProcess, map->addr, allocsize, ok = ok && !!VirtualAllocEx(procinfo.hProcess, map->addr, allocsize,
kNtMemReserve | kNtMemCommit, kNtMemReserve | kNtMemCommit, page_flags);
kNtPageExecuteReadwrite);
} }
} }
uint32_t parent_old_protect;
if (!(map->prot & PROT_READ)) if (!(map->prot & PROT_READ))
ok = ok && !!VirtualProtect(map->addr, map->size, kNtPageReadwrite, ok = ok && !!VirtualProtect(map->addr, map->size, kNtPageReadwrite,
&parent_old_protect); &parent_old_protect);
ok = ok && !!WriteProcessMemory(procinfo.hProcess, map->addr, map->addr, ok = ok &&
map->size, 0); !!WriteProcessMemory(procinfo.hProcess, map->addr, map->addr,
(map->size + __pagesize - 1) & -__pagesize, 0);
if (map->prot != alloc_prot) {
uint32_t child_old_protect;
ok = ok && ok = ok &&
!!VirtualProtectEx(procinfo.hProcess, map->addr, map->size, !!VirtualProtectEx(procinfo.hProcess, map->addr, map->size,
__prot2nt(map->prot, false), &child_old_protect); __prot2nt(map->prot, false), &child_old_protect);
}
if (!(map->prot & PROT_READ)) if (!(map->prot & PROT_READ))
ok = ok && !!VirtualProtect(map->addr, map->size, parent_old_protect, ok = ok && !!VirtualProtect(map->addr, map->size, parent_old_protect,
&parent_old_protect); &parent_old_protect);

View file

@ -16,10 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
@ -37,12 +39,13 @@
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h" #include "libc/runtime/syslib.internal.h"
#include "libc/stdio/internal.h" #include "libc/stdio/internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/ss.h"
#include "libc/thread/itimer.h" #include "libc/thread/itimer.h"
#include "libc/thread/posixthread.internal.h" #include "libc/thread/posixthread.internal.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
@ -52,9 +55,9 @@
__msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId; __msabi extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId;
extern atomic_int __sig_worker_state;
extern pthread_mutex_t __cxa_lock_obj; extern pthread_mutex_t __cxa_lock_obj;
extern pthread_mutex_t __pthread_lock_obj; extern pthread_mutex_t __pthread_lock_obj;
extern pthread_mutex_t __sig_worker_lock;
void __rand64_lock(void); void __rand64_lock(void);
void __rand64_unlock(void); void __rand64_unlock(void);
@ -119,6 +122,8 @@ static void fork_prepare(void) {
_weaken(__localtime_lock)(); _weaken(__localtime_lock)();
if (_weaken(__dlopen_lock)) if (_weaken(__dlopen_lock))
_weaken(__dlopen_lock)(); _weaken(__dlopen_lock)();
if (IsWindows())
__proc_lock();
if (_weaken(cosmo_stack_lock)) if (_weaken(cosmo_stack_lock))
_weaken(cosmo_stack_lock)(); _weaken(cosmo_stack_lock)();
__cxa_lock(); __cxa_lock();
@ -151,6 +156,8 @@ static void fork_parent(void) {
__cxa_unlock(); __cxa_unlock();
if (_weaken(cosmo_stack_unlock)) if (_weaken(cosmo_stack_unlock))
_weaken(cosmo_stack_unlock)(); _weaken(cosmo_stack_unlock)();
if (IsWindows())
__proc_unlock();
if (_weaken(__dlopen_unlock)) if (_weaken(__dlopen_unlock))
_weaken(__dlopen_unlock)(); _weaken(__dlopen_unlock)();
if (_weaken(__localtime_unlock)) if (_weaken(__localtime_unlock))
@ -161,7 +168,7 @@ static void fork_parent(void) {
_pthread_mutex_unlock(&supreme_lock); _pthread_mutex_unlock(&supreme_lock);
} }
static void fork_child(void) { static void fork_child(int ppid_win32, int ppid_cosmo) {
if (_weaken(__rand64_wipe)) if (_weaken(__rand64_wipe))
_weaken(__rand64_wipe)(); _weaken(__rand64_wipe)();
_pthread_mutex_wipe_np(&__fds_lock_obj); _pthread_mutex_wipe_np(&__fds_lock_obj);
@ -185,9 +192,11 @@ static void fork_child(void) {
sys_read_nt_wipe_keystrokes(); sys_read_nt_wipe_keystrokes();
__proc_wipe_and_reset(); __proc_wipe_and_reset();
__itimer_wipe_and_reset(); __itimer_wipe_and_reset();
_pthread_mutex_wipe_np(&__sig_worker_lock); atomic_init(&__sig_worker_state, 0);
if (_weaken(__sig_init)) if (_weaken(__sig_init))
_weaken(__sig_init)(); _weaken(__sig_init)();
if (_weaken(sys_getppid_nt_wipe))
_weaken(sys_getppid_nt_wipe)(ppid_win32, ppid_cosmo);
} }
if (_weaken(_pthread_onfork_child)) if (_weaken(_pthread_onfork_child))
_weaken(_pthread_onfork_child)(); _weaken(_pthread_onfork_child)();
@ -196,8 +205,9 @@ static void fork_child(void) {
int _fork(uint32_t dwCreationFlags) { int _fork(uint32_t dwCreationFlags) {
struct Dll *e; struct Dll *e;
int ax, dx, tid, parent; int ax, dx, tid, ppid_win32, ppid_cosmo;
parent = __pid; ppid_win32 = IsWindows() ? GetCurrentProcessId() : 0;
ppid_cosmo = __pid;
BLOCK_SIGNALS; BLOCK_SIGNALS;
fork_prepare(); fork_prepare();
if (!IsWindows()) { if (!IsWindows()) {
@ -217,7 +227,7 @@ int _fork(uint32_t dwCreationFlags) {
// get new thread id // get new thread id
struct CosmoTib *tib = __get_tls(); struct CosmoTib *tib = __get_tls();
struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread; struct PosixThread *me = (struct PosixThread *)tib->tib_pthread;
tid = IsLinux() || IsXnuSilicon() ? dx : sys_gettid(); tid = IsLinux() || IsXnuSilicon() ? dx : sys_gettid();
atomic_init(&tib->tib_ctid, tid); atomic_init(&tib->tib_ctid, tid);
atomic_init(&tib->tib_ptid, tid); atomic_init(&tib->tib_ptid, tid);
@ -237,10 +247,10 @@ int _fork(uint32_t dwCreationFlags) {
// turn other threads into zombies // turn other threads into zombies
// we can't free() them since we're monopolizing all locks // we can't free() them since we're monopolizing all locks
// we assume the operating system already reclaimed system handles // we assume the operating system already reclaimed system handles
dll_remove(&_pthread_list, &pt->list); dll_remove(&_pthread_list, &me->list);
struct Dll *old_threads = _pthread_list; struct Dll *old_threads = _pthread_list;
_pthread_list = 0; _pthread_list = 0;
dll_make_first(&_pthread_list, &pt->list); dll_make_first(&_pthread_list, &me->list);
atomic_init(&_pthread_count, 1); atomic_init(&_pthread_count, 1);
// get new system thread handle // get new system thread handle
@ -258,25 +268,43 @@ int _fork(uint32_t dwCreationFlags) {
atomic_init(&tib->tib_sigpending, 0); atomic_init(&tib->tib_sigpending, 0);
// we can't be canceled if the canceler no longer exists // we can't be canceled if the canceler no longer exists
atomic_init(&pt->pt_canceled, false); atomic_init(&me->pt_canceled, false);
// forget locks // forget locks
bzero(tib->tib_locks, sizeof(tib->tib_locks)); bzero(tib->tib_locks, sizeof(tib->tib_locks));
// xnu fork() doesn't preserve sigaltstack()
if (IsXnu() && me->tib->tib_sigstack_addr) {
struct sigaltstack_bsd ss;
ss.ss_sp = me->tib->tib_sigstack_addr;
ss.ss_size = me->tib->tib_sigstack_size;
ss.ss_flags = me->tib->tib_sigstack_flags;
if (IsXnuSilicon()) {
__syslib->__sigaltstack(&ss, 0);
} else {
sys_sigaltstack(&ss, 0);
}
}
// run user fork callbacks // run user fork callbacks
fork_child(); fork_child(ppid_win32, ppid_cosmo);
// free threads // free threads
if (_weaken(_pthread_free)) { if (_weaken(_pthread_free)) {
while ((e = dll_first(old_threads))) { while ((e = dll_first(old_threads))) {
pt = POSIXTHREAD_CONTAINER(e); struct PosixThread *pt = POSIXTHREAD_CONTAINER(e);
atomic_init(&pt->tib->tib_syshand, 0); atomic_init(&pt->tib->tib_syshand, 0);
dll_remove(&old_threads, e); dll_remove(&old_threads, e);
_weaken(_pthread_free)(pt); _weaken(_pthread_free)(pt);
} }
} }
STRACE("fork() → 0 (child of %d)", parent); // reactivate ftrace
/* if (ftrace_stackdigs) */
/* if (_weaken(ftrace_install)) */
/* _weaken(ftrace_install)(); */
STRACE("fork() → 0 (child of %d)", ppid_cosmo);
} else { } else {
// this is the parent process // this is the parent process
fork_parent(); fork_parent();

93
libc/proc/getppid-nt.c Normal file
View file

@ -0,0 +1,93 @@
/*-*- 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 2021 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/atomic.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/cosmo.h"
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/nt/process.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processbasicinformation.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
int sys_getppid_nt_win32;
int sys_getppid_nt_cosmo;
textwindows static int sys_getppid_nt_ntdll(void) {
struct NtProcessBasicInformation ProcessInformation;
uint32_t gotsize = 0;
if (!NtError(
NtQueryInformationProcess(GetCurrentProcess(), 0, &ProcessInformation,
sizeof(ProcessInformation), &gotsize)) &&
gotsize >= sizeof(ProcessInformation) &&
ProcessInformation.InheritedFromUniqueProcessId) {
return ProcessInformation.InheritedFromUniqueProcessId;
}
return 0;
}
static void sys_getppid_nt_extract(const char *str) {
int c;
int win32 = 0;
int cosmo = 0;
if (str) {
for (;;) {
c = *str;
if (!('0' <= c && c <= '9'))
break;
win32 *= 10;
win32 += c - '0';
++str;
}
if (win32 && *str++ == ':') {
for (;;) {
c = *str;
if (!('0' <= c && c <= '9'))
break;
cosmo *= 10;
cosmo += c - '0';
++str;
}
if (win32 == sys_getppid_nt_ntdll()) {
sys_getppid_nt_win32 = win32;
sys_getppid_nt_cosmo = cosmo;
}
}
}
}
__attribute__((__constructor__(90))) static void init(void) {
if (!IsWindows())
return;
sys_getppid_nt_extract(getenv("_COSMO_PPID"));
}
textwindows int sys_getppid_nt(void) {
if (sys_getppid_nt_cosmo)
return sys_getppid_nt_cosmo;
return sys_getppid_nt_ntdll();
}
textwindows void sys_getppid_nt_wipe(int win32, int cosmo) {
sys_getppid_nt_win32 = win32;
sys_getppid_nt_cosmo = cosmo;
}

View file

@ -22,7 +22,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h" #include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -29,7 +29,7 @@
#include "libc/nt/struct/iocounters.h" #include "libc/nt/struct/iocounters.h"
#include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h" #include "libc/sysv/consts/rusage.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -19,7 +19,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
// retrieves handle of process // retrieves handle of process
// supports only current process and processes we created // supports only current process and processes we created

View file

@ -33,7 +33,7 @@
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__

View file

@ -51,6 +51,7 @@
#include "libc/nt/enum/processcreationflags.h" #include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/startf.h" #include "libc/nt/enum/startf.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/startupinfo.h"
@ -58,7 +59,8 @@
#include "libc/proc/ntspawn.h" #include "libc/proc/ntspawn.h"
#include "libc/proc/posix_spawn.h" #include "libc/proc/posix_spawn.h"
#include "libc/proc/posix_spawn.internal.h" #include "libc/proc/posix_spawn.internal.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
@ -396,6 +398,14 @@ static textwindows errno_t posix_spawn_nt_impl(
} }
FormatUint64(stpcpy(maskvar, "_MASK="), childmask); FormatUint64(stpcpy(maskvar, "_MASK="), childmask);
// inherit parent process id
char ppidvar[12 + 21 + 1 + 21 + 1], *p = ppidvar;
p = stpcpy(p, "_COSMO_PPID=");
p = FormatUint64(p, GetCurrentProcessId());
*p++ = ':';
p = FormatUint64(p, __pid);
setenv("_COSMO_PPID", ppidvar, true);
// launch process // launch process
int rc = -1; int rc = -1;
struct NtProcessInformation procinfo; struct NtProcessInformation procinfo;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/proc/proc.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
@ -47,7 +48,6 @@
#include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
@ -67,9 +67,8 @@
#define STACK_SIZE 65536 #define STACK_SIZE 65536
struct Procs __proc = { struct Procs __proc;
.lock = PTHREAD_MUTEX_INITIALIZER, static pthread_mutex_t __proc_lock_obj = PTHREAD_MUTEX_INITIALIZER;
};
textwindows static void __proc_stats(int64_t h, struct rusage *ru) { textwindows static void __proc_stats(int64_t h, struct rusage *ru) {
bzero(ru, sizeof(*ru)); bzero(ru, sizeof(*ru));
@ -258,14 +257,14 @@ textwindows static void __proc_setup(void) {
*/ */
textwindows void __proc_lock(void) { textwindows void __proc_lock(void) {
cosmo_once(&__proc.once, __proc_setup); cosmo_once(&__proc.once, __proc_setup);
_pthread_mutex_lock(&__proc.lock); _pthread_mutex_lock(&__proc_lock_obj);
} }
/** /**
* Unlocks process tracker. * Unlocks process tracker.
*/ */
textwindows void __proc_unlock(void) { textwindows void __proc_unlock(void) {
_pthread_mutex_unlock(&__proc.lock); _pthread_mutex_unlock(&__proc_lock_obj);
} }
/** /**
@ -273,10 +272,8 @@ textwindows void __proc_unlock(void) {
*/ */
textwindows void __proc_wipe_and_reset(void) { textwindows void __proc_wipe_and_reset(void) {
// TODO(jart): Should we preserve this state in forked children? // TODO(jart): Should we preserve this state in forked children?
pthread_mutex_t lock = __proc.lock; _pthread_mutex_wipe_np(&__proc_lock_obj);
bzero(&__proc, sizeof(__proc)); bzero(&__proc, sizeof(__proc));
__proc.lock = lock;
_pthread_mutex_wipe_np(&__proc.lock);
} }
/** /**

View file

@ -27,7 +27,6 @@ struct Proc {
struct Procs { struct Procs {
int waiters; int waiters;
atomic_uint once; atomic_uint once;
pthread_mutex_t lock;
intptr_t thread; intptr_t thread;
intptr_t onbirth; intptr_t onbirth;
intptr_t haszombies; intptr_t haszombies;
@ -41,16 +40,16 @@ struct Procs {
extern struct Procs __proc; extern struct Procs __proc;
void __proc_lock(void) dontthrow; void __proc_lock(void);
void __proc_unlock(void) dontthrow; void __proc_unlock(void);
int64_t __proc_handle(int) libcesque; int64_t __proc_handle(int);
int64_t __proc_search(int) libcesque; int64_t __proc_search(int);
struct Proc *__proc_new(void) libcesque; struct Proc *__proc_new(void);
void __proc_add(struct Proc *) libcesque; void __proc_add(struct Proc *);
void __proc_free(struct Proc *) libcesque; void __proc_free(struct Proc *);
void __proc_wipe_and_reset(void) libcesque; void __proc_wipe_and_reset(void);
int __proc_harvest(struct Proc *, bool) libcesque; int __proc_harvest(struct Proc *, bool);
int sys_wait4_nt(int, int *, int, struct rusage *) libcesque; int sys_wait4_nt(int, int *, int, struct rusage *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_PROC_H_ */ #endif /* COSMOPOLITAN_LIBC_PROC_H_ */

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static dontinline textwindows int sys_sched_setaffinity_nt( static dontinline textwindows int sys_sched_setaffinity_nt(

View file

@ -23,7 +23,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h" #include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
@ -27,25 +28,22 @@
#include "libc/nt/events.h" #include "libc/nt/events.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h" #include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__
static textwindows int __proc_reap(struct Proc *pr, int *wstatus, textwindows static int __proc_reap(struct Proc *pr, int *wstatus,
struct rusage *opt_out_rusage) { struct rusage *opt_out_rusage) {
if (wstatus) { if (wstatus)
*wstatus = pr->wstatus; *wstatus = pr->wstatus;
} if (opt_out_rusage)
if (opt_out_rusage) {
*opt_out_rusage = pr->ru; *opt_out_rusage = pr->ru;
}
dll_remove(&__proc.zombies, &pr->elem); dll_remove(&__proc.zombies, &pr->elem);
if (dll_is_empty(__proc.zombies)) { if (dll_is_empty(__proc.zombies))
ResetEvent(__proc.haszombies); ResetEvent(__proc.haszombies);
}
if (pr->waiters) { if (pr->waiters) {
pr->status = PROC_UNDEAD; pr->status = PROC_UNDEAD;
dll_make_first(&__proc.undead, &pr->elem); dll_make_first(&__proc.undead, &pr->elem);
@ -56,19 +54,18 @@ static textwindows int __proc_reap(struct Proc *pr, int *wstatus,
return pr->pid; return pr->pid;
} }
static textwindows int __proc_check(int pid, int *wstatus, textwindows static int __proc_check(int pid, int *wstatus,
struct rusage *opt_out_rusage) { struct rusage *opt_out_rusage) {
struct Dll *e; struct Dll *e;
for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, e)) { for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, e)) {
struct Proc *pr = PROC_CONTAINER(e); struct Proc *pr = PROC_CONTAINER(e);
if (pid == -1 || pid == pr->pid) { if (pid == -1 || pid == pr->pid)
return __proc_reap(pr, wstatus, opt_out_rusage); return __proc_reap(pr, wstatus, opt_out_rusage);
} }
}
return 0; return 0;
} }
static textwindows int __proc_wait(int pid, int *wstatus, int options, textwindows static int __proc_wait(int pid, int *wstatus, int options,
struct rusage *rusage, sigset_t waitmask) { struct rusage *rusage, sigset_t waitmask) {
for (;;) { for (;;) {
@ -134,14 +131,18 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// perform blocking operation // perform blocking operation
uint32_t wi; uint32_t wi;
uintptr_t event; uintptr_t event;
if ((event = CreateEvent(0, 0, 0, 0))) {
struct PosixThread *pt = _pthread_self(); struct PosixThread *pt = _pthread_self();
pt->pt_event = event;
pt->pt_blkmask = waitmask; pt->pt_blkmask = waitmask;
pt->pt_event = event = CreateEvent(0, 0, 0, 0);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT, atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release); memory_order_release);
wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, event}, 0, -1u); wi = WaitForMultipleObjects(2, (intptr_t[2]){hWaitObject, event}, 0, -1u);
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release); atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
CloseHandle(event); CloseHandle(event);
} else {
wi = -1u;
}
// log warning if handle unexpectedly closed // log warning if handle unexpectedly closed
if (wi & kNtWaitAbandoned) { if (wi & kNtWaitAbandoned) {
@ -159,9 +160,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// check if killed or win32 error // check if killed or win32 error
if (wi) { if (wi) {
if (pr) { if (pr) {
if (!--pr->waiters && pr->status == PROC_UNDEAD) { if (!--pr->waiters && pr->status == PROC_UNDEAD)
__proc_free(pr); __proc_free(pr);
}
} else { } else {
--__proc.waiters; --__proc.waiters;
} }
@ -178,17 +178,15 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// handle process exit notification // handle process exit notification
--pr->waiters; --pr->waiters;
if (pr->status == PROC_ALIVE) { if (pr->status == PROC_ALIVE)
__proc_harvest(pr, true); __proc_harvest(pr, true);
}
switch (pr->status) { switch (pr->status) {
case PROC_ALIVE: case PROC_ALIVE:
// exit caused by execve() reparenting // exit caused by execve() reparenting
__proc_unlock(); if (!pr->waiters)
if (!pr->waiters) {
// avoid deadlock that could theoretically happen // avoid deadlock that could theoretically happen
SetEvent(__proc.onbirth); SetEvent(__proc.onbirth);
} __proc_unlock();
break; break;
case PROC_ZOMBIE: case PROC_ZOMBIE:
// exit happened and we're the first to know // exit happened and we're the first to know
@ -197,9 +195,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
return rc; return rc;
case PROC_UNDEAD: case PROC_UNDEAD:
// exit happened but another thread waited first // exit happened but another thread waited first
if (!pr->waiters) { if (!pr->waiters)
__proc_free(pr); __proc_free(pr);
}
__proc_unlock(); __proc_unlock();
return echild(); return echild();
default: default:

View file

@ -21,7 +21,7 @@
#include "libc/calls/struct/rusage.internal.h" #include "libc/calls/struct/rusage.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**

View file

@ -30,18 +30,18 @@
// @param 8(rsp) x6 is arg // @param 8(rsp) x6 is arg
// @return tid of child on success, or -errno on error // @return tid of child on success, or -errno on error
sys_clone_linux: sys_clone_linux:
beg
pro
#ifdef __x86_64__ #ifdef __x86_64__
push %rbp cpush %rbx
mov %rsp,%rbp
push %rbx
mov %rcx,%r10 mov %rcx,%r10
mov 16(%rbp),%rbx mov 16(%rbp),%rbx
mov $56,%eax // __NR_clone mov $56,%eax // __NR_clone
syscall syscall
test %rax,%rax test %rax,%rax
jz 2f jz 2f
0: pop %rbx 0: cpop %rbx
pop %rbp epi
ret ret
2: xor %ebp,%ebp // child thread 2: xor %ebp,%ebp // child thread
mov %rbx,%rdi // arg mov %rbx,%rdi // arg
@ -50,15 +50,13 @@ sys_clone_linux:
mov $60,%eax // __NR_exit(exitcode) mov $60,%eax // __NR_exit(exitcode)
syscall syscall
#elif defined(__aarch64__) #elif defined(__aarch64__)
stp x29,x30,[sp,#-16]!
mov x29,sp
mov x8,x3 // swap x3 and x4 mov x8,x3 // swap x3 and x4
mov x3,x4 // swap x3 and x4 mov x3,x4 // swap x3 and x4
mov x4,x8 // swap x3 and x4 mov x4,x8 // swap x3 and x4
mov x8,#220 // __NR_clone mov x8,#220 // __NR_clone
svc #0 svc #0
cbz x0,2f cbz x0,2f
ldp x29,x30,[sp],#16 epi
ret ret
2: mov x29,#0 // wipe backtrace 2: mov x29,#0 // wipe backtrace
mov x28,x3 // set cosmo tls mov x28,x3 // set cosmo tls
@ -69,4 +67,5 @@ sys_clone_linux:
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif
end
.endfn sys_clone_linux,globl,hidden .endfn sys_clone_linux,globl,hidden

View file

@ -32,8 +32,8 @@
// @param rdx is environ // @param rdx is environ
// @param rcx is auxv // @param rcx is auxv
// @noreturn // @noreturn
cosmo: push %rbp cosmo: beg
mov %rsp,%rbp pro
mov %edi,%r12d mov %edi,%r12d
mov %rsi,%r13 mov %rsi,%r13
mov %rdx,%r14 mov %rdx,%r14
@ -104,7 +104,10 @@ cosmo: push %rbp
je 2f je 2f
push %rax push %rax
push %rax push %rax
call .Largs mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
call *(%rax) call *(%rax)
pop %rax pop %rax
pop %rax pop %rax
@ -112,17 +115,15 @@ cosmo: push %rbp
jmp 1b jmp 1b
// call main() // call main()
2: call .Largs 2: mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
.weak main .weak main
call main call main
xchg %eax,%edi xchg %eax,%edi
call exit call exit
end
.Largs: mov %r12d,%edi
mov %r13,%rsi
mov %r14,%rdx
mov %r15,%rcx
ret
.endfn cosmo,weak .endfn cosmo,weak
// Enables Thread Local Storage. // Enables Thread Local Storage.

View file

@ -28,8 +28,12 @@ ftrace_hook:
cmpl $0,__ftrace(%rip) cmpl $0,__ftrace(%rip)
jle 1f jle 1f
.cfi_startproc
push %rbp push %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
mov %rsp,%rbp mov %rsp,%rbp
.cfi_def_cfa_register %rbp
and $-16,%rsp and $-16,%rsp
sub $128,%rsp sub $128,%rsp
movdqu %xmm0,-0x80(%rbp) movdqu %xmm0,-0x80(%rbp)
@ -41,13 +45,21 @@ ftrace_hook:
movdqu %xmm6,-0x20(%rbp) movdqu %xmm6,-0x20(%rbp)
movdqu %xmm7,-0x10(%rbp) movdqu %xmm7,-0x10(%rbp)
push %rax push %rax
.cfi_offset %rax, -24
push %rcx push %rcx
.cfi_offset %rcx, -32
push %rdx push %rdx
.cfi_offset %rdx, -40
push %rdi push %rdi
.cfi_offset %rdi, -48
push %rsi push %rsi
.cfi_offset %rsi, -56
push %r8 push %r8
.cfi_offset %r8, -64
push %r9 push %r9
.cfi_offset %r9, -72
push %r10 push %r10
.cfi_offset %r10, -80
call ftracer call ftracer
movdqu -0x80(%rbp),%xmm0 movdqu -0x80(%rbp),%xmm0
movdqu -0x70(%rbp),%xmm1 movdqu -0x70(%rbp),%xmm1
@ -66,12 +78,20 @@ ftrace_hook:
pop %rcx pop %rcx
pop %rax pop %rax
leave leave
.cfi_restore %rbp
.cfi_def_cfa %rsp, 8
1: ret 1: ret
.cfi_endproc
#elif defined(__aarch64__) #elif defined(__aarch64__)
stp x29,x30,[sp,-384]! stp x29,x30,[sp,-384]!
.cfi_startproc
.cfi_def_cfa_offset 384
.cfi_offset 29, -384 // x29 (fp) is saved at [sp - 384]
.cfi_offset 30, -376 // x30 (lr) is saved at [sp - 376]
mov x29,sp mov x29,sp
.cfi_def_cfa_register 29
stp x0,x1,[sp,16] stp x0,x1,[sp,16]
adrp x0,__ftrace adrp x0,__ftrace
@ -80,18 +100,45 @@ ftrace_hook:
ble 1f ble 1f
stp x2,x3,[sp,32] stp x2,x3,[sp,32]
.cfi_offset 2, -352
.cfi_offset 3, -344
stp x4,x5,[sp,48] stp x4,x5,[sp,48]
.cfi_offset 4, -336
.cfi_offset 5, -328
stp x6,x7,[sp,64] stp x6,x7,[sp,64]
.cfi_offset 6, -320
.cfi_offset 7, -312
stp x8,x9,[sp,80] stp x8,x9,[sp,80]
.cfi_offset 8, -304
.cfi_offset 9, -296
stp x10,x11,[sp,96] stp x10,x11,[sp,96]
.cfi_offset 10, -288
.cfi_offset 11, -280
stp x12,x13,[sp,112] stp x12,x13,[sp,112]
.cfi_offset 12, -272
.cfi_offset 13, -264
stp x14,x15,[sp,128] stp x14,x15,[sp,128]
.cfi_offset 14, -256
.cfi_offset 15, -248
stp x16,x19,[sp,160] stp x16,x19,[sp,160]
.cfi_offset 16, -224
.cfi_offset 19, -216
stp x20,x21,[sp,176] stp x20,x21,[sp,176]
.cfi_offset 20, -208
.cfi_offset 21, -200
stp x22,x23,[sp,192] stp x22,x23,[sp,192]
.cfi_offset 22, -192
.cfi_offset 23, -184
stp x24,x25,[sp,208] stp x24,x25,[sp,208]
.cfi_offset 24, -176
.cfi_offset 25, -168
stp x26,x27,[sp,224] stp x26,x27,[sp,224]
.cfi_offset 26, -160
.cfi_offset 27, -152
stp x17,x28,[sp,240] stp x17,x28,[sp,240]
.cfi_offset 17, -144
.cfi_offset 28, -136
// No CFI directives needed for FP registers
stp q0,q1,[sp,256] stp q0,q1,[sp,256]
stp q2,q3,[sp,288] stp q2,q3,[sp,288]
stp q4,q5,[sp,320] stp q4,q5,[sp,320]
@ -119,7 +166,12 @@ ftrace_hook:
1: ldp x0,x1,[sp,16] 1: ldp x0,x1,[sp,16]
ldp x29,x30,[sp],384 ldp x29,x30,[sp],384
.cfi_restore 29
.cfi_restore 30
.cfi_def_cfa 7, 0 // On some ARM systems the stack pointer is represented by register 7
.cfi_def_cfa_offset 0
ret ret
.cfi_endproc
#endif /* __x86_64__ */ #endif /* __x86_64__ */
.endfn ftrace_hook,globl,hidden .endfn ftrace_hook,globl,hidden

View file

@ -24,12 +24,13 @@
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; __msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__funline void __morph_mprotect(void *addr, size_t size, int prot, int ntprot) { __funline void __morph_mprotect(void *addr, size_t size, int prot, int ntprot) {
#ifdef __x86_64__ #ifdef __x86_64__
@ -54,7 +55,7 @@ __funline void __morph_mprotect(void *addr, size_t size, int prot, int ntprot) {
} }
#endif #endif
} else { } else {
__imp_VirtualProtect(addr, size, ntprot, &op); __imp_VirtualProtectEx(GetCurrentProcess(), addr, size, ntprot, &op);
} }
#elif defined(__aarch64__) #elif defined(__aarch64__)
register long r0 asm("x0") = (long)addr; register long r0 asm("x0") = (long)addr;

View file

@ -83,7 +83,6 @@ extern uint64_t kStartTsc;
extern const char kNtSystemDirectory[]; extern const char kNtSystemDirectory[];
extern const char kNtWindowsDirectory[]; extern const char kNtWindowsDirectory[];
extern size_t __virtualmax; extern size_t __virtualmax;
extern size_t __virtualsize;
extern size_t __stackmax; extern size_t __stackmax;
extern bool32 __isworker; extern bool32 __isworker;
/* utilities */ /* utilities */

View file

@ -79,7 +79,7 @@ __msabi extern typeof(SetConsoleMode) *const __imp_SetConsoleMode;
__msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP; __msabi extern typeof(SetConsoleOutputCP) *const __imp_SetConsoleOutputCP;
__msabi extern typeof(SetEnvironmentVariable) *const __imp_SetEnvironmentVariableW; __msabi extern typeof(SetEnvironmentVariable) *const __imp_SetEnvironmentVariableW;
__msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle; __msabi extern typeof(SetStdHandle) *const __imp_SetStdHandle;
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; __msabi extern typeof(VirtualProtectEx) *const __imp_VirtualProtectEx;
__msabi extern typeof(WriteFile) *const __imp_WriteFile; __msabi extern typeof(WriteFile) *const __imp_WriteFile;
// clang-format on // clang-format on
@ -206,10 +206,11 @@ abi wontreturn static void WinInit(const char16_t *cmdline) {
int stackprot = (intptr_t)ape_stack_prot; int stackprot = (intptr_t)ape_stack_prot;
if (~stackprot & PROT_EXEC) { if (~stackprot & PROT_EXEC) {
uint32_t old; uint32_t old;
__imp_VirtualProtect(stackaddr, stacksize, kNtPageReadwrite, &old); __imp_VirtualProtectEx(GetCurrentProcess(), stackaddr, stacksize,
kNtPageReadwrite, &old);
} }
uint32_t oldattr; uint32_t oldattr;
__imp_VirtualProtect(stackaddr, GetGuardSize(), __imp_VirtualProtectEx(GetCurrentProcess(), stackaddr, GetGuardSize(),
kNtPageReadwrite | kNtPageGuard, &oldattr); kNtPageReadwrite | kNtPageGuard, &oldattr);
if (_weaken(__maps_stack)) { if (_weaken(__maps_stack)) {
struct NtSystemInfo si; struct NtSystemInfo si;

View file

@ -18,13 +18,19 @@
*/ */
#include "libc/sock/ifaddrs.h" #include "libc/sock/ifaddrs.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sock/struct/ifconf.h" #include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h" #include "libc/sock/struct/ifreq.h"
#include "libc/sock/struct/sockaddr6.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/iff.h" #include "libc/sysv/consts/iff.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sio.h" #include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sock.h"
@ -36,6 +42,20 @@ struct IfAddr {
struct sockaddr_in bstaddr; struct sockaddr_in bstaddr;
}; };
struct IfAddr6Info {
int addr_scope;
int addr_flags;
};
struct IfAddr6 {
struct ifaddrs ifaddrs;
char name[IFNAMSIZ];
struct sockaddr_in6 addr;
struct sockaddr_in6 netmask;
struct sockaddr_in6 bstaddr; // unused
struct IfAddr6Info info;
};
/** /**
* Frees network interface address list. * Frees network interface address list.
*/ */
@ -48,6 +68,73 @@ void freeifaddrs(struct ifaddrs *ifp) {
} }
} }
// hex repr to network order int
static uint128_t hex2no(const char *str) {
uint128_t res = 0;
const int max_quads = sizeof(uint128_t) * 2;
int i = 0;
while ((i < max_quads) && str[i]) {
uint8_t acc = (((str[i] & 0xF) + (str[i] >> 6)) | ((str[i] >> 3) & 0x8));
acc = acc << 4;
i += 1;
if (str[i]) {
acc = acc | (((str[i] & 0xF) + (str[i] >> 6)) | ((str[i] >> 3) & 0x8));
i += 1;
}
res = (res >> 8) | (((uint128_t)acc) << ((sizeof(uint128_t) - 1) * 8));
}
res = res >> ((max_quads - i) * 4);
return res;
}
/**
* Gets network interface IPv6 address list on linux.
*
* @return 0 on success, or -1 w/ errno
*/
static int getifaddrs_linux_ip6(struct ifconf *conf) {
int fd;
int n = 0;
struct ifreq *ifreq = conf->ifc_req;
const int bufsz = 44 + IFNAMSIZ + 1;
char buf[bufsz + 1]; // one line max size
if ((fd = sys_openat(0, "/proc/net/if_inet6", O_RDONLY, 0)) == -1) {
return -1;
}
while ((n = sys_read(fd, &buf[n], bufsz - n)) &&
((char *)ifreq < (conf->ifc_buf + conf->ifc_len))) {
// flags linux include/uapi/linux/if_addr.h:44
// scope linux include/net/ipv6.h:L99
// *addr, *index, *plen, *scope, *flags, *ifname
char *s[] = {&buf[0], &buf[33], &buf[36], &buf[39], &buf[42], &buf[45]};
int ifnamelen = 0;
while (*s[5] == ' ') {
++s[5];
}
while (s[5][ifnamelen] > '\n') {
++ifnamelen;
}
buf[32] = buf[35] = buf[38] = buf[41] = buf[44] = s[5][ifnamelen] = '\0';
bzero(ifreq, sizeof(*ifreq));
ifreq->ifr_addr.sa_family = AF_INET6;
memcpy(&ifreq->ifr_name, s[5], ifnamelen);
*((uint128_t *)&ifreq->ifr6_addr) = hex2no(s[0]);
ifreq->ifr6_ifindex = hex2no(s[1]);
ifreq->ifr6_prefixlen = hex2no(s[2]);
ifreq->ifr6_scope = hex2no(s[3]);
ifreq->ifr6_flags = hex2no(s[4]);
++ifreq;
int tlen = &s[5][ifnamelen] - &buf[0] + 1;
n = bufsz - tlen;
memcpy(&buf, &buf[tlen], n);
}
conf->ifc_len = (char *)ifreq - conf->ifc_buf;
return sys_close(fd);
}
/** /**
* Gets network interface address list. * Gets network interface address list.
* *
@ -55,6 +142,7 @@ void freeifaddrs(struct ifaddrs *ifp) {
* @see tool/viz/getifaddrs.c for example code * @see tool/viz/getifaddrs.c for example code
*/ */
int getifaddrs(struct ifaddrs **out_ifpp) { int getifaddrs(struct ifaddrs **out_ifpp) {
// printf("%d\n", sizeof(struct ifreq));
int rc = -1; int rc = -1;
int fd; int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) { if ((fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) != -1) {
@ -65,12 +153,20 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
conf.ifc_buf = data; conf.ifc_buf = data;
conf.ifc_len = size; conf.ifc_len = size;
if (!ioctl(fd, SIOCGIFCONF, &conf)) { if (!ioctl(fd, SIOCGIFCONF, &conf)) {
if (IsLinux()) {
struct ifconf confl6;
confl6.ifc_buf = data + conf.ifc_len;
confl6.ifc_len = size - conf.ifc_len;
if ((rc = getifaddrs_linux_ip6(&confl6)))
return rc;
conf.ifc_len += confl6.ifc_len;
}
struct ifaddrs *res = 0; struct ifaddrs *res = 0;
for (struct ifreq *ifr = (struct ifreq *)data; for (struct ifreq *ifr = (struct ifreq *)data;
(char *)ifr < data + conf.ifc_len; ++ifr) { (char *)ifr < data + conf.ifc_len; ++ifr) {
if (ifr->ifr_addr.sa_family != AF_INET) { uint16_t family = ifr->ifr_addr.sa_family;
continue; // TODO(jart): IPv6 support if (family == AF_INET) {
}
struct IfAddr *addr; struct IfAddr *addr;
if ((addr = calloc(1, sizeof(struct IfAddr)))) { if ((addr = calloc(1, sizeof(struct IfAddr)))) {
memcpy(addr->name, ifr->ifr_name, IFNAMSIZ); memcpy(addr->name, ifr->ifr_name, IFNAMSIZ);
@ -102,6 +198,44 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
addr->ifaddrs.ifa_next = res; addr->ifaddrs.ifa_next = res;
res = (struct ifaddrs *)addr; res = (struct ifaddrs *)addr;
} }
} else if (family == AF_INET6) {
struct IfAddr6 *addr6;
if ((addr6 = calloc(1, sizeof(struct IfAddr6)))) {
addr6->ifaddrs.ifa_name = addr6->name;
addr6->ifaddrs.ifa_addr = (struct sockaddr *)&addr6->addr;
addr6->ifaddrs.ifa_netmask = (struct sockaddr *)&addr6->netmask;
addr6->ifaddrs.ifa_broadaddr = (struct sockaddr *)&addr6->bstaddr;
addr6->ifaddrs.ifa_data = (void *)&addr6->info;
memcpy(&addr6->name, &ifr->ifr_name, IFNAMSIZ);
addr6->info.addr_flags = ifr->ifr6_flags;
addr6->info.addr_scope = ifr->ifr6_scope;
addr6->addr.sin6_family = AF_INET6;
addr6->addr.sin6_port = 0;
addr6->addr.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->addr.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr));
addr6->netmask.sin6_family = AF_INET6;
addr6->netmask.sin6_port = 0;
addr6->netmask.sin6_flowinfo = 0;
addr6->addr.sin6_scope_id = ifr->ifr6_ifindex;
memcpy(&addr6->netmask.sin6_addr, &ifr->ifr6_addr,
sizeof(struct in6_addr));
*((uint128_t *)&(addr6->netmask.sin6_addr)) &=
(UINT128_MAX >> ifr->ifr6_prefixlen);
if (!ioctl(fd, SIOCGIFFLAGS, ifr)) {
addr6->ifaddrs.ifa_flags = ifr->ifr_flags;
}
bzero(&addr6->bstaddr, sizeof(struct sockaddr_in6));
addr6->ifaddrs.ifa_next = res;
res = (struct ifaddrs *)addr6;
}
}
} }
*out_ifpp = res; *out_ifpp = res;
rc = 0; rc = 0;

View file

@ -92,9 +92,10 @@ textwindows dontinline static ssize_t sys_sendfile_nt(
} }
struct NtOverlapped ov = {.hEvent = WSACreateEvent(), .Pointer = offset}; struct NtOverlapped ov = {.hEvent = WSACreateEvent(), .Pointer = offset};
cosmo_once(&g_transmitfile.once, transmitfile_init); cosmo_once(&g_transmitfile.once, transmitfile_init);
if (g_transmitfile.lpTransmitFile(oh, ih, uptobytes, 0, &ov, 0, 0) || if (ov.hEvent &&
(g_transmitfile.lpTransmitFile(oh, ih, uptobytes, 0, &ov, 0, 0) ||
WSAGetLastError() == kNtErrorIoPending || WSAGetLastError() == kNtErrorIoPending ||
WSAGetLastError() == WSAEINPROGRESS) { WSAGetLastError() == WSAEINPROGRESS)) {
if (WSAGetOverlappedResult(oh, &ov, &uptobytes, true, &flags)) { if (WSAGetOverlappedResult(oh, &ov, &uptobytes, true, &flags)) {
rc = uptobytes; rc = uptobytes;
if (opt_in_out_inoffset) { if (opt_in_out_inoffset) {

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ #ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ #define COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_
#include "libc/sock/struct/sockaddr.h" #include "libc/sock/struct/sockaddr.h"
#include "libc/sock/struct/sockaddr6.h"
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#define IF_NAMESIZE 16 #define IF_NAMESIZE 16
@ -11,6 +12,14 @@ struct ifreq {
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */ char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn; } ifr_ifrn;
union { union {
struct {
uint16_t sa_family;
uint16_t ifr6_ifindex; /* Interface index */
uint16_t ifr6_flags; /* Flags */
uint8_t ifr6_scope; /* Addr scope */
uint8_t ifr6_prefixlen; /* Prefix length */
struct in6_addr ifr6_addr;
} in6;
struct sockaddr ifru_addr; /* SIOCGIFADDR */ struct sockaddr ifru_addr; /* SIOCGIFADDR */
struct sockaddr ifru_dstaddr; /* SIOCGIFDSTADDR */ struct sockaddr ifru_dstaddr; /* SIOCGIFDSTADDR */
struct sockaddr ifru_netmask; /* SIOCGIFNETMASK */ struct sockaddr ifru_netmask; /* SIOCGIFNETMASK */
@ -29,5 +38,11 @@ struct ifreq {
#define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_ifindex ifr_ifru.ifru_ivalue #define ifr_ifindex ifr_ifru.ifru_ivalue
#define ifr6_addr ifr_ifru.in6.ifr6_addr /* IP6 Addr */
#define ifr6_scope ifr_ifru.in6.ifr6_scope /* IP6 Addr scope */
#define ifr6_prefixlen ifr_ifru.in6.ifr6_prefixlen /* IP6 Prefix length */
#define ifr6_ifindex ifr_ifru.in6.ifr6_ifindex /* IP6 If index */
#define ifr6_flags ifr_ifru.in6.ifr6_flags /* IP6 If flags */
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ */ #endif /* COSMOPOLITAN_LIBC_SOCK_STRUCT_IFREQ_H_ */

View file

@ -21,6 +21,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
int sys_getentropy(void *, size_t) asm("sys_getrandom"); int sys_getentropy(void *, size_t) asm("sys_getrandom");
@ -39,6 +40,8 @@ int getentropy(void *p, size_t n) {
rc = eio(); rc = eio();
} else if ((!p && n)) { } else if ((!p && n)) {
rc = efault(); rc = efault();
} else if (IsXnuSilicon()) {
rc = __syslib->__getentropy(p, n);
} else if (IsXnu() || IsOpenbsd()) { } else if (IsXnu() || IsOpenbsd()) {
rc = sys_getentropy(p, n); rc = sys_getentropy(p, n);
} else { } else {

View file

@ -1981,4 +1981,4 @@ syscon misc UL_SETFSIZE 2 2 2 2 2 0 0 0
syscon misc XATTR_CREATE 1 1 2 2 0 0 0 0 syscon misc XATTR_CREATE 1 1 2 2 0 0 0 0
syscon misc XATTR_REPLACE 2 2 4 4 0 0 0 0 syscon misc XATTR_REPLACE 2 2 4 4 0 0 0 0
# https://youtu.be/GUQUD3IMbb4?t=85 # https://youtu.be/3SNBXoWs4GM

View file

@ -102,8 +102,8 @@ __pid: .quad 0
.previous .previous
systemfive_cp: systemfive_cp:
push %rbp beg
mov %rsp,%rbp // so backtraces work pro
systemfive_cancellable: // our pthread_cancel() miracle code systemfive_cancellable: // our pthread_cancel() miracle code
cmpb $0,__tls_enabled(%rip) // inspired by the musl libc design! cmpb $0,__tls_enabled(%rip) // inspired by the musl libc design!
je 1f // we handle linux and bsd together! je 1f // we handle linux and bsd together!
@ -123,7 +123,7 @@ systemfive_cancellable: // our pthread_cancel() miracle code
clc // no cancellable system calls exist clc // no cancellable system calls exist
syscall // that have 7+ args on the bsd OSes syscall // that have 7+ args on the bsd OSes
systemfive_cancellable_end: // i/o calls park here for long time systemfive_cancellable_end: // i/o calls park here for long time
pop %rbp epi
jnc 2f jnc 2f
neg %rax // turns bsd errno to system v errno neg %rax // turns bsd errno to system v errno
2: cmp $-4095,%rax // but we still check again on eintr 2: cmp $-4095,%rax // but we still check again on eintr
@ -144,11 +144,13 @@ systemfive_cancellable_end: // i/o calls park here for long time
je systemfive_errno // we aren't actually cancelled je systemfive_errno // we aren't actually cancelled
jmp 4f // now we are in fact cancelled jmp 4f // now we are in fact cancelled
systemfive_cancel: // SIGTHR will jump here too systemfive_cancel: // SIGTHR will jump here too
pop %rbp epi
4: jmp _pthread_cancel_ack // tail call 4: jmp _pthread_cancel_ack // tail call
.weak _pthread_cancel_ack // must be linked if we're cancelled .weak _pthread_cancel_ack // must be linked if we're cancelled
end
#if IsModeDbg() #if IsModeDbg()
not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
beg
nop nop
.weak report_cancellation_point .weak report_cancellation_point
5: ezlea report_cancellation_point,cx 5: ezlea report_cancellation_point,cx
@ -157,6 +159,7 @@ not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
call *%rcx call *%rcx
6: ud2 6: ud2
nop nop
end
#endif #endif
.globl systemfive_cancellable_end .globl systemfive_cancellable_end
.globl systemfive_cancellable .globl systemfive_cancellable
@ -166,19 +169,20 @@ not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
.Lanchorpoint: .Lanchorpoint:
#if SupportsLinux() || SupportsMetal() #if SupportsLinux() || SupportsMetal()
systemfive_linux: systemfive_linux:
beg
and $0xfff,%eax // remove nonlinux bits from ordinal and $0xfff,%eax // remove nonlinux bits from ordinal
cmp $0xfff,%eax // checks if unsupported by platform cmp $0xfff,%eax // checks if unsupported by platform
je systemfive_enosys // never taken branches cost nothing je systemfive_enosys // never taken branches cost nothing
btr $11,%eax // 0x800 means a call is cancellable btr $11,%eax // 0x800 means a call is cancellable
jc systemfive_cp // it is handled by the holiest code jc systemfive_cp // it is handled by the holiest code
mov %rcx,%r10 // syscall instruction clobbers %rcx mov %rcx,%r10 // syscall instruction clobbers %rcx
push %rbp // linux never reads args from stack pro // linux never reads args from stack
mov %rsp,%rbp // having frame will help backtraces
syscall // this is known as a context switch syscall // this is known as a context switch
pop %rbp // next we check to see if it failed epi // next we check to see if it failed
cmp $-4095,%rax // system five nexgen32e abi § a.2.1 cmp $-4095,%rax // system five nexgen32e abi § a.2.1
jae systemfive_error // encodes errno as neg return value jae systemfive_error // encodes errno as neg return value
ret ret
end
.endfn systemfive_linux,globl,hidden .endfn systemfive_linux,globl,hidden
systemfive_error: systemfive_error:
neg %eax neg %eax
@ -186,27 +190,35 @@ systemfive_error:
.endfn systemfive_error,globl,hidden .endfn systemfive_error,globl,hidden
#endif #endif
systemfive_errno: systemfive_errno:
beg
xchg %eax,%ecx xchg %eax,%ecx
call __errno_location call __errno_location
mov %ecx,(%rax) // normalize to c library convention mov %ecx,(%rax) // normalize to c library convention
push $-1 // negative one is only error result push $-1 // negative one is only error result
pop %rax // the push pop is to save code size pop %rax // the push pop is to save code size
ret ret
end
.endfn systemfive_errno,globl,hidden .endfn systemfive_errno,globl,hidden
systemfive_enosys: systemfive_enosys:
beg
mov ENOSYS(%rip),%eax mov ENOSYS(%rip),%eax
jmp systemfive_errno jmp systemfive_errno
end
.endfn systemfive_enosys,globl,hidden .endfn systemfive_enosys,globl,hidden
#if SupportsNetbsd() #if SupportsNetbsd()
systemfive_netbsd: systemfive_netbsd:
beg
shr $4*13,%rax shr $4*13,%rax
jmp systemfive_bsdscrub jmp systemfive_bsdscrub
end
.endfn systemfive_netbsd,globl,hidden .endfn systemfive_netbsd,globl,hidden
#endif #endif
#if SupportsOpenbsd() #if SupportsOpenbsd()
systemfive_openbsd: systemfive_openbsd:
beg
shr $4*10,%rax shr $4*10,%rax
jmp systemfive_bsdscrub jmp systemfive_bsdscrub
end
.endfn systemfive_openbsd,globl,hidden .endfn systemfive_openbsd,globl,hidden
#endif #endif
#if SupportsFreebsd() #if SupportsFreebsd()
@ -222,6 +234,7 @@ systemfive_bsdscrub:
// 𝑠𝑙𝑖𝑑𝑒 // 𝑠𝑙𝑖𝑑𝑒
.endfn systemfive_bsdscrub,globl,hidden .endfn systemfive_bsdscrub,globl,hidden
systemfive_bsd: systemfive_bsd:
beg
cmp $0xfff,%ax cmp $0xfff,%ax
je systemfive_enosys je systemfive_enosys
btr $11,%eax // checks/reset the 800 cancellable bit btr $11,%eax // checks/reset the 800 cancellable bit
@ -230,6 +243,7 @@ systemfive_bsd:
syscall // bsd will need arg on stack sometimes syscall // bsd will need arg on stack sometimes
jc systemfive_errno // bsd sets carry flag if %rax is errno jc systemfive_errno // bsd sets carry flag if %rax is errno
ret ret
end
.endfn systemfive_bsd .endfn systemfive_bsd
#endif #endif
#if SupportsXnu() #if SupportsXnu()

View file

@ -215,6 +215,7 @@ LIBC_TESTMAIN_DIRECTDEPS = \
LIBC_LOG \ LIBC_LOG \
LIBC_MEM \ LIBC_MEM \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_PROC \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_STDIO \ LIBC_STDIO \
LIBC_SYSV \ LIBC_SYSV \
@ -222,7 +223,7 @@ LIBC_TESTMAIN_DIRECTDEPS = \
LIBC_TESTLIB \ LIBC_TESTLIB \
LIBC_TESTLIB_RUNNER \ LIBC_TESTLIB_RUNNER \
THIRD_PARTY_DLMALLOC \ THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GETOPT THIRD_PARTY_GETOPT \
LIBC_TESTMAIN_DEPS := \ LIBC_TESTMAIN_DEPS := \
$(call uniq,$(foreach x,$(LIBC_TESTMAIN_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(LIBC_TESTMAIN_DIRECTDEPS),$($(x))))

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/cpuset.h"
#include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
@ -31,6 +32,7 @@
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/intrin/ubsan.h" #include "libc/intrin/ubsan.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/limits.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/mem/leaks.h" #include "libc/mem/leaks.h"
@ -52,6 +54,8 @@
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#include "third_party/getopt/getopt.internal.h" #include "third_party/getopt/getopt.internal.h"
#pragma weak main
#define USAGE \ #define USAGE \
" [FLAGS]\n\ " [FLAGS]\n\
\n\ \n\
@ -88,7 +92,41 @@ static void GetOpts(int argc, char *argv[]) {
} }
} }
#pragma weak main static int rando(void) {
return _rand64() & INT_MAX;
}
static void limit_process_to_single_cpu(void) {
extern int disable_limit_process_to_single_cpu;
if (_weaken(disable_limit_process_to_single_cpu))
return;
if (!(IsLinux() || IsFreebsd() || IsNetbsd() || IsWindows()))
return;
if (IsFreebsd() && getuid())
return;
cpu_set_t legal;
if (sched_getaffinity(0, sizeof(cpu_set_t), &legal) == -1) {
perror("sched_setaffinity failed");
exit(1);
}
int count = CPU_COUNT(&legal);
cpu_set_t newset;
CPU_ZERO(&newset);
bool done = false;
while (!done) {
for (int i = 0; i < CPU_SETSIZE; ++i) {
if (CPU_ISSET(i, &legal) && !(rando() % count)) {
CPU_SET(rando() % count, &newset);
done = true;
break;
}
}
}
if (sched_setaffinity(0, sizeof(cpu_set_t), &newset) == -1) {
perror("sched_setaffinity failed");
exit(1);
}
}
/** /**
* Generic test program main function. * Generic test program main function.
@ -108,8 +146,11 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
// // this sometimes helps tease out mt bugs
// limit_process_to_single_cpu();
// test huge pointers by enabling pml5t // test huge pointers by enabling pml5t
if (_rand64() % 2) { if (rando() % 2) {
errno_t e = errno; errno_t e = errno;
mmap((char *)0x80000000000000, 1, PROT_NONE, // mmap((char *)0x80000000000000, 1, PROT_NONE, //
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

View file

@ -23,17 +23,36 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/thread/thread.h"
/** /**
* Returns true if signal is most likely a stack overflow. * Returns true if signal is caused by stack overflow.
*/ */
char __is_stack_overflow(siginfo_t *si, void *arg) { char __is_stack_overflow(siginfo_t *si, void *arg) {
// sanity check
ucontext_t *uc = arg; ucontext_t *uc = arg;
if (!si || !uc) if (!si || !uc)
return false; return false;
if (si->si_signo != SIGSEGV && si->si_signo != SIGBUS) if (si->si_signo != SIGSEGV && //
si->si_signo != SIGBUS)
return false; return false;
intptr_t sp = uc->uc_mcontext.SP;
intptr_t fp = (intptr_t)si->si_addr; // get stack information
return ABS(fp - sp) < __pagesize; pthread_attr_t attr;
if (pthread_getattr_np(pthread_self(), &attr))
return false;
size_t guardsize;
if (pthread_attr_getguardsize(&attr, &guardsize))
return false;
void *stackaddr;
size_t stacksize;
if (pthread_attr_getstack(&attr, &stackaddr, &stacksize))
return false;
// determine if faulting address is inside guard region
char *x = (char *)si->si_addr;
char *lo = (char *)stackaddr - guardsize;
char *hi = (char *)stackaddr;
return lo <= x && x < hi;
} }

Some files were not shown because too many files have changed in this diff Show more