diff --git a/ape/ape.S b/ape/ape.S index 2f26782f..5b4e74dd 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -175,7 +175,7 @@ stub: mov $0x40,%dl # *literally* dos built the last forty years these routines also canonicalize the cpu and program state, as it is written in the System V ABI. */ -/ Initializes program and jumps to long mode loader. +/ Initializes program and jumps to real mode loader. / / @param dl drive number (use 0x40 to skip bios disk load) / @mode real @@ -188,62 +188,46 @@ pc: cld #endif mov $REAL_STACK_FRAME>>4,%di # we need a stack xor %cx,%cx + mov %cx,%es rlstack %di,%cx - movpp %cs,%ax # memcpy() [relocate this page] + push %cs # memcpy() [relocate this page] + pop %ds call 1f 1: pop %si sub $RVA(1b),%si - mov $4,%cl -1: shr %si - loop 1b - mov $512,%cx - mov $IMAGE_BASE_REAL>>4,%di - mov %si,%ds - mov %di,%es - xor %si,%si + mov $IMAGE_BASE_REAL>>4,%ax + push %ax # save real base + push %ax + pop %es xor %di,%di - rep - movsb %ds:(%si),%es:(%di) + mov $512,%cx + rep movsb #if USE_SYMBOL_HACK .byte 0x0f,0x1f,0207 # nop rdi binbase .short (IMAGE_BASE_REAL-0x7c00)/512 #endif ljmp $0,$REAL(1f) # longjmp() -1: mov $-512,%cx # memcpy() [relocate this frame] - rep - movsb %ds:(%si),%es:(%di) - xor %bp,%bp - mov %bp,%ds # %ds and %cs are now zero - call 1f # setup frame pointers -1: push %bp - mov %sp,%bp - mov $XLM_SIZE,%cx # memset() [clear real bss] +1: mov %cx,%ds # %ds and %cs are now zero + mov $XLM_SIZE,%cx # memset to clear real bss mov $XLM_BASE_REAL>>4,%ax mov %ax,%es xor %ax,%ax xor %di,%di - rep - stosb %al,%es:(%di) + rep stosb cmp $0x40,%dl # statfs() [disk geometry] je 6f call dsknfo - mov $IMAGE_BASE_REAL>>4,%ax - mov %ax,%es - mov $v_ape_realsectors,%di # total sectors to read - xor %dh,%dh # current head state - xor %cx,%cx # current cylinder state -3: mov %di,%ax - call pcread - mov %es,%si -4: add $512>>4,%si + pop %es # restore real base + mov $1,%al # current sector + xor %cx,%cx # current cylinder + xor %dh,%dh # current head + mov $v_ape_realsectors,%di # total sectors +3: call pcread dec %di - jz 6f - dec %ax - jnz 4b - mov %si,%es - jmp 3b -6: mov %cx,XLM(LOADSTATE)+0 - mov %dx,XLM(LOADSTATE)+2 + jnz 3b +6: mov %ax,XLM(LOADSTATE)+0 + mov %cx,XLM(LOADSTATE)+2 + mov %dx,XLM(LOADSTATE)+4 ljmp $0,$REAL(realmodeloader) .endfn pc,globl,hidden @@ -334,66 +318,40 @@ dsknfo: push %bx jmp 1b .endfn dsknfo -/ Reads disk sectors via BIOS. +/ Reads disk sector via BIOS. / -/ Each call to this function performs a single read. It has a -/ special ABI, where its parameters are preserved, and rolled -/ forward accordingly across calls. BIOS requirements on read -/ parameter validity are abstracted. If the requested size is -/ too large for one read, then it's tuned down appropriately. -/ -/ Please note that dskinfo() must be called beforehand. -/ -/ @param ax number sectors to read +/ @param al sector number / @param es destination memory address >> 4 / @param cx cylinder number / @param dh head number / @param dl drive number / @return number of sectors actually read -pcread: push %bx - xor %bx,%bx - mov XLM(DRIVE_LAST_SECTOR),%bl - cmp %ax,%bx # ax = min(ax, pertrack) - ja 1f - mov %bx,%ax -1: push %cx # how many sectors until 64k - push %ax # boundary reads can't cross - mov $0x1000,%bx # canonicalizing the segment - mov %es,%ax # register is not sufficient - sub %ax,%bx - and $0x0fff,%bx - mov $5,%cx -0: shr %bx - loop 0b - pop %ax - pop %cx - test %bx,%bx # %es 64k-aligned edge case - jz 1f - cmp %ax,%bx # ax = min(ax, remain64k) - ja 1f - mov %bx,%ax -1: push %ax # setup int-13-2() params +pcread: push %ax push %cx xchg %cl,%ch ror %cl ror %cl - or $1,%cl # one cylinder at a time + or %al,%cl xor %bx,%bx # es:bx is destination addr - mov $0x02,%ah # read disk sectors ordinal + mov $1,%al # read only one disk sector + mov $2,%ah # read disk sectors ordinal int $0x13 pop %cx - pop %bx + pop %ax jc 9f - mov $0,%ah - cmp %ax,%bx - jl 9f + mov %es,%si + add $512>>4,%si + mov %si,%es + inc %al + cmp XLM(DRIVE_LAST_SECTOR),%al + jbe 2f + mov $1,%al inc %cx cmp XLM(DRIVE_LAST_CYLINDER),%cx - jle 2f + jbe 2f xor %cx,%cx inc %dh -2: pop %bx - ret +2: ret 9: push %ax xor %ax,%ax # try disk reset on error int $0x13 @@ -824,11 +782,11 @@ ape.pe: .ascin "PE",4 .long 0 # Checksum .short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console .short .LDLLEXE # DllCharacteristics - .quad 0x0000000000100000 # StackReserve - .quad 0x0000000000100000 # StackCommit - .quad 0x0000000000000000 # HeapReserve - .quad 0x0000000000000000 # HeapCommit - .long 0x00000000 # LoaderFlags + .quad 0x0000000000080000 # StackReserve + .quad 0x0000000000080000 # StackCommit + .quad 0 # HeapReserve + .quad 0 # HeapCommit + .long 0 # LoaderFlags .long 16 # NumberOfDirectoryEntries .long 0,0 # ExportsDirectory .long RVA(idata.idt) # ImportsDirectory @@ -857,10 +815,10 @@ ape.pe: .ascin "PE",4 .stub .Lape.text.rva,long # Relative Virtual Address .stub .Lape.text.filesz,long # Physical Size .stub .Lape.text.offset,long # Physical Offset - .long 0x00000000 # Relocation Table Offset - .long 0x00000000 # Line Number Table Offset - .short 0x0000 # Relocation Count - .short 0x0000 # Line Number Count + .long 0 # Relocation Table Offset + .long 0 # Line Number Table Offset + .short 0 # Relocation Count + .short 0 # Line Number Count .long .LPETEXT # Flags .previous @@ -870,10 +828,10 @@ ape.pe: .ascin "PE",4 .stub .Lape.ram.rva,long # Relative Virtual Address .stub .Lape.ram.filesz,long # Physical Size .stub .Lape.ram.offset,long # Physical Offset - .long 0x00000000 # Relocation Table Offset - .long 0x00000000 # Line Number Table Offset - .short 0x0000 # Relocation Count - .short 0x0000 # Line Number Count + .long 0 # Relocation Table Offset + .long 0 # Line Number Table Offset + .short 0 # Relocation Count + .short 0 # Line Number Count .long .LPEDATA # Flags .previous @@ -1246,7 +1204,8 @@ sflush: mov %si,%cx mov $UART_TTYIDL,%ah 1: in %dx,%al and %ah,%al - rep nop # todo(jart): interrupts are better + rep + nop jz 1b loop 0b 2: ret @@ -1269,7 +1228,8 @@ sputc: push %ax 1: in %dx,%al and %ah,%al jnz 2f - rep nop # todo(jart): interrupts are better + rep + nop jmp 1b 2: mov %di,%ax mov %si,%dx @@ -1356,7 +1316,7 @@ longmodeloader: call e820 jc 9f call unreal - call hiload +/ call hiload jmp golong 9: mov $REAL(.Lstr.e820),%ax call rldie @@ -1478,8 +1438,9 @@ hiload: push %bx mov $v_ape_highsectors,%di # then copy rest off disk mov $REAL_SCRATCH_AREA>>4,%ax # to real memory buffer mov %ax,%es - mov XLM(LOADSTATE)+0,%cx - mov XLM(LOADSTATE)+2,%dx + mov XLM(LOADSTATE)+0,%ax + mov XLM(LOADSTATE)+2,%cx + mov XLM(LOADSTATE)+4,%dx 0: test %di,%di jz 9f mov %di,%ax @@ -1590,6 +1551,7 @@ pinit: push %ds add $0x1000,%eax add $8,%si loop 0b + movb $0,0 # unmap null pop %ds movl $TIP-0x4000,XLM(PAGE_TABLE_STACK_POINTER) # STACK→XLM mov $TIP-0x1000,%eax # PML4T→CR3 @@ -1631,13 +1593,13 @@ long: push $GDT_LONG_DATA xor %ebp,%ebp mov $REAL_STACK_FRAME+FRAMESIZE,%esp call __map_image - ezlea _metal,ax + ezlea metal,ax jmp *%rax .endfn long / Long mode in virtual address space. / @noreturn -_metal: +metal: #if USE_SYMBOL_HACK .byte 0x0f,0x1f,0207 # nop rdi binbase .long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512 @@ -1658,7 +1620,7 @@ _metal: push $0 # argc xor %edi,%edi jmp _start - .endfn _metal + .endfn metal / Avoid linker script variables appearing as code in objdump. .macro .ldsvar name:req diff --git a/ape/ape.lds b/ape/ape.lds index d8857c56..046e1707 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -537,7 +537,8 @@ HIDDEN(.Lape.bss.align = .Lape.data.align); /* Program Loader Auto-Tune */ HIDDEN(v_ape_realsectors = MIN(REAL_SCRATCH_AREA - IMAGE_BASE_REAL, - ROUNDUP(RVA(_edata), 512)) / 512); + ROUNDUP(RVA(_edata), 4096)) / 512); +HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512)); HIDDEN(v_ape_highsectors = (ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors); diff --git a/ape/config.h b/ape/config.h index 8c4b35f1..f51cc072 100644 --- a/ape/config.h +++ b/ape/config.h @@ -126,7 +126,7 @@ #define XLM_BADIDT 0x2230 #define XLM_BADIDT_SIZE 6 #define XLM_LOADSTATE 0x2240 -#define XLM_LOADSTATE_SIZE 4 +#define XLM_LOADSTATE_SIZE 6 #define XLM_SIZE ROUNDUP(XLM_LOADSTATE + XLM_LOADSTATE_SIZE, 0x1000) #define IMAGE_BASE_REAL (XLM_BASE_REAL + XLM_SIZE) diff --git a/ape/lib/mapimage.c b/ape/lib/mapimage.c index bc3d0629..0961fa5b 100644 --- a/ape/lib/mapimage.c +++ b/ape/lib/mapimage.c @@ -25,12 +25,11 @@ textreal static void __map_segment(uint64_t k, uint64_t a, uint64_t b) { uint64_t *e; for (; a < b; a += 0x1000) { e = getpagetableentry(IMAGE_BASE_VIRTUAL + a, 3, &g_pml4t, &g_ptsp_xlm); - *e = (IMAGE_BASE_PHYSICAL + a) | k; + *e = (IMAGE_BASE_REAL + a) | k; } } textreal void __map_image(void) { - pageunmap(0); __map_segment(PAGE_V | PAGE_U, 0, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL); __map_segment(PAGE_V | PAGE_U | PAGE_RW | PAGE_XD, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL, diff --git a/build/archive b/build/archive index a72c39c4..f7fed175 100755 --- a/build/archive +++ b/build/archive @@ -4,57 +4,28 @@ # # OVERVIEW # -# GNU Archiver Veneer +# Cosmopolitan Archiver # # DESCRIPTION # -# This script wraps normal archive commands that're transparently -# passed-through. It adds value too, by addressing difficulties -# that would normally cause a developer to need `make clean`. +# This goes 100x faster than ar and ranlib. # # EXAMPLE # -# build/archive ar rcsD library.a foo.o ... +# build/archive rcsD library.a foo.o ... -if [ ! -d o/third_party/gcc ]; then - third_party/gcc/unbundle.sh -fi - -export LC_ALL=C -RM=${RM:-$(command -v rm) -f} || exit MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit - -AR=$1 -ARFLAGS=$2 -OUT=$3 -shift 3 - -# remove directory arguments (having .a targets depend on dirs is what -# lets them be invalidated by deleted files) -FIRST=1 -for x; do - if [ $FIRST -eq 1 ]; then - set -- - FIRST=0 - fi - if [ -d "$x" ]; then - if [ -f "$OUT" ] && [ "$x" -nt "$OUT" ]; then - $RM "$OUT" - fi - continue - fi - if [ "$x" != "${x%.o}" ]; then - set -- "$@" "$x" - fi -done - -set -- "$AR" "$ARFLAGS" "$OUT" "$@" -printf %s\\n "$*" >"$OUT.cmd" - -OUTDIR="${OUT%/*}" -if [ "$OUTDIR" != "$OUT" ] && [ ! -d "$OUTDIR" ]; then - $MKDIR "$OUTDIR" || exit 2 +# if [ -x "o/$MODE/tool/build/ar.com" ]; then +# set -- "o/$MODE/tool/build/ar.com" "$@" +# else +if [ ! -x o/build/bootstrap/ar.com ]; then + mkdir -p o/build/bootstrap && + cp -f build/bootstrap/ar.com o/build/bootstrap/ar.com.$$ && + mv -f o/build/bootstrap/ar.com.$$ o/build/bootstrap/ar.com || exit fi +set -- o/build/bootstrap/ar.com "$@" +# fi +OUT=$3 printf "$LOGFMT" "${ACTION:-ARCHIVE.a}" "$OUT" >&2 # if [ "$SILENT" = "0" ]; then diff --git a/build/bootstrap/ar.com b/build/bootstrap/ar.com new file mode 100755 index 00000000..9bad4cd1 Binary files /dev/null and b/build/bootstrap/ar.com differ diff --git a/build/definitions.mk b/build/definitions.mk index e983c6e2..139f213e 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -65,7 +65,7 @@ CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++ CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd -AR = o/third_party/gcc/bin/x86_64-linux-musl-ar +AR = build/archive NM = o/third_party/gcc/bin/x86_64-linux-musl-nm GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip @@ -295,7 +295,7 @@ PREPROCESS.lds = $(CC) $(PREPROCESS.lds.flags) LINK = build/link $(LD) $(LINK.flags) ELF = o/libc/elf/elf.lds ELFLINK = ACTION=LINK.elf $(LINK) $(LINKARGS) $(OUTPUT_OPTION) -ARCHIVE = build/archive $(AR) $(ARFLAGS) +ARCHIVE = $(AR) $(ARFLAGS) LINKARGS = $(patsubst %.lds,-T %.lds,$(call uniqr,$(LD.libs) $(filter-out %.pkg,$^))) LOLSAN = build/lolsan -b $(IMAGE_BASE_VIRTUAL) diff --git a/examples/printmysymbols.c b/examples/printmysymbols.c index 64cd0cdf..16869424 100644 --- a/examples/printmysymbols.c +++ b/examples/printmysymbols.c @@ -23,7 +23,7 @@ int main(int argc, char *argv[]) { (tab = OpenSymbolTable(filename))) { for (unsigned i = 0; i < tab->count; ++i) { printf("%p %s\n", tab->addr_base + tab->symbols[i].addr_rva, - getelfstring(tab->elf, tab->elfsize, tab->name_base, + GetElfString(tab->elf, tab->elfsize, tab->name_base, tab->symbols[i].name_rva)); } } else { diff --git a/libc/bits/bits.h b/libc/bits/bits.h index 31742e7d..a43606ab 100644 --- a/libc/bits/bits.h +++ b/libc/bits/bits.h @@ -148,6 +148,36 @@ unsigned long hamming(unsigned long, unsigned long) pureconst; Ple[7] = (uint8_t)(Vle >> 070); \ } while (0) +#define WRITE16BE(P, V) \ + do { \ + uint8_t *Ple = (uint8_t *)(P); \ + uint16_t Vle = (V); \ + Ple[1] = (uint8_t)(Vle >> 000); \ + Ple[0] = (uint8_t)(Vle >> 010); \ + } while (0) +#define WRITE32BE(P, V) \ + do { \ + uint8_t *Ple = (uint8_t *)(P); \ + uint32_t Vle = (V); \ + Ple[3] = (uint8_t)(Vle >> 000); \ + Ple[2] = (uint8_t)(Vle >> 010); \ + Ple[1] = (uint8_t)(Vle >> 020); \ + Ple[0] = (uint8_t)(Vle >> 030); \ + } while (0) +#define WRITE64BE(P, V) \ + do { \ + uint8_t *Ple = (uint8_t *)(P); \ + uint64_t Vle = (V); \ + Ple[7] = (uint8_t)(Vle >> 000); \ + Ple[6] = (uint8_t)(Vle >> 010); \ + Ple[5] = (uint8_t)(Vle >> 020); \ + Ple[4] = (uint8_t)(Vle >> 030); \ + Ple[3] = (uint8_t)(Vle >> 040); \ + Ple[2] = (uint8_t)(Vle >> 050); \ + Ple[1] = (uint8_t)(Vle >> 060); \ + Ple[0] = (uint8_t)(Vle >> 070); \ + } while (0) + /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § bits » some assembly required ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ diff --git a/libc/calls/calls.h b/libc/calls/calls.h index ac13bf8e..ff0aa62e 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -79,12 +79,12 @@ bool isexecutable(const char *); bool isregularfile(const char *); bool32 isatty(int) nosideeffect; bool32 ischardev(int) nosideeffect; +char *commandv(const char *, char[hasatleast PATH_MAX]); char *get_current_dir_name(void) nodiscard; char *getcwd(char *, size_t); char *realpath(const char *, char *); char *replaceuser(const char *) nodiscard; char *ttyname(int); -char *commandv(const char *, char[hasatleast PATH_MAX]); int access(const char *, int) nothrow; int arch_prctl(); int chdir(const char *); @@ -120,6 +120,8 @@ int fstat(int, struct stat *); int fstatat(int, const char *, struct stat *, uint32_t); int fsync(int); int ftruncate(int, int64_t); +int getdomainname(char *, size_t); +int gethostname(char *, size_t); int getppid(void); int getpriority(int, unsigned); int getrlimit(int, struct rlimit *); @@ -161,18 +163,18 @@ int rmdir(const char *); int sched_getaffinity(int, uint64_t, void *); int sched_setaffinity(int, uint64_t, const void *); int sched_yield(void); +int setegid(uint32_t); +int seteuid(uint32_t); +int setgid(uint32_t); int setpgid(int, int); int setpriority(int, unsigned, int); +int setregid(uint32_t, uint32_t); +int setresgid(uint32_t, uint32_t, uint32_t); +int setresuid(uint32_t, uint32_t, uint32_t); +int setreuid(uint32_t, uint32_t); int setrlimit(int, const struct rlimit *); int setsid(void); int setuid(uint32_t); -int setgid(uint32_t); -int seteuid(uint32_t); -int setegid(uint32_t); -int setreuid(uint32_t, uint32_t); -int setregid(uint32_t, uint32_t); -int setresuid(uint32_t, uint32_t, uint32_t); -int setresgid(uint32_t, uint32_t, uint32_t); int sigaction(int, const struct sigaction *, struct sigaction *); int sigignore(int); int sigprocmask(int, const struct sigset *, struct sigset *); @@ -200,6 +202,7 @@ int64_t preadv(int, struct iovec *, int, int64_t); int64_t pwrite(int, const void *, size_t, int64_t); int64_t pwritev(int, const struct iovec *, int, int64_t); int64_t syscall(); +void sync(void); long telldir(DIR *); int getpid(void); long times(struct tms *); diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index dd4b8d58..9ad430aa 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -16,10 +16,10 @@ LIBC_CALLS_ARTIFACTS += LIBC_CALLS_A LIBC_CALLS = $(LIBC_CALLS_A_DEPS) $(LIBC_CALLS_A) LIBC_CALLS_A = o/$(MODE)/libc/calls/syscalls.a LIBC_CALLS_A_FILES := \ + $(wildcard libc/calls/*) \ $(wildcard libc/calls/typedef/*) \ $(wildcard libc/calls/thunks/*) \ - $(wildcard libc/calls/struct/*) \ - $(wildcard libc/calls/*) + $(wildcard libc/calls/struct/*) LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES)) diff --git a/libc/calls/getdomainname.c b/libc/calls/getdomainname.c new file mode 100644 index 00000000..626bbc0a --- /dev/null +++ b/libc/calls/getdomainname.c @@ -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 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/utsname.h" +#include "libc/dce.h" +#include "libc/macros.h" +#include "libc/nt/enum/computernameformat.h" +#include "libc/nt/errors.h" +#include "libc/nt/runtime.h" +#include "libc/nt/systeminfo.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +int getdomainname(char *name, size_t len) { + uint32_t nSize; + char16_t name16[256]; + struct utsname u; + if (len < 1) return einval(); + if (!name) return efault(); + if (!IsWindows()) { + if (uname(&u) == -1) return -1; + if (!memccpy(name, u.domainname[0] ? u.domainname : u.nodename, '\0', + len)) { + name[len - 1] = '\0'; + } + return 0; + } else { + nSize = ARRAYLEN(name16); + if (!GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) { + return winerr(); + } + tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16); + return 0; + } +} diff --git a/libc/calls/gethostname.c b/libc/calls/gethostname.c new file mode 100644 index 00000000..c3fc401e --- /dev/null +++ b/libc/calls/gethostname.c @@ -0,0 +1,58 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/utsname.h" +#include "libc/dce.h" +#include "libc/macros.h" +#include "libc/nt/enum/computernameformat.h" +#include "libc/nt/errors.h" +#include "libc/nt/runtime.h" +#include "libc/nt/systeminfo.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +/** + * Returns name of host system, e.g. + * + * pheidippides.domain.example + * ^^^^^^^^^^^^ + */ +int gethostname(char *name, size_t len) { + uint32_t nSize; + char16_t name16[256]; + struct utsname u; + if (len < 1) return einval(); + if (!name) return efault(); + if (!IsWindows()) { + if (uname(&u) == -1) return -1; + if (!memccpy(name, u.nodename, '\0', len)) { + name[len - 1] = '\0'; + } + return 0; + } else { + nSize = ARRAYLEN(name16); + if (!GetComputerNameEx(kNtComputerNameDnsHostname, name16, &nSize)) { + return winerr(); + } + tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16); + return 0; + } +} diff --git a/libc/calls/getntsyspath.S b/libc/calls/getntsyspath.S index 58d4d03a..9ec99129 100644 --- a/libc/calls/getntsyspath.S +++ b/libc/calls/getntsyspath.S @@ -49,7 +49,7 @@ __getntsyspath: cmpb $'\\,-1(%rdi) jne 2f movb $'/,-1(%rdi) -2: loop 1b +2: .loop 1b leave ret .endfn __getntsyspath,globl,hidden diff --git a/libc/calls/internal.h b/libc/calls/internal.h index d742e24f..ce52ae9b 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -161,6 +161,7 @@ i32 sigaction$sysv(i32, const void *, void *, i64) hidden; i32 sigprocmask$sysv(i32, const sigset *, sigset *, u64) hidden; i32 sigsuspend$sysv(const sigset *, u64) hidden; i32 symlinkat$sysv(const char *, i32, const char *) hidden; +i32 sync$sysv(void) hidden; i32 sync_file_range$sysv(i32, i64, i64, u32) hidden; i32 sysinfo$sysv(struct sysinfo *) hidden; i32 truncate$sysv(const char *, u64) hidden; @@ -239,6 +240,7 @@ int rename$nt(const char *, const char *) hidden; int rmdir$nt(const char *) hidden; int sched_yield$nt(void) hidden; int stat$nt(const char *, struct stat *) hidden; +int sync$nt(void) hidden; int symlink$nt(const char *, const char *) hidden; int sysinfo$nt(struct sysinfo *) hidden; int truncate$nt(const char *, u64) hidden; diff --git a/libc/calls/renameat.c b/libc/calls/renameat.c index 21503785..a8c760b7 100644 --- a/libc/calls/renameat.c +++ b/libc/calls/renameat.c @@ -21,6 +21,9 @@ #include "libc/calls/internal.h" #include "libc/sysv/consts/at.h" +/** + * Renames files relative to directories. + */ int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { unsigned mode; diff --git a/libc/calls/sync-nt.c b/libc/calls/sync-nt.c new file mode 100644 index 00000000..6df5e383 --- /dev/null +++ b/libc/calls/sync-nt.c @@ -0,0 +1,54 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/nt/createfile.h" +#include "libc/nt/files.h" +#include "libc/nt/runtime.h" +#include "libc/sysv/consts/ok.h" + +/** + * Flushes all open file handles and, if possible, all disk drives. + */ +int sync$nt(void) { + unsigned i; + int64_t volume; + uint32_t drives; + char16_t path[] = u"\\\\.\\C:"; + for (i = 0; i < g_fds.n; ++i) { + if (g_fds.p[i].kind == kFdFile) { + FlushFileBuffers(g_fds.p[i].handle); + } + } + for (drives = GetLogicalDrives(), i = 0; i <= 'Z' - 'A'; ++i) { + if (!(drives & (1 << i))) continue; + path[4] = 'A' + i; + if (ntaccesscheck(path, R_OK | W_OK) != -1) { + if ((volume = CreateFile( + path, kNtFileReadAttributes, + kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0, + kNtOpenExisting, 0, 0)) != -1) { + FlushFileBuffers(volume); + CloseHandle(volume); + } + } + } + return 0; +} diff --git a/libc/runtime/getstack.c b/libc/calls/sync.c similarity index 81% rename from libc/runtime/getstack.c rename to libc/calls/sync.c index 013aea32..348d7aaa 100644 --- a/libc/runtime/getstack.c +++ b/libc/calls/sync.c @@ -18,19 +18,16 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/prot.h" +#include "libc/calls/internal.h" +#include "libc/dce.h" /** - * Allocates deterministic stack for process. - * @see _executive() + * Flushes file system changes to disk to the greatest extent possible. */ -void *_getstack(void) { - char *p; - p = mmap((char *)0x700000000000 /* IMAGE_BASE_VIRTUAL */ - STACKSIZE, - STACKSIZE, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) abort(); - return p + STACKSIZE; +void sync(void) { + if (!IsWindows()) { + sync$sysv(); + } else { + sync$nt(); + } } diff --git a/libc/conv/itoa.h b/libc/conv/itoa.h index 10918dba..d5f79bd1 100644 --- a/libc/conv/itoa.h +++ b/libc/conv/itoa.h @@ -22,6 +22,7 @@ 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]); size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t); +size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]); #ifndef __STRICT_ANSI__ size_t int128toarray_radix10(int128_t, char *); diff --git a/libc/elf/getelfsectionbyaddress.c b/libc/conv/itoa64radix8.c similarity index 79% rename from libc/elf/getelfsectionbyaddress.c rename to libc/conv/itoa64radix8.c index a37b50c5..3fb18d78 100644 --- a/libc/elf/getelfsectionbyaddress.c +++ b/libc/conv/itoa64radix8.c @@ -17,21 +17,24 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/elf/def.h" -#include "libc/elf/elf.h" +#include "libc/alg/reverse.h" +#include "libc/conv/conv.h" +#include "libc/conv/itoa.h" +#include "libc/limits.h" -Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *elf, size_t mapsize, - void *addr) { - Elf64_Half i; - Elf64_Shdr *shdr; - if (elf) { - for (i = elf->e_shnum; i > 0; --i) { - shdr = getelfsectionheaderaddress(elf, mapsize, i - 1); - if ((intptr_t)addr >= shdr->sh_addr && - (intptr_t)addr < shdr->sh_addr + shdr->sh_size) { - return shdr; - } - } - } - return NULL; +/** + * Converts unsigned 64-bit integer to octal string. + * @param a needs at least 24 bytes + * @return bytes written w/o nul + */ +noinline size_t uint64toarray_radix8(uint64_t i, char a[hasatleast 24]) { + size_t j; + j = 0; + do { + a[j++] = i % 8 + '0'; + i /= 8; + } while (i > 0); + a[j] = '\0'; + reverse(a, j); + return j; } diff --git a/libc/elf/elf.h b/libc/elf/elf.h index 2a5da336..155dfa03 100644 --- a/libc/elf/elf.h +++ b/libc/elf/elf.h @@ -20,10 +20,9 @@ COSMOPOLITAN_C_START_ struct MappedFile; Elf64_Ehdr *mapelfread(const char *, struct MappedFile *); -char *getelfstringtable(const Elf64_Ehdr *, size_t); -Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *); -Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *); -bool iself64binary(const Elf64_Ehdr *, size_t); +char *GetElfStringTable(const Elf64_Ehdr *, size_t); +Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *); +bool IsElf64Binary(const Elf64_Ehdr *, size_t); forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, size_t addrsize) { @@ -94,7 +93,7 @@ static inline void getelfvirtualaddressrange(const Elf64_Ehdr *elf, if (out_end) *out_end = end; } -static inline char *getelfstring(const Elf64_Ehdr *elf, size_t mapsize, +static inline char *GetElfString(const Elf64_Ehdr *elf, size_t mapsize, const char *strtab, Elf64_Word rva) { intptr_t addr = (intptr_t)strtab + rva; #if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) @@ -105,10 +104,10 @@ static inline char *getelfstring(const Elf64_Ehdr *elf, size_t mapsize, return (char *)addr; } -static inline const char *getelfsectionname(const Elf64_Ehdr *elf, +static inline const char *GetElfSectionName(const Elf64_Ehdr *elf, size_t mapsize, Elf64_Shdr *shdr) { if (!elf || !shdr) return NULL; - return getelfstring(elf, mapsize, getelfsectionnamestringtable(elf, mapsize), + return GetElfString(elf, mapsize, getelfsectionnamestringtable(elf, mapsize), shdr->sh_name); } diff --git a/libc/elf/getelfstringtable.c b/libc/elf/getelfstringtable.c index bea8bb87..365e895d 100644 --- a/libc/elf/getelfstringtable.c +++ b/libc/elf/getelfstringtable.c @@ -20,7 +20,7 @@ #include "libc/elf/def.h" #include "libc/elf/elf.h" -char *getelfstringtable(const Elf64_Ehdr *elf, size_t mapsize) { +char *GetElfStringTable(const Elf64_Ehdr *elf, size_t mapsize) { Elf64_Half i; Elf64_Shdr *shdr; for (i = elf->e_shnum; i > 0; --i) { diff --git a/libc/elf/getelfsymboltable.c b/libc/elf/getelfsymboltable.c index 40457c4f..f0e60765 100644 --- a/libc/elf/getelfsymboltable.c +++ b/libc/elf/getelfsymboltable.c @@ -20,7 +20,7 @@ #include "libc/elf/def.h" #include "libc/elf/elf.h" -Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *elf, size_t mapsize, +Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, size_t mapsize, Elf64_Xword *out_count) { Elf64_Half i; Elf64_Shdr *shdr; diff --git a/libc/elf/iself64binary.c b/libc/elf/iself64binary.c index 5c61f4eb..c45717f3 100644 --- a/libc/elf/iself64binary.c +++ b/libc/elf/iself64binary.c @@ -19,7 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/elf/elf.h" -bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) { +bool IsElf64Binary(const Elf64_Ehdr *elf, size_t mapsize) { if (mapsize < sizeof(Elf64_Ehdr)) return false; if (memcmp(elf->e_ident, ELFMAG, 4)) return false; return (elf->e_ident[EI_CLASS] == ELFCLASSNONE || diff --git a/libc/elf/struct/sym.h b/libc/elf/struct/sym.h index c33f625b..faf45e6c 100644 --- a/libc/elf/struct/sym.h +++ b/libc/elf/struct/sym.h @@ -10,6 +10,7 @@ typedef struct Elf64_Sym { uint8_t st_info; /* STV_{DEFAULT,INTERNAL,HIDDEN,PROTECTED} */ uint8_t st_other; + /* SHN_UNDEF,
, SHN_ABS, SHN_COMMON, etc. */ Elf64_Section st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; diff --git a/libc/fmt/strerror_r.c b/libc/fmt/strerror_r.c index 436876f8..739871b4 100644 --- a/libc/fmt/strerror_r.c +++ b/libc/fmt/strerror_r.c @@ -63,7 +63,7 @@ int strerror_r(int err, char *buf, size_t size) { if (FormatMessage( kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, NULL, err, 0, buf16, ARRAYLEN(buf16) - 1, 0) > 0) { - chomp(buf16); + chomp16(buf16); } else { buf16[0] = u'\0'; } diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 292299fb..8fdb46a4 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -152,6 +152,7 @@ relegated static void ShowMemoryMappings(int outfd) { relegated static void ShowCrashReport(int err, int fd, int sig, ucontext_t *ctx) { + int i; struct utsname names; (dprintf)(fd, VEIL("r", "\r\n%serror%s: Uncaught SIG%s\r\n %s\r\n %s\r\n"), RED2, RESET, TinyStrSignal(sig), getauxval(AT_EXECFN), @@ -167,6 +168,11 @@ relegated static void ShowCrashReport(int err, int fd, int sig, } write(fd, "\r\n", 2); ShowMemoryMappings(fd); + write(fd, "\r\n", 2); + for (i = 0; i < g_argc; ++i) { + write(fd, g_argv[i], strlen(g_argv[i])); + write(fd, "\r\n", 2); + } } relegated static void RestoreDefaultCrashSignalHandlers(void) { diff --git a/libc/macros.inc b/libc/macros.inc index 06525302..9aaccaed 100644 --- a/libc/macros.inc +++ b/libc/macros.inc @@ -186,10 +186,10 @@ .endif .endm -/ Overrides LOOP instruction. +/ LOOP Instruction Replacement. / With its mop-Fusion Mexican equivalent. / Thus avoiding 3x legacy pipeline slowdown. -.macro loop label:req +.macro .loop label:req .byte 0x83,0xe9,0x01 # sub $1,%ecx jnz \label .endm diff --git a/libc/nexgen32e/crc32init.S b/libc/nexgen32e/crc32init.S index 435caa00..6e2a9701 100644 --- a/libc/nexgen32e/crc32init.S +++ b/libc/nexgen32e/crc32init.S @@ -59,7 +59,7 @@ crc32init: pand %xmm0,%xmm3 pxor %xmm4,%xmm3 movdqa %xmm3,%xmm4 - loop 2b + .loop 2b movdqu %xmm3,(%rdi) add $16,%rdi paddd %xmm2,%xmm1 diff --git a/libc/nexgen32e/imapxlatab.S b/libc/nexgen32e/imapxlatab.S index ca1ac009..3cd46224 100644 --- a/libc/nexgen32e/imapxlatab.S +++ b/libc/nexgen32e/imapxlatab.S @@ -35,7 +35,7 @@ imapxlatab: .align 8 1: stosq add %rdx,%rax - loop 1b + .loop 1b .leafepilogue .endfn imapxlatab,globl,hidden .source __FILE__ diff --git a/libc/nexgen32e/kbase36.S b/libc/nexgen32e/kbase36.S index 38965f59..5ee59c31 100644 --- a/libc/nexgen32e/kbase36.S +++ b/libc/nexgen32e/kbase36.S @@ -35,13 +35,13 @@ kBase36:.zero 256 pushpop 10,%rcx 0: inc %eax stosb - loop 0b + .loop 0b add $'A-1-'9,%rdi pushpop 'Z+1-'A,%rcx 0: inc %eax mov %al,0x20(%rdi) stosb - loop 0b + .loop 0b add $255-'Z,%rdi .init.end 300,_init_kBase36 .source __FILE__ diff --git a/libc/nexgen32e/ktolower.S b/libc/nexgen32e/ktolower.S index 5352947e..6974aff0 100644 --- a/libc/nexgen32e/ktolower.S +++ b/libc/nexgen32e/ktolower.S @@ -51,7 +51,7 @@ kToLower16: mov $256,%ecx 0: lodsb stosw - loop 0b + .loop 0b pop %rsi .init.end 300,_init_kToLower diff --git a/libc/nexgen32e/ktoupper.S b/libc/nexgen32e/ktoupper.S index 9fdd95d1..cb088654 100644 --- a/libc/nexgen32e/ktoupper.S +++ b/libc/nexgen32e/ktoupper.S @@ -30,6 +30,6 @@ kToUpper: call imapxlatab pushpop 'z-'a,%rcx 0: subb $0x20,(%r8,%rcx) - loop 0b + .loop 0b .init.end 300,_init_kToUpper .source __FILE__ diff --git a/libc/nexgen32e/memjmpinit.S b/libc/nexgen32e/memjmpinit.S index 352d86da..79c08a30 100644 --- a/libc/nexgen32e/memjmpinit.S +++ b/libc/nexgen32e/memjmpinit.S @@ -36,7 +36,7 @@ memjmpinit: lodsb add %rdx,%rax stosq - loop 0b + .loop 0b xor %eax,%eax testb X86_HAVE(ERMS)+kCpuids(%rip) setnz %al diff --git a/libc/nexgen32e/rldecode.S b/libc/nexgen32e/rldecode.S index 2041f2fc..1bad8e9a 100644 --- a/libc/nexgen32e/rldecode.S +++ b/libc/nexgen32e/rldecode.S @@ -34,7 +34,7 @@ rldecode: lodsb jrcxz 2f 1: stosb - loop 1b + .loop 1b jmp 0b 2: .leafepilogue .endfn rldecode,globl diff --git a/libc/nt/KernelBase/GetComputerNameExW.s b/libc/nt/KernelBase/GetComputerNameExW.s index 05bea6ac..e1e49668 100644 --- a/libc/nt/KernelBase/GetComputerNameExW.s +++ b/libc/nt/KernelBase/GetComputerNameExW.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .imp KernelBase,__imp_GetComputerNameExW,GetComputerNameExW,449 + + .text.windows +GetComputerNameEx: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_GetComputerNameExW(%rip),%rax + jmp __sysv2nt + .endfn GetComputerNameEx,globl + .previous diff --git a/libc/nt/enum/computernameformat.h b/libc/nt/enum/computernameformat.h new file mode 100644 index 00000000..4854d5ed --- /dev/null +++ b/libc/nt/enum/computernameformat.h @@ -0,0 +1,16 @@ +#ifndef COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_ +#define COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) + +#define kNtComputerNameNetBios 0 +#define kNtComputerNameDnsHostname 1 +#define kNtComputerNameDnsDomain 2 +#define kNtComputerNameDnsFullyQualified 3 +#define kNtComputerNamePhysicalNetBios 4 +#define kNtComputerNamePhysicalDnsHostname 5 +#define kNtComputerNamePhysicalDnsDomain 6 +#define kNtComputerNamePhysicalDnsFullyQualified 7 +#define kNtComputerName_MAX 8 + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_ */ diff --git a/libc/nt/master.sh b/libc/nt/master.sh index f1dd08e4..aeaf143b 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -1979,7 +1979,7 @@ imp 'GetCompressedFileSizeTransactedA' GetCompressedFileSizeTransactedA kern imp 'GetCompressedFileSizeTransacted' GetCompressedFileSizeTransactedW kernel32 479 imp 'GetComputerNameA' GetComputerNameA kernel32 481 imp 'GetComputerNameExA' GetComputerNameExA KernelBase 448 -imp 'GetComputerNameEx' GetComputerNameExW KernelBase 449 +imp 'GetComputerNameEx' GetComputerNameExW KernelBase 449 3 imp 'GetComputerName' GetComputerNameW kernel32 484 imp 'GetConsoleAliasA' GetConsoleAliasA KernelBase 450 imp 'GetConsoleAliasExesA' GetConsoleAliasExesA KernelBase 451 diff --git a/libc/nt/memory.h b/libc/nt/memory.h index 8a91fab7..ba7c1689 100644 --- a/libc/nt/memory.h +++ b/libc/nt/memory.h @@ -46,12 +46,14 @@ int64_t CreateFileMappingNuma( const struct NtSecurityAttributes *opt_lpFileMappingAttributes, uint32_t flProtect, uint32_t dwMaximumSizeHigh, uint32_t dwMaximumSizeLow, const char16_t *opt_lpName, uint32_t nndDesiredNumaNode); + void *MapViewOfFileExNuma( int64_t hFileMappingObject, /* @see CreateFileMapping() */ uint32_t dwDesiredAccess, uint32_t dwFileOffsetHigh, /* high order bits */ uint32_t dwFileOffsetLow, /* low order bits */ size_t dwNumberOfBytesToMap, void *opt_lpDesiredBaseAddress, uint32_t nndDesiredNumaNode); + bool32 UnmapViewOfFile(const void *lpBaseAddress); bool32 FlushViewOfFile(const void *lpBaseAddress, size_t dwNumberOfBytesToFlush); diff --git a/libc/nt/nt.mk b/libc/nt/nt.mk index 2035ee2e..0ff9f354 100644 --- a/libc/nt/nt.mk +++ b/libc/nt/nt.mk @@ -152,6 +152,8 @@ $(LIBC_NT_NTDLL_A): \ libc/nt/ntdll/ \ $(LIBC_NT_NTDLL_A).pkg \ $(LIBC_NT_NTDLL_A_OBJS) + @$(file >$@.cmd) $(file >>$@.cmd,$(ARCHIVE) $@ $^ >$(LIBC_NT_NTDLL_A).cmd) + @$(ARCHIVE) $@ $^ $(LIBC_NT_NTDLL_A).pkg: \ $(LIBC_NT_NTDLL_A_OBJS) \ diff --git a/libc/nt/systeminfo.h b/libc/nt/systeminfo.h index 99e0ee12..f53219d4 100644 --- a/libc/nt/systeminfo.h +++ b/libc/nt/systeminfo.h @@ -13,6 +13,9 @@ uint32_t GetSystemDirectoryA(char *lpBuffer, uint32_t uSize); uint32_t GetWindowsDirectory(char16_t *lpBuffer, uint32_t uSize); uint32_t GetTempPath(uint32_t uSize, char16_t *lpBuffer); +bool32 GetComputerNameEx(/* enum/computernameformat.h */ int NameType, + char16_t *opt_lpBuffer, uint32_t *nSize); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/systeminfo.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/runtime/directmap.c b/libc/runtime/directmap.c index 22e7f972..8ffcbeae 100644 --- a/libc/runtime/directmap.c +++ b/libc/runtime/directmap.c @@ -38,8 +38,8 @@ static textwindows struct DirectMap DirectMapNt(void *addr, size_t size, protect = prot2nt(prot, flags); access = fprot2nt(prot, flags); if ((res.maphandle = - CreateFileMappingNuma(handle, &kNtIsInheritable, protect, size >> 32, - size, NULL, kNtNumaNoPreferredNode))) { + CreateFileMappingNuma(handle, NULL, protect, size >> 32, size, NULL, + kNtNumaNoPreferredNode))) { if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off, size, addr, kNtNumaNoPreferredNode))) { CloseHandle(res.maphandle); diff --git a/libc/runtime/executive.S b/libc/runtime/executive.S index 92ae7d43..e9caa82c 100644 --- a/libc/runtime/executive.S +++ b/libc/runtime/executive.S @@ -42,16 +42,13 @@ _executive: mov %rdx,%r14 mov %rcx,%r15 call _spawn - call _getstack - mov %rax,%rdi + mov %r12d,%edi + mov %r13,%rsi + mov %r14,%rdx + mov %r15,%rcx .weak main - mov $main,%esi - mov %r12,%rdx - mov %r13,%rcx - mov %r14,%r8 - mov %r15,%r9 - call _setstack - mov %eax,%edi + call main + xchg %eax,%edi call exit .endfn _executive,weak,hidden ud2 diff --git a/libc/runtime/internal.h b/libc/runtime/internal.h index dacac5bb..34447bed 100644 --- a/libc/runtime/internal.h +++ b/libc/runtime/internal.h @@ -25,6 +25,7 @@ void *__cxa_finalize(void *) hidden; void _executive(int, char **, char **, long (*)[2]) hidden noreturn; void __stack_chk_fail(void) noreturn relegated; void __stack_chk_fail_local(void) noreturn relegated hidden; +long _setstack(void *, void *, ...) hidden; int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden; forceinline void AssertNeverCalledWhileTerminating(void) { diff --git a/libc/runtime/mapelfread.c b/libc/runtime/mapelfread.c index 6a59ed39..0d40fb0e 100644 --- a/libc/runtime/mapelfread.c +++ b/libc/runtime/mapelfread.c @@ -22,7 +22,7 @@ #include "libc/runtime/ezmap.h" Elf64_Ehdr *mapelfread(const char *filename, struct MappedFile *mf) { - if (mapfileread(filename, mf) != -1 && iself64binary(mf->addr, mf->size)) { + if (mapfileread(filename, mf) != -1 && IsElf64Binary(mf->addr, mf->size)) { return mf->addr; } else { unmapfile(mf); diff --git a/libc/runtime/msync.c b/libc/runtime/msync.c index 27c53e03..0a6dd802 100644 --- a/libc/runtime/msync.c +++ b/libc/runtime/msync.c @@ -27,7 +27,9 @@ /** * Synchronize memory mapping changes to disk. * - * @param flags needs MS_SYNC or MS_ASYNC and can have MS_INVALIDATE + * Without this, there's no guarantee memory is written back to disk. + * + * @param flags needs MS_ASYNC or MS_SYNC and can have MS_INVALIDATE * @return 0 on success or -1 w/ errno */ int msync(void *addr, size_t size, int flags) { diff --git a/libc/runtime/opensymboltable.c b/libc/runtime/opensymboltable.c index b2e46f21..9e2d3c81 100644 --- a/libc/runtime/opensymboltable.c +++ b/libc/runtime/opensymboltable.c @@ -39,8 +39,8 @@ struct SymbolTable *OpenSymbolTable(const char *filename) { t = MAP_FAILED; if (filename && (t = mapanon(BIGPAGESIZE)) != MAP_FAILED && mapelfread(filename, &t->mf) && - (t->name_base = getelfstringtable(t->elf, t->elfsize)) != NULL && - (symtab = getelfsymboltable(t->elf, t->elfsize, &t->count)) && + (t->name_base = GetElfStringTable(t->elf, t->elfsize)) != NULL && + (symtab = GetElfSymbolTable(t->elf, t->elfsize, &t->count)) && sizeof(struct SymbolTable) + sizeof(struct Symbol) * t->count < (t->scratch = BIGPAGESIZE)) { getelfvirtualaddressrange(t->elf, t->elfsize, &t->addr_base, &t->addr_end); diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index fcb11eb8..a185c093 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -43,7 +43,6 @@ void longjmp(jmp_buf, int) libcesque noreturn paramsnonnull(); void exit(int) noreturn; void _exit(int) libcesque noreturn; void _Exit(int) libcesque noreturn; -long _setstack(void *, void *, ...); void abort(void) noreturn noinstrument; void panic(void) noreturn noinstrument privileged; void triplf(void) noreturn noinstrument privileged; diff --git a/libc/runtime/setstack.S b/libc/runtime/setstack.S index f3d3f134..711433b7 100644 --- a/libc/runtime/setstack.S +++ b/libc/runtime/setstack.S @@ -24,7 +24,7 @@ / @param rdi is new rsp, passed as malloc(size) + size / @param rsi is function to call in new stack space / @param rdx,rcx,r8,r9 get passed as args to rsi -/ @return happens on original stack +/ @return rax and happens on original stack _setstack: push %rbp mov %rsp,%rbp @@ -43,4 +43,4 @@ _setstack: pop %rbx pop %rbp ret - .endfn _setstack,globl + .endfn _setstack,globl,hidden diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 5a26b133..3b4a099a 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -25,7 +25,9 @@ #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/enum/loadlibrarysearch.h" +#include "libc/nt/enum/pageflags.h" #include "libc/nt/files.h" +#include "libc/nt/memory.h" #include "libc/nt/pedef.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" @@ -117,10 +119,10 @@ static textwindows void NormalizeCmdExe(void) { * 3. Environment variables are passed to us as a sorted UTF-16 double * NUL terminated list. We translate this to char ** using UTF-8. * - * 4. NT likes to choose a stack address that's beneath the program - * image. We want to be able to assume that stack addresses are - * located at higher addresses than heap and program memory. So the - * _executive() function will switch stacks appropriately. + * 4. Allocates new stack at a high address. NT likes to choose a + * stack address that's beneath the program image. We want to be + * able to assume that stack addresses are located at higher + * addresses than heap and program memory. * * 5. Windows users are afraid of "drive-by downloads" where someone * might accidentally an evil DLL to their Downloads folder which @@ -131,21 +133,27 @@ static textwindows void NormalizeCmdExe(void) { */ textwindows int WinMain(void *hInstance, void *hPrevInstance, const char *lpCmdLine, int nCmdShow) { + char *stack; int i, count; const char16_t *cmd16, *env16; - char *argarray[512], *envarray[512]; + char *argv[512], *envp[512]; char argblock[ARG_MAX], envblock[ENV_MAX]; - long auxarray[][2] = {{pushpop(0L), pushpop(0L)}}; + long auxv[][2] = {{pushpop(0L), pushpop(0L)}}; MitigateDriveByDownloads(); NormalizeCmdExe(); *(/*unconst*/ int *)&hostos = WINDOWS; cmd16 = GetCommandLine(); env16 = GetEnvironmentStrings(); - count = GetDosArgv(cmd16, argblock, ARG_MAX, argarray, 512); - for (i = 0; argarray[0][i]; ++i) { - if (argarray[0][i] == '\\') argarray[0][i] = '/'; + count = GetDosArgv(cmd16, argblock, ARG_MAX, argv, 512); + for (i = 0; argv[0][i]; ++i) { + if (argv[0][i] == '\\') argv[0][i] = '/'; } - GetDosEnviron(env16, envblock, ENV_MAX, envarray, 512); + GetDosEnviron(env16, envblock, ENV_MAX, envp, 512); FreeEnvironmentStrings(env16); - _executive(count, argarray, envarray, auxarray); + stack = MapViewOfFileExNuma( + CreateFileMappingNuma(-1, NULL, pushpop(kNtPageReadwrite), 0, STACKSIZE, + NULL, kNtNumaNoPreferredNode), + kNtFileMapRead | kNtFileMapWrite, 0, 0, STACKSIZE, + (char *)0x777000000000 - STACKSIZE, kNtNumaNoPreferredNode); + return _setstack(stack + STACKSIZE, _executive, count, argv, envp, auxv); } diff --git a/libc/str/str.h b/libc/str/str.h index f30a1565..5d87cb0c 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -256,97 +256,6 @@ bool luhn(const char *); char *strsignal(int) returnsnonnull libcesque; -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § strings » hooks ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -extern int (*const hook$strcmp16)(const char16_t *, const char16_t *); -extern int (*const hook$strncmp16)(const char16_t *, const char16_t *, size_t); -extern int (*const hook$wcscmp)(const wchar_t *, const wchar_t *); -extern int (*const hook$wcsncmp)(const wchar_t *, const wchar_t *, size_t); -#define __STR_HOOK(SYMBOL) hook$##SYMBOL -#else -#define __STR_HOOK(SYMBOL) SYMBOL -#endif /* GNUC && !ANSI */ - -/* TODO(jart): Use @gotpcrel. */ -#undef __STR_HOOK -#define __STR_HOOK(SYMBOL) SYMBOL - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § strings » generic typing ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#if __STDC_VERSION__ + 0 >= 201112 - -#define strnlen(s, n) \ - _Generic(*(s), wchar_t \ - : wcsnlen, char16_t \ - : strnlen16, default \ - : strnlen)(s, n) - -#define strnlen_s(s, n) \ - _Generic(*(s), wchar_t \ - : wcsnlen_s, char16_t \ - : strnlen16_s, default \ - : strnlen_s)(s, n) - -#define strpbrk(s, c) \ - _Generic(*(s), wchar_t \ - : wcspbrk, char16_t \ - : strpbrk16, default \ - : strpbrk)(s, c) - -#define strspn(s, c) \ - _Generic(*(s), wchar_t : wcsspn, char16_t : strspn16, default : strspn)(s, c) - -#define strcspn(s, c) \ - _Generic(*(s), wchar_t \ - : wcscspn, char16_t \ - : strcspn16, default \ - : strcspn)(s, c) - -/* clang-format off */ -#define strcmp(s1, s2) \ - _Generic((s1)[0], \ - wchar_t: __STR_HOOK(wcscmp), \ - char16_t: _Generic(*(s2), \ - char: strcmp16to8, \ - default: __STR_HOOK(strcmp16)), \ - default: _Generic(*(s2), \ - char16_t: strcmp8to16, \ - default: strcmp))(s1, s2) -/* clang-format on */ - -#define strncmp(s1, s2, n) \ - _Generic(*(s1), wchar_t \ - : __STR_HOOK(wcsncmp), char16_t \ - : _Generic(*(s2), char \ - : strncmp16to8, default \ - : __STR_HOOK(strncmp16)), \ - default \ - : _Generic(*(s2), char16_t \ - : strncmp8to16, default \ - : strncmp))(s1, s2, n) - -#define strcasecmp(s1, s2) \ - _Generic(*(s1), wchar_t \ - : wcscasecmp, char16_t \ - : strcasecmp16, default \ - : strcasecmp)(s1, s2) - -#define strncasecmp(s1, s2, n) \ - _Generic(*(s1), wchar_t \ - : wcsncasecmp, char16_t \ - : strncasecmp16, default \ - : strncasecmp)(s1, s2, n) - -#define chomp(s) \ - _Generic(*(s), wchar_t : wchomp, char16_t : chomp16, default : chomp)(s) - -#endif /* C11 */ - /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § strings » optimizations ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ diff --git a/libc/str/strcspn.c b/libc/str/strcspn.c index 89bc647e..322f700f 100644 --- a/libc/str/strcspn.c +++ b/libc/str/strcspn.c @@ -28,7 +28,7 @@ * @see strspn(), strtok_r() * @asyncsignalsafe */ -size_t(strcspn)(const char *s, const char *reject) { +size_t strcspn(const char *s, const char *reject) { size_t i; for (i = 0; s[i]; ++i) { if (HasCharacter(s[i], reject)) { diff --git a/libc/str/strcspn16.c b/libc/str/strcspn16.c index 46096f56..56b25e9e 100644 --- a/libc/str/strcspn16.c +++ b/libc/str/strcspn16.c @@ -20,9 +20,20 @@ #include "libc/nexgen32e/hascharacter.h" #include "libc/str/str.h" -#undef strcspn -#define char char16_t -#define HasCharacter HasCharacter16 -#define strcspn strcspn16 - -#include "libc/str/strcspn.c" +/** + * Returns prefix length, consisting of chars not in reject. + * a.k.a. Return index of first byte that's in charset. + * + * @param reject is nul-terminated character set + * @see strspn(), strtok_r() + * @asyncsignalsafe + */ +size_t strcspn16(const char16_t *s, const char16_t *reject) { + size_t i; + for (i = 0; s[i]; ++i) { + if (HasCharacter16(s[i], reject)) { + break; + } + } + return i; +} diff --git a/libc/str/wcscspn.c b/libc/str/wcscspn.c index b25cdb09..351e414c 100644 --- a/libc/str/wcscspn.c +++ b/libc/str/wcscspn.c @@ -20,9 +20,20 @@ #include "libc/nexgen32e/hascharacter.h" #include "libc/str/str.h" -#undef strcspn -#define char wchar_t -#define HasCharacter HasCharacterWide -#define strcspn wcscspn - -#include "libc/str/strcspn.c" +/** + * Returns prefix length, consisting of chars not in reject. + * a.k.a. Return index of first byte that's in charset. + * + * @param reject is nul-terminated character set + * @see strspn(), strtok_r() + * @asyncsignalsafe + */ +size_t wcscspn(const wchar_t *s, const wchar_t *reject) { + size_t i; + for (i = 0; s[i]; ++i) { + if (HasCharacterWide(s[i], reject)) { + break; + } + } + return i; +} diff --git a/libc/sysv/calls/gethostname.s b/libc/sysv/calls/gethostname.s deleted file mode 100644 index 10dcf7ff..00000000 --- a/libc/sysv/calls/gethostname.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.inc" -.scall gethostname 0xffff0057ffffffff globl diff --git a/libc/sysv/calls/sync-sysv.s b/libc/sysv/calls/sync-sysv.s new file mode 100644 index 00000000..3866fc77 --- /dev/null +++ b/libc/sysv/calls/sync-sysv.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.inc" +.scall sync$sysv 0x00240024202400a2 globl hidden diff --git a/libc/sysv/calls/sync.s b/libc/sysv/calls/sync.s deleted file mode 100644 index 133639cc..00000000 --- a/libc/sysv/calls/sync.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.inc" -.scall sync 0x00240024202400a2 globl diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index ecf0d77a..7156acf8 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -178,7 +178,7 @@ scall mlockall 0x010f014421440097 globl scall munlockall 0x0110014521450098 globl scall 'setrlimit$sysv' 0x00c300c320c300a0 globl hidden scall chroot 0x003d003d203d00a1 globl -scall sync 0x00240024202400a2 globl +scall 'sync$sysv' 0x00240024202400a2 globl hidden scall acct 0x00330033203300a3 globl scall settimeofday 0x0044007a207a00a4 globl scall mount 0x0015001520a700a5 globl @@ -649,10 +649,10 @@ scall fhlinkat 0xffff0236ffffffff globl scall fhreadlink 0xffff0237ffffffff globl scall getaudit 0xffff01c1ffffffff globl scall getcontext 0xffff01a5ffffffff globl -scall getdomainname 0xffff00a2ffffffff globl +#scall getdomainname 0xffff00a2ffffffff globl scall getfhat 0xffff0234ffffffff globl scall gethostid 0xffff008effffffff globl -scall gethostname 0xffff0057ffffffff globl +#scall gethostname 0xffff0057ffffffff globl scall getkerninfo 0xffff003fffffffff globl scall getloginclass 0xffff020bffffffff globl scall 'getpagesize$freebsd' 0xffff0040ffffffff globl hidden diff --git a/tool/build/ar.c b/tool/build/ar.c new file mode 100644 index 00000000..af4d73cc --- /dev/null +++ b/tool/build/ar.c @@ -0,0 +1,255 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/arraylist2.h" +#include "libc/bits/bits.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/iovec.h" +#include "libc/calls/struct/stat.h" +#include "libc/conv/conv.h" +#include "libc/conv/itoa.h" +#include "libc/elf/def.h" +#include "libc/elf/elf.h" +#include "libc/errno.h" +#include "libc/log/check.h" +#include "libc/macros.h" +#include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/madv.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "libc/x/x.h" + +/** + * @fileoverview System Five Static Archive Builder. + * + * GNU ar has a bug which causes it to take hundreds of milliseconds to + * build archives like ntdll.a and several minutes for cosmopolitan.a. + * This goes quadratically faster taking 1ms to do ntdll w/ hot cache. + * + * Compared to LLVM ar this tool goes 10x faster because it uses madvise + * and copy_file_range which give us the optimal page cached file system + * beahvior that a build environment needs. + * + * This tool also adds a feature: it ignores directory parameters. This + * is important because good Makefiles on Linux will generally have the + * directory be a .a prerequisite so archives rebuild on file deletion. + */ + +struct String { + size_t i, n; + char *p; +}; + +struct Ints { + size_t i, n; + int *p; +}; + +struct Header { + char name[16]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char fmag[2]; +}; + +static void MakeHeader(struct Header *h, const char *name, int ref, int mode, + int size) { + size_t n; + char buf[21]; + memset(h, ' ', sizeof(*h)); + n = strlen(name); + memcpy(h->name, name, n); + if (ref != -1) { + memcpy(h->name + n, buf, uint64toarray_radix10(ref, buf)); + } + if (strcmp(name, "//") != 0) { + h->date[0] = '0'; + h->uid[0] = '0'; + h->gid[0] = '0'; + memcpy(h->mode, buf, uint64toarray_radix8(mode & 0777, buf)); + } + h->fmag[0] = '`'; + h->fmag[1] = '\n'; + memcpy(h->size, buf, uint64toarray_radix10(size, buf)); +} + +int main(int argc, char *argv[]) { + void *elf; + char *strs; + ssize_t rc; + struct stat *st; + uint32_t outpos; + Elf64_Sym *syms; + uint64_t outsize; + char **objectargs; + uint8_t *tablebuf; + struct iovec iov[7]; + const char *symname; + Elf64_Xword symcount; + struct Ints symnames; + struct String symbols; + struct String filenames; + const char *options, *outpath; + struct Header *header1, *header2; + size_t wrote, remain, objectargcount; + int *offsets, *modes, *sizes, *names; + int i, j, fd, err, name, outfd, tablebufsize; + + st = xmalloc(sizeof(struct stat)); + symbols.i = 0; + symbols.n = 4096; + symbols.p = xmalloc(symbols.n); + filenames.i = 0; + filenames.n = 1024; + filenames.p = xmalloc(filenames.n); + symnames.i = 0; + symnames.n = 1024; + symnames.p = xmalloc(symnames.n * sizeof(int)); + + CHECK_GT(argc, 3); + options = argv[1]; + outpath = argv[2]; + objectargs = argv + 3; + objectargcount = argc - 3; + CHECK_EQ(0, strcmp(options, "rcsD")); + modes = xmalloc(sizeof(int) * objectargcount); + names = xmalloc(sizeof(int) * objectargcount); + sizes = xmalloc(sizeof(int) * objectargcount); + + // load global symbols and populate page cache + for (i = 0; i < objectargcount; ++i) { + TryAgain: + CHECK_NE(-1, (fd = open(objectargs[i], O_RDONLY))); + CHECK_NE(-1, fstat(fd, st)); + CHECK_LT(st->st_size, 0x7ffff000); + if (!st->st_size || S_ISDIR(st->st_mode) || + endswith(objectargs[i], ".pkg")) { + close(fd); + for (j = i; j + 1 < objectargcount; ++j) { + objectargs[j] = objectargs[j + 1]; + } + --objectargcount; + goto TryAgain; + } + names[i] = filenames.i; + sizes[i] = st->st_size; + modes[i] = st->st_mode; + CONCAT(&filenames.p, &filenames.i, &filenames.n, basename(objectargs[i]), + strlen(basename(objectargs[i]))); + CONCAT(&filenames.p, &filenames.i, &filenames.n, "/\n", 2); + CHECK_NE(MAP_FAILED, + (elf = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0))); + madvise(elf, st->st_size, MADV_WILLNEED); + CHECK(IsElf64Binary(elf, st->st_size)); + CHECK_NOTNULL((strs = GetElfStringTable(elf, st->st_size))); + CHECK_NOTNULL((syms = GetElfSymbolTable(elf, st->st_size, &symcount))); + for (j = 0; j < symcount; ++j) { + if (syms[j].st_shndx == SHN_UNDEF) continue; + if (syms[j].st_other == STV_INTERNAL) continue; + if (ELF64_ST_BIND(syms[j].st_info) == STB_LOCAL) continue; + symname = GetElfString(elf, st->st_size, strs, syms[j].st_name); + CONCAT(&symbols.p, &symbols.i, &symbols.n, symname, strlen(symname) + 1); + APPEND(&symnames.p, &symnames.i, &symnames.n, &i); + } + CHECK_NE(-1, munmap(elf, st->st_size)); + close(fd); + } + APPEND(&filenames.p, &filenames.i, &filenames.n, "\n"); + + // compute length of output archive + outsize = 0; + tablebufsize = 4 + symnames.i * 4; + tablebuf = xmalloc(tablebufsize); + offsets = xmalloc(objectargcount * 4); + header1 = xmalloc(sizeof(struct Header)); + header2 = xmalloc(sizeof(struct Header)); + iov[0].iov_base = "!\n"; + outsize += (iov[0].iov_len = 8); + iov[1].iov_base = header1; + outsize += (iov[1].iov_len = 60); + iov[2].iov_base = tablebuf; + outsize += (iov[2].iov_len = tablebufsize); + iov[3].iov_base = symbols.p; + outsize += (iov[3].iov_len = symbols.i); + iov[4].iov_base = "\n"; + outsize += (iov[4].iov_len = outsize & 1); + iov[5].iov_base = header2; + outsize += (iov[5].iov_len = 60); + iov[6].iov_base = filenames.p; + outsize += (iov[6].iov_len = filenames.i); + for (i = 0; i < objectargcount; ++i) { + outsize += outsize & 1; + offsets[i] = outsize; + outsize += 60; + outsize += sizes[i]; + } + CHECK_LE(outsize, 0x7ffff000); + + // serialize metadata + MakeHeader(header1, "/", -1, 0, tablebufsize + symbols.i); + MakeHeader(header2, "//", -1, 0, filenames.i); + WRITE32BE(tablebuf, symnames.i); + for (i = 0; i < symnames.i; ++i) { + WRITE32BE(tablebuf + 4 + i * 4, offsets[symnames.p[i]]); + } + + // write output archive + CHECK_NE(-1, (outfd = open(outpath, O_WRONLY | O_TRUNC | O_CREAT, 0644))); + ftruncate(outfd, outsize); + if ((outsize = writev(outfd, iov, ARRAYLEN(iov))) == -1) goto fail; + for (i = 0; i < objectargcount; ++i) { + if ((fd = open(objectargs[i], O_RDONLY)) == -1) goto fail; + iov[0].iov_base = "\n"; + outsize += (iov[0].iov_len = outsize & 1); + iov[1].iov_base = header1; + outsize += (iov[1].iov_len = 60); + MakeHeader(header1, "/", names[i], modes[i], sizes[i]); + if (writev(outfd, iov, 2) == -1) goto fail; + outsize += (remain = sizes[i]); + if (copy_file_range(fd, NULL, outfd, NULL, remain, 0) != remain) goto fail; + close(fd); + } + close(outfd); + + free(header2); + free(header1); + free(offsets); + free(tablebuf); + free(sizes); + free(names); + free(modes); + free(symbols.p); + free(filenames.p); + free(symnames.p); + free(st); + return 0; + +fail: + err = errno; + if (!err) err = 1; + unlink(outpath); + fputs("error: ar failed\n", stderr); + return err; +} diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 36b4f3d8..9ef52f53 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -21,6 +21,7 @@ #include "dsp/tty/tty.h" #include "libc/alg/arraylist2.h" #include "libc/assert.h" +#include "libc/bits/bits.h" #include "libc/bits/safemacros.h" #include "libc/calls/calls.h" #include "libc/calls/ioctl.h" @@ -165,7 +166,7 @@ FEATURES\n\ struct MemoryView { int64_t start; - unsigned zoom; + int zoom; }; struct MachineState { @@ -1158,10 +1159,17 @@ static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, int64_t a) { } } -static void ZoomMemoryView(struct MemoryView *v, int dy) { - v->start *= (DUMPWIDTH * (1ull << v->zoom)); - v->zoom = MIN(MAXZOOM, MAX(0, v->zoom + dy)); - v->start /= (DUMPWIDTH * (1ull << v->zoom)); +static void ZoomMemoryView(struct MemoryView *v, long y, long x, int dy) { + long a, b, i, s; + s = v->start; + a = v->zoom; + b = MIN(MAXZOOM, MAX(0, a + dy)); + i = y * DUMPWIDTH - x; + s *= DUMPWIDTH * (1L << a); + s += i * (1L << a) - i * (1L << b); + s /= DUMPWIDTH * (1L << b); + v->zoom = b; + v->start = s; } static void ScrollMemoryViews(void) { @@ -1171,15 +1179,15 @@ static void ScrollMemoryViews(void) { ScrollMemoryView(&pan.stack, &stackview, GetSp()); } -static void ZoomMemoryViews(struct Panel *p, int dy) { +static void ZoomMemoryViews(struct Panel *p, int y, int x, int dy) { if (p == &pan.code) { - ZoomMemoryView(&codeview, dy); + ZoomMemoryView(&codeview, y, x, dy); } else if (p == &pan.readdata) { - ZoomMemoryView(&readview, dy); + ZoomMemoryView(&readview, y, x, dy); } else if (p == &pan.writedata) { - ZoomMemoryView(&writeview, dy); + ZoomMemoryView(&writeview, y, x, dy); } else if (p == &pan.stack) { - ZoomMemoryView(&stackview, dy); + ZoomMemoryView(&stackview, y, x, dy); } } @@ -1798,14 +1806,18 @@ static void OnDiskServiceGetParams(void) { static void OnDiskServiceReadSectors(void) { static int x; uint64_t addr, size; - int64_t drive, head, track, sector, offset; + int64_t sectors, drive, head, track, sector, offset; + sectors = m->ax[0]; drive = m->dx[0]; head = m->dx[1]; track = (m->cx[0] & 0b11000000) << 2 | m->cx[1]; sector = (m->cx[0] & 0b00111111) - 1; offset = head * track * sector * 512; - size = m->ax[0] * 512; + size = sectors * 512; offset = sector * 512 + track * 512 * 63 + head * 512 * 63 * 1024; + VERBOSEF("bios read sectors %d " + "@ sector %ld track %ld head %ld drive %ld offset %#lx", + sectors, sector, track, head, drive, offset); if (0 <= sector && offset + size <= elf->mapsize) { addr = Read64(m->es) + Read16(m->bx); if (addr + size <= m->real.n) { @@ -1819,6 +1831,8 @@ static void OnDiskServiceReadSectors(void) { SetCarry(true); } } else { + WARNF("bios read sector failed 0 <= %d && %lx + %lx <= %lx", sector, offset, + size, elf->mapsize); m->ax[0] = 0x00; m->ax[1] = 0x0d; SetCarry(true); @@ -2074,7 +2088,9 @@ static void OnBinbase(struct Machine *m) { } static void OnLongBranch(struct Machine *m) { - Disassemble(); + if (tuimode) { + Disassemble(); + } } static void OnPageUp(void) { @@ -2098,20 +2114,28 @@ static void SetStatus(const char *fmt, ...) { setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL); } +static int ClampSpeed(int s) { + return MAX(-0x1000, MIN(0x40000000, s)); +} + static void OnTurbo(void) { - if (speed >= -1) { - speed = MIN(0x40000000, MAX(1, speed) << 1); // 1..40mips skip + if (!speed || speed == -1) { + speed = 1; + } else if (speed > 0) { + speed = ClampSpeed(speed << 1); } else { - speed >>= 1; + speed = ClampSpeed(speed >> 1); } SetStatus("speed %,d", speed); } static void OnSlowmo(void) { - if (speed > 0) { - speed >>= 1; + if (!speed || speed == 1) { + speed = -1; + } else if (speed > 0) { + speed = ClampSpeed(speed >> 1); } else { - speed = MAX(-(5 * 1000), MIN(-1, speed) << 1); // 1ms..5s delay + speed = ClampSpeed(speed << 1); } SetStatus("speed %,d", speed); } @@ -2221,7 +2245,7 @@ static void Sleep(int ms) { poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms); } -static void OnMouseWheelUp(struct Panel *p) { +static void OnMouseWheelUp(struct Panel *p, int y, int x) { if (p == &pan.disassembly) { opstart -= WHEELDELTA; } else if (p == &pan.code) { @@ -2241,7 +2265,7 @@ static void OnMouseWheelUp(struct Panel *p) { } } -static void OnMouseWheelDown(struct Panel *p) { +static void OnMouseWheelDown(struct Panel *p, int y, int x) { if (p == &pan.disassembly) { opstart += WHEELDELTA; } else if (p == &pan.code) { @@ -2261,12 +2285,12 @@ static void OnMouseWheelDown(struct Panel *p) { } } -static void OnMouseCtrlWheelUp(struct Panel *p) { - ZoomMemoryViews(p, -1); +static void OnMouseCtrlWheelUp(struct Panel *p, int y, int x) { + ZoomMemoryViews(p, y, x, -1); } -static void OnMouseCtrlWheelDown(struct Panel *p) { - ZoomMemoryViews(p, +1); +static void OnMouseCtrlWheelDown(struct Panel *p, int y, int x) { + ZoomMemoryViews(p, y, x, +1); } static struct Panel *LocatePanel(int y, int x) { @@ -2290,18 +2314,20 @@ static void OnMouse(char *p) { y = min(tyn, max(1, strtol(p, &p, 10))) - 1; e |= (*p == 'm') << 2; if ((ep = LocatePanel(y, x))) { + y -= ep->top; + x -= ep->left; switch (e) { case kMouseWheelUp: - OnMouseWheelUp(ep); + OnMouseWheelUp(ep, y, x); break; case kMouseWheelDown: - OnMouseWheelDown(ep); + OnMouseWheelDown(ep, y, x); break; case kMouseCtrlWheelUp: - OnMouseCtrlWheelUp(ep); + OnMouseCtrlWheelUp(ep, y, x); break; case kMouseCtrlWheelDown: - OnMouseCtrlWheelDown(ep); + OnMouseCtrlWheelDown(ep, y, x); break; default: break; diff --git a/tool/build/dropcache.c b/tool/build/dropcache.c new file mode 100644 index 00000000..c1b49116 --- /dev/null +++ b/tool/build/dropcache.c @@ -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 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/log/check.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +/** + * Removes file system caches from RAM. + * + * make o//tool/build/dropcache.com + * sudo mv o//tool/build/dropcache.com /usr/local/bin/ + * sudo chown root /usr/local/bin/dropcache.com + * sudo chmod u+s /usr/local/bin/dropcache.com + */ + +static void Write(int fd, const char *s) { + write(fd, s, strlen(s)); +} + +int main(int argc, char *argv[]) { + int fd; + sync(); + fd = open("/proc/sys/vm/drop_caches", O_WRONLY); + if (fd == -1) { + if (errno == EACCES) { + Write(1, "error: need root privileges\n"); + } else if (errno == ENOENT) { + Write(1, "error: need /proc filesystem\n"); + } + exit(1); + } + Write(fd, "3\n"); + close(fd); + return 0; +} diff --git a/tool/build/lib/diself.c b/tool/build/lib/diself.c index a5222162..9dab5071 100644 --- a/tool/build/lib/diself.c +++ b/tool/build/lib/diself.c @@ -74,8 +74,8 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) { const Elf64_Sym *st, *sym; bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject; j = 0; - if ((d->syms.stab = getelfstringtable(elf->ehdr, elf->size)) && - (st = getelfsymboltable(elf->ehdr, elf->size, &n))) { + if ((d->syms.stab = GetElfStringTable(elf->ehdr, elf->size)) && + (st = GetElfSymbolTable(elf->ehdr, elf->size, &n))) { stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab; if (d->syms.n < n) { d->syms.n = n; diff --git a/tool/build/lib/disspec.c b/tool/build/lib/disspec.c index 1e3d3e2e..2ded30e3 100644 --- a/tool/build/lib/disspec.c +++ b/tool/build/lib/disspec.c @@ -238,8 +238,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0xCB, "lret"); RCASE(0xCC, "int3"); RCASE(0xCD, "int Ib"); - RCASE(0xD0, "BIT Eb $1"); - RCASE(0xD1, "BIT Evqp $1"); + RCASE(0xD0, "BIT Eb"); + RCASE(0xD1, "BIT Evqp"); RCASE(0xD2, "BIT Evqp %cl"); RCASE(0xD3, "BIT Evqp %cl"); RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib"); diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index 34bb726b..6941826b 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -178,7 +178,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode) { void elfwriter_close(struct ElfWriter *elf) { size_t i; FlushTables(elf); - CHECK_NE(-1, msync(elf->map, elf->wrote, MS_SYNC)); + CHECK_NE(-1, msync(elf->map, elf->wrote, MS_ASYNC)); CHECK_NE(-1, munmap(elf->map, elf->mapsize)); CHECK_NE(-1, ftruncate(elf->fd, elf->wrote)); CHECK_NE(-1, close(elf->fd)); diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index df450c5f..95b315d7 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -137,40 +137,24 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, int fd; ssize_t rc; int64_t sp; - char *real; - void *stack; struct stat st; - size_t i, codesize, mappedsize, extrasize; + size_t i, mappedsize; DCHECK_NOTNULL(prog); elf->prog = prog; if ((fd = open(prog, O_RDONLY)) == -1 || - (fstat(fd, &st) == -1 || !st.st_size) /* || !S_ISREG(st.st_mode) */) { + (fstat(fd, &st) == -1 || !st.st_size)) { fputs(prog, stderr); fputs(": not found\n", stderr); exit(1); } - codesize = st.st_size; - elf->mapsize = ROUNDDOWN(codesize, FRAMESIZE); - extrasize = codesize - elf->mapsize; - elf->map = real = (char *)0x0000400000000000; - if (elf->mapsize) { - CHECK_NE(MAP_FAILED, mmap(real, elf->mapsize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_FIXED, fd, 0)); - real += elf->mapsize; - } - if (extrasize) { - CHECK_NE(MAP_FAILED, - mmap(real, ROUNDUP(extrasize, FRAMESIZE), PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)); - for (i = 0; i < extrasize; i += (size_t)rc) { - CHECK_NE(-1, (rc = pread(fd, real + i, extrasize - i, elf->mapsize + i))); - } - elf->mapsize += ROUNDUP(extrasize, FRAMESIZE); - } + elf->mapsize = st.st_size; + CHECK_NE(MAP_FAILED, + (elf->map = mmap(NULL, elf->mapsize, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0))); CHECK_NE(-1, close(fd)); ResetCpu(m); if ((m->mode & 3) == XED_MODE_REAL) { - BootProgram(m, elf, codesize); + BootProgram(m, elf, elf->mapsize); } else { sp = 0x800000000000; Write64(m->sp, sp); @@ -179,13 +163,13 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, LoadArgv(m, prog, args, vars); if (memcmp(elf->map, "\177ELF", 4) == 0) { elf->ehdr = (void *)elf->map; - elf->size = codesize; + elf->size = elf->mapsize; LoadElf(m, elf); } else { elf->base = IMAGE_BASE_VIRTUAL; elf->ehdr = NULL; elf->size = 0; - LoadBin(m, elf->base, prog, elf->map, codesize); + LoadBin(m, elf->base, prog, elf->map, elf->mapsize); } } } diff --git a/tool/build/package.c b/tool/build/package.c index bb6aa695..81a762a6 100644 --- a/tool/build/package.c +++ b/tool/build/package.c @@ -109,24 +109,24 @@ struct Packages { struct Package { uint32_t magic; int32_t abi; - uint32_t path; /* pkg->strings.p[path] */ - int64_t fd; /* not persisted */ - void *addr; /* not persisted */ - size_t size; /* not persisted */ + uint32_t path; // pkg->strings.p[path] + int64_t fd; // not persisted + void *addr; // not persisted + size_t size; // not persisted struct Strings { size_t i, n; - char *p; /* persisted as pkg+RVA */ - } strings; /* TODO(jart): interning? */ + char *p; // persisted as pkg+RVA + } strings; // TODO(jart): interning? struct Objects { size_t i, n; struct Object { - uint32_t path; /* pkg->strings.p[path] */ - int64_t fd; /* 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 */ + 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 { @@ -149,20 +149,20 @@ struct Packages { } * p; } ops; } * p; - } sections; /* not persisted */ - } * p; /* persisted as pkg+RVA */ + } sections; // not persisted + } * p; // persisted as pkg+RVA } objects; struct Symbols { size_t i, n; struct Symbol { - uint32_t name; /* pkg->strings.p[name] */ + uint32_t name; // pkg->strings.p[name] 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] + } * 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, @@ -265,7 +265,7 @@ void IndexSections(struct Object *obj) { memset(§, 0, 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))); + 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.")) || @@ -329,7 +329,7 @@ void LoadSymbols(struct Package *pkg, uint32_t object) { 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); + 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); @@ -347,23 +347,25 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot, int flags) { int fd; struct stat st; - CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], mode)), "path=%`'s", - &pkg->strings.p[obj->path]); + 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))); CHECK_NE(-1, close(fd)); - CHECK(iself64binary(obj->elf, obj->size), "path=%`'s", + CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s", &pkg->strings.p[obj->path]); - CHECK_NOTNULL((obj->strs = getelfstringtable(obj->elf, obj->size))); + CHECK_NOTNULL((obj->strs = GetElfStringTable(obj->elf, obj->size))); CHECK_NOTNULL( - (obj->syms = getelfsymboltable(obj->elf, obj->size, &obj->symcount))); + (obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount))); CHECK_NE(0, obj->symcount); IndexSections(obj); } void CloseObject(struct Object *obj) { - msync(obj->elf, obj->size, MS_SYNC); + if ((obj->mode & O_ACCMODE) != O_RDONLY) { + CHECK_NE(-1, msync(obj->elf, obj->size, MS_ASYNC | MS_INVALIDATE)); + } CHECK_NE(-1, munmap(obj->elf, obj->size)); } @@ -477,7 +479,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps, if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 || ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCREL) && FindSymbol( - getelfstring(obj->elf, obj->size, obj->strs, + GetElfString(obj->elf, obj->size, obj->strs, obj->syms[ELF64_R_SYM(rela->r_info)].st_name), pkg, deps, &refpkg, &refsym) && (refsym->kind == kData || refsym->kind == kBss) && @@ -500,7 +502,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps, * Then libc/runtime/ftrace.greg.c morphs it back at runtime. */ if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX && - strcmp(getelfstring(obj->elf, obj->size, obj->strs, + strcmp(GetElfString(obj->elf, obj->size, obj->strs, obj->syms[ELF64_R_SYM(rela->r_info)].st_name), "mcount") == 0) { rela->r_info = R_X86_64_NONE; @@ -518,7 +520,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps, */ if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 || ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) && - strcmp(getelfstring(obj->elf, obj->size, obj->strs, + strcmp(GetElfString(obj->elf, obj->size, obj->strs, obj->syms[ELF64_R_SYM(rela->r_info)].st_name), "mcount") == 0) { rela->r_info = R_X86_64_NONE; @@ -598,7 +600,7 @@ void CompressLowEntropyReadOnlyDataSections(struct Package *pkg, !(shdr->sh_flags & (SHF_WRITE | SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED))) && (p = getelfsectionaddress(obj->elf, obj->size, shdr)) && - startswith((name = getelfsectionname(obj->elf, obj->size, shdr)), + startswith((name = GetElfSectionName(obj->elf, obj->size, shdr)), ".rodata") && rlencode(&rle, p, shdr->sh_size) != -1) { isprofitable = rle.i * sizeof(rle.p[0]) <= shdr->sh_size / 2; diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index 69ec6152..397c808a 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -312,6 +312,7 @@ void zipobj(int argc, char **argv) { } int main(int argc, char **argv) { + showcrashreports(); zipobj(argc, argv); return 0; } diff --git a/tool/decode/ar.c b/tool/decode/ar.c new file mode 100644 index 00000000..1296ca6b --- /dev/null +++ b/tool/decode/ar.c @@ -0,0 +1,146 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/conv/conv.h" +#include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "libc/x/x.h" + +#define AR_MAGIC1 "!\n" +#define AR_MAGIC2 "`\n" + +/** + * ar rU doge.a NOTICE # create archive and use non-deterministic stuff + * o//tool/decode/ar.com doge.a + */ + +static int fd; +static uint8_t *data; +static long size; +static const char *path; +static struct stat st; + +static void PrintString(uint8_t *p, long n, const char *name) { + char *s; + s = xmalloc(n + 1); + s[n] = '\0'; + memcpy(s, p, n); + printf("\t.ascii\t%`'.*s\t\t\t# %s\n", n, s, name); + free(s); +} + +static void Open(void) { + if ((fd = open(path, O_RDONLY)) == -1) { + fprintf(stderr, "error: open() failed: %s\n", path); + exit(1); + } + CHECK_NE(-1, fstat(fd, &st)); + if (!(size = st.st_size)) exit(0); + CHECK_NE(MAP_FAILED, + (data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0))); + LOGIFNEG1(close(fd)); +} + +static void Close(void) { + LOGIFNEG1(munmap(data, size)); +} + +static void Check(void) { + if (size < 8 + 60 + 4 || + (memcmp(data, AR_MAGIC1, strlen(AR_MAGIC1)) != 0 || + memcmp(data + 66, AR_MAGIC2, strlen(AR_MAGIC2)) != 0)) { + fprintf(stderr, "error: not a unix archive: %s\n", path); + exit(1); + } +} + +static void PrintTable(void) { +} + +static void PrintHeader(uint8_t *p) { + PrintString(p + 0, 16, "file identifier [ascii]"); + PrintString(p + 16, 12, "file modification timestamp [decimal]"); + PrintString(p + 28, 6, "owner id [decimal]"); + PrintString(p + 34, 6, "group id [decimal]"); + PrintString(p + 40, 8, "file mode [octal] (type and permission)"); + PrintString(p + 48, 10, "file size in bytes [decimal]"); + PrintString(p + 58, 2, "ending characters"); +} + +static void Print(void) { + int arsize; + uint8_t *b, *p; + uint64_t offset; + uint32_t i, n, o, table, entries, symbols, symbolslen; + arsize = atoi((char *)(data + 8 + 48)); + CHECK_LE(4, arsize); + CHECK_LE(8 + 60 + arsize, size); + entries = read32be(data + 8 + 60); + CHECK_LE(4 + entries * 4 + 1, arsize); + printf("\t# %'s\n", path); + PrintString(data, 8, "file signature"); + PrintHeader(data + 8); + + printf("\n"); + printf("\t.long\t%u\t\t\t# %s\n", entries, "symbol table entries"); + table = 8 + 60 + 4; + for (i = 0; i < entries; ++i) { + printf("\t.long\t%#x\t\t\t\t# %u\n", read32be(data + table + i * 4), i); + } + symbols = table + entries * 4; + symbolslen = arsize - (4 + entries * 4); + for (i = o = 0; o < symbolslen; ++i, o += n + 1) { + b = data + symbols + o; + CHECK_NOTNULL((p = memchr(b, '\0', symbolslen - (symbols + o)))); + n = p - b; + printf("\t.asciz\t%#`'.*s\t\t\t# %u\n", n, b, i); + } + + offset = 8 + 60 + arsize; + while (offset < size) { + offset += offset & 1; + CHECK_LE(offset + 60, size); + CHECK_EQ(0, memcmp(data + offset + 58, AR_MAGIC2, strlen(AR_MAGIC2))); + arsize = atoi((char *)(data + offset + 48)); + CHECK_LE(offset + 60 + arsize, size); + printf("\n"); + PrintHeader(data + offset); + offset += 60 + arsize; + } +} + +int main(int argc, char *argv[]) { + if (argc < 2) return 1; + path = argv[1]; + Open(); + Check(); + Print(); + Close(); + return 0; +} diff --git a/tool/decode/elf.c b/tool/decode/elf.c index d09e62a3..739d7f5c 100644 --- a/tool/decode/elf.c +++ b/tool/decode/elf.c @@ -134,8 +134,8 @@ static void printelfsectionheader(int i, char *shstrtab) { printf(".Lsh%d:", i); show(".long", format(b1, "%d", shdr->sh_name), format(b2, - "%`'s == getelfstring(elf, st->st_size, shstrtab, shdr->sh_name)", - getelfstring(elf, st->st_size, shstrtab, shdr->sh_name))); + "%`'s == GetElfString(elf, st->st_size, shstrtab, shdr->sh_name)", + GetElfString(elf, st->st_size, shstrtab, shdr->sh_name))); show(".long", firstnonnull(findnamebyid(kElfSectionTypeNames, shdr->sh_type), format(b1, "%d", shdr->sh_type)), @@ -167,7 +167,7 @@ static void printelfsectionheaders(void) { ->sh_offset); for (i = 0; i < elf->e_shnum; ++i) { Elf64_Shdr *shdr = getelfsectionheaderaddress(elf, st->st_size, i); - const char *str = getelfstring(elf, st->st_size, shstrtab, shdr->sh_name); + const char *str = GetElfString(elf, st->st_size, shstrtab, shdr->sh_name); show(".asciz", format(b1, "%`'s", str), NULL); } } @@ -199,14 +199,14 @@ static void printelfsymbolother(Elf64_Sym *sym) { static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) { show(".long", format(b1, "%d", sym->st_name), format(b2, "%`'s (sym->st_name)", - getelfstring(elf, st->st_size, strtab, sym->st_name))); + GetElfString(elf, st->st_size, strtab, sym->st_name))); printelfsymbolinfo(sym); printelfsymbolother(sym); show(".short", format(b1, "%d", sym->st_shndx), format(b2, "%s sym->st_shndx", sym->st_shndx < 0xff00 ? format(b1, "%`'s", - getelfstring(elf, st->st_size, shstrtab, + GetElfString(elf, st->st_size, shstrtab, getelfsectionheaderaddress( elf, st->st_size, sym->st_shndx) ->sh_name)) @@ -217,8 +217,8 @@ static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) { static void printelfsymboltable(void) { size_t i, symcount = 0; - Elf64_Sym *symtab = getelfsymboltable(elf, st->st_size, &symcount); - char *strtab = getelfstringtable(elf, st->st_size); + Elf64_Sym *symtab = GetElfSymbolTable(elf, st->st_size, &symcount); + char *strtab = GetElfStringTable(elf, st->st_size); char *shstrtab = getelfsectionnamestringtable(elf, st->st_size); if (symtab && strtab) { printf("\n\n"); @@ -239,8 +239,8 @@ static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize, ((shstrtab && !sym->st_name && ELF64_ST_TYPE(sym->st_info) == STT_SECTION && (shdr = getelfsectionheaderaddress(elf, mapsize, sym->st_shndx)) && - (res = getelfstring(elf, mapsize, shstrtab, shdr->sh_name))) || - (strtab && (res = getelfstring(elf, mapsize, strtab, sym->st_name))))) { + (res = GetElfString(elf, mapsize, shstrtab, shdr->sh_name))) || + (strtab && (res = GetElfString(elf, mapsize, strtab, sym->st_name))))) { return res; } else { return NULL; @@ -254,13 +254,13 @@ static void printelfrelocations(void) { const Elf64_Rela *rela; const Elf64_Shdr *shdr, *boop; char *strtab, *shstrtab, *symbolname; - strtab = getelfstringtable(elf, st->st_size); + strtab = GetElfStringTable(elf, st->st_size); shstrtab = getelfsectionnamestringtable(elf, st->st_size); for (i = 0; i < elf->e_shnum; ++i) { if ((shdr = getelfsectionheaderaddress(elf, st->st_size, i)) && shdr->sh_type == SHT_RELA && (rela = getelfsectionaddress(elf, st->st_size, shdr))) { - printf("\n/\t%s\n", getelfsectionname(elf, st->st_size, shdr)); + printf("\n/\t%s\n", GetElfSectionName(elf, st->st_size, shdr)); printf("\t.org\t%#x\n", (intptr_t)rela - (intptr_t)elf); for (j = 0; ((uintptr_t)rela + sizeof(Elf64_Rela) <= min((uintptr_t)elf + st->st_size, @@ -272,7 +272,7 @@ static void printelfrelocations(void) { symbolname = getelfsymbolname(elf, st->st_size, strtab, shstrtab, &syms[sym]); printf("/\t%s+%#lx → %s%c%#lx\n", - getelfstring( + GetElfString( elf, st->st_size, shstrtab, getelfsectionheaderaddress(elf, st->st_size, shdr->sh_info) ->sh_name), diff --git a/tool/decode/lib/pollnames.S b/tool/decode/lib/pollnames.S index 052bf72c..7b0035dc 100644 --- a/tool/decode/lib/pollnames.S +++ b/tool/decode/lib/pollnames.S @@ -68,6 +68,6 @@ kPollNames: lodsl add %rbx,%rax # %rbx is image base (cosmo abi) stosq - loop 0b + .loop 0b add $16,%rdi .init.end 301,_init_kPollNames