Make numerous improvements

- Python static hello world now 1.8mb
- Python static fully loaded now 10mb
- Python HTTPS client now uses MbedTLS
- Python REPL now completes import stmts
- Increase stack size for Python for now
- Begin synthesizing posixpath and ntpath
- Restore Python \N{UNICODE NAME} support
- Restore Python NFKD symbol normalization
- Add optimized code path for Intel SHA-NI
- Get more Python unit tests passing faster
- Get Python help() pagination working on NT
- Python hashlib now supports MbedTLS PBKDF2
- Make memcpy/memmove/memcmp/bcmp/etc. faster
- Add Mersenne Twister and Vigna to LIBC_RAND
- Provide privileged __printf() for error code
- Fix zipos opendir() so that it reports ENOTDIR
- Add basic chmod() implementation for Windows NT
- Add Cosmo's best functions to Python cosmo module
- Pin function trace indent depth to that of caller
- Show memory diagram on invalid access in MODE=dbg
- Differentiate stack overflow on crash in MODE=dbg
- Add stb_truetype and tools for analyzing font files
- Upgrade to UNICODE 13 and reduce its binary footprint
- COMPILE.COM now logs resource usage of build commands
- Start implementing basic poll() support on bare metal
- Set getauxval(AT_EXECFN) to GetModuleFileName() on NT
- Add descriptions to strerror() in non-TINY build modes
- Add COUNTBRANCH() macro to help with micro-optimizations
- Make error / backtrace / asan / memory code more unbreakable
- Add fast perfect C implementation of μ-Law and a-Law audio codecs
- Make strtol() functions consistent with other libc implementations
- Improve Linenoise implementation (see also github.com/jart/bestline)
- COMPILE.COM now suppresses stdout/stderr of successful build commands
This commit is contained in:
Justine Tunney 2021-09-27 22:58:51 -07:00
parent fa7b4f5bd1
commit 39bf41f4eb
806 changed files with 77494 additions and 63859 deletions

View file

@ -16,85 +16,69 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/nexgen32e/x86feature.h"
/**
* Sets memory.
* Returns population count of array.
*
* @param p is memory address
* @param c is masked with 255 and used as repeated byte
* @param n is byte length
* @return p
* @asyncsignalsafe
* @param a is byte sequence
* @return number of bits set to one
* @note 30gbps on Nehalem (Intel 2008+) otherwise 3gbps
*/
void *memset_pure(void *p, int c, size_t n) {
char *b;
size_t _countbits(const void *a, size_t n) {
int i;
size_t t;
unsigned b;
uint64_t x;
b = p;
x = 0x0101010101010101ul * (c & 0xff);
switch (n) {
case 0:
return p;
case 1:
__builtin_memcpy(b, &x, 1);
return p;
case 2:
__builtin_memcpy(b, &x, 2);
return p;
case 3:
__builtin_memcpy(b, &x, 2);
__builtin_memcpy(b + 1, &x, 2);
return p;
case 4:
__builtin_memcpy(b, &x, 4);
return p;
case 5 ... 7:
__builtin_memcpy(b, &x, 4);
__builtin_memcpy(b + n - 4, &x, 4);
return p;
case 8:
__builtin_memcpy(b, &x, 8);
return p;
case 9 ... 16:
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
return p;
default:
do {
n -= 16;
__builtin_memcpy(b + n, &x, 8);
asm volatile("" ::: "memory");
__builtin_memcpy(b + n + 8, &x, 8);
} while (n >= 16);
switch (n) {
case 0:
return p;
case 1:
__builtin_memcpy(b, &x, 1);
return p;
case 2:
__builtin_memcpy(b, &x, 2);
return p;
case 3:
__builtin_memcpy(b, &x, 2);
__builtin_memcpy(b + 1, &x, 2);
return p;
case 4:
__builtin_memcpy(b, &x, 4);
return p;
case 5 ... 7:
__builtin_memcpy(b, &x, 4);
__builtin_memcpy(b + n - 4, &x, 4);
return p;
case 8:
__builtin_memcpy(b, &x, 8);
return p;
case 9 ... 15:
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
return p;
default:
unreachable;
long Ai, Bi, Ci, Di;
long Ao, Bo, Co, Do;
const char *p, *e;
t = 0;
p = a;
e = p + n;
if (!IsTiny()) {
if (X86_HAVE(POPCNT)) {
while (p + sizeof(long) * 4 <= e) {
__builtin_memcpy(&Ai, p + 000, sizeof(long));
__builtin_memcpy(&Bi, p + 010, sizeof(long));
__builtin_memcpy(&Ci, p + 020, sizeof(long));
__builtin_memcpy(&Di, p + 030, sizeof(long));
asm("popcnt\t%1,%0" : "=r"(Ao) : "r"(Ai) : "cc");
asm("popcnt\t%1,%0" : "=r"(Bo) : "r"(Bi) : "cc");
asm("popcnt\t%1,%0" : "=r"(Co) : "r"(Ci) : "cc");
asm("popcnt\t%1,%0" : "=r"(Do) : "r"(Di) : "cc");
t += Ao + Bo + Co + Do;
p += sizeof(long) * 4;
}
while (p + sizeof(long) <= e) {
__builtin_memcpy(&Ai, p, 8);
asm("popcnt\t%1,%0" : "=r"(Ao) : "rm"(Ai) : "cc");
p += sizeof(long);
t += Ao;
}
} else {
while (p + 8 <= e) {
__builtin_memcpy(&x, p, 8);
x = x - ((x >> 1) & 0x5555555555555555);
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
x = (x + (x >> 32)) & 0xffffffff;
x = x + (x >> 16);
x = (x + (x >> 8)) & 0x7f;
t += x;
p += 8;
}
}
}
while (p < e) {
b = *p++ & 255;
b = b - ((b >> 1) & 0x55);
b = ((b >> 2) & 0x33) + (b & 0x33);
b = (b + (b >> 4)) & 15;
t += b;
}
return t;
}

View file

@ -4,6 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
size_t _countbits(const void *, size_t);
unsigned long popcnt(unsigned long) pureconst;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)

16
libc/bits/xadd.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_BITS_XADD_H_
#define COSMOPOLITAN_LIBC_BITS_XADD_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _xadd(p, v) \
({ \
typeof(*(p)) Res; \
autotype(Res) Val = (v); \
asm volatile("xadd\t%0,%1" : "=r"(Res), "+m"(*(p)) : "0"(Val)); \
Res + Val; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_XADD_H_ */

View file

@ -17,18 +17,21 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_chdir_nt(const char *path) {
uint32_t n;
int e, ms, len;
char16_t path16[PATH_MAX];
char16_t path16[PATH_MAX], var[4];
if ((len = __mkntpath(path, path16)) == -1) return -1;
if (path16[len - 1] != u'\\') {
if (len + 1 + 1 > PATH_MAX) return enametoolong();
if (len && path16[len - 1] != u'\\') {
if (len + 2 > PATH_MAX) return enametoolong();
path16[len + 0] = u'\\';
path16[len + 1] = u'\0';
}
@ -38,7 +41,28 @@ textwindows int sys_chdir_nt(const char *path) {
*/
for (ms = 1;; ms *= 2) {
if (SetCurrentDirectory(path16)) {
return 0;
/*
* Now we need to set a magic environment variable.
*/
if ((n = GetCurrentDirectory(ARRAYLEN(path16), path16))) {
if (n < ARRAYLEN(path16)) {
if (!((path16[0] == '/' && path16[1] == '/') ||
(path16[0] == '\\' && path16[1] == '\\'))) {
var[0] = '=';
var[1] = path16[0];
var[2] = ':';
var[3] = 0;
if (!SetEnvironmentVariable(var, path16)) {
return __winerr();
}
}
return 0;
} else {
return enametoolong();
}
} else {
return __winerr();
}
} else {
e = GetLastError();
if (ms <= 512 &&

View file

@ -32,8 +32,6 @@
* CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit
* CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit
*
* This works on Windows NT if you ignore the error ;-)
*
* @param pathname must exist
* @param mode contains octal flags (base 8)
* @errors ENOENT, ENOTDIR, ENOSYS

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/macros.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
@ -36,6 +37,7 @@
*/
int close(int fd) {
int rc;
if (fd == -1) return 0;
if (fd < 0) return einval();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_close)(fd);
@ -59,5 +61,6 @@ int close(int fd) {
}
}
__releasefd(fd);
SYSDEBUG("close(%d) -> %d", fd, rc);
return rc;
}

View file

@ -22,8 +22,9 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name,
size_t namelen, size_t pathlen) {
static noasan bool AccessCommand(char path[hasatleast PATH_MAX],
const char *name, size_t namelen,
size_t pathlen) {
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/'
@ -40,8 +41,8 @@ static bool AccessCommand(char path[hasatleast PATH_MAX], const char *name,
return false;
}
static bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
size_t namelen) {
static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
size_t namelen) {
size_t i;
const char *p;
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
@ -70,7 +71,7 @@ static bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
* @asyncsignalsafe
* @vforksafe
*/
char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
char *p;
size_t namelen;
int rc, olderr;

View file

@ -33,7 +33,7 @@
#include "libc/time/time.h"
static textwindows int sys_copyfile_nt(const char *src, const char *dst,
int flags) {
int flags) {
int64_t fhsrc, fhdst;
struct NtFileTime accessed, modified;
char16_t src16[PATH_MAX], dst16[PATH_MAX];
@ -99,6 +99,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
/**
* Copies file.
*
* This implementation goes 2x faster than the `cp` command that comes
* included with most systems since we use the newer copy_file_range()
* system call rather than sendfile().
*
* @param flags may have COPYFILE_PRESERVE_TIMESTAMPS, COPYFILE_NOCLOBBER
* @return 0 on success, or -1 w/ errno
*/
int copyfile(const char *src, const char *dst, int flags) {
if (!IsWindows()) {

View file

@ -47,6 +47,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags) {
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
0, true, kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
g_fds.p[newfd].flags = flags;
return newfd;
} else {

View file

@ -35,7 +35,7 @@ int __ensurefds(int fd) {
n2 = MAX(fd + 1, n1 + (n1 << 1));
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
memcpy(p2, p1, n1 * sizeof(*p1));
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
if (cmpxchg(&g_fds.p, p1, p2)) {
g_fds.n = n2;

View file

@ -37,7 +37,7 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
uint32_t dwExitCode;
struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo;
memset(&startinfo, 0, sizeof(startinfo));
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = g_fds.p[0].handle;

View file

@ -18,8 +18,10 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -44,6 +46,19 @@ int execve(const char *program, char *const argv[], char *const envp[]) {
!__asan_is_valid_strlist(envp))) {
return efault();
}
if (DEBUGSYS) {
__printf("SYS: execve(%s, {", program);
for (i = 0; argv[i]; ++i) {
if (i) __printf(", ");
__printf("%s", argv[i]);
}
__printf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) __printf(", ");
__printf("%s", envp[i]);
}
__printf("})\n");
}
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
close(i);

39
libc/calls/fchmodat-nt.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/files.h"
textwindows int sys_fchmodat_nt(int dirfd, const char *path, uint32_t mode,
int flags) {
uint32_t attr;
uint16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
if ((attr = GetFileAttributes(path16)) != -1) {
if (mode & 0200) {
attr &= ~kNtFileAttributeReadonly;
} else {
attr |= kNtFileAttributeReadonly;
}
if (SetFileAttributes(path16, attr)) {
return 0;
}
}
return __winerr();
}

View file

@ -31,8 +31,6 @@
* CHECK_NE(-1, fchmodat(AT_FDCWD, "o/default/program.com", 0755));
* CHECK_NE(-1, fchmodat(AT_FDCWD, "privatefolder/", 0700));
*
* This works on Windows NT if you ignore the error ;-)
*
* @param path must exist
* @param mode contains octal flags (base 8)
* @param flags can have `AT_SYMLINK_NOFOLLOW`

View file

@ -29,7 +29,7 @@ textwindows int sys_flock_nt(int fd, int op) {
struct NtOverlapped ov;
struct NtByHandleFileInformation info;
if (!__isfdkind(fd, kFdFile)) return ebadf();
memset(&ov, 0, sizeof(ov));
bzero(&ov, sizeof(ov));
if (GetFileInformationByHandle(g_fds.p[fd].handle, &info) &&
((!(op & LOCK_UN) &&
LockFileEx(g_fds.p[fd].handle, op, 0, info.nFileSizeLow,

View file

@ -25,7 +25,7 @@
int sys_fstat_metal(int fd, struct stat *st) {
if (fd < 0) return einval();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) {
memset(st, 0, sizeof(*st));
bzero(st, sizeof(*st));
st->st_dev = g_fds.p[fd].handle;
st->st_rdev = g_fds.p[fd].handle;
st->st_nlink = 1;

View file

@ -76,7 +76,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
struct NtByHandleFileInformation wst;
if (!st) return efault();
if ((filetype = GetFileType(handle))) {
memset(st, 0, sizeof(*st));
bzero(st, sizeof(*st));
switch (filetype) {
case kNtFileTypeChar:
st->st_mode = S_IFCHR | 0644;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
@ -41,6 +42,7 @@ int32_t sys_fstat(int32_t fd, struct stat *st) {
__stat2cosmo(st, &ms);
return 0;
} else {
SYSDEBUG("sys_fstat(%d) failed w/ %m", fd);
return -1;
}
}

View file

@ -32,9 +32,7 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
uint16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
if ((fh = CreateFile(
path16, kNtFileReadAttributes,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
kNtOpenExisting,
path16, kNtFileReadAttributes, 0, 0, kNtOpenExisting,
kNtFileAttributeNormal | kNtFileFlagBackupSemantics |
((flags & AT_SYMLINK_NOFOLLOW) ? kNtFileFlagOpenReparsePoint
: 0),

View file

@ -34,7 +34,7 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
struct NtFileTime UserFileTime;
if (!usage) return efault();
if (who == 99) return enosys(); /* @see libc/sysv/consts.sh */
memset(usage, 0, sizeof(*usage));
bzero(usage, sizeof(*usage));
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {

View file

@ -29,6 +29,6 @@ int sys_gettimeofday_nt(struct timeval *tv, struct timezone *tz) {
struct NtFileTime ft;
GetSystemTimeAsFileTime(&ft);
if (tv) *tv = FileTimeToTimeVal(ft);
if (tz) memset(tz, 0, sizeof(*tz));
if (tz) bzero(tz, sizeof(*tz));
return 0;
}

View file

@ -261,6 +261,7 @@ int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;
int sys_fadvise_nt(int, u64, u64, int) hidden;
int sys_fchdir_nt(int) hidden;
int sys_fchmodat_nt(int, const char *, uint32_t, int) hidden;
int sys_fcntl_nt(int, int, uintptr_t) hidden;
int sys_fdatasync_nt(int) hidden;
int sys_flock_nt(int, int) hidden;

View file

@ -76,7 +76,7 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
fam = p[IsBsd() ? 17 : 16] & 255;
if (fam != AF_INET) continue;
ip = READ32BE(p + 20);
memset(req, 0, sizeof(*req));
bzero(req, sizeof(*req));
memcpy(req->ifr_name, p, 16);
memcpy(&req->ifr_addr, p + 16, 16);
req->ifr_addr.sa_family = fam;

View file

@ -34,7 +34,7 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) {
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
if (inok | outok) {
memset(tio, 0, sizeof(*tio));
bzero(tio, sizeof(*tio));
if (inok) {
if (inmode & kNtEnableLineInput) tio->c_lflag |= ICANON;
if (inmode & kNtEnableEchoInput) tio->c_lflag |= ECHO;

View file

@ -29,7 +29,7 @@
int ioctl_tcgets_nt(int, struct termios *) hidden;
static int ioctl_tcgets_metal(int fd, struct termios *tio) {
memset(tio, 0, sizeof(*tio));
bzero(tio, sizeof(*tio));
tio->c_iflag = TTYDEF_IFLAG;
tio->c_oflag = TTYDEF_OFLAG;
tio->c_lflag = TTYDEF_LFLAG;

View file

@ -38,7 +38,7 @@ textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
for (i = 0; i < ARRAYLEN(fds); ++i) {
if (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) {
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) {
memset(&sbinfo, 0, sizeof(sbinfo));
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(g_fds.p[fds[i]].handle, &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;

View file

@ -31,7 +31,9 @@ bool32 isatty(int fd) {
bool32 res;
struct winsize ws;
if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
if (__isfdkind(fd, kFdZip)) {
return false;
} else if (IsMetal()) {
return false;
} else if (!IsWindows()) {
err = errno;

View file

@ -19,9 +19,19 @@
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
bool g_isrunningundermake;
/**
* Returns true if current process was spawned by GNU Make.
*/
bool IsRunningUnderMake(void) {
return !!getenv("MAKEFLAGS");
return g_isrunningundermake;
}
textstartup void g_isrunningundermake_init(void) {
g_isrunningundermake = !!getenv("MAKEFLAGS");
}
const void *const g_isrunningundermake_ctor[] initarray = {
g_isrunningundermake_init,
};

View file

@ -23,6 +23,22 @@
#include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h"
#define APPEND(c) \
do { \
cmdline[k++] = c; \
if (k == ARG_MAX) return e2big(); \
} while (0)
static noasan bool NeedsQuotes(const char *s) {
if (!*s) return true;
do {
if (*s == ' ' || *s == '\t') {
return true;
}
} while (*s++);
return false;
}
/**
* Converts System V argv to Windows-style command line.
*
@ -34,7 +50,6 @@
* @param prog is used as argv[0]
* @param argv is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpCommandLine or NULL w/ errno
* @kudos Daniel Colascione for teaching how to quote
* @see libc/runtime/dosargv.c
*/
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
@ -43,36 +58,19 @@ textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
uint64_t w;
wint_t x, y;
int slashes, n;
size_t i, j, k;
bool needsquote;
char16_t cbuf[2];
size_t i, j, k, s;
for (arg = prog, k = i = 0; arg; arg = argv[++i]) {
if (i) {
cmdline[k++] = u' ';
if (k == ARG_MAX) return e2big();
}
needsquote = !arg[0] || arg[strcspn(arg, " \t\n\v\"")];
if (needsquote) {
cmdline[k++] = u'"';
if (k == ARG_MAX) return e2big();
}
for (j = 0;;) {
if (needsquote) {
slashes = 0;
while (arg[j] && arg[j] == '\\') slashes++, j++;
slashes <<= 1;
if (arg[j] == '"') slashes++;
while (slashes--) {
cmdline[k++] = u'\\';
if (k == ARG_MAX) return e2big();
}
}
x = arg[j++] & 0xff;
if (i) APPEND(u' ');
if ((needsquote = NeedsQuotes(arg))) APPEND(u'"');
for (slashes = j = 0;;) {
x = arg[j++] & 255;
if (x >= 0300) {
n = ThomPikeLen(x);
x = ThomPikeByte(x);
while (--n) {
if ((y = arg[j++] & 0xff)) {
if ((y = arg[j++] & 255)) {
x = ThomPikeMerge(x, y);
} else {
x = 0;
@ -81,16 +79,34 @@ textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
}
}
if (!x) break;
if (!i && x == '/') x = '\\';
w = EncodeUtf16(x);
do {
cmdline[k++] = w;
if (k == ARG_MAX) return e2big();
} while ((w >>= 16));
if (!i && x == '/') {
x = '\\';
}
if (x == '\\') {
++slashes;
} else if (x == '"') {
for (s = 0; s < slashes * 2; ++s) {
APPEND(u'\\');
}
slashes = 0;
APPEND(u'\\');
APPEND(u'"');
} else {
for (s = 0; s < slashes; ++s) {
APPEND(u'\\');
}
slashes = 0;
w = EncodeUtf16(x);
do {
APPEND(w);
} while ((w >>= 16));
}
}
for (s = 0; s < (slashes << needsquote); ++s) {
APPEND(u'\\');
}
if (needsquote) {
cmdline[k++] = u'"';
if (k == ARG_MAX) return e2big();
APPEND(u'"');
}
}
cmdline[k] = u'\0';

View file

@ -25,7 +25,8 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_nanosleep_nt(const struct timespec *req, struct timespec *rem) {
textwindows int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
int64_t millis, hectonanos, relasleep;
if (rem) memcpy(rem, req, sizeof(*rem));
hectonanos = req->tv_sec * 10000000ull + div100int64(req->tv_nsec);
@ -38,6 +39,6 @@ textwindows int sys_nanosleep_nt(const struct timespec *req, struct timespec *re
return eintr();
}
}
if (rem) memset(rem, 0, sizeof(*rem));
if (rem) bzero(rem, sizeof(*rem));
return 0;
}

View file

@ -63,7 +63,7 @@ textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
s = (void *)buffer;
secsize = sizeof(buffer);
privsize = sizeof(privileges);
memset(&privileges, 0, sizeof(privileges));
bzero(&privileges, sizeof(privileges));
mapping.GenericRead = kNtFileGenericRead;
mapping.GenericWrite = kNtFileGenericWrite;
mapping.GenericExecute = kNtFileGenericExecute;

View file

@ -33,6 +33,14 @@ textwindows void ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
ctx->uc_mcontext.rbp = cr->Rbp;
ctx->uc_mcontext.rsp = cr->Rsp;
ctx->uc_mcontext.rip = cr->Rip;
ctx->uc_mcontext.r8 = cr->R8;
ctx->uc_mcontext.r9 = cr->R9;
ctx->uc_mcontext.r10 = cr->R10;
ctx->uc_mcontext.r11 = cr->R11;
ctx->uc_mcontext.r12 = cr->R12;
ctx->uc_mcontext.r13 = cr->R13;
ctx->uc_mcontext.r14 = cr->R14;
ctx->uc_mcontext.r15 = cr->R15;
ctx->uc_mcontext.cs = cr->SegCs;
ctx->uc_mcontext.gs = cr->SegGs;
ctx->uc_mcontext.fs = cr->SegFs;

View file

@ -19,6 +19,7 @@
#include "libc/bits/pushpop.h"
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
@ -69,8 +70,10 @@ textwindows int ntspawn(
int64_t handle;
size_t blocksize;
struct SpawnBlock *block;
char16_t prog16[PATH_MAX];
rc = -1;
block = NULL;
if (__mkntpath(prog, prog16) == -1) return -1;
blocksize = ROUNDUP(sizeof(*block), FRAMESIZE);
if ((handle = CreateFileMappingNuma(
-1,
@ -83,7 +86,7 @@ textwindows int ntspawn(
blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment,
block->envvars, opt_lpCurrentDirectory, lpStartupInfo,
@ -92,6 +95,7 @@ textwindows int ntspawn(
} else {
__winerr();
}
SYSDEBUG("CreateProcess(`%S`, `%S`) -> %d", prog16, block->cmdline, rc);
}
} else {
__winerr();

View file

@ -23,7 +23,7 @@
textwindows struct NtOverlapped *offset2overlap(int64_t opt_offset,
struct NtOverlapped *mem) {
if (opt_offset == -1) return NULL;
memset(mem, 0, sizeof(struct NtOverlapped));
bzero(mem, sizeof(struct NtOverlapped));
mem->Pointer = (void *)(uintptr_t)opt_offset;
return mem;
}

View file

@ -52,7 +52,7 @@ textwindows bool32 __onntconsoleevent(uint32_t CtrlType) {
case (uintptr_t)SIG_IGN:
return true;
default:
memset(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = sig;
((sigaction_f)(_base + rva))(sig, &info, NULL);
__interrupted = true;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/f.h"
@ -32,7 +33,7 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
* flag. Other times, it return -530 which makes no sense.
*/
if (!IsLinux() || !(flags & O_CLOEXEC) || modernize) {
return __sys_openat(dirfd, file, flags, mode);
d = __sys_openat(dirfd, file, flags, mode);
} else if (once) {
if ((d = __sys_openat(dirfd, file, flags & ~O_CLOEXEC, mode)) != -1) {
e = errno;
@ -54,8 +55,13 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
once = true;
} else if (errno > 255) {
once = true;
return sys_openat(dirfd, file, flags, mode);
d = sys_openat(dirfd, file, flags, mode);
}
}
if (d != -1) {
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %d", dirfd, file, flags, mode, d);
} else {
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %m", dirfd, file, flags, mode);
}
return d;
}

View file

@ -24,6 +24,7 @@
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"

View file

@ -205,7 +205,7 @@ ssize_t readansi(int fd, char *p, size_t n) {
case kCsi1:
if (0x20 <= c && c <= 0x2f) {
t = kCsi2;
} else if (c == '[' && i == 3) {
} else if (c == '[' && (i == 3 || (i == 4 && p[1] == '\e'))) {
/* linux function keys */
} else if (0x40 <= c && c <= 0x7e) {
t = kDone;

View file

@ -29,8 +29,8 @@
#include "libc/str/str.h"
static textwindows noinline int sys_sched_setaffinity_nt(int pid,
uint64_t bitsetsize,
const void *bitset) {
uint64_t bitsetsize,
const void *bitset) {
int rc;
uintptr_t mask;
int64_t handle;

View file

@ -49,12 +49,12 @@
autotype((S2).B) b = (typeof((S2).B))(S1).B; \
autotype((S2).C) c = (typeof((S2).C))(S1).C; \
typeof((S2).D) d; \
memset(&d, 0, sizeof(d)); \
bzero(&d, sizeof(d)); \
memcpy(&d, &((S1).D), MIN(sizeof(d), sizeof((S1).D))); \
(S2).A = a; \
(S2).B = b; \
(S2).C = c; \
memset(&((S2).D), 0, sizeof((S2).D)); \
bzero(&((S2).D), sizeof((S2).D)); \
memcpy(&((S2).D), &d, MIN(sizeof(d), sizeof((S2).D))); \
} while (0);
#endif
@ -217,7 +217,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
}
} else {
if (oldact) {
memset(oldact, 0, sizeof(*oldact));
bzero(oldact, sizeof(*oldact));
}
rc = 0;
}

View file

@ -26,6 +26,6 @@
* @asyncsignalsafe
*/
int sigemptyset(sigset_t *set) {
memset(set->__bits, 0, sizeof(set->__bits));
bzero(set->__bits, sizeof(set->__bits));
return 0;
}

View file

@ -124,7 +124,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
ucontext_t uc;
rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) {
memset(&uc, 0, sizeof(uc));
bzero(&uc, sizeof(uc));
if (ctx) {
uc.uc_mcontext.fpregs = &uc.__fpustate;
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
@ -155,6 +155,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
memcpy(&uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
}
((sigaction_f)(_base + rva))(sig, (void *)si, &uc);
if (ctx) {
@ -186,6 +187,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *si,
ctx->uc_mcontext.mc_err = uc.uc_mcontext.err;
ctx->uc_mcontext.mc_rip = uc.uc_mcontext.rip;
ctx->uc_mcontext.mc_rsp = uc.uc_mcontext.rsp;
memcpy(&ctx->uc_mcontext.mc_fpstate, &uc.__fpustate, 512);
}
}
/*

View file

@ -132,8 +132,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
struct siginfo si2;
rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) {
memset(&uc, 0, sizeof(uc));
memset(&si2, 0, sizeof(si2));
bzero(&uc, sizeof(uc));
bzero(&si2, sizeof(si2));
if (si) {
si2.si_signo = si->_signo;
si2.si_code = si->_code;

View file

@ -97,8 +97,8 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *si,
struct siginfo si2;
rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) {
memset(&uc, 0, sizeof(uc));
memset(&si2, 0, sizeof(si2));
bzero(&uc, sizeof(uc));
bzero(&si2, sizeof(si2));
if (si) {
si2.si_signo = si->si_signo;
si2.si_code = si->si_code;

View file

@ -25,7 +25,7 @@
*/
int sigignore(int sig) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
bzero(&sa, sizeof(sa));
sa.sa_handler = SIG_IGN;
return (sigaction)(sig, &sa, 0);
}

View file

@ -48,7 +48,7 @@ int sigqueue(int pid, int sig, const union sigval value) {
if (IsFreebsd()) {
return sys_sigqueue(pid, sig, value);
} else {
memset(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = sig;
info.si_code = SI_QUEUE;
info.si_pid = getpid();

View file

@ -1,9 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SYSDEBUG_INTERNAL_H_
#include "libc/calls/calls.h"
#include "libc/log/libfatal.internal.h"
#if 0
#define SYSDEBUG(FMT, ...) (dprintf)(2, FMT "\n", ##__VA_ARGS__)
#ifndef DEBUGSYS
#define DEBUGSYS 0
#endif
#if DEBUGSYS
#define SYSDEBUG(FMT, ...) __printf("SYS: " FMT "\n", ##__VA_ARGS__)
#else
#define SYSDEBUG(FMT, ...) (void)0
#endif

View file

@ -41,7 +41,7 @@ int sysinfo(struct sysinfo *info) {
return efault();
}
}
memset(info, 0, sizeof(*info));
bzero(info, sizeof(*info));
if (!IsWindows()) {
rc = sys_sysinfo(info);
} else {

View file

@ -29,7 +29,7 @@ int uname(struct utsname *lool) {
char *out;
size_t i, j, len;
char tmp[sizeof(struct utsname)];
memset(tmp, 0, sizeof(tmp));
bzero(tmp, sizeof(tmp));
if (sys_uname(tmp) != -1) {
out = (char *)lool;
i = 0;
@ -45,7 +45,7 @@ int uname(struct utsname *lool) {
}
return 0;
} else {
memset(lool, 0, sizeof(struct utsname));
bzero(lool, sizeof(struct utsname));
return -1;
}
}

View file

@ -20,12 +20,11 @@
#include "libc/sysv/consts/at.h"
/**
* Deletes file.
* Removes file.
*
* Please note the deletion process has different interesting properties
* on each platform. For example, on System V, if open descriptors exist
* then only the name of the file is removed and it's actually deleted
* later on when appropriate.
* This may be used to delete files but it can't be used to delete
* directories. The exception are symlinks, which this will delete
* however not the linked directory.
*
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe

View file

@ -18,17 +18,29 @@
*/
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/io.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/win32fileattributedata.h"
#include "libc/nt/struct/win32finddata.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/at.h"
static textwindows int sys_unlink_nt(const char16_t *path) {
if (DeleteFile(path)) {
return 0;
static textwindows bool IsDirectorySymlink(const char16_t *path) {
int64_t h;
struct NtWin32FindData data;
struct NtWin32FileAttributeData info;
if (GetFileAttributesEx(path, 0, &info) &&
((info.dwFileAttributes & kNtFileAttributeDirectory) &&
(info.dwFileAttributes & kNtFileAttributeReparsePoint)) &&
(h = FindFirstFile(path, &data)) != -1) {
FindClose(h);
return data.dwReserved0 == kNtIoReparseTagSymlink ||
data.dwReserved0 == kNtIoReparseTagMountPoint;
} else {
return __winerr();
return false;
}
}
@ -54,6 +66,11 @@ static textwindows int sys_rmdir_nt(const char16_t *path) {
return -1;
}
static textwindows int sys_unlink_nt(const char16_t *path) {
if (IsDirectorySymlink(path)) return sys_rmdir_nt(path);
return DeleteFile(path) ? 0 : __winerr();
}
textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) {
uint16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;

View file

@ -84,7 +84,7 @@ textwindows int sys_wait4_nt(int pid, int *opt_out_wstatus, int options,
*opt_out_wstatus = (dwExitCode & 0xff) << 8;
}
if (opt_out_rusage) {
memset(opt_out_rusage, 0, sizeof(*opt_out_rusage));
bzero(opt_out_rusage, sizeof(*opt_out_rusage));
if (GetProcessTimes(g_fds.p[pids[i]].handle, &createfiletime,
&exitfiletime, &kernelfiletime, &userfiletime)) {
opt_out_rusage->ru_utime =

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/calls/wait4.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
@ -37,6 +38,7 @@
*/
int wait4(int pid, int *opt_out_wstatus, int options,
struct rusage *opt_out_rusage) {
int rc, ws;
if (IsAsan() &&
((opt_out_wstatus &&
!__asan_is_valid(opt_out_wstatus, sizeof(*opt_out_wstatus))) ||
@ -44,9 +46,13 @@ int wait4(int pid, int *opt_out_wstatus, int options,
!__asan_is_valid(opt_out_rusage, sizeof(*opt_out_rusage))))) {
return efault();
}
ws = 0;
if (!IsWindows()) {
return sys_wait4(pid, opt_out_wstatus, options, opt_out_rusage);
rc = sys_wait4(pid, &ws, options, opt_out_rusage);
} else {
return sys_wait4_nt(pid, opt_out_wstatus, options, opt_out_rusage);
rc = sys_wait4_nt(pid, &ws, options, opt_out_rusage);
}
SYSDEBUG("waitpid(%d, [0x%x], %d) -> [%d]", pid, ws, options, rc);
if (opt_out_wstatus) *opt_out_wstatus = ws;
return rc;
}

View file

@ -25,7 +25,7 @@ void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue,
uint32_t dwTimerHighValue) {
int rva;
siginfo_t info;
memset(&info, 0, sizeof(info));
bzero(&info, sizeof(info));
info.si_signo = SIGALRM;
rva = __sighandrvas[SIGALRM];
if (rva >= kSigactionMinRva) {

View file

@ -70,7 +70,7 @@ textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
default:
return kNtExceptionContinueSearch;
}
memset(&g, 0, sizeof(g));
bzero(&g, sizeof(g));
rva = __sighandrvas[sig];
if (rva >= kSigactionMinRva) {
ntcontext2linux(&g.ctx, ep->ContextRecord);

View file

@ -61,7 +61,7 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
if (addrsize < kMinSockaddr4Size) return einval();
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!resolvconf->nameservers.i) return 0;
memset(&h, 0, sizeof(h));
bzero(&h, sizeof(h));
rc = ebadmsg();
h.id = rand64();
h.bf1 = 1; /* recursion desired */
@ -69,7 +69,7 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
q.qname = name;
q.qtype = DNS_TYPE_A;
q.qclass = DNS_CLASS_IN;
memset(msg, 0, sizeof(msg));
bzero(msg, sizeof(msg));
SerializeDnsHeader(msg, &h);
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;

View file

@ -63,7 +63,7 @@ int ResolveDnsReverse(const struct ResolvConf *resolvconf, int af,
uint16_t rtype, rclass, rdlength;
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
if (!resolvconf->nameservers.i) return 0;
memset(&h, 0, sizeof(h));
bzero(&h, sizeof(h));
rc = ebadmsg();
h.id = rand64();
h.bf1 = 1; /* recursion desired */
@ -71,7 +71,7 @@ int ResolveDnsReverse(const struct ResolvConf *resolvconf, int af,
q.qname = name;
q.qtype = DNS_TYPE_PTR;
q.qclass = DNS_CLASS_IN;
memset(msg, 0, sizeof(msg));
bzero(msg, sizeof(msg));
SerializeDnsHeader(msg, &h);
if ((n = SerializeDnsQuestion(msg + 12, 500, &q)) == -1) return -1;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1;

View file

@ -13,6 +13,7 @@ COSMOPOLITAN_C_START_
*/
char *GetElfStringTable(const Elf64_Ehdr *, size_t);
char *GetElfStrs(const Elf64_Ehdr *, size_t, size_t *);
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
bool IsElf64Binary(const Elf64_Ehdr *, size_t);
void CheckElfAddress(const Elf64_Ehdr *, size_t, intptr_t, size_t);

39
libc/elf/getelfstrs.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- 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/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/str/str.h"
char *GetElfStrs(const Elf64_Ehdr *elf, size_t mapsize, size_t *out_size) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
if (shdr->sh_type == SHT_STRTAB) {
name = GetElfSectionName(elf, mapsize,
GetElfSectionHeaderAddress(elf, mapsize, i));
if (name && !strcmp(name, ".strtab")) {
if (out_size) *out_size = shdr->sh_size;
return GetElfSectionAddress(elf, mapsize, shdr);
}
}
}
return 0;
}

View file

@ -24,6 +24,16 @@
/**
* Decodes decimal integer from ASCII string.
*
* atoi 10 22𝑐 7𝑛𝑠
* strtol 10 37𝑐 12𝑛𝑠
* strtoul 10 35𝑐 11𝑛𝑠
* wcstol 10 30𝑐 10𝑛𝑠
* wcstoul 10 30𝑐 10𝑛𝑠
* strtoimax 10 80𝑐 26𝑛𝑠
* strtoumax 10 78𝑐 25𝑛𝑠
* wcstoimax 10 77𝑐 25𝑛𝑠
* wcstoumax 10 76𝑐 25𝑛𝑠
*
* @param s is a non-null nul-terminated string
* @return the decoded signed saturated integer
*/

View file

@ -69,6 +69,7 @@ char *dirname(char *);
char *basename(const char *) nosideeffect;
char *basename_n(const char *, size_t) nosideeffect;
bool isabspath(const char *) paramsnonnull() nosideeffect;
char *stripext(char *);
char *stripexts(char *);
/*───────────────────────────────────────────────────────────────────────────│─╗

View file

@ -391,7 +391,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
s = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
if (decpt == 9999) {
Format9999:
p = q = memset(special, 0, sizeof(special));
bzero(special, sizeof(special));
p = q = special;
if (sgn) {
*q++ = '-';
} else if (flags & FLAGS_PLUS) {
@ -423,12 +424,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
if (flags & FLAGS_ZEROPAD) {
if (sign) PUT(sign);
sign = 0;
do
PUT('0');
do PUT('0');
while (--width > 0);
} else {
do
PUT(' ');
do PUT(' ');
while (--width > 0);
}
}
@ -530,12 +529,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
if (flags & FLAGS_ZEROPAD) {
if (sign) PUT(sign);
sign = 0;
do
PUT('0');
do PUT('0');
while (--width > 0);
} else {
do
PUT(' ');
do PUT(' ');
while (--width > 0);
}
}
@ -682,12 +679,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
PUT(sign);
sign = 0;
}
do
PUT('0');
do PUT('0');
while (--width > 0);
} else {
do
PUT(' ');
do PUT(' ');
while (--width > 0);
}
}

View file

@ -58,6 +58,8 @@ $(LIBC_FMT_A_OBJS): \
OVERRIDE_CFLAGS += \
-fno-jump-tables
o/$(MODE)/libc/fmt/formatint64.o \
o/$(MODE)/libc/fmt/formatint64thousands.o \
o/$(MODE)/libc/fmt/dosdatetimetounix.o \
o/$(MODE)/libc/fmt/itoa64radix10.greg.o: \
OVERRIDE_CFLAGS += \

55
libc/fmt/formatint64.c Normal file
View file

@ -0,0 +1,55 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
/**
* Converts unsigned 64-bit integer to string.
*
* @param p needs at least 21 bytes
* @return pointer to nul byte
*/
noinline char *FormatUint64(char p[static 21], uint64_t x) {
char t;
size_t i, a, b;
i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
/**
* Converts signed 64-bit integer to string.
*
* @param p needs at least 21 bytes
* @return pointer to nul byte
*/
char *FormatInt64(char p[static 21], int64_t x) {
if (x < 0) *p++ = '-', x = -(uint64_t)x;
return FormatUint64(p, x);
}

View file

@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
/**
* Converts unsigned 64-bit integer to string w/ commas.
*
* @param p needs at least 21 bytes
* @return pointer to nul byte
*/
noinline char *FormatUint64Thousands(char p[static 27], uint64_t x) {
size_t i;
char m[26];
i = 0;
do {
m[i++] = x % 10 + '0';
x = x / 10;
} while (x);
for (;;) {
*p++ = m[--i];
if (!i) break;
if (!(i % 3)) *p++ = ',';
}
*p = '\0';
return p;
}
/**
* Converts 64-bit integer to string w/ commas.
*
* @param p needs at least 21 bytes
* @return pointer to nul byte
*/
char *FormatInt64Thousands(char p[static 27], int64_t x) {
if (x < 0) *p++ = '-', x = -(uint64_t)x;
return FormatUint64Thousands(p, x);
}

View file

@ -16,6 +16,10 @@ COSMOPOLITAN_C_START_
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
char *FormatInt64(char[hasatleast 21], int64_t);
char *FormatUint64(char[hasatleast 21], uint64_t);
char *FormatInt64Thousands(char[hasatleast 27], int64_t);
char *FormatUint64Thousands(char[hasatleast 27], uint64_t);
size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);

View file

@ -20,7 +20,6 @@
#include "libc/fmt/itoa.h"
size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) {
int i;
char *p;
assert(k <= 64 && !(k & 3));
for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];

183
libc/fmt/kerrornameslong.S Normal file
View file

@ -0,0 +1,183 @@
/*-*- 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 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.macro .e e s
.long \e - kErrorNamesLong
.long 1f - kErrorNamesLong
.rodata.str1.1
1: .asciz "\s"
.previous
.endm
.section .rodata
.align 4
kErrorNamesLong:
.e EPIPE,"EPIPE[Broken pipe]"
.e ENODEV,"ENODEV[No such device]"
.e EINVAL,"EINVAL[Invalid argument]"
.e EINTR,"EINTR[Interrupted system call]"
.e ENOTBLK,"ENOTBLK[Block device required]"
.e ENOSYS,"ENOSYS[Function not implemented]"
.e EHOSTUNREACH,"EHOSTUNREACH[No route to host]"
.e ESRCH,"ESRCH[No such process]"
.e EUSERS,"EUSERS[Too many users]"
.e EXDEV,"EXDEV[Cross-device link]"
.e E2BIG,"E2BIG[Arg list too long]"
.e EREMOTE,"EREMOTE[Object is remote]"
.e ECHILD,"ECHILD[No child processes]"
.e EMSGSIZE,"EMSGSIZE[Message too long]"
.e ENOTEMPTY,"ENOTEMPTY[Directory not empty]"
.e ENOBUFS,"ENOBUFS[No buffer space available]"
.e ELOOP,"ELOOP[Too many symbolic links encountered]"
.e EAFNOSUPPORT,"EAFNOSUPPORT[Address family not supported by protocol]"
.e EHOSTDOWN,"EHOSTDOWN[Host is down]"
.e EPFNOSUPPORT,"EPFNOSUPPORT[Protocol family not supported]"
.e ENOPROTOOPT,"ENOPROTOOPT[Protocol not available]"
.e EBUSY,"EBUSY[Device or resource busy]"
.e EWOULDBLOCK,"EWOULDBLOCK[Operation would block]"
.e EBADFD,"EBADFD[File descriptor in bad state]"
.e EISCONN,"EISCONN[Transport endpoint is already connected]"
.e ESHUTDOWN,"ESHUTDOWN[Cannot send after transport endpoint shutdown]"
.e ENONET,"ENONET[Machine is not on the network]"
.e EBADE,"EBADE[Invalid exchange]"
.e EBADF,"EBADF[Bad file number]"
.e EMULTIHOP,"EMULTIHOP[Multihop attempted]"
.e EIO,"EIO[I/O error]"
.e EUNATCH,"EUNATCH[Protocol driver not attached]"
.e EPROTOTYPE,"EPROTOTYPE[Protocol wrong type for socket]"
.e ENOSPC,"ENOSPC[No space left on device]"
.e ENOEXEC,"ENOEXEC[Exec format error]"
.e EALREADY,"EALREADY[Operation already in progress]"
.e ENETDOWN,"ENETDOWN[Network is down]"
.e ENOTNAM,"ENOTNAM[Not a XENIX named type file]"
.e EACCES,"EACCES[Permission denied]"
.e ELNRNG,"ELNRNG[Link number out of range]"
.e EILSEQ,"EILSEQ[Illegal byte sequence]"
.e ENOTDIR,"ENOTDIR[Not a directory]"
.e ENOTUNIQ,"ENOTUNIQ[Name not unique on network]"
.e EPERM,"EPERM[Operation not permitted]"
.e EDOM,"EDOM[Math argument out of domain of func]"
.e EXFULL,"EXFULL[Exchange full]"
.e ECONNREFUSED,"ECONNREFUSED[Connection refused]"
.e EISDIR,"EISDIR[Is a directory]"
.e EPROTONOSUPPORT,"EPROTONOSUPPORT[Protocol not supported]"
.e EROFS,"EROFS[Read-only file system]"
.e EADDRNOTAVAIL,"EADDRNOTAVAIL[Cannot assign requested address]"
.e EIDRM,"EIDRM[Identifier removed]"
.e ECOMM,"ECOMM[Communication error on send]"
.e ESRMNT,"ESRMNT[Srmount error]"
.e EREMOTEIO,"EREMOTEIO[Remote I/O error]"
.e EL3RST,"EL3RST[Level 3 reset]"
.e EBADMSG,"EBADMSG[Not a data message]"
.e ENFILE,"ENFILE[File table overflow]"
.e ELIBMAX,"ELIBMAX[Attempting to link in too many shared libraries]"
.e ESPIPE,"ESPIPE[Illegal seek]"
.e ENOLINK,"ENOLINK[Link has been severed]"
.e ENETRESET,"ENETRESET[Network dropped connection because of reset]"
.e ETIMEDOUT,"ETIMEDOUT[Connection timed out]"
.e ENOENT,"ENOENT[No such file or directory]"
.e EEXIST,"EEXIST[File exists]"
.e EDQUOT,"EDQUOT[Quota exceeded]"
.e ENOSTR,"ENOSTR[Device not a stream]"
.e EBADSLT,"EBADSLT[Invalid slot]"
.e EBADRQC,"EBADRQC[Invalid request code]"
.e ELIBACC,"ELIBACC[Can not access a needed shared library]"
.e EFAULT,"EFAULT[Bad address]"
.e EFBIG,"EFBIG[File too large]"
.e EDEADLK,"EDEADLK[Resource deadlock would occur]"
.e ENOTCONN,"ENOTCONN[Transport endpoint is not connected]"
.e EDESTADDRREQ,"EDESTADDRREQ[Destination address required]"
.e ELIBSCN,"ELIBSCN[.lib section in a.out corrupted]"
.e ENOLCK,"ENOLCK[No record locks available]"
.e EISNAM,"EISNAM[Is a named type file]"
.e ECONNABORTED,"ECONNABORTED[Software caused connection abort]"
.e ENETUNREACH,"ENETUNREACH[Network is unreachable]"
.e ESTALE,"ESTALE[Stale NFS file handle]"
.e ENOSR,"ENOSR[Out of streams resources]"
.e ENOMEM,"ENOMEM[Out of memory]"
.e ENOTSOCK,"ENOTSOCK[Socket operation on non-socket]"
.e ESTRPIPE,"ESTRPIPE[Streams pipe error]"
.e EMLINK,"EMLINK[Too many links]"
.e ERANGE,"ERANGE[Math result not representable]"
.e ELIBEXEC,"ELIBEXEC[Cannot exec a shared library directly]"
.e EL3HLT,"EL3HLT[Level 3 halted]"
.e ECONNRESET,"ECONNRESET[Connection reset by peer]"
.e EADDRINUSE,"EADDRINUSE[Address already in use]"
.e EOPNOTSUPP,"EOPNOTSUPP[Operation not supported on transport endpoint]"
.e EREMCHG,"EREMCHG[Remote address changed]"
.e EAGAIN,"EAGAIN[Try again]"
.e ENAMETOOLONG,"ENAMETOOLONG[File name too long]"
.e ENOTTY,"ENOTTY[Not a typewriter]"
.e ERESTART,"ERESTART[Interrupted system call should be restarted]"
.e ESOCKTNOSUPPORT,"ESOCKTNOSUPPORT[Socket type not supported]"
.e ETIME,"ETIME[Timer expired]"
.e ETOOMANYREFS,"ETOOMANYREFS[Too many references: cannot splice]"
.e EMFILE,"EMFILE[Too many open files]"
.e ETXTBSY,"ETXTBSY[Text file busy]"
.e EINPROGRESS,"EINPROGRESS[Operation now in progress]"
.e ENXIO,"ENXIO[No such device or address]"
.e ENOTSUP,"ENOTSUP[Operation not supported]"
.e EPROTO,"EPROTO[Protocol error]"
.e ENOMSG,"ENOMSG[No message of desired type]"
.e ENODATA,"ENODATA[No data available]"
.e EOVERFLOW,"EOVERFLOW[Value too large for defined data type]"
.e ENOMEDIUM,"ENOMEDIUM[No medium found]"
.e EMEDIUMTYPE,"EMEDIUMTYPE[Wrong medium type]"
.e ECANCELED,"ECANCELED[Operation Canceled]"
.e EOWNERDEAD,"EOWNERDEAD[Owner died]"
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[State not recoverable]"
.e EOWNERDEAD,"EOWNERDEAD[Process died with the lock]"
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[Lock is not recoverable]"
.e EFTYPE,"EFTYPE[Inappropriate file type or format]"
.e EAUTH,"EAUTH[Authentication error]"
.e EBADRPC,"EBADRPC[RPC struct is bad]"
.e ENEEDAUTH,"ENEEDAUTH[Need authenticator]"
.e ENOATTR,"ENOATTR[Attribute not found]"
.e EPROCUNAVAIL,"EPROCUNAVAIL[Bad procedure for program]"
.e EPROGMISMATCH,"EPROGMISMATCH[Program version wrong]"
.e EPROGUNAVAIL,"EPROGUNAVAIL[RPC prog. not avail]"
.e ERPCMISMATCH,"ERPCMISMATCH[RPC version wrong]"
.e EPROCLIM,"EPROCLIM[Too many processes]"
.e EBADARCH,"EBADARCH[Bad CPU type in executable]"
.e EBADEXEC,"EBADEXEC[Bad executable (or shared library)]"
.e EBADMACHO,"EBADMACHO[Malformed Mach-o file]"
.e EDEVERR,"EDEVERR[Device error]"
.e ENOPOLICY,"ENOPOLICY[Policy not found]"
.e EPWROFF,"EPWROFF[Device power is off]"
.e ESHLIBVERS,"ESHLIBVERS[Shared library version mismatch]"
.e ENOANO,"ENOANO[No anode]"
.e EADV,"EADV[Advertise error]"
.e EL2HLT,"EL2HLT[Level 2 halted]"
.e EDOTDOT,"EDOTDOT[RFS specific error]"
.e ENOPKG,"ENOPKG[Package not installed]"
.e EBADR,"EBADR[Invalid request descriptor]"
.e ENOCSI,"ENOCSI[No CSI structure available]"
.e ENOKEY,"ENOKEY[Required key not available]"
.e EUCLEAN,"EUCLEAN[Structure needs cleaning]"
.e ECHRNG,"ECHRNG[Channel number out of range]"
.e EL2NSYNC,"EL2NSYNC[Level 2 not synchronized]"
.e EKEYEXPIRED,"EKEYEXPIRED[Key has expired]"
.e ENAVAIL,"ENAVAIL[No XENIX semaphores available]"
.e EKEYREVOKED,"EKEYREVOKED[Key has been revoked]"
.e ELIBBAD,"ELIBBAD[Accessing a corrupted shared library]"
.e EKEYREJECTED,"EKEYREJECTED[Key was rejected by service]"
.e ERFKILL,"ERFKILL[Operation not possible due to RF-kill]"
.long 0
.endobj kErrorNamesLong,globl,hidden

View file

@ -27,10 +27,13 @@
#include "libc/nt/runtime.h"
#include "libc/str/str.h"
extern const struct Error {
struct Error {
int x;
int s;
} kErrorNames[];
};
extern const struct Error kErrorNames[];
extern const struct Error kErrorNamesLong[];
static const char *GetErrorName(long x) {
int i;
@ -44,6 +47,20 @@ static const char *GetErrorName(long x) {
return "EUNKNOWN";
}
static const char *GetErrorNameLong(long x) {
int i;
if (x) {
for (i = 0; kErrorNamesLong[i].x; ++i) {
if (x ==
*(const long *)((uintptr_t)kErrorNamesLong + kErrorNamesLong[i].x)) {
return (const char *)((uintptr_t)kErrorNamesLong +
kErrorNamesLong[i].s);
}
}
}
return "EUNKNOWN[No error information]";
}
/**
* Converts errno value to string.
* @return 0 on success, or error code
@ -52,7 +69,11 @@ int strerror_r(int err, char *buf, size_t size) {
char *p;
const char *s;
err &= 0xFFFF;
s = GetErrorName(err);
if (IsTiny()) {
s = GetErrorName(err);
} else {
s = GetErrorNameLong(err);
}
p = buf;
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
p = stpcpy(p, s);

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,25 +16,27 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/carsort.h"
#include "libc/fmt/fmt.h"
#include "libc/str/str.h"
/**
* Sorts int32 key-value arrays of trivial size.
* Removes file extension.
*
* @see test/libc/alg/carsort_test.c
* @see carsort1000() if larger
* @param s is mutated
* @return s
*/
textstartup void carsort100(size_t n, int32_t a[n][2]) {
int32_t t[2];
unsigned i, j;
for (i = 1; i < n; ++i) {
j = i;
memcpy(t, a[i], sizeof(t));
while (j > 0 && t[0] < a[j - 1][0]) {
memcpy(a[j], a[j - 1], sizeof(t));
--j;
char *stripext(char *s) {
size_t i;
for (i = strlen(s); i--;) {
switch (s[i]) {
case '.':
s[i] = 0;
return s;
case '/':
return s;
default:
break;
}
memcpy(a[j], t, sizeof(t));
}
return s;
}

View file

@ -37,21 +37,24 @@
* @see strtoumax()
*/
intmax_t strtoimax(const char *s, char **endptr, int base) {
char t = 0;
int d, c = *s;
intmax_t x = 0;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
errno = ERANGE;
break;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
if (!((t |= 1) & 2)) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
errno = ERANGE;
t |= 2;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
}
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return x;
}

View file

@ -25,6 +25,16 @@
/**
* Decodes signed integer from ASCII string.
*
* atoi 10 22𝑐 7𝑛𝑠
* strtol 10 37𝑐 12𝑛𝑠
* strtoul 10 35𝑐 11𝑛𝑠
* wcstol 10 30𝑐 10𝑛𝑠
* wcstoul 10 30𝑐 10𝑛𝑠
* strtoimax 10 80𝑐 26𝑛𝑠
* strtoumax 10 78𝑐 25𝑛𝑠
* wcstoimax 10 77𝑐 25𝑛𝑠
* wcstoumax 10 76𝑐 25𝑛𝑠
*
* @param s is a non-null nul-terminated string
* @param endptr if non-null will always receive a pointer to the char
* following the last one this function processed, which is usually
@ -36,21 +46,24 @@
* @return the decoded signed saturated number
*/
long strtol(const char *s, char **endptr, int base) {
char t = 0;
long x = 0;
int d, c = *s;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? LONG_MAX : LONG_MIN;
errno = ERANGE;
break;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
if (!((t |= 1) & 2)) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? LONG_MAX : LONG_MIN;
errno = ERANGE;
t |= 2;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
}
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return x;
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
#define CONSUME_SPACES(s, c) \
if (endptr) *endptr = s; \
while (c == ' ' || c == '\t') c = *++s
#define GET_SIGN(s, c, d) \
@ -11,6 +12,7 @@
#define GET_RADIX(s, c, r) \
if (!(2 <= r && r <= 36)) { \
if (c == '0') { \
t |= 1; \
c = *++s; \
if (c == 'x' || c == 'X') { \
c = *++s; \
@ -25,6 +27,7 @@
r = 10; \
} \
} else if (c == '0') { \
t |= 1; \
c = *++s; \
if ((r == 2 && (c == 'b' || c == 'B')) || \
(r == 16 && (c == 'x' || c == 'X'))) { \

View file

@ -35,17 +35,19 @@
* @return decoded integer mod 2 negated if leading `-`
*/
unsigned long strtoul(const char *s, char **endptr, int base) {
char t = 0;
int d, c = *s;
unsigned long x = 0;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
t |= 1;
do {
x *= base;
x += c;
} while ((c = kBase36[*++s & 255]) && --c < base);
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return d > 0 ? x : -x;
}

View file

@ -35,17 +35,19 @@
* @see strtoimax()
*/
uintmax_t strtoumax(const char *s, char **endptr, int base) {
char t = 0;
int d, c = *s;
uintmax_t x = 0;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
t |= 1;
do {
x *= base;
x += c;
} while ((c = kBase36[*++s & 255]) && --c < base);
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return d > 0 ? x : -x;
}

View file

@ -37,25 +37,24 @@
* @see strtoumax()
*/
intmax_t wcstoimax(const wchar_t *s, wchar_t **endptr, int base) {
int c, d;
intmax_t x;
c = *s;
char t = 0;
intmax_t x = 0;
int d, c = *s;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
x = 0;
if ((c = kBase36[c & 255]) && --c < base) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
errno = ERANGE;
break;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
}
if (endptr) {
*endptr = s;
if (!((t |= 1) & 2)) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? INTMAX_MAX : INTMAX_MIN;
errno = ERANGE;
t |= 2;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
}
}
if (t && endptr) *endptr = s;
return x;
}

View file

@ -36,21 +36,24 @@
* @return the decoded signed saturated number
*/
long wcstol(const wchar_t *s, wchar_t **endptr, int base) {
char t = 0;
long x = 0;
int d, c = *s;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? LONG_MAX : LONG_MIN;
errno = ERANGE;
break;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
if (!((t |= 1) & 2)) {
do {
if (__builtin_mul_overflow(x, base, &x) ||
__builtin_add_overflow(x, c * d, &x)) {
x = d > 0 ? LONG_MAX : LONG_MIN;
errno = ERANGE;
t |= 2;
}
} while ((c = kBase36[*++s & 255]) && --c < base);
}
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return x;
}

View file

@ -35,17 +35,19 @@
* @return decoded integer mod 2 negated if leading `-`
*/
unsigned long wcstoul(const wchar_t *s, wchar_t **endptr, int base) {
char t = 0;
int d, c = *s;
unsigned long x = 0;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
if ((c = kBase36[c & 255]) && --c < base) {
t |= 1;
do {
x *= base;
x += c;
} while ((c = kBase36[*++s & 255]) && --c < base);
}
if (endptr) *endptr = s;
if (t && endptr) *endptr = s;
return d > 0 ? x : -x;
}

View file

@ -35,21 +35,19 @@
* @see strtoimax()
*/
uintmax_t wcstoumax(const wchar_t *s, wchar_t **endptr, int base) {
int c, d;
uintmax_t x;
c = *s;
char t = 0;
int d, c = *s;
uintmax_t x = 0;
CONSUME_SPACES(s, c);
GET_SIGN(s, c, d);
GET_RADIX(s, c, base);
x = 0;
if ((c = kBase36[c & 255]) && --c < base) {
t |= 1;
do {
x *= base;
x += c;
} while ((c = kBase36[*++s & 255]) && --c < base);
}
if (endptr) {
*endptr = s;
}
if (t && endptr) *endptr = s;
return d > 0 ? x : -x;
}

View file

@ -644,6 +644,10 @@ typedef uint64_t uintmax_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
#ifdef __llvm__
#define __builtin_ia32_movntdq(x, y) (*(x) = (y))
#endif
#ifndef _Section
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__)
#define _Section(s) __attribute__((__section__(s)))

View file

@ -64,7 +64,7 @@
#endif
#define BIGPAGESIZE 0x200000
#define STACKSIZE 0x100000
#define STACKSIZE 0x200000
#define FRAMESIZE 0x10000 /* 8086 */
#define PAGESIZE 0x1000 /* i386+ */
#define BUFSIZ 0x1000 /* best stdio default */

View file

@ -24,6 +24,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/hook/hook.internal.h"
@ -32,12 +33,16 @@
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/dlmalloc/dlmalloc.internal.h"
#define COOKIE 21578
STATIC_YOINK("_init_asan");
/**
@ -85,6 +90,8 @@ STATIC_YOINK("_init_asan");
} \
} while (0)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
struct AsanSourceLocation {
const char *filename;
int line;
@ -129,6 +136,28 @@ static uint64_t __asan_rounddown2pow(uint64_t x) {
return x ? 1ull << __asan_bsrl(x) : 0;
}
static uint64_t __asan_encodeutf8(unsigned c) {
static const unsigned short kTpEnc[32 - 7] = {
1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 1 | 0300 << 8, 2 | 0340 << 8,
2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 2 | 0340 << 8, 3 | 0360 << 8,
3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 3 | 0360 << 8, 4 | 0370 << 8,
4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 4 | 0370 << 8, 5 | 0374 << 8,
5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8, 5 | 0374 << 8,
};
int e, n;
unsigned long long w;
if (c < 0200) return c;
e = kTpEnc[__asan_bsrl(c) - 7];
n = e & 0xff;
w = 0;
do {
w |= 0200 | (c & 077);
w <<= 8;
c >>= 6;
} while (--n);
return c | w | e >> 8;
}
static size_t __asan_strlen(const char *s) {
size_t n = 0;
while (*s++) ++n;
@ -299,20 +328,68 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
return p;
}
static char *__asan_uint2str(char *p, uint64_t i) {
int j = 0;
static char *__asan_uintcpy(char p[hasatleast 21], uint64_t x) {
char t;
size_t i, a, b;
i = 0;
do {
p[j++] = i % 10 + '0';
i /= 10;
} while (i > 0);
reverse(p, j);
return p + j;
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
static char *__asan_intcpy(char *p, int64_t i) {
if (i >= 0) return __asan_uint2str(p, i);
*p++ = '-';
return __asan_uint2str(p, -i);
static char *__asan_intcpy(char p[hasatleast 21], int64_t x) {
if (x < 0) *p++ = '-', x = -(uint64_t)x;
return __asan_uintcpy(p, x);
}
privileged noinline wontreturn void __asan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
privileged noinline ssize_t __asan_write(const void *data, size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
static ssize_t __asan_write_string(const char *s) {
return __asan_write(s, __asan_strlen(s));
}
wontreturn void __asan_die(const char *msg) {
__asan_write_string(msg);
if (weaken(__die)) weaken(__die)();
__asan_exit(134);
}
void __asan_poison(uintptr_t p, size_t n, int t) {
@ -320,13 +397,16 @@ void __asan_poison(uintptr_t p, size_t n, int t) {
k = p & 7;
s = (signed char *)((p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n && (!*s || *s > k) && 8 - k >= n) *s = k;
++s, n -= MIN(8 - k, n);
if (k < *s && *s <= k + n) *s = k;
n -= MIN(8 - k, n);
s += 1;
}
__asan_memset(s, t, n >> 3);
if ((k = n & 7)) {
s += n >> 3;
if (*s < 0 || 0 < *s && *s <= k) *s = t;
if (*s >= 0) {
*s = kAsanHeapOverrun;
}
}
}
@ -335,54 +415,126 @@ void __asan_unpoison(uintptr_t p, size_t n) {
k = p & 7;
s = (signed char *)((p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n) *s = 0;
++s, n -= MIN(8 - k, n);
if (!n) return;
if (k + n < 8) {
*s = MAX(*s, k + n);
return;
} else {
*s = 0;
}
n -= MIN(8 - k, n);
s += 1;
}
__asan_memset(s, 0, n >> 3);
if ((k = n & 7)) {
s += n >> 3;
if (*s && *s < k) *s = k;
if (*s < 0) {
*s = k;
} else if (*s > 0) {
*s = MAX(*s, k);
}
}
}
bool __asan_is_valid(const void *p, size_t n) {
signed char k, *s, *e;
if (n) {
if (p) {
k = (uintptr_t)p & 7;
s = (signed char *)(((uintptr_t)p >> 3) + 0x7fff8000);
if (UNLIKELY(k)) {
if (n && !(!*s || *s >= k + n)) return false;
++s, n -= MIN(8 - k, n);
}
e = s;
k = n & 7;
e += n >> 3;
for (; s + 8 <= e; s += 8) {
if ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070) {
return false;
}
}
while (s < e) {
if (*s++) {
return false;
}
}
if (k) {
if (!(!*s || *s >= k)) {
return false;
}
}
return true;
} else {
return false;
}
static inline bool __asan_is_mapped(int x) {
int i;
struct MemoryIntervals *m;
m = weaken(_mmi);
i = FindMemoryInterval(m, x);
return i < m->i && m->p[i].x <= x && x <= m->p[i].y;
}
static inline bool __asan_is_image(const unsigned char *p) {
return _base <= p && p < _end;
}
static inline bool __asan_exists(const void *x) {
return __asan_is_image(x) || __asan_is_mapped((intptr_t)x >> 16);
}
static struct AsanFault __asan_fault(signed char *s, char dflt) {
struct AsanFault r;
if (s[0] < 0) {
r.kind = s[0];
} else if (((uintptr_t)(s + 1) & (PAGESIZE - 1)) && s[1] < 0) {
r.kind = s[1];
} else {
return true;
r.kind = dflt;
}
r.shadow = s;
return r;
}
struct AsanFault __asan_check(const void *p, size_t n) {
intptr_t a;
uint64_t w;
unsigned u, r;
signed char k, *s, *e, *f;
if (!n) return (struct AsanFault){0};
k = (intptr_t)p & 7;
a = ((intptr_t)p >> 3) + 0x7fff8000;
s = (signed char *)a;
if (!__asan_is_mapped(a >> 16)) {
return (struct AsanFault){kAsanUnmapped, s};
}
if (UNLIKELY(k)) {
if (!*s) {
n -= MIN(8 - k, n);
s += 1;
} else if (*s > 0 && k + n < 8 && *s >= k + n) {
return (struct AsanFault){0};
} else {
return __asan_fault(s, kAsanHeapOverrun);
}
}
e = s;
k = n & 7;
e += n >> 3;
while (s < e && ((intptr_t)s & 7)) {
if (*s++) {
return __asan_fault(s - 1, kAsanHeapOverrun);
}
}
for (; s + 8 <= e; s += 8) {
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
if (!__asan_is_mapped(a >> 16)) {
return (struct AsanFault){kAsanUnmapped, s};
}
}
if ((w = ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070))) {
s += (unsigned)__builtin_ctzll(w) >> 3;
return __asan_fault(s, kAsanHeapOverrun);
}
}
while (s < e) {
if (*s++) {
return __asan_fault(s - 1, kAsanHeapOverrun);
}
}
if (!k || !*s || k <= *s) {
return (struct AsanFault){0};
} else {
return __asan_fault(s, kAsanHeapOverrun);
}
}
void __asan_verify(const void *p, size_t n) {
const char *q;
struct AsanFault f;
if (!(f = __asan_check(p, n)).kind) return;
q = UNSHADOW(f.shadow);
if ((uintptr_t)q != ((uintptr_t)p & -8) && (uintptr_t)q - (uintptr_t)p < n) {
n -= (uintptr_t)q - (uintptr_t)p;
p = q;
}
__asan_report(p, n, "verify", f.kind);
}
bool __asan_is_valid(const void *p, size_t n) {
return !__asan_check(p, n).kind;
}
bool __asan_is_valid_iov(const struct iovec *iov, int iovlen) {
@ -423,10 +575,8 @@ static const char *__asan_dscribe_heap_poison(long c) {
}
}
static const char *__asan_describe_access_poison(signed char *p) {
int c = p[0];
if (1 <= c && c <= 7) c = p[1];
switch (c) {
static const char *__asan_describe_access_poison(char kind) {
switch (kind) {
case kAsanHeapFree:
return "heap use after free";
case kAsanStackFree:
@ -453,89 +603,163 @@ static const char *__asan_describe_access_poison(signed char *p) {
return "unscoped";
case kAsanUnmapped:
return "unmapped";
case kAsanProtected:
return "protected";
case kAsanStackGuard:
return "stack overflow";
default:
return "poisoned";
}
}
static privileged noinline wontreturn void __asan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static privileged noinline ssize_t __asan_write(const void *data, size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
static ssize_t __asan_write_string(const char *s) {
return __asan_write(s, __asan_strlen(s));
}
static wontreturn void __asan_die(const char *msg) {
__asan_write_string(msg);
if (weaken(__die)) weaken(__die)();
__asan_exit(134);
}
static char *__asan_report_start(char *p) {
bool ansi;
static bool __asan_ansi(void) {
const char *term;
term = weaken(getenv) ? weaken(getenv)("TERM") : NULL;
ansi = !term || __asan_strcmp(term, "dumb") != 0;
return !term || __asan_strcmp(term, "dumb") != 0;
}
static char *__asan_report_start(char *p, bool ansi) {
if (ansi) p = __asan_stpcpy(p, "\r\e[J\e[1;91m");
p = __asan_stpcpy(p, "asan error");
if (ansi) p = __asan_stpcpy(p, "\e[0m");
return __asan_stpcpy(p, ": ");
}
static wontreturn void __asan_report_heap_fault(void *addr, long c) {
char *p, ibuf[21], buf[256];
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c));
p = __asan_stpcpy(p, " at 0x");
static wontreturn void __asan_report_invalid_pointer(void *addr) {
char *p;
p = __asan_report_start(__fatalbuf, __asan_ansi());
p = __asan_stpcpy(p, "invalid pointer 0x");
p = __asan_hexcpy(p, (intptr_t)addr, 48);
p = __asan_stpcpy(p, " shadow 0x");
p = __asan_hexcpy(p, (intptr_t)SHADOW(addr), 48);
p = __asan_stpcpy(p, "\r\n");
__asan_die(buf);
__asan_die(__fatalbuf);
}
static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
const char *kind) {
char *p, ibuf[21], buf[256];
p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr)));
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
p = __asan_hexcpy(p, a, 48);
*p++ = '-';
p = __asan_hexcpy(p, b, 48);
return p;
}
static char *__asan_format_section(char *p, void *p1, void *p2,
const char *name, void *addr) {
intptr_t a, b;
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
p = __asan_format_interval(p, a, b);
*p++ = ' ';
p = __asan_stpcpy(p, name);
if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
p = __asan_stpcpy(p, " ←address");
}
*p++ = '\r';
*p++ = '\n';
}
return p;
}
wontreturn void __asan_report(void *addr, int size, const char *message,
char kind) {
bool a;
wint_t c;
int i, cc;
signed char t;
uint64_t x, y, z;
char *p, *q, *base;
struct MemoryIntervals *m;
a = __asan_ansi();
p = __asan_report_start(__fatalbuf, a);
p = __asan_stpcpy(p, __asan_describe_access_poison(kind));
p = __asan_stpcpy(p, " ");
p = __asan_intcpy(p, size);
p = __asan_stpcpy(p, "-byte ");
p = __asan_stpcpy(p, kind);
p = __asan_stpcpy(p, message);
p = __asan_stpcpy(p, " at 0x");
p = __asan_hexcpy(p, (uintptr_t)addr, 48);
p = __asan_stpcpy(p, " shadow 0x");
p = __asan_hexcpy(p, (uintptr_t)SHADOW(addr), 48);
p = __asan_stpcpy(p, "\r\n");
__asan_die(buf);
*p++ = '\r', *p++ = '\n';
if (0 < size && size < 80) {
base = (char *)addr - ((80 >> 1) - (size >> 1));
for (i = 0; i < 80; ++i) {
if ((char *)addr <= base + i && base + i < (char *)addr + size) {
if (__asan_is_valid(base + i, 1)) {
*p++ = '*';
} else {
*p++ = 'x';
}
} else {
*p++ = ' ';
}
}
*p++ = '\r', *p++ = '\n';
for (c = i = 0; i < 80; ++i) {
if (!(t = __asan_check(base + i, 1).kind)) {
if (a && c != 32) {
p = __asan_stpcpy(p, "\e[32m");
c = 32;
}
*p++ = '.';
} else {
if (a && c != 31) {
p = __asan_stpcpy(p, "\e[31m");
c = 31;
}
*p++ = "FFRRUOOGUOUOSMP~"[-t & 15];
}
}
if (a) p = __asan_stpcpy(p, "\e[39m");
*p++ = '\r', *p++ = '\n';
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
for (; i + 8 <= 80; i += 8) {
q = p + 8;
*p++ = '|';
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
if (__asan_is_mapped(z >> 16)) {
p = __asan_intcpy(p, *(signed char *)z);
} else {
*p++ = '!';
}
while (p < q) {
*p++ = ' ';
}
}
for (; i < 80; ++i) *p++ = ' ';
*p++ = '\r', *p++ = '\n';
for (i = 0; i < 80; ++i) {
if (__asan_exists(base + i)) {
c = kCp437[((unsigned char *)base)[i]];
} else {
c = u'';
}
z = __asan_encodeutf8(c);
do {
*p++ = z;
} while ((z >>= 8));
}
*p++ = '\r', *p++ = '\n';
}
p = __asan_format_section(p, _base, _etext, ".text", addr);
p = __asan_format_section(p, _etext, _edata, ".data", addr);
p = __asan_format_section(p, _end, _edata, ".bss", addr);
for (m = weaken(_mmi), i = 0; i < m->i; ++i) {
x = m->p[i].x;
y = m->p[i].y;
p = __asan_format_interval(p, x << 16, (y << 16) + (FRAMESIZE - 1));
z = (intptr_t)addr >> 16;
if (x <= z && z <= y) p = __asan_stpcpy(p, " ←address");
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
if (x <= z && z <= y) p = __asan_stpcpy(p, " ←shadow");
*p++ = '\r', *p++ = '\n';
}
*p = 0;
__asan_die(__fatalbuf);
}
wontreturn void __asan_report_memory_fault(void *addr, int size,
const char *message) {
__asan_report(addr, size, message, __asan_fault(SHADOW(addr), -128).kind);
}
const void *__asan_morgue_add(void *p) {
@ -566,75 +790,108 @@ static void __asan_morgue_flush(void) {
}
static size_t __asan_heap_size(size_t n) {
if (n < -8) {
if (n <= 0x7fffffffffff) {
return __asan_roundup2pow(ROUNDUP(n, 8) + 8);
} else {
return -1;
}
}
static size_t __asan_user_size(size_t n) {
if (n) {
return n;
} else {
return 1;
}
}
static size_t __asan_stack_size(void) {
extern char ape_stack_memsz[] __attribute__((__weak__));
if (ape_stack_memsz) {
return (uintptr_t)ape_stack_memsz;
} else {
return STACKSIZE;
}
}
forceinline void __asan_write48(char *p, uint64_t x) {
uint64_t value, cookie;
cookie = COOKIE;
cookie ^= x & 0xffff;
value = (x & 0xffffffffffff) | cookie << 48;
WRITE64BE(p, value);
}
forceinline bool __asan_read48(const char *p, uint64_t *x) {
uint64_t value, cookie;
value = READ64BE(p);
cookie = value >> 48;
cookie ^= value & 0xffff;
*x = (int64_t)(value << 16) >> 16;
return cookie == COOKIE;
}
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
char *p;
size_t c;
char *p, *f;
if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) {
n = __asan_user_size(n);
c = weaken(dlmalloc_usable_size)(p);
__asan_unpoison((uintptr_t)p, n);
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
__asan_poison((uintptr_t)p + n, c - n, overrun);
__asan_memset(p, 0xF9, n);
f = p + c - 8;
WRITE64BE(f, n);
__asan_write48(p + c - 8, n);
}
return p;
}
static size_t __asan_malloc_usable_size(const void *p) {
size_t c, n;
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
if ((n = READ64BE((char *)p + c - 8)) <= c) {
return n;
} else {
__asan_report_heap_fault(p, n);
struct AsanFault f;
if (!(f = __asan_check(p, 1)).kind) {
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
if (__asan_read48((char *)p + c - 8, &n) && n <= c) {
return n;
}
}
__asan_report_invalid_pointer(p);
} else {
__asan_report_heap_fault(p, 0);
__asan_report(p, 1, "heaping", f.kind);
}
}
static void __asan_deallocate(char *p, long kind) {
size_t c, n;
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
if ((n = READ64BE(p + c - 8)) <= c) {
WRITE64BE(p + c - 8, kind);
__asan_poison((uintptr_t)p, c - 8, kind);
if (weaken(dlfree)) {
if (c <= FRAMESIZE) {
p = __asan_morgue_add(p);
}
weaken(dlfree)(p);
if (__asan_read48(p + c - 8, &n) && n <= c) {
__asan_poison((uintptr_t)p, c, kind);
if (c <= FRAMESIZE) {
p = __asan_morgue_add(p);
}
weaken(dlfree)(p);
} else {
__asan_report_heap_fault(p, n);
__asan_report_invalid_pointer(p);
}
} else {
__asan_report_heap_fault(p, 0);
__asan_report_invalid_pointer(p);
}
}
static void __asan_free(void *p) {
void __asan_free(void *p) {
if (!p) return;
__asan_deallocate(p, kAsanHeapFree);
}
static void *__asan_memalign(size_t align, size_t size) {
void *__asan_memalign(size_t align, size_t size) {
return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun);
}
static void *__asan_malloc(size_t size) {
void *__asan_malloc(size_t size) {
return __asan_memalign(__BIGGEST_ALIGNMENT__, size);
}
static void *__asan_calloc(size_t n, size_t m) {
void *__asan_calloc(size_t n, size_t m) {
char *p;
if (__builtin_mul_overflow(n, m, &n)) n = -1;
if ((p = __asan_malloc(n))) __asan_memset(p, 0, n);
@ -660,27 +917,27 @@ static void *__asan_realloc_impl(void *p, size_t n,
size_t c, m;
if ((c = weaken(dlmalloc_usable_size)(p)) >= 8) {
f = (char *)p + c - 8;
if ((m = READ64BE(f)) <= c) {
if (__asan_read48(f, &m) && m <= c) {
if (n <= m) { /* shrink */
__asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun);
WRITE64BE(f, n);
__asan_write48(f, n);
return p;
} else if (n <= c - 8) { /* small growth */
__asan_unpoison((uintptr_t)p + m, n - m);
WRITE64BE(f, n);
__asan_write48(f, n);
return p;
} else { /* exponential growth */
return grow(p, n, m);
}
} else {
__asan_report_heap_fault(p, m);
__asan_report_invalid_pointer(p);
}
} else {
__asan_report_heap_fault(p, 0);
__asan_report_invalid_pointer(p);
}
}
static void *__asan_realloc(void *p, size_t n) {
void *__asan_realloc(void *p, size_t n) {
if (p) {
if (n) {
return __asan_realloc_impl(p, n, __asan_realloc_grow);
@ -693,7 +950,7 @@ static void *__asan_realloc(void *p, size_t n) {
}
}
static void *__asan_realloc_in_place(void *p, size_t n) {
void *__asan_realloc_in_place(void *p, size_t n) {
if (p) {
return __asan_realloc_impl(p, n, __asan_realloc_nogrow);
} else {
@ -701,15 +958,15 @@ static void *__asan_realloc_in_place(void *p, size_t n) {
}
}
static void *__asan_valloc(size_t n) {
void *__asan_valloc(size_t n) {
return __asan_memalign(PAGESIZE, n);
}
static void *__asan_pvalloc(size_t n) {
void *__asan_pvalloc(size_t n) {
return __asan_valloc(ROUNDUP(n, PAGESIZE));
}
static int __asan_malloc_trim(size_t pad) {
int __asan_malloc_trim(size_t pad) {
__asan_morgue_flush();
if (weaken(dlmalloc_trim)) {
return weaken(dlmalloc_trim)(pad);
@ -727,9 +984,10 @@ void __asan_stack_free(char *p, size_t size, int classid) {
}
void __asan_handle_no_return(void) {
uintptr_t rsp;
rsp = (uintptr_t)__builtin_frame_address(0);
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
uintptr_t stk, ssz;
stk = (uintptr_t)__builtin_frame_address(0);
ssz = __asan_stack_size();
__asan_unpoison(stk, ROUNDUP(stk, ssz) - stk);
}
void __asan_register_globals(struct AsanGlobal g[], int n) {
@ -797,14 +1055,6 @@ void __asan_install_malloc_hooks(void) {
HOOK(hook_malloc_usable_size, __asan_malloc_usable_size);
}
static bool __asan_is_mapped(int x) {
int i;
struct MemoryIntervals *m;
m = weaken(_mmi);
i = weaken(FindMemoryInterval)(m, x);
return i < m->i && x >= m->p[i].x && x <= m->p[i].y;
}
void __asan_map_shadow(uintptr_t p, size_t n) {
int i, x, a, b;
struct DirectMap sm;
@ -862,17 +1112,22 @@ static textstartup void __asan_shadow_string_list(char **list) {
static textstartup void __asan_shadow_existing_mappings(void) {
size_t i;
uintptr_t rsp, stk, ssz;
struct MemoryIntervals m;
__asan_memcpy(&m, weaken(_mmi), sizeof(m));
for (i = 0; i < m.i; ++i) {
__asan_map_shadow((uintptr_t)m.p[i].x << 16,
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16);
}
rsp = (uintptr_t)__builtin_frame_address(0);
ssz = __asan_stack_size();
stk = ROUNDDOWN(rsp, ssz);
__asan_poison(stk, PAGESIZE, kAsanStackGuard);
}
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
weaken(FindMemoryInterval) && weaken(TrackMemoryInterval);
weaken(TrackMemoryInterval);
}
textstartup void __asan_init(int argc, char **argv, char **envp,
@ -886,7 +1141,6 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
REQUIRE(_mmi);
REQUIRE(sys_mmap);
REQUIRE(MAP_ANONYMOUS);
REQUIRE(FindMemoryInterval);
REQUIRE(TrackMemoryInterval);
if (weaken(hook_malloc) || weaken(hook_calloc) || weaken(hook_realloc) ||
weaken(hook_realloc_in_place) || weaken(hook_pvalloc) ||

View file

@ -4,27 +4,49 @@
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanHeapFree -1
#define kAsanStackFree -2
#define kAsanRelocated -3
#define kAsanHeapUnderrun -4
#define kAsanHeapOverrun -5
#define kAsanGlobalOverrun -6
#define kAsanGlobalUnregistered -7
#define kAsanStackUnderrun -8
#define kAsanStackOverrun -9
#define kAsanAllocaUnderrun -10
#define kAsanAllocaOverrun -11
#define kAsanUnscoped -12
#define kAsanUnmapped -13
#define kAsanHeapFree -1 /* F */
#define kAsanStackFree -2 /* F */
#define kAsanRelocated -3 /* R */
#define kAsanHeapUnderrun -4 /* U */
#define kAsanHeapOverrun -5 /* O */
#define kAsanGlobalOverrun -6 /* O */
#define kAsanGlobalUnregistered -7 /* G */
#define kAsanStackUnderrun -8 /* U */
#define kAsanStackOverrun -9 /* O */
#define kAsanAllocaUnderrun -10 /* U */
#define kAsanAllocaOverrun -11 /* O */
#define kAsanUnscoped -12 /* S */
#define kAsanUnmapped -13 /* M */
#define kAsanProtected -14 /* P */
#define kAsanStackGuard -15 /* _ */
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3))
struct AsanFault {
char kind;
signed char *shadow;
};
void __asan_unpoison(uintptr_t, size_t);
void __asan_verify(const void *, size_t);
void __asan_map_shadow(uintptr_t, size_t);
void __asan_poison(uintptr_t, size_t, int);
void __asan_unpoison(uintptr_t, size_t);
bool __asan_is_valid(const void *, size_t);
bool __asan_is_valid_iov(const struct iovec *, int);
bool __asan_is_valid_strlist(char *const *);
bool __asan_is_valid_iov(const struct iovec *, int);
struct AsanFault __asan_check(const void *, size_t);
void __asan_report_memory_fault(void *, int, const char *) wontreturn;
void __asan_report(void *, int, const char *, char) wontreturn;
void *__asan_memalign(size_t, size_t);
void __asan_free(void *);
void *__asan_malloc(size_t);
void *__asan_calloc(size_t, size_t);
void *__asan_realloc(void *, size_t);
void *__asan_realloc_in_place(void *, size_t);
void *__asan_valloc(size_t);
void *__asan_pvalloc(size_t);
int __asan_malloc_trim(size_t);
void __asan_die(const char *) wontreturn;
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

157
libc/intrin/bzero.c Normal file
View file

@ -0,0 +1,157 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
static noinline antiquity void bzero_sse(char *p, size_t n) {
xmm_t v = {0};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
}
microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
xmm_t v = {0};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
asm("rep stosb" : "+D"(p), "+c"(n), "=m"(*(char(*)[n])p) : "a"(0));
} else {
if (n < kHalfCache3 || !kHalfCache3) {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
} else {
while ((uintptr_t)(p + n) & 15) {
p[--n] = 0;
}
do {
n -= 32;
__builtin_ia32_movntdq((xmm_a *)(p + n), (xmm_a)v);
__builtin_ia32_movntdq((xmm_a *)(p + n + 16), (xmm_a)v);
} while (n > 32);
asm("sfence");
}
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
}
/**
* Sets memory to zero.
*
* bzero n=0 661 picoseconds
* bzero n=1 661 ps/byte 1,476 mb/s
* bzero n=2 330 ps/byte 2,952 mb/s
* bzero n=3 220 ps/byte 4,428 mb/s
* bzero n=4 165 ps/byte 5,904 mb/s
* bzero n=7 94 ps/byte 10,333 mb/s
* bzero n=8 41 ps/byte 23,618 mb/s
* bzero n=15 44 ps/byte 22,142 mb/s
* bzero n=16 20 ps/byte 47,236 mb/s
* bzero n=31 21 ps/byte 45,760 mb/s
* bzero n=32 20 ps/byte 47,236 mb/s
* bzero n=63 10 ps/byte 92,997 mb/s
* bzero n=64 15 ps/byte 62,982 mb/s
* bzero n=127 15 ps/byte 62,490 mb/s
* bzero n=128 10 ps/byte 94,473 mb/s
* bzero n=255 14 ps/byte 68,439 mb/s
* bzero n=256 9 ps/byte 105 gb/s
* bzero n=511 15 ps/byte 62,859 mb/s
* bzero n=512 11 ps/byte 83,976 mb/s
* bzero n=1023 15 ps/byte 61,636 mb/s
* bzero n=1024 10 ps/byte 88,916 mb/s
* bzero n=2047 9 ps/byte 105 gb/s
* bzero n=2048 8 ps/byte 109 gb/s
* bzero n=4095 8 ps/byte 115 gb/s
* bzero n=4096 8 ps/byte 118 gb/s
* bzero n=8191 7 ps/byte 129 gb/s
* bzero n=8192 7 ps/byte 130 gb/s
* bzero n=16383 6 ps/byte 136 gb/s
* bzero n=16384 6 ps/byte 137 gb/s
* bzero n=32767 6 ps/byte 140 gb/s
* bzero n=32768 6 ps/byte 141 gb/s
* bzero n=65535 15 ps/byte 64,257 mb/s
* bzero n=65536 15 ps/byte 64,279 mb/s
* bzero n=131071 15 ps/byte 63,166 mb/s
* bzero n=131072 15 ps/byte 63,115 mb/s
* bzero n=262143 15 ps/byte 62,052 mb/s
* bzero n=262144 15 ps/byte 62,097 mb/s
* bzero n=524287 15 ps/byte 61,699 mb/s
* bzero n=524288 15 ps/byte 61,674 mb/s
* bzero n=1048575 16 ps/byte 60,179 mb/s
* bzero n=1048576 15 ps/byte 61,330 mb/s
* bzero n=2097151 15 ps/byte 61,071 mb/s
* bzero n=2097152 15 ps/byte 61,065 mb/s
* bzero n=4194303 16 ps/byte 60,942 mb/s
* bzero n=4194304 16 ps/byte 60,947 mb/s
* bzero n=8388607 16 ps/byte 60,872 mb/s
* bzero n=8388608 16 ps/byte 60,879 mb/s
*
* @param p is memory address
* @param n is byte length
* @return p
* @asyncsignalsafe
*/
void(bzero)(void *p, size_t n) {
char *b;
uint64_t x;
b = p;
if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
return;
}
asm("xorl\t%k0,%k0" : "=r"(x));
if (n <= 16) {
if (n >= 8) {
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
} else if (n >= 4) {
__builtin_memcpy(b, &x, 4);
__builtin_memcpy(b + n - 4, &x, 4);
} else if (n) {
do {
asm volatile("" ::: "memory");
b[--n] = x;
} while (n);
}
} else if (X86_HAVE(AVX)) {
bzero_avx(b, n);
} else {
bzero_sse(b, n);
}
}

21
libc/intrin/fatalbuf.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/libfatal.internal.h"
char __fatalbuf[FRAMESIZE];

1
libc/intrin/ho.s Normal file
View file

@ -0,0 +1 @@
bsr %rdi,%rax

View file

@ -46,8 +46,27 @@ o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all \
-fno-stack-protector \
-mgeneral-regs-only \
-O2
-O3
o/$(MODE)/libc/intrin/memcmp.o: \
OVERRIDE_CFLAGS += \
-Os
o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-fno-toplevel-reorder
o//libc/intrin/bzero.o \
o//libc/intrin/memset.o \
o//libc/intrin/memmove.o: \
OVERRIDE_CFLAGS += \
-O3
o/tiny/libc/intrin/memcmp.o \
o/tiny/libc/intrin/memmove.o \
o/tiny/libc/intrin/memmove-gcc.asm: \
OVERRIDE_CFLAGS += \
-fpie
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))

210
libc/intrin/memcmp.c Normal file
View file

@ -0,0 +1,210 @@
/*-*- 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/bits/likely.h"
#include "libc/dce.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
static noinline antiquity int memcmp_sse(const unsigned char *p,
const unsigned char *q, size_t n) {
uint64_t w;
unsigned u, u0, u1, u2, u3;
if (n > 32) {
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)p, *(const xmm_t *)q)) -
0xffff)) {
n -= 16;
p += 16;
q += 16;
} else {
u = __builtin_ctzl(u);
return p[u] - q[u];
}
}
}
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)p, *(const xmm_t *)q)) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
0xffff)) {
return 0;
} else {
u = __builtin_ctzl(u);
return p[n - 16 + u] - q[n - 16 + u];
}
} else {
u = __builtin_ctzl(u);
return p[u] - q[u];
}
}
microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
const unsigned char *q,
size_t n) {
uint64_t w;
unsigned u, u0, u1, u2, u3;
if (n > 32) {
while (n >= 16 + 64) {
u0 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
((const xmm_t *)p)[0], ((const xmm_t *)q)[0]));
u1 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
((const xmm_t *)p)[1], ((const xmm_t *)q)[1]));
u2 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
((const xmm_t *)p)[2], ((const xmm_t *)q)[2]));
u3 = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
((const xmm_t *)p)[3], ((const xmm_t *)q)[3]));
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
(uint64_t)u3 << 48;
if (w == -1) {
n -= 64;
p += 64;
q += 64;
} else {
w = __builtin_ctzll(w ^ -1);
return p[w] - q[w];
}
}
while (n > 16 + 16) {
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)p, *(const xmm_t *)q)) -
0xffff)) {
n -= 16;
p += 16;
q += 16;
} else {
u = __builtin_ctzl(u);
return p[u] - q[u];
}
}
}
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)p, *(const xmm_t *)q)) -
0xffff)) {
if (!(u = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(
*(const xmm_t *)(p + n - 16), *(const xmm_t *)(q + n - 16))) -
0xffff)) {
return 0;
} else {
u = __builtin_ctzl(u);
return p[n - 16 + u] - q[n - 16 + u];
}
} else {
u = __builtin_ctzl(u);
return p[u] - q[u];
}
}
/**
* Compares memory byte by byte.
*
* memcmp n=0 992 picoseconds
* memcmp n=1 1 ns/byte 738 mb/s
* memcmp n=2 661 ps/byte 1,476 mb/s
* memcmp n=3 551 ps/byte 1,771 mb/s
* memcmp n=4 248 ps/byte 3,936 mb/s
* memcmp n=5 198 ps/byte 4,920 mb/s
* memcmp n=6 165 ps/byte 5,904 mb/s
* memcmp n=7 141 ps/byte 6,889 mb/s
* memcmp n=8 124 ps/byte 7,873 mb/s
* memcmp n=9 110 ps/byte 8,857 mb/s
* memcmp n=15 44 ps/byte 22,143 mb/s
* memcmp n=16 41 ps/byte 23,619 mb/s
* memcmp n=17 77 ps/byte 12,547 mb/s
* memcmp n=31 42 ps/byte 22,881 mb/s
* memcmp n=32 41 ps/byte 23,619 mb/s
* memcmp n=33 60 ps/byte 16,238 mb/s
* memcmp n=80 53 ps/byte 18,169 mb/s
* memcmp n=128 38 ps/byte 25,194 mb/s
* memcmp n=256 32 ps/byte 30,233 mb/s
* memcmp n=16384 27 ps/byte 35,885 mb/s
* memcmp n=32768 29 ps/byte 32,851 mb/s
* memcmp n=131072 33 ps/byte 28,983 mb/s
*
* @return unsigned char subtraction at stop index
* @asyncsignalsafe
*/
int memcmp(const void *a, const void *b, size_t n) {
int c;
unsigned u;
uint32_t k, i, j;
uint64_t w, x, y;
const unsigned char *p, *q;
if ((p = a) == (q = b)) return 0;
if (!IsTiny()) {
if (n <= 16) {
if (n >= 8) {
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
p += n - 8;
q += n - 8;
if (!(w = (x = ((uint64_t)p[0] << 000 | (uint64_t)p[1] << 010 |
(uint64_t)p[2] << 020 | (uint64_t)p[3] << 030 |
(uint64_t)p[4] << 040 | (uint64_t)p[5] << 050 |
(uint64_t)p[6] << 060 | (uint64_t)p[7] << 070)) ^
(y = ((uint64_t)q[0] << 000 | (uint64_t)q[1] << 010 |
(uint64_t)q[2] << 020 | (uint64_t)q[3] << 030 |
(uint64_t)q[4] << 040 | (uint64_t)q[5] << 050 |
(uint64_t)q[6] << 060 | (uint64_t)q[7] << 070)))) {
return 0;
}
}
u = __builtin_ctzll(w);
u = u & -8;
return ((x >> u) & 255) - ((y >> u) & 255);
} else if (n >= 4) {
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
p += n - 4;
q += n - 4;
if (!(k = (i = ((uint32_t)p[0] << 000 | (uint32_t)p[1] << 010 |
(uint32_t)p[2] << 020 | (uint32_t)p[3] << 030)) ^
(j = ((uint32_t)q[0] << 000 | (uint32_t)q[1] << 010 |
(uint32_t)q[2] << 020 | (uint32_t)q[3] << 030)))) {
return 0;
}
}
u = __builtin_ctzl(k);
u = u & -8;
return ((i >> u) & 255) - ((j >> u) & 255);
}
} else if (LIKELY(X86_HAVE(AVX))) {
return memcmp_avx(p, q, n);
} else {
return memcmp_sse(p, q, n);
}
}
for (; n; ++p, ++q, --n) {
if ((c = *p - *q)) {
return c;
}
}
return 0;
}

309
libc/intrin/memmove.c Normal file
View file

@ -0,0 +1,309 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
asm("memcpy = memmove\n\t"
".globl\tmemcpy");
/**
* Copies memory.
*
* memmove n=0 661 picoseconds
* memmove n=1 661 ps/byte 1,476 mb/s
* memmove n=2 330 ps/byte 2,952 mb/s
* memmove n=3 330 ps/byte 2,952 mb/s
* memmove n=4 165 ps/byte 5,904 mb/s
* memmove n=7 141 ps/byte 6,888 mb/s
* memmove n=8 82 ps/byte 11 GB/s
* memmove n=15 44 ps/byte 21 GB/s
* memmove n=16 41 ps/byte 23 GB/s
* memmove n=31 32 ps/byte 29 GB/s
* memmove n=32 31 ps/byte 30 GB/s
* memmove n=63 21 ps/byte 45 GB/s
* memmove n=64 15 ps/byte 61 GB/s
* memmove n=127 13 ps/byte 73 GB/s
* memmove n=128 31 ps/byte 30 GB/s
* memmove n=255 20 ps/byte 45 GB/s
* memmove n=256 19 ps/byte 49 GB/s
* memmove n=511 16 ps/byte 56 GB/s
* memmove n=512 17 ps/byte 54 GB/s
* memmove n=1023 18 ps/byte 52 GB/s
* memmove n=1024 13 ps/byte 72 GB/s
* memmove n=2047 9 ps/byte 96 GB/s
* memmove n=2048 9 ps/byte 98 GB/s
* memmove n=4095 8 ps/byte 112 GB/s
* memmove n=4096 8 ps/byte 109 GB/s
* memmove n=8191 7 ps/byte 124 GB/s
* memmove n=8192 7 ps/byte 125 GB/s
* memmove n=16383 7 ps/byte 134 GB/s
* memmove n=16384 7 ps/byte 134 GB/s
* memmove n=32767 13 ps/byte 72 GB/s
* memmove n=32768 13 ps/byte 72 GB/s
* memmove n=65535 13 ps/byte 68 GB/s
* memmove n=65536 14 ps/byte 67 GB/s
* memmove n=131071 14 ps/byte 65 GB/s
* memmove n=131072 14 ps/byte 64 GB/s
* memmove n=262143 15 ps/byte 63 GB/s
* memmove n=262144 15 ps/byte 63 GB/s
* memmove n=524287 15 ps/byte 61 GB/s
* memmove n=524288 15 ps/byte 61 GB/s
* memmove n=1048575 15 ps/byte 61 GB/s
* memmove n=1048576 15 ps/byte 61 GB/s
* memmove n=2097151 19 ps/byte 48 GB/s
* memmove n=2097152 27 ps/byte 35 GB/s
* memmove n=4194303 28 ps/byte 33 GB/s
* memmove n=4194304 28 ps/byte 33 GB/s
* memmove n=8388607 28 ps/byte 33 GB/s
* memmove n=8388608 28 ps/byte 33 GB/s
*
* DST and SRC may overlap.
*
* @param dst is destination
* @param src is memory to copy
* @param n is number of bytes to copy
* @return dst
* @asyncsignalsafe
*/
void *memmove(void *dst, const void *src, size_t n) {
size_t i;
char *d, *r;
const char *s;
uint64_t a, b;
xmm_t v, w, x, y, V, W, X, Y, wut;
d = dst;
s = src;
if (IsTiny()) {
if (d <= s) {
asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
: "m"(*(char(*)[n])src));
} else {
d += n - 1;
s += n - 1;
asm("std\n\t"
"rep movsb\n\t"
"cld"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
: "m"(*(char(*)[n])src));
}
return dst;
}
switch (n) {
case 0:
return d;
case 1:
*d = *s;
return d;
case 2:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(d, &a, 2);
return d;
case 3:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(&b, s + 1, 2);
__builtin_memcpy(d, &a, 2);
__builtin_memcpy(d + 1, &b, 2);
return d;
case 4:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(d, &a, 4);
return d;
case 5 ... 7:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(&b, s + n - 4, 4);
__builtin_memcpy(d, &a, 4);
__builtin_memcpy(d + n - 4, &b, 4);
return d;
case 8:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(d, &a, 8);
return d;
case 9 ... 15:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(&b, s + n - 8, 8);
__builtin_memcpy(d, &a, 8);
__builtin_memcpy(d + n - 8, &b, 8);
return d;
case 16:
*(xmm_t *)d = *(xmm_t *)s;
return d;
case 17 ... 32:
v = *(xmm_t *)s;
w = *(xmm_t *)(s + n - 16);
*(xmm_t *)d = v;
*(xmm_t *)(d + n - 16) = w;
return d;
case 33 ... 64:
v = *(xmm_t *)s;
w = *(xmm_t *)(s + 16);
x = *(xmm_t *)(s + n - 32);
y = *(xmm_t *)(s + n - 16);
*(xmm_t *)d = v;
*(xmm_t *)(d + 16) = w;
*(xmm_t *)(d + n - 32) = x;
*(xmm_t *)(d + n - 16) = y;
return d;
case 65 ... 127:
v = *(xmm_t *)s;
w = *(xmm_t *)(s + 16);
x = *(xmm_t *)(s + 32);
y = *(xmm_t *)(s + 48);
V = *(xmm_t *)(s + n - 64);
W = *(xmm_t *)(s + n - 48);
X = *(xmm_t *)(s + n - 32);
Y = *(xmm_t *)(s + n - 16);
*(xmm_t *)d = v;
*(xmm_t *)(d + 16) = w;
*(xmm_t *)(d + 32) = x;
*(xmm_t *)(d + 48) = y;
*(xmm_t *)(d + n - 64) = V;
*(xmm_t *)(d + n - 48) = W;
*(xmm_t *)(d + n - 32) = X;
*(xmm_t *)(d + n - 16) = Y;
return d;
default:
r = d;
if (d == s) return d;
if (n < kHalfCache3 || !kHalfCache3) {
if (d > s) {
if (IsAsan() || n < 1024 || !X86_HAVE(ERMS)) {
do {
n -= 32;
v = *(const xmm_t *)(s + n);
w = *(const xmm_t *)(s + n + 16);
*(xmm_t *)(d + n) = v;
*(xmm_t *)(d + n + 16) = w;
} while (n >= 32);
} else {
asm("std\n\t"
"rep movsb\n\t"
"cld"
: "=D"(d), "=S"(s), "+c"(n), "=m"(*(char(*)[n])d)
: "0"(d + n - 1), "1"(s + n - 1), "m"(*(char(*)[n])s));
return r;
}
} else {
if (IsAsan() || n < 1024 || !X86_HAVE(ERMS)) {
i = 0;
do {
v = *(const xmm_t *)(s + i);
w = *(const xmm_t *)(s + i + 16);
*(xmm_t *)(d + i) = v;
*(xmm_t *)(d + i + 16) = w;
} while ((i += 32) + 32 <= n);
d += i;
s += i;
n -= i;
} else {
asm("rep movsb"
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
: "m"(*(char(*)[n])s));
return r;
}
}
} else {
if (d > s) {
while ((uintptr_t)(d + n) & 15) {
--n;
d[n] = s[n];
}
do {
n -= 32;
v = *(const xmm_t *)(s + n);
w = *(const xmm_t *)(s + n + 16);
__builtin_ia32_movntdq((xmm_a *)(d + n), v);
__builtin_ia32_movntdq((xmm_a *)(d + n + 16), w);
} while (n >= 32);
} else {
i = 0;
while ((uintptr_t)(d + i) & 15) {
d[i] = s[i];
++i;
}
do {
v = *(const xmm_t *)(s + i);
w = *(const xmm_t *)(s + i + 16);
__builtin_ia32_movntdq((xmm_a *)(d + i), v);
__builtin_ia32_movntdq((xmm_a *)(d + i + 16), w);
} while ((i += 32) + 32 <= n);
d += i;
s += i;
n -= i;
}
asm("sfence");
}
switch (n) {
case 0:
return r;
case 17 ... 31:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(&w, s + n - 16, 16);
__builtin_memcpy(d, &v, 16);
__builtin_memcpy(d + n - 16, &w, 16);
return r;
case 9 ... 15:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(&b, s + n - 8, 8);
__builtin_memcpy(d, &a, 8);
__builtin_memcpy(d + n - 8, &b, 8);
return r;
case 5 ... 7:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(&b, s + n - 4, 4);
__builtin_memcpy(d, &a, 4);
__builtin_memcpy(d + n - 4, &b, 4);
return r;
case 16:
__builtin_memcpy(&v, s, 16);
__builtin_memcpy(d, &v, 16);
return r;
case 8:
__builtin_memcpy(&a, s, 8);
__builtin_memcpy(d, &a, 8);
return r;
case 4:
__builtin_memcpy(&a, s, 4);
__builtin_memcpy(d, &a, 4);
return r;
case 1:
*d = *s;
return r;
case 2:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(d, &a, 2);
return r;
case 3:
__builtin_memcpy(&a, s, 2);
__builtin_memcpy(&b, s + 1, 2);
__builtin_memcpy(d, &a, 2);
__builtin_memcpy(d + 1, &b, 2);
return r;
default:
unreachable;
}
}
}

View file

@ -18,7 +18,7 @@
*/
#include "libc/str/str.h"
void *mempcpy_pure(void *dst, const void *src, size_t n) {
memmove_pure(dst, src, n);
void *mempcpy(void *dst, const void *src, size_t n) {
memmove(dst, src, n);
return (char *)dst + n;
}

164
libc/intrin/memset.c Normal file
View file

@ -0,0 +1,164 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
return p;
}
microarchitecture("avx") static void *memset_avx(char *p, char c, size_t n) {
char *t;
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
if (n <= 32) {
*(xmm_t *)(p + n - 16) = v;
*(xmm_t *)p = v;
} else if (!IsAsan() && n >= 1024 && X86_HAVE(ERMS)) {
asm("rep stosb" : "=D"(t), "+c"(n), "=m"(*(char(*)[n])p) : "0"(p), "a"(c));
} else {
if (n < kHalfCache3 || !kHalfCache3) {
do {
n -= 32;
*(xmm_t *)(p + n) = v;
*(xmm_t *)(p + n + 16) = v;
} while (n > 32);
} else {
while ((uintptr_t)(p + n) & 15) {
p[--n] = c;
}
do {
n -= 32;
__builtin_ia32_movntdq((xmm_a *)(p + n), (xmm_a)v);
__builtin_ia32_movntdq((xmm_a *)(p + n + 16), (xmm_a)v);
} while (n > 32);
asm("sfence");
}
*(xmm_t *)(p + 16) = v;
*(xmm_t *)p = v;
}
return p;
}
/**
* Sets memory.
*
* memset n=0 992 picoseconds
* memset n=1 992 ps/byte 984 mb/s
* memset n=2 330 ps/byte 2,952 mb/s
* memset n=3 330 ps/byte 2,952 mb/s
* memset n=4 165 ps/byte 5,904 mb/s
* memset n=7 94 ps/byte 10,333 mb/s
* memset n=8 124 ps/byte 7,872 mb/s
* memset n=15 66 ps/byte 14,761 mb/s
* memset n=16 62 ps/byte 15,745 mb/s
* memset n=31 32 ps/byte 30,506 mb/s
* memset n=32 20 ps/byte 47,236 mb/s
* memset n=63 26 ps/byte 37,198 mb/s
* memset n=64 20 ps/byte 47,236 mb/s
* memset n=127 23 ps/byte 41,660 mb/s
* memset n=128 12 ps/byte 75,578 mb/s
* memset n=255 18 ps/byte 53,773 mb/s
* memset n=256 12 ps/byte 75,578 mb/s
* memset n=511 17 ps/byte 55,874 mb/s
* memset n=512 12 ps/byte 75,578 mb/s
* memset n=1023 16 ps/byte 58,080 mb/s
* memset n=1024 11 ps/byte 86,375 mb/s
* memset n=2047 9 ps/byte 101 gb/s
* memset n=2048 8 ps/byte 107 gb/s
* memset n=4095 8 ps/byte 113 gb/s
* memset n=4096 8 ps/byte 114 gb/s
* memset n=8191 7 ps/byte 126 gb/s
* memset n=8192 7 ps/byte 126 gb/s
* memset n=16383 7 ps/byte 133 gb/s
* memset n=16384 7 ps/byte 131 gb/s
* memset n=32767 14 ps/byte 69,246 mb/s
* memset n=32768 6 ps/byte 138 gb/s
* memset n=65535 15 ps/byte 62,756 mb/s
* memset n=65536 15 ps/byte 62,982 mb/s
* memset n=131071 18 ps/byte 52,834 mb/s
* memset n=131072 15 ps/byte 62,023 mb/s
* memset n=262143 15 ps/byte 61,169 mb/s
* memset n=262144 16 ps/byte 61,011 mb/s
* memset n=524287 16 ps/byte 60,633 mb/s
* memset n=524288 16 ps/byte 57,902 mb/s
* memset n=1048575 16 ps/byte 60,405 mb/s
* memset n=1048576 16 ps/byte 58,754 mb/s
* memset n=2097151 16 ps/byte 59,329 mb/s
* memset n=2097152 16 ps/byte 58,729 mb/s
* memset n=4194303 16 ps/byte 59,329 mb/s
* memset n=4194304 16 ps/byte 59,262 mb/s
* memset n=8388607 16 ps/byte 59,530 mb/s
* memset n=8388608 16 ps/byte 60,205 mb/s
*
* @param p is memory address
* @param c is masked with 255 and used as repeated byte
* @param n is byte length
* @return p
* @asyncsignalsafe
*/
void *memset(void *p, int c, size_t n) {
char *b;
uint32_t u;
uint64_t x;
b = p;
if (IsTiny()) {
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
return p;
}
if (n <= 16) {
if (n >= 8) {
x = 0x0101010101010101ul * (c & 255);
__builtin_memcpy(b, &x, 8);
__builtin_memcpy(b + n - 8, &x, 8);
} else if (n >= 4) {
u = 0x01010101u * (c & 255);
__builtin_memcpy(b, &u, 4);
__builtin_memcpy(b + n - 4, &u, 4);
} else if (n) {
do {
asm volatile("" ::: "memory");
b[--n] = c;
} while (n);
}
return b;
} else if (X86_HAVE(AVX)) {
return memset_avx(b, c, n);
} else {
return memset_sse(b, c, n);
}
}

185
libc/intrin/printf.c Normal file
View file

@ -0,0 +1,185 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/tpenc.h"
#include "libc/sysv/consts/nr.h"
/**
* Low-level printf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noinstrument void __printf(const char *fmt, ...) {
long d, ax;
va_list va;
uint16_t dx;
const char *s;
uint32_t wrote;
unsigned long x;
unsigned char al;
const char16_t *S;
int n, t, w, plus;
char c, f, *p, *e, b[2048];
w = 0;
p = b;
e = p + sizeof(b);
va_start(va, fmt);
do {
switch ((c = *fmt++)) {
default:
if (p < e) {
*p++ = c;
}
break;
case '\0':
break;
case '%':
w = 0;
f = ' ';
plus = 0;
NeedMoar:
switch ((c = *fmt++)) {
case '\0':
break;
case '0':
f = c;
goto NeedMoar;
case '+':
plus = c;
goto NeedMoar;
case '*':
w = va_arg(va, int);
goto NeedMoar;
case 'd':
d = va_arg(va, long);
ApiAbuse:
if (p + 22 <= e) {
if (d || !plus) {
if (d > 0 && plus) {
*p++ = plus;
}
p = __intcpy(p, d);
}
}
break;
case 'p':
w = 12;
f = '0';
/* fallthrough */
case 'x':
x = va_arg(va, unsigned long);
if (x) {
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1);
n >>= 2;
n += 1;
} else {
n = 1;
}
while (w-- > n) {
if (p < e) {
*p++ = f;
}
}
while (n--) {
if (p < e) {
*p++ = "0123456789abcdef"[(x >> (n << 2)) & 15];
}
}
break;
case 's':
s = va_arg(va, const char *);
if (!s) {
EmitNullString:
s = "NULL";
}
if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s;
goto ApiAbuse;
}
for (n = 0; s[n];) ++n;
while (w-- > n) {
if (p < e) {
*p++ = f;
}
}
while ((t = *s++)) {
if (p < e) {
*p++ = t;
}
}
break;
case 'S':
S = va_arg(va, const char16_t *);
if (!S) goto EmitNullString;
while ((t = *S++)) {
if (p + 3 <= e && (t & 0xfc00) != 0xdc00) {
if (t <= 0x7ff) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
} else {
if (t > 0xffff) t = 0xfffd;
p[0] = 0340 | t >> 12;
p[1] = 0200 | x << 8 | (t >> 6) & 077;
p[2] = 0200 | x << 8 | t & 077;
p += 3;
}
}
}
break;
default:
break;
}
break;
}
} while (c);
va_end(va);
if (p == e) {
e[-4] = '.';
e[-3] = '.';
e[-2] = '.';
e[-1] = '\n';
}
if (IsWindows()) {
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &wrote, 0);
} else if (IsMetal()) {
for (e = p, p = b; p < e; ++p) {
for (;;) {
dx = 0x3F8 + UART_LSR;
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
if (al & UART_TTYTXR) break;
asm("pause");
}
dx = 0x3F8;
asm volatile("outb\t%0,%1"
: /* no inputs */
: "a"(*p), "dN"(dx));
}
} else {
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b)
: "rcx", "r11", "memory");
}
}

43
libc/intrin/strlen.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
/**
* Returns length of NUL-terminated string.
*
* @param s is non-null NUL-terminated string pointer
* @return number of bytes (excluding NUL)
* @asyncsignalsafe
*/
noasan size_t strlen(const char *s) {
size_t n;
xmm_t v, z = {0};
unsigned m, k = (uintptr_t)s & 15;
const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16);
if (IsAsan()) __asan_verify(s, 1);
m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*p, z)) >> k << k;
while (!m) m = __builtin_ia32_pmovmskb128(__builtin_ia32_pcmpeqb128(*++p, z));
n = (const char *)p + __builtin_ctzl(m) - s;
if (IsAsan()) __asan_verify(s, n);
return n;
}

View file

@ -1,7 +1,7 @@
/*-*- 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
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -18,10 +18,7 @@
*/
#include "libc/macros.internal.h"
// Returns arc sine of 𝑥.
//
// @param 𝑥 is double scalar in low half of %xmm0
// @return double scalar in low half of %xmm0
asin: ezlea asinl,ax
jmp _d2ld2
.endfn asin,globl
__syscall__:
syscall
ret
.endfn __syscall__,globl,hidden

View file

@ -18,6 +18,6 @@
*/
#include "libc/log/log.h"
const char *GetAddr2linePath(void) {
noasan const char *GetAddr2linePath(void) {
return commandvenv("ADDR2LINE", "addr2line");
}

View file

@ -17,65 +17,107 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/rusage.h"
#include "libc/fmt/itoa.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/runtime/clktck.h"
#include "libc/stdio/append.internal.h"
static void AppendInt(char **b, int64_t x) {
char buf[27], *e;
e = FormatInt64Thousands(buf, x);
appendd(b, buf, e - buf);
}
static void AppendMetric(char **b, const char *s1, int64_t x, const char *s2,
const char *nl) {
appends(b, s1);
AppendInt(b, x);
appends(b, s2);
appends(b, nl);
}
static void AppendUnit(char **b, int64_t x, const char *s) {
AppendInt(b, x);
appendw(b, ' ');
appends(b, s);
if (x == 1) {
appendw(b, 's');
}
}
/**
* Generates process resource usage report.
*/
void AppendResourceReport(char **b, struct rusage *ru, const char *nl) {
char ibuf[27];
long utime, stime;
long double ticks;
if (ru->ru_maxrss) {
(appendf)(b, "ballooned to %,ldkb in size%s", ru->ru_maxrss, nl);
AppendMetric(b, "ballooned to ", ru->ru_maxrss, "kb in size", nl);
}
if ((utime = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec) |
(stime = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec)) {
appends(b, "needed ");
AppendInt(b, utime + stime);
appends(b, "us cpu (");
AppendInt(b, (long double)stime / (utime + stime) * 100);
appends(b, "% kernel)");
appends(b, nl);
ticks = ceill((long double)(utime + stime) / (1000000.L / CLK_TCK));
(appendf)(b, "needed %,ldµs cpu (%d%% kernel)%s", utime + stime,
(int)((long double)stime / (utime + stime) * 100), nl);
if (ru->ru_idrss) {
(appendf)(b, "needed %,ldkb memory on average%s",
lroundl(ru->ru_idrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_idrss / ticks),
" memory on average", nl);
}
if (ru->ru_isrss) {
(appendf)(b, "needed %,ldkb stack on average%s",
lroundl(ru->ru_isrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_isrss / ticks),
" stack on average", nl);
}
if (ru->ru_ixrss) {
(appendf)(b, "mapped %,ldkb shared on average%s",
lroundl(ru->ru_ixrss / ticks), nl);
AppendMetric(b, "needed ", lroundl(ru->ru_ixrss / ticks),
" shared on average", nl);
}
}
if (ru->ru_minflt || ru->ru_majflt) {
(appendf)(b, "caused %,ld page faults (%d%% memcpy)%s",
ru->ru_minflt + ru->ru_majflt,
(int)((long double)ru->ru_minflt /
(ru->ru_minflt + ru->ru_majflt) * 100),
nl);
appends(b, "caused ");
AppendInt(b, ru->ru_minflt + ru->ru_majflt);
appends(b, " page faults (");
AppendInt(
b, (long double)ru->ru_minflt / (ru->ru_minflt + ru->ru_majflt) * 100);
appends(b, "% memcpy)");
appends(b, nl);
}
if (ru->ru_nvcsw + ru->ru_nivcsw > 1) {
(appendf)(
b, "%,ld context switches (%d%% consensual)%s",
ru->ru_nvcsw + ru->ru_nivcsw,
(int)((long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100),
nl);
AppendInt(b, ru->ru_nvcsw + ru->ru_nivcsw);
appends(b, " context switch (");
AppendInt(b,
(long double)ru->ru_nvcsw / (ru->ru_nvcsw + ru->ru_nivcsw) * 100);
appends(b, "% consensual)");
appends(b, nl);
}
if (ru->ru_msgrcv || ru->ru_msgsnd) {
(appendf)(b, "received %,ld message%s and sent %,ld%s", ru->ru_msgrcv,
ru->ru_msgrcv == 1 ? "" : "s", ru->ru_msgsnd, nl);
appends(b, "received ");
AppendUnit(b, ru->ru_msgrcv, "message");
appends(b, " and sent ");
AppendInt(b, ru->ru_msgsnd);
appends(b, nl);
}
if (ru->ru_inblock || ru->ru_oublock) {
(appendf)(b, "performed %,ld read%s and %,ld write i/o operations%s",
ru->ru_inblock, ru->ru_inblock == 1 ? "" : "s", ru->ru_oublock,
nl);
appends(b, "performed ");
AppendUnit(b, ru->ru_inblock, "read");
appends(b, " and ");
AppendInt(b, ru->ru_oublock);
appends(b, " write i/o operations");
appends(b, nl);
}
if (ru->ru_nsignals) {
(appendf)(b, "received %,ld signals%s", ru->ru_nsignals, nl);
appends(b, "received ");
AppendUnit(b, ru->ru_nsignals, "signal");
appends(b, nl);
}
if (ru->ru_nswap) {
(appendf)(b, "got swapped %,ld times%s", ru->ru_nswap, nl);
appends(b, "got swapped ");
AppendUnit(b, ru->ru_nswap, "time");
appends(b, nl);
}
}

View file

@ -28,10 +28,12 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.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/fileno.h"
#include "libc/sysv/consts/o.h"
@ -40,7 +42,8 @@
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
static noasan int PrintBacktraceUsingAddr2line(int fd,
const struct StackFrame *bp) {
ssize_t got;
intptr_t addr;
size_t i, j, gi;
@ -52,9 +55,8 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1;
if (IsWindows()) return -1;
if (!(debugbin = FindDebugBinary()) || !(addr2line = GetAddr2linePath())) {
return -1;
}
if (!(debugbin = FindDebugBinary())) return -1;
if (!(addr2line = GetAddr2linePath())) return -1;
i = 0;
j = 0;
argv[i++] = "addr2line";
@ -132,11 +134,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
strlen(" (discriminator ") - 1)) &&
(p3 = memchr(p2, '\n', got - (p2 - p1)))) {
if (p3 > p2 && p3[-1] == '\r') --p3;
write(fd, p1, p2 - p1);
__write(p1, p2 - p1);
got -= p3 - p1;
p1 += p3 - p1;
} else {
write(fd, p1, got);
__write(p1, got);
break;
}
}
@ -154,7 +156,7 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
}
}
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
if (!IsTiny()) {
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
return 0;
@ -163,7 +165,7 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) {
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
}
void ShowBacktrace(int fd, const struct StackFrame *bp) {
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
static bool noreentry;
++ftrace;
if (!bp) bp = __builtin_frame_address(0);

View file

@ -23,6 +23,7 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/stackframe.h"
@ -40,52 +41,42 @@
* @param st is open symbol table for current executable
* @return -1 w/ errno if error happened
*/
int PrintBacktraceUsingSymbols(int fd, const struct StackFrame *bp,
struct SymbolTable *st) {
int rc;
char *p;
noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
const struct StackFrame *bp,
struct SymbolTable *st) {
size_t gi;
intptr_t addr;
int64_t addend;
int symbol, addend;
struct Garbages *garbage;
char buf[256], ibuf[21];
const struct Symbol *symbol;
const struct StackFrame *frame;
++ftrace;
if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (rc = 0, frame = bp; frame; frame = frame->next) {
for (frame = bp; frame; frame = frame->next) {
addr = frame->addr;
if (addr == weakaddr("__gc")) {
do {
--gi;
} while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
}
p = buf;
p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)frame, ibuf, 48));
*p++ = ' ';
p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48));
*p++ = ' ';
if (st && st->count &&
((intptr_t)addr >= (intptr_t)&_base &&
(intptr_t)addr <= (intptr_t)&_end)) {
symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols,
st->count, addr - st->addr_base - 1)];
p = stpcpy(p, &st->name_base[symbol->name_rva]);
addend = addr - st->addr_base - symbol->addr_rva;
*p++ = addend >= 0 ? '+' : '-';
if (addend) *p++ = '0', *p++ = 'x';
p = mempcpy(p, ibuf, uint64toarray_radix16(ABS(addend), ibuf));
/*
* we subtract one to handle the case of noreturn functions with a
* call instruction at the end, since %rip in such cases will point
* to the start of the next function. generally %rip always points
* to the byte after the instruction. one exception is in case like
* __restore_rt where the kernel creates a stack frame that points
* to the beginning of the function.
*/
if ((symbol = GetSymbol(st, addr - 1)) != -1 ||
(symbol = GetSymbol(st, addr - 0)) != -1) {
addend = addr - st->addr_base;
addend -= st->symbols[symbol].x;
} else {
p = stpcpy(p, "UNKNOWN");
}
*p++ = '\n';
if (write(fd, buf, p - buf) == -1) {
rc = -1;
break;
addend = 0;
}
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend);
}
--ftrace;
return rc;
return 0;
}

View file

@ -48,6 +48,7 @@
bool cancolor(void) {
static bool once;
static bool result;
return 1;
if (!once) {
result = (!IsWindows() || NtGetVersion() >= kNtVersionWindows10 ||
!ischardev(1)) &&

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