/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-│
│vi: set et ft=asm ts=8 tw=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 & 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 EVEN                │
│ CONSEQUENTIAL DAMAGE OR ANY DAMAGES WHATSOEVER RESULTING FROM                │
│ LOSS OF USE, DATA OR PROFITS WHETHER IN AN ACTION OF CONTRACT                │
│ NEGLIGENCE OR OTHER TORTIOUS ACTION, THAT ARISE OUT OF, OR IN                │
│ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.                     │
╠──────────────────────────────────────────────────────────────────────────────╣
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│
│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│
│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│
╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│
│ αcτµαlly pδrταblε εxεcµταblε § program header                                │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/macros.internal.h"
#include "ape/notice.inc"
#include "ape/relocations.h"
#include "libc/calls/metalfile.internal.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/macho.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/pedef.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/sysv/consts/prot.h"

#define USE_SYMBOL_HACK 1

	.section .text,"ax",@progbits
	.align	__SIZEOF_POINTER__
	.previous
	.section .rodata,"a",@progbits
	.align	__SIZEOF_POINTER__
__ro:	.endobj	__ro,globl,hidden		# ←for gdb readability
	.previous
	.section .data,"aw",@progbits
	.align	__SIZEOF_POINTER__
	.previous
	.section .bss,"aw",@nobits
	.align	__SIZEOF_POINTER__
	.previous
	.section .rodata.str1.1,"a",@progbits
cstr:	.endobj	cstr,globl,hidden		# ←for gdb readability
	.previous
	.section .head,"ax",@progbits

/*	    ████████               ████████        ███████████
	    ██░░░░▒▒██           ██░░░░▒▒██    ████░░░░░░░░░▒▒████
	    ██░░░░░░██           ██░░░░▒▒██  ██░░░░▒▒███████░░░░▒▒██
	    ██░░░░░░▒▒██      ░██░░░░░░▒▒██  ██░░▒▒██       ██░░▒▒██
	    ██░░▒▒░░░░██      ░██░░░░░░▒▒██  ██░░▒▒██       ████████
	    ██░░▒▒▒▒░░▒▒██  ██▓░░░░▒▒░░▒▒██  ██░░▒▒▒▒███████
	    ██░░▒▒██░░░░██  ██▓░░░░██░░▒▒██    ████░░░░░░░▒▒████
	    ██░░▒▒████░░▒▒██░░░░░████░░▒▒██        ███████░░░░▒▒██
	    ██░░▒▒████░░░░██░░░░░████░░▒▒██  ██████       ██░░░░▒▒██
	    ██░░▒▒██  ██░░▒▒░░▒██  ██░░▒▒██  ██░░░░██       ██░░▒▒██
	    ██░░▒▒██  ██░░░░░░▒██  ██░░▒▒██  ██░░░░█████████░░░░▒▒██
	    ██░░▒▒██  ▓▓▒▒░░▒▒▒▓▓  ██░░▒▒██  ▓▓▒▒░░▓▓▓▓▓▓▓▓▓░░░░▓▓▓▓
	    ██░░▒▒██    ██░░██▓    ██░░▒▒██    ██░░░░░░░░░░░░░▒▒██
	  ████████████████████▓  ██████████████  ███████████████
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░████
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░░░░░░░██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▒░░▓▓░░▓▓░░▓▓██░░░░░░░░░░░░░░░░░░░░░░░░░██
	  ██▓▓▓▓▓▓██████████░░▒▓▓▓▓██████▓▓██░░░░░░███████████▓▓░░░░▓▓██
	  ██▓▓▓▓▓▓████████░░▓▓▓▓▓██▓▓▓▓██████░░░░████░░▒▓▓██  ██▓▓▓▓▓▓██
	  ██▓▓▓▓▓▓████████▓▓░░▒████▓▓▓▓██████░░░░██▓▓▓▓▒░░██    ██████
	  ██▓▓▓▓▓▓██    ██░░▓▓▓▓▓██▓▓▓▓██  ██▓▓░░████░░▒▓▓██████
	  ██▓▓▓▓▓▓██    ██▓▓░░▒████▓▓▓▓██    ██▓▓██▓▓▓▓▒░░██░░░░████
	  ██▓▓▓▓▓▓██    ██░░▓▓▓▓▓██▓▓▓▓██      ██████░░▒▓▓██░░░░░░░░██
	  ██▓▓▓▓▓▓██    ██▓▓░░▒████▓▓▓▓██        ██▓▓▓▓▒░░██▓▓░░░░░░░░██
	  ██▓▓▓▓▓▓██    ██░░▓▓▓████▓▓▓▓██    ████████░░▒▓▓████▓▓░░░░░░██
	  ██▓▓▓▓▓▓██      ██░░▒██▓▓▓▓████  ██░░░░░░██▓▓███    ██░░░░░░██
	  ██▓▓▓▓▓▓█████████████▓▓▓▓██████████▓▓░░░░░░█████████░░░░░░░░██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░██▓▓░░░░░░░░░░░░░░░░░░░░░▓▓██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓██▓▓▓▓░░░░░░░░░░░░░░░░░▓▓▓▓██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓░░▓▓██▓▓▓▓▓▓░░░░░░░░░░░▓▓▓▓▓▓██
	  ██▓▓█████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██
	  ███████████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓████
	    ██████████████████▓    ██████████████  █████████████
╔──────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § the old technology                            │
╚─────────────────────────────────────────────────────────────────────────────*/

#if SupportsWindows() || SupportsMetal() || SupportsXnu()

//	MZ Literally Executable Header
//
//	This is the beginning of the program file and it can serve as an
//	entrypoint too. It shouldn't matter if the program is running on
//	Linux, Windows, etc. Please note if the underlying machine isn't
//	a machine, this header may need to morph itself to say the magic
//	words, e.g. ⌂ELF, which also works fine as a generic entrypoint.
//
//	@param	dl is drive number
//	@noreturn
ape_mz:
#if SupportsWindows() || SupportsMetal()
	.asciz	"MZqFpD='\n"		# Mark 'Zibo' Joseph Zbikowski
//	# in real mode
//	dec	%bp
//	pop	%dx
//	jno	0x4a
//	jo	0x4a
//
//	# in legacy mode
//	push	%ebp
//	pop	%edx
//	jno	0x4a
//	jo	0x4a
//
//	# 64-bit mode
//	rex.WRB
//	pop	%r10
//	jno	0x4a
//	jo	0x4a
#else
//	Avoid virus scanner reputation damage when targeting System Five.
	.asciz	"jartsr='\n"		# Justine Alexandra Roberts Tunney
//	push	$0x61
//	jb	0x78
//	jae	0x78
#endif
	.short	0x1000			# MZ: lowers upper bound load / 16
	.short	0xf800			# MZ: roll greed on bss
	.short	0			# MZ: lower bound on stack segment
	.short	0			# MZ: initialize stack pointer
	.short	0			# MZ: ∑bₙ checksum don't bother
	.short	0x0100			# MZ: initial ip value
	.short	0x0800			# MZ: increases cs load lower bound
	.short	0x0040			# MZ: reloc table offset
	.short	0			# MZ: overlay number
	.org	0x24			# MZ: bytes reserved for you
	.ascii	"JT"			# MZ: OEM identifier
	.short	0			# MZ: OEM information
	.ascii	"' <<'@'\n"
	.org	0x40-4			# MZ: bytes reserved for you
#if SupportsWindows() || SupportsMetal()
	.long	RVA(ape_pe)		# PE: the new technology
#else
	.long	0
	.org	0x78
	pop	%rax
	jmp	_start
#endif
	.endfn	ape_mz,globl,hidden

#else /* !(SupportsWindows() || SupportsMetal() || SupportsXnu()) */

//	ELF Literally Executable Header
//
//	If we don't need to support Microsoft or Apple then we can
//	produce a conventional executable without the shell script
//
//	@param	dl is drive number
//	@noreturn
	.ascii	"\177ELF"			# 0x0: ⌂ELF
	.byte	ELFCLASS64			#   4: long mode
	.byte	ELFDATA2LSB			#   5: little endian
	.byte	1				#   6: elf v1.o
	.byte	ELFOSABI_FREEBSD		#   7: FreeBSD
	.byte	0				#   8: os/abi ver.
	.align	8,0				#   9: padding
	.short	ET_EXEC				#  10: εxεcµταblε
	.short	EM_NEXGEN32E			#  12: NexGen32e
	.long	1				#  14: elf v1.o
	.quad	ape_elf_entry			#  18: e_entry
	.quad	ape_elf_phoff			#  20: e_phoff
	.quad	ape_elf_shoff			#  28: e_shoff
	.long	0				#  30: e_flags
	.short	64				#  34: e_ehsize
	.short	56				#  36: e_phentsize
	.short	ape_elf_phnum			#  38: e_phnum
	.short	0				#  3a: e_shentsize
	.short	ape_elf_shnum			#  3c: e_shnum
	.short	ape_elf_shstrndx		#  3e: e_shstrndx

#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */

#if SupportsMetal()

//	Disk Operating System Stub
//
//	@param	dl is drive number
//	@noreturn
	.org	0x40			# mz/elf header length
stub:	mov	$0x40,%dl		# *literally* dos
	jmp	1f			# good bios skips here
1:	jmp	pc			# thus avoiding heroics
	nop				# system five bootpoint
	.org	0x48,0x90		# note ⌂ELF means JG 47
	jmp	3f			# MZ also means pop r10
2:	sub	$8,%rsp			# a.k.a. dec %ax sub %sp
	xor	%edx,%edx		# MZ ate BIOS drive code
3:	.byte	0xbd,0,0		# a.k.a. mov imm,%bp
	jmp	pc			# real mode, is real
	jmp	_start			# surprise it's unix
	.endfn	stub

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § ibm personal computer                         │
╚──────────────────────────────────────────────────────────────────────────────┘
	IBM designed BIOS to run programs by handing over the computer
	to a program as soon as its first sector is loaded. That gives
	us control over user-facing latency, even though the next step
	will generally be asking the BIOS to load more.

	The process is trivial enough that this entrypoint can support
	handoffs from alternative program-loaders e.g. Grub and MS-DOS
	so long as they either load our full program, or implement the
	PC BIOS disk service API.

	Since so many different implementations of these APIs have been
	built the last forty years these routines also canonicalize the
	cpu and program state, as it is written in the System V ABI. */

//	Initializes program and jumps to real mode loader.
//
//	@param	dl drive number (use 0x40 to skip bios disk load)
//	@mode	real
//	@noreturn
pc:	cld
	.code16
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.short	(0x7c00-IMAGE_BASE_VIRTUAL)/512
#endif
	mov	$0x70000>>4,%di			# we need a stack
	xor	%cx,%cx				# 0x7f000-0x80000
	mov	%cx,%es
	rlstack	%di,%cx
	push	%cs				# determine load address
	pop	%ds				# and relocate this code
	call	1f				# to a way lower address
1:	pop	%si				# and we'll make cs zero
	sub	$RVA(1b),%si
	mov	$IMAGE_BASE_REAL>>4,%ax
	push	%ax				# save IMAGE_BASE_REAL>>4
	push	%ax
	pop	%es
	xor	%di,%di
	mov	$512,%cx
	rep movsb
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.short	(IMAGE_BASE_REAL-0x7c00)/512
#endif
	ljmp	$0,$REAL(1f)
1:	mov	%cx,%ds
	.set	mm,0x0500			# struct mman
	mov	$IMAGE_BASE_REAL-mm,%cx		# clears bss
	mov	$mm>>4,%ax
	mov	%ax,%es
	xor	%ax,%ax
	xor	%di,%di
	rep stosb
	cmp	$0x40,%dl
	je	6f
	call	dsknfo
	pop	%es				# restore IMAGE_BASE_REAL>>4
	mov	$1,%al				# current sector
	xor	%cx,%cx				# current cylinder
	xor	%dh,%dh				# current head
	mov	$v_ape_realsectors,%di		# total sectors
3:	call	pcread
	mov	%es,%si				# addr += 512
	add	$512>>4,%si
	mov	%si,%es
	dec	%di
	jnz	3b
6:	ljmp	$0,$REAL(realmodeloader)
	.endfn	pc

//	Determines disk geometry.
//
//	We use imperial measurements for storage systems so the software
//	can have an understanding of physical locality, which deeply
//	impacts the latency of operations.
//
//	 - 160KB:  40 cylinders × 1 head  ×  8 sectors × 512 =   163,840
//	 - 180KB:  40 cylinders × 1 head  ×  9 sectors × 512 =   184,320
//	 - 320KB:  40 cylinders × 2 heads ×  8 sectors × 512 =   327,680
//	 - 360KB:  40 cylinders × 2 heads ×  9 sectors × 512 =   368,640
//	 - 720KB:  80 cylinders × 2 heads ×  9 sectors × 512 =   737,280
//	 - 1.2MB:  80 cylinders × 2 heads × 15 sectors × 512 = 1,228,800
//	 - 1.44MB: 80 cylinders × 2 heads × 18 sectors × 512 = 1,474,560
//
//	Terminology
//
//	 - Heads are also known as Tracks
//
//	Disk Base Table
//
//	   0: specify byte 1, step-rate time, head unload time
//	   1: specify byte 2, head load time, DMA mode
//	   2: timer ticks to wait before disk motor shutoff
//	   3: bytes per sector code
//	        0: 128 bytes  2: 512 bytes
//	        1: 256 bytes  3: 1024 bytes
//	   4: sectors per track (last sector number)
//	   5: inter-block gap length/gap between sectors
//	   6: data length, if sector length not specified
//	   7: gap length between sectors for format
//	   8: fill byte for formatted sectors
//	   9: head settle time in milliseconds
//	  10: motor startup time in eighths of a second
//
//	@param	dl drive number
//	@return	dl = pc_drive (corrected if clobbered by header)
//		pc_drive
//		pc_drive_type
//		pc_drive_heads
//		pc_drive_last_cylinder
//		pc_drive_last_sector
//	@clob	ax, cx, dx, di, si, es, flags
//	@since	IBM Personal Computer XT
dsknfo:	push	%bx
1:	push	%dx
	mov	$0x16,%ah		# make sure there is disk in drive,
	int	$0x13			# by querying change-line status
	jnc	2f
	xor	%ax,%ax			# if error or change line active,
	int	$0x13			# do a reset...
	jc	9f
	mov	$0x0201,%ax		# ...then do a read, to confirm that
	mov	$0x0001,%cx		# there is disk in drive
	mov	$0,%dh			# (verify (%ah = 4) does not work
	mov	$IMAGE_BASE_REAL>>4,%bx	# under QEMU, which always returns
	mov	%bx,%es			# success)
	xor	%bx,%bx
	int	$0x13
	jc	9f
2:	mov	$0x08,%ah		# get disk params
	int	$0x13
	jc	9f
	mov	%cl,%bh
	and	$0b00111111,%bh
	and	$0b11000000,%cl
	rol	%cl
	rol	%cl
	xchg	%cl,%ch
	push	%ds			# disk base table in es:di
	movpp	%es,%ds
	xor	%si,%si
	mov	%si,%es
	mov	$mm+"struct mman::pc_drive_base_table",%si
	xchg	%si,%di
	movsw	#→ headunloadtime, headloadtime
	movsw	#→ shutofftime, bytespersector
	movsw	#→ sectorspertrack, sectorgap
	movsw	#→ datalength, formatgap
	movsw	#→ formatfill, settletime
	movsb	#→ startuptime
	pop	%ds
	xchg	%bx,%ax
	stosw	#→ pc_drive_type, pc_drive_last_sector
	scasb
	xchg	%cx,%ax
	stosw	#→ pc_drive_last_cylinder
	xchg	%dx,%ax
	stosw	#→ pc_drives_attached, pc_drive_last_head
	pop	%ax
	stosb	#→ pc_drive
	xchg	%ax,%dx
	pop	%bx
	ret
9:	pop	%dx
8:	xor	$0x80,%dl		# try cycling drive a/c
	xor	%ax,%ax			# reset disk
	int	$0x13
	jc	8b
	jmp	1b
	.endfn	dsknfo

//	Reads disk sector via BIOS.
//
//	@param	al sector number
//	@param	es destination memory address >> 4
//	@param	cx cylinder number
//	@param	dh head number
//	@param	dl drive number
//	@return	number of sectors actually read
pcread:	push	%ax
	push	%cx
	xchg	%cl,%ch
	ror	%cl
	ror	%cl
	or	%al,%cl
	xor	%bx,%bx			# es:bx is destination addr
	mov	$1,%al			# read only one disk sector
	mov	$2,%ah			# read disk sectors ordinal
	int	$0x13
	pop	%cx
	pop	%ax
	jc	9f
	inc	%al			# ++sector
	cmp	mm+"struct mman::pc_drive_last_sector",%al
	jbe	2f
	mov	$1,%al
	inc	%dh			# ++head
	cmp	mm+"struct mman::pc_drive_last_head",%dh
	jbe	2f
	xor	%dh,%dh
	inc	%cx			# ++cylinder
2:	ret
9:	push	%ax
	xor	%ax,%ax			# try disk reset on error
	int	$0x13
	pop	%ax
	jmp	pcread
	.endfn	pcread

//	Video put string.
//
//	@param	di is the string
//	@clob	bp,bx
//	@mode	real
rvputs:	mov	%di,%si
0:	lodsb
	test	%al,%al
	je	1f
	mov	$7,%bx				# normal mda/cga style page zero
	mov	$0x0e,%ah			# teletype output al cp437
	int	$0x10				# vidya service
	jmp	0b
1:	ret
	.endfn	rvputs

//	Abnormally halts startup.
//
//	@param	di message
//	@mode	real
//	@noreturn
rldie:	push	%di
	mov	$REAL(str.error),%di
	call	rvputs
	pop	%di
	call	rvputs
	mov	$REAL(str.crlf),%di
	call	rvputs
0:	rep nop
	jmp	0b
	.endfn	rldie

//	Initializes present PC serial lines.
sinit4:	mov	$4,%cx
	mov	$0x400,%si			# BDA.COM1
0:	lodsw
	test	%ax,%ax
	jz	1f
	push	%cx
	push	%si
	xchg	%ax,%di
	mov	$REAL(sconf),%si
	call	sinit
	pop	%si
	pop	%cx
1:	loop	0b
	ret
	.endfn	sinit4,global,hidden

//	Initializes Serial Line Communications 8250 UART 16550A
//
//	@param	word di tty port
//	@param	char (*{es:,e,r}si)[4] register initial values
//	@mode	long,legacy,real
//	@see	www.lammertbies.nl/comm/info/serial-uart.html
sinit:	mov	%di,%dx
	test	%dx,%dx
	jz	2f
	push	%dx
	push	%si
	xor	%cx,%cx
	mov	$UART_LCR,%cl
	add	%cx,%dx
	lodsb	%ds:(%si),%al
	pop	%si
	or	$UART_DLAB,%al
	out	%al,%dx
	pop	%dx
1:	lodsb	%ds:(%si),%al
	out	%al,%dx
	inc	%dx
	dec	%cx
	jns	1b
2:	ret
	.endfn	sinit,global,hidden

/*───────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § partition table                           ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/

//	Partition Table.
ape.mbrpad:
	.org	0x1b4
	.endobj	ape.mbrpad
ape_disk:
	.stub	ape.diskid,quad
	.org	0x1be,0x00
	.macro	.partn	x:req sta h0 s0 c0 fs h9 s9 c9 lba0 nsec
	.stub	ape.part\x\().status,byte,\sta	# 0=non-boot / 0x80=active
	.stub	ape.part\x\().first.head,byte,\h0
	.stub	ape.part\x\().first.sector,byte,\s0 # in low 6 bits
	.stub	ape.part\x\().first.cylinder,byte,\c0
	.stub	ape.part\x\().filesystem,byte,\fs
	.stub	ape.part\x\().last.head,byte,\h9
	.stub	ape.part\x\().last.sector,byte,\s9
	.stub	ape.part\x\().last.cylinder,byte,\c9
	.stub	ape.part\x\().lba,long,\lba0	# c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
	.stub	ape.part\x\().sector.count,long,\nsec # sectors are 512 bytes
	.endm
	.partn	1,0x80,0,1,0,0x7f,0xff,0xff,0xff,0,0xffffffff
	.partn	2
	.partn	3
	.partn	4
	.org	0x1fe
	.short	BOOTSIG
	.endobj	ape_disk

#endif /* SupportsMetal() */

/*                                           ▄▄▄
                       ▄▄▄                    ▀▓▓▒▄
                     ▄▓▒▒░                      ▀▓▒▒▒▄
                   ▄▓▓▓▒▀              ▄▄▄▄      ▒▓▒▒░▒▄
                  ▄▓▓▓▒▓        ▄▄▓██▓▓▓▓▒▒▒▒▓▓▄▄▓▓▒▒▒░░▒
                  ▓▓▓▓▒▒▒▄▄  ░▒█▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▒░░▒░
                  ██▓▓▓▒▒░░▒▒▒▒▓▓▓▓▓▓▒▓▒░▒▒░▀▒▒▒▒░▀░▒▒▒░▒
                  ▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▒▓▓▒▒▒░▒▒░░  ░▒▒░  ░▒▒▒▒
                   ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░▒░░    ░▒▒  ░ ▀▒▒
                     ▀▓▓█▓▓▓▓▓▓▓▓▓▓▒▒░░▒▒░░   ░░░▓░ ▓░░░▒
                       ▀▀█▓███▓▓▓▓▓▒▒░░░▒░░  ░█▓░█▓░█▓▓▄▒░
                          ░▓██▓▓▓▓▓▒▒░░░▒░░  ░████▓▒▓█▓▀░▀▄
                          ░▓██▓▓▓▓▓▒▒▒░░░▒░░  ▒██▓▒▒▒▒▒▒░░░▒
                           ████▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░▒▓▓▒░░░░▒░░░▒░ ░░░░░
                           ░▓███▓▓▓▓▓▒▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒░░░ ░░░░░   ░
                             ▓███▓▓▓▓▓▒▓▒▒▒▒░░░░░░░░░▒▓▒▒░▀ ░░░  ░░░░░
                              ▀▒██▓▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▓▀▀░    ░░░░░░░░░     ░
                                 ▓▓▓▓▓▓▓▒▓▒▒▒▒▓▓▓▒▀░ ░░░░░▄░░░  ░░░  ░░░░░░
                                 ▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓     █▓▒░░▒░░░░ ░░░░░░░░
                                ▄▓▓▓▒▒▒▒▒░░░░░░░▒▄▄▄░▒▓▓▒▒░▀░
                               ░▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒░░░▒  besiyata
                               ▓▓█▓▓▒▓▓▓▒▒▒░░░░░░▒▓▓▓▓▒▒▒▒▒░   dishmaya
                               ▓▓█▓▓▓▓▓▓▒▒▒░░░░░░░▒▓▓▒▀▀▀
                               ▓▓██▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▀
                                █▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
                               ▒▓▓▓▓▀░░▒▓▓▓▓▓▓▓▓▒▒░░▒
                              ▄▓▓▀░░░▄▓▓▓▓▒▒▒▒▒░░░░▄░
                             ▄███▄▄▓▓▓▓▓▓▓▒▒▒▒▒░░▒▒░
                           ▄▓▓▓█▓█▓▓███▓▓▓▓▓▓▓▓▓▓▓░
                       ▄░▓▓▓▓▓▓▀▒▓▓▓▒▒▓▒░░░▒▓▒░░░▓
               ▄▄▄░▒▓▓▓▓▓▓░▀▀   ▓▓▒░▓▒▒▒▒▒▒▒▒▒▒▄░░▀▀░░ ▄▄▄▄
     ▄▄▄▒▒▓▓█▓▓▓▓▓▀▀▀▀▀        ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▀░░▀░░▒▒▒░░░   ░░░░░
  ▄▓▓▓▒▀▀                      ▓▒▓▓▓▓▓▒▒▒▒▒▒▒▒▓░░░       ▒▒▒░░░░░░░░▒
  █▓▓▒      ▄▄▄                  ▀▓▒▓▒▒▒▓▓▓▓▓▓▒▒▒░░░░░░░░░▒▒░░░░░░░
   ▀▓▓▓▓▒▄▄▒▒▒▒▒▒▄▄                    ▀▀▀▀░░▒▒▒▒░░░░░░
       ▀▀▀▓▓▓▓▒▒▒▒▒▓▓▄▄
╔────────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § bell system five                          ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	the bourne executable & linkable format */

#if SupportsWindows() || SupportsMetal() || SupportsXnu()
apesh:	.ascii	"\n@\n#'\"\n"			# sixth edition shebang
	.ascii	"m=\"$(uname -m)\"\n"

	.ascii	"if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]; then\n"
//	Until all operating systems can be updated to support APE,
//	we have a beautiful, yet imperfect workaround, which is to
//	modify the binary to follow the local system's convention.
//	There isn't a one-size-fits-all approach for this, thus we
//	present two choices.
	.ascii	"o=\"$(command -v \"$0\")\"\n"
//	Try to use a system-wide APE loader.
	.ascii	"[ x\"$1\" != x--assimilate ] && "
	.ascii	  "type ape >/dev/null 2>&1 && "
	.ascii	    "exec ape \"$o\" \"$@\"\n"
#ifdef APE_LOADER
//	There is no system-wide APE loader, but there is one
//	embedded inside the APE. So if the system is not MacOs,
//	extract the loader into a temp folder, and use it to
//	load the APE without modifying it.
	.ascii	"[ x\"$1\" != x--assimilate ] && {\n"
	.ascii	  "t=\"${TMPDIR:-${HOME:-.}}/.ape\"\n"
	.ascii	  "[ -x \"$t\" ] || {\n"
	.ascii	    "mkdir -p \"${t%/*}\" &&\n"
	.ascii	    "dd if=\"$o\" of=\"$t.$$\" skip="
	.shstub	      ape_loader_dd_skip,2
	.ascii	      " count="
	.shstub	      ape_loader_dd_count,2
	.ascii	      " bs=64 2>/dev/null\n"
#if SupportsXnu()
	.ascii	    "[ -d /Applications ] && "
	.ascii	      "dd if=\"$t.$$\""
	.ascii	        " of=\"$t.$$\""
	.ascii	        " skip=6"
	.ascii	        " count=10"
	.ascii	        " bs=64"
	.ascii	        " conv=notrunc"
	.ascii	        " 2>/dev/null\n"
#endif /* SupportsXnu() */
	.ascii	    "chmod 755 \"$t.$$\"\n"
	.ascii	    "mv -f \"$t.$$\" \"$t\"\n"
	.ascii	  "}\n"
	.ascii	  "exec \"$t\" \"$o\" \"$@\"\n"
	.ascii	"}\n"
#endif /* APE_LOADER */
#ifndef APE_NO_MODIFY_SELF
//	The default behavior is: to overwrite the header in place.
//	We prefer this because it's a tiny constant one time cost.
//	We simply printf a 64-byte header and call execve() again.
#else
//	The alternative behavior is to copy to $TMPDIR or $HOME or
//	the current directory. We like TMPDIR because it's part of
//	the IEEE POSIX standard whereas alternatives (XDG) aren't.
	.ascii	"t=\"${TMPDIR:-${HOME:-.}}/$0\"\n"
	.ascii	"[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n"
	.ascii	  "[ x\"$1\" != x--assimilate ] && {\n"
	.ascii	    "mkdir -p \"${t%/*}\" 2>/dev/null\n"
	.ascii	    "cp -f \"$o\" \"$t.$$\" &&\n"
	.ascii	    "mv -f \"$t.$$\" \"$t\" || exit 120\n"
	.ascii	    "o=\"$t\"\n"
	.ascii	  "}\n"
#endif /* APE_NO_MODIFY_SELF */
	.ascii	"exec 7<> \"$o\" || exit 121\n"
	.ascii	"printf '"
	.ascii	  "\\177ELF"			# 0x0: ⌂ELF
	.ascii	  "\\2"				#   4: long mode
	.ascii	  "\\1"				#   5: little endian
	.ascii	  "\\1"				#   6: elf v1.o
	.ascii	  "\\011"			#   7: FreeBSD
	.ascii	  "\\0"				#   8: os/abi ver.
	.ascii	  "\\0\\0\\0"			#   9: padding 3/7
	.ascii	  "\\0\\0\\0\\0"		#      padding 4/7
	.ascii	  "\\2\\0"			#  10: εxεcµταblε
	.ascii	  "\\076\\0"			#  12: NexGen32e
	.ascii	  "\\1\\0\\0\\0"		#  14: elf v1.o
	.shstub	  ape_elf_entry,8		#  18: e_entry
	.shstub	  ape_elf_phoff,8		#  20: e_phoff
	.shstub	  ape_elf_shoff,8		#  28: e_shoff
	.ascii	  "\\0\\0\\0\\0"		#  30: e_flags
	.ascii	  "\\100\\0"			#  34: e_ehsize
	.ascii	  "\\070\\0"			#  36: e_phentsize
	.shstub	  ape_elf_phnum,2		#  38: e_phnum
	.ascii	  "\\0\\0"			#  3a: e_shentsize
	.shstub	  ape_elf_shnum,2		#  3c: e_shnum
	.shstub	  ape_elf_shstrndx,2		#  3e: e_shstrndx
	.ascii	  "' >&7\n"
	.ascii	"exec 7<&-\n"
#if SupportsXnu()
	.ascii	"[ -d /Applications ] && "
	.ascii	  "dd if=\"$o\""
	.ascii	    " of=\"$o\""
	.ascii	    " bs=8"
	.ascii	    " skip="
	.shstub	    ape_macho_dd_skip,2
	.ascii	    " count="
	.shstub	    ape_macho_dd_count,2
	.ascii	    " conv=notrunc 2>/dev/null\n"
#endif /* XNU */
	.ascii	"[ x\"$1\" = x--assimilate ] && exit 0\n"
#ifndef APE_NO_MODIFY_SELF
	.ascii	"exec \"$0\" \"$@\"\n"		# try to preserve argv[0]
#else
	.ascii	"}\n"
	.ascii	"o=\"$t\"\n"
	.ascii	"exec \"$o\" \"$@\"\n"
#endif /* APE_NO_MODIFY_SELF */
	.ascii	"exit $?\n"
	.ascii	"fi\n"

	.ascii	"PHDRS='' <<'@'\n"
	.endobj	apesh
//	elf program headers get inserted here
//	because they need to be in the first 4096 bytes
        .section .emush,"a",@progbits
emush:	.ascii	"\n@\n#'\"\n"
	.ascii	"s=\"$(uname -s)\"\n"

//	our script is running on a non-x86_64 architecture
//	1. `dd` out the appropriate blink vm blob
//	2. gunzip the blink virtual machine executable
//	3. relaunch this program inside the blink vm
	.ascii	"o=\"$(command -v \"$0\")\"\n"
	.ascii	"e=\"${TMPDIR:-${HOME:-.}}/.ape-blink-1.1\"\n"

//	Blink for Apple Silicon, e.g. M1 Macbook
	.ascii	"if [ \"$s\" = Darwin ] && [ \"$m\" = arm64 ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-darwin-arm64 to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_darwin_arm64_b9
	.byte	blink_darwin_arm64_b8
	.byte	blink_darwin_arm64_b7
	.byte	blink_darwin_arm64_b6
	.byte	blink_darwin_arm64_b5
	.byte	blink_darwin_arm64_b4
	.byte	blink_darwin_arm64_b3
	.byte	blink_darwin_arm64_b2
	.byte	blink_darwin_arm64_b1
	.byte	blink_darwin_arm64_b0
	.ascii	")) count=$(("
	.byte	blink_darwin_arm64_size_b9
	.byte	blink_darwin_arm64_size_b8
	.byte	blink_darwin_arm64_size_b7
	.byte	blink_darwin_arm64_size_b6
	.byte	blink_darwin_arm64_size_b5
	.byte	blink_darwin_arm64_size_b4
	.byte	blink_darwin_arm64_size_b3
	.byte	blink_darwin_arm64_size_b2
	.byte	blink_darwin_arm64_size_b1
	.byte	blink_darwin_arm64_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Aarch64 Linux, e.g. Raspberry Pi
	.ascii	"if [ \"$s\" = Linux ]; then\n"
	.ascii	"if [ \"$m\" = aarch64 ] || [ \"$m\" = arm64 ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-aarch64 to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_aarch64_b9
	.byte	blink_aarch64_b8
	.byte	blink_aarch64_b7
	.byte	blink_aarch64_b6
	.byte	blink_aarch64_b5
	.byte	blink_aarch64_b4
	.byte	blink_aarch64_b3
	.byte	blink_aarch64_b2
	.byte	blink_aarch64_b1
	.byte	blink_aarch64_b0
	.ascii	")) count=$(("
	.byte	blink_aarch64_size_b9
	.byte	blink_aarch64_size_b8
	.byte	blink_aarch64_size_b7
	.byte	blink_aarch64_size_b6
	.byte	blink_aarch64_size_b5
	.byte	blink_aarch64_size_b4
	.byte	blink_aarch64_size_b3
	.byte	blink_aarch64_size_b2
	.byte	blink_aarch64_size_b1
	.byte	blink_aarch64_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"
	.ascii	"fi\n"

//	Blink for Linux Generic ARM
	.ascii	"if [ \"$s\" = Linux ] && [ \"${m#arm}\" != \"$m\" ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-arm to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_arm_b9
	.byte	blink_arm_b8
	.byte	blink_arm_b7
	.byte	blink_arm_b6
	.byte	blink_arm_b5
	.byte	blink_arm_b4
	.byte	blink_arm_b3
	.byte	blink_arm_b2
	.byte	blink_arm_b1
	.byte	blink_arm_b0
	.ascii	")) count=$(("
	.byte	blink_arm_size_b9
	.byte	blink_arm_size_b8
	.byte	blink_arm_size_b7
	.byte	blink_arm_size_b6
	.byte	blink_arm_size_b5
	.byte	blink_arm_size_b4
	.byte	blink_arm_size_b3
	.byte	blink_arm_size_b2
	.byte	blink_arm_size_b1
	.byte	blink_arm_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Linux on Legacy x86
	.ascii	"if [ \"$s\" = Linux ]; then\n"
	.ascii	"if [ \"$m\" = i686 ] || [ \"$m\" = i386 ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-i486 to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_i486_b9
	.byte	blink_i486_b8
	.byte	blink_i486_b7
	.byte	blink_i486_b6
	.byte	blink_i486_b5
	.byte	blink_i486_b4
	.byte	blink_i486_b3
	.byte	blink_i486_b2
	.byte	blink_i486_b1
	.byte	blink_i486_b0
	.ascii	")) count=$(("
	.byte	blink_i486_size_b9
	.byte	blink_i486_size_b8
	.byte	blink_i486_size_b7
	.byte	blink_i486_size_b6
	.byte	blink_i486_size_b5
	.byte	blink_i486_size_b4
	.byte	blink_i486_size_b3
	.byte	blink_i486_size_b2
	.byte	blink_i486_size_b1
	.byte	blink_i486_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"
	.ascii	"fi\n"

//	Blink for Linux on RISC-V
	.ascii	"if [ \"$s\" = Linux ] && [ \"$m\" = riscv64 ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-riscv64 to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_riscv64_b9
	.byte	blink_riscv64_b8
	.byte	blink_riscv64_b7
	.byte	blink_riscv64_b6
	.byte	blink_riscv64_b5
	.byte	blink_riscv64_b4
	.byte	blink_riscv64_b3
	.byte	blink_riscv64_b2
	.byte	blink_riscv64_b1
	.byte	blink_riscv64_b0
	.ascii	")) count=$(("
	.byte	blink_riscv64_size_b9
	.byte	blink_riscv64_size_b8
	.byte	blink_riscv64_size_b7
	.byte	blink_riscv64_size_b6
	.byte	blink_riscv64_size_b5
	.byte	blink_riscv64_size_b4
	.byte	blink_riscv64_size_b3
	.byte	blink_riscv64_size_b2
	.byte	blink_riscv64_size_b1
	.byte	blink_riscv64_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Linux on MIPS Little Endian, e.g. Ubiquiti EdgerouterX
	.ascii	"if [ \"$s\" = Linux ] && [ \"$m\" = mips ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-mipsel to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_mipsel_b9
	.byte	blink_mipsel_b8
	.byte	blink_mipsel_b7
	.byte	blink_mipsel_b6
	.byte	blink_mipsel_b5
	.byte	blink_mipsel_b4
	.byte	blink_mipsel_b3
	.byte	blink_mipsel_b2
	.byte	blink_mipsel_b1
	.byte	blink_mipsel_b0
	.ascii	")) count=$(("
	.byte	blink_mipsel_size_b9
	.byte	blink_mipsel_size_b8
	.byte	blink_mipsel_size_b7
	.byte	blink_mipsel_size_b6
	.byte	blink_mipsel_size_b5
	.byte	blink_mipsel_size_b4
	.byte	blink_mipsel_size_b3
	.byte	blink_mipsel_size_b2
	.byte	blink_mipsel_size_b1
	.byte	blink_mipsel_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Linux on PowerPC 64 Little Endian, e.g. Raptor
	.ascii	"if [ \"$s\" = Linux ] && [ \"$m\" = ppc64le ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-powerpc64le to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_powerpc64le_b9
	.byte	blink_powerpc64le_b8
	.byte	blink_powerpc64le_b7
	.byte	blink_powerpc64le_b6
	.byte	blink_powerpc64le_b5
	.byte	blink_powerpc64le_b4
	.byte	blink_powerpc64le_b3
	.byte	blink_powerpc64le_b2
	.byte	blink_powerpc64le_b1
	.byte	blink_powerpc64le_b0
	.ascii	")) count=$(("
	.byte	blink_powerpc64le_size_b9
	.byte	blink_powerpc64le_size_b8
	.byte	blink_powerpc64le_size_b7
	.byte	blink_powerpc64le_size_b6
	.byte	blink_powerpc64le_size_b5
	.byte	blink_powerpc64le_size_b4
	.byte	blink_powerpc64le_size_b3
	.byte	blink_powerpc64le_size_b2
	.byte	blink_powerpc64le_size_b1
	.byte	blink_powerpc64le_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Linux on PowerPC, e.g. Old Macintosh
	.ascii	"if [ \"$s\" = Linux ] && [ \"$m\" = ppc ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-powerpc to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_powerpc_b9
	.byte	blink_powerpc_b8
	.byte	blink_powerpc_b7
	.byte	blink_powerpc_b6
	.byte	blink_powerpc_b5
	.byte	blink_powerpc_b4
	.byte	blink_powerpc_b3
	.byte	blink_powerpc_b2
	.byte	blink_powerpc_b1
	.byte	blink_powerpc_b0
	.ascii	")) count=$(("
	.byte	blink_powerpc_size_b9
	.byte	blink_powerpc_size_b8
	.byte	blink_powerpc_size_b7
	.byte	blink_powerpc_size_b6
	.byte	blink_powerpc_size_b5
	.byte	blink_powerpc_size_b4
	.byte	blink_powerpc_size_b3
	.byte	blink_powerpc_size_b2
	.byte	blink_powerpc_size_b1
	.byte	blink_powerpc_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

//	Blink for Linux on IBM Mainframes
	.ascii	"if [ \"$s\" = Linux ] && [ \"$m\" = s390x ]; then\n"
	.ascii	"if ! [ -x \"$e\" ]; then\n"
	.ascii	"echo \"extracting blink-s390x to ${e}\" >&2\n"
	.ascii	"dd if=\"$o\" bs=1 skip=$(("
	.byte	blink_s390x_b9
	.byte	blink_s390x_b8
	.byte	blink_s390x_b7
	.byte	blink_s390x_b6
	.byte	blink_s390x_b5
	.byte	blink_s390x_b4
	.byte	blink_s390x_b3
	.byte	blink_s390x_b2
	.byte	blink_s390x_b1
	.byte	blink_s390x_b0
	.ascii	")) count=$(("
	.byte	blink_s390x_size_b9
	.byte	blink_s390x_size_b8
	.byte	blink_s390x_size_b7
	.byte	blink_s390x_size_b6
	.byte	blink_s390x_size_b5
	.byte	blink_s390x_size_b4
	.byte	blink_s390x_size_b3
	.byte	blink_s390x_size_b2
	.byte	blink_s390x_size_b1
	.byte	blink_s390x_size_b0
	.ascii	")) conv=notrunc 2>/dev/null | gunzip >\"$e.$$\"\n"
	.ascii	"mv -f \"$e.$$\" \"$e\"\n"
	.ascii	"chmod +x \"$e\"\n"
	.ascii	"fi\n"
	.ascii	"exec \"$e\" \"$o\" \"$@\"\n"
	.ascii	"fi\n"

	.ascii	"echo unsupported architecture >&2\n"
	.rept	16
	.ascii	"exit 127\n"
	.endr

	.ascii	"exit 1\n"
	.endobj	emush
#ifdef APE_LOADER
        .section .ape.loader,"a",@progbits
	.align	64
ape_loader:
        .incbin APE_LOADER
	.endobj	ape_loader,globl
	.align	64
ape_loader_end:
	nop
	.endobj	ape_loader_end,globl
        .previous
#endif /* APE_LOADER */
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */

#if SupportsSystemv() || SupportsMetal()
	.section .elf.phdrs,"a",@progbits

	.long	PT_LOAD
	.long	PF_R|PF_X
	.stub	ape_rom_offset,quad
	.stub	ape_rom_vaddr,quad
	.stub	ape_rom_paddr,quad
	.stub	ape_rom_filesz,quad
	.stub	ape_rom_memsz,quad
	.stub	ape_rom_align,quad

	.long	PT_LOAD
	.long	PF_R|PF_W
	.stub	ape_ram_offset,quad
	.stub	ape_ram_vaddr,quad
	.stub	ape_ram_paddr,quad
	.stub	ape_ram_filesz,quad
	.stub	ape_ram_memsz,quad
	.stub	ape_ram_align,quad

//	APE Stack Configuration
//
//	We actually respect this when allocating a deterministically
//	addressed stack on Windows and other operating systems. However
//	there's a few caveats:
//
//	- If ape_stack_pf has PF_X then OpenBSD probably won't work
//	- We don't bother creating a deterministic stack in MODE=tiny
//
//	With that said, here's some examples of configuration:
//
//	    STATIC_SYMBOL("ape_stack_pf", "7");  // RWX
//	    STATIC_STACK_ADDR(0x6fffffff0000);
//	    STATIC_STACK_SIZE(65536);
//
//	@see ape.lds for defaults
	.long	PT_GNU_STACK
	.stub	ape_stack_pf,long		# override w/ PF_X for execstack
	.stub	ape_stack_offset,quad		# ignored
	.stub	ape_stack_vaddr,quad		# is mmap()'d with MAP_FIXED
	.stub	ape_stack_paddr,quad		# ignored
	.stub	ape_stack_filesz,quad		# ignored
	.stub	ape_stack_memsz,quad		# is mmap(size) argument
	.stub	ape_stack_align,quad		# must be 16+

#if SupportsOpenbsd() || SupportsNetbsd()
	.long	PT_NOTE
	.long	PF_R
	.stub	ape_note_offset,quad
	.stub	ape_note_vaddr,quad
	.stub	ape_note_paddr,quad
	.stub	ape_note_filesz,quad
	.stub	ape_note_memsz,quad
	.stub	ape_note_align,quad
#endif
	.previous
#endif /* SupportsSystemv() || SupportsMetal() */

#if SupportsOpenbsd()
	.section .note.openbsd.ident,"a",@progbits
openbsd.ident:
	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"OpenBSD"
2:	.align	4
3:	.long	0
4:	.size	openbsd.ident,.-openbsd.ident
	.type	openbsd.ident,@object
	.previous
#endif /* SupportsOpenbsd() */

#if SupportsNetbsd()
	.section .note.netbsd.ident,"a",@progbits
netbsd.ident:
	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"NetBSD"
2:	.align	4
3:	.long	901000000
4:	.size	netbsd.ident,.-netbsd.ident
	.type	netbsd.ident,@object
	.previous
#endif /* SupportsNetbsd() */

/*	                                      ▄▄███▄
	                                  ▄▄████████▄
	                               ▄█████████████▄
	                           ▄▄███▓▓▓▓▓▓▓▓▓▓▓███▄
	                       ▄▄█████▓▓▓█████████▓▓▓██▄
	                   ▄▄████████▓▓▓███████▓▓▓▓▓████▄
	                ▄█████░░░████▓▓█████▓▓▓▓█████████▄
	            ▄▄█████████░░░███▓▓█▓▓▓▓▒███████▓▓▒███▄
	         ▄██████████████░░░██▓▓▓▓███████████▓▓█████▄
	       ██████████████████░░░██▓▓▓█████████▓▓▓███████▄
	        ███░░░░░░█████████▓░░███▓▓▓▓▓▓▓▓▓▓▓█████▒▒▒██▄
	       █░███░░░██░░░░░░░░░██░░██████████████▒▒▒▒██████▄
	      ███████░░░█████████░░░░░░█████████▒▒▒▒▒██████████▄
	      █████ ██░░░███████████████████▒▒▒▒▒██░▒▒██████████▄
	      ██████ ██░░░██████████████░███▒████████▒▒██████████▄
	     ████████ ███░░█████████████░░████████████▒▒███████████
	     █████████ ███░░███████████░░██████████████▒▒███████████
	    ▄██████████ ██████████████ ░░███████████████▒▒███████████
	    ████████████ ███░░░░░█████░░█████████████████▒▒██████  █
	    █████████████ ██████░░░░░░░▒█████████████████████  ████▀
	     █████████████ ██████████░░░░░░░░░███████████  ████████
	      █████████████ ████████░░███████░░░██████ ▓██████████
	       █████████████ ██████░░░████████████  █████████████
╔────────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § nexstep carnegie melon mach object format ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	@note	hey xnu before we get upx'd email feedback jtunney@gmail.com
	@see	OS X ABI Mach-O File Format Reference, Apple Inc. 2009-02-04
	@see	System V Application Binary Interface NexGen32e Architecture
		Processor Supplement, Version 1.0, December 5th, 2018 */

#if SupportsXnu()
.section .macho,"a",@progbits
.align	__SIZEOF_POINTER__

ape_macho:
	.long	0xFEEDFACE+1
	.long	MAC_CPU_NEXGEN32E
	.long	MAC_CPU_NEXGEN32E_ALL
	.long	MAC_EXECUTE
	.long	5				# number of load commands
	.long	60f-10f				# size of all load commands
	.long	MAC_NOUNDEFS			# flags
	.long	0				# reserved
10:	.long	MAC_LC_SEGMENT_64
	.long	20f-10b				# unmaps first page dir
	.ascin	"__PAGEZERO",16			# consistent with linux
	.quad	0,0x200000,0,0			# which forbids mem <2m
	.long	0,0,0,0
20:	.long	MAC_LC_SEGMENT_64
	.long	30f-20b
	.ascin	"__TEXT",16
	.stub	ape_rom_vaddr,quad
	.stub	ape_rom_memsz,quad
	.stub	ape_rom_offset,quad
	.stub	ape_rom_filesz,quad
	.long	PROT_EXEC|PROT_READ|PROT_WRITE	# maxprot
	.long	PROT_EXEC|PROT_READ		# initprot
	.long	1				# segment section count
	.long	0				# flags
210:	.ascin	"__text",16			# section name (.text)
	.ascin	"__TEXT",16
	.stub	ape_text_vaddr,quad
	.stub	ape_text_memsz,quad
	.stub	ape_text_offset,long
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	MAC_S_ATTR_SOME_INSTRUCTIONS	# section type & attributes
	.long	0,0,0				# reserved
30:	.long	MAC_LC_SEGMENT_64
	.long	40f-30b
	.ascin	"__DATA",16
	.stub	ape_ram_vaddr,quad
	.stub	ape_ram_memsz,quad
	.stub	ape_ram_offset,quad
	.stub	ape_ram_filesz,quad
	.long	PROT_EXEC|PROT_READ|PROT_WRITE	# maxprot
	.long	PROT_READ|PROT_WRITE		# initprot
	.long	2				# segment section count
	.long	0				# flags
310:	.ascin	"__data",16			# section name (.data)
	.ascin	"__DATA",16
	.stub	ape_data_vaddr,quad
	.stub	ape_data_memsz,quad
	.stub	ape_data_offset,long
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	0				# section type & attributes
	.long	0,0,0				# reserved
320:	.ascin	"__bss",16			# section name (.bss)
	.ascin	"__DATA",16
	.stub	ape_bss_vaddr,quad		# virtual address
	.stub	ape_bss_memsz,quad		# memory size
	.long	0				# file offset
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	MAC_S_ZEROFILL			# section type & attributes
	.long	0,0,0				# reserved
40:	.long	MAC_LC_UUID
	.long	50f-40b
	.stub	ape_uuid1,quad
	.stub	ape_uuid2,quad
50:	.long	MAC_LC_UNIXTHREAD
	.long	60f-50b				# cmdsize
	.long	MAC_THREAD_NEXGEN32E		# flavaflav
	.long	(520f-510f)/4			# count
510:	.quad	0				# rax
	.quad	IMAGE_BASE_VIRTUAL		# rbx
	.quad	_HOSTXNU			# rcx
	.quad	0				# rdx
	.quad	0				# rdi
	.quad	0				# rsi
	.quad	0				# rbp
	.quad	0				# rsp
	.quad	0				# r8
	.quad	0				# r9
	.quad	0				# r10
	.quad	0				# r11
	.quad	0				# r12
	.quad	0				# r13
	.quad	0				# r14
	.quad	0				# r15
	.quad	_start				# rip
	.quad	0				# rflags
	.quad	0				# cs
	.quad	0				# fs
	.quad	0				# gs
520:
60:

.endobj	ape_macho,globl,hidden
.previous /* .macho */
#endif /* SupportsXnu() */

/*                             ░░░░
                        ▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
                       ▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
                      ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▒▓░
                      ▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓   ▓▓▓▓▓▓▒        ▒▒▒▓▓█
                     ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                    ░▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓   █▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                    ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓░  ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                   ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒
                   ▒▒▒▒▓▓      ▓▒▒▓▓▓▓   ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                                    ▒▓  ▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓
                   ░░░░░░░░░░░▒▒▒▒      ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                 ▒▒░░░░░░░░░░▒▒▒▒▒▓▓▓     ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                ░▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓░      ░▓███▓
                ▒▒░░░░░░░░░░▒▒▒▒▒▓▓░  ▒▓▓▓▒▒▒         ░▒▒▒▓   ████████████
               ▒▒░░░░░░░░░░░▒▒▒▒▒▓▓  ▒▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒░           ░███
               ▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓            ███
              ▒▒░░░░░░░░░░▒▒▒▒▒▒▓▓  ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒            ▓██
              ▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒▓           ▓██
             ▒▒░░░▒▒▒░░░▒▒░▒▒▒▓▓▒  ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒           ███
                             ░▒▓  ░▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓          ▓██
╔─────────────────────────────────────────────────────────────────▀▀▀────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § the new technology                        ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	The Portable Executable Format

	@see https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
	@see "The Portable Executable File Format from Top to Bottom",
	     Randy Kath, Microsoft Developer Network Technology Group. */

//	    ┌14:Uniprocessor Machine            ┌─────────────────────────┐
//	    │┌13:DLL                            │ PE File Characteristics │
//	    ││┌12:System                        ├─────────────────────────┤
//	    │││┌11:If Net Run From Swap         │ r │ reserved            │
//	    ││││┌10:If Removable Run From Swap  │ d │ deprecated          │
//	    │││││┌9:Debug Stripped              │ D │ deprecated with     │
//	    ││││││┌8:32bit Machine              │   │ extreme prejudice   │
//	    │││││││  ┌5:Large Address Aware     └───┴─────────────────────┘
//	    │││││││  │   ┌1:Executable
//	    │││││││  │   │┌0:Relocs Stripped
//	   d│││││││dr│Ddd││
PEEXE = 0b00000001000100011

//	   ┌15:TERMINAL_SERVER_AWARE            ┌─────────────────────────┐
//	   │┌14:GUARD_CF                        │ PE DLL Characteristics  │
//	   ││┌13:WDM_DRIVER                     ├─────────────────────────┤
//	   │││┌12:APPCONTAINER                  │ r │ reserved            │
//	   ││││┌11:NO_BIND                      └───┴─────────────────────┘
//	   │││││┌10:NO_SEH
//	   ││││││┌9:NO_ISOLATION
//	   │││││││┌8:NX_COMPAT
//	   ││││││││┌7:FORCE_INTEGRITY
//	   │││││││││┌6:DYNAMIC_BASE
//	   ││││││││││┌5:HIGH_ENTROPY_VA
//	   │││││││││││rrrrr
DLLSTD = 0b0000000100100000
DLLPIE = 0b0000000001100000
DLLEXE = DLLSTD

//	   ┌31:Writeable                        ┌─────────────────────────┐
//	   │┌30:Readable                        │ PE Section Flags        │
//	   ││┌29:Executable                     ├─────────────────────────┤
//	   │││┌28:Shareable                     │ o │ for object files    │
//	   ││││┌27:Unpageable                   │ r │ reserved            │
//	   │││││┌26:Uncacheable                 └───┴─────────────────────┘
//	   ││││││┌25:Discardable
//	   │││││││┌24:Contains Extended Relocations
//	   ││││││││        ┌15:Contains Global Pointer (GP) Relative Data
//	   ││││││││        │       ┌7:Contains Uninitialized Data
//	   ││││││││        │       │┌6:Contains Initialized Data
//	   ││││││││ o      │       ││┌5:Contains Code
//	   ││││││││┌┴─┐rrrr│  ooror│││rorrr
PETEXT = 0b01100000000000000000000001100000
PEDATA = 0b11000000000000000000000011000000
PEIMPS = 0b11000000000000000000000001000000

#if SupportsWindows() || SupportsMetal()

	.section .pe.header,"a",@progbits
	.align	__SIZEOF_POINTER__
ape_pe:	.ascin	"PE",4
	.short	kNtImageFileMachineNexgen32e
	.stub	ape_pe_shnum,short	# NumberOfSections
	.long	0x5c64126b		# TimeDateStamp
	.long	0			# PointerToSymbolTable
	.long	0			# NumberOfSymbols
	.stub	ape_pe_optsz,short	# SizeOfOptionalHeader
	.short	PEEXE			# Characteristics
	.short	kNtPe64bit		# Optional Header Magic
	.byte	14			# MajorLinkerVersion
	.byte	15			# MinorLinkerVersion
	.long	0			# SizeOfCode
	.long	0			# SizeOfInitializedData
	.long	0			# SizeOfUninitializedData
	.long	RVA(ape_pe_entry)	# EntryPoint
	.long	0			# BaseOfCode
	.quad	ape_pe_base		# ImageBase
	.long	4096			# SectionAlignment
	.long	4096			# FileAlignment
	.short	v_ntversion		# MajorOperatingSystemVersion
	.short	0			# MinorOperatingSystemVersion
	.short	0			# MajorImageVersion
	.short	0			# MinorImageVersion
	.short	v_ntsubversion		# MajorSubsystemVersion
	.short	0			# MinorSubsystemVersion
	.long	0			# Win32VersionValue
	.long	RVA(_end)		# SizeOfImage
	.long	RVA(_ehead)		# SizeOfHeaders
	.long	0			# Checksum
	.short	v_ntsubsystem		# Subsystem: 0=Neutral,2=GUI,3=Console
	.stub	v_ntdllchar,short	# DllCharacteristics
	.quad	0x0000000000100000	# StackReserve
	.quad	0x00000000000fc000	# StackCommit
	.quad	0			# HeapReserve
	.quad	0			# HeapCommit
	.long	0			# LoaderFlags
	.long	16			# NumberOfDirectoryEntries
	.long	0,0			# ExportsDirectory
	.stub	ape_idata,long		# ImportsDirectory
	.stub	ape_idata_idtsize,long	# ImportsDirectorySize
	.long	0,0			# ResourcesDirectory
	.long	0,0			# ExceptionsDirectory
	.long	0,0			# SecurityDirectory
	.long	0,0			# BaseRelocationTable
	.long	0,0			# DebugDirectory
	.long	0,0			# DescriptionString
	.long	0,0			# MachineSpecific
	.long	0,0			# ThreadLocalStorage
	.long	0,0			# LoadConfigurationDirectory
	.long	0,0			# BoundImportDirectory
	.stub	ape_idata,long		# ImportAddressDirectory
	.stub	ape_idata_iatsize,long	# ImportAddressDirectorySize
	.long	0,0			# DelayImportDescriptor
	.long	0,0			# ComPlusRuntimeHeader
	.long	0,0			# Reserved
	.endobj	ape_pe,globl
	.previous

	.section .pe.sections,"a",@progbits
	.ascin	".text",8		# Section Name
	.stub	ape_text_memsz,long	# Virtual Size or Physical Address
	.stub	ape_text_rva,long	# Relative Virtual Address
	.stub	ape_text_filesz,long	# Physical Size
	.stub	ape_text_offset,long	# Physical Offset
	.long	0			# Relocation Table Offset
	.long	0			# Line Number Table Offset
	.short	0			# Relocation Count
	.short	0			# Line Number Count
	.long	PETEXT			# Flags
	.previous

	.section .pe.sections,"a",@progbits
	.ascin	".data",8		# Section Name
	.stub	ape_ram_memsz,long	# Virtual Size or Physical Address
	.stub	ape_ram_rva,long	# Relative Virtual Address
	.stub	ape_ram_filesz,long	# Physical Size
	.stub	ape_ram_offset,long	# Physical Offset
	.long	0			# Relocation Table Offset
	.long	0			# Line Number Table Offset
	.short	0			# Relocation Count
	.short	0			# Line Number Count
	.long	PEDATA			# Flags
	.previous

#endif /* SupportsWindows() || SupportsMetal() */

	.section .idata.ro.idt.1,"a",@progbits
	.type	ape_idata_idtend,@object
	.type	ape_idata_idt,@object
	.globl	ape_idata_idt,ape_idata_idtend
	.hidden	ape_idata_idt,ape_idata_idtend
ape_idata_idt:
	.previous/*
	...
	decentralized content
	...
	*/.section .idata.ro.idt.3,"a",@progbits
	.long	0,0,0,0,0
ape_idata_idtend:
	.previous

	.section .piro.data.sort.metal_gdt,"aw",@progbits
	.align	8
_gdt:
//	          ┌G:granularity (1 → limit *= 0x1000)
//	          │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
//	          ││┌L:long mode
//	          │││┌AVL:this bit is thine (1<<52)
//	          ││││    ┌P:present
//	          ││││    │┌DPL:privilege
//	          ││││    ││ ┌─────────data/code(1)
//	          ││││    ││ │┌────data(0)──────code(1)
//	          ││││    ││ ││┌───conforming───expand-down
//	          ││││    ││ │││┌──writeable────readable
//	          ││││    ││ ││││┌─accessed─────accessed
//	          ││││    ││ │││││
//	          ││││ ┌──││─│││││───────────────────────────────┐
//	      ┌───││││─│──││─│││││───────────┐                   │
//	  ┌───┴──┐││││┌┴─┐│├┐│││││┌──────────┴───────────┐┌──────┴───────┐
//	  │      ││││││  ││││││││││          base address││ segment limit│
//	  │      ││││││  ││││││││││               32 bits││       20 bits│
//	  │      ││││││  ││││││││││                      ││              │
//	  6666555555555544444444443333333333222222222211111111110000000000
//	  3210987654321098765432109876543210987654321098765432109876543210
//	  │      ││││││  ││││││││││                      ││              │
.quad	0b0000000000000000000000000000000000000000000000000000000000000000 # 0
.quad	0b0000000000001111100110100000000000000000000000001111111111111111 # 8
.quad	0b0000000000001111100100100000000000000000000000001111111111111111 #16
.quad	0b0000000011001111100110100000000000000000000000001111111111111111 #24
.quad	0b0000000011001111100100100000000000000000000000001111111111111111 #32
.quad	0b0000000010101111100110110000000000000000000000001111111111111111 #40
.quad	0b0000000010101111100100110000000000000000000000001111111111111111 #48
.tssdescstub _tss							#56,64
_gdt_end:
	.endobj	_gdt,global,hidden
	.previous

	.section .piro.data.sort.iat.1,"aw",@progbits
	.type	ape_idata_iatend,@object
	.type	ape_idata_iat,@object
	.globl	ape_idata_iat,ape_idata_iatend
	.hidden	ape_idata_iat,ape_idata_iatend
ape_idata_iat:
	.previous/*
	...
	decentralized content
	...
	*/.section .piro.data.sort.iat.3,"aw",@progbits
ape_idata_iatend:
	.previous

#if SupportsMetal()
/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § early-stage read-only data                    │
╚──────────────────────────────────────────────────────────────────────────────╝
	better code/data separation (.head is rwx[real] rx[long]) */

//	NUL-Terminated Strings.
str.error:
	.asciz	"error: "
	.endobj	str.error
str.crlf:
	.asciz	"\r\n"
	.endobj	str.crlf
str.e820:
	.asciz	"e820"
	.endobj	str.e820
str.oldcpu:
	.asciz	"oldcpu"
	.endobj	str.oldcpu

//	Serial Line Configuration (8250 UART 16550)
//	If it's hacked, it'll at least get hacked very slowly.
sconf:	.short	1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
//
//	          ┌interrupt trigger level {1,4,8,14}
//	          │ ┌enable 64 byte fifo (UART 16750+)
//	          │ │ ┌select dma mode
//	          │ │ │┌clear transmit fifo
//	          │ │ ││┌clear receive fifo
//	          ├┐│ │││┌enable fifos
	.byte	0b00000000
//
//	          ┌dlab: flips configuration mode state
//	          │┌enable break signal
//	          ││ ┌parity {none,odd,even,high,low}
//	          ││ │ ┌extra stop bit
//	          ││ │ │┌data word length (bits+5)
//	          ││┌┴┐│├┐
	.byte	0b01000011
	.endobj	sconf,global,hidden

//	Global Descriptor Table
	.align	8
_gdtrlo:
	.short	2f-_gdtlo-1	# table byte length
	.long	REAL(_gdtlo)	# table address (base memory space)
	.endobj	_gdtrlo,global,hidden
_gdtr:
	.short	_gdt_end-_gdt-1	# table byte length
	.quad	_gdt		# table address (final virtual space)
	.endobj	_gdtr,global,hidden
	.align	8
//	Partial GDT with descriptors for switching to unreal mode or long mode.
_gdtlo	= .-GDT_LEGACY_DATA
.quad	0b0000000011001111100100100000000000000000000000001111111111111111 #32
.quad	0b0000000010101111100110110000000000000000000000001111111111111111 #40
.quad	0b0000000010101111100100110000000000000000000000001111111111111111 #48
2:

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § real mode                                     │
╚──────────────────────────────────────────────────────────────────────────────╝
	the default mode of operation on modern cpus */

realmodeloader:
	call	lhinit
	call	rlinit
	call	sinit4
	.optfn	_start16
	call	_start16
	call	longmodeloader
	.endfn	realmodeloader

//	Prepares to later load parts of the program that are not loaded yet.
//
//	@param	al next sector number
//	@param	cx next cylinder number
//	@param	dh next head number
//	@param	dl drive number
//	@clob	ax, cx, es, di
lhinit:	cmp	$0x40,%dl
	je	9f
	pushpop	0,%es
	mov	$mm+"struct mman::pc_drive_next_sector",%di
	cld
	stosb	#→ pc_drive_next_sector
	xchg	%ax,%cx
	stosw	#→ pc_drive_next_cylinder
	mov	%dh,%al
	stosb	#→ pc_drive_next_head
9:	ret

	.section .sort.text.real.init.1,"ax",@progbits
	.type	rlinit,@function
rlinit:	.previous/*
	...
	decentralized function
	...
	*/.section .sort.text.real.init.3,"ax",@progbits
	ret
	.previous

/*                                                               █ █▒
                                                               █     █
                                        █▓▄                   █       █
                                       ▒▓  ░█░         ░▒▓▓███░        █▒
                                       ▒▓      ▒▓███▓▒░                 ░▓
                                        █                                ▓░
                                      ▄██░                                █
                                     ▓▓    ▓██░              ▓█░▓█        ▒▓
                                    ▒█   ░█    █            ░▓    █        █
                                    █░    █   ░▓             ▀▒  █░        █
                                    █▒     ▀▒░                             ▓▓
                        ▄▄▄▓████▓▓▒░ █                 ▄▄▄▄▓▓▓█▓▓▓▓▒░     ▒█
                    ▄▓▓▀              ▒       ░█     ▄▓▀                ░███▒
                   ▓▀                  ░░      ▀▓▄▄▄▒▒                     █
                   █                     ░░█▒       ▒█        ▒▓           █
                   ▀█       ▄▄▄▄▄▄▄▄▄▄               ▀▀░▓██▓               █
                     ▀■▄▄▄■▀          ▀▀█▄                                 █
                                         ▀▀█▄                              █
                                            ▀█▄                            █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
╔──────────────────────────────────────────────────────────────────────────▀─│─╗
│ αcτµαlly pδrταblε εxεcµταblε § long mode loader                          ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	long mode is long */

longmodeloader:
	call	lcheck
	call	a20
	call	e820
	call	cpyhi
	call	loadhi
	call	pinit
	call	golong
	.endfn	longmodeloader

//	Long Mode Hardware Check
lcheck:	pushf				# check for i8086 / i8088 / i80186
	pop	%ax
	test	$0x80,%ah		# see intel manual volume 1 20.1.2
	jnz	10f			# we now assume 32bit is supported
	pushfl				# now check for i386 or early i486
	pop	%eax			# test ability to change cpuid bit
	mov	%eax,%ecx
	mov	$1<<21,%ebx
	xor	%ebx,%eax
	push	%eax
	popfl
	pushfl
	pop	%eax
	cmp	%eax,%ecx
	je	10f			# we assume cpuid inst is available
	or	%ebx,%eax		# puts cpuid bit in the on position
	push	%eax
	popfl
	mov	$0x80000000,%edi	# get amd ext cpuid thingy length
	mov	%edi,%eax
	inc	%edi
	cpuid				# clobbers eax, ebx, ecx, and edx
	cmp	%edi,%eax
	jl	10f
	mov	%edi,%eax
	cpuid
	mov	$1<<29|1<<20,%edi	# need nexgen32e long mode support
	and	%edi,%edx		# & nx support
	cmp	%edi,%edx
	jne	10f
	xor	%ax,%ax
1:	ret
10:	mov	$REAL(str.oldcpu),%di
20:	call	rldie
	.endfn	lcheck

//	Gets memory map from BIOS.
e820:	xor	%ebx,%ebx		# %ebx is an api state tracker
	mov	%bx,%es
	mov	$mm+"struct mman::e820",%di # es:di is destination buffer
1:	mov	$0xE820,%eax		# magic
	mov	$8+8+4+4,%ecx		# sizeof(struct SmapEntry)
	mov	$0x534d4150,%edx	# magic number
	movl	$1,8+8+4/*SmapEntry::acpi3*/(%di) # prefill ACPI attributes;
					# apparently some buggy BIOSes say
					# that they return this field, yet
					# do not fill it correctly
	int	$0x15			# ax,bx,cx,dx,di → ax,bx,cx
	jc	9f			# cf = unsupported or abuse
	cmp	%edx,%eax		# more magic means success
	jne	9f
	test	%cx,%cx			# discard empty results
	jz	5f
	mov	8/*LODWORD(SmapEntry::size)*/(%di),%eax
	or	8+4/*HIDWORD(SmapEntry::size)*/(%di),%eax
	jz	5f
	cmp	$8+8+4+1,%cx		# discard if ignore flag
	jb	4f
	testb	$1/*don't ignore*/,8+8+4/*SmapEntry::acpi3*/(%di)
	jz	5f
4:	add	$8+8+4+4,%di		# keep entry
5:	test	%ebx,%ebx		# last entry?
	jz	8f
	cmp	$mm+"struct mman::e820_end"-(8+8+4+4),%di
	jb	1b
8:	xor	%ax,%ax			# add a blank sentinel entry
	mov	$(8+8)/2,%cx
	cld
	rep stosw
	ret
9:	mov	$REAL(str.e820),%di
	call	rldie
	.endfn	e820

//	Asks keyboard to grant system 65,519 more bytes of memory.
//
//	Yup.
//
//	@assume	realmode && df=0
//	@clob	ax,di,si,es,flags
//	@mode	real
//	@see	wiki.osdev.org/A20_Line
a20:	cli
	push	%ds
	xor	%ax,%ax
	mov	%ax,%es
	dec	%ax
	mov	%ax,%ds
	mov	$0x0500,%di
	mov	$0x0510,%si
	mov	%es:(%di),%al
	push	%ax
	mov	%ds:(%si),%al
	push	%ax
	movb	$0x00,%es:(%di)
	movb	$0xff,%ds:(%si)
	cmpb	$0xff,%es:(%di)
	pop	%ax
	mov	%al,%ds:(%si)
	pop	%ax
	mov	%al,%es:(%di)
	pop	%ds
	jne	3f
	mov	$1,%ax
	call	1f
	mov	$0xad,%al
	out	%al,$0x64
	call	1f
	mov	$0xd0,%al
	out	%al,$0x64
	call	2f
	in	$0x60,%al
	push	%ax
	call	1f
	mov	$0xd1,%al
	out	%al,$0x64
	call	1f
	pop	%ax
	or	$2,%al
	out	%al,$0x60
	call	1f
	mov	$0xae,%al
	out	%al,$0x64
	call	1f
	jmp	a20
1:	in	$0x64,%al
	test	$2,%al
	jnz	1b
	ret
2:	in	$0x64,%al
	test	$1,%al
	jz	2b
	ret
3:	sti
5:	ret
	.endfn	a20

//	Copies program pages loaded into base memory, to extended memory.
//
//	@clob	esi, edi
cpyhi:	push	%es
	movpp	%ds,%es
	call	unreal
	mov	$IMAGE_BASE_REAL,%esi
	mov	$IMAGE_BASE_PHYSICAL,%edi
	mov	$v_ape_realdwords,%ecx
	cld
	rep movsl %ds:(%esi),%es:(%edi)
	sti
	pop	%es
	ret
	.endfn	cpyhi

//	Disables interrupts and switches to "unreal mode".
//
//	@return	ds, es have same base addresses as before but can access
//		4 GiB of memory
//	@clob	eax
unreal:	push	%ds
	push	%es
	cli
	lgdt	REAL(_gdtrlo)
	mov	%cr0,%eax
	or	$CR0_PE,%al
	mov	%eax,%cr0
	jmp	0f
0:	pushpop	GDT_LEGACY_DATA,%ds
	movpp	%ds,%es
	and	$~CR0_PE,%al
	mov	%eax,%cr0
	jmp	1f
1:	pop	%es
	pop	%ds
	ret

//	Reads any remaining program pages into memory which have not yet
//	been read by the boot sector.
//
//	@clob	eax, ecx, dx, esi, edi, bp
loadhi:	mov	$v_ape_highsectors,%bp
	test	%bp,%bp
	jz	9f
	mov	$mm+"struct mman::pc_drive",%si
	cld
	lodsb	#← pc_drive
	xchg	%ax,%dx
	lodsw
	lodsb	#← pc_drive_next_sector
	test	%al,%al
	jz	9f
	xchg	%ax,%cx
	lodsw	#← pc_drive_next_cylinder
	xchg	%ax,%cx
	mov	(%si),%dh #← pc_drive_next_head
	push	%es
#define	SEG 0x79000
	mov	$IMAGE_BASE_PHYSICAL+v_ape_realbytes-SEG,%edi
	push	$SEG>>4
	pop	%es
0:	call	pcread
	push	%ax
	call	unreal
	pop	%ax
	push	%cx
	xor	%esi,%esi
	xor	%ecx,%ecx
	mov	$512/4,%cl
	cld
	rep movsl %es:(%esi),%es:(%edi)
	sti
	pop	%cx
	dec	%bp
	jnz	0b
	pop	%es
9:	ret

//	Initializes long mode paging.
pinit:	push	%ds
	push	%es
	mov	$SEG>>4,%ax
	mov	%ax,%ds
	mov	%ax,%es
	xor	%di,%di
	xor	%ax,%ax
	mov	$(0x7f000-SEG)/2,%cx
	cld
	rep stosw
	movl	$0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG	# PDPT←PML4T (+)
	movl	$0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG	# PDPT←PML4T (-)
	movl	$0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG	# PDT←PDPT   (+)
	movl	$0x7a000+PAGE_V+PAGE_RW,0x7c000-SEG	# PDT←PDPT   (-)
	movl	$0x79000+PAGE_V+PAGE_RW,0x7b000-SEG	# PD←PDT     (+)
	movl	$0x79000+PAGE_V+PAGE_RW,0x7a000-SEG	# PD←PDT     (-)
	mov	$512,%cx				# PD±2MB
	mov	$PAGE_V+PAGE_RSRV+PAGE_RW,%eax
	xor	%di,%di
0:	stosl
	add	$0x1000,%eax
	scasl						# di += 4
	loop	0b
	mov	$0x7e000,%eax				# PML4T←CR3
	mov	%eax,%cr3
	pop	%es
	pop	%ds
	ret
	.endfn	pinit

//	Switch from Real Mode → Long Mode
//
//	@see	Intel Manual V3A §4.1.2
golong:	cli
	lidt	mm+"struct mman::bad_idt"
	mov	%cr4,%eax
	or	$CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
	mov	%eax,%cr4
	movl	$EFER,%ecx
	rdmsr
	or	$EFER_LME|EFER_SCE|EFER_NXE,%eax
	wrmsr
	lgdt	REAL(_gdtrlo)
	mov	%cr0,%eax
	or	$CR0_PE|CR0_PG|CR0_MP,%eax
	and	$~CR0_EM,%eax
	mov	%eax,%cr0
	ljmp	$GDT_LONG_CODE,$REAL(long)
	.endfn	golong

//	Long mode is long.
	.code64
long:	movabs	$BANE+PHYSICAL(0f),%rax
	jmp	*%rax
0:	xor	%eax,%eax
	mov	$GDT_LONG_DATA,%al
	mov	%eax,%ds
	mov	%eax,%ss
	mov	%eax,%es
	mov	%eax,%fs
	mov	%eax,%gs
	mov	$0x80000,%esp
	xor	%r12d,%r12d
	xor	%r13d,%r13d
	xor	%r14d,%r14d
	xor	%r15d,%r15d
	xor	%ebx,%ebx
	xor	%ebp,%ebp
	mov	$mm,%rdi
	mov	%cr3,%rsi
	mov	$IMAGE_BASE_PHYSICAL,%edx
	lea	v_ape_allbytes(%rdx),%ecx
	call	__map_phdrs
	push	$0x037f
	fldcw	(%rsp)
	lgdt	_gdtr					# reload GDTR for
							# virtual memory space
	movabs	$kernel,%rax
	jmp	*%rax
	.endfn	long

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § multiboot stub                                │
╚──────────────────────────────────────────────────────────────────────────────╝
	boot modernized for the nineties */

#define GRUB_MAGIC 0x1BADB002
#define GRUB_EAX 0x2BADB002
#define GRUB_AOUT (1 << 16)
#define GRUB_CHECKSUM(FLAGS) (-(GRUB_MAGIC + (FLAGS)) & 0xffffffff)

//	Grub Header.
	.align	4
ape_grub:
	.long	GRUB_MAGIC			# Magic
	.long	GRUB_AOUT			# Flags
	.long	GRUB_CHECKSUM(GRUB_AOUT)	# Checksum
	.long	RVA(ape_grub)			# HeaderPhysicalAddress
	.long	IMAGE_BASE_PHYSICAL		# TextPhysicalAddress
	.long	PHYSICAL(_edata)		# LoadEndPhysicalAddress
	.long	PHYSICAL(_end)			# BssEndPhysicalAddress
	.long	RVA(ape_grub_entry)		# EntryPhysicalAddress
	.endobj	ape_grub,globl

//	Grub Entrypoint.
//	Takes CPU out of legacy mode and jumps to normal entrypoint.
//	@noreturn
	.align	4
ape_grub_entry:
	.code32
//	cmp	$GRUB_EAX,%eax
//	jne	triplf
	push	$0
	popf
	mov	$0x40,%dl
	mov	%cr0,%eax
	and	$~CR0_PE,%eax
	mov	%eax,%cr0
	ljmpw	$0,$REAL(pc)
	.code64
	.endfn	ape_grub_entry

/*  ▄▄▒▀▀▀▀▒▒▄
█████▓▓▄░░░░  ▒▒▄
▐█▓▓█▓▄█████▓░   ▀▒▄
 ▓█▓▓▓▓▓▓▓▓▓█▓     ░▀▒░
   ▀▀▓█▓▓▓▓▓▓█▓       ░▀▒▄▄▒▄▄▄▒▒▒▀▀▀▀▀▀▀▀▀▀▀▀▀▀▒▒▄▒
       ▀▓▓█▓▓▓▓▓▄          ░                       ░▀▒▄▄                       ▄
           ▀█▓▓▓▓▓▄░                                   ░▀▒░                  ▄▓▌
            ▀█▓▓▓▓▓█▓░                                    ░▀▄░            ░▄▓██░
              ▀█▓▓▓▓▓█▄                                      ░▀▒▄▄▄▄▄▄▄▄▒▀▓█▓█▓░
                ▀█▓▓▓▓█▓░                                             ░▄▓█▓▓█▓▄▌
                  ▀█▓▓▓▓▓▄                        ▄▄▄▓▓██▓▓▒▒░      ▒▒▄▓█▓▓▓▓█▓
                   ▀█▓▓▓▓▓▓▄▄░               ░▄▄▓██▓▓▓▓▓██████████████▓▓▓▓▓▓█▀
                    ▐█▓▓▓▓▓▓▓██▓▓▄▄▄▄▄▄▄▄▄▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████████▓▓▀
                     ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█░ ░░░░░░
                     ▄░▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█▌
                     █▓▄▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▀▀▀▀▀▀▀▓█▓▓▓▓▓▓▓▓▓▓▓▓
                    ▐█▓█▓░▓█▓▓▓▓▓▓▓█▀▀▀▀▒░  ▐▓▓▓▓▓▓▄▒▀▓█▓▓▓▓▓▓▓▓█▌
                    ▐█▓▓▓█▒▀█▓▓▓▓▓▓█▌        ▀█▓▓▓▓▓█▄░▀▓▓█▓▓▓▓▓▓█░
                    █▓▓▓▓▓█░▐█▓▓▓▓▓█▌         ▀▓█▓▓▓▓█▌   ░▀█▓▓▓▓▓█▄
                    █▓▓▓▓█▌ ░█▓▓▓▓▓█░           ▓█▓▓▓▓▓░    ▒█▓▓▓▓▓█░
                    █▓▓▓▓█░  █▓▓▓▓▓█░            █▓▓▓▓▓█░    ▐█▓▓▓▓█▌
                    ▐█▓▓▓▓▓▄ █▓▓▓▓▓█         ░▄▄▓█▓▓▓▓▓█░    ▐█▓▓▓▓█░
                     ▓█▓▓▓█▓▐█▓▓▓▓█▌        ▓██▓▓▓▓▓▓█▀      ▓█▓▓▓▓█
                      ▀▓██▒▄█▓▓▓▓▓█░       ░█▓▓▓▓▓██▀░     ░▓█▓▓▓▓█▌
                         ░░█▓▓▓▓▓█▓         ░▀▀▀▀▀▀        ▓█▓▓▓▓▓▓
╔───────────────────────────────────────────────────────────▀▀▀▀▀▀───────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § cosmopolitan libc runtime runtime         ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/
kernel:	movabs	$ape_stack_vaddr,%rsp
	add	$ape_stack_memsz,%rsp
	movl	$0,0x7b000			# unmap null 2mb
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.long	(IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
#endif
	movabs	$BANE+mm,%rdi
	mov	$0x79000,%esi
	mov	$0x7f000,%edx
	call	__reclaim_boot_pages
	push	$_HOSTMETAL			# sets __hostos in crt.S
	pop	%rcx
	pushq	.Lenv0(%rip)			# envp[0][0]
	mov	%rsp,%rbp
	pushq	.Largv0+8(%rip)			# argv[0][8]
	pushq	.Largv0(%rip)			# argv[0][0]
	mov	%rsp,%rax
	push	$0				# auxv[1][1]
	push	$0				# auxv[1][0]
	push	%rax				# auxv[0][1]
	push	$31				# auxv[0][0] AT_EXECFN
	push	$0				# envp[1]
	push	%rbp				# envp[0]
	push	$0				# argv[1]
	push	%rax				# argv[0]
	push	$1				# argc
	xor	%ebp,%ebp
	xor	%eax,%eax
	xor	%edx,%edx
	xor	%edi,%edi
	xor	%esi,%esi
	xor	%r8d,%r8d
	xor	%r9d,%r9d
	xor	%r10d,%r10d
	xor	%r11d,%r11d
	jmp	_start
	.endfn	kernel

	.rodata
.Lenv0:	.asciz	"METAL=1"
.Largv0:
	.asciz	APE_COM_NAME
	.org	.Largv0+16
	.previous

#endif /* SupportsMetal() */

//	Avoid linker script variables appearing as code in objdump.
	.macro	.ldsvar	name:req
	.type	\name,@object
	.weak	\name
	.endm
	.ldsvar	_end
	.ldsvar	_etext
	.ldsvar	v_ape_realsectors
	.ldsvar	v_ape_realbytes
	.ldsvar	v_ape_highsectors
	.ldsvar	ape_idata_ro
	.ldsvar	ape_pad_rodata
	.ldsvar	ape_piro
	.ldsvar	ape_piro_end
	.type	ape_macho_end,@object
	.type	ape_note,@object
	.type	ape_note_end,@object
	.type	ape_note_vaddr,@object
	.type	ape_phdrs,@object
	.type	ape_pe_sections,@object
	.type	ape_pe_sections_end,@object
	.type	ape_text_nops,@object
	.type	__test_end,@object

	.section .commentprologue,"a",@progbits
	.globl	kLegalNotices
	.type	kLegalNotices,@object
	.hidden	kLegalNotices
kLegalNotices:/*
	...
	decentralized content
	...
	*/.previous
	.section .commentepilogue,"a",@progbits
	.byte	0
	.previous

	.section .ape.pad.head,"a",@progbits
	.type	ape_pad_head,@object
	.hidden	ape_pad_head
ape_pad_head:
	.previous

	.section .ape.pad.text,"a",@progbits
	.type	ape_pad_text,@object
	.hidden	ape_pad_text
ape_pad_text:
	.previous

	.section .ape.pad.privileged,"a",@progbits
	.type	ape_pad_privileged,@object
	.hidden	ape_pad_privileged
ape_pad_privileged:
	.align	4096
	.previous

	.section .ape.pad.rodata,"a",@progbits
	.type	ape_pad_rodata,@object
	.hidden	ape_pad_rodata
ape_pad_rodata:
	.previous

	.section .ape.pad.data,"a",@progbits
	.type	ape_pad_data,@object
	.hidden	ape_pad_data
ape_pad_data:
	.previous

	.section .idata.ro,"a",@progbits
	.type	ape_idata_ro,@object
	.hidden	ape_idata_ro
ape_idata_ro:
	.previous

	.section .dataprologue,"aw",@progbits
	.type	__data_start,@object
	.globl	__data_start
	.hidden	__data_start
__data_start:
	.previous

	.section .dataepilogue,"aw",@progbits
	.type	__data_end,@object
	.globl	__data_end
	.hidden	__data_end
__data_end:
	.previous

	.section .bssprologue,"aw",@nobits
	.type	__bss_start,@object
	.globl	__bss_start
	.hidden	__bss_start
__bss_start:
	.previous

	.section .bssepilogue,"aw",@nobits
	.type	__bss_end,@object
	.globl	__bss_end
	.hidden	__bss_end
__bss_end:
	.previous

	.section .blink,"a",@progbits
	.globl	blink_aarch64_size
blink_aarch64:
	.incbin	"ape/blink-aarch64.gz"
	.endobj	blink_aarch64,globl
blink_aarch64_size = . - blink_aarch64
	.previous

	.section .blink,"a",@progbits
	.globl	blink_darwin_arm64_size
blink_darwin_arm64:
	.incbin	"ape/blink-darwin-arm64.gz"
	.endobj	blink_darwin_arm64,globl
blink_darwin_arm64_size = . - blink_darwin_arm64
	.previous

	.section .blink,"a",@progbits
	.globl	blink_arm_size
blink_arm:
	.incbin	"ape/blink-arm.gz"
	.endobj	blink_arm,globl
blink_arm_size = . - blink_arm
	.previous

	.section .blink,"a",@progbits
	.globl	blink_i486_size
blink_i486:
	.incbin	"ape/blink-i486.gz"
	.endobj	blink_i486,globl
blink_i486_size = . - blink_i486
	.previous

	.section .blink,"a",@progbits
	.globl	blink_riscv64_size
blink_riscv64:
	.incbin	"ape/blink-riscv64.gz"
	.endobj	blink_riscv64,globl
blink_riscv64_size = . - blink_riscv64
	.previous

	.section .blink,"a",@progbits
	.globl	blink_mipsel_size
blink_mipsel:
	.incbin	"ape/blink-mipsel.gz"
	.endobj	blink_mipsel,globl
blink_mipsel_size = . - blink_mipsel
	.previous

	.section .blink,"a",@progbits
	.globl	blink_powerpc64le_size
blink_powerpc64le:
	.incbin	"ape/blink-powerpc64le.gz"
	.endobj	blink_powerpc64le,globl
blink_powerpc64le_size = . - blink_powerpc64le
	.previous

	.section .blink,"a",@progbits
	.globl	blink_powerpc_size
blink_powerpc:
	.incbin	"ape/blink-powerpc.gz"
	.endobj	blink_powerpc,globl
blink_powerpc_size = . - blink_powerpc
	.previous

	.section .blink,"a",@progbits
	.globl	blink_s390x_size
blink_s390x:
	.incbin	"ape/blink-s390x.gz"
	.endobj	blink_s390x,globl
blink_s390x_size = . - blink_s390x
	.previous

.end