/*-*- 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 │ ╚─────────────────────────────────────────────────────────────────────────────*/ / Shorthand notation for widely-acknowledged sections. .macro .rodata .section .rodata,"a",@progbits .endm .macro .init .section .init,"ax",@progbits .endm .macro .real .section .text.real,"ax",@progbits .endm .macro .text.startup .section .text.startup,"ax",@progbits .endm .macro .text.exit .section .text.exit,"ax",@progbits .endm .macro .firstclass .section .text.hot,"ax",@progbits .endm .macro .text.unlikely .section .text.unlikely,"ax",@progbits .endm .macro .text.likely .section .text.hot,"ax",@progbits .endm .macro .text.modernity .section .text.modernity,"ax",@progbits .align 16 .endm .macro .text.antiquity .section .text.antiquity,"ax",@progbits .endm .macro .text.hot .section .text.hot,"ax",@progbits .endm .macro .preinit_array .section .preinit_array,"a",@init_array .endm .macro .init_array .section .init_array,"a",@init_array .endm .macro .text.windows .section .text.windows,"ax",@progbits .endm / Mergeable numeric constant sections. / / @note linker de-dupes item/values across whole compile / @note therefore item/values are reordered w.r.t. link order / @note therefore no section relative addressing .macro .rodata.cst4 .section .rodata.cst4,"aM",@progbits,4 .align 4 .endm .macro .rodata.cst8 .section .rodata.cst8,"aM",@progbits,8 .align 8 .endm .macro .rodata.cst16 .section .rodata.cst16,"aM",@progbits,16 .align 16 .endm .macro .rodata.cst32 .section .rodata.cst32,"aM",@progbits,32 .align 32 .endm .macro .rodata.cst64 .section .rodata.cst64,"aM",@progbits,64 .align 64 .endm .macro .tdata .section .tdata,"awT",@progbits .align 4 .endm .macro .tbss .section .tdata,"awT",@nobits .align 4 .endm / Mergeable NUL-terminated UTF-8 string constant section. / / @note linker de-dupes C strings here across whole compile / @note therefore item/values are reordered w.r.t. link order / @note therefore no section relative addressing .macro .rodata.str1.1 .section .rodata.str1.1,"aSM",@progbits,1 .align 1 .endm / Locates unreferenced code invulnerable to --gc-sections. .macro .keep.text .section .keep.text,"ax",@progbits .endm / Flags code as only allowed for testing purposes. .macro .testonly .section .test,"ax",@progbits .endm / Makes code runnable while code morphing. .macro .privileged .section .privileged,"ax",@progbits .endm / Post-Initialization Read-Only (PIRO) BSS section. / @param ss is an optional string, for control image locality .macro .piro ss .ifnb \ss .section .piro.sort.bss.\ss,"aw",@nobits .else .section .piro.bss,"aw",@nobits .endif .endm / Helpers for Cosmopolitan _init() amalgamation magic. / @param name should be consistent across macros for a module / @see libc/runtime/_init.S .macro .initro number:req name:req .section .initro.\number\().\name,"a",@progbits .align 8 .endm .macro .initbss number:req name:req .section .piro.bss.init.2.\number\().\name,"aw",@nobits .align 8 .endm .macro .init.start number:req name:req .section .init.\number\().\name,"ax",@progbits \name: .endm .macro .init.end number:req name:req bnd=globl vis .endfn \name,\bnd,\vis .previous .endm / Declares alternative implementation of function. / @param implement e.g. tinymath_pow / @param canonical e.g. pow .macro .alias implement:req canonical:req .equ \canonical,\implement .weak \canonical .endm / Ends function definition. / @cost saves 1-3 lines of code .macro .endfn name:req bnd vis .size \name,.-\name .type \name,@function .ifnb \bnd .\bnd \name .endif .ifnb \vis .\vis \name .endif .endm / Ends variable definition. / @cost saves 1-3 lines of code .macro .endobj name:req bnd vis .size \name,.-\name .type \name,@object .ifnb \bnd .\bnd \name .endif .ifnb \vis .\vis \name .endif .endm / Custom emulator instruction for bottom stack frame. .macro bofram endfunc:req .byte 0x0f,0x1f,0x45,\endfunc-. # nopl disp8(%rbp) .endm / Overrides LOOP instruction. / With its mop-Fusion Mexican equivalent. / Thus avoiding 3x legacy pipeline slowdown. .macro loop label:req .byte 0x83,0xe9,0x01 # sub $1,%ecx jnz \label .endm / Pushes CONSTEXPR ∈ [-128,127]. / @note assembler is wrong for non-literal constexprs .macro pushb x:req .byte 0x6a,\x .endm / Sign-extends CONSTEXPR ∈ [-128,127] to REGISTER. / @cost ≥1 cycles, -2 bytes .macro pushpop constexpr:req register:req pushb \constexpr pop \register .endm / Moves REGISTER to REGISTER. / @cost ≥1 cycles, -1 REX byte .macro movpp src:req dest:req push \src pop \dest .endm / Declares optional function. .macro .optfn fn:req .globl \fn .weak \fn .equ \fn,missingno .type \fn,@function .endm / Embeds fixed-width zero-filled string table. / @note zero-padded ≠ nul-terminated .macro .fxstr width head rest:vararg .ifnb \head 0: .ascii "\head" .org 0b+\width .fxstr \width,\rest .endif .endm / Embeds Fixed-Width Zero-Padded String. / @note .fxstr is better .macro .ascin str:req fieldsize:req 1347: .ascii "\str" .org 1347b+\fieldsize,0x00 .endm / Marks symbols as object en-masse. / @note zero-padded ≠ nul-terminated .macro .object symbol rest:vararg .ifnb \symbol .type \symbol,@object .object \rest .endif .endm / Pads function prologue unconditionally for runtime hooking. / @cost ≥0.3 cycles, 5 bytes / @see .profilable .macro .hookable / nopl 0x00(%rax,%rax,1) 83457: .byte 0x0f,0x1f,0x44,0x00,0x00 .pushsection __mcount_loc,"a",@progbits .quad 83457b .popsection .endm / Puts initialized data in uninitialized data section. .macro .bsdata name:req expr:req bnd vis .pushsection .initbss.300._init_\name,"aw",@nobits \name: .quad 0 .endobj \name,\bnd,\vis .popsection .pushsection .initro.300._init_\name,"a",@progbits .quad \expr .popsection .pushsection .init.300._init_\name,"ax",@progbits _init_\name: movsq .endfn _init_\name .popsection .endm / ICE Breakpoint. / Modern gas forgot this but objdump knows / @mode long,legacy,real .macro icebp .byte 0xF1 .endm .macro int1 icebp .endm / Sets breakpoint for software debugger. / @mode long,legacy,real .macro .softicebp .byte 0x53 # push bx .byte 0x87,0xdb # xchg bx,bx (bochs breakpoint) .byte 0x5b # pop bx .byte 0x66,0x90 # xchg ax,ax (microsoft breakpoint) int3 # gdb breakpoint .endm / Assembles Intel Official 4-Byte NOP. .macro fatnop4 .byte 0x0f,0x1f,0x40,0x00 .endm / Pulls unrelated module into linkage. / / In order for this technique to work with --gc-sections, another / module somewhere might want to weakly reference whats yoinked. .macro yoink symbol:req .pushsection .yoink nop "\symbol" .popsection .endm .macro .yoink symbol:req .pushsection .yoink nop "\symbol" .popsection .endm / Calls Windows function. / / @param cx,dx,r8,r9,stack / @return ax / @clob ax,cx,dx,r8-r11 .macro ntcall symbol:req sub $32,%rsp call *\symbol(%rip) add $32,%rsp .endm