333 lines
8.5 KiB
PHP
333 lines
8.5 KiB
PHP
/*-*- 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
|
|
|
|
/ LOOP Instruction Replacement.
|
|
/ 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
|
|
|
|
/ Custom emulator instruction for bottom stack frame.
|
|
.macro bofram endfunc:req
|
|
.byte 0x0f,0x1f,0105,\endfunc-. # nopl disp8(%rbp)
|
|
.endm
|