/*-*- 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                              │
│                                                                              │
│ Permission to use, copy, modify, and/or distribute this software for         │
│ any purpose with or without fee is hereby granted, provided that the         │
│ above copyright notice and this permission notice appear in all copies.      │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
│ PERFORMANCE OF THIS SOFTWARE.                                                │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/relocations.h"
/* clang-format off */

#if __MNO_VZEROUPPER__ + 0
#define vzeroupper
#endif

//	Begins definition of frameless function that calls no functions.
.macro	.leafprologue
#if !(defined(TINY) && !defined(__PG__))
	push	%rbp
	mov	%rsp,%rbp
#endif
.endm

//	Ends definition of frameless function that calls no functions.
.macro	.leafepilogue
#if !(defined(TINY) && !defined(__PG__))
	pop	%rbp
#endif
	ret
.endm

//	Good alignment for functions where alignment actually helps.
//	@note 16-byte
.macro	.alignfunc
#ifndef	__OPTIMIZE_SIZE__
	.p2align 4
#endif
.endm

//	Good alignment for loops where alignment actually helps.
//	@note 16-byte if <10 padding otherwise 8-byte
.macro	.alignloop
#ifndef	__OPTIMIZE_SIZE__
	.p2align 4,,10
	.p2align 4
#endif
.endm

//	Loads Effective Address
//	Supporting security blankets
.macro	plea	symbol:req reg64:req reg32:req
#if	__PIC__ + __PIE__ + __code_model_medium__ + __code_model_large__ + 0 > 1
	lea	\symbol(%rip),\reg64
#else
	mov	$\symbol,\reg32
#endif
.endm

//	Loads Effective Address to Stack
//	Supporting security blankets
.macro	pshaddr	symbol:req
#if	__PIC__ + __PIE__ + __code_model_medium__ + __code_model_large__ + 0 > 1
	push	$IMAGE_BASE_VIRTUAL+RVA(\symbol)(%rip),\reg64
#else
	push	$\symbol
#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

.macro	farcall	symbol:req
 .type	\symbol,@function
#if	__PIC__ + __PIE__ + __code_model_medium__ + __code_model_large__ + 0 > 1
	call	*\symbol\()@gotpcrel(%rip)
#else
	call	\symbol\()@plt
#endif
.endm

//	Creates first stack frame.
.macro	.frame0
	and	$-16,%rsp
	xor	%ebp,%ebp
.endm

.macro	.source	symbol:req
.endm

//	Inserts profiling hook in prologue if cc wants it.
//
//	Cosmopolitan does this in a slightly different way from normal
//	GNU toolchains. We always use the -mnop-mcount behavior, since
//	the runtime is able to morph the binary at runtime. It is good
//	since we can put hooks for profiling and function tracing into
//	most builds, without any impact on performance.
//
//	@cost	≥0.3 cycles, 5 bytes
//	@see	build/compile
.macro	.profilable
#ifdef __PG__
1382:
#if defined(__MFENTRY__)
	call	__fentry__
#elif defined(__PIC__) || defined(__PIE__)
//	nopw 0x00(%rax,%rax,1)
	.byte	0x66,0x0f,0x1f,0x44,0x00,0x00
#else
//	nopl 0x00(%rax,%rax,1)
	.byte	0x0f,0x1f,0x44,0x00,0x00
#endif
#endif
.endm

//	Pushes RVA on stack of linktime mergeable string literal.
//	@see	popstr
.macro	pushstr	text
	.section .rodata.str1.1,"aSM",@progbits,1
.Lstr\@: .asciz	"\text"
	.endobj	.Lstr\@
	.previous
	push	$.Lstr\@ - IMAGE_BASE_VIRTUAL
.endm

//	Pops off stack string address.
//	@see	pushstr
.macro	popstr	dest:req
	addl	$IMAGE_BASE_VIRTUAL,(%rsp)
	pop	\dest
.endm

//	Loads address of linktime mergeable string literal into register.
.macro	getstr	text:req reg64:req reg32 regsz64 regsz32 bias=0
 .section .rodata.str1.1,"aSM",@progbits,1
  .type	.Lstr\@,@object
.Lstr\@: .asciz	"\text"
.Lstr\@.size = .-.Lstr\@ - 1
  .size	.Lstr\@,.-.Lstr\@
 .previous
	plea	.Lstr\@,\reg64,\reg32
 .ifnb	\regsz64
#ifdef	__OPTIMIZE_SIZE__
  .if	.Lstr\@.size + \bias < 128
	pushpop	.Lstr\@.size,\regsz64
  .else
	mov	$.Lstr\@.size,\regsz32
  .endif
#else
	mov	$.Lstr\@.size,\regsz32
#endif
 .endif
.endm

//	TODO(jart): delete
//	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
