Compare commits

...

26 commits

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

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

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

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

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

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

Fixes the other part of #1346.
2025-01-05 20:47:34 -08:00
Justine Tunney
98861b23fc
Make some style fixes to prng code 2025-01-05 20:18:05 -08:00
Steven Dee (Jōshin)
dab6d7a345
Resolve multiple definition of __sig (fixes #1346) (#1352) 2025-01-05 19:54:49 -08:00
Justine Tunney
90119c422c
Fix 404 url
Closes #1347
2025-01-05 17:04:37 -08:00
58 changed files with 1318 additions and 152 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -129,10 +129,12 @@ imp 'GetFileTime' GetFileTime kernel32 4
imp 'GetFileType' GetFileType kernel32 1
imp 'GetFinalPathNameByHandle' GetFinalPathNameByHandleW kernel32 4
imp 'GetFullPathName' GetFullPathNameW kernel32 4
imp 'GetShortPathName' GetShortPathNameW kernel32 3
imp 'GetHandleInformation' GetHandleInformation kernel32 2
imp 'GetLargestConsoleWindowSize' GetLargestConsoleWindowSize kernel32 1
imp 'GetLastError' GetLastError kernel32 0
imp 'GetLogicalDrives' GetLogicalDrives kernel32 0
imp 'GetLogicalDriveStringsA' GetLogicalDriveStringsA kernel32 2
imp 'GetMaximumProcessorCount' GetMaximumProcessorCount kernel32 1 # Windows 7+
imp 'GetModuleFileName' GetModuleFileNameW kernel32 3
imp 'GetModuleHandle' GetModuleHandleA kernel32 1
@ -186,6 +188,9 @@ imp 'GetVolumeInformationByHandle' GetVolumeInformationByHandleW kernel32
imp 'GetVolumePathName' GetVolumePathNameW kernel32 3
imp 'GetWindowsDirectory' GetWindowsDirectoryW kernel32 2
imp 'GetWindowsDirectoryA' GetWindowsDirectoryA kernel32 2
imp 'GetOEMCP' GetOEMCP kernel32 0
imp 'GetACP' GetACP kernel32 0
imp 'GetCPInfoEx' GetCPInfoExW kernel32 3
imp 'GlobalAlloc' GlobalAlloc kernel32 2
imp 'GlobalFree' GlobalFree kernel32 1
imp 'GlobalLock' GlobalLock kernel32 1
@ -356,6 +361,7 @@ imp 'RegLoadKey' RegLoadKeyW advapi32 3
imp 'RegNotifyChangeKeyValue' RegNotifyChangeKeyValue advapi32 5
imp 'RegOpenCurrentUser' RegOpenCurrentUser advapi32 2
imp 'RegOpenKeyEx' RegOpenKeyExW advapi32 5
imp 'RegOpenKeyExA' RegOpenKeyExA advapi32 5
imp 'RegOpenUserClassesRoot' RegOpenUserClassesRoot advapi32 4
imp 'RegOverridePredefKey' RegOverridePredefKey advapi32 2
imp 'RegQueryInfoKey' RegQueryInfoKeyW advapi32 12

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

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -51,6 +51,9 @@ void SetUpOnce(void) {
// ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath", 0));
}
// TODO(jart): fix this test
#if 0
TEST(cachestat, testCachestatOnDevices) {
const char *const files[] = {
"/dev/zero", "/dev/null", "/dev/urandom", "/proc/version", "/proc",
@ -64,6 +67,8 @@ TEST(cachestat, testCachestatOnDevices) {
}
}
#endif
TEST(cachestat, testCachestatAfterWrite) {
size_t size = 4 * pagesize;
char *data = gc(xmalloc(size));

View file

@ -32,7 +32,7 @@
#include <unistd.h>
// clang-format off
// sh -c 'build/bootstrap/make -j8 V=1 o//test/posix/sigchld_test.runs'
// sh -c '.cosmocc/current/bin/make -j8 V=1 o//test/posix/sigchld_test.runs'
// clang-format on
void Assert(const char *file, int line, bool ok) {

View file

@ -85,6 +85,13 @@
" executable will self-modify its header on\n" \
" the first run, to use the platform format\n" \
"\n" \
" -k KERNEL test for maching kernel name [repeatable]\n" \
" when set, the shell script for subsequent\n" \
" loader executables will check if uname -s\n" \
" output matches the kernel string, only if\n" \
" the loader executable architecture is not\n" \
" an architecture in the input binary list\n" \
"\n" \
" -M PATH bundle ape loader source code file for m1\n" \
" processors running the xnu kernel so that\n" \
" it can be compiled on the fly by xcode\n" \
@ -213,6 +220,7 @@ struct Loader {
char *ddarg_size1;
char *ddarg_skip2;
char *ddarg_size2;
const char *kernel;
};
struct Loaders {
@ -244,6 +252,7 @@ static struct Inputs inputs;
static char ape_heredoc[15];
static enum Strategy strategy;
static struct Loaders loaders;
static const char *loader_kernel;
static const char *custom_sh_code;
static bool force_bypass_binfmt_misc;
static bool generate_debuggable_binary;
@ -979,13 +988,19 @@ static void AddLoader(const char *path) {
if (loaders.n == ARRAYLEN(loaders.p)) {
Die(prog, "too many loaders");
}
loaders.p[loaders.n++].path = path;
struct Loader *loader = &loaders.p[loaders.n++];
loader->path = path;
loader->kernel = loader_kernel;
}
static void SetLoaderKernel(const char *kernel) {
loader_kernel = kernel;
}
static void GetOpts(int argc, char *argv[]) {
int opt, bits;
bool got_support_vector = false;
while ((opt = getopt(argc, argv, "hvgsGBo:l:S:M:V:")) != -1) {
while ((opt = getopt(argc, argv, "hvgsGBo:l:k:S:M:V:")) != -1) {
switch (opt) {
case 'o':
outpath = optarg;
@ -1009,6 +1024,10 @@ static void GetOpts(int argc, char *argv[]) {
HashInputString("-l");
AddLoader(optarg);
break;
case 'k':
HashInputString("-k");
SetLoaderKernel(optarg);
break;
case 'S':
HashInputString("-S");
HashInputString(optarg);
@ -1630,6 +1649,28 @@ static char *GenerateScriptIfMachine(char *p, struct Input *in) {
}
}
static char *GenerateScriptIfLoaderMachine(char *p, struct Loader *loader) {
if (loader->machine == EM_NEXGEN32E) {
p = stpcpy(p, "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]");
} else if (loader->machine == EM_AARCH64) {
p = stpcpy(p, "if [ \"$m\" = aarch64 ] || [ \"$m\" = arm64 ] || [ \"$m\" = evbarm ]");
} else if (loader->machine == EM_PPC64) {
p = stpcpy(p, "if [ \"$m\" = ppc64le ]");
} else if (loader->machine == EM_MIPS) {
p = stpcpy(p, "if [ \"$m\" = mips64 ]");
} else {
Die(loader->path, "unsupported cpu architecture");
}
if (loader->kernel) {
p = stpcpy(p, " && [ \"$k\" = ");
p = stpcpy(p, loader->kernel);
p = stpcpy(p, " ]");
}
return stpcpy(p, "; then\n");
}
static char *FinishGeneratingDosHeader(char *p) {
p = WRITE16LE(p, 0x1000); // 10: MZ: lowers upper bound load / 16
p = WRITE16LE(p, 0xf800); // 12: MZ: roll greed on bss
@ -1879,7 +1920,15 @@ int main(int argc, char *argv[]) {
for (j = i + 1; j < loaders.n; ++j) {
if (loaders.p[i].os == loaders.p[j].os &&
loaders.p[i].machine == loaders.p[j].machine) {
Die(prog, "multiple ape loaders specified for the same platform");
if (!loaders.p[i].kernel && !loaders.p[j].kernel) {
Die(prog, "multiple ape loaders specified for the same platform");
}
if (loaders.p[i].kernel != NULL &&
loaders.p[j].kernel != NULL &&
strcmp(loaders.p[i].kernel, loaders.p[j].kernel) == 0) {
Die(prog, "multiple ape loaders specified for the same platform "
"with matching kernels");
}
}
}
}
@ -2190,6 +2239,36 @@ int main(int argc, char *argv[]) {
gotsome = true;
}
}
// extract the ape loader for non-input architectures
// if the user requested a host kernel check, get the host kernel
if (loader_kernel) {
p = stpcpy(p, "k=$(uname -s 2>/dev/null) || k=unknown\n");
}
for (i = 0; i < loaders.n; ++i) {
struct Loader *loader = loaders.p + i;
if (loader->used) {
continue;
}
loader->used = true;
p = GenerateScriptIfLoaderMachine(p, loader);
p = stpcpy(p, "mkdir -p \"${t%/*}\" ||exit\n"
"dd if=\"$o\"");
p = stpcpy(p, " skip=");
loader->ddarg_skip2 = p;
p = GenerateDecimalOffsetRelocation(p);
p = stpcpy(p, " count=");
loader->ddarg_size2 = p;
p = GenerateDecimalOffsetRelocation(p);
p = stpcpy(p, " bs=1 2>/dev/null | gzip -dc >\"$t.$$\" ||exit\n"
"chmod 755 \"$t.$$\" ||exit\n"
"mv -f \"$t.$$\" \"$t\" ||exit\n");
p = stpcpy(p, "exec \"$t\" \"$o\" \"$@\"\n"
"fi\n");
gotsome = true;
}
// close if-statements
if (inputs.n && (support_vector & _HOSTXNU)) {
if (!gotsome) {
p = stpcpy(p, "true\n");

283
tool/build/renamestr.c Normal file
View file

@ -0,0 +1,283 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2024 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/phdr.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/getopt/getopt.internal.h"
#define VERSION \
"renamestr v0.1\n" \
"https://github.com/jart/cosmopolitan\n"
#define MANUAL \
" -f FROM -t TO INPUT \n" \
"\n" \
"DESCRIPTION\n" \
"\n" \
" in-place string replacement in ELF binary .rodata\n" \
"\n" \
" this program may be used to replace strings in the\n" \
" .rodata sections of ELF binaries, in-place.\n" \
"\n" \
"FLAGS\n" \
"\n" \
" -h show usage\n" \
"\n" \
" -v show version\n" \
"\n" \
" -f FROM source string to replace\n" \
"\n" \
" -t TO target string replacement. must be shorter\n" \
" than FROM string for replacement to work\n" \
"\n" \
" INPUT ELF binary containing strings to replace\n" \
"\n"
static const char *prog;
static const char *exepath;
static Elf64_Shdr *rodata;
static char *rostart;
static char *roend;
static int exefd;
static wontreturn void Die(const char *thing, const char *reason) {
tinyprint(2, thing, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void DieSys(const char *thing) {
perror(thing);
exit(1);
}
static wontreturn void ShowUsage(int rc, int fd) {
tinyprint(fd, "USAGE\n\n ", prog, MANUAL, NULL);
exit(rc);
}
static void Pwrite(const void *data, size_t size, uint64_t offset) {
ssize_t rc;
const char *p, *e;
for (p = data, e = p + size; p < e; p += (size_t)rc, offset += (size_t)rc) {
if ((rc = pwrite(exefd, p, e - p, offset)) == -1) {
DieSys(exepath);
}
}
}
struct String {
const char *str;
size_t len;
};
struct Param {
struct String from;
struct String to;
int count;
char *roloc;
};
struct Params {
int n;
struct Param p[4];
};
static struct Params params;
static void GetOpts(int argc, char *argv[]) {
int opt;
bool partial = false;
params.n = 0;
struct Param *param;
while ((opt = getopt(argc, argv, "hvf:t:")) != -1) {
if (params.n >= ARRAYLEN(params.p)) {
param = NULL;
} else {
param = &(params.p[params.n]);
}
switch (opt) {
case 'f':
if (!param) {
Die(prog, "too many replacements provided");
}
if (param->from.str) {
Die(prog, "from string already provided");
}
param->from.str = optarg;
param->from.len = strlen(optarg);
partial = !partial;
break;
case 't':
if (!param) {
Die(prog, "too many replacements provided");
}
if (param->to.str) {
Die(prog, "to string already provided");
}
param->to.str = optarg;
param->to.len = strlen(optarg);
partial = !partial;
break;
case 'v':
tinyprint(0, VERSION, NULL);
exit(0);
case 'h':
ShowUsage(0, 1);
default:
ShowUsage(1, 2);
}
if (param->from.str && param->to.str) {
if (param->from.len < param->to.len) {
Die(prog, "to.str longer than from.str, cannot replace");
}
params.n++;
}
}
if (params.n == 0) {
Die(prog, "no replacements provided");
}
if (partial) {
Die(prog, "partial replacement provided");
}
if (optind == argc) {
Die(prog, "missing input argument");
}
if (optind != argc - 1) {
Die(prog, "too many args");
}
exepath = argv[optind];
}
struct Input {
union {
char *map;
Elf64_Ehdr *elf;
unsigned char *umap;
};
size_t size;
const char *path;
};
static struct Input input;
static void OpenInput(const char *path) {
int fd;
if ((fd = open(path, O_RDWR)) == -1)
DieSys(path);
if ((input.size = lseek(fd, 0, SEEK_END)) == -1)
DieSys(path);
input.path = path;
input.map = mmap(0, input.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (input.map == MAP_FAILED)
DieSys(path);
if (!IsElf64Binary(input.elf, input.size))
Die(path, "not an elf64 binary");
exefd = fd;
}
static void ReplaceString(struct Param *param) {
size_t len;
char *x = (char *)memchr(param->roloc, 0, roend - param->roloc);
memmove(param->roloc, param->to.str, param->to.len);
if (UNLIKELY(x == NULL)) {
len = roend - param->roloc;
memmove(param->roloc + param->to.len, param->roloc + param->from.len,
len - param->from.len);
} else {
len = x - param->roloc;
memmove(param->roloc + param->to.len, param->roloc + param->from.len,
len + 1 - param->from.len);
}
param->roloc += param->to.len;
}
int main(int argc, char *argv[]) {
#ifdef MODE_DBG
ShowCrashReports();
#endif
prog = argv[0];
if (!prog)
prog = "renamestr";
GetOpts(argc, argv);
OpenInput(exepath);
rodata = FindElfSectionByName(
input.elf, input.size,
GetElfSectionNameStringTable(input.elf, input.size), ".rodata");
if (!rodata)
Die(exepath, "doesn't have .rodata");
rostart = GetElfSectionAddress(input.elf, input.size, rodata);
if (!rostart)
Die(prog, "could not get to start of .rodata");
roend = rostart + rodata->sh_size;
#ifdef MODE_DBG
kprintf("elf file to process: %s\n", exepath);
kprintf("file size is %ld\n", input.size);
#endif
for (int i = 0; i < params.n; ++i) {
struct Param *param = &(params.p[i]);
param->roloc = rostart;
param->count = 0;
#ifdef MODE_DBG
kprintf("need to replace '%s' with '%s'\n", param->from.str, param->to.str);
#endif
}
#define NEXT_ROLOC(z) \
memmem((z)->roloc, roend - (z)->roloc, (z)->from.str, (z)->from.len)
for (int i = 0; i < params.n; ++i) {
struct Param *param = &(params.p[i]);
for (param->roloc = NEXT_ROLOC(param); param->roloc != NULL;
param->roloc = NEXT_ROLOC(param)) {
ReplaceString(param);
param->count++;
}
}
#undef NEXT_ROLOC
Pwrite(input.map, input.size, 0);
if (close(exefd)) {
Die(prog, "unable to close file after writing");
}
for (int i = 0; i < params.n; ++i) {
struct Param *param = &(params.p[i]);
printf("'%s' -> '%s': %d replacements\n", param->from.str, param->to.str,
param->count);
}
return 0;
}

0
tool/cosmocc/bin/cosmoranlib Normal file → Executable file
View file

View file

@ -15,17 +15,49 @@ mode() {
esac
}
_nproc() {
case $(uname -s) in
Darwin) sysctl -n hw.logicalcpu ;;
*) nproc ;;
esac
}
TMPDIR=${TMPDIR:-/tmp}
OUTDIR=${1:-cosmocc}
APELINK=o/$(mode)/tool/build/apelink
AMD64=${2:-x86_64}
ARM64=${3:-aarch64}
NPROC=$(($(nproc)/2))
NPROC=$(($(_nproc)/2))
GCCVER=14.1.0
make -j$NPROC m= \
if ! MAKE=$(command -v gmake); then
if ! MAKE=$(command -v make); then
echo please install gnu make >&2
exit 1
fi
fi
$MAKE -j$NPROC m= \
$APELINK
make -j$NPROC m=$AMD64 \
if ! APE=$(command -v ape); then
case $(uname -s) in
Darwin)
case $(mode) in
aarch64)
cc -O -o "$TMPDIR/ape.$$" .cosmocc/current/bin/ape-m1.c || exit
trap 'rm "$TMPDIR/ape.$$"' EXIT
APE=$TMPDIR/ape.$$
;;
*) APE=.cosmocc/current/bin/ape-x86_64.macho ;;
esac
;;
*) APE=.cosmocc/current/bin/ape-$(uname -m).elf ;;
esac
fi
stat $APE
$MAKE -j$NPROC m=$AMD64 \
o/cosmocc.h.txt \
o/$AMD64/ape/ape.lds \
o/$AMD64/libc/crt/crt.o \
@ -62,7 +94,7 @@ make -j$NPROC m=$AMD64 \
o/$AMD64/third_party/make/make.dbg \
o/$AMD64/third_party/ctags/ctags.dbg
make -j$NPROC m=$AMD64-tiny \
$MAKE -j$NPROC m=$AMD64-tiny \
o/cosmocc.h.txt \
o/$AMD64-tiny/ape/ape.lds \
o/$AMD64-tiny/libc/crt/crt.o \
@ -74,7 +106,7 @@ make -j$NPROC m=$AMD64-tiny \
o/$AMD64-tiny/cosmopolitan.a \
o/$AMD64-tiny/third_party/libcxx/libcxx.a \
make -j$NPROC m=$AMD64-dbg \
$MAKE -j$NPROC m=$AMD64-dbg \
o/cosmocc.h.txt \
o/$AMD64-dbg/ape/ape.lds \
o/$AMD64-dbg/libc/crt/crt.o \
@ -86,7 +118,7 @@ make -j$NPROC m=$AMD64-dbg \
o/$AMD64-dbg/cosmopolitan.a \
o/$AMD64-dbg/third_party/libcxx/libcxx.a \
make CONFIG_TARGET_ARCH= -j$NPROC m=$AMD64-optlinux \
$MAKE CONFIG_TARGET_ARCH= -j$NPROC m=$AMD64-optlinux \
o/cosmocc.h.txt \
o/$AMD64-optlinux/ape/ape.lds \
o/$AMD64-optlinux/libc/crt/crt.o \
@ -98,7 +130,7 @@ make CONFIG_TARGET_ARCH= -j$NPROC m=$AMD64-optlinux \
o/$AMD64-optlinux/cosmopolitan.a \
o/$AMD64-optlinux/third_party/libcxx/libcxx.a \
make -j$NPROC m=$ARM64 \
$MAKE -j$NPROC m=$ARM64 \
o/$ARM64/ape/ape.elf \
o/$ARM64/ape/aarch64.lds \
o/$ARM64/libc/crt/crt.o \
@ -130,21 +162,21 @@ make -j$NPROC m=$ARM64 \
o/$ARM64/third_party/make/make.dbg \
o/$ARM64/third_party/ctags/ctags.dbg
make -j$NPROC m=$ARM64-tiny \
$MAKE -j$NPROC m=$ARM64-tiny \
o/$ARM64-tiny/ape/ape.elf \
o/$ARM64-tiny/ape/aarch64.lds \
o/$ARM64-tiny/libc/crt/crt.o \
o/$ARM64-tiny/cosmopolitan.a \
o/$ARM64-tiny/third_party/libcxx/libcxx.a \
make -j$NPROC m=$ARM64-dbg \
$MAKE -j$NPROC m=$ARM64-dbg \
o/$ARM64-dbg/ape/ape.elf \
o/$ARM64-dbg/ape/aarch64.lds \
o/$ARM64-dbg/libc/crt/crt.o \
o/$ARM64-dbg/cosmopolitan.a \
o/$ARM64-dbg/third_party/libcxx/libcxx.a \
make -j$NPROC m=$ARM64-optlinux \
$MAKE -j$NPROC m=$ARM64-optlinux \
o/$ARM64-optlinux/ape/ape.elf \
o/$ARM64-optlinux/ape/aarch64.lds \
o/$ARM64-optlinux/libc/crt/crt.o \
@ -169,14 +201,36 @@ fetch() {
else
curl -LO $1
fi
if command -v sha256sum >/dev/null 2>&1; then
# can use system sha256sum
true
elif command -v shasum >/dev/null 2>&1; then
sha256sum() {
shasum -a 256 "$@"
}
elif command -v "$PWD/o/build/sha256sum" >/dev/null 2>&1; then
# should have been built by download-cosmocc.sh if a system
# sha256sum/shasum does not exist
sha256sum() {
"$PWD/o/build/sha256sum" "$@"
}
else
echo please install sha256sum >&2
exit 1
fi
filename=$(basename $1)
printf '%s\n' "$2 $filename" >$filename.sha256sum
sha256sum -c $filename.sha256sum || exit 1
}
OLD=$PWD
cd "$OUTDIR/"
if [ ! -x bin/x86_64-linux-cosmo-gcc ]; then
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/aarch64-gcc.zip &
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/x86_64-gcc.zip &
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/llvm.zip &
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/aarch64-gcc.zip 6a07f915ec0296cd33b3142e75c00ed1a7072c75d92c82a0c0b5f5df2cff0dd2 &
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/x86_64-gcc.zip cbb1659c56a0a4f95a71f59f94693515000d3dd53f79a597acacd53cbad2c7d8 &
fetch https://github.com/ahgamut/superconfigure/releases/download/z0.0.60/llvm.zip d42c2e46204d4332975d2d7464c5df63c898c34f8d9d2b83c168c14705ca8edd &
wait
unzip aarch64-gcc.zip &
unzip x86_64-gcc.zip &
@ -272,7 +326,7 @@ cp -f o/$ARM64/ape/ape.elf "$OUTDIR/bin/ape-aarch64.elf"
for x in assimilate march-native mktemper fixupobj zipcopy apelink pecheck mkdeps zipobj \
ar chmod cocmd cp echo gzip objbincopy package rm touch mkdir compile sha256sum \
resymbol; do
ape $APELINK \
$APE $APELINK \
-l o/$AMD64/ape/ape.elf \
-l o/$ARM64/ape/ape.elf \
-M ape/ape-m1.c \
@ -286,7 +340,7 @@ for x in ar chmod cp echo gzip package rm touch mkdir compile sha256sum; do
done
for x in make ctags; do
ape $APELINK \
$APE $APELINK \
-l o/$AMD64/ape/ape.elf \
-l o/$ARM64/ape/ape.elf \
-M ape/ape-m1.c \

View file

@ -4864,9 +4864,9 @@ UNIX MODULE
end
It's possible to accomplish the same thing as unix.mapshared()
using files and unix.fcntl() advisory locks. However this goes
significantly faster. For example, that's what SQLite does and
we recommend using SQLite for IPC in redbean. But, if your app
using files and unix.fcntl() advisory locks. For example, that's
what SQLite does and we recommend using SQLite for IPC in redbean.
However, unix.mapshared is significantly faster and if your app
has thousands of forked processes fighting for a file lock you
might need something lower level than file locks, to implement
things like throttling. Shared memory is a good way to do that

View file

@ -33,7 +33,7 @@
eth0
addr: 10.10.10.237
netmask: 255.255.255.0
broadcast: 255.255.255.0
broadcast: 10.10.10.255
flags: IFF_UP IFF_BROADCAST IFF_MULTICAST IFF_RUNNING
lo
@ -74,13 +74,87 @@ int main(int argc, char *argv[]) {
tinyprint(1, "netmask: ", buf, "\n", NULL);
}
if ((ifa->ifa_flags & IFF_BROADCAST) &&
sockaddr2str(ifa->ifa_netmask, buf, sizeof(buf))) {
sockaddr2str(ifa->ifa_broadaddr, buf, sizeof(buf))) {
tinyprint(1, "broadcast: ", buf, "\n", NULL);
} else if ((ifa->ifa_flags & IFF_POINTOPOINT) &&
sockaddr2str(ifa->ifa_dstaddr, buf, sizeof(buf))) {
tinyprint(1, "dstaddr: ", buf, "\n", NULL);
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
int scope = ((int *)ifa->ifa_data)[0];
int aflags = ((int *)ifa->ifa_data)[1];
// #define IPV6_ADDR_LOOPBACK 0x0010U
// #define IPV6_ADDR_LINKLOCAL 0x0020U
// #define IPV6_ADDR_SITELOCAL 0x0040U
// #define IFA_F_TEMPORARY 0x01
// #define IFA_F_NODAD 0x02
// #define IFA_F_OPTIMISTIC 0x04
// #define IFA_F_DADFAILED 0x08
// #define IFA_F_HOMEADDRESS 0x10
// #define IFA_F_DEPRECATED 0x20
// #define IFA_F_TENTATIVE 0x40
// #define IFA_F_PERMANENT 0x80
// #define IFA_F_MANAGETEMPADDR 0x100
// #define IFA_F_NOPREFIXROUTE 0x200
// #define IFA_F_MCAUTOJOIN 0x400
// #define IFA_F_STABLE_PRIVACY 0x800
tinyprint(1, "scope:", NULL);
if (scope == 0x10) {
tinyprint(1, " loopback", NULL);
}
if (scope == 0x20) {
tinyprint(1, " linklocal", NULL);
}
if (scope == 0x40) {
tinyprint(1, " sitelocal", NULL);
}
if (scope == 0x00) {
tinyprint(1, " global", NULL);
}
tinyprint(1, "\n", NULL);
tinyprint(1, "addr flags:", NULL);
if (aflags & 0x01) {
tinyprint(1, " temporary", NULL);
}
if (aflags & 0x02) {
tinyprint(1, " nodad", NULL);
}
if (aflags & 0x04) {
tinyprint(1, " optimistic", NULL);
}
if (aflags & 0x08) {
tinyprint(1, " dadfailed", NULL);
}
if (aflags & 0x10) {
tinyprint(1, " homeaddress", NULL);
}
if (aflags & 0x20) {
tinyprint(1, " deprecated", NULL);
}
if (aflags & 0x40) {
tinyprint(1, " tentative", NULL);
}
if (aflags & 0x80) {
tinyprint(1, " permanent", NULL);
}
if (aflags & 0x100) {
tinyprint(1, " managetempaddr", NULL);
}
if (aflags & 0x200) {
tinyprint(1, " noprefixroute", NULL);
}
if (aflags & 0x400) {
tinyprint(1, " mcautojoin", NULL);
}
if (aflags & 0x800) {
tinyprint(1, " stable_privacy", NULL);
}
tinyprint(1, "\n", NULL);
}
tinyprint(1, "flags:", NULL);
if (ifa->ifa_flags & IFF_UP) {
tinyprint(1, " IFF_UP", NULL);

View file

@ -17,7 +17,12 @@ cut -d' ' -f2 /proc/mounts | while read -r line; do
return 0
fi
done
if whence doas >/dev/null; then
doas=doas
else
doas=sudo
fi
( set -x
sudo mount -t tmpfs -o size=10G,noatime,nodiratime /dev/shm "$o"
$doas mount -t tmpfs -o size=10G,noatime,nodiratime /dev/shm "$o"
)
# vim:ft=zsh

View file

@ -38,8 +38,21 @@ done
whence nproc >/dev/null || autoload -Uz nproc
j=-j$(nproc)
}
local make=${MAKE:-${COSMOCC:-/opt/cosmocc/current}/bin/make}
[[ -x $make ]] || make=${COSMO:-$PWD}/build/bootstrap/make
local make=$(
case $MAKE in
*/*) echo $MAKE ;;
?*) command -v $MAKE ;;
*) echo .cosmocc/current/bin/make ;;
esac
)
if [[ ! -x $make ]]; then
{ echo 'please install a suitable make, for example:'
echo
echo 'https://cosmo.zip/pub/cosmos/bin/make'
echo
echo 'then put it on $PATH or point $MAKE to it.'
} >&2; return 1
fi
( set -x
exec $make $j $flags MODE=$mode $targs )
# vim:ft=zsh

View file

@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT
JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx
MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg
VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm
aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo
I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng
o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G
A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB
zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW
RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----