mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-07 17:22:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ad50f5ae | ||
|
|
4b8874ceb9 | ||
|
|
cf19e3e46a | ||
|
|
1429a7b3ef | ||
|
|
7486a2cd51 | ||
|
|
fd0da9c0df | ||
|
|
6d36584ff2 | ||
|
|
f422edaf15 | ||
|
|
1473eafd1a | ||
|
|
cac86197cb | ||
|
|
006c44ff5d | ||
|
|
be3e109309 | ||
|
|
2bad436abf | ||
|
|
7ab4630cc9 | ||
|
|
5dab97b6d4 | ||
|
|
b38a442386 | ||
|
|
0708310041 | ||
|
|
cd27a53345 | ||
|
|
416e173448 | ||
|
|
d73523864a | ||
|
|
eb69a42863 | ||
|
|
651826b660 | ||
|
|
6dcdf91458 | ||
|
|
a6586cafb2 | ||
|
|
e496ee7a80 | ||
|
|
a4b6803556 | ||
|
|
9c72fef086 | ||
|
|
10d1c6da18 | ||
|
|
5ed84e04f8 | ||
|
|
25fa6acc4d | ||
|
|
9a46c5afc4 | ||
|
|
97ae5f7b1e | ||
|
|
1c7c277432 | ||
|
|
70ca8c4016 | ||
|
|
73507d5f4e | ||
|
|
d2f811eff3 | ||
|
|
2e5181666f | ||
|
|
5c0ce6b83e | ||
|
|
f6b3019796 | ||
|
|
dd04aeba1c | ||
|
|
57c0dcdc29 | ||
|
|
6d39c6f646 | ||
|
|
5a3c646307 | ||
|
|
0da47c51de | ||
|
|
120079b0a6 | ||
|
|
3da887c58f | ||
|
|
4922bc4890 | ||
|
|
ed161b240e | ||
|
|
531bfbd61f | ||
|
|
cd0b12ed1a | ||
|
|
0dc0758574 | ||
|
|
bcae817215 | ||
|
|
b850b14300 | ||
|
|
a277170c9a | ||
|
|
711bd095db | ||
|
|
d55b019284 | ||
|
|
f2af97711b | ||
|
|
b46ac13504 | ||
|
|
cee6871710 | ||
|
|
b74d8c1acd | ||
|
|
fc595a7111 | ||
|
|
bf7843833f | ||
|
|
251dcb07eb | ||
|
|
b407327972 | ||
|
|
aee50b1327 | ||
|
|
4de2cf34e6 | ||
|
|
52f1db7220 | ||
|
|
c995838e5c | ||
|
|
539bddce8c | ||
|
|
002df0f16c | ||
|
|
be16bcdcd3 | ||
|
|
cb9a0466f1 | ||
|
|
543c93f623 | ||
|
|
3f0bcdc3ef | ||
|
|
0d7c265392 | ||
|
|
022536cab6 | ||
|
|
2278327eba | ||
|
|
37d40e087f | ||
|
|
179e048bba | ||
|
|
c2590cf7a0 | ||
|
|
89d1e5b8f2 | ||
|
|
5e60e5ad10 | ||
|
|
6b06a8176d | ||
|
|
14d036b68d | ||
|
|
fae0c0286f | ||
|
|
d6ff4c754e | ||
|
|
f44d88707e | ||
|
|
fc96af058b | ||
|
|
bd6069deb5 | ||
|
|
e9735a7738 | ||
|
|
0ea10c8631 | ||
|
|
e522aa3a07 | ||
|
|
d7b88734cd | ||
|
|
da8f5009fd | ||
|
|
ef9776755e | ||
|
|
da336b3ea8 | ||
|
|
69bee64a59 | ||
|
|
f7ff77d865 | ||
|
|
648bf6555c | ||
|
|
60cb435cb4 | ||
|
|
64c284003d | ||
|
|
3d2d04b25e | ||
|
|
5af19b7eed | ||
|
|
8111462789 | ||
|
|
f52f65b2e3 | ||
|
|
997ce29ddc | ||
|
|
d38700687a | ||
|
|
0f89140882 | ||
|
|
0cee831da3 | ||
|
|
b41f91c658 | ||
|
|
e7329b7cba | ||
|
|
c19ac8729d | ||
|
|
9d2f993364 | ||
|
|
31dab8a75d | ||
|
|
7a06760e6f | ||
|
|
9209ea63a7 | ||
|
|
84b9b8ed87 | ||
|
|
e557058ac8 | ||
|
|
467a332e38 | ||
|
|
7ae556463a | ||
|
|
c424352a0a | ||
|
|
d5910e2673 | ||
|
|
9b7c8db846 | ||
|
|
4a6fd3d910 | ||
|
|
38df0a4186 | ||
|
|
1c0adb556d | ||
|
|
8aca94f951 | ||
|
|
38e3ab57a6 | ||
|
|
672ccda37c | ||
|
|
9849b4c7ba | ||
|
|
3421b9a580 | ||
|
|
29d695f4c9 | ||
|
|
7d6835c0dd | ||
|
|
05197afca2 | ||
|
|
bc353f454b | ||
|
|
7bc24888fe | ||
|
|
59ac141e49 | ||
|
|
60b68d7152 | ||
|
|
a5b483f2d4 | ||
|
|
d3efa47f81 | ||
|
|
7822917fc2 | ||
|
|
81ee11a16e | ||
|
|
f155205eb0 | ||
|
|
e46ef487a8 | ||
|
|
afc07b9339 | ||
|
|
edb8fef06c | ||
|
|
b75a4654cf | ||
|
|
fe3216e961 | ||
|
|
174d288e66 | ||
|
|
9f9b240f3d | ||
|
|
726f04e8aa | ||
|
|
556697cbd8 | ||
|
|
3ee3736a01 | ||
|
|
01bd7d1008 | ||
|
|
32321ab1e9 | ||
|
|
3b4fcd8575 | ||
|
|
6ba3b448f3 | ||
|
|
91e167caaf | ||
|
|
ccbae7799e | ||
|
|
af24c19db3 | ||
|
|
950a1b310b | ||
|
|
daca5499b9 | ||
|
|
2526a9b8c7 | ||
|
|
7549a5755e | ||
|
|
795d295590 | ||
|
|
3f3cb0650b | ||
|
|
acd8900071 | ||
|
|
6c60793f3a | ||
|
|
ad97775370 | ||
|
|
0b5f84dd20 | ||
|
|
27b5deefb1 | ||
|
|
ecb2ef7c39 | ||
|
|
304cf8869c | ||
|
|
3e0ddf70e9 | ||
|
|
5005f2e446 | ||
|
|
bc8532688b | ||
|
|
09811e739f | ||
|
|
24988f2351 | ||
|
|
b46f763ee7 | ||
|
|
87708c5d6e |
No files matched your search
@@ -21,8 +21,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: support ape bins
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
|
||||
- name: support ape bins 1
|
||||
run: sudo cp build/bootstrap/ape.elf /usr/bin/ape
|
||||
|
||||
- name: support ape bins 2
|
||||
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
|
||||
|
||||
- name: make matrix
|
||||
run: V=0 make -j2 MODE=${{ matrix.mode }}
|
||||
@@ -60,8 +60,8 @@
|
||||
# build/config.mk
|
||||
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
|
||||
MAKEFLAGS += -j --no-builtin-rules
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
@@ -92,6 +92,7 @@ o/$(MODE): \
|
||||
.UNVEIL = \
|
||||
libc/integral \
|
||||
libc/disclaimer.inc \
|
||||
rwc:/dev/shm \
|
||||
rx:build/bootstrap \
|
||||
rx:o/third_party/gcc \
|
||||
/proc/stat \
|
||||
@@ -121,11 +122,13 @@ include third_party/compiler_rt/compiler_rt.mk # │
|
||||
include libc/str/str.mk # │
|
||||
include third_party/xed/xed.mk # │
|
||||
include third_party/zlib/zlib.mk # │
|
||||
include third_party/double-conversion/dc.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/vga/vga.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include third_party/nsync/nsync.mk # │
|
||||
@@ -149,7 +152,6 @@ include dsp/mpeg/mpeg.mk # │
|
||||
include dsp/dsp.mk # │
|
||||
include third_party/zlib/gz/gz.mk # │
|
||||
include third_party/musl/musl.mk # │
|
||||
include third_party/getopt/getopt.mk # │
|
||||
include libc/libc.mk #─┘
|
||||
include libc/sock/sock.mk #─┐
|
||||
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||
@@ -160,6 +162,7 @@ include net/https/https.mk # │
|
||||
include third_party/regex/regex.mk #─┘
|
||||
include third_party/tidy/tidy.mk
|
||||
include third_party/third_party.mk
|
||||
include third_party/nsync/testing/testing.mk
|
||||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include tool/args/args.mk
|
||||
@@ -167,11 +170,14 @@ include test/tool/args/test.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
include net/finger/finger.mk
|
||||
include third_party/double-conversion/double-conversion.mk
|
||||
include third_party/double-conversion/test/test.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/tr/tr.mk
|
||||
include third_party/sed/sed.mk
|
||||
include third_party/awk/awk.mk
|
||||
include third_party/hiredis/hiredis.mk
|
||||
include third_party/make/make.mk
|
||||
include third_party/ctags/ctags.mk
|
||||
include third_party/finger/finger.mk
|
||||
include third_party/argon2/argon2.mk
|
||||
include third_party/smallz4/smallz4.mk
|
||||
@@ -188,6 +194,7 @@ include third_party/python/python.mk
|
||||
include tool/build/emucrt/emucrt.mk
|
||||
include tool/build/emubin/emubin.mk
|
||||
include tool/build/build.mk
|
||||
include tool/curl/curl.mk
|
||||
include examples/examples.mk
|
||||
include examples/pyapp/pyapp.mk
|
||||
include examples/pylife/pylife.mk
|
||||
@@ -202,6 +209,7 @@ include tool/hash/hash.mk
|
||||
include tool/net/net.mk
|
||||
include tool/viz/viz.mk
|
||||
include tool/tool.mk
|
||||
include net/turfwar/turfwar.mk
|
||||
include test/libc/tinymath/test.mk
|
||||
include test/libc/intrin/test.mk
|
||||
include test/libc/mem/test.mk
|
||||
@@ -273,14 +281,14 @@ o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS
|
||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: private .UNSANDBOXED = 1
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) o/$(MODE)/third_party/ctags/ctags.com
|
||||
@$(RM) $@
|
||||
@$(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||
@o/$(MODE)/third_party/ctags/ctags.com $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: private .UNSANDBOXED = 1
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS) o/$(MODE)/third_party/ctags/ctags.com
|
||||
@$(RM) $@
|
||||
@build/htags -L $< -o $@
|
||||
@build/htags o/$(MODE)/third_party/ctags/ctags.com -L $< -o $@
|
||||
|
||||
loc: private .UNSANDBOXED = 1
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
@@ -307,7 +315,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_THREAD \
|
||||
THIRD_PARTY_NSYNC_MALLOC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
LIBC_MEM \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
LIBC_RUNTIME \
|
||||
@@ -366,11 +374,9 @@ COSMOPOLITAN_HEADERS = \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
THIRD_PARTY_REGEX
|
||||
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
o/$(MODE)/cosmopolitan.a: \
|
||||
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
|
||||
|
||||
o/cosmopolitan.h: \
|
||||
@@ -400,6 +406,15 @@ $(SRCS): \
|
||||
libc/integral/lp64arg.inc \
|
||||
libc/integral/lp64.inc
|
||||
|
||||
.PHONY: toolchain
|
||||
toolchain: o/cosmopolitan.h \
|
||||
o/$(MODE)/ape/public/ape.lds \
|
||||
o/$(MODE)/libc/crt/crt.o \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o \
|
||||
o/$(MODE)/cosmopolitan.a
|
||||
|
||||
# UNSPECIFIED PREREQUISITES TUTORIAL
|
||||
#
|
||||
# A build rule must exist for all files that make needs to consider in
|
||||
@@ -424,9 +439,9 @@ $(SRCS):
|
||||
$(HDRS):
|
||||
$(INCS):
|
||||
.DEFAULT:
|
||||
@$(ECHO) >&2
|
||||
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||
@$(ECHO) >&2
|
||||
@$(ECHO)
|
||||
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@
|
||||
@$(ECHO)
|
||||
$(RM) o/$(MODE)/depend
|
||||
|
||||
-include o/$(MODE)/depend
|
||||
@@ -23,8 +23,8 @@ If you're doing your development work on Linux or BSD then you need just
|
||||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.1.zip
|
||||
unzip cosmopolitan-amalgamation-2.1.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.2.zip
|
||||
unzip cosmopolitan-amalgamation-2.2.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
||||
@@ -57,9 +57,13 @@ sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status'
|
||||
|
||||
Since we used the `ape-no-modify-self.o` bootloader (rather than
|
||||
`ape.o`) your executable will not modify itself when it's run. What
|
||||
it'll instead do, is extract a 4kb program to `${TMPDIR:-${HOME:-.}}`
|
||||
that maps your program into memory without needing to copy it. It's
|
||||
possible to install the APE loader systemwide as follows.
|
||||
it'll instead do, is extract a 4kb program (the [APE loader](https://justine.lol/apeloader/))
|
||||
to `${TMPDIR:-${HOME:-.}}` that maps your program into memory without
|
||||
needing to copy it. The APE loader must be in an executable location
|
||||
(e.g. not stored on a `noexec` mount) for it to run. See below for
|
||||
alternatives:
|
||||
|
||||
It's possible to install the APE loader systemwide as follows.
|
||||
|
||||
```sh
|
||||
# System-Wide APE Install
|
||||
@@ -246,20 +250,26 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
| AMD | K8 Venus | 2005 |
|
||||
| Intel | Core | 2006 |
|
||||
| Linux | 2.6.18 | 2007 |
|
||||
| Windows | 8 | 2012 |
|
||||
| Windows | 8 [1] | 2012 |
|
||||
| Mac OS X | 15.6 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| FreeBSD | 13 | 2020 |
|
||||
| NetBSD | 9.2 | 2021 |
|
||||
|
||||
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
|
||||
for a community supported version of Cosmopolitan that works on Windows
|
||||
Vista and Windows 7.
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Funding for this project is crowdsourced using
|
||||
[GitHub Sponsors](https://github.com/sponsors/jart) and
|
||||
[Patreon](https://www.patreon.com/jart). Your support is what makes this
|
||||
project possible. Thank you! We'd also like to give special thanks to
|
||||
the following individuals:
|
||||
the following groups and individuals:
|
||||
|
||||
- [Joe Drumgoole](https://github.com/jdrumgoole)
|
||||
- [Rob Figueiredo](https://github.com/robfig)
|
||||
- [Wasmer](https://wasmer.io/)
|
||||
|
||||
For publicly sponsoring our work at the highest tier.
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "ape/macros.internal.h"
|
||||
#include "ape/notice.inc"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/macho.internal.h"
|
||||
@@ -112,7 +113,33 @@ cstr: .endobj cstr,globl,hidden # ←for gdb readability
|
||||
//
|
||||
// @param dl is drive number
|
||||
// @noreturn
|
||||
ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
ape_mz:
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
// # in real mode
|
||||
// dec %bp
|
||||
// pop %dx
|
||||
// jno 0x4a
|
||||
// jo 0x4a
|
||||
//
|
||||
// # in legacy mode
|
||||
// push %ebp
|
||||
// pop %edx
|
||||
// jno 0x4a
|
||||
// jo 0x4a
|
||||
//
|
||||
// # 64-bit mode
|
||||
// rex.WRB
|
||||
// pop %r10
|
||||
// jno 0x4a
|
||||
// jo 0x4a
|
||||
#else
|
||||
// Avoid virus scanner reputation damage when targeting System Five.
|
||||
.asciz "jartsr='\n" # Justine Alexandra Roberts Tunney
|
||||
// push $0x61
|
||||
// jb 0x78
|
||||
// jae 0x78
|
||||
#endif
|
||||
.short 0x1000 # MZ: lowers upper bound load / 16
|
||||
.short 0xf800 # MZ: roll greed on bss
|
||||
.short 0 # MZ: lower bound on stack segment
|
||||
@@ -125,11 +152,15 @@ ape_mz: .asciz "MZqFpD='\n" # Mark 'Zibo' Joseph Zbikowski
|
||||
.org 0x24 # MZ: bytes reserved for you
|
||||
.ascii "JT" # MZ: OEM identifier
|
||||
.short 0 # MZ: OEM information
|
||||
.ascii "' <<'@'\n"
|
||||
.org 0x40-4 # MZ: bytes reserved for you
|
||||
#if SupportsWindows() || SupportsMetal()
|
||||
.long RVA(ape_pe) # PE: the new technology
|
||||
#else
|
||||
.long 0
|
||||
.org 0x78
|
||||
pop %rax
|
||||
jmp _start
|
||||
#endif
|
||||
.endfn ape_mz,globl,hidden
|
||||
|
||||
@@ -250,8 +281,10 @@ pc: cld
|
||||
xor %cx,%cx # current cylinder
|
||||
xor %dh,%dh # current head
|
||||
mov $v_ape_realsectors,%di # total sectors
|
||||
sub $v_ape_realslacksectors,%di
|
||||
3: call pcread
|
||||
mov %es,%si # addr += 512
|
||||
add $512>>4,%si
|
||||
mov %si,%es
|
||||
dec %di
|
||||
jnz 3b
|
||||
6: ljmp $0,$REAL(realmodeloader)
|
||||
@@ -340,6 +373,7 @@ dsknfo: push %bx
|
||||
pop %ds
|
||||
xchg %bx,%ax
|
||||
stosw #→ pc_drive_type, pc_drive_last_sector
|
||||
scasb
|
||||
xchg %cx,%ax
|
||||
stosw #→ pc_drive_last_cylinder
|
||||
xchg %dx,%ax
|
||||
@@ -378,9 +412,6 @@ pcread: push %ax
|
||||
pop %cx
|
||||
pop %ax
|
||||
jc 9f
|
||||
mov %es,%si # addr += 512
|
||||
add $512>>4,%si
|
||||
mov %si,%es
|
||||
inc %al # ++sector
|
||||
cmp mm+"struct mman::pc_drive_last_sector",%al
|
||||
jbe 2f
|
||||
@@ -549,7 +580,10 @@ ape_disk:
|
||||
the bourne executable & linkable format */
|
||||
|
||||
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
|
||||
apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
apesh: .ascii "\n@\n#'\"\n" # sixth edition shebang
|
||||
.ascii "m=\"$(uname -m)\"\n"
|
||||
|
||||
.ascii "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]; then\n"
|
||||
// Until all operating systems can be updated to support APE,
|
||||
// we have a beautiful, yet imperfect workaround, which is to
|
||||
// modify the binary to follow the local system's convention.
|
||||
@@ -651,17 +685,332 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
||||
.ascii "o=\"$t\"\n"
|
||||
.ascii "exec \"$o\" \"$@\"\n"
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "R=$?\n"
|
||||
.ascii "if [ \"$(uname -m)\" != x86_64 ]; then\n"
|
||||
.ascii "Q=\"$(command -v qemu-x86_64)\" &&\n"
|
||||
.ascii "exec \"$Q\" \"$o\" \"$@\"\n"
|
||||
#ifndef APE_NO_MODIFY_SELF
|
||||
.ascii "else\n" # means argv[0] was wrong
|
||||
.ascii " exec \"$o\" \"$@\"\n" # so do a path resolution
|
||||
#endif /* APE_NO_MODIFY_SELF */
|
||||
.ascii "exit $?\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exit $R\n"
|
||||
|
||||
.ascii "PHDRS='' <<'@'\n"
|
||||
.endobj apesh
|
||||
// elf program headers get inserted here
|
||||
// because they need to be in the first 4096 bytes
|
||||
.section .emush,"a",@progbits
|
||||
emush: .ascii "\n@\n#'\"\n"
|
||||
.ascii "s=\"$(uname -s)\"\n"
|
||||
|
||||
// our script is running on a non-x86_64 architecture
|
||||
// 1. `dd` out the appropriate blink vm blob
|
||||
// 2. gunzip the blink virtual machine executable
|
||||
// 3. relaunch this program inside the blink vm
|
||||
.ascii "o=\"$(command -v \"$0\")\"\n"
|
||||
.ascii "e=\"${TMPDIR:-${HOME:-.}}/.ape-blink-1.1\"\n"
|
||||
|
||||
// Blink for Apple Silicon, e.g. M1 Macbook
|
||||
.ascii "if [ \"$s\" = Darwin ] && [ \"$m\" = arm64 ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-darwin-arm64 to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_darwin_arm64_b9
|
||||
.byte blink_darwin_arm64_b8
|
||||
.byte blink_darwin_arm64_b7
|
||||
.byte blink_darwin_arm64_b6
|
||||
.byte blink_darwin_arm64_b5
|
||||
.byte blink_darwin_arm64_b4
|
||||
.byte blink_darwin_arm64_b3
|
||||
.byte blink_darwin_arm64_b2
|
||||
.byte blink_darwin_arm64_b1
|
||||
.byte blink_darwin_arm64_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_darwin_arm64_size_b9
|
||||
.byte blink_darwin_arm64_size_b8
|
||||
.byte blink_darwin_arm64_size_b7
|
||||
.byte blink_darwin_arm64_size_b6
|
||||
.byte blink_darwin_arm64_size_b5
|
||||
.byte blink_darwin_arm64_size_b4
|
||||
.byte blink_darwin_arm64_size_b3
|
||||
.byte blink_darwin_arm64_size_b2
|
||||
.byte blink_darwin_arm64_size_b1
|
||||
.byte blink_darwin_arm64_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Aarch64 Linux, e.g. Raspberry Pi
|
||||
.ascii "if [ \"$s\" = Linux ]; then\n"
|
||||
.ascii "if [ \"$m\" = aarch64 ] || [ \"$m\" = arm64 ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-aarch64 to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_aarch64_b9
|
||||
.byte blink_aarch64_b8
|
||||
.byte blink_aarch64_b7
|
||||
.byte blink_aarch64_b6
|
||||
.byte blink_aarch64_b5
|
||||
.byte blink_aarch64_b4
|
||||
.byte blink_aarch64_b3
|
||||
.byte blink_aarch64_b2
|
||||
.byte blink_aarch64_b1
|
||||
.byte blink_aarch64_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_aarch64_size_b9
|
||||
.byte blink_aarch64_size_b8
|
||||
.byte blink_aarch64_size_b7
|
||||
.byte blink_aarch64_size_b6
|
||||
.byte blink_aarch64_size_b5
|
||||
.byte blink_aarch64_size_b4
|
||||
.byte blink_aarch64_size_b3
|
||||
.byte blink_aarch64_size_b2
|
||||
.byte blink_aarch64_size_b1
|
||||
.byte blink_aarch64_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux Generic ARM
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"${m#arm}\" != \"$m\" ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-arm to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_arm_b9
|
||||
.byte blink_arm_b8
|
||||
.byte blink_arm_b7
|
||||
.byte blink_arm_b6
|
||||
.byte blink_arm_b5
|
||||
.byte blink_arm_b4
|
||||
.byte blink_arm_b3
|
||||
.byte blink_arm_b2
|
||||
.byte blink_arm_b1
|
||||
.byte blink_arm_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_arm_size_b9
|
||||
.byte blink_arm_size_b8
|
||||
.byte blink_arm_size_b7
|
||||
.byte blink_arm_size_b6
|
||||
.byte blink_arm_size_b5
|
||||
.byte blink_arm_size_b4
|
||||
.byte blink_arm_size_b3
|
||||
.byte blink_arm_size_b2
|
||||
.byte blink_arm_size_b1
|
||||
.byte blink_arm_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on Legacy x86
|
||||
.ascii "if [ \"$s\" = Linux ]; then\n"
|
||||
.ascii "if [ \"$m\" = i686 ] || [ \"$m\" = i386 ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-i486 to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_i486_b9
|
||||
.byte blink_i486_b8
|
||||
.byte blink_i486_b7
|
||||
.byte blink_i486_b6
|
||||
.byte blink_i486_b5
|
||||
.byte blink_i486_b4
|
||||
.byte blink_i486_b3
|
||||
.byte blink_i486_b2
|
||||
.byte blink_i486_b1
|
||||
.byte blink_i486_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_i486_size_b9
|
||||
.byte blink_i486_size_b8
|
||||
.byte blink_i486_size_b7
|
||||
.byte blink_i486_size_b6
|
||||
.byte blink_i486_size_b5
|
||||
.byte blink_i486_size_b4
|
||||
.byte blink_i486_size_b3
|
||||
.byte blink_i486_size_b2
|
||||
.byte blink_i486_size_b1
|
||||
.byte blink_i486_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on RISC-V
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"$m\" = riscv64 ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-riscv64 to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_riscv64_b9
|
||||
.byte blink_riscv64_b8
|
||||
.byte blink_riscv64_b7
|
||||
.byte blink_riscv64_b6
|
||||
.byte blink_riscv64_b5
|
||||
.byte blink_riscv64_b4
|
||||
.byte blink_riscv64_b3
|
||||
.byte blink_riscv64_b2
|
||||
.byte blink_riscv64_b1
|
||||
.byte blink_riscv64_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_riscv64_size_b9
|
||||
.byte blink_riscv64_size_b8
|
||||
.byte blink_riscv64_size_b7
|
||||
.byte blink_riscv64_size_b6
|
||||
.byte blink_riscv64_size_b5
|
||||
.byte blink_riscv64_size_b4
|
||||
.byte blink_riscv64_size_b3
|
||||
.byte blink_riscv64_size_b2
|
||||
.byte blink_riscv64_size_b1
|
||||
.byte blink_riscv64_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on MIPS Little Endian, e.g. Ubiquiti EdgerouterX
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"$m\" = mips ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-mipsel to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_mipsel_b9
|
||||
.byte blink_mipsel_b8
|
||||
.byte blink_mipsel_b7
|
||||
.byte blink_mipsel_b6
|
||||
.byte blink_mipsel_b5
|
||||
.byte blink_mipsel_b4
|
||||
.byte blink_mipsel_b3
|
||||
.byte blink_mipsel_b2
|
||||
.byte blink_mipsel_b1
|
||||
.byte blink_mipsel_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_mipsel_size_b9
|
||||
.byte blink_mipsel_size_b8
|
||||
.byte blink_mipsel_size_b7
|
||||
.byte blink_mipsel_size_b6
|
||||
.byte blink_mipsel_size_b5
|
||||
.byte blink_mipsel_size_b4
|
||||
.byte blink_mipsel_size_b3
|
||||
.byte blink_mipsel_size_b2
|
||||
.byte blink_mipsel_size_b1
|
||||
.byte blink_mipsel_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on PowerPC 64 Little Endian, e.g. Raptor
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"$m\" = ppc64le ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-powerpc64le to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_powerpc64le_b9
|
||||
.byte blink_powerpc64le_b8
|
||||
.byte blink_powerpc64le_b7
|
||||
.byte blink_powerpc64le_b6
|
||||
.byte blink_powerpc64le_b5
|
||||
.byte blink_powerpc64le_b4
|
||||
.byte blink_powerpc64le_b3
|
||||
.byte blink_powerpc64le_b2
|
||||
.byte blink_powerpc64le_b1
|
||||
.byte blink_powerpc64le_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_powerpc64le_size_b9
|
||||
.byte blink_powerpc64le_size_b8
|
||||
.byte blink_powerpc64le_size_b7
|
||||
.byte blink_powerpc64le_size_b6
|
||||
.byte blink_powerpc64le_size_b5
|
||||
.byte blink_powerpc64le_size_b4
|
||||
.byte blink_powerpc64le_size_b3
|
||||
.byte blink_powerpc64le_size_b2
|
||||
.byte blink_powerpc64le_size_b1
|
||||
.byte blink_powerpc64le_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on PowerPC, e.g. Old Macintosh
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"$m\" = ppc ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-powerpc to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_powerpc_b9
|
||||
.byte blink_powerpc_b8
|
||||
.byte blink_powerpc_b7
|
||||
.byte blink_powerpc_b6
|
||||
.byte blink_powerpc_b5
|
||||
.byte blink_powerpc_b4
|
||||
.byte blink_powerpc_b3
|
||||
.byte blink_powerpc_b2
|
||||
.byte blink_powerpc_b1
|
||||
.byte blink_powerpc_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_powerpc_size_b9
|
||||
.byte blink_powerpc_size_b8
|
||||
.byte blink_powerpc_size_b7
|
||||
.byte blink_powerpc_size_b6
|
||||
.byte blink_powerpc_size_b5
|
||||
.byte blink_powerpc_size_b4
|
||||
.byte blink_powerpc_size_b3
|
||||
.byte blink_powerpc_size_b2
|
||||
.byte blink_powerpc_size_b1
|
||||
.byte blink_powerpc_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
// Blink for Linux on IBM Mainframes
|
||||
.ascii "if [ \"$s\" = Linux ] && [ \"$m\" = s390x ]; then\n"
|
||||
.ascii "if ! [ -x \"$e\" ]; then\n"
|
||||
.ascii "echo \"extracting blink-s390x to ${e}\" >&2\n"
|
||||
.ascii "dd if=\"$o\" bs=1 skip=$(("
|
||||
.byte blink_s390x_b9
|
||||
.byte blink_s390x_b8
|
||||
.byte blink_s390x_b7
|
||||
.byte blink_s390x_b6
|
||||
.byte blink_s390x_b5
|
||||
.byte blink_s390x_b4
|
||||
.byte blink_s390x_b3
|
||||
.byte blink_s390x_b2
|
||||
.byte blink_s390x_b1
|
||||
.byte blink_s390x_b0
|
||||
.ascii ")) count=$(("
|
||||
.byte blink_s390x_size_b9
|
||||
.byte blink_s390x_size_b8
|
||||
.byte blink_s390x_size_b7
|
||||
.byte blink_s390x_size_b6
|
||||
.byte blink_s390x_size_b5
|
||||
.byte blink_s390x_size_b4
|
||||
.byte blink_s390x_size_b3
|
||||
.byte blink_s390x_size_b2
|
||||
.byte blink_s390x_size_b1
|
||||
.byte blink_s390x_size_b0
|
||||
.ascii ")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
|
||||
.ascii "mv -f \"$e.$$\" \"$e\"\n"
|
||||
.ascii "chmod +x \"$e\"\n"
|
||||
.ascii "fi\n"
|
||||
.ascii "exec \"$e\" \"$o\" \"$@\"\n"
|
||||
.ascii "fi\n"
|
||||
|
||||
.ascii "echo unsupported architecture >&2\n"
|
||||
.rept 16
|
||||
.ascii "exit 127\n"
|
||||
.endr
|
||||
|
||||
.ascii "exit 1\n"
|
||||
.endobj emush
|
||||
#ifdef APE_LOADER
|
||||
.section .ape.loader,"a",@progbits
|
||||
.align 64
|
||||
@@ -874,7 +1223,7 @@ ape_macho:
|
||||
.long (520f-510f)/4 # count
|
||||
510: .quad 0 # rax
|
||||
.quad IMAGE_BASE_VIRTUAL # rbx
|
||||
.quad XNU # rcx
|
||||
.quad _HOSTXNU # rcx
|
||||
.quad 0 # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
@@ -1081,6 +1430,42 @@ ape_idata_idt:
|
||||
ape_idata_idtend:
|
||||
.previous
|
||||
|
||||
.section .piro.data.sort.metal_gdt,"aw",@progbits
|
||||
.align 8
|
||||
_gdt:
|
||||
// ┌G:granularity (1 → limit *= 0x1000)
|
||||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||||
// ││┌L:long mode
|
||||
// │││┌AVL:this bit is thine (1<<52)
|
||||
// ││││ ┌P:present
|
||||
// ││││ │┌DPL:privilege
|
||||
// ││││ ││ ┌─────────data/code(1)
|
||||
// ││││ ││ │┌────data(0)──────code(1)
|
||||
// ││││ ││ ││┌───conforming───expand-down
|
||||
// ││││ ││ │││┌──writeable────readable
|
||||
// ││││ ││ ││││┌─accessed─────accessed
|
||||
// ││││ ││ │││││
|
||||
// ││││ ┌──││─│││││───────────────────────────────┐
|
||||
// ┌───││││─│──││─│││││───────────┐ │
|
||||
// ┌───┴──┐││││┌┴─┐│├┐│││││┌──────────┴───────────┐┌──────┴───────┐
|
||||
// │ ││││││ ││││││││││ base address││ segment limit│
|
||||
// │ ││││││ ││││││││││ 32 bits││ 20 bits│
|
||||
// │ ││││││ ││││││││││ ││ │
|
||||
// 6666555555555544444444443333333333222222222211111111110000000000
|
||||
// 3210987654321098765432109876543210987654321098765432109876543210
|
||||
// │ ││││││ ││││││││││ ││ │
|
||||
.quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0
|
||||
.quad 0b0000000000001111100110100000000000000000000000001111111111111111 # 8
|
||||
.quad 0b0000000000001111100100100000000000000000000000001111111111111111 #16
|
||||
.quad 0b0000000011001111100110100000000000000000000000001111111111111111 #24
|
||||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||||
.tssdescstub _tss #56,64
|
||||
_gdt_end:
|
||||
.endobj _gdt,global,hidden
|
||||
.previous
|
||||
|
||||
.section .piro.data.sort.iat.1,"aw",@progbits
|
||||
.type ape_idata_iatend,@object
|
||||
.type ape_idata_iat,@object
|
||||
@@ -1137,42 +1522,22 @@ sconf: .short 1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
|
||||
.endobj sconf,global,hidden
|
||||
|
||||
// Global Descriptor Table
|
||||
//
|
||||
// @note address portion only concern legacy modes
|
||||
.align 8
|
||||
gdt: .short 2f-1f # table byte length
|
||||
.long REAL(1f),0 # table address
|
||||
.zero 2
|
||||
1:
|
||||
// ┌G:granularity (1 → limit *= 0x1000)
|
||||
// │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
|
||||
// ││┌L:long mode
|
||||
// │││┌AVL:this bit is thine (1<<52)
|
||||
// ││││ ┌P:present
|
||||
// ││││ │┌DPL:privilege
|
||||
// ││││ ││ ┌─────────data/code(1)
|
||||
// ││││ ││ │┌────data(0)──────code(1)
|
||||
// ││││ ││ ││┌───conforming───expand-down
|
||||
// ││││ ││ │││┌──writeable────readable
|
||||
// ││││ ││ ││││┌─accessed─────accessed
|
||||
// ││││ ││ │││││
|
||||
// ││││ ┌──││─│││││───────────────────────────────┐
|
||||
// ┌───││││─│──││─│││││───────────┐ │
|
||||
// ┌───┴──┐││││┌┴─┐│├┐│││││┌──────────┴───────────┐┌──────┴───────┐
|
||||
// │ ││││││ ││││││││││ base address││ segment limit│
|
||||
// │ ││││││ ││││││││││ 32 bits││ 20 bits│
|
||||
// │ ││││││ ││││││││││ ││ │
|
||||
// 6666555555555544444444443333333333222222222211111111110000000000
|
||||
// 3210987654321098765432109876543210987654321098765432109876543210
|
||||
// │ ││││││ ││││││││││ ││ │
|
||||
.quad 0b0000000000000000000000000000000000000000000000000000000000000000 # 0
|
||||
.quad 0b0000000000001111100110100000000000000000000000001111111111111111 # 8
|
||||
.quad 0b0000000000001111100100100000000000000000000000001111111111111111 #16
|
||||
.quad 0b0000000011001111100110100000000000000000000000001111111111111111 #24
|
||||
_gdtrlo:
|
||||
.short 2f-_gdtlo-1 # table byte length
|
||||
.long REAL(_gdtlo) # table address (base memory space)
|
||||
.endobj _gdtrlo,global,hidden
|
||||
_gdtr:
|
||||
.short _gdt_end-_gdt-1 # table byte length
|
||||
.quad _gdt # table address (final virtual space)
|
||||
.endobj _gdtr,global,hidden
|
||||
.align 8
|
||||
// Partial GDT with descriptors for switching to unreal mode or long mode.
|
||||
_gdtlo = .-GDT_LEGACY_DATA
|
||||
.quad 0b0000000011001111100100100000000000000000000000001111111111111111 #32
|
||||
.quad 0b0000000010101111100110110000000000000000000000001111111111111111 #40
|
||||
.quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48
|
||||
2: .endobj gdt,global,hidden
|
||||
2:
|
||||
|
||||
/*─────────────────────────────────────────────────────────────────────────────╗
|
||||
│ αcτµαlly pδrταblε εxεcµταblε § real mode │
|
||||
@@ -1180,6 +1545,7 @@ gdt: .short 2f-1f # table byte length
|
||||
the default mode of operation on modern cpus */
|
||||
|
||||
realmodeloader:
|
||||
call lhinit
|
||||
call rlinit
|
||||
call sinit4
|
||||
.optfn _start16
|
||||
@@ -1187,6 +1553,25 @@ realmodeloader:
|
||||
call longmodeloader
|
||||
.endfn realmodeloader
|
||||
|
||||
// Prepares to later load parts of the program that are not loaded yet.
|
||||
//
|
||||
// @param al next sector number
|
||||
// @param cx next cylinder number
|
||||
// @param dh next head number
|
||||
// @param dl drive number
|
||||
// @clob ax, cx, es, di
|
||||
lhinit: cmp $0x40,%dl
|
||||
je 9f
|
||||
pushpop 0,%es
|
||||
mov $mm+"struct mman::pc_drive_next_sector",%di
|
||||
cld
|
||||
stosb #→ pc_drive_next_sector
|
||||
xchg %ax,%cx
|
||||
stosw #→ pc_drive_next_cylinder
|
||||
mov %dh,%al
|
||||
stosb #→ pc_drive_next_head
|
||||
9: ret
|
||||
|
||||
.section .sort.text.real.init.1,"ax",@progbits
|
||||
.type rlinit,@function
|
||||
rlinit: .previous/*
|
||||
@@ -1247,6 +1632,8 @@ longmodeloader:
|
||||
call lcheck
|
||||
call a20
|
||||
call e820
|
||||
call cpyhi
|
||||
call loadhi
|
||||
call pinit
|
||||
call golong
|
||||
.endfn longmodeloader
|
||||
@@ -1278,8 +1665,8 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
jl 10f
|
||||
mov %edi,%eax
|
||||
cpuid
|
||||
mov $1<<29,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx
|
||||
mov $1<<29|1<<20,%edi # need nexgen32e long mode support
|
||||
and %edi,%edx # & nx support
|
||||
cmp %edi,%edx
|
||||
jne 10f
|
||||
xor %ax,%ax
|
||||
@@ -1389,10 +1776,88 @@ a20: cli
|
||||
5: ret
|
||||
.endfn a20
|
||||
|
||||
// Copies program pages loaded into base memory, to extended memory.
|
||||
//
|
||||
// @clob esi, edi
|
||||
cpyhi: push %es
|
||||
movpp %ds,%es
|
||||
call unreal
|
||||
mov $IMAGE_BASE_REAL,%esi
|
||||
mov $IMAGE_BASE_PHYSICAL,%edi
|
||||
mov $v_ape_realdwords,%ecx
|
||||
cld
|
||||
rep movsl %ds:(%esi),%es:(%edi)
|
||||
sti
|
||||
pop %es
|
||||
ret
|
||||
.endfn cpyhi
|
||||
|
||||
// Disables interrupts and switches to "unreal mode".
|
||||
//
|
||||
// @return ds, es have same base addresses as before but can access
|
||||
// 4 GiB of memory
|
||||
// @clob eax
|
||||
unreal: push %ds
|
||||
push %es
|
||||
cli
|
||||
lgdt REAL(_gdtrlo)
|
||||
mov %cr0,%eax
|
||||
or $CR0_PE,%al
|
||||
mov %eax,%cr0
|
||||
jmp 0f
|
||||
0: pushpop GDT_LEGACY_DATA,%ds
|
||||
movpp %ds,%es
|
||||
and $~CR0_PE,%al
|
||||
mov %eax,%cr0
|
||||
jmp 1f
|
||||
1: pop %es
|
||||
pop %ds
|
||||
ret
|
||||
|
||||
// Reads any remaining program pages into memory which have not yet
|
||||
// been read by the boot sector.
|
||||
//
|
||||
// @clob eax, ecx, dx, esi, edi, bp
|
||||
loadhi: mov $v_ape_highsectors,%bp
|
||||
test %bp,%bp
|
||||
jz 9f
|
||||
mov $mm+"struct mman::pc_drive",%si
|
||||
cld
|
||||
lodsb #← pc_drive
|
||||
xchg %ax,%dx
|
||||
lodsw
|
||||
lodsb #← pc_drive_next_sector
|
||||
test %al,%al
|
||||
jz 9f
|
||||
xchg %ax,%cx
|
||||
lodsw #← pc_drive_next_cylinder
|
||||
xchg %ax,%cx
|
||||
mov (%si),%dh #← pc_drive_next_head
|
||||
push %es
|
||||
#define SEG 0x79000
|
||||
mov $IMAGE_BASE_PHYSICAL+v_ape_realbytes-SEG,%edi
|
||||
push $SEG>>4
|
||||
pop %es
|
||||
0: call pcread
|
||||
push %ax
|
||||
call unreal
|
||||
pop %ax
|
||||
push %cx
|
||||
xor %esi,%esi
|
||||
xor %ecx,%ecx
|
||||
mov $512/4,%cl
|
||||
cld
|
||||
rep movsl %es:(%esi),%es:(%edi)
|
||||
sti
|
||||
pop %cx
|
||||
dec %bp
|
||||
jnz 0b
|
||||
pop %es
|
||||
9: ret
|
||||
|
||||
// Initializes long mode paging.
|
||||
pinit: push %ds
|
||||
push %es
|
||||
#define SEG 0x79000
|
||||
mov $SEG>>4,%ax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
@@ -1408,7 +1873,7 @@ pinit: push %ds
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7b000-SEG # PD←PDT (+)
|
||||
movl $0x79000+PAGE_V+PAGE_RW,0x7a000-SEG # PD←PDT (-)
|
||||
mov $512,%cx # PD±2MB
|
||||
mov $PAGE_V+PAGE_RW,%eax
|
||||
mov $PAGE_V+PAGE_RSRV+PAGE_RW,%eax
|
||||
xor %di,%di
|
||||
0: stosl
|
||||
add $0x1000,%eax
|
||||
@@ -1431,9 +1896,9 @@ golong: cli
|
||||
mov %eax,%cr4
|
||||
movl $EFER,%ecx
|
||||
rdmsr
|
||||
or $EFER_LME|EFER_SCE,%eax
|
||||
or $EFER_LME|EFER_SCE|EFER_NXE,%eax
|
||||
wrmsr
|
||||
lgdt REAL(gdt)
|
||||
lgdt REAL(_gdtrlo)
|
||||
mov %cr0,%eax
|
||||
or $CR0_PE|CR0_PG|CR0_MP,%eax
|
||||
and $~CR0_EM,%eax
|
||||
@@ -1443,7 +1908,9 @@ golong: cli
|
||||
|
||||
// Long mode is long.
|
||||
.code64
|
||||
long: xor %eax,%eax
|
||||
long: movabs $BANE+PHYSICAL(0f),%rax
|
||||
jmp *%rax
|
||||
0: xor %eax,%eax
|
||||
mov $GDT_LONG_DATA,%al
|
||||
mov %eax,%ds
|
||||
mov %eax,%ss
|
||||
@@ -1457,13 +1924,15 @@ long: xor %eax,%eax
|
||||
xor %r15d,%r15d
|
||||
xor %ebx,%ebx
|
||||
xor %ebp,%ebp
|
||||
push %rbp
|
||||
mov $mm,%rdi
|
||||
mov %cr3,%rsi
|
||||
mov $IMAGE_BASE_REAL,%edx
|
||||
mov $IMAGE_BASE_PHYSICAL,%edx
|
||||
lea v_ape_allbytes(%rdx),%ecx
|
||||
call __map_phdrs
|
||||
push $0x037f
|
||||
fldcw (%rsp)
|
||||
lgdt _gdtr # reload GDTR for
|
||||
# virtual memory space
|
||||
movabs $kernel,%rax
|
||||
jmp *%rax
|
||||
.endfn long
|
||||
@@ -1544,21 +2013,25 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||
#endif
|
||||
push $METAL # sets __hostos in crt.S
|
||||
movabs $BANE+mm,%rdi
|
||||
mov $0x79000,%esi
|
||||
mov $0x7f000,%edx
|
||||
call __reclaim_boot_pages
|
||||
push $_HOSTMETAL # sets __hostos in crt.S
|
||||
pop %rcx
|
||||
push $0
|
||||
pushq .Lenv0(%rip) # envp[0][0]
|
||||
mov %rsp,%rbp
|
||||
mov .Lenv0(%rip),%rax
|
||||
mov %rax,(%rbp) # envp[0][0]
|
||||
push $0 # argv[0][0]
|
||||
pushq .Largv0+8(%rip) # argv[0][8]
|
||||
pushq .Largv0(%rip) # argv[0][0]
|
||||
mov %rsp,%rax
|
||||
push $0 # auxv[1][1]
|
||||
push $0 # auxv[1][0]
|
||||
push %rbp # auxv[0][1]
|
||||
push %rax # auxv[0][1]
|
||||
push $31 # auxv[0][0] AT_EXECFN
|
||||
push $0 # envp[1]
|
||||
push $.Lenv0 # envp[0]
|
||||
push %rbp # envp[0]
|
||||
push $0 # argv[1]
|
||||
push %rbp # argv[0]
|
||||
push %rax # argv[0]
|
||||
push $1 # argc
|
||||
xor %ebp,%ebp
|
||||
xor %eax,%eax
|
||||
@@ -1574,6 +2047,9 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
|
||||
.rodata
|
||||
.Lenv0: .asciz "METAL=1"
|
||||
.Largv0:
|
||||
.asciz APE_COM_NAME
|
||||
.org .Largv0+16
|
||||
.previous
|
||||
|
||||
#endif /* SupportsMetal() */
|
||||
@@ -1586,7 +2062,7 @@ kernel: movabs $ape_stack_vaddr,%rsp
|
||||
.ldsvar _end
|
||||
.ldsvar _etext
|
||||
.ldsvar v_ape_realsectors
|
||||
.ldsvar v_ape_realslacksectors
|
||||
.ldsvar v_ape_realbytes
|
||||
.ldsvar v_ape_highsectors
|
||||
.ldsvar ape_idata_ro
|
||||
.ldsvar ape_pad_rodata
|
||||
@@ -1680,5 +2156,77 @@ __bss_start:
|
||||
__bss_end:
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_aarch64_size
|
||||
blink_aarch64:
|
||||
.incbin "ape/blink-aarch64.gz"
|
||||
.endobj blink_aarch64,globl
|
||||
blink_aarch64_size = . - blink_aarch64
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_darwin_arm64_size
|
||||
blink_darwin_arm64:
|
||||
.incbin "ape/blink-darwin-arm64.gz"
|
||||
.endobj blink_darwin_arm64,globl
|
||||
blink_darwin_arm64_size = . - blink_darwin_arm64
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_arm_size
|
||||
blink_arm:
|
||||
.incbin "ape/blink-arm.gz"
|
||||
.endobj blink_arm,globl
|
||||
blink_arm_size = . - blink_arm
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_i486_size
|
||||
blink_i486:
|
||||
.incbin "ape/blink-i486.gz"
|
||||
.endobj blink_i486,globl
|
||||
blink_i486_size = . - blink_i486
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_riscv64_size
|
||||
blink_riscv64:
|
||||
.incbin "ape/blink-riscv64.gz"
|
||||
.endobj blink_riscv64,globl
|
||||
blink_riscv64_size = . - blink_riscv64
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_mipsel_size
|
||||
blink_mipsel:
|
||||
.incbin "ape/blink-mipsel.gz"
|
||||
.endobj blink_mipsel,globl
|
||||
blink_mipsel_size = . - blink_mipsel
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_powerpc64le_size
|
||||
blink_powerpc64le:
|
||||
.incbin "ape/blink-powerpc64le.gz"
|
||||
.endobj blink_powerpc64le,globl
|
||||
blink_powerpc64le_size = . - blink_powerpc64le
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_powerpc_size
|
||||
blink_powerpc:
|
||||
.incbin "ape/blink-powerpc.gz"
|
||||
.endobj blink_powerpc,globl
|
||||
blink_powerpc_size = . - blink_powerpc
|
||||
.previous
|
||||
|
||||
.section .blink,"a",@progbits
|
||||
.globl blink_s390x_size
|
||||
blink_s390x:
|
||||
.incbin "ape/blink-s390x.gz"
|
||||
.endobj blink_s390x,globl
|
||||
blink_s390x_size = . - blink_s390x
|
||||
.previous
|
||||
|
||||
.end
|
||||
|
||||
+238
-36
@@ -216,6 +216,8 @@ SECTIONS {
|
||||
KEEP(*(.elf.phdrs))
|
||||
HIDDEN(ape_phdrs_end = .);
|
||||
|
||||
KEEP(*(.emush))
|
||||
|
||||
/* OpenBSD */
|
||||
. = ALIGN(__SIZEOF_POINTER__);
|
||||
HIDDEN(ape_note = .);
|
||||
@@ -273,6 +275,7 @@ SECTIONS {
|
||||
KEEP(*(.textwindowsprologue))
|
||||
*(.text.windows)
|
||||
KEEP(*(.textwindowsepilogue))
|
||||
KEEP(*(.blink))
|
||||
*(SORT_BY_ALIGNMENT(.text.modernity))
|
||||
*(SORT_BY_ALIGNMENT(.text.modernity.*))
|
||||
*(SORT_BY_ALIGNMENT(.text.hot))
|
||||
@@ -349,9 +352,30 @@ SECTIONS {
|
||||
HIDDEN(_etext = .);
|
||||
PROVIDE_HIDDEN(etext = .);
|
||||
/*END: Read Only Data (only needed for initialization) */
|
||||
/*END: Read Only Data */
|
||||
} :Rom
|
||||
|
||||
/* initialization image for thread-local storage, this is copied */
|
||||
/* out to actual TLS areas at runtime, so just make it read-only */
|
||||
.tdata . : {
|
||||
_tdata_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tdata))
|
||||
*(SORT_BY_ALIGNMENT(.tdata.*))
|
||||
_tdata_end = .;
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Tls :Rom
|
||||
/*END: Read Only Data */
|
||||
|
||||
/* this only tells the linker about the layout of uninitialized */
|
||||
/* TLS data, and does not advance the linker's location counter */
|
||||
.tbss . : {
|
||||
_tbss_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tbss))
|
||||
*(SORT_BY_ALIGNMENT(.tbss.*))
|
||||
. = ALIGN(TLS_ALIGNMENT);
|
||||
/* the %fs register is based on this location */
|
||||
_tbss_end = .;
|
||||
} :Tls
|
||||
|
||||
.data ALIGN(PAGESIZE) : {
|
||||
/*BEGIN: Read/Write Data */
|
||||
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
|
||||
@@ -385,26 +409,7 @@ SECTIONS {
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Ram
|
||||
|
||||
.tdata . : {
|
||||
_tdata_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tdata))
|
||||
*(SORT_BY_ALIGNMENT(.tdata.*))
|
||||
_tdata_end = .;
|
||||
. = ALIGN(PAGESIZE);
|
||||
} :Tls :Ram
|
||||
|
||||
/*END: file content that's loaded by o/s */
|
||||
/*BEGIN: bss memory void */
|
||||
|
||||
.tbss . : {
|
||||
_tbss_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tbss))
|
||||
*(SORT_BY_ALIGNMENT(.tbss.*))
|
||||
. = ALIGN(TLS_ALIGNMENT);
|
||||
/* the %fs register is based on this location */
|
||||
_tbss_end = .;
|
||||
} :Tls
|
||||
|
||||
/*END: file content */
|
||||
/*BEGIN: bss memory that's addressable */
|
||||
|
||||
@@ -427,7 +432,7 @@ SECTIONS {
|
||||
|
||||
KEEP(*(.bssepilogue))
|
||||
/*END: NT FORK COPYING */
|
||||
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
|
||||
. = ALIGN(PAGESIZE);
|
||||
HIDDEN(_end = .);
|
||||
PROVIDE_HIDDEN(end = .);
|
||||
} :Bss
|
||||
@@ -509,7 +514,7 @@ HIDDEN(ape_rom_rva = RVA(ape_rom_vaddr));
|
||||
HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz);
|
||||
HIDDEN(ape_ram_vaddr = ADDR(.data));
|
||||
HIDDEN(ape_ram_paddr = LOADADDR(.data));
|
||||
HIDDEN(ape_ram_filesz = SIZEOF(.data) + SIZEOF(.tdata));
|
||||
HIDDEN(ape_ram_filesz = SIZEOF(.data));
|
||||
HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
|
||||
HIDDEN(ape_ram_align = PAGESIZE);
|
||||
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
|
||||
@@ -533,16 +538,16 @@ HIDDEN(ape_note_align = __SIZEOF_POINTER__);
|
||||
HIDDEN(ape_text_offset = ape_rom_offset + LOADADDR(.text) - ape_rom_paddr);
|
||||
HIDDEN(ape_text_paddr = LOADADDR(.text));
|
||||
HIDDEN(ape_text_vaddr = ADDR(.text));
|
||||
HIDDEN(ape_text_filesz = SIZEOF(.text));
|
||||
HIDDEN(ape_text_memsz = SIZEOF(.text));
|
||||
HIDDEN(ape_text_filesz = SIZEOF(.text) + SIZEOF(.tdata));
|
||||
HIDDEN(ape_text_memsz = SIZEOF(.text) + SIZEOF(.tdata));
|
||||
HIDDEN(ape_text_align = PAGESIZE);
|
||||
HIDDEN(ape_text_rva = RVA(ape_text_vaddr));
|
||||
|
||||
HIDDEN(ape_data_offset = ape_ram_offset + LOADADDR(.data) - ape_ram_paddr);
|
||||
HIDDEN(ape_data_paddr = LOADADDR(.data));
|
||||
HIDDEN(ape_data_vaddr = ADDR(.data));
|
||||
HIDDEN(ape_data_filesz = SIZEOF(.data) + SIZEOF(.tdata));
|
||||
HIDDEN(ape_data_memsz = SIZEOF(.data) + SIZEOF(.tdata));
|
||||
HIDDEN(ape_data_filesz = SIZEOF(.data));
|
||||
HIDDEN(ape_data_memsz = SIZEOF(.data));
|
||||
HIDDEN(ape_data_align = PAGESIZE);
|
||||
HIDDEN(ape_data_rva = RVA(ape_data_vaddr));
|
||||
|
||||
@@ -562,16 +567,213 @@ SHSTUB2(ape_loader_dd_count,
|
||||
? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64
|
||||
: 0);
|
||||
|
||||
HIDDEN(blink_aarch64_b0 = RVA(blink_aarch64) % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b1 = RVA(blink_aarch64) < 10 ? 32 : RVA(blink_aarch64) / 10 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b2 = RVA(blink_aarch64) < 100 ? 32 : RVA(blink_aarch64) / 100 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b3 = RVA(blink_aarch64) < 1000 ? 32 : RVA(blink_aarch64) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b4 = RVA(blink_aarch64) < 10000 ? 32 : RVA(blink_aarch64) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b5 = RVA(blink_aarch64) < 100000 ? 32 : RVA(blink_aarch64) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b6 = RVA(blink_aarch64) < 1000000 ? 32 : RVA(blink_aarch64) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b7 = RVA(blink_aarch64) < 10000000 ? 32 : RVA(blink_aarch64) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b8 = RVA(blink_aarch64) < 100000000 ? 32 : RVA(blink_aarch64) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_b9 = RVA(blink_aarch64) < 1000000000 ? 32 : RVA(blink_aarch64) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_aarch64_size_b0 = blink_aarch64_size % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b1 = blink_aarch64_size < 10 ? 32 : blink_aarch64_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b2 = blink_aarch64_size < 100 ? 32 : blink_aarch64_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b3 = blink_aarch64_size < 1000 ? 32 : blink_aarch64_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b4 = blink_aarch64_size < 10000 ? 32 : blink_aarch64_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b5 = blink_aarch64_size < 100000 ? 32 : blink_aarch64_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b6 = blink_aarch64_size < 1000000 ? 32 : blink_aarch64_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b7 = blink_aarch64_size < 10000000 ? 32 : blink_aarch64_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b8 = blink_aarch64_size < 100000000 ? 32 : blink_aarch64_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_aarch64_size_b9 = blink_aarch64_size < 1000000000 ? 32 : blink_aarch64_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_darwin_arm64_b0 = RVA(blink_darwin_arm64) % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b1 = RVA(blink_darwin_arm64) < 10 ? 32 : RVA(blink_darwin_arm64) / 10 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b2 = RVA(blink_darwin_arm64) < 100 ? 32 : RVA(blink_darwin_arm64) / 100 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b3 = RVA(blink_darwin_arm64) < 1000 ? 32 : RVA(blink_darwin_arm64) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b4 = RVA(blink_darwin_arm64) < 10000 ? 32 : RVA(blink_darwin_arm64) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b5 = RVA(blink_darwin_arm64) < 100000 ? 32 : RVA(blink_darwin_arm64) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b6 = RVA(blink_darwin_arm64) < 1000000 ? 32 : RVA(blink_darwin_arm64) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b7 = RVA(blink_darwin_arm64) < 10000000 ? 32 : RVA(blink_darwin_arm64) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b8 = RVA(blink_darwin_arm64) < 100000000 ? 32 : RVA(blink_darwin_arm64) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_b9 = RVA(blink_darwin_arm64) < 1000000000 ? 32 : RVA(blink_darwin_arm64) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_darwin_arm64_size_b0 = blink_darwin_arm64_size % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b1 = blink_darwin_arm64_size < 10 ? 32 : blink_darwin_arm64_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b2 = blink_darwin_arm64_size < 100 ? 32 : blink_darwin_arm64_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b3 = blink_darwin_arm64_size < 1000 ? 32 : blink_darwin_arm64_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b4 = blink_darwin_arm64_size < 10000 ? 32 : blink_darwin_arm64_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b5 = blink_darwin_arm64_size < 100000 ? 32 : blink_darwin_arm64_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b6 = blink_darwin_arm64_size < 1000000 ? 32 : blink_darwin_arm64_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b7 = blink_darwin_arm64_size < 10000000 ? 32 : blink_darwin_arm64_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b8 = blink_darwin_arm64_size < 100000000 ? 32 : blink_darwin_arm64_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_darwin_arm64_size_b9 = blink_darwin_arm64_size < 1000000000 ? 32 : blink_darwin_arm64_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_arm_b0 = RVA(blink_arm) % 10 + 48);
|
||||
HIDDEN(blink_arm_b1 = RVA(blink_arm) < 10 ? 32 : RVA(blink_arm) / 10 % 10 + 48);
|
||||
HIDDEN(blink_arm_b2 = RVA(blink_arm) < 100 ? 32 : RVA(blink_arm) / 100 % 10 + 48);
|
||||
HIDDEN(blink_arm_b3 = RVA(blink_arm) < 1000 ? 32 : RVA(blink_arm) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b4 = RVA(blink_arm) < 10000 ? 32 : RVA(blink_arm) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b5 = RVA(blink_arm) < 100000 ? 32 : RVA(blink_arm) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b6 = RVA(blink_arm) < 1000000 ? 32 : RVA(blink_arm) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b7 = RVA(blink_arm) < 10000000 ? 32 : RVA(blink_arm) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b8 = RVA(blink_arm) < 100000000 ? 32 : RVA(blink_arm) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_b9 = RVA(blink_arm) < 1000000000 ? 32 : RVA(blink_arm) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_arm_size_b0 = blink_arm_size % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b1 = blink_arm_size < 10 ? 32 : blink_arm_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b2 = blink_arm_size < 100 ? 32 : blink_arm_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b3 = blink_arm_size < 1000 ? 32 : blink_arm_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b4 = blink_arm_size < 10000 ? 32 : blink_arm_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b5 = blink_arm_size < 100000 ? 32 : blink_arm_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b6 = blink_arm_size < 1000000 ? 32 : blink_arm_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b7 = blink_arm_size < 10000000 ? 32 : blink_arm_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b8 = blink_arm_size < 100000000 ? 32 : blink_arm_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_arm_size_b9 = blink_arm_size < 1000000000 ? 32 : blink_arm_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_i486_b0 = RVA(blink_i486) % 10 + 48);
|
||||
HIDDEN(blink_i486_b1 = RVA(blink_i486) < 10 ? 32 : RVA(blink_i486) / 10 % 10 + 48);
|
||||
HIDDEN(blink_i486_b2 = RVA(blink_i486) < 100 ? 32 : RVA(blink_i486) / 100 % 10 + 48);
|
||||
HIDDEN(blink_i486_b3 = RVA(blink_i486) < 1000 ? 32 : RVA(blink_i486) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b4 = RVA(blink_i486) < 10000 ? 32 : RVA(blink_i486) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b5 = RVA(blink_i486) < 100000 ? 32 : RVA(blink_i486) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b6 = RVA(blink_i486) < 1000000 ? 32 : RVA(blink_i486) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b7 = RVA(blink_i486) < 10000000 ? 32 : RVA(blink_i486) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b8 = RVA(blink_i486) < 100000000 ? 32 : RVA(blink_i486) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_b9 = RVA(blink_i486) < 1000000000 ? 32 : RVA(blink_i486) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_i486_size_b0 = blink_i486_size % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b1 = blink_i486_size < 10 ? 32 : blink_i486_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b2 = blink_i486_size < 100 ? 32 : blink_i486_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b3 = blink_i486_size < 1000 ? 32 : blink_i486_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b4 = blink_i486_size < 10000 ? 32 : blink_i486_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b5 = blink_i486_size < 100000 ? 32 : blink_i486_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b6 = blink_i486_size < 1000000 ? 32 : blink_i486_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b7 = blink_i486_size < 10000000 ? 32 : blink_i486_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b8 = blink_i486_size < 100000000 ? 32 : blink_i486_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_i486_size_b9 = blink_i486_size < 1000000000 ? 32 : blink_i486_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_riscv64_b0 = RVA(blink_riscv64) % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b1 = RVA(blink_riscv64) < 10 ? 32 : RVA(blink_riscv64) / 10 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b2 = RVA(blink_riscv64) < 100 ? 32 : RVA(blink_riscv64) / 100 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b3 = RVA(blink_riscv64) < 1000 ? 32 : RVA(blink_riscv64) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b4 = RVA(blink_riscv64) < 10000 ? 32 : RVA(blink_riscv64) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b5 = RVA(blink_riscv64) < 100000 ? 32 : RVA(blink_riscv64) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b6 = RVA(blink_riscv64) < 1000000 ? 32 : RVA(blink_riscv64) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b7 = RVA(blink_riscv64) < 10000000 ? 32 : RVA(blink_riscv64) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b8 = RVA(blink_riscv64) < 100000000 ? 32 : RVA(blink_riscv64) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_b9 = RVA(blink_riscv64) < 1000000000 ? 32 : RVA(blink_riscv64) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_riscv64_size_b0 = blink_riscv64_size % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b1 = blink_riscv64_size < 10 ? 32 : blink_riscv64_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b2 = blink_riscv64_size < 100 ? 32 : blink_riscv64_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b3 = blink_riscv64_size < 1000 ? 32 : blink_riscv64_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b4 = blink_riscv64_size < 10000 ? 32 : blink_riscv64_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b5 = blink_riscv64_size < 100000 ? 32 : blink_riscv64_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b6 = blink_riscv64_size < 1000000 ? 32 : blink_riscv64_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b7 = blink_riscv64_size < 10000000 ? 32 : blink_riscv64_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b8 = blink_riscv64_size < 100000000 ? 32 : blink_riscv64_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_riscv64_size_b9 = blink_riscv64_size < 1000000000 ? 32 : blink_riscv64_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_mipsel_b0 = RVA(blink_mipsel) % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b1 = RVA(blink_mipsel) < 10 ? 32 : RVA(blink_mipsel) / 10 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b2 = RVA(blink_mipsel) < 100 ? 32 : RVA(blink_mipsel) / 100 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b3 = RVA(blink_mipsel) < 1000 ? 32 : RVA(blink_mipsel) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b4 = RVA(blink_mipsel) < 10000 ? 32 : RVA(blink_mipsel) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b5 = RVA(blink_mipsel) < 100000 ? 32 : RVA(blink_mipsel) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b6 = RVA(blink_mipsel) < 1000000 ? 32 : RVA(blink_mipsel) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b7 = RVA(blink_mipsel) < 10000000 ? 32 : RVA(blink_mipsel) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b8 = RVA(blink_mipsel) < 100000000 ? 32 : RVA(blink_mipsel) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_b9 = RVA(blink_mipsel) < 1000000000 ? 32 : RVA(blink_mipsel) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_mipsel_size_b0 = blink_mipsel_size % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b1 = blink_mipsel_size < 10 ? 32 : blink_mipsel_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b2 = blink_mipsel_size < 100 ? 32 : blink_mipsel_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b3 = blink_mipsel_size < 1000 ? 32 : blink_mipsel_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b4 = blink_mipsel_size < 10000 ? 32 : blink_mipsel_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b5 = blink_mipsel_size < 100000 ? 32 : blink_mipsel_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b6 = blink_mipsel_size < 1000000 ? 32 : blink_mipsel_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b7 = blink_mipsel_size < 10000000 ? 32 : blink_mipsel_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b8 = blink_mipsel_size < 100000000 ? 32 : blink_mipsel_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_mipsel_size_b9 = blink_mipsel_size < 1000000000 ? 32 : blink_mipsel_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_powerpc64le_b0 = RVA(blink_powerpc64le) % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b1 = RVA(blink_powerpc64le) < 10 ? 32 : RVA(blink_powerpc64le) / 10 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b2 = RVA(blink_powerpc64le) < 100 ? 32 : RVA(blink_powerpc64le) / 100 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b3 = RVA(blink_powerpc64le) < 1000 ? 32 : RVA(blink_powerpc64le) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b4 = RVA(blink_powerpc64le) < 10000 ? 32 : RVA(blink_powerpc64le) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b5 = RVA(blink_powerpc64le) < 100000 ? 32 : RVA(blink_powerpc64le) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b6 = RVA(blink_powerpc64le) < 1000000 ? 32 : RVA(blink_powerpc64le) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b7 = RVA(blink_powerpc64le) < 10000000 ? 32 : RVA(blink_powerpc64le) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b8 = RVA(blink_powerpc64le) < 100000000 ? 32 : RVA(blink_powerpc64le) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_b9 = RVA(blink_powerpc64le) < 1000000000 ? 32 : RVA(blink_powerpc64le) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_powerpc64le_size_b0 = blink_powerpc64le_size % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b1 = blink_powerpc64le_size < 10 ? 32 : blink_powerpc64le_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b2 = blink_powerpc64le_size < 100 ? 32 : blink_powerpc64le_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b3 = blink_powerpc64le_size < 1000 ? 32 : blink_powerpc64le_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b4 = blink_powerpc64le_size < 10000 ? 32 : blink_powerpc64le_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b5 = blink_powerpc64le_size < 100000 ? 32 : blink_powerpc64le_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b6 = blink_powerpc64le_size < 1000000 ? 32 : blink_powerpc64le_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b7 = blink_powerpc64le_size < 10000000 ? 32 : blink_powerpc64le_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b8 = blink_powerpc64le_size < 100000000 ? 32 : blink_powerpc64le_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc64le_size_b9 = blink_powerpc64le_size < 1000000000 ? 32 : blink_powerpc64le_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_powerpc_b0 = RVA(blink_powerpc) % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b1 = RVA(blink_powerpc) < 10 ? 32 : RVA(blink_powerpc) / 10 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b2 = RVA(blink_powerpc) < 100 ? 32 : RVA(blink_powerpc) / 100 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b3 = RVA(blink_powerpc) < 1000 ? 32 : RVA(blink_powerpc) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b4 = RVA(blink_powerpc) < 10000 ? 32 : RVA(blink_powerpc) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b5 = RVA(blink_powerpc) < 100000 ? 32 : RVA(blink_powerpc) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b6 = RVA(blink_powerpc) < 1000000 ? 32 : RVA(blink_powerpc) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b7 = RVA(blink_powerpc) < 10000000 ? 32 : RVA(blink_powerpc) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b8 = RVA(blink_powerpc) < 100000000 ? 32 : RVA(blink_powerpc) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_b9 = RVA(blink_powerpc) < 1000000000 ? 32 : RVA(blink_powerpc) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_powerpc_size_b0 = blink_powerpc_size % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b1 = blink_powerpc_size < 10 ? 32 : blink_powerpc_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b2 = blink_powerpc_size < 100 ? 32 : blink_powerpc_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b3 = blink_powerpc_size < 1000 ? 32 : blink_powerpc_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b4 = blink_powerpc_size < 10000 ? 32 : blink_powerpc_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b5 = blink_powerpc_size < 100000 ? 32 : blink_powerpc_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b6 = blink_powerpc_size < 1000000 ? 32 : blink_powerpc_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b7 = blink_powerpc_size < 10000000 ? 32 : blink_powerpc_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b8 = blink_powerpc_size < 100000000 ? 32 : blink_powerpc_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_powerpc_size_b9 = blink_powerpc_size < 1000000000 ? 32 : blink_powerpc_size / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_s390x_b0 = RVA(blink_s390x) % 10 + 48);
|
||||
HIDDEN(blink_s390x_b1 = RVA(blink_s390x) < 10 ? 32 : RVA(blink_s390x) / 10 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b2 = RVA(blink_s390x) < 100 ? 32 : RVA(blink_s390x) / 100 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b3 = RVA(blink_s390x) < 1000 ? 32 : RVA(blink_s390x) / 1000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b4 = RVA(blink_s390x) < 10000 ? 32 : RVA(blink_s390x) / 10000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b5 = RVA(blink_s390x) < 100000 ? 32 : RVA(blink_s390x) / 100000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b6 = RVA(blink_s390x) < 1000000 ? 32 : RVA(blink_s390x) / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b7 = RVA(blink_s390x) < 10000000 ? 32 : RVA(blink_s390x) / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b8 = RVA(blink_s390x) < 100000000 ? 32 : RVA(blink_s390x) / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_b9 = RVA(blink_s390x) < 1000000000 ? 32 : RVA(blink_s390x) / 1000000000 % 10 + 48);
|
||||
|
||||
HIDDEN(blink_s390x_size_b0 = blink_s390x_size % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b1 = blink_s390x_size < 10 ? 32 : blink_s390x_size / 10 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b2 = blink_s390x_size < 100 ? 32 : blink_s390x_size / 100 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b3 = blink_s390x_size < 1000 ? 32 : blink_s390x_size / 1000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b4 = blink_s390x_size < 10000 ? 32 : blink_s390x_size / 10000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b5 = blink_s390x_size < 100000 ? 32 : blink_s390x_size / 100000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b6 = blink_s390x_size < 1000000 ? 32 : blink_s390x_size / 1000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b7 = blink_s390x_size < 10000000 ? 32 : blink_s390x_size / 10000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b8 = blink_s390x_size < 100000000 ? 32 : blink_s390x_size / 100000000 % 10 + 48);
|
||||
HIDDEN(blink_s390x_size_b9 = blink_s390x_size < 1000000000 ? 32 : blink_s390x_size / 1000000000 % 10 + 48);
|
||||
|
||||
#if SupportsMetal()
|
||||
HIDDEN(v_ape_realsectors =
|
||||
MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 4096)) / 512);
|
||||
HIDDEN(v_ape_realslacksectors =
|
||||
v_ape_realsectors - MIN(0x70000 - IMAGE_BASE_REAL,
|
||||
ROUNDUP(RVA(_edata), 512)) / 512);
|
||||
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||
HIDDEN(v_ape_highsectors =
|
||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||
MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512);
|
||||
HIDDEN(v_ape_realbytes = v_ape_realsectors * 512);
|
||||
HIDDEN(v_ape_realdwords = v_ape_realsectors * (512 / 4));
|
||||
HIDDEN(v_ape_allsectors = ROUNDUP(RVA(_ezip), 512) / 512);
|
||||
HIDDEN(v_ape_allbytes = v_ape_allsectors * 512);
|
||||
HIDDEN(v_ape_highsectors = v_ape_allsectors - v_ape_realsectors);
|
||||
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
|
||||
#endif
|
||||
|
||||
/* ZIP End of Central Directory header */
|
||||
@@ -653,7 +855,7 @@ CHURN(ADDR(.bss));
|
||||
CHURN(_start);
|
||||
CHURN(ape_phdrs);
|
||||
#if SupportsMetal()
|
||||
CHURN(v_ape_realsectors);
|
||||
CHURN(v_ape_allsectors);
|
||||
#endif
|
||||
#if SupportsXnu()
|
||||
CHURN(ape_macho);
|
||||
@@ -717,7 +919,7 @@ ASSERT(IS2POW(ape_stack_memsz),
|
||||
"ape_stack_memsz must be a two power");
|
||||
|
||||
ASSERT(ape_stack_vaddr % ape_stack_memsz == 0,
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000040000 - ape_stack_memsz);");
|
||||
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000040000 & -ape_stack_memsz);");
|
||||
|
||||
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
|
||||
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
|
||||
|
||||
+32
-1
@@ -96,6 +96,17 @@ o/ape/idata.inc: \
|
||||
ape/idata.internal.h \
|
||||
ape/relocations.h
|
||||
|
||||
o/$(MODE)/ape/ape.o: \
|
||||
ape/blink-aarch64.gz \
|
||||
ape/blink-arm.gz \
|
||||
ape/blink-darwin-arm64.gz \
|
||||
ape/blink-i486.gz \
|
||||
ape/blink-mipsel.gz \
|
||||
ape/blink-powerpc.gz \
|
||||
ape/blink-powerpc64le.gz \
|
||||
ape/blink-riscv64.gz \
|
||||
ape/blink-s390x.gz
|
||||
|
||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
ape/ape.S \
|
||||
ape/macros.internal.h \
|
||||
@@ -107,6 +118,7 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
@@ -114,6 +126,15 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/symbolic.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-aarch64.gz \
|
||||
ape/blink-arm.gz \
|
||||
ape/blink-darwin-arm64.gz \
|
||||
ape/blink-i486.gz \
|
||||
ape/blink-mipsel.gz \
|
||||
ape/blink-powerpc.gz \
|
||||
ape/blink-powerpc64le.gz \
|
||||
ape/blink-riscv64.gz \
|
||||
ape/blink-s390x.gz \
|
||||
o/$(MODE)/ape/ape.elf
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
@@ -133,13 +154,23 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
||||
libc/macho.internal.h \
|
||||
libc/macros.internal.h \
|
||||
libc/nexgen32e/uart.internal.h \
|
||||
libc/calls/metalfile.internal.h \
|
||||
libc/nexgen32e/vidya.internal.h \
|
||||
libc/nt/pedef.internal.h \
|
||||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/symbolic.h \
|
||||
libc/sysv/consts/prot.h
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-aarch64.gz \
|
||||
ape/blink-arm.gz \
|
||||
ape/blink-darwin-arm64.gz \
|
||||
ape/blink-i486.gz \
|
||||
ape/blink-mipsel.gz \
|
||||
ape/blink-powerpc.gz \
|
||||
ape/blink-powerpc64le.gz \
|
||||
ape/blink-riscv64.gz \
|
||||
ape/blink-s390x.gz
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $UID -eq 0 ]; then
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
SUDO=
|
||||
else
|
||||
SUDO=sudo
|
||||
@@ -97,6 +97,8 @@ if [ x"$(uname -s)" = xLinux ]; then
|
||||
echo you may need to edit configs to persist across reboot >&2
|
||||
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
|
||||
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
|
||||
echo done >&2
|
||||
|
||||
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then
|
||||
|
||||
+8
-6
@@ -8,17 +8,19 @@ fi
|
||||
|
||||
{
|
||||
echo
|
||||
echo "APE Uninstaller intends to run"
|
||||
echo "APE Uninstaller intends to run (in pseudo-shell)"
|
||||
echo
|
||||
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE'"
|
||||
echo " $SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
|
||||
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
|
||||
echo " sudo rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
|
||||
echo
|
||||
echo "You may then use ape/apeinstall.sh to reinstall it"
|
||||
echo
|
||||
} >&2
|
||||
|
||||
set -ex
|
||||
if [ -f /proc/sys/fs/binfmt_misc/APE ]; then
|
||||
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE' || exit
|
||||
fi
|
||||
for f in /proc/sys/fs/binfmt_misc/APE*; do
|
||||
if [ -f $f ]; then
|
||||
$SUDO sh -c "echo -1 >$f" || exit
|
||||
fi
|
||||
done
|
||||
$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit
|
||||
Binary file not shown.
Binary file not shown.
File renamed without changes.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-2
@@ -175,7 +175,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -221,7 +221,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ macho: .long 0xFEEDFACE+1
|
||||
510: .quad 0 # rax
|
||||
.quad 0 # rbx
|
||||
.quad 0 # rcx
|
||||
.quad XNU # rdx
|
||||
.quad _HOSTXNU # rdx
|
||||
.quad 0 # rdi
|
||||
.quad 0 # rsi
|
||||
.quad 0 # rbp
|
||||
@@ -121,7 +121,7 @@ _start:
|
||||
jne 0f
|
||||
cmp $+1,%edx
|
||||
jne 0f
|
||||
mov $XNU,%dl
|
||||
mov $_HOSTXNU,%dl
|
||||
xor %ecx,%ecx
|
||||
|
||||
0: mov %rsp,%rsi
|
||||
|
||||
@@ -180,6 +180,20 @@
|
||||
.stub \name\()_bcs\n,long
|
||||
.endm
|
||||
|
||||
// Task State Segment Descriptor Entries.
|
||||
.macro .tssdescstub name:req
|
||||
.ifndef \name
|
||||
.weak \name
|
||||
.set \name,0
|
||||
.endif
|
||||
.ifndef \name\()_end
|
||||
.weak \name\()_end
|
||||
.set \name\()_end,0
|
||||
.endif
|
||||
.stub \name\()_desc_ent0,quad
|
||||
.stub \name\()_desc_ent1,quad
|
||||
.endm
|
||||
|
||||
/* clang-format on */
|
||||
#elif defined(__LINKER__)
|
||||
|
||||
@@ -257,5 +271,22 @@
|
||||
(X) % 10 * 0x1000000 \
|
||||
: 0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
* Laying out the GDT entries for a TSS for bare metal operation.
|
||||
*/
|
||||
#define TSSDESCSTUB2(SYM, BASE, LIM) \
|
||||
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
|
||||
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
|
||||
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
|
||||
#define TSSDESC_ENT0(BASE, LIM) \
|
||||
(((LIM) << 0 & 0x000000000000ffff) | \
|
||||
((BASE) << 16 & 0x000000ffffff0000) | \
|
||||
0x89 << 40 | \
|
||||
((LIM) >> 16 << 48 & 0x000f000000000000) | \
|
||||
0x2 << 52 | \
|
||||
((BASE) >> 24 << 56 & 0xff00000000000000))
|
||||
#define TSSDESC_ENT1(BASE) \
|
||||
((BASE) >> 32 << 0 & 0x00000000ffffffff)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* APE_MACROS_H_ */
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern unsigned char _base[];
|
||||
extern unsigned char _ehead[];
|
||||
extern unsigned char _etext[];
|
||||
extern unsigned char _edata[];
|
||||
extern unsigned char _ezip[];
|
||||
extern unsigned char _end[];
|
||||
extern unsigned char _ereal[];
|
||||
extern unsigned char _tdata_start[];
|
||||
extern unsigned char _tdata_end[];
|
||||
extern unsigned char _tbss_start[];
|
||||
extern unsigned char _tbss_end[];
|
||||
extern unsigned char __privileged_start[];
|
||||
extern unsigned char __privileged_addr[];
|
||||
extern unsigned char __privileged_size[];
|
||||
extern unsigned char __privileged_end[];
|
||||
extern unsigned char __test_start[];
|
||||
extern unsigned char __ro[];
|
||||
extern unsigned char *__relo_start[];
|
||||
extern unsigned char *__relo_end[];
|
||||
extern uint8_t __zip_start[];
|
||||
extern uint8_t __zip_end[];
|
||||
extern uint8_t __data_start[];
|
||||
extern uint8_t __data_end[];
|
||||
extern uint8_t __bss_start[];
|
||||
extern uint8_t __bss_end[];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+27
-6
@@ -29,7 +29,7 @@ endif
|
||||
#
|
||||
ifeq ($(MODE),fastbuild)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
|
||||
CONFIG_OFLAGS += -g0
|
||||
CONFIG_LDFLAGS += -S
|
||||
TARGET_ARCH ?= -msse3
|
||||
@@ -125,6 +125,22 @@ TARGET_ARCH ?= -msse3
|
||||
OVERRIDE_CCFLAGS += -fno-pie
|
||||
endif
|
||||
|
||||
# System Five Mode
|
||||
#
|
||||
# - `make MODE=sysv`
|
||||
# - Optimized
|
||||
# - Backtraces
|
||||
# - Debuggable
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - No Windows bloat!
|
||||
#
|
||||
ifeq ($(MODE), sysv)
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
|
||||
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
|
||||
TARGET_ARCH ?= -msse3
|
||||
endif
|
||||
|
||||
# Tiny Mode
|
||||
#
|
||||
# - `make MODE=tiny`
|
||||
@@ -151,7 +167,8 @@ CONFIG_CCFLAGS += \
|
||||
-fschedule-insns2 \
|
||||
-fomit-frame-pointer \
|
||||
-momit-leaf-frame-pointer \
|
||||
-foptimize-sibling-calls
|
||||
-foptimize-sibling-calls \
|
||||
-DDWARFLESS
|
||||
CONFIG_OFLAGS += \
|
||||
-g0
|
||||
CONFIG_LDFLAGS += \
|
||||
@@ -181,7 +198,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=1
|
||||
-DSUPPORT_VECTOR=1 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -217,7 +235,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=113
|
||||
-DSUPPORT_VECTOR=113 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_OFLAGS += \
|
||||
@@ -252,7 +271,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=121
|
||||
-DSUPPORT_VECTOR=121 \
|
||||
-DDWARFLESS
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
CONFIG_CCFLAGS += \
|
||||
@@ -287,7 +307,8 @@ CONFIG_CPPFLAGS += \
|
||||
-DTINY \
|
||||
-DNDEBUG \
|
||||
-DTRUSTWORTHY \
|
||||
-DSUPPORT_VECTOR=251
|
||||
-DSUPPORT_VECTOR=251 \
|
||||
-DDWARFLESS
|
||||
CONFIG_CCFLAGS += \
|
||||
-Os \
|
||||
-fno-align-functions \
|
||||
|
||||
+15
-24
@@ -45,7 +45,6 @@
|
||||
LC_ALL = C
|
||||
SOURCE_DATE_EPOCH = 0
|
||||
|
||||
TAGS ?= /usr/bin/ctags # emacs source builds or something breaks it
|
||||
ARFLAGS = rcsD
|
||||
ZFLAGS ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
@@ -73,33 +72,25 @@ IMAGE_BASE_VIRTUAL ?= 0x400000
|
||||
IGNORE := $(shell $(ECHO) -2 ♥cosmo)
|
||||
IGNORE := $(shell $(MKDIR) o/tmp)
|
||||
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","")
|
||||
AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe
|
||||
CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe
|
||||
LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe
|
||||
NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe
|
||||
GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-*)","")
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
|
||||
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
|
||||
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
|
||||
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
|
||||
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
|
||||
endif
|
||||
|
||||
AS = $(PREFIX)as
|
||||
CC = $(PREFIX)gcc
|
||||
CXX = $(PREFIX)g++
|
||||
CXXFILT = $(PREFIX)c++filt
|
||||
LD = $(PREFIX)ld.bfd
|
||||
NM = $(PREFIX)nm
|
||||
GCC = $(PREFIX)gcc
|
||||
STRIP = $(PREFIX)strip
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
|
||||
+4
-1
@@ -43,6 +43,9 @@
|
||||
# '(progn
|
||||
# (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook)))
|
||||
|
||||
TAGS="$1"
|
||||
shift
|
||||
|
||||
# ctags doesn't understand atomics, e.g.
|
||||
# extern char **environ;
|
||||
set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@"
|
||||
@@ -63,7 +66,7 @@ set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
|
||||
# struct WorstSoftwareEver;
|
||||
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
|
||||
|
||||
exec ${TAGS:-ctags} \
|
||||
exec $TAGS \
|
||||
-e \
|
||||
--langmap=c:.c.h \
|
||||
--exclude=libc/nt/struct/imagefileheader.internal.h \
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
@@ -59,9 +59,15 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
kprintf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
char *buffer;
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
buffer = malloc(13);
|
||||
|
||||
+7
-7
@@ -20,22 +20,22 @@ int main(int argc, char *argv[]) {
|
||||
volatile unsigned long x;
|
||||
struct timespec now, start, next, interval;
|
||||
printf("hammering the cpu...\n");
|
||||
next = start = _timespec_mono();
|
||||
interval = _timespec_frommillis(500);
|
||||
next = _timespec_add(next, interval);
|
||||
next = start = timespec_mono();
|
||||
interval = timespec_frommillis(500);
|
||||
next = timespec_add(next, interval);
|
||||
for (;;) {
|
||||
for (i = 0;; ++i) {
|
||||
x *= 7;
|
||||
if (!(i % 256)) {
|
||||
now = _timespec_mono();
|
||||
if (_timespec_gte(now, next)) {
|
||||
now = timespec_mono();
|
||||
if (timespec_cmp(now, next) >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
next = _timespec_add(next, interval);
|
||||
next = timespec_add(next, interval);
|
||||
printf("consumed %10g seconds monotonic time and %10g seconds cpu time\n",
|
||||
_timespec_tonanos(_timespec_sub(now, start)) / 1000000000.,
|
||||
timespec_tonanos(timespec_sub(now, start)) / 1000000000.,
|
||||
(double)clock() / CLOCKS_PER_SEC);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void show(int clock) {
|
||||
}
|
||||
shown[n++] = clock;
|
||||
if (clock_getres(clock, &ts) != -1) {
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), _timespec_tonanos(ts));
|
||||
kprintf("%s %'ld ns\n", DescribeClockName(clock), timespec_tonanos(ts));
|
||||
} else {
|
||||
kprintf("%s %s\n", DescribeClockName(clock), _strerrno(errno));
|
||||
}
|
||||
@@ -38,10 +38,12 @@ int main(int argc, char *argv[]) {
|
||||
show(CLOCK_REALTIME);
|
||||
show(CLOCK_REALTIME_FAST);
|
||||
show(CLOCK_REALTIME_PRECISE);
|
||||
show(CLOCK_REALTIME_COARSE);
|
||||
show(CLOCK_MONOTONIC);
|
||||
show(CLOCK_MONOTONIC_RAW);
|
||||
show(CLOCK_MONOTONIC_FAST);
|
||||
show(CLOCK_MONOTONIC_PRECISE);
|
||||
show(CLOCK_MONOTONIC_COARSE);
|
||||
show(CLOCK_PROCESS_CPUTIME_ID);
|
||||
show(CLOCK_THREAD_CPUTIME_ID);
|
||||
show(CLOCK_PROF);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
@@ -24,6 +25,12 @@
|
||||
*/
|
||||
|
||||
noubsan int main(int argc, char *argv[]) {
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
ShowCrashReports();
|
||||
return 1 / (x = 0);
|
||||
|
||||
+25
-1
@@ -49,12 +49,12 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
@@ -71,19 +71,24 @@ EXAMPLES_DIRECTDEPS = \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_AWK \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_DOUBLECONVERSION \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LINENOISE \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_HIREDIS \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_NSYNC \
|
||||
THIRD_PARTY_NSYNC_MEM \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_SED \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_TR \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
@@ -142,6 +147,25 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
# # force symtab.com to be a zip file, by pulling a zip asset into linkage
|
||||
# # we wouldn't need to do this if we depended on functions like localtime
|
||||
# o/$(MODE)/examples/symtab.com.dbg: \
|
||||
# $(EXAMPLES_DEPS) \
|
||||
# o/$(MODE)/examples/symtab.o \
|
||||
# o/$(MODE)/examples/symtab.c.zip.o \
|
||||
# o/$(MODE)/examples/examples.pkg \
|
||||
# $(EXAMPLES_BOOTLOADER)
|
||||
# @$(APELINK)
|
||||
|
||||
# modify .com so it can read the symbol table without needing the .com.dbg file
|
||||
o/$(MODE)/examples/symtab.com: \
|
||||
o/$(MODE)/examples/symtab.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
o/$(MODE)/tool/build/symtab.com
|
||||
@$(MAKE_OBJCOPY)
|
||||
@$(MAKE_SYMTAB_CREATE)
|
||||
@$(MAKE_SYMTAB_ZIP)
|
||||
|
||||
o/$(MODE)/examples/picol.o: private \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
+1
-8
@@ -9,19 +9,12 @@
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/mem/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
dontinline void dostuff(const char *s) {
|
||||
int i, us;
|
||||
srand(rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
srand(_rand64()); /* seeds rand() w/ intel rdrnd, auxv, etc. */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
us = rand() % 500000;
|
||||
usleep(us);
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int main() {
|
||||
kprintf("%d\n", GetCpuCount());
|
||||
kprintf("%d\n", _getcpucount());
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/errno.h"
|
||||
@@ -102,7 +103,7 @@ uint64_t rngset64(void) {
|
||||
static unsigned i;
|
||||
static uint64_t s;
|
||||
if (!i) {
|
||||
s = rand64();
|
||||
s = _rand64();
|
||||
i = (s + 1) & (511);
|
||||
}
|
||||
return MarsagliaXorshift64(&s);
|
||||
@@ -215,7 +216,7 @@ const struct Function {
|
||||
{"moby", moby}, //
|
||||
{"mt19937", _mt19937}, //
|
||||
{"python", pythonx2}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rand64", _rand64}, //
|
||||
{"rdrand", rdrand}, //
|
||||
{"rdrnd", rdrand}, //
|
||||
{"rdseed", rdseed}, //
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/pollfd.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
@@ -137,7 +136,7 @@ void *Worker(void *id) {
|
||||
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
|
||||
errno = 0;
|
||||
|
||||
if (bind(server, &addr, sizeof(addr)) == -1) {
|
||||
if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
kprintf("%s() failed %m\n", "socket");
|
||||
goto CloseWorker;
|
||||
}
|
||||
@@ -167,7 +166,7 @@ void *Worker(void *id) {
|
||||
|
||||
// wait for client connection
|
||||
clientaddrsize = sizeof(clientaddr);
|
||||
client = accept(server, &clientaddr, &clientaddrsize);
|
||||
client = accept(server, (struct sockaddr *)&clientaddr, &clientaddrsize);
|
||||
|
||||
// accept() can raise a very diverse number of errors but none of
|
||||
// them are really true showstoppers that would necessitate us to
|
||||
@@ -299,7 +298,7 @@ int main(int argc, char *argv[]) {
|
||||
PORT);
|
||||
}
|
||||
|
||||
threads = argc > 1 ? atoi(argv[1]) : GetCpuCount();
|
||||
threads = argc > 1 ? atoi(argv[1]) : _getcpucount();
|
||||
if (!(1 <= threads && threads <= 100000)) {
|
||||
kprintf("error: invalid number of threads: %d\n", threads);
|
||||
exit(1);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/hiredis/hiredis.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Demo of using hiredis to connect to a Redis server
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 3 || argc > 5) {
|
||||
fprintf(stderr, "Usage: %s HOST PORT [KEY] [VALUE]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool setValue = (argc == 5), getValue = (argc == 4);
|
||||
|
||||
redisContext *c = redisConnect(argv[1], atoi(argv[2]));
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
fprintf(stderr, "Connection error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
} else {
|
||||
fputs("Failed to allocate redis context\n", stderr);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
redisReply *reply;
|
||||
if (!setValue && !getValue) {
|
||||
reply = redisCommand(c, "PING");
|
||||
printf("PING: %s\n", reply->str);
|
||||
} else if (setValue) {
|
||||
reply = redisCommand(c, "SET %s %s", argv[3], argv[4]);
|
||||
printf("SET: %s\n", reply->str);
|
||||
} else {
|
||||
reply = redisCommand(c, "GET %s", argv[3]);
|
||||
printf("GET: %s\n", reply->str);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
redisFree(c);
|
||||
return 0;
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,43 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
|
||||
/**
|
||||
* @fileoverview shows how accurate clock_nanosleep() is
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
long i, ns;
|
||||
struct timespec x, y, w;
|
||||
timespec_sleep(timespec_fromnanos(0)); // warmup
|
||||
|
||||
printf("\nrelative sleep\n");
|
||||
for (i = 0; i < 28; ++i) {
|
||||
ns = 1l << i;
|
||||
x = timespec_real();
|
||||
timespec_sleep(timespec_fromnanos(ns));
|
||||
y = timespec_real();
|
||||
printf("%,11ld ns sleep took %,ld ns\n", ns,
|
||||
timespec_tonanos(timespec_sub(y, x)));
|
||||
}
|
||||
|
||||
printf("\nabsolute sleep\n");
|
||||
for (i = 0; i < 28; ++i) {
|
||||
ns = 1l << i;
|
||||
x = timespec_real();
|
||||
timespec_sleep_until(timespec_add(x, timespec_fromnanos(ns)));
|
||||
y = timespec_real();
|
||||
printf("%,11ld ns sleep took %,ld ns\n", ns,
|
||||
timespec_tonanos(timespec_sub(y, x)));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
#include "third_party/libcxx/vector"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("zipos");
|
||||
|
||||
#define USAGE \
|
||||
" [ROM] [FMV]\n\
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
#include "net/http/ip.h"
|
||||
|
||||
/**
|
||||
* @fileoverview fast local network port scanner, e.g.
|
||||
*
|
||||
* make -j8 o//examples/portscan.com
|
||||
* o//examples/portscan.com 10.10.10.0/24 22
|
||||
*/
|
||||
|
||||
const char *FormatIp(char buf[16], uint32_t ip) {
|
||||
snprintf(buf, 16, "%hhu.%hhu.%hhu.%hhu", ip >> 24, ip >> 16, ip >> 8, ip);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define FormatIp(x) FormatIp(alloca(16), x)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int port;
|
||||
struct Cidr in;
|
||||
uint32_t netmask;
|
||||
const char *status;
|
||||
struct timeval timeout;
|
||||
uint32_t network_address;
|
||||
uint32_t last_host_address;
|
||||
uint32_t first_host_address;
|
||||
|
||||
if (argc != 3) {
|
||||
PrintUsage:
|
||||
fprintf(stderr,
|
||||
"usage: %s IP/CIDR PORT\n"
|
||||
"example: %s 192.168.0.0/24 22\n",
|
||||
argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in = ParseCidr(argv[1], -1);
|
||||
if (in.addr == -1) {
|
||||
fprintf(stderr, "error: bad ip/cidr\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
port = atoi(argv[2]);
|
||||
if (!(1 <= port && port <= 65535)) {
|
||||
fprintf(stderr, "error: bad port\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr > 30) {
|
||||
fprintf(stderr, "error: maximum supported cidr is 30\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
if (in.cidr < 22) {
|
||||
fprintf(stderr, "error: minimum cidr support right now is 22\n");
|
||||
goto PrintUsage;
|
||||
}
|
||||
|
||||
netmask = -1u << (32 - in.cidr);
|
||||
network_address = in.addr & netmask;
|
||||
first_host_address = network_address + 1;
|
||||
last_host_address = (network_address | ~netmask) - 1;
|
||||
|
||||
assert(last_host_address > first_host_address);
|
||||
assert(last_host_address - first_host_address < 1024);
|
||||
|
||||
fprintf(stderr, "scanning %s through %s\n", FormatIp(first_host_address),
|
||||
FormatIp(last_host_address));
|
||||
|
||||
timeout = timeval_frommillis(100);
|
||||
for (int64_t ip = first_host_address; ip <= last_host_address; ++ip) {
|
||||
if (!fork()) {
|
||||
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
setsockopt(3, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
setsockopt(3, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
if (!connect(3,
|
||||
(struct sockaddr *)&(struct sockaddr_in){
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(ip),
|
||||
.sin_port = htons(port),
|
||||
},
|
||||
sizeof(struct sockaddr_in))) {
|
||||
status = "open";
|
||||
} else if (errno == ECONNREFUSED) {
|
||||
status = "closed";
|
||||
} else if (errno != EINPROGRESS) {
|
||||
status = _strerrno(errno);
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
if (status) {
|
||||
printf("%-15s %s\n", FormatIp(ip), status);
|
||||
}
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (wait(0) == -1 && errno == ECHILD) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("reboot your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_AUTOBOOT)) {
|
||||
printf("system is rebooting...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/reboot.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char line[8] = {0};
|
||||
if (argc > 1 && !strcmp(argv[1], "-y")) {
|
||||
line[0] = 'y';
|
||||
} else {
|
||||
printf("shutdown your computer? yes or no [no] ");
|
||||
fflush(stdout);
|
||||
fgets(line, sizeof(line), stdin);
|
||||
}
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
if (reboot(RB_POWER_OFF)) {
|
||||
printf("system is shutting down...\n");
|
||||
exit(0);
|
||||
} else {
|
||||
perror("reboot");
|
||||
exit(1);
|
||||
}
|
||||
} else if (line[0] == 'n' || line[0] == 'N') {
|
||||
exit(0);
|
||||
} else {
|
||||
printf("error: unrecognized response\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
/**
|
||||
* @fileoverview example of how to embed symbol table in .com file
|
||||
*
|
||||
* # build our binary
|
||||
* make -j16 o//examples/symtab.com
|
||||
*
|
||||
* # move binary somewhere else
|
||||
* # so it can't find the .com.dbg binary
|
||||
* cp o//examples/symtab.com /tmp
|
||||
*
|
||||
* # run program
|
||||
* # notice that it has a symbolic backtrace
|
||||
* /tmp/symtab.com
|
||||
*
|
||||
* @see examples/examples.mk
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// this links all the debugging and zip functionality
|
||||
ShowCrashReports();
|
||||
|
||||
kprintf("----------------\n");
|
||||
kprintf(" THIS IS A TEST \n");
|
||||
kprintf("SIMULATING CRASH\n");
|
||||
kprintf("----------------\n");
|
||||
|
||||
volatile int64_t x;
|
||||
return 1 / (x = 0);
|
||||
}
|
||||
+13
-6
@@ -7,13 +7,20 @@
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Command Interpreter Demo
|
||||
* Yes this works on Windows.
|
||||
*/
|
||||
|
||||
STATIC_YOINK("_tr");
|
||||
STATIC_YOINK("_sed");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (IsWindows()) {
|
||||
system("notepad");
|
||||
} else {
|
||||
system("ls | tr a-z A-Z");
|
||||
}
|
||||
system("x=world\n"
|
||||
"echo hello $x |\n"
|
||||
" tr a-z A-Z |\n"
|
||||
" sed 's/\\(.\\)/\\1 /g'");
|
||||
}
|
||||
+436
-357
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -49,12 +49,12 @@ int main(int argc, char *argv[]) {
|
||||
printf("res = %d?\n", res);
|
||||
return -1;
|
||||
}
|
||||
printf("Hello World! %.19Lg\n", atan2l(x, y));
|
||||
printf("\e[92;44mHello World!\e[0m %.19Lg\n", atan2l(x, y));
|
||||
|
||||
// read/print loop so machine doesn't reset on metal
|
||||
for (;;) {
|
||||
if ((res = readansi(0, buf, 16)) > 0) {
|
||||
printf("got %`'.*s\r\n", res, buf);
|
||||
printf("got \e[97m%`'.*s\e[0m\r\n", res, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/isystem/unistd.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Demo of program crash reporting with Bare Metal VGA TTY.
|
||||
*
|
||||
* make -j8 o//examples/vga2.com
|
||||
* qemu-system-x86_64 -hda o//examples/vga2.com -serial stdio
|
||||
*/
|
||||
|
||||
STATIC_YOINK("vga_console");
|
||||
STATIC_YOINK("_idt");
|
||||
STATIC_YOINK("EfiMain");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
volatile int x = 1;
|
||||
volatile int y = 2;
|
||||
printf("argc = %d\n", argc);
|
||||
for (i = 0; i < argc; ++i) {
|
||||
printf("argv[%d] = \"%s\"\n", i, argv[i]);
|
||||
}
|
||||
printf("\e[92;44mHello World!\e[0m %d\n", 1 / (x + y - 3));
|
||||
for (;;);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/passwd.h"
|
||||
|
||||
/**
|
||||
* @fileoverview program for broadcasting message to all terminals, e.g.
|
||||
*
|
||||
* o//examples/wall.com hello friends
|
||||
*
|
||||
* Will place some bold text into the top left corners of all terminals:
|
||||
*
|
||||
* Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022):
|
||||
* hello friends
|
||||
*
|
||||
* It's useful for having one terminal tab notify your other ones when
|
||||
* something like a long running job completes. In the old days back
|
||||
* when unix systems had multiple users, the wall command provided the
|
||||
* ultimate lulz especially if it's a setuid binary with root privs.
|
||||
*/
|
||||
|
||||
#define GETOPTS "v"
|
||||
#define USAGE \
|
||||
"\
|
||||
Usage: wall.com [-v] [TEXTMSG] [<TEXTMSG]\n\
|
||||
-v increase verbosity\n\
|
||||
Examples:\n\
|
||||
wall.com 'hello my friends'\n\
|
||||
echo hello my friends | wall.com\n\
|
||||
"
|
||||
|
||||
int g_verbose;
|
||||
|
||||
static void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
g_verbose++;
|
||||
break;
|
||||
case '?':
|
||||
write(1, USAGE, sizeof(USAGE) - 1);
|
||||
exit(0);
|
||||
default:
|
||||
write(2, USAGE, sizeof(USAGE) - 1);
|
||||
exit(64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GetHost(void) {
|
||||
static char host[254];
|
||||
if (gethostname(host, sizeof(host))) {
|
||||
strcpy(host, "localhost");
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
char *GetTime(void) {
|
||||
int64_t t;
|
||||
struct tm tm;
|
||||
struct timespec ts;
|
||||
clock_gettime(0, &ts);
|
||||
localtime_r(&ts.tv_sec, &tm);
|
||||
return _chomp(asctime(&tm));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GetOpts(argc, argv);
|
||||
|
||||
// create broadcast banner
|
||||
// we use \e[1m so the text is strong & visually distinct
|
||||
// we use \e[K so it doesn't get lost in a forest of text
|
||||
// we map \n → \r\n because teletype might be in raw mode
|
||||
char *msg = 0;
|
||||
const char *s;
|
||||
appends(&msg, "\e7"); // save cursor position
|
||||
appends(&msg, "\e[H"); // goto top left corne
|
||||
appends(&msg, "\e[K"); // clear line forward
|
||||
appends(&msg, "\e[1m"); // bold text
|
||||
appendf(&msg, "Broadcast message from %s@%s", getpwuid(getuid())->pw_name,
|
||||
GetHost());
|
||||
if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s);
|
||||
appendf(&msg, " (%s):\r\n", GetTime());
|
||||
appends(&msg, "\e[K");
|
||||
|
||||
// append broadcast message
|
||||
if (optind < argc) {
|
||||
// use cli arguments as message if they exist
|
||||
for (int i = 0; optind + i < argc; ++i) {
|
||||
if (i) appends(&msg, " ");
|
||||
for (s = argv[optind + i]; *s; ++s) {
|
||||
if (*s == '\n') {
|
||||
appends(&msg, "\r\n\e[K");
|
||||
} else {
|
||||
appendw(&msg, *s & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise use stdin as message
|
||||
ssize_t i, rc;
|
||||
char buf[512];
|
||||
while ((rc = read(0, buf, sizeof(buf))) > 0) {
|
||||
for (i = 0; i < rc; ++i) {
|
||||
if (buf[i] == '\n') {
|
||||
appends(&msg, "\r\n\e[K"); // clear line forward
|
||||
} else {
|
||||
appendw(&msg, buf[i] & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
appends(&msg, "\r\n\e[K\e[0m\e8"); // restore
|
||||
|
||||
// try to send message to all pseudoteletypewriters
|
||||
for (int i = 0;; ++i) {
|
||||
int fd;
|
||||
char pts[32];
|
||||
snprintf(pts, sizeof(pts), "/dev/pts/%d", i);
|
||||
if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) {
|
||||
if (errno == ENOENT) break;
|
||||
if (g_verbose) perror(pts);
|
||||
}
|
||||
write(fd, msg, appendz(msg).i);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_AR_H_
|
||||
#define COSMOPOLITAN_LIBC_AR_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define ARMAG "!<arch>\n"
|
||||
#define SARMAG 8
|
||||
#define ARFMAG "`\n"
|
||||
|
||||
struct ar_hdr {
|
||||
char ar_name[16];
|
||||
char ar_date[12];
|
||||
char ar_uid[6], ar_gid[6];
|
||||
char ar_mode[8];
|
||||
char ar_size[10];
|
||||
char ar_fmag[2];
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_AR_H_ */
|
||||
+51
-10
@@ -4,7 +4,7 @@
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern bool __assert_disable;
|
||||
void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
void __assert_fail(const char *, const char *, int) _Hide relegated;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define assert(x) ((void)0)
|
||||
@@ -16,19 +16,60 @@ void __assert_fail(const char *, const char *, int) hidden relegated;
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#define _unassert(x) \
|
||||
do { \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if !defined(TINY) && !defined(MODE_DBG)
|
||||
/**
|
||||
* Specifies expression can't possibly be false.
|
||||
*
|
||||
* This macro uses the `notpossible` keyword and is intended for things
|
||||
* like systems integration, where we know for a fact that something is
|
||||
* never going to happen, but there's no proof. So we don't want to add
|
||||
* extra bloat for filenames and line numbers, since `ShowCrashReports`
|
||||
* can print a backtrace if we just embed the UD2 instruction to crash.
|
||||
* That's useful for systems code, for the following reason. Invariants
|
||||
* make sense with _unassert() since they usually get placed at the top
|
||||
* of functions. But if you used _unassert() to test a system call does
|
||||
* not fail, then check happens at the end of your function usually and
|
||||
* is therefore likely to result in a failure condition where execution
|
||||
* falls through into a different function, which is shocking to debug.
|
||||
*
|
||||
* In `MODE=tiny` these assertions are redefined as undefined behavior.
|
||||
*/
|
||||
#define _npassert(x) \
|
||||
do { \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
notpossible; \
|
||||
} \
|
||||
} while (0)
|
||||
(void)0; \
|
||||
})
|
||||
#else
|
||||
#define _npassert(x) _unassert(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
/**
|
||||
* Specifies expression being false is undefined behavior.
|
||||
*
|
||||
* This is a good way to tell the compiler about your invariants, which
|
||||
* leads to smaller faster programs. The expression is never removed by
|
||||
* the preprocessor so it's recommended that it be free of side-effects
|
||||
* if you intend for it to be removed. At the same time, this guarantee
|
||||
* makes this assertion useful for things like system calls, since they
|
||||
* won't be removed by `NDEBUG` mode.
|
||||
*
|
||||
* If this assertion fails, the worst possible things can happen unless
|
||||
* you've built your binary in `MODE=dbg` since UBSAN is the only thing
|
||||
* that's capable of debugging this macro.
|
||||
*/
|
||||
#define _unassert(x) \
|
||||
({ \
|
||||
if (__builtin_expect(!(x), 0)) { \
|
||||
unreachable; \
|
||||
} \
|
||||
(void)0; \
|
||||
})
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/sig.internal.h"
|
||||
|
||||
bool __time_critical;
|
||||
struct Signals __sig;
|
||||
@@ -16,26 +16,23 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/sections.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||
* @threadsafe
|
||||
*/
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
@@ -61,6 +58,18 @@ static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
static inline textwindows int __sig_is_masked(int sig) {
|
||||
if (__tls_enabled) {
|
||||
return __get_tls()->tib_sigmask & (1ull << (sig - 1));
|
||||
} else {
|
||||
return __sig.sigmask & (1ull << (sig - 1));
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int __sig_is_applicable(struct Signal *s) {
|
||||
return s->tid <= 0 || s->tid == gettid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
@@ -70,7 +79,7 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (__sig_is_applicable(res) && !__sig_is_masked(res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
@@ -78,8 +87,6 @@ static textwindows struct Signal *__sig_remove(void) {
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%G is masked", res->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
@@ -101,7 +108,6 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
STRACE("delivering %G", sig);
|
||||
|
||||
// enter the signal
|
||||
__sig_lock();
|
||||
rva = __sighandrvas[sig];
|
||||
flags = __sighandflags[sig];
|
||||
if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
|
||||
@@ -112,12 +118,11 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// signal handler. in that case you must use SA_NODEFER.
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
__sig_unlock();
|
||||
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
__repstosb(&info, 0, sizeof(info));
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
@@ -134,7 +139,9 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
// since sigaction() is @asyncsignalsafe we only restore it if the
|
||||
// user didn't change it during the signal handler. we also don't
|
||||
// need to do anything if this was a oneshot signal or nodefer.
|
||||
_lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
if (__sighandrvas[sig] == (int32_t)(intptr_t)SIG_DFL) {
|
||||
__sighandrvas[sig] = rva;
|
||||
}
|
||||
}
|
||||
|
||||
if (!restartable) {
|
||||
@@ -150,7 +157,7 @@ static bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
static textwindows bool __sig_is_fatal(int sig) {
|
||||
if (sig == SIGCHLD || sig == SIGURG || sig == SIGWINCH) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -168,7 +175,7 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
if (__sig_is_fatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
_Exitr(128 + sig);
|
||||
}
|
||||
@@ -194,20 +201,18 @@ bool __sig_handle(bool restartable, int sig, int si_code, ucontext_t *ctx) {
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
__sig_lock();
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
__sig_unlock();
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (!__sig_is_masked(sig)) {
|
||||
++__sig_count;
|
||||
// TODO(jart): ucontext_t support
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
} else {
|
||||
STRACE("%G is masked", sig);
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
return __sig_add(gettid(), sig, si_code);
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,18 +221,19 @@ textwindows int __sig_raise(int sig, int si_code) {
|
||||
* @return 0 on success, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
textwindows int __sig_add(int tid, int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
__sig_lock();
|
||||
if (1 <= sig && sig <= 64) {
|
||||
if (__sighandrvas[sig] == (unsigned)(intptr_t)SIG_IGN) {
|
||||
STRACE("ignoring %G", sig);
|
||||
rc = 0;
|
||||
} else {
|
||||
STRACE("enqueuing %G", sig);
|
||||
__sig_lock();
|
||||
++__sig_count;
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->tid = tid;
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
@@ -236,8 +242,8 @@ textwindows int __sig_add(int sig, int si_code) {
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
__sig_unlock();
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
@@ -276,7 +282,7 @@ textwindows bool __sig_check(bool restartable) {
|
||||
textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
struct Signal *cur, *prev, *next;
|
||||
if (rva != (unsigned)(intptr_t)SIG_IGN &&
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_isfatal(sig))) {
|
||||
(rva != (unsigned)(intptr_t)SIG_DFL || __sig_is_fatal(sig))) {
|
||||
return;
|
||||
}
|
||||
if (__sig.queue) {
|
||||
@@ -298,25 +304,3 @@ textwindows void __sig_check_ignore(const int sig, const unsigned rva) {
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *cur;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (cur = __sig.queue; cur; cur = cur->next) {
|
||||
if (__sighandrvas[cur->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
pending->__bits[(cur->sig - 1) >> 6] |= (1ull << ((cur->sig - 1) & 63));
|
||||
} else {
|
||||
STRACE("%G is ignored", cur->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
@@ -16,50 +16,45 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||
* @threadsafe
|
||||
*/
|
||||
#define GetSigBit(x) (1ull << (((x)-1) & 63))
|
||||
|
||||
struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
#define GetSigBit(XXSIG) (1ull << (((XXSIG)-1) & 63))
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
|
||||
int i;
|
||||
uint64_t a, b;
|
||||
uint64_t x, y, *mask;
|
||||
if (how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK) {
|
||||
__sig_lock();
|
||||
if (__tls_enabled) {
|
||||
mask = &__get_tls()->tib_sigmask;
|
||||
} else {
|
||||
mask = &__sig.sigmask;
|
||||
}
|
||||
if (old) {
|
||||
*old = __sig.mask;
|
||||
old->__bits[0] = *mask;
|
||||
old->__bits[1] = 0;
|
||||
}
|
||||
if (neu) {
|
||||
for (i = 0; i < ARRAYLEN(__sig.mask.__bits); ++i) {
|
||||
if (how == SIG_BLOCK) {
|
||||
__sig.mask.__bits[i] |= neu->__bits[i];
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
__sig.mask.__bits[i] &= ~neu->__bits[i];
|
||||
} else {
|
||||
__sig.mask.__bits[i] = neu->__bits[i];
|
||||
}
|
||||
x = *mask;
|
||||
y = neu->__bits[0];
|
||||
if (how == SIG_BLOCK) {
|
||||
x |= y;
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
x &= ~y;
|
||||
} else {
|
||||
x = y;
|
||||
}
|
||||
__sig.mask.__bits[0] &= ~(GetSigBit(SIGKILL) | GetSigBit(SIGSTOP));
|
||||
x &= ~(0
|
||||
#define M(x) | GetSigBit(x)
|
||||
#include "libc/intrin/sigisprecious.inc"
|
||||
);
|
||||
*mask = x;
|
||||
}
|
||||
__sig_unlock();
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
#undef GetSigBit
|
||||
@@ -0,0 +1,43 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
|
||||
/**
|
||||
* Determines the pending signals on New Technology.
|
||||
*
|
||||
* @param pending is to hold the pending signals
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows void __sig_pending(sigset_t *pending) {
|
||||
struct Signal *s;
|
||||
sigemptyset(pending);
|
||||
if (__sig.queue) {
|
||||
__sig_lock();
|
||||
for (s = __sig.queue; s; s = s->next) {
|
||||
if (__sig_is_applicable(s) &&
|
||||
__sighandrvas[s->sig] != (unsigned)(intptr_t)SIG_IGN) {
|
||||
sigaddset(pending, s->sig);
|
||||
}
|
||||
}
|
||||
__sig_unlock();
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -22,9 +22,14 @@
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
*
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* faccessat(AT_FDCWD, path, mode, 0);
|
||||
*
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @return 0 if ok, or -1 w/ errno
|
||||
* @see faccessat() for further documentation
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
|
||||
+1
-3
@@ -32,12 +32,10 @@
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
unsigned alarm(unsigned seconds) {
|
||||
int rc;
|
||||
struct itimerval it;
|
||||
bzero(&it, sizeof(it));
|
||||
it.it_value.tv_sec = seconds;
|
||||
rc = setitimer(ITIMER_REAL, &it, &it);
|
||||
assert(rc != -1);
|
||||
_npassert(!setitimer(ITIMER_REAL, &it, &it));
|
||||
if (!it.it_value.tv_sec && !it.it_value.tv_usec) {
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
@@ -14,6 +15,10 @@ forceinline bool __asan_is_valid_timespec(const struct timespec *ts) {
|
||||
return zf;
|
||||
}
|
||||
|
||||
forceinline bool __asan_is_valid_timeval(const struct timeval *tv) {
|
||||
return __asan_is_valid_timespec((const struct timespec *)tv);
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_
|
||||
#include "libc/thread/thread.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_CANCELLATIONS \
|
||||
do { \
|
||||
int _CancelState; \
|
||||
_CancelState = _pthread_block_cancellations()
|
||||
|
||||
#define ALLOW_CANCELLATIONS \
|
||||
_pthread_allow_cancellations(_CancelState); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int _pthread_block_cancellations(void);
|
||||
void _pthread_allow_cancellations(int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKCANCEL_H_ */
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define BLOCK_SIGNALS \
|
||||
do { \
|
||||
sigset_t _SigMask; \
|
||||
_SigMask = _sigblockall()
|
||||
|
||||
#define ALLOW_SIGNALS \
|
||||
_sigsetmask(_SigMask); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_BLOCKSIGS_H_ */
|
||||
+56
-55
@@ -35,11 +35,10 @@
|
||||
#define WIFCONTINUED(s) ((s) == 0xffff)
|
||||
#define WIFEXITED(s) (!WTERMSIG(s))
|
||||
#define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu)
|
||||
#define WIFSTOPPED(s) \
|
||||
((short)(((0xffff & (unsigned)(s)) * 0x10001) >> 8) > 0x7f00)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WTERMSIG(s) (127 & (s))
|
||||
#define W_STOPCODE(s) ((s) << 8 | 0177)
|
||||
#define WIFSTOPPED(s) ((255 & (s)) == 127)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WTERMSIG(s) (127 & (s))
|
||||
#define W_STOPCODE(s) ((s) << 8 | 0177)
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
@@ -65,13 +64,13 @@ char *ttyname(int);
|
||||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chmod(const char *, unsigned);
|
||||
int chown(const char *, unsigned, unsigned);
|
||||
int chroot(const char *);
|
||||
int close(int);
|
||||
int close_range(unsigned, unsigned, unsigned);
|
||||
int closefrom(int);
|
||||
int creat(const char *, uint32_t);
|
||||
int creat(const char *, unsigned);
|
||||
int dup(int);
|
||||
int dup2(int, int);
|
||||
int dup3(int, int, int);
|
||||
@@ -84,24 +83,22 @@ int execv(const char *, char *const[]);
|
||||
int execve(const char *, char *const[], char *const[]);
|
||||
int execvp(const char *, char *const[]);
|
||||
int execvpe(const char *, char *const[], char *const[]);
|
||||
int faccessat(int, const char *, int, uint32_t);
|
||||
int faccessat(int, const char *, int, int);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, uint32_t) dontthrow;
|
||||
int fchmodat(int, const char *, uint32_t, int);
|
||||
int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
int fchmod(int, unsigned) dontthrow;
|
||||
int fchmodat(int, const char *, unsigned, int);
|
||||
int fchown(int, unsigned, unsigned);
|
||||
int fchownat(int, const char *, unsigned, unsigned, int);
|
||||
int fcntl(int, int, ...);
|
||||
int fdatasync(int);
|
||||
int fexecve(int, char *const[], char *const[]);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
int getdomainname(char *, size_t);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
int getgroups(int size, uint32_t list[]);
|
||||
int getgroups(int, unsigned[]);
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int) libcesque;
|
||||
@@ -109,35 +106,29 @@ int getpgrp(void) nosideeffect;
|
||||
int getpid(void) nosideeffect libcesque;
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresgid(unsigned *, unsigned *, unsigned *);
|
||||
int getresuid(unsigned *, unsigned *, unsigned *);
|
||||
int getsid(int) nosideeffect libcesque;
|
||||
int gettid(void) libcesque;
|
||||
uint32_t getuid(void) libcesque;
|
||||
int sys_iopl(int);
|
||||
int ioprio_get(int, int);
|
||||
int ioprio_set(int, int, int);
|
||||
int issetugid(void);
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int lchmod(const char *, uint32_t);
|
||||
int lchown(const char *, uint32_t, uint32_t);
|
||||
int lchmod(const char *, unsigned);
|
||||
int lchown(const char *, unsigned, unsigned);
|
||||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int makedirs(const char *, unsigned);
|
||||
int memfd_create(const char *, unsigned int);
|
||||
int mincore(void *, size_t, unsigned char *);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
int mkfifo(const char *, uint32_t);
|
||||
int mkfifoat(int, const char *, uint32_t);
|
||||
int mknod(const char *, uint32_t, uint64_t);
|
||||
int mknodat(int, const char *, int32_t, uint64_t);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int mkdir(const char *, unsigned);
|
||||
int mkdirat(int, const char *, unsigned);
|
||||
int mkfifo(const char *, unsigned);
|
||||
int mkfifoat(int, const char *, unsigned);
|
||||
int mknod(const char *, unsigned, uint64_t);
|
||||
int mknodat(int, const char *, int, uint64_t);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openat(int, const char *, int, ...);
|
||||
@@ -147,7 +138,7 @@ int pipe(int[hasatleast 2]);
|
||||
int pipe2(int[hasatleast 2], int);
|
||||
int pivot_root(const char *, const char *);
|
||||
int pledge(const char *, const char *);
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_fadvise(int, int64_t, int64_t, int);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
int prctl(int, ...);
|
||||
int raise(int);
|
||||
@@ -159,36 +150,42 @@ int renameat2(long, const char *, long, const char *, int);
|
||||
int rmdir(const char *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int setegid(uint32_t);
|
||||
int seteuid(uint32_t);
|
||||
int setfsgid(int);
|
||||
int setfsuid(int);
|
||||
int setgid(int);
|
||||
int setgroups(size_t size, const uint32_t list[]);
|
||||
int setegid(unsigned);
|
||||
int seteuid(unsigned);
|
||||
int setfsgid(unsigned);
|
||||
int setfsuid(unsigned);
|
||||
int setgid(unsigned);
|
||||
int setgroups(size_t, const unsigned[]);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
int setregid(uint32_t, uint32_t);
|
||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||
int setreuid(uint32_t, uint32_t);
|
||||
int setregid(unsigned, unsigned);
|
||||
int setresgid(unsigned, unsigned, unsigned);
|
||||
int setresuid(unsigned, unsigned, unsigned);
|
||||
int setreuid(unsigned, unsigned);
|
||||
int setsid(void);
|
||||
int setuid(int);
|
||||
int setuid(unsigned);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
int sys_iopl(int);
|
||||
int sys_mlock(const void *, size_t);
|
||||
int sys_mlock2(const void *, size_t, int);
|
||||
int sys_mlockall(int);
|
||||
int sys_munlock(const void *, size_t);
|
||||
int sys_munlockall(void);
|
||||
int sys_ptrace(int, ...);
|
||||
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int tcgetpgrp(int);
|
||||
int tcsetpgrp(int, int);
|
||||
int tgkill(int, int, int);
|
||||
int tkill(int, int);
|
||||
int tmpfd(void);
|
||||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int touch(const char *, unsigned);
|
||||
int truncate(const char *, int64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int umask(int);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
int unlinkat(int, const char *, int);
|
||||
@@ -197,21 +194,25 @@ int usleep(unsigned);
|
||||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
int32_t tcgetpgrp(int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, unsigned);
|
||||
ssize_t lseek(int, int64_t, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
ssize_t pwrite(int, const void *, size_t, int64_t);
|
||||
ssize_t read(int, void *, size_t);
|
||||
ssize_t readansi(int, char *, size_t);
|
||||
ssize_t readlink(const char *, char *, size_t);
|
||||
ssize_t readlinkat(int, const char *, char *, size_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
unsigned getegid(void) nosideeffect;
|
||||
unsigned geteuid(void) nosideeffect;
|
||||
unsigned getgid(void) nosideeffect;
|
||||
unsigned getuid(void) libcesque;
|
||||
unsigned umask(unsigned);
|
||||
void sync(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
||||
+17
-16
@@ -65,6 +65,13 @@ $(LIBC_CALLS_A).pkg: \
|
||||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
# we can't use asan because:
|
||||
# siginfo_t memory is owned by kernels
|
||||
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we can't use asan because:
|
||||
# ucontext_t memory is owned by xnu kernel
|
||||
o/$(MODE)/libc/calls/sigenter-xnu.o: private \
|
||||
@@ -114,21 +121,12 @@ o/$(MODE)/libc/calls/execlp.o \
|
||||
o/$(MODE)/libc/calls/statfs.o \
|
||||
o/$(MODE)/libc/calls/fstatfs.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/execve-nt.greg.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: private \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
# we must disable static stack safety because:
|
||||
# PATH_MAX*sizeof(char16_t)*2 exceeds 4096 byte frame limit
|
||||
o/$(MODE)/libc/calls/copyfile.o \
|
||||
o/$(MODE)/libc/calls/symlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/linkat-nt.o \
|
||||
o/$(MODE)/libc/calls/renameat-nt.o: private \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
# we must segregate codegen because:
|
||||
# file contains multiple independently linkable apis
|
||||
o/$(MODE)/libc/calls/ioctl-siocgifconf.o \
|
||||
@@ -172,12 +170,15 @@ o//libc/calls/statfs2cosmo.o: private \
|
||||
# we always want -O2 because:
|
||||
# division is expensive if not optimized
|
||||
o/$(MODE)/libc/calls/clock.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/_timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/_timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/_timespec_frommicros.o: private \
|
||||
o/$(MODE)/libc/calls/timespec_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_tomicros.o \
|
||||
o/$(MODE)/libc/calls/timespec_totimeval.o \
|
||||
o/$(MODE)/libc/calls/timespec_fromnanos.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timespec_frommicros.o \
|
||||
o/$(MODE)/libc/calls/timeval_tomillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommillis.o \
|
||||
o/$(MODE)/libc/calls/timeval_frommicros.o: private \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-O2
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int cfsetispeed(struct termios *t, int speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (speed & ~CBAUD) return einval();
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -20,7 +20,59 @@
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int cfsetospeed(struct termios *t, int speed) {
|
||||
/**
|
||||
* Returns input baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetispeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ispeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns output baud rate.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
uint32_t cfgetospeed(const struct termios *t) {
|
||||
if (CBAUD) {
|
||||
return t->c_cflag & CBAUD;
|
||||
} else {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets input baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetispeed(struct termios *t, unsigned speed) {
|
||||
if (speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
t->c_cflag |= speed;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
t->c_ispeed = speed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output baud rate.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int cfsetospeed(struct termios *t, unsigned speed) {
|
||||
if (CBAUD) {
|
||||
if (!(speed & ~CBAUD)) {
|
||||
t->c_cflag &= ~CBAUD;
|
||||
+4
-2
@@ -16,11 +16,12 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,8 @@
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
int rc;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
GetProgramExecutableName(); // XXX: ugly workaround
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_chdir(path);
|
||||
|
||||
+28
-2
@@ -17,17 +17,43 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes root directory.
|
||||
*
|
||||
* Please consider using unveil() instead of chroot(). If you use this
|
||||
* system call then consider using both chdir() and closefrom() before
|
||||
* calling this function. Otherwise there's a small risk that fchdir()
|
||||
* could be used to escape the chroot() environment. Cosmopolitan Libc
|
||||
* focuses on static binaries which make chroot() infinitely easier to
|
||||
* use since you don't need to construct an entire userspace each time
|
||||
* however unveil() is still better to use on modern Linux and OpenBSD
|
||||
* because it doesn't require root privileges.
|
||||
*
|
||||
* @param path shall become the new root directory
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EACCES if we don't have permission to search a component of `path`
|
||||
* @raise ENOTDIR if a directory component in `path` exists as non-directory
|
||||
* @raise ENAMETOOLONG if symlink-resolved `path` length exceeds `PATH_MAX`
|
||||
* @raise ENAMETOOLONG if component in `path` exists longer than `NAME_MAX`
|
||||
* @raise EPERM if not root or pledge() is in play
|
||||
* @raise EIO if a low-level i/o error occurred
|
||||
* @raise EFAULT if `path` is bad memory
|
||||
* @raise ENOENT if `path` doesn't exist
|
||||
* @raise ENOSYS on Windows
|
||||
*/
|
||||
int chroot(const char *path) {
|
||||
int rc;
|
||||
rc = sys_chroot(path);
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
rc = sys_chroot(path);
|
||||
}
|
||||
STRACE("chroot(%s) → %d% m", path, rc);
|
||||
return rc;
|
||||
}
|
||||
+1
-1
@@ -55,7 +55,7 @@ int64_t clock(void) {
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == -1) {
|
||||
errno = e;
|
||||
if (getrusage(RUSAGE_SELF, &ru) != -1) {
|
||||
ts = _timeval_totimespec(_timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
ts = timeval_totimespec(timeval_add(ru.ru_utime, ru.ru_stime));
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/time.h"
|
||||
@@ -49,6 +49,12 @@ static int sys_clock_getres_xnu(int clock, struct timespec *ts) {
|
||||
|
||||
/**
|
||||
* Returns granularity of clock.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EPERM if pledge() is in play without stdio promise
|
||||
* @error EINVAL if `clock` isn't supported on this system
|
||||
* @error EFAULT if `ts` points to bad memory
|
||||
* @threadsafe
|
||||
*/
|
||||
int clock_getres(int clock, struct timespec *ts) {
|
||||
int rc;
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
static struct {
|
||||
pthread_once_t once;
|
||||
@@ -30,7 +30,7 @@ static struct {
|
||||
} g_mono;
|
||||
|
||||
static void sys_clock_gettime_mono_init(void) {
|
||||
g_mono.base_wall = _timespec_real();
|
||||
g_mono.base_wall = timespec_real();
|
||||
g_mono.base_tick = rdtsc();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ int sys_clock_gettime_mono(struct timespec *time) {
|
||||
pthread_once(&g_mono.once, sys_clock_gettime_mono_init);
|
||||
cycles = rdtsc() - g_mono.base_tick;
|
||||
nanos = cycles / 3;
|
||||
*time = _timespec_add(g_mono.base_wall, _timespec_fromnanos(nanos));
|
||||
*time = timespec_add(g_mono.base_wall, timespec_fromnanos(nanos));
|
||||
return 0;
|
||||
} else {
|
||||
return einval();
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/clock_gettime.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/syscall_support-sysv.internal.h"
|
||||
@@ -30,9 +29,11 @@
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
@@ -48,12 +49,33 @@
|
||||
* __clock_gettime l: 35𝑐 11𝑛𝑠
|
||||
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
|
||||
*
|
||||
* @param clock can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
|
||||
* @param clock can be one of:
|
||||
* - `CLOCK_REALTIME`: universally supported
|
||||
* - `CLOCK_REALTIME_FAST`: ditto but faster on freebsd
|
||||
* - `CLOCK_REALTIME_PRECISE`: ditto but better on freebsd
|
||||
* - `CLOCK_REALTIME_COARSE`: : like `CLOCK_REALTIME_FAST` w/ Linux 2.6.32+
|
||||
* - `CLOCK_MONOTONIC`: universally supported
|
||||
* - `CLOCK_MONOTONIC_FAST`: ditto but faster on freebsd
|
||||
* - `CLOCK_MONOTONIC_PRECISE`: ditto but better on freebsd
|
||||
* - `CLOCK_MONOTONIC_COARSE`: : like `CLOCK_MONOTONIC_FAST` w/ Linux 2.6.32+
|
||||
* - `CLOCK_MONOTONIC_RAW`: is actually monotonic but needs Linux 2.6.28+
|
||||
* - `CLOCK_PROCESS_CPUTIME_ID`: linux and bsd
|
||||
* - `CLOCK_THREAD_CPUTIME_ID`: linux and bsd
|
||||
* - `CLOCK_MONOTONIC_COARSE`: linux, freebsd
|
||||
* - `CLOCK_PROF`: linux and netbsd
|
||||
* - `CLOCK_BOOTTIME`: linux and openbsd
|
||||
* - `CLOCK_REALTIME_ALARM`: linux-only
|
||||
* - `CLOCK_BOOTTIME_ALARM`: linux-only
|
||||
* - `CLOCK_TAI`: linux-only
|
||||
* @param ts is where the result is stored
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINVAL if clock isn't supported on this system
|
||||
* @error EPERM if pledge() is in play without stdio promise
|
||||
* @error EINVAL if `clock` isn't supported on this system
|
||||
* @error EFAULT if `ts` points to bad memory
|
||||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int clock_gettime(int clock, struct timespec *ts) {
|
||||
int rc;
|
||||
@@ -65,7 +87,7 @@ int clock_gettime(int clock, struct timespec *ts) {
|
||||
rc = __clock_gettime(clock, ts);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!__time_critical) {
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_gettime(%s, [%s]) → %d% m", DescribeClockName(clock),
|
||||
DescribeTimespec(rc, ts), rc);
|
||||
}
|
||||
@@ -97,7 +119,7 @@ clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) {
|
||||
return res;
|
||||
}
|
||||
|
||||
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
|
||||
_Hide int __clock_gettime_init(int clockid, struct timespec *ts) {
|
||||
clock_gettime_f *gettime;
|
||||
__clock_gettime = gettime = __clock_gettime_get(0);
|
||||
return gettime(clockid, ts);
|
||||
|
||||
@@ -7,9 +7,9 @@ COSMOPOLITAN_C_START_
|
||||
typedef int clock_gettime_f(int, struct timespec *);
|
||||
|
||||
extern clock_gettime_f *__clock_gettime;
|
||||
clock_gettime_f *__clock_gettime_get(bool *) hidden;
|
||||
int __clock_gettime_init(int, struct timespec *) hidden;
|
||||
int sys_clock_gettime_mono(struct timespec *) hidden;
|
||||
clock_gettime_f *__clock_gettime_get(bool *) _Hide;
|
||||
int __clock_gettime_init(int, struct timespec *) _Hide;
|
||||
int sys_clock_gettime_mono(struct timespec *) _Hide;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_clock_nanosleep_nt(int clock, int flags,
|
||||
const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
struct timespec now, abs;
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = *req;
|
||||
for (;;) {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) return -1;
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
if (sys_clock_gettime_nt(clock, &now)) return -1;
|
||||
abs = timespec_add(now, *req);
|
||||
for (;;) {
|
||||
sys_clock_gettime_nt(clock, &now);
|
||||
if (timespec_cmp(now, abs) >= 0) return 0;
|
||||
if (_check_interrupts(false, g_fds.p)) {
|
||||
if (rem) *rem = timespec_sub(abs, now);
|
||||
return -1;
|
||||
}
|
||||
SleepEx(MIN(__SIG_POLLING_INTERVAL_MS,
|
||||
timespec_tomillis(timespec_sub(abs, now))),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_clock_nanosleep_openbsd(int clock, int flags,
|
||||
const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int res;
|
||||
struct timespec now, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (!flags) {
|
||||
res = sys_nanosleep(req, rem);
|
||||
} else {
|
||||
sys_clock_gettime(clock, &now);
|
||||
if (timespec_cmp(*req, now) > 0) {
|
||||
rel = timespec_sub(*req, now);
|
||||
res = sys_nanosleep(&rel, 0);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = enotsup();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
@@ -16,21 +16,34 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_utimes_nt(const char *path, const struct timeval tv[2]) {
|
||||
struct timespec ts[2];
|
||||
if (tv) {
|
||||
ts[0].tv_sec = tv[0].tv_sec;
|
||||
ts[0].tv_nsec = tv[0].tv_usec * 1000;
|
||||
ts[1].tv_sec = tv[1].tv_sec;
|
||||
ts[1].tv_nsec = tv[1].tv_usec * 1000;
|
||||
return sys_utimensat_nt(AT_FDCWD, path, ts, 0);
|
||||
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int res;
|
||||
struct timeval now, abs, rel;
|
||||
if (clock == CLOCK_REALTIME) {
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
abs = timespec_totimeval(*req);
|
||||
sys_gettimeofday_xnu(&now, 0, 0);
|
||||
if (timeval_cmp(abs, now) > 0) {
|
||||
rel = timeval_sub(abs, now);
|
||||
res = sys_select(0, 0, 0, 0, &rel);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
res = sys_nanosleep_xnu(req, rem);
|
||||
}
|
||||
} else {
|
||||
return sys_utimensat_nt(AT_FDCWD, path, NULL, 0);
|
||||
res = enotsup();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/clock_gettime.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timespec.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/timeval.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/ntdll.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/sysv/consts/timer.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
static int64_t g_nanosleep_latency;
|
||||
|
||||
static errno_t sys_clock_nanosleep(int clock, int flags,
|
||||
const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int e, rc;
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
e = errno;
|
||||
if (IsLinux() || IsFreebsd() || IsNetbsd()) {
|
||||
rc = __sys_clock_nanosleep(clock, flags, req, rem);
|
||||
} else if (IsXnu()) {
|
||||
rc = sys_clock_nanosleep_xnu(clock, flags, req, rem);
|
||||
} else if (IsOpenbsd()) {
|
||||
rc = sys_clock_nanosleep_openbsd(clock, flags, req, rem);
|
||||
} else {
|
||||
rc = sys_clock_nanosleep_nt(clock, flags, req, rem);
|
||||
}
|
||||
if (rc == -1) {
|
||||
rc = errno;
|
||||
errno = e;
|
||||
}
|
||||
END_CANCELLATION_POINT;
|
||||
return rc;
|
||||
}
|
||||
|
||||
// determine sched_yield() vs. clock_nanosleep() threshold
|
||||
// 1ns sys_clock_nanosleep() on Windows takes milliseconds :'(
|
||||
// 1ns sys_clock_nanosleep() on Linux/FreeBSD takes tens of microseconds
|
||||
// 1ns sys_clock_nanosleep() on OpenBSD/NetBSD takes tens of milliseconds D:
|
||||
static struct timespec GetNanosleepLatency(void) {
|
||||
errno_t rc;
|
||||
int64_t nanos;
|
||||
clock_gettime_f *cgt;
|
||||
struct timespec x, y, w = {0, 1};
|
||||
if (!(nanos = g_nanosleep_latency)) {
|
||||
BLOCK_CANCELLATIONS;
|
||||
for (cgt = __clock_gettime_get(0);;) {
|
||||
_npassert(!cgt(CLOCK_REALTIME_PRECISE, &x));
|
||||
rc = sys_clock_nanosleep(CLOCK_REALTIME, 0, &w, 0);
|
||||
_npassert(!rc || rc == EINTR);
|
||||
if (!rc) {
|
||||
_npassert(!cgt(CLOCK_REALTIME_PRECISE, &y));
|
||||
nanos = timespec_tonanos(timespec_sub(y, x));
|
||||
g_nanosleep_latency = nanos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
}
|
||||
return timespec_fromnanos(nanos);
|
||||
}
|
||||
|
||||
static errno_t CheckCancel(void) {
|
||||
if (_weaken(pthread_testcancel_np)) {
|
||||
return _weaken(pthread_testcancel_np)();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static errno_t SpinNanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
errno_t rc;
|
||||
clock_gettime_f *cgt;
|
||||
struct timespec now, start, elapsed;
|
||||
if ((rc = CheckCancel())) {
|
||||
if (rc == EINTR && !flags && rem) {
|
||||
*rem = *req;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
cgt = __clock_gettime_get(0);
|
||||
_npassert(!cgt(CLOCK_REALTIME, &start));
|
||||
for (;;) {
|
||||
sched_yield();
|
||||
_npassert(!cgt(CLOCK_REALTIME, &now));
|
||||
if (flags & TIMER_ABSTIME) {
|
||||
if (timespec_cmp(now, *req) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((rc = CheckCancel())) {
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
if (timespec_cmp(now, start) < 0) continue;
|
||||
elapsed = timespec_sub(now, start);
|
||||
if ((rc = CheckCancel())) {
|
||||
if (rc == EINTR && rem) {
|
||||
if (timespec_cmp(elapsed, *req) >= 0) {
|
||||
bzero(rem, sizeof(*rem));
|
||||
} else {
|
||||
*rem = elapsed;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if (timespec_cmp(elapsed, *req) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldUseSpinNanosleep(int clock, int flags,
|
||||
const struct timespec *req) {
|
||||
errno_t e;
|
||||
struct timespec now;
|
||||
if (IsWindows()) {
|
||||
// Our spin technique here is intended to take advantage of the fact
|
||||
// that sched_yield() takes about a hundred nanoseconds. But Windows
|
||||
// SleepEx(0, 0) a.k.a. NtYieldExecution() takes a whole millisecond
|
||||
// and it matters not whether our intent is to yielding or sleeping,
|
||||
// since we use the SleepEx() function to implement both. Therefore,
|
||||
// there's no reason to use SpinNanosleep() on Windows.
|
||||
return false;
|
||||
}
|
||||
if (clock != CLOCK_REALTIME && //
|
||||
clock != CLOCK_REALTIME_PRECISE && //
|
||||
clock != CLOCK_MONOTONIC && //
|
||||
clock != CLOCK_MONOTONIC_RAW && //
|
||||
clock != CLOCK_MONOTONIC_PRECISE) {
|
||||
return false;
|
||||
}
|
||||
if (!flags) {
|
||||
return timespec_cmp(*req, GetNanosleepLatency()) < 0;
|
||||
}
|
||||
// We need a clock_gettime() system call to perform this check if the
|
||||
// sleep request is an absolute timestamp. So we avoid doing that on
|
||||
// systems where sleep latency isn't too outrageous.
|
||||
if (timespec_cmp(GetNanosleepLatency(), timespec_fromnanos(50 * 1000)) < 0) {
|
||||
return false;
|
||||
}
|
||||
e = errno;
|
||||
if (__clock_gettime_get(0)(clock, &now)) {
|
||||
// punt to the nanosleep system call
|
||||
errno = e;
|
||||
return false;
|
||||
}
|
||||
return timespec_cmp(*req, now) < 0 ||
|
||||
timespec_cmp(timespec_sub(*req, now), GetNanosleepLatency()) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps for particular amount of time.
|
||||
*
|
||||
* Here's how you could sleep for one second:
|
||||
*
|
||||
* clock_nanosleep(0, 0, &(struct timespec){1}, 0);
|
||||
*
|
||||
* Your sleep will be interrupted automatically if you do something like
|
||||
* press ctrl-c during the wait. That's an `EINTR` error and it lets you
|
||||
* immediately react to status changes. This is always the case, even if
|
||||
* you're using `SA_RESTART` since this is a `@norestart` system call.
|
||||
*
|
||||
* void OnCtrlC(int sig) {} // EINTR only happens after delivery
|
||||
* signal(SIGINT, OnCtrlC); // do delivery rather than kill proc
|
||||
* printf("save me from sleeping forever by pressing ctrl-c\n");
|
||||
* clock_nanosleep(0, 0, &(struct timespec){INT_MAX}, 0);
|
||||
* printf("you're my hero\n");
|
||||
*
|
||||
* If you want to perform an uninterruptible sleep without having to use
|
||||
* sigprocmask() to block all signals then this function provides a good
|
||||
* solution to that problem. For example:
|
||||
*
|
||||
* struct timespec rel, now, abs;
|
||||
* clock_gettime(CLOCK_REALTIME, &now);
|
||||
* rel = timespec_frommillis(100);
|
||||
* abs = timespec_add(now, rel);
|
||||
* while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &abs, 0));
|
||||
*
|
||||
* will accurately spin on `EINTR` errors. That way you're not impeding
|
||||
* signal delivery and you're not losing precision on your wait timeout.
|
||||
* This function has first-class support on Linux, FreeBSD, and NetBSD;
|
||||
* on OpenBSD it's good; on XNU it's bad; and on Windows it's ugly.
|
||||
*
|
||||
* @param clock should be `CLOCK_REALTIME` and you may consult the docs
|
||||
* of your preferred platforms to see what other clocks might work
|
||||
* @param flags can be 0 for relative and `TIMER_ABSTIME` for absolute
|
||||
* @param req can be a relative or absolute time, depending on `flags`
|
||||
* @param rem shall be updated with the remainder of unslept time when
|
||||
* (1) it's non-null; (2) `flags` is 0; and (3) -1 w/ `EINTR` is
|
||||
* returned; if this function returns 0 then `rem` is undefined;
|
||||
* if flags is `TIMER_ABSTIME` then `rem` is ignored
|
||||
* @return 0 on success, or errno on error
|
||||
* @raise EINTR when a signal got delivered while we were waiting
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise ENOTSUP if `clock` is known but we can't use it here
|
||||
* @raise EFAULT if `req` or null or bad memory was passed
|
||||
* @raise EINVAL if `clock` is unknown to current platform
|
||||
* @raise EINVAL if `flags` has an unrecognized value
|
||||
* @raise EINVAL if `req->tv_nsec ∉ [0,1000000000)`
|
||||
* @raise ENOSYS on bare metal
|
||||
* @cancellationpoint
|
||||
* @returnserrno
|
||||
* @norestart
|
||||
*/
|
||||
errno_t clock_nanosleep(int clock, int flags, const struct timespec *req,
|
||||
struct timespec *rem) {
|
||||
int rc;
|
||||
LOCKTRACE("clock_nanosleep(%s, %s, %s) → ...", DescribeClockName(clock),
|
||||
DescribeSleepFlags(flags), DescribeTimespec(0, req));
|
||||
if (IsMetal()) {
|
||||
rc = ENOSYS;
|
||||
} else if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
||||
(rem && !__asan_is_valid_timespec(rem))))) {
|
||||
rc = EFAULT;
|
||||
} else if (clock == 127 || //
|
||||
(flags & ~TIMER_ABSTIME) || //
|
||||
req->tv_sec < 0 || //
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
rc = EINVAL;
|
||||
} else if (ShouldUseSpinNanosleep(clock, flags, req)) {
|
||||
rc = SpinNanosleep(clock, flags, req, rem);
|
||||
} else {
|
||||
rc = sys_clock_nanosleep(clock, flags, req, rem);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (__tls_enabled && !(__get_tls()->tib_flags & TIB_FLAG_TIME_CRITICAL)) {
|
||||
STRACE("clock_nanosleep(%s, %s, %s, [%s]) → %s", DescribeClockName(clock),
|
||||
DescribeSleepFlags(flags), DescribeTimespec(0, req),
|
||||
DescribeTimespec(rc, rem), DescribeErrno(rc));
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
@@ -18,15 +18,22 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd) {
|
||||
void sys_fcntl_nt_lock_cleanup(int) _Hide;
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd, int fildes) {
|
||||
int e;
|
||||
bool ok = true;
|
||||
|
||||
if (_weaken(sys_fcntl_nt_lock_cleanup)) {
|
||||
_weaken(sys_fcntl_nt_lock_cleanup)(fildes);
|
||||
}
|
||||
|
||||
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
|
||||
+19
-11
@@ -16,10 +16,10 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -32,17 +32,25 @@
|
||||
/**
|
||||
* Closes file descriptor.
|
||||
*
|
||||
* This function may be used for file descriptors returned by functions
|
||||
* like open, socket, accept, epoll_create, and landlock_create_ruleset.
|
||||
* This function releases resources returned by functions such as:
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
* that doesn't mean the error should be ignored.
|
||||
* - openat()
|
||||
* - socket()
|
||||
* - accept()
|
||||
* - epoll_create()
|
||||
* - landlock_create_ruleset()
|
||||
*
|
||||
* This function should never be reattempted if an error is returned;
|
||||
* however, that doesn't mean the error should be ignored. This goes
|
||||
* against the conventional wisdom of looping on `EINTR`.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINTR means a signal was received while closing in which case
|
||||
* close() does not need to be called again, since the fd will close
|
||||
* in the background
|
||||
* @raise EINTR if signal was delivered; do *not* retry
|
||||
* @raise EBADF if `fd` is negative or not open; however, an exception
|
||||
* is made by Cosmopolitan Libc for `close(-1)` which returns zero
|
||||
* and does nothing, in order to assist with code that may wish to
|
||||
* close the same resource multiple times without dirtying `errno`
|
||||
* @raise EIO if a low-level i/o error occurred
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
@@ -51,7 +59,7 @@ int close(int fd) {
|
||||
if (fd == -1) {
|
||||
rc = 0;
|
||||
} else if (fd < 0) {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
} else {
|
||||
// for performance reasons we want to avoid holding __fds_lock()
|
||||
// while sys_close() is happening. this leaves the kernel / libc
|
||||
@@ -73,7 +81,7 @@ int close(int fd) {
|
||||
} else if (__isfdkind(fd, kFdFile) || //
|
||||
__isfdkind(fd, kFdConsole) || //
|
||||
__isfdkind(fd, kFdProcess)) { //
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
rc = sys_close_nt(g_fds.p + fd, fd);
|
||||
} else {
|
||||
rc = eio();
|
||||
}
|
||||
|
||||
+16
-16
@@ -27,35 +27,35 @@
|
||||
/**
|
||||
* Closes extra file descriptors, e.g.
|
||||
*
|
||||
* // close all non-stdio file descriptors
|
||||
* if (closefrom(3) == -1) {
|
||||
* for (int i = 3; i < 256; ++i) {
|
||||
* if (closefrom(3))
|
||||
* for (int i = 3; i < 256; ++i)
|
||||
* close(i);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EBADF if `first` is negative
|
||||
* @error EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @error EINVAL if flags are bad or first is greater than last
|
||||
* @error EMFILE if a weird race condition happens on Linux
|
||||
* @error ENOSYS if not Linux 5.9+, FreeBSD 8+, or OpenBSD
|
||||
* @error EINTR possibly on OpenBSD
|
||||
* @error ENOMEM on Linux maybe
|
||||
* @raise EBADF if `first` is negative
|
||||
* @raise ENOSYS if not Linux 5.9+, FreeBSD 8+, OpenBSD, or NetBSD
|
||||
* @raise EBADF on OpenBSD if `first` is greater than highest fd
|
||||
* @raise EINVAL if flags are bad or first is greater than last
|
||||
* @raise EMFILE if a weird race condition happens on Linux
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINTR possibly on OpenBSD
|
||||
* @raise ENOMEM on Linux maybe
|
||||
*/
|
||||
int closefrom(int first) {
|
||||
int rc, err;
|
||||
if (IsNetbsd() || IsWindows() || IsMetal()) {
|
||||
rc = enosys();
|
||||
} else if (first < 0) {
|
||||
if (first < 0) {
|
||||
// consistent with openbsd
|
||||
// freebsd allows this but it's dangerous
|
||||
// necessary on linux due to type signature
|
||||
rc = ebadf();
|
||||
} else if (IsFreebsd() || IsOpenbsd()) {
|
||||
rc = sys_closefrom(first);
|
||||
} else if (IsLinux()) {
|
||||
rc = sys_close_range(first, 0xffffffffu, 0);
|
||||
} else if (IsNetbsd()) {
|
||||
rc = __sys_fcntl(first, 10 /*F_CLOSEM*/, first);
|
||||
} else {
|
||||
rc = sys_closefrom(first);
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("closefrom(%d) → %d% m", first, rc);
|
||||
return rc;
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
@@ -38,6 +41,7 @@ static bool HasCopyFileRange(void) {
|
||||
bool ok;
|
||||
int e, rc;
|
||||
e = errno;
|
||||
BLOCK_CANCELLATIONS;
|
||||
if (IsLinux()) {
|
||||
// We modernize our detection by a few years for simplicity.
|
||||
// This system call is chosen since it's listed by pledge().
|
||||
@@ -48,6 +52,7 @@ static bool HasCopyFileRange(void) {
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
errno = e;
|
||||
return ok;
|
||||
}
|
||||
@@ -79,6 +84,8 @@ static void copy_file_range_init(void) {
|
||||
* @raise EXDEV if source and destination are on different filesystems
|
||||
* @raise EBADF if `infd` or `outfd` aren't open files or append-only
|
||||
* @raise EPERM if `fdout` refers to an immutable file on Linux
|
||||
* @raise ENOTSUP if `infd` or `outfd` is a zip file descriptor
|
||||
* @raise ECANCELED if thread was cancelled in masked mode
|
||||
* @raise EINVAL if ranges overlap or `flags` is non-zero
|
||||
* @raise EFBIG if `setrlimit(RLIMIT_FSIZE)` is exceeded
|
||||
* @raise EFAULT if one of the pointers memory is bad
|
||||
@@ -91,12 +98,15 @@ static void copy_file_range_init(void) {
|
||||
* @raise EIO if a low-level i/o error happens
|
||||
* @see sendfile() for seekable → socket
|
||||
* @see splice() for fd ↔ pipe
|
||||
* @cancellationpoint
|
||||
*/
|
||||
ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
int64_t *opt_in_out_outoffset, size_t uptobytes,
|
||||
uint32_t flags) {
|
||||
ssize_t rc;
|
||||
pthread_once(&g_copy_file_range.once, copy_file_range_init);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!g_copy_file_range.ok) {
|
||||
rc = enosys();
|
||||
} else if (IsAsan() && ((opt_in_out_inoffset &&
|
||||
@@ -104,10 +114,14 @@ ssize_t copy_file_range(int infd, int64_t *opt_in_out_inoffset, int outfd,
|
||||
(opt_in_out_outoffset &&
|
||||
!__asan_is_valid(opt_in_out_outoffset, 8)))) {
|
||||
rc = efault();
|
||||
} else if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_copy_file_range(infd, opt_in_out_inoffset, outfd,
|
||||
opt_in_out_outoffset, uptobytes, flags);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
STRACE("copy_file_range(%d, %s, %d, %s, %'zu, %#x) → %'ld% m", infd,
|
||||
DescribeInOutInt64(rc, opt_in_out_inoffset), outfd,
|
||||
DescribeInOutInt64(rc, opt_in_out_outoffset), uptobytes, flags);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/thread/posixthread.internal.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#ifdef MODE_DBG
|
||||
|
||||
int begin_cancellation_point(void) {
|
||||
int state = 0;
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
state = pt->flags & PT_INCANCEL;
|
||||
pt->flags |= PT_INCANCEL;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
void end_cancellation_point(int state) {
|
||||
struct CosmoTib *tib;
|
||||
struct PosixThread *pt;
|
||||
if (__enable_tls) {
|
||||
tib = __get_tls();
|
||||
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
|
||||
pt->flags &= ~PT_INCANCEL;
|
||||
pt->flags |= state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void report_cancellation_point(void) {
|
||||
BLOCK_CANCELLATIONS;
|
||||
_bt("error: need BEGIN/END_CANCELLATION_POINT\n");
|
||||
ALLOW_CANCELLATIONS;
|
||||
}
|
||||
|
||||
#endif /* MODE_DBG */
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int begin_cancellation_point(void);
|
||||
void end_cancellation_point(int);
|
||||
|
||||
#ifndef MODE_DBG
|
||||
#define BEGIN_CANCELLATION_POINT (void)0
|
||||
#define END_CANCELLATION_POINT (void)0
|
||||
#else
|
||||
#define BEGIN_CANCELLATION_POINT \
|
||||
do { \
|
||||
int _Cp; \
|
||||
_Cp = begin_cancellation_point()
|
||||
#define END_CANCELLATION_POINT \
|
||||
end_cancellation_point(_Cp); \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_CP_INTERNAL_H_ */
|
||||
+12
-10
@@ -21,20 +21,22 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* Creates new file, returning open()'d file descriptor.
|
||||
* Creates file.
|
||||
*
|
||||
* This function is shorthand for:
|
||||
* This is equivalent to saying:
|
||||
*
|
||||
* open(file, O_CREAT | O_WRONLY | O_TRUNC, mode)
|
||||
* int fd = openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
*
|
||||
* @param file is a UTF-8 string, which is truncated if it exists
|
||||
* @param mode is an octal user/group/other permission, e.g. 0755
|
||||
* @return a number registered with the system to track the open file,
|
||||
* which must be stored using a 64-bit type in order to support both
|
||||
* System V and Windows, and must be closed later on using close()
|
||||
* @see open(), touch()
|
||||
* @param file specifies filesystem path to create
|
||||
* @param mode is octal bits, e.g. 0644 usually
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @see openat() for further documentation
|
||||
* @cancellationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
* @threadsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
dontdiscard int creat(const char *file, uint32_t mode) {
|
||||
int creat(const char *file, uint32_t mode) {
|
||||
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
+14
-25
@@ -31,13 +31,11 @@
|
||||
// Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
int64_t rc, proc, handle;
|
||||
_unassert(oldfd >= 0);
|
||||
_unassert(newfd >= -1);
|
||||
_unassert(!(flags & ~O_CLOEXEC));
|
||||
|
||||
__fds_lock();
|
||||
|
||||
if (oldfd >= g_fds.n ||
|
||||
if (!__isfdopen(oldfd) || newfd < -1 ||
|
||||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||
__fds_unlock();
|
||||
@@ -45,27 +43,18 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
|
||||
// allocate a new file descriptor
|
||||
for (;;) {
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
__fds_unlock();
|
||||
close(newfd);
|
||||
__fds_lock();
|
||||
}
|
||||
if (!g_fds.p[newfd].kind) {
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
break;
|
||||
}
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd_unlocked(start)) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (__ensurefds_unlocked(newfd) == -1) {
|
||||
__fds_unlock();
|
||||
return -1;
|
||||
}
|
||||
if (g_fds.p[newfd].kind) {
|
||||
sys_close_nt(g_fds.p + newfd, newfd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +75,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd_unlocked(newfd);
|
||||
__releasefd(newfd);
|
||||
rc = __winerr();
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -32,15 +32,16 @@
|
||||
*
|
||||
* @param fd remains open afterwards
|
||||
* @return some arbitrary new number for fd
|
||||
* @raise EOPNOTSUPP if zipos file
|
||||
* @raise EBADF if fd isn't open
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise ENOTSUP if `fd` is a zip file descriptor
|
||||
* @raise EBADF if `fd` is negative or not open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup(int fd) {
|
||||
int rc;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup(fd);
|
||||
} else {
|
||||
|
||||
+7
-4
@@ -18,10 +18,10 @@
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
@@ -38,16 +38,19 @@
|
||||
* @param newfd if already assigned, is silently closed beforehand;
|
||||
* unless it's equal to oldfd, in which case dup2() is a no-op
|
||||
* @return new file descriptor, or -1 w/ errno
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EMFILE if `RLIMIT_NOFILE` has been reached
|
||||
* @raise ENOTSUP if `oldfd` is on zip file system
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int dup2(int oldfd, int newfd) {
|
||||
int rc;
|
||||
if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup2(oldfd, newfd);
|
||||
} else if (newfd < 0) {
|
||||
|
||||
+7
-5
@@ -38,11 +38,13 @@
|
||||
* @param flags may have O_CLOEXEC which is needed to preserve the
|
||||
* close-on-execve() state after file descriptor duplication
|
||||
* @return newfd on success, or -1 w/ errno
|
||||
* @raise EINVAL if flags has unsupported bits
|
||||
* @raise EINVAL if newfd equals oldfd
|
||||
* @raise EBADF is oldfd isn't open
|
||||
* @raise EBADF is newfd negative or too big
|
||||
* @raise ENOTSUP if `oldfd` is a zip file descriptor
|
||||
* @raise EPERM if pledge() is in play without stdio
|
||||
* @raise EINVAL if `flags` has unsupported bits
|
||||
* @raise EINTR if a signal handler was called
|
||||
* @raise EBADF is `newfd` negative or too big
|
||||
* @raise EINVAL if `newfd` equals oldfd
|
||||
* @raise EBADF is `oldfd` isn't open
|
||||
* @see dup(), dup2()
|
||||
*/
|
||||
int dup3(int oldfd, int newfd, int flags) {
|
||||
@@ -52,7 +54,7 @@ int dup3(int oldfd, int newfd, int flags) {
|
||||
} else if (oldfd < 0 || newfd < 0) {
|
||||
rc = ebadf();
|
||||
} else if (__isfdkind(oldfd, kFdZip)) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, flags);
|
||||
} else {
|
||||
|
||||
@@ -99,7 +99,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||
startinfo.hStdError = __getfdhandleactual(2);
|
||||
|
||||
// spawn the process
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
|
||||
rc = ntspawn(program, argv, envp, 0, 0, 0, true, 0, 0, &startinfo, &procinfo);
|
||||
if (rc == -1) {
|
||||
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
|
||||
__imp_ExitProcess(6543);
|
||||
|
||||
+37
-24
@@ -16,6 +16,8 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/blockcancel.internal.h"
|
||||
#include "libc/calls/blocksigs.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -39,12 +41,17 @@ static bool IsApeBinary(const char *path) {
|
||||
int fd;
|
||||
char buf[8];
|
||||
bool res = false;
|
||||
// TODO(jart): Should we block signals too?
|
||||
BLOCK_CANCELLATIONS;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
|
||||
if (sys_read(fd, buf, 8) == 8 && //
|
||||
(READ64LE(buf) == READ64LE("MZqFpD='") ||
|
||||
READ64LE(buf) == READ64LE("JTqFpD='"))) {
|
||||
res = true;
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
ALLOW_CANCELLATIONS;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -61,35 +68,41 @@ static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
|
||||
}
|
||||
|
||||
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int e;
|
||||
size_t i;
|
||||
int e, rc;
|
||||
char *buf;
|
||||
char **shargs;
|
||||
const char *ape;
|
||||
e = errno;
|
||||
__sys_execve(prog, argv, envp);
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
if (errno == ENOEXEC) {
|
||||
for (i = 0; argv[i];) ++i;
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape", buf))) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("HOME"), "."), ".ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else if (CanExecute(prog)) {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
errno = e;
|
||||
rc = __sys_execve(shargs[0], shargs, envp);
|
||||
} else {
|
||||
rc = enoexec();
|
||||
}
|
||||
} else {
|
||||
return enoexec();
|
||||
rc = -1;
|
||||
}
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
return rc;
|
||||
}
|
||||
+10
-18
@@ -23,6 +23,7 @@
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/promises.internal.h"
|
||||
@@ -35,6 +36,10 @@
|
||||
/**
|
||||
* Replaces current process with program.
|
||||
*
|
||||
* 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
|
||||
* corrupted.
|
||||
*
|
||||
* @param program will not be PATH searched, see commandv()
|
||||
* @param argv[0] is the name of the program to run
|
||||
* @param argv[1,n-2] optionally specify program arguments
|
||||
@@ -49,26 +54,13 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int rc;
|
||||
size_t i;
|
||||
if (!prog || !argv || !envp ||
|
||||
(IsAsan() &&
|
||||
(!__asan_is_valid(prog, 1) || !__asan_is_valid_strlist(argv) ||
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
(IsAsan() && (!__asan_is_valid_str(prog) || //
|
||||
!__asan_is_valid_strlist(argv) || //
|
||||
!__asan_is_valid_strlist(envp)))) {
|
||||
rc = efault();
|
||||
} else {
|
||||
#ifdef SYSDEBUG
|
||||
if (UNLIKELY(__strace > 0)) {
|
||||
kprintf(STRACE_PROLOGUE "execve(%#s, {", prog);
|
||||
for (i = 0; argv[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", argv[i]);
|
||||
}
|
||||
kprintf("}, {");
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
if (i) kprintf(", ");
|
||||
kprintf("%#s", envp[i]);
|
||||
}
|
||||
kprintf("})\n");
|
||||
}
|
||||
#endif
|
||||
STRACE("execve(%#s, %s, %s) → ...", prog, DescribeStringList(argv),
|
||||
DescribeStringList(envp));
|
||||
if (!IsWindows()) {
|
||||
rc = 0;
|
||||
if (IsLinux() && __execpromises && _weaken(sys_pledge_linux)) {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
int execvpe(const char *prog, char *const argv[], char *const *envp) {
|
||||
char *exe;
|
||||
char pathbuf[PATH_MAX];
|
||||
if (IsAsan() && !__asan_is_valid(prog, 1)) return efault();
|
||||
if (IsAsan() && !__asan_is_valid_str(prog)) return efault();
|
||||
if (!(exe = commandv(prog, pathbuf, sizeof(pathbuf)))) return -1;
|
||||
return execve(exe, argv, envp);
|
||||
}
|
||||
+22
-12
@@ -17,6 +17,7 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
@@ -35,33 +36,42 @@
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
|
||||
* @note on Linux flags is only supported on Linux 5.8+
|
||||
* @param amode can be `R_OK`, `W_OK`, `X_OK`, or `F_OK`
|
||||
* @param flags can have `AT_EACCESS` and/or `AT_SYMLINK_NOFOLLOW`
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @raise EINVAL if `mode` has bad value
|
||||
* @raise EPERM if pledge() is in play without rpath promise
|
||||
* @raise EACCES if access for requested `mode` would be denied
|
||||
* @raise ENOTDIR if a directory component in `path` exists as non-directory
|
||||
* @raise ENOENT if component of `path` doesn't exist or `path` is empty
|
||||
* @raise ENOTSUP if `path` is a zip file and `dirfd` isn't `AT_FDCWD`
|
||||
* @note on Linux `flags` is only supported on Linux 5.8+
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
int faccessat(int dirfd, const char *path, int amode, int flags) {
|
||||
int e, rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
struct ZiposUri zipname;
|
||||
if (!path || (IsAsan() && !__asan_is_valid_str(path))) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
_weaken(__zipos_notat)(dirfd, path) == -1) {
|
||||
rc = -1; /* TODO(jart): implement me */
|
||||
} else if (__isfdkind(dirfd, kFdZip)) {
|
||||
rc = enotsup();
|
||||
} else if (_weaken(__zipos_open) &&
|
||||
_weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
rc = _weaken(__zipos_access)(&zipname, amode);
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if (!flags) goto NoFlags;
|
||||
if ((rc = sys_faccessat2(dirfd, path, mode, flags)) == -1) {
|
||||
if ((rc = sys_faccessat2(dirfd, path, amode, flags)) == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
errno = e;
|
||||
NoFlags:
|
||||
rc = sys_faccessat(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat(dirfd, path, amode, flags);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = sys_faccessat_nt(dirfd, path, mode, flags);
|
||||
rc = sys_faccessat_nt(dirfd, path, amode, flags);
|
||||
}
|
||||
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(dirfd), path,
|
||||
mode, flags, rc);
|
||||
amode, flags, rc);
|
||||
return rc;
|
||||
}
|
||||
@@ -37,17 +37,18 @@
|
||||
* @param path must exist
|
||||
* @param mode contains octal flags (base 8)
|
||||
* @param flags can have `AT_SYMLINK_NOFOLLOW`
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see fchmod()
|
||||
*/
|
||||
int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
rc = eopnotsupp();
|
||||
rc = enotsup();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fchmodat(dirfd, path, mode, flags);
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
* @param gid is group id, or -1 to not change
|
||||
* @param flags can have AT_SYMLINK_NOFOLLOW, etc.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise ENOTSUP if `dirfd` or `path` use zip file system
|
||||
* @see chown(), lchown() for shorthand notation
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
@@ -42,11 +43,11 @@
|
||||
int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
|
||||
int flags) {
|
||||
int rc;
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) {
|
||||
if (IsAsan() && !__asan_is_valid_str(path)) {
|
||||
rc = efault();
|
||||
} else if (_weaken(__zipos_notat) &&
|
||||
(rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("zipos fchownat not supported yet");
|
||||
rc = enotsup();
|
||||
} else {
|
||||
rc = sys_fchownat(dirfd, path, uid, gid, flags);
|
||||
}
|
||||
|
||||
+223
-47
@@ -16,6 +16,7 @@
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
@@ -24,65 +25,131 @@
|
||||
#include "libc/calls/syscall_support-nt.internal.h"
|
||||
#include "libc/calls/wincrash.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kmalloc.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/filelockflags.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/byhandlefileinformation.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
bool __force_sqlite_to_work_until_we_can_fix_it;
|
||||
struct FileLock {
|
||||
struct FileLock *next;
|
||||
int64_t off;
|
||||
int64_t len;
|
||||
int fd;
|
||||
bool exc;
|
||||
};
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
struct FileLocks {
|
||||
pthread_mutex_t mu;
|
||||
struct FileLock *list;
|
||||
struct FileLock *free;
|
||||
};
|
||||
|
||||
static struct FileLocks g_locks;
|
||||
|
||||
static textwindows struct FileLock *NewFileLock(void) {
|
||||
struct FileLock *fl;
|
||||
if (g_locks.free) {
|
||||
fl = g_locks.free;
|
||||
g_locks.free = fl->next;
|
||||
} else {
|
||||
fl = kmalloc(sizeof(*fl));
|
||||
}
|
||||
bzero(fl, sizeof(*fl));
|
||||
fl->next = g_locks.list;
|
||||
g_locks.list = fl;
|
||||
return fl;
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
static textwindows void FreeFileLock(struct FileLock *fl) {
|
||||
fl->next = g_locks.free;
|
||||
g_locks.free = fl;
|
||||
}
|
||||
|
||||
static textwindows bool OverlapsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
uint64_t BegA, EndA, BegB, EndB;
|
||||
BegA = off;
|
||||
EndA = off + (len - 1);
|
||||
BegB = fl->off;
|
||||
EndB = fl->off + (fl->len - 1);
|
||||
return MAX(BegA, BegB) < MIN(EndA, EndB);
|
||||
}
|
||||
|
||||
static textwindows bool EncompassesFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return off <= fl->off && fl->off + fl->len <= off + len;
|
||||
}
|
||||
|
||||
static textwindows bool EqualsFileLock(struct FileLock *fl, int64_t off,
|
||||
int64_t len) {
|
||||
return fl->off == off && off + len == fl->off + fl->len;
|
||||
}
|
||||
|
||||
_Hide textwindows void sys_fcntl_nt_lock_cleanup(int fd) {
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_lock(struct Fd *f, int fd, int cmd,
|
||||
uintptr_t arg) {
|
||||
int e;
|
||||
struct flock *l;
|
||||
uint32_t flags, err;
|
||||
int64_t pos, off, len, size;
|
||||
struct NtByHandleFileInformation info;
|
||||
|
||||
if (!GetFileInformationByHandle(f->handle, &info)) {
|
||||
return __winerr();
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
if (!SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
return __winerr();
|
||||
}
|
||||
struct FileLock *fl, *ft, **flp;
|
||||
int64_t pos, off, len, end, size;
|
||||
|
||||
l = (struct flock *)arg;
|
||||
len = l->l_len;
|
||||
off = l->l_start;
|
||||
size = (uint64_t)info.nFileSizeHigh << 32 | info.nFileSizeLow;
|
||||
|
||||
switch (l->l_whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
off = pos + off;
|
||||
pos = 0;
|
||||
if (SetFilePointerEx(f->handle, 0, &pos, SEEK_CUR)) {
|
||||
off = pos + off;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
break;
|
||||
case SEEK_END:
|
||||
off = size - off;
|
||||
off = INT64_MAX - off;
|
||||
break;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!len) {
|
||||
len = size - off;
|
||||
len = INT64_MAX - off;
|
||||
}
|
||||
|
||||
if (off < 0 || len < 0) {
|
||||
if (off < 0 || len < 0 || __builtin_add_overflow(off, len, &end)) {
|
||||
return einval();
|
||||
}
|
||||
|
||||
@@ -91,8 +158,57 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
.Pointer = (void *)(uintptr_t)off};
|
||||
|
||||
if (l->l_type == F_RDLCK || l->l_type == F_WRLCK) {
|
||||
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW) {
|
||||
// make it possible to transition read locks to write locks
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd) {
|
||||
if (EqualsFileLock(fl, off, len)) {
|
||||
if (fl->exc == l->l_type == F_WRLCK) {
|
||||
// we already have this lock
|
||||
return 0;
|
||||
} else {
|
||||
// unlock our read lock and acquire write lock below
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
continue;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (OverlapsFileLock(fl, off, len)) {
|
||||
return enotsup();
|
||||
}
|
||||
}
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// return better information on conflicting locks if possible
|
||||
if (cmd == F_GETLK) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len) &&
|
||||
(l->l_type == F_WRLCK || !fl->exc)) {
|
||||
l->l_whence = SEEK_SET;
|
||||
l->l_start = fl->off;
|
||||
l->l_len = fl->len;
|
||||
l->l_type == fl->exc ? F_WRLCK : F_RDLCK;
|
||||
l->l_pid = getpid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (cmd != F_SETLKW) {
|
||||
// TODO(jart): we should use expo backoff in wrapper function
|
||||
// should not matter since sqlite doesn't need it
|
||||
flags |= kNtLockfileFailImmediately;
|
||||
}
|
||||
if (l->l_type == F_WRLCK) {
|
||||
@@ -103,72 +219,132 @@ static textwindows int sys_fcntl_nt_lock(struct Fd *f, int cmd, uintptr_t arg) {
|
||||
if (ok) {
|
||||
l->l_type = F_UNLCK;
|
||||
if (!UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
notpossible;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
l->l_pid = -1;
|
||||
ok = true;
|
||||
}
|
||||
} else if (ok) {
|
||||
fl = NewFileLock();
|
||||
fl->off = off;
|
||||
fl->len = len;
|
||||
fl->exc = l->l_type == F_WRLCK;
|
||||
fl->fd = fd;
|
||||
}
|
||||
if (ok || __force_sqlite_to_work_until_we_can_fix_it) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
if (l->l_type == F_UNLCK) {
|
||||
if (cmd == F_GETLK) return einval();
|
||||
e = errno;
|
||||
if (UnlockFileEx(f->handle, 0, len, len >> 32, &ov)) {
|
||||
return 0;
|
||||
} else if (errno == ENOLCK) {
|
||||
errno = e;
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
// allow a big range to unlock many small ranges
|
||||
for (flp = &g_locks.list, fl = *flp; fl;) {
|
||||
if (fl->fd == fd && EncompassesFileLock(fl, off, len)) {
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
*flp = fl->next;
|
||||
ft = fl->next;
|
||||
FreeFileLock(fl);
|
||||
fl = ft;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
flp = &fl->next;
|
||||
fl = *flp;
|
||||
}
|
||||
}
|
||||
|
||||
// win32 won't let us carve up existing locks
|
||||
int overlap_count = 0;
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
OverlapsFileLock(fl, off, len)) {
|
||||
++overlap_count;
|
||||
}
|
||||
}
|
||||
|
||||
// try to handle the carving cases needed by sqlite
|
||||
if (overlap_count == 1) {
|
||||
for (fl = g_locks.list; fl; fl = fl->next) {
|
||||
if (fl->fd == fd && //
|
||||
off <= fl->off && //
|
||||
off + len >= fl->off && //
|
||||
off + len < fl->off + fl->len) {
|
||||
// cleave left side of lock
|
||||
struct NtOverlapped ov = {.hEvent = f->handle,
|
||||
.Pointer = (void *)(uintptr_t)fl->off};
|
||||
if (!UnlockFileEx(f->handle, 0, fl->len, fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
fl->len = (fl->off + fl->len) - (off + len);
|
||||
fl->off = off + len;
|
||||
ov.Pointer = (void *)(uintptr_t)fl->off;
|
||||
if (!LockFileEx(f->handle, kNtLockfileExclusiveLock, 0, fl->len,
|
||||
fl->len >> 32, &ov)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (overlap_count) {
|
||||
return enotsup();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return einval();
|
||||
}
|
||||
|
||||
static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
|
||||
if (start < 0) return einval();
|
||||
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
|
||||
}
|
||||
|
||||
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
|
||||
int rc;
|
||||
uint32_t flags;
|
||||
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
|
||||
if (cmd == F_GETFL) {
|
||||
return g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME |
|
||||
O_NONBLOCK | O_RANDOM | O_SEQUENTIAL);
|
||||
rc = g_fds.p[fd].flags &
|
||||
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
|
||||
O_RANDOM | O_SEQUENTIAL);
|
||||
} else if (cmd == F_SETFL) {
|
||||
// O_APPEND doesn't appear to be tunable at cursory glance
|
||||
// O_NONBLOCK might require we start doing all i/o in threads
|
||||
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
|
||||
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
|
||||
// not worth it.
|
||||
return einval();
|
||||
rc = enosys();
|
||||
} else if (cmd == F_GETFD) {
|
||||
if (g_fds.p[fd].flags & O_CLOEXEC) {
|
||||
return FD_CLOEXEC;
|
||||
rc = FD_CLOEXEC;
|
||||
} else {
|
||||
return 0;
|
||||
rc = 0;
|
||||
}
|
||||
} else if (cmd == F_SETFD) {
|
||||
if (arg & FD_CLOEXEC) {
|
||||
g_fds.p[fd].flags |= O_CLOEXEC;
|
||||
return FD_CLOEXEC;
|
||||
} else {
|
||||
g_fds.p[fd].flags &= ~O_CLOEXEC;
|
||||
return 0;
|
||||
}
|
||||
rc = 0;
|
||||
} else if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) {
|
||||
return sys_fcntl_nt_lock(g_fds.p + fd, cmd, arg);
|
||||
pthread_mutex_lock(&g_locks.mu);
|
||||
rc = sys_fcntl_nt_lock(g_fds.p + fd, fd, cmd, arg);
|
||||
pthread_mutex_unlock(&g_locks.mu);
|
||||
} else if (cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC) {
|
||||
return sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
rc = sys_fcntl_nt_dupfd(fd, cmd, arg);
|
||||
} else {
|
||||
return einval();
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
rc = ebadf();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
int sys_fcntl(int fd, int cmd, uintptr_t arg, int impl(int, int, ...)) {
|
||||
int e, rc;
|
||||
bool islock;
|
||||
if ((islock = cmd == F_GETLK || //
|
||||
@@ -40,12 +40,12 @@ int sys_fcntl(int fd, int cmd, uintptr_t arg) {
|
||||
cosmo2flock(arg);
|
||||
}
|
||||
e = errno;
|
||||
rc = __sys_fcntl(fd, cmd, arg);
|
||||
rc = impl(fd, cmd, arg);
|
||||
if (islock) {
|
||||
flock2cosmo(arg);
|
||||
} else if (rc == -1 && cmd == F_DUPFD_CLOEXEC && errno == EINVAL) {
|
||||
errno = e;
|
||||
rc = __fixupnewfd(__sys_fcntl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
rc = __fixupnewfd(impl(fd, F_DUPFD, arg), O_CLOEXEC);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+107
-14
@@ -17,17 +17,22 @@
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/cp.internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/flock.h"
|
||||
#include "libc/calls/struct/flock.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Does things with file descriptor, via re-imagined hourglass api, e.g.
|
||||
* Does things with file descriptor, e.g.
|
||||
*
|
||||
* CHECK_NE(-1, fcntl(fd, F_SETFD, FD_CLOEXEC));
|
||||
*
|
||||
@@ -37,16 +42,60 @@
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD, 3)), 3);
|
||||
* CHECK_GE((newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 3)), 3);
|
||||
*
|
||||
* This function implements POSIX Advisory Locks, which let independent
|
||||
* processes (and on Windows, threads too!) read/write lock byte ranges
|
||||
* of files. See `test/libc/calls/lock_test.c` for an example.
|
||||
* This function implements file record locking, which lets independent
|
||||
* processes (and on Linux 3.15+, threads too!) lock arbitrary ranges
|
||||
* associated with a file. See `test/libc/calls/lock_test.c` and other
|
||||
* locking related tests in that folder.
|
||||
*
|
||||
* Please be warned that locks currently do nothing on Windows since
|
||||
* figuring out how to polyfill them correctly is a work in progress.
|
||||
* On Windows, the Cosmopolitan Libc polyfill for POSIX advisory locks
|
||||
* only implements enough of its nuances to support SQLite's needs. Some
|
||||
* possibilities, e.g. punching holes in lock, will raise `ENOTSUP`.
|
||||
*
|
||||
* @param cmd can be F_{GET,SET}{FD,FL}, etc.
|
||||
* @param fd is the file descriptor
|
||||
* @param cmd can be one of:
|
||||
* - `F_GETFD` gets `FD_CLOEXEC` status of `fd
|
||||
* - `F_SETFD` sets `FD_CLOEXEC` status of `arg` file descriptor
|
||||
* - `F_GETFL` returns file descriptor status flags
|
||||
* - `F_SETFL` sets file descriptor status flags
|
||||
* - `F_DUPFD` is like dup() but `arg` is a minimum result, e.g. 3
|
||||
* - `F_DUPFD_CLOEXEC` ditto but sets `O_CLOEXEC` on returned fd
|
||||
* - `F_SETLK` for record locking where `arg` is `struct flock *`
|
||||
* - `F_SETLKW` ditto but waits for lock (SQLite avoids this)
|
||||
* - `F_GETLK` to retrieve information about a record lock
|
||||
* - `F_OFD_SETLK` for better non-blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_SETLKW` for better blocking lock (Linux 3.15+ only)
|
||||
* - `F_OFD_GETLK` for better lock querying (Linux 3.15+ only)
|
||||
* - `F_FULLFSYNC` on MacOS for fsync() with release barrier
|
||||
* - `F_BARRIERFSYNC` on MacOS for fsync() with even more barriers
|
||||
* - `F_SETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETNOSIGPIPE` on MacOS and NetBSD to control `SIGPIPE`
|
||||
* - `F_GETPATH` on MacOS and NetBSD where arg is `char[PATH_MAX]`
|
||||
* - `F_MAXFD` on NetBSD to get max open file descriptor
|
||||
* - `F_NOCACHE` on MacOS to toggle data caching
|
||||
* - `F_GETPIPE_SZ` on Linux to get pipe size
|
||||
* - `F_SETPIPE_SZ` on Linux to set pipe size
|
||||
* - `F_NOTIFY` raise `SIGIO` upon `fd` events in `arg` (Linux only)
|
||||
* - `DN_ACCESS` for file access
|
||||
* - `DN_MODIFY` for file modifications
|
||||
* - `DN_CREATE` for file creations
|
||||
* - `DN_DELETE` for file deletions
|
||||
* - `DN_RENAME` for file renames
|
||||
* - `DN_ATTRIB` for file attribute changes
|
||||
* - `DN_MULTISHOT` bitwise or for realtime signals (non-coalesced)
|
||||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EBADF if `fd` isn't a valid open file descriptor
|
||||
* @raise EINVAL if `cmd` is unknown or unsupported by os
|
||||
* @raise EINVAL if `cmd` is invalid or unsupported by os
|
||||
* @raise EPERM if pledge() is in play w/o `stdio` or `flock` promise
|
||||
* @raise ENOLCK if `F_SETLKW` would have exceeded `RLIMIT_LOCKS`
|
||||
* @raise EPERM if `cmd` is `F_SETOWN` and we weren't authorized
|
||||
* @raise ESRCH if `cmd` is `F_SETOWN` and process group not found
|
||||
* @raise ENOTSUP on Windows if locking operation isn't supported yet
|
||||
* @raise EDEADLK if `cmd` was `F_SETLKW` and waiting would deadlock
|
||||
* @raise EMFILE if `cmd` is `F_DUPFD` or `F_DUPFD_CLOEXEC` and
|
||||
* `RLIMIT_NOFILE` would be exceeded
|
||||
* @cancellationpoint when `cmd` is `F_SETLKW` or `F_OFD_SETLKW`
|
||||
* @asyncsignalsafe
|
||||
* @restartable
|
||||
*/
|
||||
@@ -54,20 +103,64 @@ int fcntl(int fd, int cmd, ...) {
|
||||
int rc;
|
||||
va_list va;
|
||||
uintptr_t arg;
|
||||
|
||||
va_start(va, cmd);
|
||||
arg = va_arg(va, uintptr_t);
|
||||
va_end(va);
|
||||
|
||||
if (fd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_fcntl(fd, cmd, arg);
|
||||
if (cmd >= 0) {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = _weaken(__zipos_fcntl)(fd, cmd, arg);
|
||||
} else if (!IsWindows()) {
|
||||
if (cmd == F_SETLKW || cmd == F_OFD_SETLKW) {
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl_cp);
|
||||
END_CANCELLATION_POINT;
|
||||
} else {
|
||||
rc = sys_fcntl(fd, cmd, arg, __sys_fcntl);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
}
|
||||
} else {
|
||||
rc = sys_fcntl_nt(fd, cmd, arg);
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = einval();
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc);
|
||||
|
||||
#ifdef SYSDEBUG
|
||||
if (cmd == F_GETFD || //
|
||||
cmd == F_GETOWN || //
|
||||
cmd == F_FULLFSYNC || //
|
||||
cmd == F_BARRIERFSYNC || //
|
||||
cmd == F_MAXFD) {
|
||||
STRACE("fcntl(%d, %s) → %d% m", fd, DescribeFcntlCmd(cmd), rc);
|
||||
} else if (cmd == F_GETFL) {
|
||||
STRACE("fcntl(%d, %s) → %s% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeOpenFlags(rc));
|
||||
} else if (cmd == F_SETLK || //
|
||||
cmd == F_SETLKW || //
|
||||
cmd == F_GETLK || //
|
||||
((SupportsLinux() || SupportsXnu()) && //
|
||||
cmd != -1 && //
|
||||
(cmd == F_OFD_SETLK || //
|
||||
cmd == F_OFD_SETLKW || //
|
||||
cmd == F_OFD_GETLK))) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeFlock(cmd, (struct flock *)arg), rc);
|
||||
} else if ((SupportsNetbsd() || SupportsXnu()) && cmd != -1 &&
|
||||
cmd == F_GETPATH) {
|
||||
STRACE("fcntl(%d, %s, [%s]) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
!rc ? (const char *)arg : "n/a", rc);
|
||||
} else if (SupportsLinux() && cmd != -1 && cmd == F_NOTIFY) {
|
||||
STRACE("fcntl(%d, %s, %s) → %d% m", fd, DescribeFcntlCmd(cmd),
|
||||
DescribeDnotifyFlags(arg), rc);
|
||||
} else {
|
||||
STRACE("fcntl(%d, %s, %ld) → %#x% m", fd, DescribeFcntlCmd(cmd), arg, rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -23,5 +23,6 @@
|
||||
textwindows int sys_fdatasync_nt(int fd) {
|
||||
// TODO(jart): what should we do with worker pipes?
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (_check_interrupts(false, 0)) return -1;
|
||||
return FlushFileBuffers(g_fds.p[fd].handle) ? 0 : -1;
|
||||
}
|
||||
Loaded 100 of 2049 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user