mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Implement more security stuff
- Support deterministic stacks on OpenBSD - Support OpenBSD system call origin verification - Fix overrun by one in chibicc string token allocator - Get all chibicc tests passing under Address Sanitizer
This commit is contained in:
parent
cbfd4ccd1e
commit
c843243322
56 changed files with 376 additions and 245 deletions
|
@ -282,6 +282,9 @@ SECTIONS {
|
||||||
KEEP(*(.textwindowsepilogue))
|
KEEP(*(.textwindowsepilogue))
|
||||||
*(SORT_BY_ALIGNMENT(.text.modernity))
|
*(SORT_BY_ALIGNMENT(.text.modernity))
|
||||||
*(SORT_BY_ALIGNMENT(.text.modernity.*))
|
*(SORT_BY_ALIGNMENT(.text.modernity.*))
|
||||||
|
HIDDEN(__text_syscall_start = .);
|
||||||
|
*(.text.syscall .text.syscall.*)
|
||||||
|
HIDDEN(__text_syscall_end = .);
|
||||||
*(SORT_BY_ALIGNMENT(.text.hot))
|
*(SORT_BY_ALIGNMENT(.text.hot))
|
||||||
*(SORT_BY_ALIGNMENT(.text.hot.*))
|
*(SORT_BY_ALIGNMENT(.text.hot.*))
|
||||||
KEEP(*(.keep.text))
|
KEEP(*(.keep.text))
|
||||||
|
@ -483,6 +486,10 @@ SHSTUB2(.Lape.macho.dd.skip, RVA(ape.macho) / 8);
|
||||||
SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8);
|
SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8);
|
||||||
PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz);
|
PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz);
|
||||||
|
|
||||||
|
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
|
||||||
|
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
|
||||||
|
ROUNDDOWN(__text_syscall_start, PAGESIZE)));
|
||||||
|
|
||||||
HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24));
|
HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24));
|
||||||
HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40);
|
HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40);
|
||||||
HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt);
|
HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt);
|
||||||
|
|
|
@ -94,8 +94,7 @@ CONFIG_CPPFLAGS += \
|
||||||
CONFIG_CCFLAGS += \
|
CONFIG_CCFLAGS += \
|
||||||
$(BACKTRACES) \
|
$(BACKTRACES) \
|
||||||
$(FTRACE) \
|
$(FTRACE) \
|
||||||
-O1 \
|
-O2
|
||||||
-fno-inline
|
|
||||||
|
|
||||||
CONFIG_COPTS += \
|
CONFIG_COPTS += \
|
||||||
$(SECURITY_BLANKETS) \
|
$(SECURITY_BLANKETS) \
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
|
.text.syscall
|
||||||
|
|
||||||
/ Tiny Raw Linux Binary Tutorial
|
/ Tiny Raw Linux Binary Tutorial
|
||||||
/
|
/
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
* @errors ENOENT, ENOTDIR, ENOSYS
|
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @see fchmod()
|
* @see fchmod()
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int chmod(const char *pathname, uint32_t mode) {
|
int chmod(const char *pathname, uint32_t mode) {
|
||||||
if (!pathname) return efault();
|
if (!pathname) return efault();
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
* errno isn't restored to its original value, to detect prec. loss
|
* errno isn't restored to its original value, to detect prec. loss
|
||||||
* @see strftime(), gettimeofday()
|
* @see strftime(), gettimeofday()
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int clock_gettime(int clockid, struct timespec *out_ts) {
|
int clock_gettime(int clockid, struct timespec *out_ts) {
|
||||||
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */
|
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
* @param len 0 means ‘til end of file
|
* @param len 0 means ‘til end of file
|
||||||
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
|
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
|
||||||
* @return -1 on error
|
* @return -1 on error
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @note limited availability on rhel5 and openbsd
|
* @note limited availability on rhel5 and openbsd
|
||||||
* @see ftruncate()
|
* @see ftruncate()
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
* @errors ENOSYS
|
* @errors ENOSYS
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @see chmod()
|
* @see chmod()
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fchmod(int fd, uint32_t mode) {
|
int fchmod(int fd, uint32_t mode) {
|
||||||
/* TODO(jart): Windows */
|
/* TODO(jart): Windows */
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @see /etc/passwd for user ids
|
* @see /etc/passwd for user ids
|
||||||
* @see /etc/group for group ids
|
* @see /etc/group for group ids
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fchown(int fd, uint32_t uid, uint32_t gid) {
|
int fchown(int fd, uint32_t uid, uint32_t gid) {
|
||||||
/* TODO(jart): Windows? */
|
/* TODO(jart): Windows? */
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
* @param arg can be FD_CLOEXEC, etc. depending
|
* @param arg can be FD_CLOEXEC, etc. depending
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fcntl(int fd, int cmd, ...) {
|
int fcntl(int fd, int cmd, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @see fsync(), sync_file_range()
|
* @see fsync(), sync_file_range()
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
* @syscall
|
|
||||||
*/
|
*/
|
||||||
int fdatasync(int fd) {
|
int fdatasync(int fd) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
|
.text.syscall
|
||||||
|
|
||||||
/ Forks process without copying page tables.
|
/ Forks process without copying page tables.
|
||||||
/
|
/
|
||||||
|
|
|
@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @see mmap()
|
* @see mmap()
|
||||||
*/
|
*/
|
||||||
int mprotect(void *addr, uint64_t len, int prot) {
|
textsyscall int mprotect(void *addr, uint64_t len, int prot) {
|
||||||
bool cf;
|
bool cf;
|
||||||
int64_t rc;
|
int64_t rc;
|
||||||
uint32_t oldprot;
|
uint32_t oldprot;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "ape/relocations.h"
|
#include "ape/relocations.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Cosmopolitan ELF-Normative Linker Script.
|
* @fileoverview Cosmopolitan ELF-Normative Linker Script.
|
||||||
|
@ -66,6 +67,9 @@ SECTIONS {
|
||||||
.text : {
|
.text : {
|
||||||
*(SORT_BY_ALIGNMENT(.text.hot))
|
*(SORT_BY_ALIGNMENT(.text.hot))
|
||||||
KEEP(*(.keep.text))
|
KEEP(*(.keep.text))
|
||||||
|
HIDDEN(__text_syscall_start = .);
|
||||||
|
*(.text.syscall .text.syscall.*)
|
||||||
|
HIDDEN(__text_syscall_end = .);
|
||||||
*(.text .text.*)
|
*(.text .text.*)
|
||||||
KEEP(*(SORT_BY_NAME(.sort.text.*)))
|
KEEP(*(SORT_BY_NAME(.sort.text.*)))
|
||||||
}
|
}
|
||||||
|
@ -207,3 +211,7 @@ SECTIONS {
|
||||||
*(.*)
|
*(.*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
|
||||||
|
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
|
||||||
|
ROUNDDOWN(__text_syscall_start, PAGESIZE)));
|
||||||
|
|
|
@ -618,6 +618,7 @@ typedef uint64_t uintmax_t;
|
||||||
#define textexit _Section(".text.exit") noinstrument
|
#define textexit _Section(".text.exit") noinstrument
|
||||||
#define textreal _Section(".text.real")
|
#define textreal _Section(".text.real")
|
||||||
#define textwindows _Section(".text.windows")
|
#define textwindows _Section(".text.windows")
|
||||||
|
#define textsyscall _Section(".text.syscall")
|
||||||
#define antiquity _Section(".text.antiquity")
|
#define antiquity _Section(".text.antiquity")
|
||||||
#else
|
#else
|
||||||
#define testonly
|
#define testonly
|
||||||
|
|
|
@ -374,7 +374,9 @@ static const char *__asan_dscribe_heap_poison(long c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *__asan_describe_access_poison(int c) {
|
static const char *__asan_describe_access_poison(char *p) {
|
||||||
|
int c = p[0];
|
||||||
|
if (1 <= c && c <= 7) c = p[1];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case kAsanHeapFree:
|
case kAsanHeapFree:
|
||||||
return "heap use after free";
|
return "heap use after free";
|
||||||
|
@ -407,7 +409,7 @@ static const char *__asan_describe_access_poison(int c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t __asan_write(const void *data, size_t size) {
|
static textsyscall ssize_t __asan_write(const void *data, size_t size) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
if (weaken(write)) {
|
if (weaken(write)) {
|
||||||
if ((rc = weaken(write)(2, data, size)) != -1) {
|
if ((rc = weaken(write)(2, data, size)) != -1) {
|
||||||
|
@ -421,7 +423,7 @@ static ssize_t __asan_write_string(const char *s) {
|
||||||
return __asan_write(s, __asan_strlen(s));
|
return __asan_write(s, __asan_strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static wontreturn void __asan_exit(int rc) {
|
static textsyscall wontreturn void __asan_exit(int rc) {
|
||||||
if (weaken(_Exit)) {
|
if (weaken(_Exit)) {
|
||||||
weaken(_Exit)(rc);
|
weaken(_Exit)(rc);
|
||||||
} else {
|
} else {
|
||||||
|
@ -431,6 +433,7 @@ static wontreturn void __asan_exit(int rc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static wontreturn void __asan_abort(void) {
|
static wontreturn void __asan_abort(void) {
|
||||||
|
if (weaken(__die)) weaken(__die)();
|
||||||
if (weaken(abort)) weaken(abort)();
|
if (weaken(abort)) weaken(abort)();
|
||||||
__asan_exit(134);
|
__asan_exit(134);
|
||||||
}
|
}
|
||||||
|
@ -468,7 +471,7 @@ static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
|
||||||
const char *kind) {
|
const char *kind) {
|
||||||
char *p, ibuf[21], buf[256];
|
char *p, ibuf[21], buf[256];
|
||||||
p = __asan_report_start(buf);
|
p = __asan_report_start(buf);
|
||||||
p = __asan_stpcpy(p, __asan_describe_access_poison(*SHADOW(addr)));
|
p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr)));
|
||||||
p = __asan_stpcpy(p, " ");
|
p = __asan_stpcpy(p, " ");
|
||||||
p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf));
|
p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf));
|
||||||
p = __asan_stpcpy(p, "-byte ");
|
p = __asan_stpcpy(p, "-byte ");
|
||||||
|
@ -524,6 +527,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
|
||||||
__asan_unpoison((uintptr_t)p, n);
|
__asan_unpoison((uintptr_t)p, n);
|
||||||
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
|
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
|
||||||
__asan_poison((uintptr_t)p + n, c - n, overrun);
|
__asan_poison((uintptr_t)p + n, c - n, overrun);
|
||||||
|
__asan_memset(p, 0xF9, n);
|
||||||
WRITE64BE(p + c - sizeof(n), n);
|
WRITE64BE(p + c - sizeof(n), n);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
|
@ -664,6 +668,14 @@ void __asan_report_store_impl(uint8_t *addr, int size) {
|
||||||
__asan_report_memory_fault(addr, size, "store");
|
__asan_report_memory_fault(addr, size, "store");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __asan_poison_stack_memory(uintptr_t addr, size_t size) {
|
||||||
|
__asan_poison(addr, size, kAsanStackFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) {
|
||||||
|
__asan_unpoison(addr, size);
|
||||||
|
}
|
||||||
|
|
||||||
void __asan_alloca_poison(uintptr_t addr, size_t size) {
|
void __asan_alloca_poison(uintptr_t addr, size_t size) {
|
||||||
/* TODO(jart): Make sense of this function. */
|
/* TODO(jart): Make sense of this function. */
|
||||||
/* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */
|
/* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +31,18 @@
|
||||||
* @see __start_fatal_ndebug()
|
* @see __start_fatal_ndebug()
|
||||||
*/
|
*/
|
||||||
relegated void __start_fatal(const char *file, int line) {
|
relegated void __start_fatal(const char *file, int line) {
|
||||||
dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1,
|
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p;
|
||||||
file, line, program_invocation_short_name, RESET);
|
p = stpcpy(s, CLS);
|
||||||
|
p = stpcpy(p, RED);
|
||||||
|
p = stpcpy(p, "error");
|
||||||
|
p = stpcpy(p, BLUE1);
|
||||||
|
p = stpcpy(p, ":");
|
||||||
|
p = stpcpy(p, file);
|
||||||
|
p = stpcpy(p, ":");
|
||||||
|
p += int64toarray_radix10(line, p);
|
||||||
|
p = stpcpy(p, ":");
|
||||||
|
p = stpcpy(p, program_invocation_short_name);
|
||||||
|
p = stpcpy(p, RESET);
|
||||||
|
p = stpcpy(p, ": ");
|
||||||
|
write(2, s, p - s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
.macro .text.exit
|
.macro .text.exit
|
||||||
.section .text.exit,"ax",@progbits
|
.section .text.exit,"ax",@progbits
|
||||||
.endm
|
.endm
|
||||||
|
.macro .text.syscall
|
||||||
|
.section .text.syscall,"ax",@progbits
|
||||||
|
.endm
|
||||||
.macro .firstclass
|
.macro .firstclass
|
||||||
.section .text.hot,"ax",@progbits
|
.section .text.hot,"ax",@progbits
|
||||||
.endm
|
.endm
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
||||||
│ │
|
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
|
||||||
│ above copyright notice and this permission notice appear in all copies. │
|
|
||||||
│ │
|
|
||||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
||||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
||||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
||||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
||||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
||||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
||||||
#include "libc/nexgen32e/macros.h"
|
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
|
||||||
#include "libc/macros.h"
|
|
||||||
|
|
||||||
/ Mutates string to uppercase roman characters.
|
|
||||||
/
|
|
||||||
/ @param RDI points to non-const NUL-terminated string
|
|
||||||
/ @return RAX will be original RDI
|
|
||||||
/ @note 10x faster than C
|
|
||||||
strtoupper:
|
|
||||||
mov $'A-'a,%edx # adding this uppers
|
|
||||||
mov $'a|'z<<8,%ecx # uint8_t range a..z
|
|
||||||
jmp strcaseconv
|
|
||||||
.endfn strtoupper,globl
|
|
||||||
|
|
||||||
/ Mutates string to lowercase roman characters.
|
|
||||||
/
|
|
||||||
/ @param RDI points to non-const NUL-terminated string
|
|
||||||
/ @return RAX will be original RDI
|
|
||||||
/ @note 10x faster than C
|
|
||||||
strtolower:
|
|
||||||
mov $'a-'A,%edx # adding this lowers
|
|
||||||
mov $'A|'Z<<8,%ecx # uint8_t range A..Z
|
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
|
||||||
.endfn strtolower,globl
|
|
||||||
|
|
||||||
/ Support code for strtolower() and strtoupper().
|
|
||||||
/
|
|
||||||
/ @param RDI points to non-const NUL-terminated string
|
|
||||||
/ @param CL defines start of character range to mutate
|
|
||||||
/ @param CH defines end of character range to mutate
|
|
||||||
/ @param DL is added to each DIL ∈ [CL,CH]
|
|
||||||
/ @return RAX will be original RDI
|
|
||||||
strcaseconv:
|
|
||||||
.leafprologue
|
|
||||||
.profilable
|
|
||||||
mov %rdi,%rsi
|
|
||||||
0: testb $15,%sil # is it aligned?
|
|
||||||
#if X86_NEED(SSE4_2)
|
|
||||||
jz .Lsse4
|
|
||||||
#else
|
|
||||||
jnz 1f
|
|
||||||
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
|
|
||||||
jnz .Lsse4 # is it nehalem?
|
|
||||||
#endif
|
|
||||||
1: lodsb # AL = *RSI++
|
|
||||||
test %al,%al # is it NUL?
|
|
||||||
jz 3f
|
|
||||||
cmp %cl,%al # is it in range?
|
|
||||||
jb 0b
|
|
||||||
cmp %ch,%al
|
|
||||||
ja 0b
|
|
||||||
add %dl,-1(%rsi)
|
|
||||||
jmp 0b
|
|
||||||
.Lsse4: movd %ecx,%xmm1 # XMM1 = ['A,'Z,0,0,...]
|
|
||||||
movd %edx,%xmm2 # XMM2 = ['a-'A,'a-'A,...]
|
|
||||||
pbroadcastb %xmm2
|
|
||||||
xor %ecx,%ecx
|
|
||||||
2: movdqa (%rsi,%rcx),%xmm3
|
|
||||||
/ ┌─0:index of the LEAST significant, set, bit is used
|
|
||||||
/ │ regardless of corresponding input element validity
|
|
||||||
/ │ intres2 is returned in least significant bits of xmm0
|
|
||||||
/ ├─1:index of the MOST significant, set, bit is used
|
|
||||||
/ │ regardless of corresponding input element validity
|
|
||||||
/ │ each bit of intres2 is expanded to byte/word
|
|
||||||
/ │┌─0:negation of intres1 is for all 16 (8) bits
|
|
||||||
/ │├─1:negation of intres1 is masked by reg/mem validity
|
|
||||||
/ ││┌─intres1 is negated (1’s complement)
|
|
||||||
/ │││┌─mode{equalany,ranges,equaleach,equalordered}
|
|
||||||
/ ││││ ┌─issigned
|
|
||||||
/ ││││ │┌─is16bit
|
|
||||||
/ u│││├┐││
|
|
||||||
pcmpistrm $0b01000100,%xmm3,%xmm1 # →XMM0 8-bit byte mask
|
|
||||||
pand %xmm2,%xmm0 # won't mask after NUL
|
|
||||||
paddb %xmm0,%xmm3
|
|
||||||
movdqa %xmm3,(%rsi,%rcx)
|
|
||||||
lea 16(%rcx),%rcx
|
|
||||||
jnz 2b # PCMPISTRM found NUL
|
|
||||||
3: mov %rdi,%rax
|
|
||||||
.leafepilogue
|
|
||||||
.endfn strcaseconv
|
|
||||||
.source __FILE__
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
.real
|
.text.syscall
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
/ Terminates program abnormally.
|
/ Terminates program abnormally.
|
||||||
|
|
|
@ -95,7 +95,7 @@ static int arch_prctl$freebsd(int code, int64_t addr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arch_prctl$xnu(int code, int64_t addr) {
|
static textsyscall int arch_prctl$xnu(int code, int64_t addr) {
|
||||||
int ax;
|
int ax;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ARCH_SET_GS:
|
case ARCH_SET_GS:
|
||||||
|
@ -113,7 +113,7 @@ static int arch_prctl$xnu(int code, int64_t addr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arch_prctl$openbsd(int code, int64_t addr) {
|
static textsyscall int arch_prctl$openbsd(int code, int64_t addr) {
|
||||||
int64_t rax;
|
int64_t rax;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ARCH_GET_FS:
|
case ARCH_GET_FS:
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
.privileged
|
.text.syscall
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
/ Terminates process, ignoring destructors and atexit() handlers.
|
/ Terminates process, ignoring destructors and atexit() handlers.
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#define WasImported(SLOT) \
|
#define WasImported(SLOT) \
|
||||||
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
|
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
|
||||||
|
|
||||||
static privileged void __print$nt(const void *data, size_t len) {
|
static void __print$nt(const void *data, size_t len) {
|
||||||
int64_t hand;
|
int64_t hand;
|
||||||
char xmm[256];
|
char xmm[256];
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
|
@ -49,7 +49,7 @@ static privileged void __print$nt(const void *data, size_t len) {
|
||||||
* @param len can be computed w/ tinystrlen()
|
* @param len can be computed w/ tinystrlen()
|
||||||
* @clob nothing except flags
|
* @clob nothing except flags
|
||||||
*/
|
*/
|
||||||
privileged void __print(const void *data, size_t len) {
|
textsyscall void __print(const void *data, size_t len) {
|
||||||
int64_t ax, ordinal;
|
int64_t ax, ordinal;
|
||||||
if (WasImported(__imp_WriteFile)) {
|
if (WasImported(__imp_WriteFile)) {
|
||||||
__print$nt(data, len);
|
__print$nt(data, len);
|
||||||
|
@ -68,7 +68,7 @@ privileged void __print(const void *data, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
privileged void __print_string(const char *s) {
|
void __print_string(const char *s) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (s[n]) ++n;
|
while (s[n]) ++n;
|
||||||
__print(s, n);
|
__print(s, n);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
/**
|
/**
|
||||||
* Aborts program under enemy fire to avoid being taken alive.
|
* Aborts program under enemy fire to avoid being taken alive.
|
||||||
*/
|
*/
|
||||||
void __stack_chk_fail(void) {
|
textsyscall void __stack_chk_fail(void) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
int64_t ax, cx, si;
|
int64_t ax, cx, si;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
||||||
return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
||||||
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
||||||
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "libc/str/oldutf16.internal.h"
|
#include "libc/str/oldutf16.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
/* TODO(jart): DELETE */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes character to string as UTF-16.
|
* Encodes character to string as UTF-16.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) {
|
||||||
return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 |
|
||||||
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
(uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 |
|
||||||
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
(uint64_t)p[1] << 010 | (uint64_t)p[0] << 000;
|
||||||
|
|
|
@ -187,7 +187,6 @@ char16_t *tinystrstr16(const char16_t *, const char16_t *) strlenesque;
|
||||||
void *tinymemmem(const void *, size_t, const void *, size_t) strlenesque;
|
void *tinymemmem(const void *, size_t, const void *, size_t) strlenesque;
|
||||||
void *tinymemccpy(void *, const void *, int, size_t) memcpyesque;
|
void *tinymemccpy(void *, const void *, int, size_t) memcpyesque;
|
||||||
|
|
||||||
void *memtolower(void *, size_t);
|
|
||||||
char *strntolower(char *, size_t);
|
char *strntolower(char *, size_t);
|
||||||
char *strtolower(char *) paramsnonnull();
|
char *strtolower(char *) paramsnonnull();
|
||||||
char *strntoupper(char *, size_t);
|
char *strntoupper(char *, size_t);
|
||||||
|
|
|
@ -18,16 +18,18 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates string to ASCII uppercase w/ limit.
|
||||||
|
*
|
||||||
|
* @praam s is string
|
||||||
|
* @praam n is max bytes to consider
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
char *strntoupper(char *s, size_t n) {
|
char *strntoupper(char *s, size_t n) {
|
||||||
unsigned char *p = (unsigned char *)s;
|
size_t i;
|
||||||
for (;;) {
|
for (i = 0; s[i] && i < n; ++i) {
|
||||||
if (n-- && *p) {
|
if ('a' <= s[i] && s[i] <= 'z') {
|
||||||
if ('a' <= *p && *p <= 'z') {
|
s[i] -= 'a' - 'A';
|
||||||
*p -= 'a' - 'A';
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
|
|
@ -16,9 +16,20 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/math.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/nexgen32e/nexgen32e.h"
|
|
||||||
|
|
||||||
bool ctz(double x, double y) {
|
/**
|
||||||
return __builtin_islessgreater(x, y);
|
* Mutates string to ASCII lowercase.
|
||||||
|
*
|
||||||
|
* @praam s is string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
char *strtolower(char *s) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; s[i]; ++i) {
|
||||||
|
if ('A' <= s[i] && s[i] <= 'Z') {
|
||||||
|
s[i] += 'a' - 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
}
|
}
|
35
libc/str/strtoupper.c
Normal file
35
libc/str/strtoupper.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates string to ASCII uppercase.
|
||||||
|
*
|
||||||
|
* @praam s is string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
char *strtoupper(char *s) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; s[i]; ++i) {
|
||||||
|
if ('a' <= s[i] && s[i] <= 'z') {
|
||||||
|
s[i] -= 'a' - 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -17,15 +17,21 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/tinymemmem.internal.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Naïve substring search implementation.
|
* Naïve substring search implementation.
|
||||||
* @see libc/alg/memmem.c
|
* @see libc/alg/memmem.c
|
||||||
*/
|
*/
|
||||||
void *tinymemmem(const void *haystk, size_t haystksize, const void *needle,
|
void *tinymemmem(const void *haystack, size_t haystacksize, const void *needle,
|
||||||
size_t needlesize) {
|
size_t needlesize) {
|
||||||
return (/*unconst*/ void *)tinymemmemi(
|
size_t i;
|
||||||
(const unsigned char *)haystk, haystksize, (const unsigned char *)needle,
|
const char *p, *pe;
|
||||||
needlesize);
|
for (p = haystack, pe = p + haystacksize; p < pe;) {
|
||||||
|
for (++p, i = 0;;) {
|
||||||
|
if (++i > needlesize) return p - 1;
|
||||||
|
if (p == pe) break;
|
||||||
|
if (((const char *)needle)[i - 1] != (p - 1)[i - 1]) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !haystacksize && !needlesize ? haystack : NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_
|
|
||||||
#define COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_
|
|
||||||
#ifndef __STRICT_ANSI__
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
||||||
|
|
||||||
forceinline void *tinymemmemi(const void *haystk, size_t haystksize,
|
|
||||||
const void *needle, size_t needlesize) {
|
|
||||||
const char *p = (const char *)haystk;
|
|
||||||
const char *pe = (const char *)haystk + haystksize;
|
|
||||||
while (p < pe) {
|
|
||||||
size_t i = 0;
|
|
||||||
++p;
|
|
||||||
for (;;) {
|
|
||||||
++i;
|
|
||||||
if (i > needlesize) return (/*unconst*/ char *)(p - 1);
|
|
||||||
if (p == pe) break;
|
|
||||||
if (((const char *)needle)[i - 1] != (p - 1)[i - 1]) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (/*unconst*/ char *)(!haystksize && !needlesize ? haystk : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
||||||
#endif /* !ANSI */
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_STR_TINYMEMMEM_H_ */
|
|
|
@ -17,13 +17,22 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/internal.h"
|
#include "libc/str/internal.h"
|
||||||
#include "libc/str/tinystrstr.internal.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Naïve substring search implementation.
|
* Naïve substring search implementation.
|
||||||
* @see libc/str/strstr.c
|
* @see libc/str/strstr.c
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
char *(tinystrstr)(const char *haystack, const char *needle) {
|
char *tinystrstr(const char *haystack, const char *needle) {
|
||||||
return (/*unconst*/ char *)tinystrstr(haystack, needle);
|
size_t i;
|
||||||
|
for (;;) {
|
||||||
|
for (i = 0;;) {
|
||||||
|
if (!needle[i]) return (/*unconst*/ char *)haystack;
|
||||||
|
if (!haystack[i]) break;
|
||||||
|
if (needle[i] != haystack[i]) break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (!*haystack++) break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_
|
|
||||||
#define COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
|
||||||
|
|
||||||
#define tinystrstr(HAYSTACK, NEEDLE) \
|
|
||||||
({ \
|
|
||||||
autotype(HAYSTACK) Haystack = (HAYSTACK); \
|
|
||||||
typeof(Haystack) Needle = (NEEDLE); \
|
|
||||||
for (;;) { \
|
|
||||||
size_t i = 0; \
|
|
||||||
for (;;) { \
|
|
||||||
if (!Needle[i]) goto Found; \
|
|
||||||
if (!Haystack[i]) break; \
|
|
||||||
if (Needle[i] != Haystack[i]) break; \
|
|
||||||
++i; \
|
|
||||||
} \
|
|
||||||
if (!*Haystack++) break; \
|
|
||||||
} \
|
|
||||||
Haystack = NULL; \
|
|
||||||
Found: \
|
|
||||||
Haystack; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_STR_TINYSTRSTR_H_ */
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/str/internal.h"
|
#include "libc/str/internal.h"
|
||||||
#include "libc/str/tinystrstr.internal.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Naïve substring search implementation.
|
* Naïve substring search implementation.
|
||||||
|
@ -25,5 +24,15 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
char16_t *tinystrstr16(const char16_t *haystack, const char16_t *needle) {
|
char16_t *tinystrstr16(const char16_t *haystack, const char16_t *needle) {
|
||||||
return (/*unconst*/ char16_t *)tinystrstr(haystack, needle);
|
size_t i;
|
||||||
|
for (;;) {
|
||||||
|
for (i = 0;;) {
|
||||||
|
if (!needle[i]) return (/*unconst*/ char16_t *)haystack;
|
||||||
|
if (!haystack[i]) break;
|
||||||
|
if (needle[i] != haystack[i]) break;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (!*haystack++) break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "libc/str/tpdecode.internal.h"
|
#include "libc/str/tpdecode.internal.h"
|
||||||
#include "libc/str/tpdecodecb.internal.h"
|
#include "libc/str/tpdecodecb.internal.h"
|
||||||
|
|
||||||
|
/* TODO(jart): DELETE */
|
||||||
|
|
||||||
forceinline int getbyte(void *arg, uint32_t i) {
|
forceinline int getbyte(void *arg, uint32_t i) {
|
||||||
return ((const unsigned char *)arg)[i];
|
return ((const unsigned char *)arg)[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,14 @@ COSMOPOLITAN_C_START_
|
||||||
uint64_t tpenc(int32_t) pureconst;
|
uint64_t tpenc(int32_t) pureconst;
|
||||||
|
|
||||||
#ifndef __STRICT_ANSI__
|
#ifndef __STRICT_ANSI__
|
||||||
#define tpenc(CODE) \
|
#define tpenc(CODE) \
|
||||||
({ \
|
({ \
|
||||||
long Buf; \
|
long Edi, Buf; \
|
||||||
int32_t Code = (CODE); \
|
asm("call\ttpenc" \
|
||||||
if (0 <= Code && Code <= 127) { \
|
: "=a"(Buf), "=D"(Edi) \
|
||||||
Buf = Code; \
|
: "1"(CODE) \
|
||||||
} else { \
|
: "rcx", "rdx", "cc"); \
|
||||||
asm("call\ttpenc" \
|
Buf; \
|
||||||
: "=a"(Buf), "+D"(Code) \
|
|
||||||
: /* inputs */ \
|
|
||||||
: "rcx", "rdx", "cc"); \
|
|
||||||
} \
|
|
||||||
Buf; \
|
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,253 +22,367 @@
|
||||||
/ @fileoverview Address Sanitizer Linker Poison
|
/ @fileoverview Address Sanitizer Linker Poison
|
||||||
|
|
||||||
__asan_addr_is_in_fake_stack:
|
__asan_addr_is_in_fake_stack:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_addr_is_in_fake_stack,weak
|
.endfn __asan_addr_is_in_fake_stack,weak
|
||||||
|
|
||||||
__asan_after_dynamic_init:
|
__asan_after_dynamic_init:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_after_dynamic_init,weak
|
.endfn __asan_after_dynamic_init,weak
|
||||||
|
|
||||||
__asan_alloca_poison:
|
__asan_alloca_poison:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_alloca_poison,weak
|
.endfn __asan_alloca_poison,weak
|
||||||
|
|
||||||
__asan_allocas_unpoison:
|
__asan_allocas_unpoison:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_allocas_unpoison,weak
|
.endfn __asan_allocas_unpoison,weak
|
||||||
|
|
||||||
__asan_before_dynamic_init:
|
__asan_before_dynamic_init:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_before_dynamic_init,weak
|
.endfn __asan_before_dynamic_init,weak
|
||||||
|
|
||||||
__asan_get_current_fake_stack:
|
__asan_get_current_fake_stack:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_get_current_fake_stack,weak
|
.endfn __asan_get_current_fake_stack,weak
|
||||||
|
|
||||||
__asan_handle_no_return:
|
__asan_handle_no_return:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_handle_no_return,weak
|
.endfn __asan_handle_no_return,weak
|
||||||
|
|
||||||
__asan_init:
|
__asan_init:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_init,weak
|
.endfn __asan_init,weak
|
||||||
|
|
||||||
__asan_load1:
|
__asan_load1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load1,weak
|
.endfn __asan_load1,weak
|
||||||
|
|
||||||
__asan_load2:
|
__asan_load2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load2,weak
|
.endfn __asan_load2,weak
|
||||||
|
|
||||||
__asan_load4:
|
__asan_load4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load4,weak
|
.endfn __asan_load4,weak
|
||||||
|
|
||||||
__asan_load8:
|
__asan_load8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load8,weak
|
.endfn __asan_load8,weak
|
||||||
|
|
||||||
__asan_load16:
|
__asan_load16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load16,weak
|
.endfn __asan_load16,weak
|
||||||
|
|
||||||
__asan_load32:
|
__asan_load32:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_load32,weak
|
.endfn __asan_load32,weak
|
||||||
|
|
||||||
__asan_option_detect_stack_use_after_return:
|
__asan_option_detect_stack_use_after_return:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_option_detect_stack_use_after_return,weak
|
.endfn __asan_option_detect_stack_use_after_return,weak
|
||||||
|
|
||||||
__asan_poison_stack_memory:
|
|
||||||
ud2
|
|
||||||
.endfn __asan_poison_stack_memory,weak
|
|
||||||
|
|
||||||
__asan_register_globals:
|
__asan_register_globals:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_register_globals,weak
|
.endfn __asan_register_globals,weak
|
||||||
|
|
||||||
__asan_report_load1:
|
__asan_report_load1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load1,weak
|
.endfn __asan_report_load1,weak
|
||||||
|
|
||||||
__asan_report_load2:
|
__asan_report_load2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load2,weak
|
.endfn __asan_report_load2,weak
|
||||||
|
|
||||||
__asan_report_load4:
|
__asan_report_load4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load4,weak
|
.endfn __asan_report_load4,weak
|
||||||
|
|
||||||
__asan_report_load8:
|
__asan_report_load8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load8,weak
|
.endfn __asan_report_load8,weak
|
||||||
|
|
||||||
__asan_report_load16:
|
__asan_report_load16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load16,weak
|
.endfn __asan_report_load16,weak
|
||||||
|
|
||||||
__asan_report_load_n:
|
__asan_report_load_n:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_load_n,weak
|
.endfn __asan_report_load_n,weak
|
||||||
|
|
||||||
__asan_report_store1:
|
__asan_report_store1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store1,weak
|
.endfn __asan_report_store1,weak
|
||||||
|
|
||||||
__asan_report_store2:
|
__asan_report_store2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store2,weak
|
.endfn __asan_report_store2,weak
|
||||||
|
|
||||||
__asan_report_store4:
|
__asan_report_store4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store4,weak
|
.endfn __asan_report_store4,weak
|
||||||
|
|
||||||
__asan_report_store8:
|
__asan_report_store8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store8,weak
|
.endfn __asan_report_store8,weak
|
||||||
|
|
||||||
__asan_report_store16:
|
__asan_report_store16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store16,weak
|
.endfn __asan_report_store16,weak
|
||||||
|
|
||||||
__asan_report_store32:
|
__asan_report_store32:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store32,weak
|
.endfn __asan_report_store32,weak
|
||||||
|
|
||||||
__asan_report_store_n:
|
__asan_report_store_n:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_report_store_n,weak
|
.endfn __asan_report_store_n,weak
|
||||||
|
|
||||||
__asan_stack_free:
|
__asan_stack_free:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free,weak
|
.endfn __asan_stack_free,weak
|
||||||
|
|
||||||
__asan_stack_free_0:
|
__asan_stack_free_0:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_0,weak
|
.endfn __asan_stack_free_0,weak
|
||||||
|
|
||||||
__asan_stack_free_1:
|
__asan_stack_free_1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_1,weak
|
.endfn __asan_stack_free_1,weak
|
||||||
|
|
||||||
__asan_stack_free_10:
|
__asan_stack_free_10:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_10,weak
|
.endfn __asan_stack_free_10,weak
|
||||||
|
|
||||||
__asan_stack_free_2:
|
__asan_stack_free_2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_2,weak
|
.endfn __asan_stack_free_2,weak
|
||||||
|
|
||||||
__asan_stack_free_3:
|
__asan_stack_free_3:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_3,weak
|
.endfn __asan_stack_free_3,weak
|
||||||
|
|
||||||
__asan_stack_free_4:
|
__asan_stack_free_4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_4,weak
|
.endfn __asan_stack_free_4,weak
|
||||||
|
|
||||||
__asan_stack_free_5:
|
__asan_stack_free_5:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_5,weak
|
.endfn __asan_stack_free_5,weak
|
||||||
|
|
||||||
__asan_stack_free_6:
|
__asan_stack_free_6:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_6,weak
|
.endfn __asan_stack_free_6,weak
|
||||||
|
|
||||||
__asan_stack_free_7:
|
__asan_stack_free_7:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_7,weak
|
.endfn __asan_stack_free_7,weak
|
||||||
|
|
||||||
__asan_stack_free_8:
|
__asan_stack_free_8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_8,weak
|
.endfn __asan_stack_free_8,weak
|
||||||
|
|
||||||
__asan_stack_free_9:
|
__asan_stack_free_9:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_free_9,weak
|
.endfn __asan_stack_free_9,weak
|
||||||
|
|
||||||
__asan_stack_malloc:
|
__asan_stack_malloc:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc,weak
|
.endfn __asan_stack_malloc,weak
|
||||||
|
|
||||||
__asan_stack_malloc_0:
|
__asan_stack_malloc_0:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_0,weak
|
.endfn __asan_stack_malloc_0,weak
|
||||||
|
|
||||||
__asan_stack_malloc_1:
|
__asan_stack_malloc_1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_1,weak
|
.endfn __asan_stack_malloc_1,weak
|
||||||
|
|
||||||
__asan_stack_malloc_2:
|
__asan_stack_malloc_2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_2,weak
|
.endfn __asan_stack_malloc_2,weak
|
||||||
|
|
||||||
__asan_stack_malloc_3:
|
__asan_stack_malloc_3:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_3,weak
|
.endfn __asan_stack_malloc_3,weak
|
||||||
|
|
||||||
__asan_stack_malloc_4:
|
__asan_stack_malloc_4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_4,weak
|
.endfn __asan_stack_malloc_4,weak
|
||||||
|
|
||||||
__asan_stack_malloc_5:
|
__asan_stack_malloc_5:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_5,weak
|
.endfn __asan_stack_malloc_5,weak
|
||||||
|
|
||||||
__asan_stack_malloc_6:
|
__asan_stack_malloc_6:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_6,weak
|
.endfn __asan_stack_malloc_6,weak
|
||||||
|
|
||||||
__asan_stack_malloc_7:
|
__asan_stack_malloc_7:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_7,weak
|
.endfn __asan_stack_malloc_7,weak
|
||||||
|
|
||||||
__asan_stack_malloc_8:
|
__asan_stack_malloc_8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_8,weak
|
.endfn __asan_stack_malloc_8,weak
|
||||||
|
|
||||||
__asan_stack_malloc_9:
|
__asan_stack_malloc_9:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_9,weak
|
.endfn __asan_stack_malloc_9,weak
|
||||||
|
|
||||||
__asan_stack_malloc_10:
|
__asan_stack_malloc_10:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_stack_malloc_10,weak
|
.endfn __asan_stack_malloc_10,weak
|
||||||
|
|
||||||
__asan_store1:
|
__asan_store1:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store1,weak
|
.endfn __asan_store1,weak
|
||||||
|
|
||||||
__asan_store2:
|
__asan_store2:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store2,weak
|
.endfn __asan_store2,weak
|
||||||
|
|
||||||
__asan_store4:
|
__asan_store4:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store4,weak
|
.endfn __asan_store4,weak
|
||||||
|
|
||||||
__asan_store8:
|
__asan_store8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store8,weak
|
.endfn __asan_store8,weak
|
||||||
|
|
||||||
__asan_store16:
|
__asan_store16:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store16,weak
|
.endfn __asan_store16,weak
|
||||||
|
|
||||||
__asan_store32:
|
__asan_store32:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_store32,weak
|
.endfn __asan_store32,weak
|
||||||
|
|
||||||
__asan_unpoison_stack_memory:
|
|
||||||
ud2
|
|
||||||
.endfn __asan_unpoison_stack_memory,weak
|
|
||||||
|
|
||||||
__asan_unregister_globals:
|
__asan_unregister_globals:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_unregister_globals,weak
|
.endfn __asan_unregister_globals,weak
|
||||||
|
|
||||||
__asan_version_mismatch_check_v8:
|
__asan_version_mismatch_check_v8:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
ud2
|
ud2
|
||||||
.endfn __asan_version_mismatch_check_v8,weak
|
.endfn __asan_version_mismatch_check_v8,weak
|
||||||
|
|
2
libc/sysv/calls/msyscall.s
Normal file
2
libc/sysv/calls/msyscall.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.internal.inc"
|
||||||
|
.scall msyscall 0x0025ffffffffffff globl
|
|
@ -237,8 +237,9 @@ syscon mmap MAP_SHARED 1 1 1 1 1 # forced consensus & faked nt
|
||||||
syscon mmap MAP_PRIVATE 2 2 2 2 2 # forced consensus & faked nt
|
syscon mmap MAP_PRIVATE 2 2 2 2 2 # forced consensus & faked nt
|
||||||
syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10 # unix consensus; openbsd appears to forbid; faked nt
|
syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10 # unix consensus; openbsd appears to forbid; faked nt
|
||||||
syscon mmap MAP_ANONYMOUS 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
|
syscon mmap MAP_ANONYMOUS 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
|
||||||
|
syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x4000 0x100000 # mandatory for OpenBSD stacks; MAP_STACK on Free/OpenBSD; MEM_TOP_DOWN on NT
|
||||||
|
syscon mmap MAP_CONCEAL 0 0 0x20000 0x8000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
|
||||||
syscon mmap MAP_NORESERVE 0x4000 0x40 0 0 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
syscon mmap MAP_NORESERVE 0x4000 0x40 0 0 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
||||||
syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x0400 0x100000 # MAP_STACK on BSD; MEM_TOP_DOWN on NT
|
|
||||||
syscon mmap MAP_HUGETLB 0x040000 0 0 0 0x80000000 # kNtSecLargePages
|
syscon mmap MAP_HUGETLB 0x040000 0 0 0 0x80000000 # kNtSecLargePages
|
||||||
syscon mmap MAP_HUGE_MASK 63 0 0 0 0
|
syscon mmap MAP_HUGE_MASK 63 0 0 0 0
|
||||||
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0
|
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0
|
||||||
|
@ -246,6 +247,8 @@ syscon mmap MAP_LOCKED 0x2000 0 0 0 0
|
||||||
syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0
|
syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0
|
||||||
syscon mmap MAP_POPULATE 0x8000 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
|
syscon mmap MAP_POPULATE 0x8000 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
|
||||||
syscon mmap MAP_TYPE 15 0 0 0 0 # what is it
|
syscon mmap MAP_TYPE 15 0 0 0 0 # what is it
|
||||||
|
syscon compat MAP_STACK 0x0100 0 0x0400 0x4000 0x100000 # use MAP_GROWSDOWN
|
||||||
|
syscon compat MAP_NOCORE 0 0 0x20000 0x8000 0 # use MAP_CONCEAL
|
||||||
syscon compat MAP_ANON 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
|
syscon compat MAP_ANON 0x20 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
|
||||||
syscon compat MAP_STACK 0x020000 0 0x0400 0x4000 0x100000
|
syscon compat MAP_STACK 0x020000 0 0x0400 0x4000 0x100000
|
||||||
syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 # ignored
|
syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 # ignored
|
||||||
|
@ -3112,6 +3115,7 @@ syscon nr __NR_io_uring_setup 0x01a9 -1 -1 -1 -1
|
||||||
syscon nr __NR_io_uring_enter 0x01aa -1 -1 -1 -1
|
syscon nr __NR_io_uring_enter 0x01aa -1 -1 -1 -1
|
||||||
syscon nr __NR_io_uring_register 0x01ab -1 -1 -1 -1
|
syscon nr __NR_io_uring_register 0x01ab -1 -1 -1 -1
|
||||||
syscon nr __NR_pledge -1 -1 -1 0x006c -1
|
syscon nr __NR_pledge -1 -1 -1 0x006c -1
|
||||||
|
syscon nr __NR_msyscall -1 -1 -1 0x0025 -1
|
||||||
syscon nr __NR_ktrace -1 -1 0x002d 0x002d -1
|
syscon nr __NR_ktrace -1 -1 0x002d 0x002d -1
|
||||||
syscon nr __NR_kqueue -1 0x200016a 0x016a 0x010d -1
|
syscon nr __NR_kqueue -1 0x200016a 0x016a 0x010d -1
|
||||||
syscon nr __NR_kevent -1 0x2000171 0x0230 0x0048 -1
|
syscon nr __NR_kevent -1 0x2000171 0x0230 0x0048 -1
|
||||||
|
|
2
libc/sysv/consts/MAP_CONCEAL.s
Normal file
2
libc/sysv/consts/MAP_CONCEAL.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
|
.syscon mmap MAP_CONCEAL 0 0 0x20000 0x8000 0
|
|
@ -1,2 +1,2 @@
|
||||||
.include "libc/sysv/consts/syscon.inc"
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
.syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x0400 0x100000
|
.syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x4000 0x100000
|
||||||
|
|
2
libc/sysv/consts/MAP_NOCORE.s
Normal file
2
libc/sysv/consts/MAP_NOCORE.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
|
.syscon compat MAP_NOCORE 0 0 0x20000 0x8000 0
|
2
libc/sysv/consts/__NR_msyscall.s
Normal file
2
libc/sysv/consts/__NR_msyscall.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "libc/sysv/consts/syscon.inc"
|
||||||
|
.syscon nr __NR_msyscall -1 -1 -1 0x0025 -1
|
|
@ -21,7 +21,6 @@ hidden extern const long MAP_NORESERVE;
|
||||||
hidden extern const long MAP_POPULATE;
|
hidden extern const long MAP_POPULATE;
|
||||||
hidden extern const long MAP_PRIVATE;
|
hidden extern const long MAP_PRIVATE;
|
||||||
hidden extern const long MAP_SHARED;
|
hidden extern const long MAP_SHARED;
|
||||||
hidden extern const long MAP_STACK;
|
|
||||||
hidden extern const long MAP_TYPE;
|
hidden extern const long MAP_TYPE;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
|
@ -34,6 +33,7 @@ COSMOPOLITAN_C_END_
|
||||||
|
|
||||||
#define MAP_32BIT SYMBOLIC(MAP_32BIT)
|
#define MAP_32BIT SYMBOLIC(MAP_32BIT)
|
||||||
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)
|
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)
|
||||||
|
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
|
||||||
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
|
||||||
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
|
||||||
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
|
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
|
||||||
|
@ -46,7 +46,8 @@ COSMOPOLITAN_C_END_
|
||||||
#define MAP_POPULATE SYMBOLIC(MAP_POPULATE)
|
#define MAP_POPULATE SYMBOLIC(MAP_POPULATE)
|
||||||
#define MAP_TYPE SYMBOLIC(MAP_TYPE)
|
#define MAP_TYPE SYMBOLIC(MAP_TYPE)
|
||||||
|
|
||||||
#define MAP_ANON MAP_ANONYMOUS
|
#define MAP_ANON MAP_ANONYMOUS
|
||||||
#define MAP_STACK MAP_GROWSDOWN
|
#define MAP_NOCORE MAP_CONCEAL
|
||||||
|
#define MAP_STACK MAP_GROWSDOWN
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MAP_H_ */
|
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MAP_H_ */
|
||||||
|
|
|
@ -332,6 +332,7 @@
|
||||||
#define __NR_io_uring_enter SYMBOLIC(__NR_io_uring_enter)
|
#define __NR_io_uring_enter SYMBOLIC(__NR_io_uring_enter)
|
||||||
#define __NR_io_uring_register SYMBOLIC(__NR_io_uring_register)
|
#define __NR_io_uring_register SYMBOLIC(__NR_io_uring_register)
|
||||||
#define __NR_pledge SYMBOLIC(__NR_pledge)
|
#define __NR_pledge SYMBOLIC(__NR_pledge)
|
||||||
|
#define __NR_msyscall SYMBOLIC(__NR_msyscall)
|
||||||
#define __NR_ktrace SYMBOLIC(__NR_ktrace)
|
#define __NR_ktrace SYMBOLIC(__NR_ktrace)
|
||||||
#define __NR_kqueue SYMBOLIC(__NR_kqueue)
|
#define __NR_kqueue SYMBOLIC(__NR_kqueue)
|
||||||
#define __NR_kevent SYMBOLIC(__NR_kevent)
|
#define __NR_kevent SYMBOLIC(__NR_kevent)
|
||||||
|
@ -1105,6 +1106,7 @@ hidden extern const long __NR_io_uring_setup;
|
||||||
hidden extern const long __NR_io_uring_enter;
|
hidden extern const long __NR_io_uring_enter;
|
||||||
hidden extern const long __NR_io_uring_register;
|
hidden extern const long __NR_io_uring_register;
|
||||||
hidden extern const long __NR_pledge;
|
hidden extern const long __NR_pledge;
|
||||||
|
hidden extern const long __NR_msyscall;
|
||||||
hidden extern const long __NR_ktrace;
|
hidden extern const long __NR_ktrace;
|
||||||
hidden extern const long __NR_kqueue;
|
hidden extern const long __NR_kqueue;
|
||||||
hidden extern const long __NR_kevent;
|
hidden extern const long __NR_kevent;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
|
.text.syscall
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
/ Linux Signal Trampoline (HOLY CODE)
|
/ Linux Signal Trampoline (HOLY CODE)
|
||||||
|
|
|
@ -365,6 +365,7 @@ scall io_uring_enter 0xffffffffffff01aa globl
|
||||||
scall io_uring_register 0xffffffffffff01ab globl
|
scall io_uring_register 0xffffffffffff01ab globl
|
||||||
#────────────────────────RHEL CLOUD────────────────────────── # ←┬─ red hat terminates community release of enterprise linux circa 2020
|
#────────────────────────RHEL CLOUD────────────────────────── # ←┬─ red hat terminates community release of enterprise linux circa 2020
|
||||||
scall pledge 0x006cffffffffffff globl # └─ online linux services ban the president of united states of america
|
scall pledge 0x006cffffffffffff globl # └─ online linux services ban the president of united states of america
|
||||||
|
scall msyscall 0x0025ffffffffffff globl
|
||||||
|
|
||||||
# The Fifth Bell System Interface, Community Edition
|
# The Fifth Bell System Interface, Community Edition
|
||||||
# » besiyata dishmaya
|
# » besiyata dishmaya
|
||||||
|
|
|
@ -102,6 +102,8 @@ __systemfive:
|
||||||
.quad 0
|
.quad 0
|
||||||
.endobj __systemfive,globl,hidden
|
.endobj __systemfive,globl,hidden
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
|
.text.syscall
|
||||||
.Lanchorpoint:
|
.Lanchorpoint:
|
||||||
systemfive.linux:
|
systemfive.linux:
|
||||||
movswl %ax,%eax # gnu/systemd ordinal is first word
|
movswl %ax,%eax # gnu/systemd ordinal is first word
|
||||||
|
@ -256,11 +258,9 @@ systemfive.init.magnums:
|
||||||
pop %rbx
|
pop %rbx
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
#ifndef TINY
|
#ifndef TINY
|
||||||
systemfive.init.stack:
|
systemfive.init.stack: # determinism ftw!
|
||||||
testb IsWindows() # already did this
|
testb IsWindows() # already did this
|
||||||
jnz systemfive.init.done
|
jnz systemfive.init.done
|
||||||
testb IsOpenbsd() # todo fix openbsd
|
|
||||||
jnz systemfive.init.done
|
|
||||||
push %rdi
|
push %rdi
|
||||||
push %rsi
|
push %rsi
|
||||||
mov __NR_mmap,%eax
|
mov __NR_mmap,%eax
|
||||||
|
@ -269,13 +269,20 @@ systemfive.init.stack:
|
||||||
mov $PROT_READ|PROT_WRITE,%edx
|
mov $PROT_READ|PROT_WRITE,%edx
|
||||||
mov $MAP_PRIVATE|MAP_FIXED,%r10d
|
mov $MAP_PRIVATE|MAP_FIXED,%r10d
|
||||||
or MAP_ANONYMOUS,%r10d
|
or MAP_ANONYMOUS,%r10d
|
||||||
or MAP_GROWSDOWN,%r10d
|
or $-1,%r8d
|
||||||
or $-1,%r8
|
|
||||||
xor %r9d,%r9d
|
xor %r9d,%r9d
|
||||||
push %r9 # openbsd:pad
|
push %r9 # openbsd:pad
|
||||||
/ clc
|
push %r9 # openbsd:align
|
||||||
|
testb IsOpenbsd()
|
||||||
|
jz 0f
|
||||||
|
syscall # openbsd:dubstack
|
||||||
|
jc 1f
|
||||||
|
mov __NR_mmap,%eax
|
||||||
|
0: or MAP_GROWSDOWN,%r10d # openbsd:mapstack
|
||||||
|
clc
|
||||||
syscall
|
syscall
|
||||||
pop %r9
|
pop %r9
|
||||||
|
pop %r9
|
||||||
jnc 2f
|
jnc 2f
|
||||||
1: mov %eax,%edi
|
1: mov %eax,%edi
|
||||||
mov __NR_exit_group,%eax
|
mov __NR_exit_group,%eax
|
||||||
|
@ -295,12 +302,26 @@ systemfive.init.stack:
|
||||||
pop %rdi
|
pop %rdi
|
||||||
leave
|
leave
|
||||||
pop %rcx
|
pop %rcx
|
||||||
lea STACKSIZE(%rax),%rsp
|
lea STACKSIZE-16(%rax),%rsp # openbsd:stackbound
|
||||||
push %rcx
|
push %rcx
|
||||||
xor %ebp,%ebp
|
xor %ebp,%ebp
|
||||||
push %rbp
|
push %rbp
|
||||||
mov %rsp,%rbp
|
mov %rsp,%rbp
|
||||||
/ 𝑠𝑙𝑖𝑑𝑒
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
|
systemfive.init.syscall:
|
||||||
|
mov __NR_msyscall,%eax # syscall origin protect
|
||||||
|
test %eax,%eax # openbsd is pretty cool
|
||||||
|
js systemfive.init.done
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
.weak __text_syscall_addr
|
||||||
|
.weak __text_syscall_size
|
||||||
|
mov $__text_syscall_addr,%edi
|
||||||
|
mov $__text_syscall_size,%esi
|
||||||
|
syscall
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
/ 𝑠𝑙𝑖𝑑𝑒
|
||||||
#endif /* TINY */
|
#endif /* TINY */
|
||||||
systemfive.init.done:
|
systemfive.init.done:
|
||||||
nop
|
nop
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/rand/rand.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/tpenc.h"
|
#include "libc/str/tpenc.h"
|
||||||
|
@ -45,7 +46,7 @@ TEST(tpenc, testBeyondTheStandard) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Tpenc(int x) {
|
uint64_t Tpenc(int x) {
|
||||||
return (v = tpenc(VEIL("r", x)));
|
return (v = EXPROPRIATE(tpenc(VEIL("r", x))));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCH(tpenc, bench) {
|
BENCH(tpenc, bench) {
|
||||||
|
|
2
third_party/chibicc/tokenize.c
vendored
2
third_party/chibicc/tokenize.c
vendored
|
@ -275,7 +275,7 @@ static Token *read_string_literal(char *start, char *quote) {
|
||||||
// is called a "surrogate pair".
|
// is called a "surrogate pair".
|
||||||
static Token *read_utf16_string_literal(char *start, char *quote) {
|
static Token *read_utf16_string_literal(char *start, char *quote) {
|
||||||
char *end = string_literal_end(quote + 1);
|
char *end = string_literal_end(quote + 1);
|
||||||
uint16_t *buf = calloc(2, end - start - 1);
|
uint16_t *buf = calloc(2, end - start);
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (char *p = quote + 1; p < end;) {
|
for (char *p = quote + 1; p < end;) {
|
||||||
if (*p == '\\') {
|
if (*p == '\\') {
|
||||||
|
|
7
third_party/third_party.mk
vendored
7
third_party/third_party.mk
vendored
|
@ -1,15 +1,10 @@
|
||||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||||
|
|
||||||
# TODO(jart): make chibicc compiled chibicc work with asan runtime
|
|
||||||
ifneq ($(MODE),dbg)
|
|
||||||
THIRD_PARTY_CHIBICC_XXX = o/$(MODE)/third_party/chibicc
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/third_party
|
.PHONY: o/$(MODE)/third_party
|
||||||
o/$(MODE)/third_party: \
|
o/$(MODE)/third_party: \
|
||||||
o/$(MODE)/third_party/blas \
|
o/$(MODE)/third_party/blas \
|
||||||
$(THIRD_PARTY_CHIBICC_XXX) \
|
o/$(MODE)/third_party/chibicc \
|
||||||
o/$(MODE)/third_party/compiler_rt \
|
o/$(MODE)/third_party/compiler_rt \
|
||||||
o/$(MODE)/third_party/dlmalloc \
|
o/$(MODE)/third_party/dlmalloc \
|
||||||
o/$(MODE)/third_party/gdtoa \
|
o/$(MODE)/third_party/gdtoa \
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/ioctl.h"
|
#include "libc/calls/ioctl.h"
|
||||||
|
#include "libc/calls/struct/dirent.h"
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
#include "libc/calls/struct/sigaction-linux.internal.h"
|
#include "libc/calls/struct/sigaction-linux.internal.h"
|
||||||
|
@ -770,6 +771,30 @@ static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int OpGetdents(struct Machine *m, int dirfd, int64_t addr,
|
||||||
|
uint32_t size) {
|
||||||
|
int rc;
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
if (size < sizeof(struct dirent)) return einval();
|
||||||
|
if (0 <= dirfd && dirfd < m->fds.i) {
|
||||||
|
if ((dir = fdopendir(m->fds.p[dirfd].fd))) {
|
||||||
|
rc = 0;
|
||||||
|
while (rc + sizeof(struct dirent) <= size) {
|
||||||
|
if (!(ent = readdir(dir))) break;
|
||||||
|
VirtualRecvWrite(m, addr + rc, ent, ent->d_reclen);
|
||||||
|
rc += ent->d_reclen;
|
||||||
|
}
|
||||||
|
free(dir);
|
||||||
|
} else {
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rc = ebadf();
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
|
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
|
||||||
int64_t offset) {
|
int64_t offset) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
@ -1395,6 +1420,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
||||||
SYSCALL(0x09E, OpArchPrctl(m, di, si));
|
SYSCALL(0x09E, OpArchPrctl(m, di, si));
|
||||||
SYSCALL(0x0BA, OpGetTid(m));
|
SYSCALL(0x0BA, OpGetTid(m));
|
||||||
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
|
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
|
||||||
|
SYSCALL(0x0D9, OpGetdents(m, di, si, dx));
|
||||||
SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0));
|
SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0));
|
||||||
SYSCALL(0x0E4, OpClockGettime(m, di, si));
|
SYSCALL(0x0E4, OpClockGettime(m, di, si));
|
||||||
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
|
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
|
||||||
|
|
|
@ -176,6 +176,7 @@
|
||||||
"interruptfn"
|
"interruptfn"
|
||||||
"nocallback"
|
"nocallback"
|
||||||
"textstartup"
|
"textstartup"
|
||||||
|
"textsyscall"
|
||||||
"warnifused"
|
"warnifused"
|
||||||
"attributeallocsize"
|
"attributeallocsize"
|
||||||
"attributeallocalign"
|
"attributeallocalign"
|
||||||
|
|
|
@ -441,7 +441,7 @@
|
||||||
(cond ((not (eq 0 (logand 8 arg)))
|
(cond ((not (eq 0 (logand 8 arg)))
|
||||||
(cosmo--assembly (setq arg (logand (lognot 8)))
|
(cosmo--assembly (setq arg (logand (lognot 8)))
|
||||||
"SILENT=0 OVERRIDE_COPTS='-fverbose-asm -fsanitize=address'"))
|
"SILENT=0 OVERRIDE_COPTS='-fverbose-asm -fsanitize=address'"))
|
||||||
(t (cosmo--assembly arg "SILENT=0 OVERRIDE_COPTS='-fverbose-asm -fsanitize=address' CPPFLAGS='-DSTACK_FRAME_UNLIMITED'"))))
|
(t (cosmo--assembly arg "SILENT=0 OVERRIDE_COPTS='' CPPFLAGS='-DSTACK_FRAME_UNLIMITED'"))))
|
||||||
|
|
||||||
(defun cosmo-assembly-native (arg)
|
(defun cosmo-assembly-native (arg)
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue