From aea89fe832a9d141ac46e04cb970b4f9ba379b07 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Mon, 9 Nov 2020 15:41:11 -0800 Subject: [PATCH] Make minor improvements - Work towards simplifying ape.S startup process - Rewrote ar because it took minutes to build cosmopolitan.a --- ape/ape.S | 166 +++++------- ape/ape.lds | 3 +- ape/config.h | 2 +- ape/lib/mapimage.c | 3 +- build/archive | 55 +--- build/bootstrap/ar.com | Bin 0 -> 40960 bytes build/definitions.mk | 4 +- examples/printmysymbols.c | 2 +- libc/bits/bits.h | 30 +++ libc/calls/calls.h | 19 +- libc/calls/calls.mk | 4 +- libc/calls/getdomainname.c | 53 ++++ libc/calls/gethostname.c | 58 ++++ libc/calls/getntsyspath.S | 2 +- libc/calls/internal.h | 2 + libc/calls/renameat.c | 3 + libc/calls/sync-nt.c | 54 ++++ libc/{runtime/getstack.c => calls/sync.c} | 21 +- libc/conv/itoa.h | 1 + .../itoa64radix8.c} | 35 +-- libc/elf/elf.h | 13 +- libc/elf/getelfstringtable.c | 2 +- libc/elf/getelfsymboltable.c | 2 +- libc/elf/iself64binary.c | 2 +- libc/elf/struct/sym.h | 1 + libc/fmt/strerror_r.c | 2 +- libc/log/oncrash.c | 6 + libc/macros.inc | 4 +- libc/nexgen32e/crc32init.S | 2 +- libc/nexgen32e/imapxlatab.S | 2 +- libc/nexgen32e/kbase36.S | 4 +- libc/nexgen32e/ktolower.S | 2 +- libc/nexgen32e/ktoupper.S | 2 +- libc/nexgen32e/memjmpinit.S | 2 +- libc/nexgen32e/rldecode.S | 2 +- libc/nt/KernelBase/GetComputerNameExW.s | 10 + libc/nt/enum/computernameformat.h | 16 ++ libc/nt/master.sh | 2 +- libc/nt/memory.h | 2 + libc/nt/nt.mk | 2 + libc/nt/systeminfo.h | 3 + libc/runtime/directmap.c | 4 +- libc/runtime/executive.S | 15 +- libc/runtime/internal.h | 1 + libc/runtime/mapelfread.c | 2 +- libc/runtime/msync.c | 4 +- libc/runtime/opensymboltable.c | 4 +- libc/runtime/runtime.h | 1 - libc/runtime/setstack.S | 4 +- libc/runtime/winmain.greg.c | 30 ++- libc/str/str.h | 91 ------- libc/str/strcspn.c | 2 +- libc/str/strcspn16.c | 23 +- libc/str/wcscspn.c | 23 +- libc/sysv/calls/gethostname.s | 2 - libc/sysv/calls/sync-sysv.s | 2 + libc/sysv/calls/sync.s | 2 - libc/sysv/syscalls.sh | 6 +- tool/build/ar.c | 255 ++++++++++++++++++ tool/build/blinkenlights.c | 84 ++++-- tool/build/dropcache.c | 55 ++++ tool/build/lib/diself.c | 4 +- tool/build/lib/disspec.c | 4 +- tool/build/lib/elfwriter.c | 2 +- tool/build/lib/loader.c | 34 +-- tool/build/package.c | 66 ++--- tool/build/zipobj.c | 1 + tool/decode/ar.c | 146 ++++++++++ tool/decode/elf.c | 24 +- tool/decode/lib/pollnames.S | 2 +- 70 files changed, 1037 insertions(+), 456 deletions(-) create mode 100755 build/bootstrap/ar.com create mode 100644 libc/calls/getdomainname.c create mode 100644 libc/calls/gethostname.c create mode 100644 libc/calls/sync-nt.c rename libc/{runtime/getstack.c => calls/sync.c} (81%) rename libc/{elf/getelfsectionbyaddress.c => conv/itoa64radix8.c} (79%) create mode 100644 libc/nt/enum/computernameformat.h delete mode 100644 libc/sysv/calls/gethostname.s create mode 100644 libc/sysv/calls/sync-sysv.s delete mode 100644 libc/sysv/calls/sync.s create mode 100644 tool/build/ar.c create mode 100644 tool/build/dropcache.c create mode 100644 tool/decode/ar.c 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 0000000000000000000000000000000000000000..9bad4cd148b7b4fedfb421f212e703f177da3928 GIT binary patch literal 40960 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 literal 0 HcmV?d00001 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