Validate privileged code relationships

- Work towards improving non-optimized build support
- Introduce MODE=zero which is -O0 without ASAN/UBSAN
- Use system GCC when ~/.cosmo.mk has USE_SYSTEM_TOOLCHAIN=1
- Have package.com check .privileged code doesn't call non-privileged
This commit is contained in:
Justine Tunney 2023-06-08 04:37:05 -07:00
parent 01fd655097
commit daf4454a06
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
82 changed files with 808 additions and 850 deletions

View file

@ -86,7 +86,10 @@ o/$(MODE): \
o/$(MODE)/examples \
o/$(MODE)/third_party
ifneq ($(USE_SYSTEM_TOOLCHAIN),)
.STRICT = 1
endif
.PLEDGE = stdio rpath wpath cpath fattr proc
.UNVEIL = \
libc/integral \

View file

@ -263,6 +263,7 @@ SECTIONS {
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }
/DISCARD/ : {
*(__patchable_function_entries)
*(.GCC.command.line)
*(.note.GNU-stack)
*(.gnu_debuglink)

View file

@ -498,6 +498,7 @@ SECTIONS {
.GCC.command.line 0 : { *(.GCC.command.line) }
/DISCARD/ : {
*(__patchable_function_entries)
*(__mcount_loc)
*(.discard)
*(.yoink)

View file

@ -191,13 +191,13 @@ o/$(MODE)/ape/ape.elf.dbg: \
o/$(MODE)/ape/loader.o \
o/$(MODE)/ape/loader-elf.o \
ape/loader.lds
@$(ELFLINK) -z max-page-size=0x10
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10
o/$(MODE)/ape/ape.macho.dbg: \
o/$(MODE)/ape/loader-xnu.o \
o/$(MODE)/ape/loader-macho.o \
ape/loader-macho.lds
@$(ELFLINK) -z max-page-size=0x10
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: $(APE_CHECKS) \

Binary file not shown.

Binary file not shown.

View file

@ -17,13 +17,31 @@ CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG
TARGET_ARCH ?= -msse3
endif
ifeq ($(MODE), aarch64)
ENABLE_FTRACE = 1
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
# Zero Optimization Mode
#
# - Goes 2x slower
# - Supports --strace
# - Unsupports --ftrace
# - Better GDB debugging
#
ifeq ($(MODE), zero)
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
OVERRIDE_CCFLAGS = -fno-omit-frame-pointer
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64-zero)
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
# Fast Build Mode
#
# - `make MODE=fastbuild`
@ -74,7 +92,7 @@ endif
ifeq ($(MODE), optlinux)
CONFIG_CPPFLAGS += -DNDEBUG -msse2avx -Wa,-msse2avx -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
DEFAULT_COPTS += -mred-zone
CONFIG_COPTS += -mred-zone
TARGET_ARCH ?= -march=native
endif
@ -121,24 +139,23 @@ endif
# - `make MODE=dbg`
# - Backtraces
# - Enables asan
# - Enables ubsan (TODO)
# - Enables ubsan
# - Stack canaries
# - No optimization (TODO)
# - No optimization
# - Enormous binaries
#
ifeq ($(MODE), dbg)
ENABLE_FTRACE = 1
CONFIG_CPPFLAGS += -DMODE_DBG
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O -fno-inline
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=address -fsanitize=undefined
TARGET_ARCH ?= -msse3
OVERRIDE_CCFLAGS += -fno-pie
endif
ifeq ($(MODE), aarch64-dbg)
ENABLE_FTRACE = 1
CONFIG_CPPFLAGS += -DMODE_DBG
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O -fno-inline
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O0 -fno-inline
CONFIG_COPTS += -fsanitize=undefined
endif
@ -197,7 +214,6 @@ PYFLAGS += \
-O2 \
-B
endif
ifeq ($(MODE), aarch64-tiny)
# TODO(jart): -mcmodel=tiny
CONFIG_CPPFLAGS += \
@ -244,8 +260,6 @@ CONFIG_CPPFLAGS += \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
@ -281,8 +295,6 @@ CONFIG_CPPFLAGS += \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=113 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_OFLAGS += \
-g0
CONFIG_LDFLAGS += \
@ -317,8 +329,6 @@ CONFIG_CPPFLAGS += \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=121 \
-DDWARFLESS
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \

View file

@ -33,14 +33,25 @@
#
# VARIABLES
#
# CCFLAGS gcc frontend flags (.i, .c, .cc, .f, .S, .lds, etc.)
# Our configuration variables, ordered by increasing preference:
#
# CCFLAGS frontend flags (.i, .c, .cc, .f, .S, .lds, etc.)
# OFLAGS objectify flags (precludes -S and -E)
# CPPFLAGS preprocessor flags (.h, .c, .cc, .S, .inc, .lds, etc.)
# TARGET_ARCH microarchitecture flags (e.g. -march=native)
# COPTS c/c++ flags (.c, .cc)
# CFLAGS c flags (.c only)
# CXXFLAGS c++ flags (.cc only)
# COPTS c/c++ flags (.c, .cc)
# LDFLAGS linker flags (don't use -Wl, frontend prefix)
# ASFLAGS assembler flags (don't use -Wa, frontend prefix)
# TARGET_ARCH microarchitecture flags (e.g. -march=native)
#
# For each FOO above, there exists (by increasing preference)
#
# DEFAULT_FOO see build/definitions.mk
# CONFIG_FOO see build/config.mk
# FOO set ~/.cosmo.mk and target-specific
# OVERRIDE_FOO set ~/.cosmo.mk and target-specific (use rarely)
#
LC_ALL = C
SOURCE_DATE_EPOCH = 0
@ -88,19 +99,19 @@ ARCH = x86_64
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win10
endif
PORTCOSMO_CCFLAGS = -fportcosmo -include build/portcosmo.h
ifeq ($(PREFIX),)
ifeq ($(USE_SYSTEM_TOOLCHAIN),)
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-*)","")
PREFIX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-
DEFAULT_CPPFLAGS += $(PORTCOSMO_CCFLAGS)
else
IGNORE := $(shell build/bootstrap/unbundle.com)
PREFIX = o/third_party/gcc/bin/x86_64-linux-musl-
DEFAULT_CPPFLAGS += $(PORTCOSMO_CCFLAGS)
endif
ifeq ($(ARCH), aarch64)
PREFIX = o/third_party/gcc/bin/aarch64-linux-musl-
endif
endif
endif
AS = $(PREFIX)as
CC = $(PREFIX)gcc
@ -112,7 +123,7 @@ GCC = $(PREFIX)gcc
STRIP = $(PREFIX)strip
OBJCOPY = $(PREFIX)objcopy
OBJDUMP = $(PREFIX)objdump
ADDR2LINE = $(PWD)/$(PREFIX)addr2line
ADDR2LINE = $(join $(PWD),$(PREFIX))addr2line
export ADDR2LINE
export LC_ALL
@ -122,15 +133,11 @@ export SOURCE_DATE_EPOCH
export TMPDIR
ifeq ($(LANDLOCKMAKE_VERSION),)
TMPSAFE = $(TMPDIR)/$(subst /,_,$@).tmp
TMPSAFE = $(join $(TMPDIR),$(subst /,_,$@)).tmp
else
TMPSAFE = $(TMPDIR)/
endif
ifneq ($(ARCH), aarch64)
MNO_FENTRY = -mno-fentry
endif
ifeq ($(ARCH), aarch64)
IMAGE_BASE_VIRTUAL ?= 0x010000000000
else
@ -150,7 +157,6 @@ SANITIZER = \
-fsanitize=address
NO_MAGIC = \
$(MNO_FENTRY) \
-fno-stack-protector \
-fwrapv \
-fno-sanitize=all
@ -170,19 +176,22 @@ DEFAULT_CCFLAGS += \
-fdebug-prefix-map='$(PWD)'= \
-frecord-gcc-switches
DEFAULT_OFLAGS = \
DEFAULT_OFLAGS ?= \
-g \
-gdwarf-4 \
-gdescribe-dies
DEFAULT_COPTS = \
DEFAULT_COPTS ?= \
-fno-math-errno \
-fno-ident \
-fno-common \
-fno-gnu-unique \
-fstrict-aliasing \
-fstrict-overflow \
-fno-semantic-interposition
-fno-semantic-interposition \
-fno-dwarf2-cfi-asm \
-fno-unwind-tables \
-fno-asynchronous-unwind-tables
ifeq ($(ARCH), x86_64)
DEFAULT_COPTS += \
@ -334,19 +343,19 @@ LD.libs = \
$(CONFIG_LIBS) \
$(LIBS)
COMPILE.c.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(cxx.flags)
COMPILE.f.flags = $(cc.flags) $(copt.flags) $(f.flags)
COMPILE.F.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(f.flags)
COMPILE.F.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(f.flags)
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
OBJECTIFY.c.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(cxx.flags)
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
OBJECTIFY.S.flags = $(copt.flags) $(cc.flags) $(o.flags) $(cpp.flags) $(S.flags)
OBJECTIFY.f.flags = $(copt.flags) $(cc.flags) $(o.flags) $(copt.flags) $(S.flags) $(f.flags)
OBJECTIFY.F.flags = $(OBJECTIFY.f.flags) $(cpp.flags)
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
OBJECTIFY.f.flags = $(cc.flags) $(o.flags) $(S.flags) $(f.flags)
OBJECTIFY.F.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(f.flags)
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
PREPROCESS.lds.flags = -D__LINKER__ $(filter-out -g%,$(PREPROCESS.flags)) -P -xc
@ -382,7 +391,6 @@ OBJECTIFY.greg.c = \
-fno-optimize-sibling-calls \
-fno-sanitize=all \
-ffreestanding \
$(MNO_FENTRY) \
-fwrapv \
-c
@ -422,7 +430,6 @@ OBJECTIFY.ncabi.c = \
$(OBJECTIFY.c.flags) \
-mno-sse \
-mfpmath=387 \
$(MNO_FENTRY) \
-fno-stack-protector \
-fno-instrument-functions \
-fno-optimize-sibling-calls \
@ -441,7 +448,6 @@ OBJECTIFY.ncabi.c = \
OBJECTIFY.initabi.c = \
$(GCC) \
$(OBJECTIFY.c.flags) \
$(MNO_FENTRY) \
-fno-stack-protector \
-fno-instrument-functions \
-fno-optimize-sibling-calls \

View file

@ -31,7 +31,7 @@
*/
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
struct termios *opt_out_oldconf) {
struct termios conf[2];
struct termios conf[2] = {0};
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
tcsetattr(ttyfd, TCSAFLUSH, &conf[1]) != -1) {

View file

@ -30,6 +30,7 @@
SUCH DAMAGE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/termios.h"

View file

@ -183,6 +183,18 @@ o/$(MODE)/libc/calls/timeval_frommicros.o: private \
CFLAGS += \
-O2
# privileged functions
o/$(MODE)/libc/calls/sigenter-freebsd.o \
o/$(MODE)/libc/calls/sigenter-netbsd.o \
o/$(MODE)/libc/calls/sigenter-openbsd.o \
o/$(MODE)/libc/calls/sigenter-linux.o \
o/$(MODE)/libc/calls/sigenter-xnu.o \
o/$(MODE)/libc/calls/pledge-linux.o \
o/$(MODE)/libc/calls/siginfo2cosmo.o: private \
CFLAGS += \
-ffreestanding \
-fno-sanitize=all
o/$(MODE)/libc/calls/pledge-linux.o \
o/$(MODE)/libc/calls/unveil.o: private \
CFLAGS += \

View file

@ -48,7 +48,7 @@
* @raise ESRCH if no such process existed
* @see setpriority()
*/
privileged int getpriority(int which, unsigned who) {
int getpriority(int which, unsigned who) {
int rc;
#ifdef __x86_64__
char cf;

View file

@ -21,7 +21,7 @@
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/pr.h"
privileged bool __is_linux_2_6_23(void) {
bool __is_linux_2_6_23(void) {
#ifdef __x86_64__
int rc;
if (!IsLinux()) return false;

View file

@ -34,7 +34,7 @@
* C library runtime won't have any awareness of this memory, so certain
* features like ASAN memory safety and kprintf() won't work as well.
*/
privileged void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
#ifdef __x86_64__
bool cf;
uintptr_t res, rdi, rsi, rdx;

View file

@ -31,7 +31,7 @@
*
* @raise ENOSYS on non-Linux
*/
privileged int prctl(int operation, ...) {
int prctl(int operation, ...) {
int rc;
va_list va;
intptr_t a, b, c, d;

View file

@ -35,7 +35,7 @@
*
* @raise ENOSYS on non-Linux.
*/
privileged int seccomp(unsigned operation, unsigned flags, void *args) {
int seccomp(unsigned operation, unsigned flags, void *args) {
int rc;
if (IsLinux()) {
#ifdef __x86_64__

View file

@ -41,7 +41,7 @@ privileged void __sigenter_wsl(int sig, struct siginfo *info, ucontext_t *ctx) {
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
for (i = 0; i < 8; ++i) {
long double nan = NAN;
memcpy(ctx->__fpustate.st + i, &nan, 16);
__builtin_memcpy(ctx->__fpustate.st + i, &nan, 16);
}
}
((sigaction_f)(__executable_start + rva))(sig, info, ctx);

View file

@ -3,20 +3,18 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
enum FdKind {
kFdEmpty,
kFdFile,
kFdSocket,
kFdProcess,
kFdConsole,
kFdSerial,
kFdZip,
kFdEpoll,
kFdReserved
};
#define kFdEmpty 0
#define kFdFile 1
#define kFdSocket 2
#define kFdProcess 3
#define kFdConsole 4
#define kFdSerial 5
#define kFdZip 6
#define kFdEpoll 7
#define kFdReserved 8
struct Fd {
enum FdKind kind;
int kind;
unsigned flags;
unsigned mode;
int64_t handle;

View file

@ -24,6 +24,7 @@
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
static textwindows int sys_tcdrain_nt(int fd) {

View file

@ -1,9 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_TERMIOS_H_
#define COSMOPOLITAN_LIBC_CALLS_TERMIOS_H_
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h"
#include "libc/sysv/consts/termios.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -38,25 +36,6 @@ uint32_t cfgetispeed(const struct termios *);
int tcsetwinsize(int, const struct winsize *);
int tcgetwinsize(int, struct winsize *);
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § teletypewriter » undiamonding
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define tcsetattr(FD, OPT, TIO) tcsetattr_dispatch(FD, OPT, TIO)
forceinline int tcsetattr_dispatch(int fd, int opt, const struct termios *tio) {
if (__EQUIVALENT(opt, TCSANOW)) return ioctl(fd, TCSETS, (void *)tio);
if (__EQUIVALENT(opt, TCSADRAIN)) return ioctl(fd, TCSETSW, (void *)tio);
if (__EQUIVALENT(opt, TCSAFLUSH)) return ioctl(fd, TCSETSF, (void *)tio);
return (tcsetattr)(fd, opt, tio);
}
#define tcgetattr(FD, TIO) tcgetattr_dispatch(FD, TIO)
forceinline int tcgetattr_dispatch(int fd, const struct termios *tio) {
return ioctl(fd, TCGETS, (void *)tio);
}
#endif /* GNUC && !ANSI */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_TERMIOS_H_ */

View file

@ -36,7 +36,7 @@
#ifdef __x86_64__
privileged unsigned __wincrash(struct NtExceptionPointers *ep) {
unsigned __wincrash(struct NtExceptionPointers *ep) {
int64_t rip;
int sig, code;
ucontext_t ctx;

View file

@ -36,12 +36,6 @@
#define IsModeDbg() 0
#endif
#ifdef __MFENTRY__
#define HaveFentry() 1
#else
#define HaveFentry() 0
#endif
#ifdef TRUSTWORTHY
#define IsTrustworthy() 1
#else
@ -72,12 +66,6 @@
#define IsXnuSilicon() 0
#endif
#if defined(__PIE__) || defined(__PIC__)
#define IsPositionIndependent() 1
#else
#define IsPositionIndependent() 0
#endif
#define SupportsLinux() ((SUPPORT_VECTOR & _HOSTLINUX) == _HOSTLINUX)
#define SupportsMetal() ((SUPPORT_VECTOR & _HOSTMETAL) == _HOSTMETAL)
#define SupportsWindows() ((SUPPORT_VECTOR & _HOSTWINDOWS) == _HOSTWINDOWS)

View file

@ -17,15 +17,16 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/elf/elf.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr,
size_t addrsize) {
#if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0
if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) {
/* kprintf("%p-%p falls outside interval %p-%p", // */
/* addr, addr + addrsize, // */
/* elf, (char *)elf + mapsize); // */
kprintf("%p-%p falls outside interval %p-%p", //
addr, addr + addrsize, //
elf, (char *)elf + mapsize); //
abort();
}
#endif

View file

@ -14,14 +14,13 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int snprintf(char *, size_t, const char *, ...) printfesque(3)
paramsnonnull((3)) dontthrow nocallback;
int snprintf(char *, size_t, const char *, ...)
printfesque(3) dontthrow nocallback;
int vsnprintf(char *, size_t, const char *, va_list)
paramsnonnull((3)) dontthrow nocallback;
int sprintf(char *, const char *, ...) printfesque(2)
paramsnonnull((2)) dontthrow nocallback frownedupon(snprintf);
dontthrow nocallback;
int sprintf(char *, const char *, ...) printfesque(2) dontthrow nocallback;
int vsprintf(char *, const char *, va_list)
paramsnonnull((2)) dontthrow nocallback frownedupon(vsnprintf);
dontthrow nocallback;
int sscanf(const char *, const char *, ...) scanfesque(2);
int vsscanf(const char *, const char *, va_list);
int vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,

View file

@ -729,6 +729,7 @@ void abort(void) wontreturn;
#if __GNUC__ >= 11
#pragma GCC diagnostic ignored /* annoying */ "-Wattributes"
#pragma GCC diagnostic ignored /* orwellian */ "-Wold-style-definition"
#pragma GCC diagnostic ignored /* what? */ "-Wformat-overflow"
#endif /* GCC11+ */
#endif /* GCC9+ */
#endif /* !C++ */
@ -834,10 +835,10 @@ void abort(void) wontreturn;
#if !defined(__STRICT_ANSI__) && !defined(__APPLE__) && defined(__x86_64__)
#define YOINK(SYMBOL) \
asm(".section .yoink\n\tnopl\t%a0\n\t.previous" : : "X"(SYMBOL))
asm(".section .yoink\n\tnopl\t%0\n\t.previous" : : "m"(SYMBOL))
#elif defined(__aarch64__)
#define YOINK(SYMBOL) \
asm(".section .yoink\n\tb\t%a0\n\t.previous" : : "X"(SYMBOL))
asm(".section .yoink\n\tb\t%0\n\t.previous" : : "m"(SYMBOL))
#else
#define YOINK(SYMBOL) (void)0
#endif

View file

@ -24,7 +24,7 @@
* @param p needs at least 12 bytes
* @return pointer to nul byte
*/
dontinline char *FormatUint32(char p[hasatleast 12], uint32_t x) {
privileged dontinline char *FormatUint32(char p[hasatleast 12], uint32_t x) {
char t;
size_t i, a, b;
i = 0;
@ -49,7 +49,7 @@ dontinline char *FormatUint32(char p[hasatleast 12], uint32_t x) {
* @param p needs at least 12 bytes
* @return pointer to nul byte
*/
char *FormatInt32(char p[hasatleast 12], int32_t x) {
privileged char *FormatInt32(char p[hasatleast 12], int32_t x) {
if (x < 0) *p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x);
}

View file

@ -18,7 +18,7 @@
*/
#include "libc/fmt/magnumstrs.internal.h"
char *GetMagnumStr(const struct MagnumStr *ms, int x) {
privileged char *GetMagnumStr(const struct MagnumStr *ms, int x) {
int i;
for (i = 0; ms[i].x != MAGNUM_TERMINATOR; ++i) {
if (x == MAGNUM_NUMBER(ms, i)) {

View file

@ -72,6 +72,7 @@ o/$(MODE)/libc/intrin/mman.greg.o: private \
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: private \
CFLAGS += \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
@ -84,7 +85,6 @@ o/$(MODE)/libc/intrin/asan.o: private \
o/$(MODE)/libc/intrin/asanthunk.o: private \
CFLAGS += \
-x-no-pg \
$(MNO_FENTRY) \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
@ -100,7 +100,6 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: private \
-fpie \
-fwrapv \
-x-no-pg \
$(MNO_FENTRY) \
-ffreestanding \
-fno-sanitize=all \
-fno-stack-protector
@ -115,7 +114,6 @@ o/$(MODE)/libc/intrin/_spinlock_debug_4.o: private \
CFLAGS += \
-fwrapv \
-x-no-pg \
$(MNO_FENTRY) \
-ffreestanding \
-fno-sanitize=all \
-mgeneral-regs-only \
@ -187,6 +185,17 @@ o/$(MODE)/libc/intrin/wsawaitformultipleevents.o: private\
-fno-stack-protector \
-fno-sanitize=all
# privileged functions
o/$(MODE)/libc/intrin/dos2errno.o \
o/$(MODE)/libc/intrin/have_fsgsbase.o \
o/$(MODE)/libc/intrin/getmagnumstr.o \
o/$(MODE)/libc/intrin/formatint32.o \
o/$(MODE)/libc/intrin/strsignal_r.o \
o/$(MODE)/libc/intrin/strerror_wr.o: private \
CFLAGS += \
-ffreestanding \
-fno-sanitize=all
o//libc/intrin/memmove.o: private \
CFLAGS += \
-fno-toplevel-reorder

View file

@ -16,7 +16,6 @@
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/nt/version.h"
@ -26,6 +25,5 @@
* This function may only be called if IsWindows() is true.
*/
privileged bool(IsAtLeastWindows10)(void) {
_unassert(IsWindows());
return IsAtLeastWindows10();
}

View file

@ -287,6 +287,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
cols = 0;
zero = 0;
uppr = 0;
ansi = 0;
abet = "0123456789abcdef";
for (;;) {
switch ((c = *f++)) {
@ -392,7 +393,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
*p++ = '3';
*p++ = '0' + x % 8;
*p++ = 'm';
ansi = true;
ansi = 1;
}
} else {
x = 666;
@ -527,10 +528,10 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
unixerr = errno;
winerr = 0;
if (IsWindows()) {
if (type == 1 && _weaken(WSAGetLastError)) {
winerr = _weaken(WSAGetLastError)();
} else if (_weaken(GetLastError)) {
winerr = _weaken(GetLastError)();
if (type == 1 && _weaken(__imp_WSAGetLastError)) {
winerr = (*_weaken(__imp_WSAGetLastError))();
} else if (_weaken(__imp_GetLastError)) {
winerr = (*_weaken(__imp_GetLastError))();
}
}
if (!unixerr && sign == ' ') {
@ -777,7 +778,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
*p++ = '0';
*p++ = 'm';
}
ansi = false;
ansi = 0;
}
break;
}

View file

@ -2,7 +2,7 @@
#define COSMOPOLITAN_LIBC_INTRIN_NOPL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0) && defined(__x86_64__) && \
defined(__GNUC__) && !defined(__llvm__) && !defined(__chibicc__) && \
!defined(__STRICT_ANSI__)
defined(__MNO_RED_ZONE__) && !defined(__STRICT_ANSI__)
/**
* @fileoverview Turns CALLs into NOPs that are fixupable at runtime.
@ -35,34 +35,39 @@
".equ\t\"" SECTION "_end\",.\n\t" \
".previous\n\t"
#define _NOPL0(SECTION, FUNC) \
#define _NOPL0(SECTION, FUNC) __NOPL0(SECTION, FUNC, IMAGE_BASE_VIRTUAL)
#define __NOPL0(SECTION, FUNC, GARDEN) ___NOPL0(SECTION, FUNC, GARDEN)
#define ___NOPL0(SECTION, FUNC, GARDEN) \
({ \
asm volatile(_NOPL_PROLOGUE(SECTION) /* */ \
_NOPL_EPILOGUE(SECTION) /* */ \
".section \".sort.rodata." SECTION ".2\",\"a\",@progbits\n\t" \
".balign\t4\n\t" \
".long\t353f-%a1\n\t" \
".long\t353f-" #GARDEN "\n\t" \
".previous\n353:\t" \
"nopl\t%a0" \
"nopl\t" #FUNC "(%%rip)" \
: /* no inputs */ \
: "X"(FUNC), "X"(IMAGE_BASE_VIRTUAL) \
: /* no outputs */ \
: "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", \
"r11", "memory", "cc"); \
(void)0; \
})
#define _NOPL1(SECTION, FUNC, ARG) \
#define _NOPL1(SECTION, FUNC, ARG) \
__NOPL1(SECTION, FUNC, ARG, IMAGE_BASE_VIRTUAL)
#define __NOPL1(SECTION, FUNC, ARG, GARDEN) ___NOPL1(SECTION, FUNC, ARG, GARDEN)
#define ___NOPL1(SECTION, FUNC, ARG, GARDEN) \
({ \
register autotype(ARG) __arg asm("rdi") = ARG; \
asm volatile(_NOPL_PROLOGUE(SECTION) /* */ \
_NOPL_EPILOGUE(SECTION) /* */ \
".section \".sort.rodata." SECTION ".2\",\"a\",@progbits\n\t" \
".balign\t4\n\t" \
".long\t353f-%a2\n\t" \
".long\t353f-" #GARDEN "\n\t" \
".previous\n353:\t" \
"nopl\t%a1" \
"nopl\t" #FUNC "(%%rip)" \
: "+D"(__arg) \
: "X"(FUNC), "X"(IMAGE_BASE_VIRTUAL) \
: /* no inputs */ \
: "rax", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", \
"memory", "cc"); \
(void)0; \

View file

@ -22,7 +22,7 @@
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
privileged void PrintSystemMappings(int outfd) {
void PrintSystemMappings(int outfd) {
int infd;
ssize_t rc;
char buf[64];

View file

@ -35,7 +35,7 @@ const unsigned char kConsoleHandles[3] = {
};
// Puts cmd.exe gui back the way it was.
noinstrument void _restorewintty(void) {
privileged noinstrument void _restorewintty(void) {
if (!IsWindows()) return;
if (__imp_GetCurrentProcessId() != __pid_exec) return;
for (int i = 0; i < 3; ++i) {

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/enum/formatmessageflags.h"
#include "libc/nt/enum/lang.h"
@ -39,8 +39,14 @@ privileged int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
char16_t winmsg[256];
const char *sym, *msg;
wanting = false;
sym = firstnonnull(_strerrno(err), (wanting = true, "EUNKNOWN"));
msg = firstnonnull(_strerdoc(err), (wanting = true, "No error information"));
if (!(sym = _strerrno(err))) {
sym = "EUNKNOWN";
wanting = true;
}
if (!(msg = _strerdoc(err))) {
msg = "No error information";
wanting = true;
}
if (IsTiny()) {
if (!sym) sym = "EUNKNOWN";
for (; (c = *sym++); --size)
@ -49,7 +55,7 @@ privileged int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
} else if (!IsWindows() || ((err == winerr || !winerr) && !wanting)) {
ksnprintf(buf, size, "%s/%d/%s", sym, err, msg);
} else {
if ((n = FormatMessage(
if ((n = __imp_FormatMessageW(
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0,
winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg,
ARRAYLEN(winmsg), 0))) {

View file

@ -36,7 +36,7 @@
* @asyncsignalsafe
* @threadsafe
*/
char *strsignal_r(int sig, char buf[hasatleast 15]) {
privileged char *strsignal_r(int sig, char buf[hasatleast 15]) {
int i;
char *p;
const char *s;

View file

@ -35,7 +35,6 @@ privileged int64_t __winerr(void) {
errno_t e;
if (IsWindows()) {
e = __dos2errno(__imp_GetLastError());
_npassert(e > 0);
} else {
e = ENOSYS;
}

View file

@ -28,7 +28,7 @@
/**
* Attaches GDB temporarily, to do something like print a variable.
*/
privileged int(gdbexec)(const char *cmd) {
relegated int(gdbexec)(const char *cmd) {
struct StackFrame *bp;
int pid, ttyin, ttyout;
intptr_t continuetoaddr;

View file

@ -19,6 +19,6 @@
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
privileged wontreturn void _log_exit(int exitcode) {
wontreturn void _log_exit(int exitcode) {
_Exitr(exitcode);
}

View file

@ -1,30 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
.real
.code16 # .code32 .code64
// Function entry hook stub.
//
// @note cc -pg -mfentry adds this to the start of every function
// @see libc/log/shadowargs.ncabi.c
// @mode long,legacy,real
__fentry__:
ret
.endfn __fentry__,weak

View file

@ -1,77 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// @fileoverview Byte-order conversion functions.
//
// Endianness is deceptively complicated to the uninitiated. Many
// helpers have been written by our top minds to address perceived
// difficulties. These ones got through standardization processes.
// To protect their legacy, all 19 functions have been implemented
// in just 17 bytes.
//
// @see READ32LE(), READ32BE(), etc.
// @asyncsignalsafe
bswap_64:
htobe64:
htole64:
be64toh:
le64toh:mov %rdi,%rax
bswap %rax
ret
.endfn le64toh,globl
.endfn be64toh,globl
.endfn htole64,globl
.endfn htobe64,globl
.endfn bswap_64,globl
bswap_32:
htobe32:
htole32:
be32toh:
le32toh:
ntohl:
htonl: mov %edi,%eax
bswap %eax
ret
.endfn htonl,globl
.endfn htole32,globl
.endfn le32toh,globl
.endfn be32toh,globl
.endfn htobe32,globl
.endfn ntohl,globl
.endfn bswap_32,globl
bswap_16:
htobe16:
htole16:
be16toh:
le16toh:
ntohs:
htons: movzwl %di,%eax
xchg %al,%ah
ret
.endfn htobe16,globl
.endfn htons,globl
.endfn le16toh,globl
.endfn be16toh,globl
.endfn htole16,globl
.endfn ntohs,globl
.endfn bswap_16,globl

View file

@ -1,10 +1,10 @@
#define GetEnvironmentVariable(...) __imp_GetEnvironmentVariableW(__VA_ARGS__)
extern typeof(GetEnvironmentVariable) *const
__imp_GetEnvironmentVariableW __msabi;
extern typeof(GetEnvironmentVariable) *const __imp_GetEnvironmentVariableW
__msabi;
#define SetEnvironmentVariable(...) __imp_SetEnvironmentVariableW(__VA_ARGS__)
extern typeof(SetEnvironmentVariable) *const
__imp_SetEnvironmentVariableW __msabi;
extern typeof(SetEnvironmentVariable) *const __imp_SetEnvironmentVariableW
__msabi;
#define GetPriorityClass(...) __imp_GetPriorityClass(__VA_ARGS__)
extern typeof(GetPriorityClass) *const __imp_GetPriorityClass __msabi;
@ -17,3 +17,4 @@ extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId __msabi;
extern typeof(FormatMessage) *const __imp_FormatMessageW __msabi;
extern typeof(SetLastError) *const __imp_SetLastError __msabi;
extern typeof(FormatMessage) *const __imp_FormatMessage __msabi;

View file

@ -1,13 +1,13 @@
#define FreeEnvironmentStrings(...) __imp_FreeEnvironmentStringsW(__VA_ARGS__)
extern typeof(FreeEnvironmentStrings) *const
__imp_FreeEnvironmentStringsW __msabi;
extern typeof(FreeEnvironmentStrings) *const __imp_FreeEnvironmentStringsW
__msabi;
#define GetCommandLine(...) __imp_GetCommandLineW(__VA_ARGS__)
extern typeof(GetCommandLine) *const __imp_GetCommandLineW __msabi;
#define GetEnvironmentStrings(...) __imp_GetEnvironmentStringsW(__VA_ARGS__)
extern typeof(GetEnvironmentStrings) *const
__imp_GetEnvironmentStringsW __msabi;
extern typeof(GetEnvironmentStrings) *const __imp_GetEnvironmentStringsW
__msabi;
#define GetStdHandle(...) __imp_GetStdHandle(__VA_ARGS__)
extern typeof(GetStdHandle) *const __imp_GetStdHandle __msabi;
@ -23,8 +23,8 @@ extern typeof(WriteFile) *const __imp_WriteFile __msabi;
#define SetDefaultDllDirectories(...) \
__imp_SetDefaultDllDirectories(__VA_ARGS__)
extern typeof(SetDefaultDllDirectories) *const
__imp_SetDefaultDllDirectories __msabi;
extern typeof(SetDefaultDllDirectories) *const __imp_SetDefaultDllDirectories
__msabi;
#define GetCurrentProcess(...) __imp_GetCurrentProcess(__VA_ARGS__)
extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess __msabi;

View file

@ -0,0 +1 @@
extern typeof(WSAGetLastError) *const __imp_WSAGetLastError __msabi;

View file

@ -6,6 +6,7 @@
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/struct/pollfd.h"
#include "libc/nt/struct/timeval.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
/* ░▓█████████████████████████████████████████████▓▒
@ -513,6 +514,9 @@ void GetAcceptExSockaddrs(
bool32 DisconnectEx(int64_t s, struct NtOverlapped *inout_opt_lpOverlapped,
uint32_t dwFlags, uint32_t dwReserved);
#if ShouldUseMsabiAttribute()
#include "libc/nt/thunk/winsock.inc"
#endif /* ShouldUseMsabiAttribute() */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_WINSOCK_H_ */

View file

@ -127,7 +127,7 @@ static int arch_prctl_xnu(int code, int64_t addr) {
}
}
static privileged dontinline int arch_prctl_openbsd(int code, int64_t addr) {
static dontinline int arch_prctl_openbsd(int code, int64_t addr) {
bool failed;
int64_t rax;
switch (code) {

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 2022 Justine Alexandra Roberts Tunney
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
@ -16,12 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/bswap.h"
#include "libc/sock/sock.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
/**
* Converts network to host short.
*/
uint16_t(ntohs)(uint16_t x) {
return bswap_16(x);
void ftrace_hook(void);
_Hide int ftrace_stackdigs;
textstartup int ftrace_install(void) {
if (GetSymbolTable()) {
ftrace_stackdigs = LengthInt64Thousands(GetStackSize());
return __hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\n");
return -1;
}
}

View file

@ -27,7 +27,6 @@
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
@ -47,9 +46,7 @@
#define DETOUR_SKEW 8
#endif
void ftrace_hook(void);
static int g_stackdigs;
extern _Hide int ftrace_stackdigs;
static struct CosmoFtrace g_ftrace;
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
@ -73,9 +70,11 @@ static privileged inline int GetNestingLevel(struct CosmoFtrace *ft,
/**
* Prints name of function being called.
*
* We insert CALL instructions that point to this function, in the
* prologues of other functions. We assume those functions behave
* according to the System Five NexGen32e ABI.
* Whenever a function is called, ftrace_hook() will be called from the
* function prologue which saves the parameter registers and calls this
* function, which is responsible for logging the function call.
*
* @see ftrace_install()
*/
privileged void ftracer(void) {
uintptr_t fn;
@ -101,20 +100,10 @@ privileged void ftracer(void) {
fn = sf->addr + DETOUR_SKEW;
if (fn != ft->ft_lastaddr) {
stackuse = GetStackAddr() + GetStackSize() - (intptr_t)sf;
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_stackdigs, stackuse,
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", ftrace_stackdigs, stackuse,
GetNestingLevel(ft, sf) * 2, "", fn);
ft->ft_lastaddr = fn;
}
ft->ft_noreentry = false;
}
}
textstartup int ftrace_install(void) {
if (GetSymbolTable()) {
g_stackdigs = LengthInt64Thousands(GetStackSize());
return __hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\n");
return -1;
}
}

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 2022 Justine Alexandra Roberts Tunney
Copyright 2023 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,12 +16,41 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/bswap.h"
#include "libc/sock/sock.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
extern _Hide struct SymbolTable *__symtab;
/**
* Converts network to host long.
* Returns low index into symbol table for address.
*
* @param t if null will be auto-populated only if already open
* @return index or -1 if nothing found
*/
uint32_t(ntohl)(uint32_t x) {
return bswap_32(x);
noinstrument privileged int __get_symbol(struct SymbolTable *t, intptr_t a) {
// we need privileged because:
// kprintf is privileged and it depends on this
// we don't want function tracing because:
// function tracing depends on this function via kprintf
unsigned l, m, r, n, k;
if (!t && __symtab) {
t = __symtab;
}
if (t) {
l = 0;
r = n = t->count;
k = a - t->addr_base;
while (l < r) {
m = (l + r) >> 1;
if (t->symbols[m].y < k) {
l = m + 1;
} else {
r = m;
}
}
if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) {
return l;
}
}
return -1;
}

View file

@ -142,37 +142,3 @@ struct SymbolTable *GetSymbolTable(void) {
pthread_spin_unlock(&g_lock);
return __symtab;
}
/**
* Returns low index into symbol table for address.
*
* @param t if null will be auto-populated only if already open
* @return index or -1 if nothing found
*/
noinstrument privileged int __get_symbol(struct SymbolTable *t, intptr_t a) {
// we need privileged because:
// kprintf is privileged and it depends on this
// we don't want function tracing because:
// function tracing depends on this function via kprintf
unsigned l, m, r, n, k;
if (!t && __symtab) {
t = __symtab;
}
if (t) {
l = 0;
r = n = t->count;
k = a - t->addr_base;
while (l < r) {
m = (l + r) >> 1;
if (t->symbols[m].y < k) {
l = m + 1;
} else {
r = m;
}
}
if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) {
return l;
}
}
return -1;
}

View file

@ -68,7 +68,6 @@ static privileged void __morph_mprotect(void *addr, size_t size, int prot,
if (cf) ax = -ax;
if (ax == -EPERM) {
kprintf("error: need pledge(prot_exec) permission to code morph\n");
_Exit(26);
}
#endif
if (ax) notpossible;

View file

@ -78,7 +78,7 @@ void fpreset(void);
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t);
void *mremap(void *, size_t, size_t, int, ...);
int munmap(void *, uint64_t);
int mprotect(void *, uint64_t, int) privileged;
int mprotect(void *, uint64_t, int);
int msync(void *, size_t, int);
int mlock(const void *, size_t);
int munlock(const void *, size_t);

View file

@ -70,7 +70,6 @@ o/$(MODE)/libc/runtime/cosmo2.o: private \
o/$(MODE)/libc/runtime/ftracer.o: private \
CFLAGS += \
-x-no-pg \
$(MNO_FENTRY) \
-ffreestanding \
-fno-sanitize=all
@ -124,6 +123,14 @@ o/$(MODE)/libc/runtime/enable_tls.o: private \
-mcmodel=large
endif
# privileged functions
o/$(MODE)/libc/runtime/getsymbol.o \
o/$(MODE)/libc/runtime/enable_threads.o \
o/$(MODE)/libc/runtime/morph_tls.o: private \
CFLAGS += \
-ffreestanding \
-fno-sanitize=all
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/runtime/init.o: libc/runtime/init.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<

View file

@ -17,9 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/kprintf.h"
#include "libc/runtime/internal.h"
privileged noasan noinstrument void __stack_chk_fail(void) {
kprintf("stack smashed\n");
_Exitr(207);
__builtin_trap();
}

View file

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

View file

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

View file

@ -166,16 +166,6 @@ int vfprintf_unlocked(FILE *, const char *, va_list)
cosmopolitan § standard i/o » optimizations
*/
#define getc(f) fgetc(f)
#define getwc(f) fgetwc(f)
#define putc(c, f) fputc(c, f)
#define putwc(c, f) fputwc(c, f)
#define getc_unlocked(f) fgetc_unlocked(f)
#define getwc_unlocked(f) fgetwc_unlocked(f)
#define putc_unlocked(c, f) fputc_unlocked(c, f)
#define putwc_unlocked(c, f) fputwc_unlocked(c, f)
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* clang-format off */
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)

View file

@ -22,7 +22,7 @@
/**
* Returns address of errno variable.
*/
nocallersavedregisters errno_t *(__errno_location)(void) {
privileged nocallersavedregisters errno_t *(__errno_location)(void) {
if (!__tls_enabled) return &__errno;
return &__get_tls_privileged()->tib_errno;
}

View file

@ -90,7 +90,7 @@
static unsigned short klog_y = 0, klog_x = 0;
privileged void _klog_vga(const char *b, size_t n) {
void _klog_vga(const char *b, size_t n) {
struct Tty tty;
_vga_reinit(&tty, klog_y, klog_x, kTtyKlog);
_TtyWrite(&tty, b, n);

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
@ -26,6 +27,7 @@
char testlib_enable_tmp_setup_teardown;
TEST(ftrace, test) {
if (!IsOptimized()) return; // TODO(jart): fix me
const char *ftraceasm;
testlib_extract("/zip/ftraceasm.txt", "ftraceasm.txt", 0755);
ftraceasm = _gc(xslurp("ftraceasm.txt", 0));
@ -38,7 +40,7 @@ TEST(ftrace, test) {
#endif
fprintf(stderr,
"error: ftrace_hook() depends on floating point code\n"
"you need to objdump o//test/libc/runtime/ftraceasm.elf\n"
"you need to objdump -d o//test/libc/runtime/prog/ftraceasm.elf\n"
"then compile the guilty module with -mgeneral-regs-only\n");
exit(1);
}

View file

@ -18,6 +18,7 @@
*/
void ftrace_hook(void);
void _start(void) {
privileged void _start(void) {
ftrace_hook();
}

View file

@ -55,6 +55,7 @@ o/$(MODE)/test/libc/runtime/%.com.dbg: \
o/$(MODE)/test/libc/runtime/prog/ftraceasm.txt.zip.o \
o/$(MODE)/test/libc/runtime/%.o \
o/$(MODE)/test/libc/runtime/runtime.pkg \
o/$(MODE)/test/libc/runtime/runtime.pkg \
$(LIBC_TESTMAIN) \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@ -86,7 +87,7 @@ o/$(MODE)/test/libc/runtime/prog/ftraceasm.elf: \
$(TEST_LIBC_RUNTIME_DEPS) \
o/$(MODE)/test/libc/runtime/prog/ftraceasm.o \
o/$(MODE)/test/libc/runtime/runtime.pkg
@$(ELFLINK)
@$(ELFLINK) --gc-sections
o/$(MODE)/test/libc/runtime/prog/ftraceasm.txt: \
o/$(MODE)/test/libc/runtime/prog/ftraceasm.elf
@$(OBJDUMP) -d $< >$@

View file

@ -69,6 +69,7 @@ TEST(system, testStdoutRedirect_withSpacesInFilename) {
}
TEST(system, testStderrRedirect_toStdout) {
if (IsAsan()) return; // TODO(jart): fix me
int pipefd[2];
int stdoutBack = dup(1);
ASSERT_NE(-1, stdoutBack);

View file

@ -1,48 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
forceinline void *Memmove(void *restrict d, const void *restrict s, size_t n) {
return __builtin___memmove_chk(d, s, n, __builtin_object_size(d, 0));
}
void foo1(void *p, void *q) {
Memmove(p, q, 19);
}
TEST(memmove, supposedPythonBug_test1) {
char a[32] = "123456789000000000";
foo1(&a[9], a);
EXPECT_STREQ("123456789123456789000000000", a);
foo1(a, &a[9]);
EXPECT_STREQ("123456789000000000", a);
}
void foo2(void *p, void *q) {
memmove(p, q, 19);
}
TEST(memmove, supposedPythonBug_test2) {
char a[32] = "123456789000000000";
foo2(&a[9], a);
EXPECT_STREQ("123456789123456789000000000", a);
foo2(a, &a[9]);
EXPECT_STREQ("123456789000000000", a);
}

View file

@ -107,7 +107,7 @@ TEST(sem_close, withUnnamedSemaphore_isUndefinedBehavior) {
SPAWN(fork);
IgnoreStderr();
sem_close(&sem);
EXITS(77);
EXITS(23); // see __assert_fail
ASSERT_SYS(0, 0, sem_destroy(&sem));
}
@ -118,7 +118,7 @@ TEST(sem_destroy, withNamedSemaphore_isUndefinedBehavior) {
SPAWN(fork);
IgnoreStderr();
sem_destroy(sem);
EXITS(77);
EXITS(23); // see __assert_fail
ASSERT_SYS(0, 0, sem_unlink("/boop"));
ASSERT_SYS(0, 0, sem_close(sem));
}

View file

@ -51,7 +51,7 @@ TEST(sem_post, afterDestroyed_isUndefinedBehavior) {
ASSERT_SYS(0, 0, sem_destroy(&sem));
IgnoreStderr();
sem_post(&sem);
EXITS(77);
EXITS(23); // see __assert_fail
}
TEST(sem_trywait, afterDestroyed_isUndefinedBehavior) {
@ -63,7 +63,7 @@ TEST(sem_trywait, afterDestroyed_isUndefinedBehavior) {
ASSERT_SYS(0, 0, sem_destroy(&sem));
IgnoreStderr();
sem_trywait(&sem);
EXITS(77);
EXITS(23); // see __assert_fail
}
TEST(sem_wait, afterDestroyed_isUndefinedBehavior) {
@ -75,7 +75,7 @@ TEST(sem_wait, afterDestroyed_isUndefinedBehavior) {
ASSERT_SYS(0, 0, sem_destroy(&sem));
IgnoreStderr();
sem_wait(&sem);
EXITS(77);
EXITS(23); // see __assert_fail
}
TEST(sem_timedwait, afterDestroyed_isUndefinedBehavior) {
@ -87,7 +87,7 @@ TEST(sem_timedwait, afterDestroyed_isUndefinedBehavior) {
ASSERT_SYS(0, 0, sem_destroy(&sem));
IgnoreStderr();
sem_timedwait(&sem, 0);
EXITS(77);
EXITS(23); // see __assert_fail
}
void *Worker(void *arg) {

1
third_party/awk/b.c vendored
View file

@ -1214,6 +1214,7 @@ rescan:
}
break;
}
return 0; /* [jart] why wasn't this here? */
}
int cgoto(fa *f, int s, int c)

View file

@ -34,6 +34,7 @@
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/termios.h"
#include "third_party/ggml/llama.h"
#include "third_party/ggml/llama_util.h"
#include "third_party/libcxx/algorithm"

View file

@ -100,14 +100,6 @@ o/opt/third_party/ggml/ggml.o: private \
CFLAGS += \
-x-no-pg
ifeq ($(ARCH), x86_64)
o/rel/third_party/ggml/ggml.o \
o/opt/third_party/ggml/ggml.o: private \
CFLAGS += \
-fschedule-insns2 \
-mred-zone
endif
################################################################################
# command for running inference on large language models
# make -j8 o//third_party/ggml/llama.com

View file

@ -129,6 +129,7 @@
#include "third_party/linenoise/linenoise.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"

View file

@ -269,7 +269,7 @@ void test_sha512_valid_param_wrapper( void ** params )
void test_sha512_invalid_param( )
{
mbedtls_sha512_context ctx;
unsigned char buf[64] = { 0 };
unsigned char buf[128] = { 0 };
size_t const buflen = sizeof( buf );
int valid_type = 0;
int invalid_type = 42;

View file

@ -4,7 +4,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef atomic_uint_fast32_t nsync_atomic_uint32_;
#define nsync_atomic_uint32_ atomic_uint_fast32_t
#define NSYNC_ATOMIC_UINT32_INIT_ 0
#define NSYNC_ATOMIC_UINT32_LOAD_(p) (*(p))

View file

@ -5,9 +5,11 @@
https://docs.python.org/3/license.html │
*/
#define PY_SSIZE_T_CLEAN
#include "third_party/python/Modules/posixmodule.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/makedev.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/iovec.h"
@ -56,6 +58,7 @@
#include "libc/sysv/consts/sf.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/st.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/consts/w.h"
#include "libc/sysv/consts/waitid.h"
#include "libc/sysv/errfuns.h"
@ -87,7 +90,6 @@
#include "third_party/python/Include/warnings.h"
#include "third_party/python/Include/yoink.h"
#include "third_party/python/Modules/_multiprocessing/multiprocessing.h"
#include "third_party/python/Modules/posixmodule.h"
#include "third_party/python/pyconfig.h"
/* clang-format off */

View file

@ -32,6 +32,8 @@
#include "libc/calls/struct/termios.h"
#include "libc/calls/termios.h"
#include "third_party/unzip/crypt.h"
#include "libc/sysv/consts/termios.h"
#include "libc/calls/ioctl.h"
#include "third_party/unzip/globals.h"
#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))

View file

@ -48,17 +48,17 @@ o/$(MODE)/tool/build/emubin/%.bin.dbg: \
$(TOOL_BUILD_EMUBIN_A) \
o/$(MODE)/tool/build/emubin/%.o \
$(TOOL_BUILD_EMUBIN_A).pkg
@$(ELFLINK) -e emucrt -z max-page-size=0x10
@$(ELFLINK) -e emucrt -z common-page-size=0x10 -z max-page-size=0x10
o/tiny/tool/build/emubin/spiral.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/spiral.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
o/tiny/tool/build/emubin/mdatest.bin.dbg: \
$(TOOL_BUILD_EMUBIN_DEPS) \
o/tiny/tool/build/emubin/mdatest.real.o
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
@$(ELFLINK) -z common-page-size=0x10 -z max-page-size=0x10 -T tool/build/emucrt/real.lds
$(TOOL_BUILD_EMUBIN_OBJS): private \
CFLAGS += \

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
@ -26,9 +27,11 @@
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
@ -41,20 +44,21 @@
* @fileoverview GCC Codegen Fixer-Upper.
*/
#define GETOPTS "h"
#define GETOPTS "ch"
#define USAGE \
"\
Usage: fixupobj.com [-h] ARGS...\n\
-?\n\
-h show help\n\
-c check-only mode\n\
"
#define COSMO_TLS_REG 28
#define MRS_TPIDR_EL0 0xd53bd040u
#define MOV_REG(DST, SRC) (0xaa0003e0u | (SRC) << 16 | (DST))
static const unsigned char kFatNops[8][8] = {
const unsigned char kFatNops[8][8] = {
{}, //
{0x90}, // nop
{0x66, 0x90}, // xchg %ax,%ax
@ -65,31 +69,43 @@ static const unsigned char kFatNops[8][8] = {
{0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, // nopl 0x00000000(%rax)
};
void Write(const char *s, ...) {
int mode;
char *symstrs;
char *secstrs;
ssize_t esize;
Elf64_Sym *syms;
const char *epath;
Elf64_Xword symcount;
const Elf64_Ehdr *elf;
void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
write(2, s, strlen(s));
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
strlcat(buf, "\n", sizeof(buf));
write(fd, buf, strlen(buf));
va_end(va);
}
wontreturn void SysExit(int rc, const char *call, const char *thing) {
int err;
char ibuf[12];
const char *estr;
err = errno;
FormatInt32(ibuf, err);
estr = _strerdoc(err);
if (!estr) estr = "EUNKNOWN";
Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", NULL);
exit(rc);
wontreturn void SysExit(const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, epath, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static void GetOpts(int argc, char *argv[]) {
void GetOpts(int argc, char *argv[]) {
int opt;
mode = O_RDWR;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
switch (opt) {
case 'c':
mode = O_RDONLY;
break;
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
@ -101,17 +117,56 @@ static void GetOpts(int argc, char *argv[]) {
}
}
Elf64_Shdr *FindElfSectionByName(const char *name) {
long i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfString(elf, esize, secstrs, shdr->sh_name), name)) {
return shdr;
}
}
return 0;
}
void CheckPrivilegedCrossReferences(void) {
long i, x;
Elf64_Shdr *shdr;
const char *secname;
Elf64_Rela *rela, *erela;
if (!(shdr = FindElfSectionByName(".rela.privileged"))) return;
rela = GetElfSectionAddress(elf, esize, shdr);
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (syms[x].st_shndx == SHN_ABS) continue;
if (!syms[x].st_shndx) continue;
shdr = GetElfSectionHeaderAddress(elf, esize, syms[x].st_shndx);
if (~shdr->sh_flags & SHF_EXECINSTR) continue; // data reference
secname = GetElfString(elf, esize, secstrs, shdr->sh_name);
if (strcmp(".privileged", secname)) {
Print(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
exit(1);
}
}
}
// Modify ARM64 code to use x28 for TLS rather than tpidr_el0.
void RewriteTlsCode(Elf64_Ehdr *elf, size_t elfsize) {
void RewriteTlsCode(void) {
int i, dest;
Elf64_Shdr *shdr;
uint32_t *p, *pe;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, i);
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_PROGBITS && //
(shdr->sh_flags & SHF_ALLOC) && //
(shdr->sh_flags & SHF_EXECINSTR) && //
(p = GetElfSectionAddress(elf, elfsize, shdr))) {
(p = GetElfSectionAddress(elf, esize, shdr))) {
for (pe = p + shdr->sh_size / 4; p <= pe; ++p) {
if ((*p & -32) == MRS_TPIDR_EL0) {
*p = MOV_REG(*p & 31, COSMO_TLS_REG);
@ -131,19 +186,16 @@ void RewriteTlsCode(Elf64_Ehdr *elf, size_t elfsize) {
* In order for this to work, the function symbol must be declared as
* `STT_FUNC` and `st_size` must have the function's byte length.
*/
void OptimizePatchableFunctionEntries(Elf64_Ehdr *elf, size_t elfsize) {
void OptimizePatchableFunctionEntries(void) {
#ifdef __x86_64__
long i, n;
int nopcount;
Elf64_Sym *syms;
Elf64_Shdr *shdr;
Elf64_Xword symcount;
unsigned char *p, *pe;
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, elfsize, &symcount)));
for (i = 0; i < symcount; ++i) {
if (ELF64_ST_TYPE(syms[i].st_info) == STT_FUNC && syms[i].st_size) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, syms[i].st_shndx);
p = GetElfSectionAddress(elf, elfsize, shdr);
shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx);
p = GetElfSectionAddress(elf, esize, shdr);
p += syms[i].st_value;
pe = p + syms[i].st_size;
for (; p + 1 < pe; p += n) {
@ -159,27 +211,22 @@ void OptimizePatchableFunctionEntries(Elf64_Ehdr *elf, size_t elfsize) {
#endif /* __x86_64__ */
}
void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
char *strs;
void OptimizeRelocations(void) {
Elf64_Half i;
Elf64_Sym *syms;
Elf64_Rela *rela;
Elf64_Xword symcount;
unsigned char *code, *p;
Elf64_Shdr *shdr, *shdrcode;
CHECK_NOTNULL((strs = GetElfStringTable(elf, elfsize)));
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, elfsize, &symcount)));
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, i);
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_RELA) {
CHECK_EQ(sizeof(struct Elf64_Rela), shdr->sh_entsize);
CHECK_NOTNULL(
(shdrcode = GetElfSectionHeaderAddress(elf, elfsize, shdr->sh_info)));
(shdrcode = GetElfSectionHeaderAddress(elf, esize, shdr->sh_info)));
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
CHECK_NOTNULL((code = GetElfSectionAddress(elf, elfsize, shdrcode)));
for (rela = GetElfSectionAddress(elf, elfsize, shdr);
CHECK_NOTNULL((code = GetElfSectionAddress(elf, esize, shdrcode)));
for (rela = GetElfSectionAddress(elf, esize, shdr);
((uintptr_t)rela + shdr->sh_entsize <=
MIN((uintptr_t)elf + elfsize,
MIN((uintptr_t)elf + esize,
(uintptr_t)elf + shdr->sh_offset + shdr->sh_size));
++rela) {
@ -189,7 +236,7 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
*/
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
strcmp(GetElfString(elf, elfsize, strs,
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
@ -207,7 +254,7 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
strcmp(GetElfString(elf, elfsize, strs,
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
@ -223,45 +270,65 @@ void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
}
}
void RewriteObject(const char *path) {
void FixupObject(void) {
int fd;
struct stat st;
Elf64_Ehdr *elf;
if ((fd = open(path, O_RDWR)) == -1) {
SysExit(__COUNTER__ + 1, "open", path);
if ((fd = open(epath, mode)) == -1) {
SysExit("open");
}
if (fstat(fd, &st) == -1) {
SysExit(__COUNTER__ + 1, "fstat", path);
if ((esize = lseek(fd, 0, SEEK_END)) == -1) {
SysExit("lseek");
}
if (st.st_size >= 64) {
if ((elf = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
0)) == MAP_FAILED) {
SysExit(__COUNTER__ + 1, "mmap", path);
if (esize) {
if ((elf = mmap(0, esize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
MAP_FAILED) {
SysExit("mmap");
}
if (elf->e_machine == EM_NEXGEN32E) {
OptimizeRelocations(elf, st.st_size);
OptimizePatchableFunctionEntries(elf, st.st_size);
if (!IsElf64Binary(elf, esize)) {
Print(2, epath, ": not an elf64 binary\n", NULL);
exit(1);
}
if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode(elf, st.st_size);
if (!(syms = GetElfSymbolTable(elf, esize, &symcount))) {
Print(2, epath, ": missing elf symbol table\n", NULL);
exit(1);
}
if (msync(elf, st.st_size, MS_ASYNC | MS_INVALIDATE)) {
SysExit(__COUNTER__ + 1, "msync", path);
if (!(secstrs = GetElfSectionNameStringTable(elf, esize))) {
Print(2, epath, ": missing elf section string table\n", NULL);
exit(1);
}
if (munmap(elf, st.st_size)) {
SysExit(__COUNTER__ + 1, "munmap", path);
if (!(symstrs = GetElfStringTable(elf, esize))) {
Print(2, epath, ": missing elf symbol string table\n", NULL);
exit(1);
}
CheckPrivilegedCrossReferences();
if (mode == O_RDWR) {
if (elf->e_machine == EM_NEXGEN32E) {
OptimizeRelocations();
OptimizePatchableFunctionEntries();
}
if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode();
}
if (msync(elf, esize, MS_ASYNC | MS_INVALIDATE)) {
SysExit("msync");
}
}
if (munmap(elf, esize)) {
SysExit("munmap");
}
}
if (close(fd)) {
SysExit(__COUNTER__ + 1, "close", path);
SysExit("close");
}
}
int main(int argc, char *argv[]) {
int i, opt;
if (IsModeDbg()) ShowCrashReports();
if (!IsOptimized()) {
ShowCrashReports();
}
GetOpts(argc, argv);
for (i = optind; i < argc; ++i) {
RewriteObject(argv[i]);
epath = argv[i];
FixupObject();
}
}

View file

@ -1,120 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 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/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/bsr.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/x/x.h"
#include "tool/build/lib/persist.h"
static bool IsWithin(size_t sz1, void *vp1, size_t sz2, void *vp2) {
char *p1 = vp1, *p2 = vp2;
return p1 >= p2 && p1 + sz1 <= p2 + sz2;
}
static bool IsOverlapping(void *vx1, void *vy1, void *vx2, void *vy2) {
char *x1 = vx1, *y1 = vy1, *x2 = vx2, *y2 = vy2;
return (x1 >= x2 && x1 <= y2) || (y1 >= x2 && y1 <= y2);
}
static bool IsOverlappingIov(struct iovec *a, struct iovec *b) {
char *ap = a->iov_base, *bp = b->iov_base;
return IsOverlapping(ap, ap + a->iov_len, bp, bp + b->iov_len);
}
/**
* Writes struct w/ dynamic arrays to mappable file, e.g.
*
* PersistObject(path, 64, &(struct ObjectParam){
* sizeof(*o), o, &o->magic, &o->abi,
* &(struct ObjectArrayParam){
* {&o->a1.i, sizeof(o->a1.p[0]), &o->a1.p},
* {&o->a2.i, sizeof(o->a2.p[0]), &o->a2.p},
* {0},
* }});
*
* @param obj->magic needs to be unique for struct
* @param obj->abi monotonically tracks breaking changes
* @param obj->arrays needs sentinel with item size of zero
* @note non-recursive i.e. array elements can't have pointers
* @see MapObject()
*/
void PersistObject(const char *path, size_t align,
const struct ObjectParam *obj) {
const char *pad;
struct iovec *iov;
int i, n, fd, iovlen;
long len, size, bytes, filesize;
unsigned char *hdr, *p1, *p2, **pp;
intptr_t arrayptroffset, arraydataoffset;
filesize = 0;
DCHECK_GE(align, 1);
CHECK_GT(*obj->magic, 0);
CHECK_GT(*obj->abi, 0);
CHECK(IsWithin(sizeof(*obj->magic), obj->magic, obj->size, obj->p));
CHECK(IsWithin(sizeof(*obj->abi), obj->abi, obj->size, obj->p));
for (n = i = 0; obj->arrays[i].size; ++i) ++n;
iovlen = (n + 1) * 2;
pad = _gc(xcalloc(align, 1));
hdr = _gc(xmalloc(obj->size));
iov = _gc(xcalloc(iovlen, sizeof(*iov)));
bytes = obj->size;
iov[0].iov_base = memcpy(hdr, obj->p, obj->size);
iov[0].iov_len = bytes;
iov[1].iov_base = pad;
iov[1].iov_len = ROUNDUP(bytes, align) - bytes;
filesize += ROUNDUP(bytes, align);
for (i = 0; i < n; ++i) {
pp = obj->arrays[i].pp;
len = obj->arrays[i].len;
size = obj->arrays[i].size;
if (!*pp || !len) continue;
p1 = obj->p;
p2 = obj->arrays[i].pp;
arrayptroffset = p2 - p1;
arraydataoffset = filesize;
CHECK((!len || _bsrl(len) + _bsrl(size) < 31),
"path=%s i=%d len=%,lu size=%,lu", path, i, len, size);
CHECK(IsWithin(sizeof(void *), pp, obj->size, obj->p));
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->magic,
obj->magic + sizeof(*obj->magic)));
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->abi,
obj->abi + sizeof(*obj->abi)));
memcpy(hdr + arrayptroffset, &arraydataoffset, sizeof(intptr_t));
CHECK_LT(filesize + arraydataoffset, 0x7ffff000);
bytes = len * size;
iov[(i + 1) * 2 + 0].iov_base = *pp;
iov[(i + 1) * 2 + 0].iov_len = bytes;
iov[(i + 1) * 2 + 1].iov_base = pad;
iov[(i + 1) * 2 + 1].iov_len = ROUNDUP(bytes, align) - bytes;
filesize += ROUNDUP(bytes, align);
CHECK(!IsOverlappingIov(&iov[(i + 0) * 2], &iov[(i + 1) * 2]),
"iov[%d]={%#p,%#x}, iov[%d]={%#p,%#x} path=%s", (i + 0) * 2,
iov[(i + 0) * 2].iov_base, iov[(i + 0) * 2].iov_len, (i + 1) * 2,
iov[(i + 1) * 2].iov_base, iov[(i + 1) * 2].iov_len, path);
}
CHECK_NE(-1, (fd = creat(path, 0644)), "%s", path);
CHECK_EQ(filesize, writev(fd, iov, iovlen));
CHECK_NE(-1, close(fd));
}

View file

@ -1,24 +0,0 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ObjectArrayParam {
size_t len;
size_t size;
void *pp;
};
struct ObjectParam {
size_t size;
void *p;
uint32_t *magic;
int32_t *abi;
struct ObjectArrayParam * arrays;
};
void PersistObject(const char *, size_t, const struct ObjectParam *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_ */

View file

@ -17,14 +17,18 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/rela.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/errno.h"
#include "libc/intrin/bswap.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/mem/arraylist.internal.h"
#include "libc/mem/mem.h"
@ -36,7 +40,8 @@
#include "third_party/getopt/getopt.h"
#include "third_party/xed/x86.h"
#include "tool/build/lib/getargs.h"
#include "tool/build/lib/persist.h"
STATIC_YOINK("realloc");
/**
* @fileoverview Build Package Script.
@ -67,7 +72,21 @@
*/
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
#define PACKAGE_ABI 1
#define PACKAGE_ABI 2
struct ObjectArrayParam {
size_t len;
size_t size;
void *pp;
};
struct ObjectParam {
size_t size;
void *p;
uint32_t *magic;
int32_t *abi;
struct ObjectArrayParam *arrays;
};
struct Packages {
size_t i, n;
@ -77,7 +96,7 @@ struct Packages {
uint32_t path; // pkg->strings.p[path]
int64_t fd; // not persisted
void *addr; // not persisted
size_t size; // not persisted
ssize_t size; // not persisted
struct Strings {
size_t i, n;
char *p; // persisted as pkg+RVA
@ -86,28 +105,29 @@ struct Packages {
size_t i, n;
struct Object {
uint32_t path; // pkg->strings.p[path]
unsigned mode; // not persisted
struct Elf64_Ehdr *elf; // not persisted
size_t size; // not persisted
char *strs; // not persisted
Elf64_Sym *syms; // not persisted
Elf64_Xword symcount; // not persisted
struct Sections {
size_t i, n;
struct Section {
enum SectionKind {
kUndef,
kText,
kData,
kPiroRelo,
kPiroData,
kPiroBss,
kBss,
} kind;
} * p;
} sections; // not persisted
} * p; // persisted as pkg+RVA
int section_offset;
int section_count;
} * p;
} objects;
struct Sections {
size_t i, n;
struct Section {
int name;
enum SectionKind {
kUndef,
kText,
kPrivilegedText,
kData,
kBss,
kOther,
} kind;
} * p;
} sections;
struct Symbols {
size_t i, n;
struct Symbol {
@ -115,80 +135,223 @@ struct Packages {
enum SectionKind kind : 8;
uint8_t bind_ : 4;
uint8_t type : 4;
uint16_t object; // pkg->objects.p[object]
} * p; // persisted as pkg+RVA
} symbols, undefs; // TODO(jart): hash undefs?
} * *p; // persisted across multiple files
uint16_t object; // pkg->objects.p[object]
uint16_t section; // pkg->sections.p[section]
} * p; // persisted as pkg+RVA
} symbols, undefs; // TODO(jart): hash undefs?
} * *p; // persisted across multiple files
};
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
const char *tab) {
struct Relas {
size_t i, n;
struct Strings s;
struct Rela {
const char *symbol_name;
const char *object_path;
} * p;
} prtu;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
const char *tab) {
return strcmp(tab + a->name, tab + b->name);
}
struct Package *LoadPackage(const char *path) {
static void PrintSymbols(struct Package *pkg, struct Symbols *syms,
const char *name) {
int i;
kprintf(" - %s=%d\n", name, syms->i);
for (i = 0; i < syms->i; ++i) {
kprintf(" - id=%d\n", i);
kprintf(" name=%d [%s]\n", syms->p[i].name,
pkg->strings.p + syms->p[i].name);
kprintf(" kind=%d\n", syms->p[i].kind);
kprintf(" bind=%d\n", syms->p[i].bind_);
kprintf(" type=%d\n", syms->p[i].type);
kprintf(" object=%d [%s]\n", syms->p[i].object,
pkg->strings.p + pkg->objects.p[syms->p[i].object].path);
kprintf(" section=%d [%s]\n", syms->p[i].section,
syms->p[i].section == SHN_ABS
? "SHN_ABS"
: pkg->strings.p + pkg->sections.p[syms->p[i].section].name);
}
}
static void PrintObject(struct Package *pkg, struct Object *obj) {
int i, o;
kprintf(" path=%d [%s]\n", obj->path, pkg->strings.p + obj->path);
kprintf(" sections=%d\n", obj->section_count);
for (i = 0; i < obj->section_count; ++i) {
o = obj->section_offset;
kprintf(" - id=%d %p (%d+%d)\n", i, pkg->sections.p, o, i);
kprintf(" name=%d [%s]\n", pkg->sections.p[o + i].name,
pkg->strings.p + pkg->sections.p[o + i].name);
kprintf(" kind=%d\n", pkg->sections.p[o + i].kind);
}
}
static void PrintPackage(struct Package *pkg) {
int i, j, o;
kprintf("- %s\n", pkg->strings.p + pkg->path);
kprintf(" objects=%d\n", pkg->objects.i);
for (i = 0; i < pkg->objects.i; ++i) {
kprintf(" - id=%d\n", i);
PrintObject(pkg, pkg->objects.p + i);
}
PrintSymbols(pkg, &pkg->symbols, "symbols");
PrintSymbols(pkg, &pkg->undefs, "undefs");
}
static void PrintPackages(struct Package *p, int n) {
int i;
for (i = 0; i < n; ++i) {
PrintPackage(p + i);
}
}
static struct Package *LoadPackage(const char *path) {
int fd;
ssize_t i;
struct stat st;
ssize_t i, size;
struct Package *pkg;
CHECK(fileexists(path), "%s: %s: %s\n", "error", path, "not found");
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(MAP_FAILED,
(pkg = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd, 0)),
"path=%s", path);
CHECK_NE(-1, close(fd));
CHECK_EQ(PACKAGE_MAGIC, pkg->magic, "corrupt package: %`'s", path);
pkg->strings.p = (char *)((intptr_t)pkg->strings.p + (intptr_t)pkg);
pkg->objects.p = (struct Object *)((intptr_t)pkg->objects.p + (intptr_t)pkg);
pkg->symbols.p = (struct Symbol *)((intptr_t)pkg->symbols.p + (intptr_t)pkg);
if ((fd = open(path, O_RDONLY)) == -1) {
SysExit(path, "open");
}
if ((size = lseek(fd, 0, SEEK_END)) == -1) {
SysExit(path, "lseek");
}
if ((pkg = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) ==
MAP_FAILED) {
SysExit(path, "mmap");
}
close(fd);
if (pkg->magic != PACKAGE_MAGIC) {
Print(2, path, ": not a cosmo .pkg file\n", NULL);
exit(1);
}
if (pkg->abi < PACKAGE_ABI) {
Print(2, path, ": package has old abi try running make clean\n", NULL);
exit(1);
}
pkg->strings.p = (void *)((uintptr_t)pkg->strings.p + (uintptr_t)pkg);
pkg->objects.p = (void *)((uintptr_t)pkg->objects.p + (uintptr_t)pkg);
pkg->symbols.p = (void *)((uintptr_t)pkg->symbols.p + (uintptr_t)pkg);
pkg->sections.p = (void *)((uintptr_t)pkg->sections.p + (uintptr_t)pkg);
pkg->addr = pkg;
pkg->size = st.st_size;
CHECK_NE(-1, mprotect(pkg, st.st_size, PROT_READ));
pkg->size = size;
if (mprotect(pkg, size, PROT_READ)) {
SysExit(path, "mprotect");
}
return pkg;
}
void AddDependency(struct Packages *deps, const char *path) {
static void AddDependency(struct Packages *deps, const char *path) {
struct Package *pkg;
pkg = LoadPackage(path);
CHECK_NE(-1, append(deps, &pkg));
append(deps, &pkg);
}
void WritePackage(struct Package *pkg) {
CHECK_NE(0, PACKAGE_MAGIC);
static void WritePackage(struct Package *pkg) {
int fd;
size_t n;
int64_t o;
const char *path;
pkg->magic = PACKAGE_MAGIC;
pkg->abi = PACKAGE_ABI;
DEBUGF("%s has %,ld objects, %,ld symbols, and a %,ld byte string table",
&pkg->strings.p[pkg->path], pkg->objects.i, pkg->symbols.i,
pkg->strings.i);
PersistObject(
&pkg->strings.p[pkg->path], 64,
&(struct ObjectParam){
sizeof(struct Package),
pkg,
&pkg->magic,
&pkg->abi,
(struct ObjectArrayParam[]){
{pkg->strings.i, sizeof(pkg->strings.p[0]), &pkg->strings.p},
{pkg->objects.i, sizeof(pkg->objects.p[0]), &pkg->objects.p},
{pkg->symbols.i, sizeof(pkg->symbols.p[0]), &pkg->symbols.p},
{0},
},
});
path = pkg->strings.p + pkg->path;
if ((fd = creat(path, 0644)) == -1) {
SysExit(path, "creat");
}
o = sizeof(*pkg);
// write objects
n = pkg->objects.i * sizeof(*pkg->objects.p);
if (pwrite(fd, pkg->objects.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->objects.p = (void *)o;
o += n;
// write symbols
n = pkg->symbols.i * sizeof(*pkg->symbols.p);
if (pwrite(fd, pkg->symbols.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->symbols.p = (void *)o;
o += n;
// write sections
n = pkg->sections.i * sizeof(*pkg->sections.p);
if (pwrite(fd, pkg->sections.p, n, o) != n) {
SysExit(path, "pwrite");
}
pkg->sections.p = (void *)o;
o += n;
// write strings
n = pkg->strings.i * sizeof(*pkg->strings.p);
pwrite(fd, pkg->strings.p, n, o);
pkg->strings.p = (void *)o;
// write header
if (pwrite(fd, pkg, sizeof(*pkg), 0) != sizeof(*pkg)) {
SysExit(path, "pwrite");
}
// we're done
if (close(fd) == -1) {
SysExit(path, "close");
}
}
void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
char *argv[]) {
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\
NAME\n\
\n\
Cosmopolitan Monorepo Packager\n\
\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] OBJECT...\n\
\n\
DESCRIPTION\n\
\n\
This program verifies the well-formedness of symbolic references\n\
and package dependencies in the cosmopolitan monolithic repository.\n\
Validation happens incrementally and is granular to static libraries.\n\
Each .a file should have its own .pkg file too, created by this tool.\n\
\n\
FLAGS\n\
\n\
-h show this help\n\
-o PATH package output path\n\
-d PATH package dependency path [repeatable]\n\
\n\
",
NULL);
exit(exitcode);
}
static void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
char *argv[]) {
long i, si, opt;
const char *arg;
struct GetArgs ga;
pkg->path = -1;
while ((opt = getopt(argc, argv, "vho:d:")) != -1) {
while ((opt = getopt(argc, argv, "ho:d:")) != -1) {
switch (opt) {
case 'v':
__log_level = kLogDebug;
break;
case 'o':
pkg->path = concat(&pkg->strings, optarg, strlen(optarg) + 1);
break;
@ -196,72 +359,74 @@ void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
AddDependency(deps, optarg);
break;
case 'h':
exit(0);
PrintUsage(1, 0);
default:
fprintf(stderr, "%s: %s [%s %s] [%s %s] %s\n", "Usage",
program_invocation_name, "-o", "OUTPACKAGE", "-d", "DEPPACKAGE",
"OBJECT...");
exit(1);
PrintUsage(2, 1);
}
}
CHECK_NE(-1, pkg->path, "no packages passed to package.com");
CHECK_LT(optind, argc,
"no objects passed to package.com; "
"is your foo.mk $(FOO_OBJS) glob broken?");
if (pkg->path == -1) {
Print(2, "error: no packages passed to package.com\n", NULL);
exit(1);
}
if (optind == argc) {
Print(2,
"no objects passed to package.com; is your foo.mk $(FOO_OBJS) glob "
"broken?\n",
NULL);
exit(1);
}
getargs_init(&ga, argv + optind);
while ((arg = getargs_next(&ga))) {
CHECK_NE(-1, (si = concat(&pkg->strings, arg, strlen(arg) + 1)));
CHECK_NE(-1, append(&pkg->objects, (&(struct Object){si})));
struct Object obj = {0};
obj.path = concat(&pkg->strings, arg, strlen(arg) + 1);
append(&pkg->objects, &obj);
}
getargs_destroy(&ga);
}
void IndexSections(struct Object *obj) {
size_t i;
static void IndexSections(struct Package *pkg, struct Object *obj) {
int i;
const char *name;
const uint8_t *code;
struct Section sect;
const Elf64_Shdr *shdr;
struct XedDecodedInst xedd;
obj->section_offset = pkg->sections.i;
for (i = 0; i < obj->elf->e_shnum; ++i) {
bzero(&sect, sizeof(sect));
CHECK_NOTNULL((shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i)));
if (shdr->sh_type != SHT_NULL) {
CHECK_NOTNULL((name = GetElfSectionName(obj->elf, obj->size, shdr)));
if (_startswith(name, ".sort.")) name += 5;
if ((strcmp(name, ".piro.relo") == 0 ||
_startswith(name, ".piro.relo.")) ||
(strcmp(name, ".data.rel.ro") == 0 ||
_startswith(name, ".data.rel.ro."))) {
sect.kind = kPiroRelo;
} else if (strcmp(name, ".piro.data") == 0 ||
_startswith(name, ".piro.data.")) {
sect.kind = kPiroData;
} else if (strcmp(name, ".piro.bss") == 0 ||
_startswith(name, ".piro.bss.")) {
sect.kind = kPiroBss;
} else if (strcmp(name, ".data") == 0 || _startswith(name, ".data.")) {
sect.kind = kData;
} else if (strcmp(name, ".bss") == 0 || _startswith(name, ".bss.")) {
sect.kind = kBss;
} else {
shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i);
name = GetElfSectionName(obj->elf, obj->size, shdr);
if (shdr->sh_type == SHT_NULL) {
sect.kind = kUndef;
} else if (shdr->sh_type == SHT_NOBITS) {
sect.kind = kBss;
} else if (shdr->sh_type == SHT_PROGBITS &&
!(shdr->sh_flags & SHF_EXECINSTR)) {
sect.kind = kData;
} else if (shdr->sh_type == SHT_PROGBITS &&
(shdr->sh_flags & SHF_EXECINSTR)) {
if (strcmp(name, ".privileged")) {
sect.kind = kText;
} else {
sect.kind = kPrivilegedText;
}
} else {
sect.kind = kUndef; /* should always and only be section #0 */
sect.kind = kOther;
}
CHECK_NE(-1, append(&obj->sections, &sect));
sect.name = concat(&pkg->strings, name, strlen(name) + 1);
append(&pkg->sections, &sect);
++obj->section_count;
}
}
enum SectionKind ClassifySection(struct Object *obj, uint8_t type,
Elf64_Section shndx) {
static enum SectionKind ClassifySection(struct Package *pkg, struct Object *obj,
uint8_t type, Elf64_Section shndx) {
if (shndx == SHN_ABS) return kOther;
if (type == STT_COMMON) return kBss;
if (!obj->sections.i) return kText;
return obj->sections.p[min(max(0, shndx), obj->sections.i - 1)].kind;
return pkg->sections.p[obj->section_offset + shndx].kind;
}
void LoadSymbols(struct Package *pkg, uint32_t object) {
static void LoadSymbols(struct Package *pkg, uint32_t object) {
Elf64_Xword i;
const char *name;
struct Object *obj;
@ -269,57 +434,104 @@ void LoadSymbols(struct Package *pkg, uint32_t object) {
obj = &pkg->objects.p[object];
symbol.object = object;
for (i = 0; i < obj->symcount; ++i) {
symbol.section = obj->section_offset + obj->syms[i].st_shndx;
symbol.bind_ = ELF64_ST_BIND(obj->syms[i].st_info);
symbol.type = ELF64_ST_TYPE(obj->syms[i].st_info);
if (symbol.bind_ != STB_LOCAL &&
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
name = GetElfString(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
DEBUGF("%s", name);
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
CHECK_NE(-1,
(symbol.name = concat(&pkg->strings, name, strlen(name) + 1)));
CHECK_NE(-1,
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs,
&symbol));
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_")) {
symbol.kind =
ClassifySection(pkg, obj, symbol.type, obj->syms[i].st_shndx);
symbol.name = concat(&pkg->strings, name, strlen(name) + 1);
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs, &symbol);
}
}
}
}
void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
int flags) {
static Elf64_Shdr *FindElfSectionByName(Elf64_Ehdr *elf, size_t esize,
const char *name) {
long i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfSectionName(elf, esize, shdr), name)) {
return shdr;
}
}
return 0;
}
static void LoadPriviligedRefsToUndefs(struct Package *pkg,
struct Object *obj) {
long x;
struct Rela r;
const char *s;
Elf64_Shdr *shdr;
Elf64_Rela *rela, *erela;
if ((shdr = FindElfSectionByName(obj->elf, obj->size, ".rela.privileged"))) {
rela = GetElfSectionAddress(obj->elf, obj->size, shdr);
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (obj->syms[x].st_shndx) continue; // symbol is defined
if (ELF64_ST_BIND(obj->syms[x].st_info) != STB_WEAK &&
ELF64_ST_BIND(obj->syms[x].st_info) != STB_GLOBAL) {
Print(2, "warning: undefined symbol not global\n", NULL);
continue;
}
r.symbol_name = strdup(
GetElfString(obj->elf, obj->size, obj->strs, obj->syms[x].st_name));
r.object_path = strdup(pkg->strings.p + obj->path);
append(&prtu, &r);
}
}
}
static void OpenObject(struct Package *pkg, struct Object *obj, int oid) {
int fd;
struct stat st;
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], (obj->mode = mode))),
"path=%`'s", &pkg->strings.p[obj->path]);
CHECK_NE(-1, fstat(fd, &st));
CHECK_NE(
MAP_FAILED,
(obj->elf = mmap(NULL, (obj->size = st.st_size), prot, flags, fd, 0)),
"path=%`'s", &pkg->strings.p[obj->path]);
CHECK_NE(-1, close(fd));
CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s",
&pkg->strings.p[obj->path]);
CHECK_NOTNULL((obj->strs = GetElfStringTable(obj->elf, obj->size)), "on %s",
&pkg->strings.p[obj->path]);
CHECK_NOTNULL(
(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount)));
CHECK_NE(0, obj->symcount);
IndexSections(obj);
const char *path;
path = pkg->strings.p + obj->path;
if ((fd = open(path, O_RDONLY)) == -1) {
SysExit(path, "open");
}
if ((obj->size = lseek(fd, 0, SEEK_END)) == -1) {
SysExit(path, "lseek");
}
if ((obj->elf = mmap(0, obj->size, PROT_READ, MAP_SHARED, fd, 0)) ==
MAP_FAILED) {
SysExit(path, "mmap");
}
close(fd);
if (!IsElf64Binary(obj->elf, obj->size)) {
Print(2, path, ": not an elf64 binary\n", NULL);
exit(1);
}
if (!(obj->strs = GetElfStringTable(obj->elf, obj->size))) {
Print(2, path, ": missing elf string table\n", NULL);
exit(1);
}
if (!(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount))) {
Print(2, path, ": missing elf symbol table\n", NULL);
exit(1);
}
IndexSections(pkg, obj);
LoadPriviligedRefsToUndefs(pkg, obj);
}
void CloseObject(struct Object *obj) {
CHECK_NE(-1, munmap(obj->elf, obj->size));
static void CloseObject(struct Object *obj) {
if (munmap(obj->elf, obj->size)) notpossible;
}
void LoadObjects(struct Package *pkg) {
static void LoadObjects(struct Package *pkg) {
size_t i;
struct Object *obj;
for (i = 0; i < pkg->objects.i; ++i) {
obj = pkg->objects.p + i;
OpenObject(pkg, obj, O_RDONLY, PROT_READ, MAP_SHARED);
OpenObject(pkg, obj, i);
LoadSymbols(pkg, i);
CloseObject(obj);
}
@ -327,7 +539,7 @@ void LoadObjects(struct Package *pkg) {
(void *)CompareSymbolName, pkg->strings.p);
}
struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
static struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
int c;
long m, l, r;
l = 0;
@ -346,9 +558,9 @@ struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
return NULL;
}
bool FindSymbol(const char *name, struct Package *pkg,
struct Packages *directdeps, struct Package **out_pkg,
struct Symbol **out_sym) {
static bool FindSymbol(const char *name, struct Package *pkg,
struct Packages *directdeps, struct Package **out_pkg,
struct Symbol **out_sym) {
size_t i, j;
struct Symbol *sym;
if ((sym = BisectSymbol(pkg, name))) {
@ -366,7 +578,7 @@ bool FindSymbol(const char *name, struct Package *pkg,
return false;
}
void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
static void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
size_t i, j;
struct Package *dep;
struct Symbol *undef;
@ -374,15 +586,13 @@ void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
undef = &pkg->undefs.p[i];
if (undef->bind_ == STB_WEAK) continue;
if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) {
fprintf(stderr, "%s: %`'s (%s) %s %s\n", "error",
pkg->strings.p + undef->name,
pkg->strings.p + pkg->objects.p[undef->object].path,
"not defined by direct deps of", pkg->strings.p + pkg->path);
Print(2, pkg->strings.p + pkg->path, ": undefined symbol '",
pkg->strings.p + undef->name, "' (",
pkg->strings.p + pkg->objects.p[undef->object].path,
") not defined by direct dependencies:\n", NULL);
for (j = 0; j < deps->i; ++j) {
dep = deps->p[j];
fputc('\t', stderr);
fputs(dep->strings.p + dep->path, stderr);
fputc('\n', stderr);
Print(2, "\t", dep->strings.p + dep->path, "\n", NULL);
}
exit(1);
}
@ -391,43 +601,53 @@ void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
bzero(&pkg->undefs, sizeof(pkg->undefs));
}
forceinline bool IsRipRelativeModrm(uint8_t modrm) {
return (modrm & 0b11000111) == 0b00000101;
static void CheckYourPrivilege(struct Package *pkg, struct Packages *deps) {
int i, j, o, f;
const char *name;
struct Symbol *sym;
struct Package *dep;
for (f = i = 0; i < prtu.i; ++i) {
name = prtu.p[i].symbol_name;
if (FindSymbol(name, pkg, deps, &dep, &sym) &&
dep->sections.p[sym->section].kind == kText) {
Print(2, prtu.p[i].object_path,
": privileged code referenced unprivileged symbol '", name,
"' in section '",
dep->strings.p + dep->sections.p[sym->section].name, "'\n", NULL);
++f;
}
}
if (f) exit(1);
}
forceinline uint8_t ChangeRipToRbx(uint8_t modrm) {
return (modrm & 0b00111000) | 0b10000011;
static bool IsSymbolDirectlyReachable(struct Package *pkg,
struct Packages *deps,
const char *symbol) {
return FindSymbol(symbol, pkg, deps, 0, 0);
}
bool IsSymbolDirectlyReachable(struct Package *pkg, struct Packages *deps,
const char *symbol) {
return FindSymbol(symbol, pkg, deps, NULL, NULL);
}
void Package(int argc, char *argv[], struct Package *pkg,
struct Packages *deps) {
static void Package(int argc, char *argv[], struct Package *pkg,
struct Packages *deps) {
size_t i, j;
GetOpts(pkg, deps, argc, argv);
LoadObjects(pkg);
CheckStrictDeps(pkg, deps);
CheckYourPrivilege(pkg, deps);
WritePackage(pkg);
for (i = 0; i < deps->i; ++i) {
CHECK_NE(-1, munmap(deps->p[i]->addr, deps->p[i]->size));
if (munmap(deps->p[i]->addr, deps->p[i]->size)) notpossible;
}
for (i = 0; i < pkg->objects.i; ++i) {
free(pkg->objects.p[i].sections.p);
}
free(pkg->strings.p);
free(pkg->objects.p);
free(pkg->symbols.p);
free(deps->p);
}
int main(int argc, char *argv[]) {
struct Package pkg;
struct Packages deps;
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
if (IsModeDbg()) ShowCrashReports();
if (argc == 2 && !strcmp(argv[1], "-n")) {
exit(0);
}
if (!IsOptimized()) {
ShowCrashReports();
}
bzero(&pkg, sizeof(pkg));
bzero(&deps, sizeof(deps));
Package(argc, argv, &pkg, &deps);

View file

@ -1052,7 +1052,9 @@ wontreturn void StraceMain(int argc, char *argv[]) {
exit(1);
}
if (IsModeDbg()) ShowCrashReports();
if (!IsOptimized()) {
ShowCrashReports();
}
if (argc < 2) {
kprintf("Usage: %s PROGRAM [ARGS...]%n", argv[0]);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/winsize.h"

View file

@ -25,6 +25,7 @@
(require 'ld-script)
(require 'make-mode)
(setq cosmo-dbg-mode "zero")
(setq c-doc-comment-style 'javadown)
(add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info
@ -162,13 +163,13 @@
(cond ((eq arg 1) "tiny")
((eq arg 2) "opt")
((eq arg 3) "rel")
((eq arg 4) "dbg")
((eq arg 4) cosmo-dbg-mode)
((eq arg 5) "")
((eq arg 6) "llvm")
((eq arg 7) "aarch64")
((eq arg 8) "aarch64-tiny")
(default default)
((cosmo-intest) "dbg")
((cosmo-intest) cosmo-dbg-mode)
(t "fastbuild")))
(defun cosmo--make-suffix (arg)
@ -684,7 +685,7 @@
(let* ((this (or (buffer-file-name) dired-directory))
(root (locate-dominating-file this "Makefile")))
(when root
(let* ((mode (cosmo--make-mode arg "dbg"))
(let* ((mode (cosmo--make-mode arg cosmo-dbg-mode))
(name (file-relative-name this root))
(next (file-name-sans-extension name))
(exec (format "o/%s/%s.com.dbg" mode next))

View file

@ -249,6 +249,7 @@ o/$(MODE)/tool/net/redbean-demo.com: \
o/$(MODE)/tool/net/redbean-static.com.dbg: \
$(TOOL_NET_DEPS) \
$(TOOL_NET_REDBEAN_LUA_MODULES) \
o/$(MODE)/tool/net/redbean-static.o \
o/$(MODE)/tool/net/net.pkg \
$(CRT) \
@ -300,6 +301,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
o/$(MODE)/tool/net/redbean-original.com.dbg: \
$(TOOL_NET_DEPS) \
$(TOOL_NET_REDBEAN_LUA_MODULES) \
o/$(MODE)/tool/net/redbean-original.o \
o/$(MODE)/tool/net/net.pkg \
$(CRT) \