cosmopolitan/libc/macros.internal.h
Justine Tunney 2ab9e9f7fd
Make improvements
- Introduce portable sched_getcpu() api
- Support GCC's __target_clones__ feature
- Make fma() go faster on x86 in default mode
- Remove some asan checks from core libraries
- WinMain() now ensures $HOME and $USER are defined
2024-02-12 10:23:00 -08:00

529 lines
12 KiB
C

#ifndef COSMOPOLITAN_LIBC_MACROS_H_
#define COSMOPOLITAN_LIBC_MACROS_H_
#if 0
/*───────────────────────────────────────────────────────────────────────────│─╗
│ cosmopolitan § macros ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/
#endif
/**
* @fileoverview Common C preprocessor, assembler, and linker macros.
*/
#ifdef MAX
#undef MAX
#endif
#ifdef MIN
#undef MIN
#endif
#define TRUE 1
#define FALSE 0
#define IS2POW(X) (!((X) & ((X) - 1)))
#define ROUNDUP(X, K) (((X) + (K) - 1) & -(K))
#define ROUNDDOWN(X, K) ((X) & -(K))
#ifndef __ASSEMBLER__
#define ABS(X) ((X) >= 0 ? (X) : -(X))
#define MIN(X, Y) ((Y) > (X) ? (X) : (Y))
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
#else
// The GNU assembler does not grok the ?: ternary operator; furthermore,
// boolean expressions yield -1 and 0 for "true" and "false", not 1 and 0.
#define __MAPBOOL(P) (!!(P) / (!!(P) + !(P)))
#define __IFELSE(P, X, Y) (__MAPBOOL(P) * (X) + __MAPBOOL(!(P)) * (Y))
#define MIN(X, Y) (__IFELSE((Y) > (X), (X), (Y)))
#define MAX(X, Y) (__IFELSE((Y) < (X), (X), (Y)))
#endif
#define PASTE(A, B) __PASTE(A, B)
#define STRINGIFY(A) __STRINGIFY(A)
#define EQUIVALENT(X, Y) (__builtin_constant_p((X) == (Y)) && ((X) == (Y)))
#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
#define TYPE_SIGNED(type) (((type) - 1) < 0)
#define TYPE_INTEGRAL(type) (((type)0.5) != 0.5)
#define ARRAYLEN(A) \
((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A)))))
#define __STRINGIFY(A) #A
#define __PASTE(A, B) A##B
#ifdef __ASSEMBLER__
// clang-format off
// 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
// 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 .head
.section .text.head,"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
.balign 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 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,"aMS",@progbits,1
.balign 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
// 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
#ifdef __aarch64__
.macro jmp dest:req
b \dest
.endm
#endif
// 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
.section .yoink
#ifdef __x86_64__
nopl "\symbol"(%rip)
#elif defined(__aarch64__)
b "\symbol"
#endif
.previous
.endm
// Begins definition of frameless function that calls no functions.
.macro .leafprologue
#if !(defined(TINY) && !defined(__PG__))
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
#elif defined(__aarch64__)
stp x29,x30,[sp,#-16]!
mov x29,sp
#endif
#endif
.endm
// Ends definition of frameless function that calls no functions.
.macro .leafepilogue
#if !(defined(TINY) && !defined(__PG__))
#ifdef __x86_64__
pop %rbp
#elif defined(__aarch64__)
ldp x29,x30,[sp],#16
#endif
#endif
ret
.endm
// Documents unreachable assembly code.
.macro .unreachable
#if !defined(NDEBUG) && defined(__x86_64__)
ud2 // crash if contract is broken
#elif !defined(NDEBUG) && defined(__aarch64__)
brk #1000
#elif defined(__FNO_OMIT_FRAME_POINTER__) && defined(__x86_64__)
nop // avoid noreturn tail call backtrace ambiguity
#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
// Inserts --ftrace pre-prologue.
// This goes immediately before the function symbol.
// @see .ftrace2
.macro .ftrace1
#ifdef FTRACE
#ifdef __x86_64__
.rept 9
nop
.endr
#elif defined(__aarch64__)
.rept 6
nop
.endr
#endif /* __x86_64__ */
#endif /* FTRACE */
.endm
// Inserts --ftrace prologue.
// This goes immediately after the function symbol.
// @see .ftrace1
.macro .ftrace2
#ifdef FTRACE
#ifdef __x86_64__
xchg %ax,%ax
#elif defined(__aarch64__)
nop
#endif /* __x86_64__ */
#endif /* FTRACE */
.endm
#ifdef __x86_64__
#if __MNO_VZEROUPPER__ + 0
#define vzeroupper
#endif
// 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
.balign 4
.endm
.macro .rodata.cst8
.section .rodata.cst8,"aM",@progbits,8
.balign 8
.endm
.macro .rodata.cst16
.section .rodata.cst16,"aM",@progbits,16
.balign 16
.endm
.macro .rodata.cst32
.section .rodata.cst32,"aM",@progbits,32
.balign 32
.endm
.macro .rodata.cst64
.section .rodata.cst64,"aM",@progbits,64
.balign 64
.endm
.macro .tdata
.section .tdata,"awT",@progbits
.balign 4
.endm
.macro .tbss
.section .tdata,"awT",@nobits
.balign 4
.endm
// Loads address of errno into %rcx
.macro .errno
call __errno_location
.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
.balign 8
.endm
.macro .initbss number:req name:req
.section ".piro.bss.init.2.\number\().\name","aw",@nobits
.balign 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
// LOOP Instruction Replacement.
.macro .loop label:req
.byte 0x83
.byte 0xe9
.byte 0x01
jnz \label
.endm
// Pushes CONSTEXPR ∈ [-128,127].
// @note assembler is wrong for non-literal constexprs
.macro pushb x:req
.byte 0x6a
.byte \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
// 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
// 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 .ftrace1
.macro .hookable
.byte 0x0f
.byte 0x1f
.byte 0x44
.byte 0x00
.byte 0x00
.endm
// Puts initialized data in uninitialized data section.
.macro .bsdata name:req expr:req bnd vis
.section ".initbss.300._init_\name","aw",@nobits
"\name":
.quad 0
.endobj "\name",\bnd,\vis
.previous
.section ".initro.300._init_\name","a",@progbits
.quad \expr
.previous
.section ".init.300._init_\name","ax",@progbits
"_init_\name":
movsq
.endfn "_init_\name"
.previous
.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 # xchg bx,bx (bochs breakpoint)
.byte 0xdb
.byte 0x5b # pop bx
.byte 0x66 # xchg ax,ax (microsoft breakpoint)
.byte 0x90
int3 # gdb breakpoint
.endm
// Assembles Intel Official 4-Byte NOP.
.macro fatnop4
.byte 0x0f,0x1f,0x40,0x00
.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
// Good alignment for functions where alignment actually helps.
// @note 16-byte
.macro .alignfunc
#ifndef __OPTIMIZE_SIZE__
.p2align 4
#endif
.endm
// TODO(jart): delete
// Loads Effective Address
// Supporting security blankets
.macro ezlea symbol:req reg:req
#if __pic__ + __pie__ + __code_model_medium__ + __code_model_large__ + 0 > 1
// lea \symbol(%rip),%r\reg
mov $\symbol,%e\reg
#else
mov $\symbol,%e\reg
#endif
.endm
// Loads address of linktime mergeable string literal into register.
.macro loadstr text:req reg:req regsz bias=0
.section .rodata.str1.1,"aSM",@progbits,1
.type .Lstr\@,@object
.Lstr\@: .asciz "\text"
.Lstr\@.size = .-.Lstr\@ - 1
.size .Lstr\@,.-.Lstr\@
.previous
ezlea .Lstr\@,\reg
.ifnb \regsz
#ifdef __OPTIMIZE_SIZE__
.if .Lstr\@.size + \bias < 128
pushpop .Lstr\@.size,%r\regsz
.else
mov $.Lstr\@.size,%e\regsz
.endif
#else
mov $.Lstr\@.size,%e\regsz
#endif
.endif
.endm
.macro .poison name:req kind:req
#ifdef __SANITIZE_ADDRESS__
2323: .quad 0
.init.start 304,"_init_\name\()_poison_\@"
push %rdi
push %rsi
ezlea 2323b,di
mov $8,%esi
mov $\kind,%edx
call __asan_poison
pop %rsi
pop %rdi
.init.end 304,"_init_\name\()_poison_\@"
#endif
.endm
.macro .underrun
#ifdef __SANITIZE_ADDRESS__
.poison __BASE_FILE__, -20 # kAsanGlobalUnderrun
#endif
.endm
.macro .overrun
#ifdef __SANITIZE_ADDRESS__
.poison __BASE_FILE__, -21 # kAsanGlobalOverrun
#endif
.endm
#else
.macro .underrun
.endm
.macro .overrun
.endm
// clang-format on
#endif /* __x86_64__ */
#endif /* __ASSEMBLER__ */
#endif /* COSMOPOLITAN_LIBC_MACROS_H_ */