mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-03 00:10:31 +00:00
Compare commits
35 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f1e83d5240 | ||
|
2fe8338f92 | ||
|
4ca513cba2 | ||
|
455910e8f2 | ||
|
9c68bc19b5 | ||
|
66d1050af6 | ||
|
fbc4fcbb71 | ||
|
afc986f741 | ||
|
5eb7cd6643 | ||
|
a8ed4fdd09 | ||
|
7b69652854 | ||
|
b235492e71 | ||
|
fc81fd8d16 | ||
|
38930de8e0 | ||
|
0e557d041d | ||
|
1d676b36e6 | ||
|
10a92cee94 | ||
|
42a9ed0131 | ||
|
12cb0669fb | ||
|
7f6a7d6fff | ||
|
9f6bf6ea71 | ||
|
102edf4ea2 | ||
|
21968acf99 | ||
|
98861b23fc | ||
|
dab6d7a345 | ||
|
90119c422c | ||
|
5907304049 | ||
|
035b0e2a62 | ||
|
7b67b20dae | ||
|
f0b0f926bf | ||
|
29eb7e67bb | ||
|
f71f61cd40 | ||
|
53c6edfd18 | ||
|
42a3bb729a | ||
|
c97a858470 |
107 changed files with 2044 additions and 898 deletions
42
.github/workflows/build.yml
vendored
42
.github/workflows/build.yml
vendored
|
@ -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 }}
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -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
|
||||||
|
|
25
README.md
25
README.md
|
@ -3,7 +3,7 @@
|
||||||
[](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
|
[](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).
|
||||||
|
|
|
@ -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)) }
|
||||||
|
|
||||||
|
|
26
ape/ape.lds
26
ape/ape.lds
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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[] = {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#define __COSMOPOLITAN_MAJOR__ 4
|
#define __COSMOPOLITAN_MAJOR__ 4
|
||||||
#define __COSMOPOLITAN_MINOR__ 0
|
#define __COSMOPOLITAN_MINOR__ 0
|
||||||
#define __COSMOPOLITAN_PATCH__ 1
|
#define __COSMOPOLITAN_PATCH__ 2
|
||||||
#define __COSMOPOLITAN__ \
|
#define __COSMOPOLITAN__ \
|
||||||
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
|
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
|
||||||
__COSMOPOLITAN_PATCH__)
|
__COSMOPOLITAN_PATCH__)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
32
libc/intrin/describeallocationtype.c
Normal file
32
libc/intrin/describeallocationtype.c
Normal 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);
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
18
libc/nt/advapi32/RegOpenKeyExA.S
Normal file
18
libc/nt/advapi32/RegOpenKeyExA.S
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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
19
libc/nt/kernel32/GetACP.S
Normal 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
|
|
@ -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
|
18
libc/nt/kernel32/GetLogicalDriveStringsA.S
Normal file
18
libc/nt/kernel32/GetLogicalDriveStringsA.S
Normal 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
|
19
libc/nt/kernel32/GetOEMCP.S
Normal file
19
libc/nt/kernel32/GetOEMCP.S
Normal 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
|
18
libc/nt/kernel32/GetShortPathNameW.S
Normal file
18
libc/nt/kernel32/GetShortPathNameW.S
Normal 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
|
|
@ -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
35
libc/nt/nls.h
Normal 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_ */
|
|
@ -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
13
libc/nt/struct/cpinfoex.h
Normal 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_ */
|
|
@ -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 \
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -140,6 +172,42 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||||
__imp_TerminateProcess(-1, ECHILD);
|
__imp_TerminateProcess(-1, ECHILD);
|
||||||
}
|
}
|
||||||
__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__ */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/proc/proc.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);
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -43,6 +45,7 @@
|
||||||
#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);
|
||||||
|
@ -120,8 +123,7 @@ static void fork_prepare(void) {
|
||||||
if (_weaken(__dlopen_lock))
|
if (_weaken(__dlopen_lock))
|
||||||
_weaken(__dlopen_lock)();
|
_weaken(__dlopen_lock)();
|
||||||
if (IsWindows())
|
if (IsWindows())
|
||||||
if (_weaken(__proc_lock))
|
__proc_lock();
|
||||||
_weaken(__proc_lock)();
|
|
||||||
if (_weaken(cosmo_stack_lock))
|
if (_weaken(cosmo_stack_lock))
|
||||||
_weaken(cosmo_stack_lock)();
|
_weaken(cosmo_stack_lock)();
|
||||||
__cxa_lock();
|
__cxa_lock();
|
||||||
|
@ -155,8 +157,7 @@ static void fork_parent(void) {
|
||||||
if (_weaken(cosmo_stack_unlock))
|
if (_weaken(cosmo_stack_unlock))
|
||||||
_weaken(cosmo_stack_unlock)();
|
_weaken(cosmo_stack_unlock)();
|
||||||
if (IsWindows())
|
if (IsWindows())
|
||||||
if (_weaken(__proc_unlock))
|
__proc_unlock();
|
||||||
_weaken(__proc_unlock)();
|
|
||||||
if (_weaken(__dlopen_unlock))
|
if (_weaken(__dlopen_unlock))
|
||||||
_weaken(__dlopen_unlock)();
|
_weaken(__dlopen_unlock)();
|
||||||
if (_weaken(__localtime_unlock))
|
if (_weaken(__localtime_unlock))
|
||||||
|
@ -167,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);
|
||||||
|
@ -191,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)();
|
||||||
|
@ -202,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()) {
|
||||||
|
@ -223,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);
|
||||||
|
@ -243,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
|
||||||
|
@ -264,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
93
libc/proc/getppid-nt.c
Normal 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;
|
||||||
|
}
|
|
@ -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"
|
||||||
|
@ -59,6 +60,7 @@
|
||||||
#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.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;
|
||||||
|
|
|
@ -131,14 +131,18 @@ textwindows static 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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -205,11 +205,9 @@ int pthread_mutex_unlock(pthread_mutex_t *) dontthrow paramsnonnull();
|
||||||
int pthread_mutex_wipe_np(pthread_mutex_t *) libcesque paramsnonnull();
|
int pthread_mutex_wipe_np(pthread_mutex_t *) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *) libcesque paramsnonnull();
|
int pthread_mutexattr_destroy(pthread_mutexattr_t *) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
|
||||||
int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_init(pthread_mutexattr_t *) libcesque paramsnonnull();
|
int pthread_mutexattr_init(pthread_mutexattr_t *) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
||||||
int pthread_mutexattr_setrobust(const pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
|
||||||
int pthread_mutexattr_settype(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
int pthread_mutexattr_settype(pthread_mutexattr_t *, int) libcesque paramsnonnull();
|
||||||
int pthread_once(pthread_once_t *, void (*)(void)) paramsnonnull();
|
int pthread_once(pthread_once_t *, void (*)(void)) paramsnonnull();
|
||||||
int pthread_orphan_np(void) libcesque;
|
int pthread_orphan_np(void) libcesque;
|
||||||
|
|
|
@ -167,7 +167,6 @@ void _StartTty(struct Tty *tty, unsigned char type, unsigned short yp,
|
||||||
unsigned short startx, unsigned char yc, unsigned char xc,
|
unsigned short startx, unsigned char yc, unsigned char xc,
|
||||||
void *fb, unsigned init_flags) {
|
void *fb, unsigned init_flags) {
|
||||||
unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor);
|
unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor);
|
||||||
struct DirectMap dm;
|
|
||||||
bzero(tty, sizeof(struct Tty));
|
bzero(tty, sizeof(struct Tty));
|
||||||
SetYp(tty, yp);
|
SetYp(tty, yp);
|
||||||
SetXp(tty, xp);
|
SetXp(tty, xp);
|
||||||
|
@ -183,9 +182,9 @@ void _StartTty(struct Tty *tty, unsigned char type, unsigned short yp,
|
||||||
tty->canvas = fb;
|
tty->canvas = fb;
|
||||||
xs = xsfb;
|
xs = xsfb;
|
||||||
} else {
|
} else {
|
||||||
dm = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE,
|
void *addr = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if (dm.addr == (void *)-1) {
|
if (addr == (void *)-1) {
|
||||||
/*
|
/*
|
||||||
* We are a bit low on memory. Try to go on anyway, & initialize
|
* We are a bit low on memory. Try to go on anyway, & initialize
|
||||||
* our tty as an emergency console.
|
* our tty as an emergency console.
|
||||||
|
@ -194,7 +193,7 @@ void _StartTty(struct Tty *tty, unsigned char type, unsigned short yp,
|
||||||
tty->canvas = fb;
|
tty->canvas = fb;
|
||||||
xs = xsfb;
|
xs = xsfb;
|
||||||
} else
|
} else
|
||||||
tty->canvas = dm.addr;
|
tty->canvas = addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetYn(tty, yn);
|
SetYn(tty, yn);
|
||||||
|
|
|
@ -51,6 +51,9 @@ void SetUpOnce(void) {
|
||||||
// ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath", 0));
|
// ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jart): fix this test
|
||||||
|
#if 0
|
||||||
|
|
||||||
TEST(cachestat, testCachestatOnDevices) {
|
TEST(cachestat, testCachestatOnDevices) {
|
||||||
const char *const files[] = {
|
const char *const files[] = {
|
||||||
"/dev/zero", "/dev/null", "/dev/urandom", "/proc/version", "/proc",
|
"/dev/zero", "/dev/null", "/dev/urandom", "/proc/version", "/proc",
|
||||||
|
@ -64,6 +67,8 @@ TEST(cachestat, testCachestatOnDevices) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(cachestat, testCachestatAfterWrite) {
|
TEST(cachestat, testCachestatAfterWrite) {
|
||||||
size_t size = 4 * pagesize;
|
size_t size = 4 * pagesize;
|
||||||
char *data = gc(xmalloc(size));
|
char *data = gc(xmalloc(size));
|
||||||
|
|
|
@ -1,242 +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 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 "dsp/core/core.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/struct/rlimit.h"
|
|
||||||
#include "libc/calls/struct/timespec.h"
|
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/errno.h"
|
|
||||||
#include "libc/intrin/directmap.h"
|
|
||||||
#include "libc/intrin/safemacros.h"
|
|
||||||
#include "libc/limits.h"
|
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/stdio/rand.h"
|
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
#include "libc/sysv/consts/auxv.h"
|
|
||||||
#include "libc/sysv/consts/map.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
|
||||||
#include "libc/sysv/consts/prot.h"
|
|
||||||
#include "libc/sysv/consts/rlimit.h"
|
|
||||||
#include "libc/sysv/consts/sig.h"
|
|
||||||
#include "libc/testlib/testlib.h"
|
|
||||||
#include "libc/time.h"
|
|
||||||
#include "libc/x/xsigaction.h"
|
|
||||||
#include "libc/x/xspawn.h"
|
|
||||||
|
|
||||||
#define MEM (64 * 1024 * 1024)
|
|
||||||
|
|
||||||
static char tmpname[PATH_MAX];
|
|
||||||
|
|
||||||
void OnSigxcpu(int sig) {
|
|
||||||
ASSERT_EQ(SIGXCPU, sig);
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnSigxfsz(int sig) {
|
|
||||||
unlink(tmpname);
|
|
||||||
ASSERT_EQ(SIGXFSZ, sig);
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testCpuLimit) {
|
|
||||||
int wstatus;
|
|
||||||
struct rlimit rlim;
|
|
||||||
struct timespec start;
|
|
||||||
double matrices[3][3][3];
|
|
||||||
if (IsWindows())
|
|
||||||
return; // of course it doesn't work on windows
|
|
||||||
if (IsXnu())
|
|
||||||
return; // TODO(jart): it worked before
|
|
||||||
if (IsOpenbsd())
|
|
||||||
return; // TODO(jart): fix flake
|
|
||||||
ASSERT_NE(-1, (wstatus = xspawn(0)));
|
|
||||||
if (wstatus == -2) {
|
|
||||||
ASSERT_EQ(0, xsigaction(SIGXCPU, OnSigxcpu, 0, 0, 0));
|
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_CPU, &rlim));
|
|
||||||
rlim.rlim_cur = 1; // set soft limit to one second
|
|
||||||
ASSERT_EQ(0, setrlimit(RLIMIT_CPU, &rlim));
|
|
||||||
start = timespec_real();
|
|
||||||
do {
|
|
||||||
matmul3(matrices[0], matrices[1], matrices[2]);
|
|
||||||
matmul3(matrices[0], matrices[1], matrices[2]);
|
|
||||||
matmul3(matrices[0], matrices[1], matrices[2]);
|
|
||||||
matmul3(matrices[0], matrices[1], matrices[2]);
|
|
||||||
} while (timespec_sub(timespec_real(), start).tv_sec < 5);
|
|
||||||
_Exit(1);
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(WIFEXITED(wstatus));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(wstatus));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testFileSizeLimit) {
|
|
||||||
char junkdata[512];
|
|
||||||
int i, fd, wstatus;
|
|
||||||
struct rlimit rlim;
|
|
||||||
if (IsWindows())
|
|
||||||
return; /* of course it doesn't work on windows */
|
|
||||||
ASSERT_NE(-1, (wstatus = xspawn(0)));
|
|
||||||
if (wstatus == -2) {
|
|
||||||
ASSERT_EQ(0, xsigaction(SIGXFSZ, OnSigxfsz, 0, 0, 0));
|
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_FSIZE, &rlim));
|
|
||||||
rlim.rlim_cur = 1024 * 1024; /* set soft limit to one megabyte */
|
|
||||||
ASSERT_EQ(0, setrlimit(RLIMIT_FSIZE, &rlim));
|
|
||||||
snprintf(tmpname, sizeof(tmpname), "%s/%s.%d",
|
|
||||||
firstnonnull(getenv("TMPDIR"), "/tmp"),
|
|
||||||
firstnonnull(program_invocation_short_name, "unknown"), getpid());
|
|
||||||
ASSERT_NE(-1, (fd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC, 0644)));
|
|
||||||
rngset(junkdata, 512, lemur64, -1);
|
|
||||||
for (i = 0; i < 5 * 1024 * 1024 / 512; ++i) {
|
|
||||||
ASSERT_EQ(512, write(fd, junkdata, 512));
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
unlink(tmpname);
|
|
||||||
_Exit(1);
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(WIFEXITED(wstatus));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(wstatus));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
int SetMemoryLimit(size_t n) {
|
|
||||||
struct rlimit rlim = {0};
|
|
||||||
getrlimit(RLIMIT_AS, &rlim);
|
|
||||||
rlim.rlim_cur = n;
|
|
||||||
rlim.rlim_max = n;
|
|
||||||
return setrlimit(RLIMIT_AS, &rlim);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testMemoryLimit) {
|
|
||||||
char *p;
|
|
||||||
bool gotsome;
|
|
||||||
int i, wstatus;
|
|
||||||
ASSERT_NE(-1, (wstatus = xspawn(0)));
|
|
||||||
if (wstatus == -2) {
|
|
||||||
ASSERT_EQ(0, SetMemoryLimit(MEM));
|
|
||||||
for (gotsome = false, i = 0; i < (MEM * 2) / getpagesize(); ++i) {
|
|
||||||
p = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
|
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
if (p != MAP_FAILED) {
|
|
||||||
gotsome = true;
|
|
||||||
} else {
|
|
||||||
ASSERT_TRUE(gotsome);
|
|
||||||
ASSERT_EQ(ENOMEM, errno);
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
rngset(p, getpagesize(), lemur64, -1);
|
|
||||||
}
|
|
||||||
_Exit(1);
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(WIFEXITED(wstatus));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(wstatus));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testVirtualMemoryLimit) {
|
|
||||||
char *p;
|
|
||||||
int i, wstatus;
|
|
||||||
ASSERT_NE(-1, (wstatus = xspawn(0)));
|
|
||||||
if (wstatus == -2) {
|
|
||||||
ASSERT_EQ(0, setrlimit(RLIMIT_AS, &(struct rlimit){MEM, MEM}));
|
|
||||||
for (i = 0; i < (MEM * 2) / getpagesize(); ++i) {
|
|
||||||
if ((p = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
|
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0)) ==
|
|
||||||
MAP_FAILED) {
|
|
||||||
ASSERT_EQ(ENOMEM, errno);
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
rngset(p, getpagesize(), lemur64, -1);
|
|
||||||
}
|
|
||||||
_Exit(1);
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(WIFEXITED(wstatus));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(wstatus));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testDataMemoryLimit) {
|
|
||||||
char *p;
|
|
||||||
int i, wstatus;
|
|
||||||
if (IsXnu())
|
|
||||||
return; /* doesn't work on darwin */
|
|
||||||
if (IsNetbsd())
|
|
||||||
return; /* doesn't work on netbsd */
|
|
||||||
if (IsFreebsd())
|
|
||||||
return; /* doesn't work on freebsd */
|
|
||||||
if (IsLinux())
|
|
||||||
return; /* doesn't work on gnu/systemd */
|
|
||||||
if (IsWindows())
|
|
||||||
return; /* of course it doesn't work on windows */
|
|
||||||
ASSERT_NE(-1, (wstatus = xspawn(0)));
|
|
||||||
if (wstatus == -2) {
|
|
||||||
ASSERT_EQ(0, setrlimit(RLIMIT_DATA, &(struct rlimit){MEM, MEM}));
|
|
||||||
for (i = 0; i < (MEM * 2) / getpagesize(); ++i) {
|
|
||||||
p = sys_mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
|
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0)
|
|
||||||
.addr;
|
|
||||||
if (p == MAP_FAILED) {
|
|
||||||
ASSERT_EQ(ENOMEM, errno);
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
rngset(p, getpagesize(), lemur64, -1);
|
|
||||||
}
|
|
||||||
_Exit(1);
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(WIFEXITED(wstatus));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(wstatus));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(wstatus));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(wstatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, testPhysicalMemoryLimit) {
|
|
||||||
/* RLIMIT_RSS doesn't work on gnu/systemd */
|
|
||||||
/* RLIMIT_RSS doesn't work on darwin */
|
|
||||||
/* RLIMIT_RSS doesn't work on freebsd */
|
|
||||||
/* RLIMIT_RSS doesn't work on netbsd */
|
|
||||||
/* RLIMIT_RSS doesn't work on openbsd */
|
|
||||||
/* of course it doesn't work on windows */
|
|
||||||
}
|
|
||||||
|
|
||||||
wontreturn void OnVfork(void *ctx) {
|
|
||||||
struct rlimit *rlim;
|
|
||||||
rlim = ctx;
|
|
||||||
rlim->rlim_cur -= 1;
|
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_CPU, rlim));
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(setrlimit, isVforkSafe) {
|
|
||||||
int ws;
|
|
||||||
struct rlimit rlim[2];
|
|
||||||
if (IsWindows())
|
|
||||||
return; /* of course it doesn't work on windows */
|
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_CPU, rlim));
|
|
||||||
ASSERT_NE(-1, (ws = xvspawn(OnVfork, rlim, 0)));
|
|
||||||
EXPECT_TRUE(WIFEXITED(ws));
|
|
||||||
EXPECT_FALSE(WIFSIGNALED(ws));
|
|
||||||
EXPECT_EQ(0, WEXITSTATUS(ws));
|
|
||||||
EXPECT_EQ(0, WTERMSIG(ws));
|
|
||||||
ASSERT_EQ(0, getrlimit(RLIMIT_CPU, rlim + 1));
|
|
||||||
EXPECT_EQ(rlim[0].rlim_cur, rlim[1].rlim_cur);
|
|
||||||
EXPECT_EQ(rlim[0].rlim_max, rlim[1].rlim_max);
|
|
||||||
}
|
|
|
@ -59,7 +59,7 @@ void CrashHandler(int sig, siginfo_t *si, void *ctx) {
|
||||||
kprintf("kprintf avoids overflowing %G si_addr=%lx sp=%lx\n", si->si_signo,
|
kprintf("kprintf avoids overflowing %G si_addr=%lx sp=%lx\n", si->si_signo,
|
||||||
si->si_addr, ((ucontext_t *)ctx)->uc_mcontext.SP);
|
si->si_addr, ((ucontext_t *)ctx)->uc_mcontext.SP);
|
||||||
smashed_stack = true;
|
smashed_stack = true;
|
||||||
unassert(__is_stack_overflow(si, ctx));
|
// unassert(__is_stack_overflow(si, ctx)); // fuzzy with main thread
|
||||||
longjmp(recover, 123);
|
longjmp(recover, 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/sigaltstack.h"
|
#include "libc/calls/struct/sigaltstack.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
@ -40,8 +41,9 @@
|
||||||
|
|
||||||
volatile bool smashed_stack;
|
volatile bool smashed_stack;
|
||||||
|
|
||||||
void CrashHandler(int sig) {
|
void CrashHandler(int sig, siginfo_t *si, void *ctx) {
|
||||||
smashed_stack = true;
|
smashed_stack = true;
|
||||||
|
unassert(__is_stack_overflow(si, ctx));
|
||||||
pthread_exit((void *)123L);
|
pthread_exit((void *)123L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ void *MyPosixThread(void *arg) {
|
||||||
ASSERT_SYS(0, 0, sigaltstack(&ss, 0));
|
ASSERT_SYS(0, 0, sigaltstack(&ss, 0));
|
||||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK; // <-- important
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK; // <-- important
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_handler = CrashHandler;
|
sa.sa_sigaction = CrashHandler;
|
||||||
sigaction(SIGBUS, &sa, 0);
|
sigaction(SIGBUS, &sa, 0);
|
||||||
sigaction(SIGSEGV, &sa, 0);
|
sigaction(SIGSEGV, &sa, 0);
|
||||||
exit(StackOverflow(1));
|
exit(StackOverflow(1));
|
||||||
|
|
|
@ -16,22 +16,28 @@
|
||||||
│ 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 <cosmo.h>
|
#include "libc/assert.h"
|
||||||
#include <limits.h>
|
#include "libc/calls/calls.h"
|
||||||
#include <pthread.h>
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include <signal.h>
|
#include "libc/calls/struct/siginfo.h"
|
||||||
#include <unistd.h>
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/sysv/consts/ss.h"
|
||||||
|
#include "libc/thread/thread.h"
|
||||||
|
#include "libc/thread/tls.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stack overflow recovery technique #5
|
* stack overflow test #5
|
||||||
* use the cosmo posix threads extensions
|
* - make sure fork() preserves sigaltstack()
|
||||||
|
* - make sure fork() preserves guard page status
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sig_atomic_t smashed_stack;
|
jmp_buf recover;
|
||||||
|
|
||||||
void CrashHandler(int sig) {
|
void CrashHandler(int sig, siginfo_t *si, void *ctx) {
|
||||||
smashed_stack = true;
|
unassert(__is_stack_overflow(si, ctx));
|
||||||
pthread_exit(0);
|
longjmp(recover, 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
int StackOverflow(int d) {
|
int StackOverflow(int d) {
|
||||||
|
@ -44,42 +50,40 @@ int StackOverflow(int d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MyPosixThread(void *arg) {
|
void *MyPosixThread(void *arg) {
|
||||||
exit(StackOverflow(1));
|
int pid;
|
||||||
|
unassert(__get_tls()->tib_sigstack_addr);
|
||||||
|
unassert((pid = fork()) != -1);
|
||||||
|
if (!pid) {
|
||||||
|
int jumpcode;
|
||||||
|
if (!(jumpcode = setjmp(recover))) {
|
||||||
|
StackOverflow(1);
|
||||||
|
_Exit(1);
|
||||||
|
}
|
||||||
|
unassert(123 == jumpcode);
|
||||||
|
} else {
|
||||||
|
int ws;
|
||||||
|
unassert(wait(&ws) != -1);
|
||||||
|
unassert(!ws);
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
// choose the most dangerously small size possible
|
|
||||||
size_t sigstacksize = sysconf(_SC_MINSIGSTKSZ) + 2048;
|
|
||||||
|
|
||||||
// setup signal handler
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_ONSTACK;
|
sa.sa_sigaction = CrashHandler;
|
||||||
sa.sa_handler = CrashHandler;
|
unassert(!sigaction(SIGBUS, &sa, 0));
|
||||||
if (sigaction(SIGBUS, &sa, 0))
|
unassert(!sigaction(SIGSEGV, &sa, 0));
|
||||||
return 1;
|
|
||||||
if (sigaction(SIGSEGV, &sa, 0))
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
// create thread with signal stack
|
pthread_t th;
|
||||||
pthread_t id;
|
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
if (pthread_attr_init(&attr))
|
unassert(!pthread_attr_init(&attr));
|
||||||
return 3;
|
unassert(!pthread_attr_setguardsize(&attr, getpagesize()));
|
||||||
if (pthread_attr_setguardsize(&attr, getpagesize()))
|
unassert(!pthread_attr_setsigaltstacksize_np(&attr, SIGSTKSZ));
|
||||||
return 4;
|
unassert(!pthread_create(&th, &attr, MyPosixThread, 0));
|
||||||
if (pthread_attr_setsigaltstacksize_np(&attr, sigstacksize))
|
unassert(!pthread_attr_destroy(&attr));
|
||||||
return 5;
|
unassert(!pthread_join(th, 0));
|
||||||
if (pthread_create(&id, &attr, MyPosixThread, 0))
|
|
||||||
return 6;
|
|
||||||
if (pthread_attr_destroy(&attr))
|
|
||||||
return 7;
|
|
||||||
if (pthread_join(id, 0))
|
|
||||||
return 8;
|
|
||||||
if (!smashed_stack)
|
|
||||||
return 9;
|
|
||||||
|
|
||||||
CheckForMemoryLeaks();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,42 @@ TEST(mmap, fixedTaken) {
|
||||||
EXPECT_SYS(0, 0, munmap(p, 1));
|
EXPECT_SYS(0, 0, munmap(p, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(mmap, anon_rw_to_rx) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED, (p = mmap(0, 1, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
ASSERT_SYS(0, 0, mprotect(p, 1, PROT_READ | PROT_EXEC));
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, anon_rw_fork_to_rx) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED, (p = mmap(0, 1, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
SPAWN(fork);
|
||||||
|
ASSERT_SYS(0, 0, mprotect(p, 1, PROT_READ | PROT_EXEC));
|
||||||
|
EXITS(0);
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, anon_r_to_rw) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED,
|
||||||
|
(p = mmap(0, 1, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
ASSERT_SYS(0, 0, mprotect(p, 1, PROT_READ | PROT_WRITE));
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, anon_r_fork_to_rw) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED,
|
||||||
|
(p = mmap(0, 1, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
SPAWN(fork);
|
||||||
|
ASSERT_SYS(0, 0, mprotect(p, 1, PROT_READ | PROT_WRITE));
|
||||||
|
EXITS(0);
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(mmap, hint) {
|
TEST(mmap, hint) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ TEST_LIBC_PROC_DIRECTDEPS = \
|
||||||
LIBC_NT_KERNEL32 \
|
LIBC_NT_KERNEL32 \
|
||||||
LIBC_PROC \
|
LIBC_PROC \
|
||||||
LIBC_RUNTIME \
|
LIBC_RUNTIME \
|
||||||
|
LIBC_LOG \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
|
@ -90,6 +91,7 @@ o/$(MODE)/test/libc/proc/execve_test.dbg: \
|
||||||
o/$(MODE)/test/libc/proc/execve_test.o \
|
o/$(MODE)/test/libc/proc/execve_test.o \
|
||||||
o/$(MODE)/test/libc/calls/life-nomod.zip.o \
|
o/$(MODE)/test/libc/calls/life-nomod.zip.o \
|
||||||
o/$(MODE)/test/libc/proc/execve_test_prog1.zip.o \
|
o/$(MODE)/test/libc/proc/execve_test_prog1.zip.o \
|
||||||
|
o/$(MODE)/test/libc/proc/execve_test_prog2.zip.o \
|
||||||
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
o/$(MODE)/test/libc/mem/prog/life.elf.zip.o \
|
||||||
o/$(MODE)/test/libc/mem/prog/sock.elf.zip.o \
|
o/$(MODE)/test/libc/mem/prog/sock.elf.zip.o \
|
||||||
o/$(MODE)/test/libc/proc/proc.pkg \
|
o/$(MODE)/test/libc/proc/proc.pkg \
|
||||||
|
@ -119,6 +121,7 @@ o/$(MODE)/test/libc/proc/life.dbg: \
|
||||||
|
|
||||||
o/$(MODE)/test/libc/proc/life.zip.o \
|
o/$(MODE)/test/libc/proc/life.zip.o \
|
||||||
o/$(MODE)/test/libc/proc/execve_test_prog1.zip.o \
|
o/$(MODE)/test/libc/proc/execve_test_prog1.zip.o \
|
||||||
|
o/$(MODE)/test/libc/proc/execve_test_prog2.zip.o \
|
||||||
o/$(MODE)/test/libc/proc/life-pe.zip.o: private \
|
o/$(MODE)/test/libc/proc/life-pe.zip.o: private \
|
||||||
ZIPOBJ_FLAGS += \
|
ZIPOBJ_FLAGS += \
|
||||||
-B
|
-B
|
||||||
|
|
|
@ -53,12 +53,12 @@ TEST(execve, testArgPassing) {
|
||||||
char ibuf[12], buf[8];
|
char ibuf[12], buf[8];
|
||||||
const char *prog = "./execve_test_prog1";
|
const char *prog = "./execve_test_prog1";
|
||||||
testlib_extract("/zip/execve_test_prog1", prog, 0755);
|
testlib_extract("/zip/execve_test_prog1", prog, 0755);
|
||||||
|
testlib_extract("/zip/execve_test_prog2", "execve_test_prog2", 0755);
|
||||||
for (i = 0; i < N; ++i) {
|
for (i = 0; i < N; ++i) {
|
||||||
FormatInt32(ibuf, i);
|
FormatInt32(ibuf, i);
|
||||||
GenBuf(buf, i);
|
GenBuf(buf, i);
|
||||||
SPAWN(vfork);
|
SPAWN(vfork);
|
||||||
execve(prog, (char *const[]){(char *)prog, "-", ibuf, buf, 0},
|
execl(prog, prog, "-", ibuf, buf, NULL);
|
||||||
(char *const[]){0});
|
|
||||||
kprintf("execve failed: %m\n");
|
kprintf("execve failed: %m\n");
|
||||||
EXITS(0);
|
EXITS(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
void GenBuf(char buf[8], int x) {
|
void GenBuf(char buf[8], int x) {
|
||||||
|
@ -40,5 +41,15 @@ int main(int argc, char *argv[]) {
|
||||||
tinyprint(2, "error: buf check failed\n", NULL);
|
tinyprint(2, "error: buf check failed\n", NULL);
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
const char *prog = "./execve_test_prog2";
|
||||||
|
if (!fork()) {
|
||||||
|
execl(prog, prog, NULL);
|
||||||
|
_Exit(127);
|
||||||
|
}
|
||||||
|
int ws;
|
||||||
|
if (wait(&ws) == -1)
|
||||||
|
return 30;
|
||||||
|
if (ws)
|
||||||
|
return 31;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
│ 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/thread/thread.h"
|
#include "libc/proc/proc.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
// this mutex is needed so execve() can shut down the signal worker
|
int main(int argc, char *argv[]) {
|
||||||
pthread_mutex_t __sig_worker_lock = PTHREAD_MUTEX_INITIALIZER;
|
}
|
|
@ -151,6 +151,32 @@ TEST(fork, preservesTlsMemory) {
|
||||||
EXITS(0);
|
EXITS(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(fork, privateExtraPageData_getsCopiedByFork) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED, (p = mmap(0, 1, PROT_WRITE | PROT_READ,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
p[0] = 1;
|
||||||
|
p[1] = 2;
|
||||||
|
SPAWN(fork);
|
||||||
|
ASSERT_EQ(1, p[0]);
|
||||||
|
ASSERT_EQ(2, p[1]);
|
||||||
|
EXITS(0);
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(fork, sharedExtraPageData_getsResurrectedByFork) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED, (p = mmap(0, 1, PROT_WRITE | PROT_READ,
|
||||||
|
MAP_ANONYMOUS | MAP_SHARED, -1, 0)));
|
||||||
|
p[0] = 1;
|
||||||
|
p[1] = 2;
|
||||||
|
SPAWN(fork);
|
||||||
|
ASSERT_EQ(1, p[0]);
|
||||||
|
ASSERT_EQ(2, p[1]);
|
||||||
|
EXITS(0);
|
||||||
|
ASSERT_SYS(0, 0, munmap(p, 1));
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_TERMSIG \
|
#define CHECK_TERMSIG \
|
||||||
if (WIFSIGNALED(ws)) { \
|
if (WIFSIGNALED(ws)) { \
|
||||||
kprintf("%s:%d: error: forked life subprocess terminated with %G\n", \
|
kprintf("%s:%d: error: forked life subprocess terminated with %G\n", \
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// sh -c 'build/bootstrap/make -j8 V=1 o//test/posix/sigchld_test.runs'
|
// sh -c '.cosmocc/current/bin/make -j8 V=1 o//test/posix/sigchld_test.runs'
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void Assert(const char *file, int line, bool ok) {
|
void Assert(const char *file, int line, bool ok) {
|
||||||
|
|
|
@ -85,6 +85,13 @@
|
||||||
" executable will self-modify its header on\n" \
|
" executable will self-modify its header on\n" \
|
||||||
" the first run, to use the platform format\n" \
|
" the first run, to use the platform format\n" \
|
||||||
"\n" \
|
"\n" \
|
||||||
|
" -k KERNEL test for maching kernel name [repeatable]\n" \
|
||||||
|
" when set, the shell script for subsequent\n" \
|
||||||
|
" loader executables will check if uname -s\n" \
|
||||||
|
" output matches the kernel string, only if\n" \
|
||||||
|
" the loader executable architecture is not\n" \
|
||||||
|
" an architecture in the input binary list\n" \
|
||||||
|
"\n" \
|
||||||
" -M PATH bundle ape loader source code file for m1\n" \
|
" -M PATH bundle ape loader source code file for m1\n" \
|
||||||
" processors running the xnu kernel so that\n" \
|
" processors running the xnu kernel so that\n" \
|
||||||
" it can be compiled on the fly by xcode\n" \
|
" it can be compiled on the fly by xcode\n" \
|
||||||
|
@ -213,6 +220,7 @@ struct Loader {
|
||||||
char *ddarg_size1;
|
char *ddarg_size1;
|
||||||
char *ddarg_skip2;
|
char *ddarg_skip2;
|
||||||
char *ddarg_size2;
|
char *ddarg_size2;
|
||||||
|
const char *kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Loaders {
|
struct Loaders {
|
||||||
|
@ -244,6 +252,7 @@ static struct Inputs inputs;
|
||||||
static char ape_heredoc[15];
|
static char ape_heredoc[15];
|
||||||
static enum Strategy strategy;
|
static enum Strategy strategy;
|
||||||
static struct Loaders loaders;
|
static struct Loaders loaders;
|
||||||
|
static const char *loader_kernel;
|
||||||
static const char *custom_sh_code;
|
static const char *custom_sh_code;
|
||||||
static bool force_bypass_binfmt_misc;
|
static bool force_bypass_binfmt_misc;
|
||||||
static bool generate_debuggable_binary;
|
static bool generate_debuggable_binary;
|
||||||
|
@ -979,13 +988,19 @@ static void AddLoader(const char *path) {
|
||||||
if (loaders.n == ARRAYLEN(loaders.p)) {
|
if (loaders.n == ARRAYLEN(loaders.p)) {
|
||||||
Die(prog, "too many loaders");
|
Die(prog, "too many loaders");
|
||||||
}
|
}
|
||||||
loaders.p[loaders.n++].path = path;
|
struct Loader *loader = &loaders.p[loaders.n++];
|
||||||
|
loader->path = path;
|
||||||
|
loader->kernel = loader_kernel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetLoaderKernel(const char *kernel) {
|
||||||
|
loader_kernel = kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetOpts(int argc, char *argv[]) {
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
int opt, bits;
|
int opt, bits;
|
||||||
bool got_support_vector = false;
|
bool got_support_vector = false;
|
||||||
while ((opt = getopt(argc, argv, "hvgsGBo:l:S:M:V:")) != -1) {
|
while ((opt = getopt(argc, argv, "hvgsGBo:l:k:S:M:V:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'o':
|
case 'o':
|
||||||
outpath = optarg;
|
outpath = optarg;
|
||||||
|
@ -1009,6 +1024,10 @@ static void GetOpts(int argc, char *argv[]) {
|
||||||
HashInputString("-l");
|
HashInputString("-l");
|
||||||
AddLoader(optarg);
|
AddLoader(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
HashInputString("-k");
|
||||||
|
SetLoaderKernel(optarg);
|
||||||
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
HashInputString("-S");
|
HashInputString("-S");
|
||||||
HashInputString(optarg);
|
HashInputString(optarg);
|
||||||
|
@ -1630,6 +1649,28 @@ static char *GenerateScriptIfMachine(char *p, struct Input *in) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *GenerateScriptIfLoaderMachine(char *p, struct Loader *loader) {
|
||||||
|
if (loader->machine == EM_NEXGEN32E) {
|
||||||
|
p = stpcpy(p, "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]");
|
||||||
|
} else if (loader->machine == EM_AARCH64) {
|
||||||
|
p = stpcpy(p, "if [ \"$m\" = aarch64 ] || [ \"$m\" = arm64 ] || [ \"$m\" = evbarm ]");
|
||||||
|
} else if (loader->machine == EM_PPC64) {
|
||||||
|
p = stpcpy(p, "if [ \"$m\" = ppc64le ]");
|
||||||
|
} else if (loader->machine == EM_MIPS) {
|
||||||
|
p = stpcpy(p, "if [ \"$m\" = mips64 ]");
|
||||||
|
} else {
|
||||||
|
Die(loader->path, "unsupported cpu architecture");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loader->kernel) {
|
||||||
|
p = stpcpy(p, " && [ \"$k\" = ");
|
||||||
|
p = stpcpy(p, loader->kernel);
|
||||||
|
p = stpcpy(p, " ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
return stpcpy(p, "; then\n");
|
||||||
|
}
|
||||||
|
|
||||||
static char *FinishGeneratingDosHeader(char *p) {
|
static char *FinishGeneratingDosHeader(char *p) {
|
||||||
p = WRITE16LE(p, 0x1000); // 10: MZ: lowers upper bound load / 16
|
p = WRITE16LE(p, 0x1000); // 10: MZ: lowers upper bound load / 16
|
||||||
p = WRITE16LE(p, 0xf800); // 12: MZ: roll greed on bss
|
p = WRITE16LE(p, 0xf800); // 12: MZ: roll greed on bss
|
||||||
|
@ -1879,8 +1920,16 @@ int main(int argc, char *argv[]) {
|
||||||
for (j = i + 1; j < loaders.n; ++j) {
|
for (j = i + 1; j < loaders.n; ++j) {
|
||||||
if (loaders.p[i].os == loaders.p[j].os &&
|
if (loaders.p[i].os == loaders.p[j].os &&
|
||||||
loaders.p[i].machine == loaders.p[j].machine) {
|
loaders.p[i].machine == loaders.p[j].machine) {
|
||||||
|
if (!loaders.p[i].kernel && !loaders.p[j].kernel) {
|
||||||
Die(prog, "multiple ape loaders specified for the same platform");
|
Die(prog, "multiple ape loaders specified for the same platform");
|
||||||
}
|
}
|
||||||
|
if (loaders.p[i].kernel != NULL &&
|
||||||
|
loaders.p[j].kernel != NULL &&
|
||||||
|
strcmp(loaders.p[i].kernel, loaders.p[j].kernel) == 0) {
|
||||||
|
Die(prog, "multiple ape loaders specified for the same platform "
|
||||||
|
"with matching kernels");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2190,6 +2239,36 @@ int main(int argc, char *argv[]) {
|
||||||
gotsome = true;
|
gotsome = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extract the ape loader for non-input architectures
|
||||||
|
// if the user requested a host kernel check, get the host kernel
|
||||||
|
if (loader_kernel) {
|
||||||
|
p = stpcpy(p, "k=$(uname -s 2>/dev/null) || k=unknown\n");
|
||||||
|
}
|
||||||
|
for (i = 0; i < loaders.n; ++i) {
|
||||||
|
struct Loader *loader = loaders.p + i;
|
||||||
|
if (loader->used) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
loader->used = true;
|
||||||
|
p = GenerateScriptIfLoaderMachine(p, loader);
|
||||||
|
p = stpcpy(p, "mkdir -p \"${t%/*}\" ||exit\n"
|
||||||
|
"dd if=\"$o\"");
|
||||||
|
p = stpcpy(p, " skip=");
|
||||||
|
loader->ddarg_skip2 = p;
|
||||||
|
p = GenerateDecimalOffsetRelocation(p);
|
||||||
|
p = stpcpy(p, " count=");
|
||||||
|
loader->ddarg_size2 = p;
|
||||||
|
p = GenerateDecimalOffsetRelocation(p);
|
||||||
|
p = stpcpy(p, " bs=1 2>/dev/null | gzip -dc >\"$t.$$\" ||exit\n"
|
||||||
|
"chmod 755 \"$t.$$\" ||exit\n"
|
||||||
|
"mv -f \"$t.$$\" \"$t\" ||exit\n");
|
||||||
|
p = stpcpy(p, "exec \"$t\" \"$o\" \"$@\"\n"
|
||||||
|
"fi\n");
|
||||||
|
gotsome = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close if-statements
|
||||||
if (inputs.n && (support_vector & _HOSTXNU)) {
|
if (inputs.n && (support_vector & _HOSTXNU)) {
|
||||||
if (!gotsome) {
|
if (!gotsome) {
|
||||||
p = stpcpy(p, "true\n");
|
p = stpcpy(p, "true\n");
|
||||||
|
|
283
tool/build/renamestr.c
Normal file
283
tool/build/renamestr.c
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/*-*- 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/calls/calls.h"
|
||||||
|
#include "libc/elf/def.h"
|
||||||
|
#include "libc/elf/elf.h"
|
||||||
|
#include "libc/elf/scalar.h"
|
||||||
|
#include "libc/elf/struct/ehdr.h"
|
||||||
|
#include "libc/elf/struct/phdr.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/intrin/likely.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/symbols.internal.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "third_party/getopt/getopt.internal.h"
|
||||||
|
|
||||||
|
#define VERSION \
|
||||||
|
"renamestr v0.1\n" \
|
||||||
|
"https://github.com/jart/cosmopolitan\n"
|
||||||
|
|
||||||
|
#define MANUAL \
|
||||||
|
" -f FROM -t TO INPUT \n" \
|
||||||
|
"\n" \
|
||||||
|
"DESCRIPTION\n" \
|
||||||
|
"\n" \
|
||||||
|
" in-place string replacement in ELF binary .rodata\n" \
|
||||||
|
"\n" \
|
||||||
|
" this program may be used to replace strings in the\n" \
|
||||||
|
" .rodata sections of ELF binaries, in-place.\n" \
|
||||||
|
"\n" \
|
||||||
|
"FLAGS\n" \
|
||||||
|
"\n" \
|
||||||
|
" -h show usage\n" \
|
||||||
|
"\n" \
|
||||||
|
" -v show version\n" \
|
||||||
|
"\n" \
|
||||||
|
" -f FROM source string to replace\n" \
|
||||||
|
"\n" \
|
||||||
|
" -t TO target string replacement. must be shorter\n" \
|
||||||
|
" than FROM string for replacement to work\n" \
|
||||||
|
"\n" \
|
||||||
|
" INPUT ELF binary containing strings to replace\n" \
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
static const char *prog;
|
||||||
|
static const char *exepath;
|
||||||
|
static Elf64_Shdr *rodata;
|
||||||
|
static char *rostart;
|
||||||
|
static char *roend;
|
||||||
|
static int exefd;
|
||||||
|
|
||||||
|
static wontreturn void Die(const char *thing, const char *reason) {
|
||||||
|
tinyprint(2, thing, ": ", reason, "\n", NULL);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static wontreturn void DieSys(const char *thing) {
|
||||||
|
perror(thing);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static wontreturn void ShowUsage(int rc, int fd) {
|
||||||
|
tinyprint(fd, "USAGE\n\n ", prog, MANUAL, NULL);
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Pwrite(const void *data, size_t size, uint64_t offset) {
|
||||||
|
ssize_t rc;
|
||||||
|
const char *p, *e;
|
||||||
|
for (p = data, e = p + size; p < e; p += (size_t)rc, offset += (size_t)rc) {
|
||||||
|
if ((rc = pwrite(exefd, p, e - p, offset)) == -1) {
|
||||||
|
DieSys(exepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
const char *str;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Param {
|
||||||
|
struct String from;
|
||||||
|
struct String to;
|
||||||
|
int count;
|
||||||
|
char *roloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Params {
|
||||||
|
int n;
|
||||||
|
struct Param p[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Params params;
|
||||||
|
|
||||||
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
|
int opt;
|
||||||
|
bool partial = false;
|
||||||
|
params.n = 0;
|
||||||
|
struct Param *param;
|
||||||
|
while ((opt = getopt(argc, argv, "hvf:t:")) != -1) {
|
||||||
|
if (params.n >= ARRAYLEN(params.p)) {
|
||||||
|
param = NULL;
|
||||||
|
} else {
|
||||||
|
param = &(params.p[params.n]);
|
||||||
|
}
|
||||||
|
switch (opt) {
|
||||||
|
case 'f':
|
||||||
|
if (!param) {
|
||||||
|
Die(prog, "too many replacements provided");
|
||||||
|
}
|
||||||
|
if (param->from.str) {
|
||||||
|
Die(prog, "from string already provided");
|
||||||
|
}
|
||||||
|
param->from.str = optarg;
|
||||||
|
param->from.len = strlen(optarg);
|
||||||
|
partial = !partial;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (!param) {
|
||||||
|
Die(prog, "too many replacements provided");
|
||||||
|
}
|
||||||
|
if (param->to.str) {
|
||||||
|
Die(prog, "to string already provided");
|
||||||
|
}
|
||||||
|
param->to.str = optarg;
|
||||||
|
param->to.len = strlen(optarg);
|
||||||
|
partial = !partial;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
tinyprint(0, VERSION, NULL);
|
||||||
|
exit(0);
|
||||||
|
case 'h':
|
||||||
|
ShowUsage(0, 1);
|
||||||
|
default:
|
||||||
|
ShowUsage(1, 2);
|
||||||
|
}
|
||||||
|
if (param->from.str && param->to.str) {
|
||||||
|
if (param->from.len < param->to.len) {
|
||||||
|
Die(prog, "to.str longer than from.str, cannot replace");
|
||||||
|
}
|
||||||
|
params.n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params.n == 0) {
|
||||||
|
Die(prog, "no replacements provided");
|
||||||
|
}
|
||||||
|
if (partial) {
|
||||||
|
Die(prog, "partial replacement provided");
|
||||||
|
}
|
||||||
|
if (optind == argc) {
|
||||||
|
Die(prog, "missing input argument");
|
||||||
|
}
|
||||||
|
if (optind != argc - 1) {
|
||||||
|
Die(prog, "too many args");
|
||||||
|
}
|
||||||
|
exepath = argv[optind];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
union {
|
||||||
|
char *map;
|
||||||
|
Elf64_Ehdr *elf;
|
||||||
|
unsigned char *umap;
|
||||||
|
};
|
||||||
|
size_t size;
|
||||||
|
const char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Input input;
|
||||||
|
|
||||||
|
static void OpenInput(const char *path) {
|
||||||
|
int fd;
|
||||||
|
if ((fd = open(path, O_RDWR)) == -1)
|
||||||
|
DieSys(path);
|
||||||
|
if ((input.size = lseek(fd, 0, SEEK_END)) == -1)
|
||||||
|
DieSys(path);
|
||||||
|
input.path = path;
|
||||||
|
input.map = mmap(0, input.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||||
|
if (input.map == MAP_FAILED)
|
||||||
|
DieSys(path);
|
||||||
|
if (!IsElf64Binary(input.elf, input.size))
|
||||||
|
Die(path, "not an elf64 binary");
|
||||||
|
exefd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReplaceString(struct Param *param) {
|
||||||
|
size_t len;
|
||||||
|
char *x = (char *)memchr(param->roloc, 0, roend - param->roloc);
|
||||||
|
memmove(param->roloc, param->to.str, param->to.len);
|
||||||
|
if (UNLIKELY(x == NULL)) {
|
||||||
|
len = roend - param->roloc;
|
||||||
|
memmove(param->roloc + param->to.len, param->roloc + param->from.len,
|
||||||
|
len - param->from.len);
|
||||||
|
} else {
|
||||||
|
len = x - param->roloc;
|
||||||
|
memmove(param->roloc + param->to.len, param->roloc + param->from.len,
|
||||||
|
len + 1 - param->from.len);
|
||||||
|
}
|
||||||
|
param->roloc += param->to.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
#ifdef MODE_DBG
|
||||||
|
ShowCrashReports();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
prog = argv[0];
|
||||||
|
|
||||||
|
if (!prog)
|
||||||
|
prog = "renamestr";
|
||||||
|
|
||||||
|
GetOpts(argc, argv);
|
||||||
|
OpenInput(exepath);
|
||||||
|
rodata = FindElfSectionByName(
|
||||||
|
input.elf, input.size,
|
||||||
|
GetElfSectionNameStringTable(input.elf, input.size), ".rodata");
|
||||||
|
if (!rodata)
|
||||||
|
Die(exepath, "doesn't have .rodata");
|
||||||
|
|
||||||
|
rostart = GetElfSectionAddress(input.elf, input.size, rodata);
|
||||||
|
if (!rostart)
|
||||||
|
Die(prog, "could not get to start of .rodata");
|
||||||
|
roend = rostart + rodata->sh_size;
|
||||||
|
|
||||||
|
#ifdef MODE_DBG
|
||||||
|
kprintf("elf file to process: %s\n", exepath);
|
||||||
|
kprintf("file size is %ld\n", input.size);
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < params.n; ++i) {
|
||||||
|
struct Param *param = &(params.p[i]);
|
||||||
|
param->roloc = rostart;
|
||||||
|
param->count = 0;
|
||||||
|
#ifdef MODE_DBG
|
||||||
|
kprintf("need to replace '%s' with '%s'\n", param->from.str, param->to.str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NEXT_ROLOC(z) \
|
||||||
|
memmem((z)->roloc, roend - (z)->roloc, (z)->from.str, (z)->from.len)
|
||||||
|
for (int i = 0; i < params.n; ++i) {
|
||||||
|
struct Param *param = &(params.p[i]);
|
||||||
|
for (param->roloc = NEXT_ROLOC(param); param->roloc != NULL;
|
||||||
|
param->roloc = NEXT_ROLOC(param)) {
|
||||||
|
ReplaceString(param);
|
||||||
|
param->count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef NEXT_ROLOC
|
||||||
|
|
||||||
|
Pwrite(input.map, input.size, 0);
|
||||||
|
if (close(exefd)) {
|
||||||
|
Die(prog, "unable to close file after writing");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < params.n; ++i) {
|
||||||
|
struct Param *param = &(params.p[i]);
|
||||||
|
printf("'%s' -> '%s': %d replacements\n", param->from.str, param->to.str,
|
||||||
|
param->count);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
0
tool/cosmocc/bin/cosmoranlib
Normal file → Executable file
0
tool/cosmocc/bin/cosmoranlib
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue