/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ │vi: set et ft=asm ts=8 sw=8 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/dce.h" #include "libc/macros.h" .source __FILE__ /* ▄▄▄ ▄▄▄ ▀▓▓▒▄ ▄▓▒▒░ ▀▓▒▒▒▄ ▄▓▓▓▒▀ ▄▄▄▄ ▒▓▒▒░▒▄ ▄▓▓▓▒▓ ▄▄▓██▓▓▓▓▒▒▒▒▓▓▄▄▓▓▒▒▒░░▒ ▓▓▓▓▒▒▒▄▄ ░▒█▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▒░░▒░ ██▓▓▓▒▒░░▒▒▒▒▓▓▓▓▓▓▒▓▒░▒▒░▀▒▒▒▒░▀░▒▒▒░▒ ▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▒▓▓▒▒▒░▒▒░░ ░▒▒░ ░▒▒▒▒ ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░▒░░ ░▒▒ ░ ▀▒▒ ▀▓▓█▓▓▓▓▓▓▓▓▓▓▒▒░░▒▒░░ ░░░▓░ ▓░░░▒ ▀▀█▓███▓▓▓▓▓▒▒░░░▒░░ ░█▓░█▓░█▓▓▄▒░ ░▓██▓▓▓▓▓▒▒░░░▒░░ ░████▓▒▓█▓▀░▀▄ ░▓██▓▓▓▓▓▒▒▒░░░▒░░ ▒██▓▒▒▒▒▒▒░░░▒ ████▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░▒▓▓▒░░░░▒░░░▒░ ░░░░░ ░▓███▓▓▓▓▓▒▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒░░░ ░░░░░ ░ ▓███▓▓▓▓▓▒▓▒▒▒▒░░░░░░░░░▒▓▒▒░▀ ░░░ ░░░░░ ▀▒██▓▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▓▀▀░ ░░░░░░░░░ ░ ▓▓▓▓▓▓▓▒▓▒▒▒▒▓▓▓▒▀░ ░░░░░▄░░░ ░░░ ░░░░░░ ▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓ █▓▒░░▒░░░░ ░░░░░░░░ ▄▓▓▓▒▒▒▒▒░░░░░░░▒▄▄▄░▒▓▓▒▒░▀░ ░▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒░░░▒ besiyata ▓▓█▓▓▒▓▓▓▒▒▒░░░░░░▒▓▓▓▓▒▒▒▒▒░ dishmaya ▓▓█▓▓▓▓▓▓▒▒▒░░░░░░░▒▓▓▒▀▀▀ ▓▓██▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▀ █▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▒▓▓▓▓▀░░▒▓▓▓▓▓▓▓▓▒▒░░▒ ▄▓▓▀░░░▄▓▓▓▓▒▒▒▒▒░░░░▄░ ▄███▄▄▓▓▓▓▓▓▓▒▒▒▒▒░░▒▒░ ▄▓▓▓█▓█▓▓███▓▓▓▓▓▓▓▓▓▓▓░ ▄░▓▓▓▓▓▓▀▒▓▓▓▒▒▓▒░░░▒▓▒░░░▓ ▄▄▄░▒▓▓▓▓▓▓░▀▀ ▓▓▒░▓▒▒▒▒▒▒▒▒▒▒▄░░▀▀░░ ▄▄▄▄ ▄▄▄▒▒▓▓█▓▓▓▓▓▀▀▀▀▀ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▀░░▀░░▒▒▒░░░ ░░░░░ ▄▓▓▓▒▀▀ ▓▒▓▓▓▓▓▒▒▒▒▒▒▒▒▓░░░ ▒▒▒░░░░░░░░▒ █▓▓▒ ▄▄▄ ▀▓▒▓▒▒▒▓▓▓▓▓▓▒▒▒░░░░░░░░░▒▒░░░░░░░ ▀▓▓▓▓▒▄▄▒▒▒▒▒▒▄▄ ▀▀▀▀░░▒▒▒▒░░░░░░ ▀▀▀▓▓▓▓▒▒▒▒▒▓▓▄▄ ╔────────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § bell system five » system call support ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ / Performs System Five System Call. / / Cosmopolitan is designed to delegate all function calls into the / Linux, FreeBSD, OpenBSD, and XNU kernels through this function, / with few exceptions. This function is intended to be called via / generated thunks in the libc/sysv/syscalls/ directory. / / It's safe to call this function on Windows, where it'll always / return -1 w/ errno == ENOSYS. Further note that -1 is the only / return value that means error, a common anti-pattern is to check / for values less than 0 (which is more problematic on 32-bit). / / It's important to consider that system calls are an order of a / magnitude more expensive than normal function calls. For example / getpid() on Linux usually takes 500ns, and cached i/o calls will / take 1µs or more. / / @param %rax function ordinal supplied by jump slot / @param %rdi,%rsi,%rdx,%rcx,%r8,%r9 and rest on stack / @return %rax:%rdx is result, or -1 w/ errno on error / @clob %rcx,%r10,%r11 / @see syscalls.sh .initbss 300,_init_systemfive hostos: .quad 0 .endobj hostos,globl,hidden systemfive: .quad 0 .endobj systemfive,globl,hidden .previous .Lanchorpoint: systemfive.linux: movswl %ax,%eax test %eax,%eax js systemfive.enosys mov %rcx,%r10 push %rbp mov %rsp,%rbp syscall pop %rbp cmp $-4095,%rax jae systemfive.error ret .endfn systemfive.linux,globl,hidden systemfive.error: neg %eax / 𝑠𝑙𝑖𝑑𝑒 .endfn systemfive.error,globl,hidden systemfive.errno: mov %eax,errno(%rip) push $-1 pop %rax stc ret .endfn systemfive.errno,globl,hidden systemfive.enosys: mov ENOSYS(%rip),%eax jmp systemfive.errno .endfn systemfive.enosys,globl,hidden systemfive.openbsd: shr $48,%rax jmp systemfive.bsd .endfn systemfive.openbsd,globl,hidden systemfive.freebsd: shr $32,%rax movzwl %ax,%eax / 𝑠𝑙𝑖𝑑𝑒 .endfn systemfive.freebsd,globl,hidden systemfive.bsd: cmp $0xfff,%ax jae systemfive.enosys mov %rcx,%r10 push %rbp mov %rsp,%rbp syscall pop %rbp jc systemfive.errno ret .endfn systemfive.bsd systemfive.xnu: / do this to rax / 0x????????2153???? / │└┴┴─┐ / └┐ ├┬┐ / 0x0000000002000153 mov %eax,%r11d shr $4*7,%r11d shl $4*6,%r11d shl $4*1,%eax shr $4*5,%eax or %r11d,%eax jmp systemfive.bsd .endfn systemfive.xnu,globl,hidden .previous / Initializes System Five system call support. / / (1) Extracts parameters passed by kernel, / (2) Detects O/S without issuing system calls, / (3) Unpacks numbers. / / @param %r15 is auxv / @note OpenBSD devs: let us know if you start using auxv .init.start 300,_init_systemfive push %rbx push %rsi testb $METAL,(%rdi) # @see ape/ape.S jnz systemfive.init.metal testb $XNU,(%rdi) # @see libc/crt/crt.S jnz systemfive.init.xnu testb $FREEBSD,(%rdi) # @see libc/crt/crt.S jnz systemfive.init.freebsd testb $WINDOWS,(%rdi) # @see libc/runtime/winmain.c jnz systemfive.init.windows cmpq $0,(%r15) # OpenBSD doesn't have auxv je systemfive.init.openbsd / default state is safe state / 𝑠𝑙𝑖𝑑𝑒 systemfive.init.linux: pushb systemfive.linux-.Lanchorpoint push $LINUX ezlea syscon.linux,si jmp systemfive.init.os systemfive.init.metal: pushb systemfive.linux-.Lanchorpoint push $METAL ezlea syscon.linux,si jmp systemfive.init.os systemfive.init.windows: pushb systemfive.enosys-.Lanchorpoint push $WINDOWS ezlea syscon.windows,si jmp systemfive.init.os systemfive.init.freebsd: pushb systemfive.freebsd-.Lanchorpoint push $FREEBSD ezlea syscon.freebsd,si jmp systemfive.init.os systemfive.init.openbsd: pushb systemfive.openbsd-.Lanchorpoint push $OPENBSD ezlea syscon.openbsd,si jmp systemfive.init.os systemfive.init.xnu: pushb systemfive.xnu-.Lanchorpoint push $XNU ezlea syscon.xnu,si / 𝑠𝑙𝑖𝑑𝑒 systemfive.init.os: ezlea .Lanchorpoint,cx pop %rax stosq #→ hostos pop %rax add %rcx,%rax stosq #→ systemfive push %rdi ezlea syscon.start,di ezlea syscon.end,bx call systemfive.sleb128unpacker pop %rdi / 𝑠𝑙𝑖𝑑𝑒 systemfive.init.done: pop %rsi pop %rbx .init.end 300,_init_systemfive,globl,hidden .text.startup systemfive.sleb128unpacker: .leafprologue or $-1,%r9 2: cmp %rbx,%rdi jnb 5f xor %ecx,%ecx xor %edx,%edx 3: lodsb mov %rax,%r8 and $127,%r8d sal %cl,%r8 add $7,%ecx or %r8,%rdx test %al,%al js 3b test $64,%al je 4f mov %r9,%rax sal %cl,%rax or %rax,%rdx 4: mov %rdx,%rax cmpq $0,(%rdi) # don't change consts already set cmovne (%rdi),%rax # @see WinMain() for example stosq jmp 2b 5: .leafepilogue .previous / Sections for varint encoded numbers. / / These sections are all ordered by (group_name, constant_name). / They're populated by modules simply referencing the symbols. / / @see libc/sysv/consts.sh / @see libc/sysv/consts/syscon.h .section .piro.bss.sort.syscon.1,"aw",@nobits .align 8 syscon.start:/* ...decentralized quadwords... */.previous .section .piro.bss.sort.syscon.3,"aw",@nobits syscon.end: .previous .section .sort.rodata.syscon.linux.1,"a",@progbits .align 1 syscon.linux:/* ...decentralized leb128... */.previous .section .sort.rodata.syscon.xnu.1,"a",@progbits .align 1 syscon.xnu:/* ...decentralized leb128... */.previous .section .sort.rodata.syscon.freebsd.1,"a",@progbits .align 1 syscon.freebsd:/* ...decentralized leb128... */.previous .section .sort.rodata.syscon.openbsd.1,"a",@progbits .align 1 syscon.openbsd:/* ...decentralized leb128... */.previous .section .sort.rodata.syscon.windows.1,"a",@progbits .align 1 syscon.windows:/* ...decentralized leb128... */.previous .type syscon.start,@object .type syscon.end,@object .type syscon.linux,@object .type syscon.xnu,@object .type syscon.freebsd,@object .type syscon.openbsd,@object .type syscon.windows,@object .globl syscon.start .globl syscon.end .globl syscon.linux .globl syscon.xnu .globl syscon.freebsd .globl syscon.openbsd .globl syscon.windows