/*-*- 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 "ape/ape.internal.h"
#include "libc/sysv/consts/prot.h"

#define USE_SYMBOL_HACK 1

	.section .text,"ax",@progbits
	.balign	__SIZEOF_POINTER__
	.previous
	.section .rodata,"a",@progbits
	.balign	__SIZEOF_POINTER__
__ro:	.endobj	__ro,globl,hidden		// âfor gdb readability
	.previous
	.section .data,"aw",@progbits
	.balign	__SIZEOF_POINTER__
	.previous
	.section .bss,"aw",@nobits
	.balign	__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.
	.balign	8,0				//   9: padding
	.short	ET_EXEC				//  10: ÎµxÎµcÂµÏÎ±blÎµ
#ifdef __x86_64__
	.short	EM_NEXGEN32E			//  12: amd
#elif __aarch64__
	.short	EM_AARCH64			//  12: arm
#elif __powerpc64__
	.short	EM_PPC64			//  12: open power
#elif __riscv
	.short	EM_RISCV			//  12: risc five
#endif
	.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 */

#ifdef APE_IS_SHELL_SCRIPT
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

#if !IsTiny()
//	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.0.0\"\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"

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

	.ascii	"exit 1\n"
	.endobj	emush
#endif /* !IsTiny() */

#ifdef APE_LOADER
        .section .ape.loader,"a",@progbits
	.balign	64
ape_loader:
        .incbin APE_LOADER
	.endobj	ape_loader,globl
	.balign	64
ape_loader_end:
	nop
	.endobj	ape_loader_end,globl
        .previous
#endif /* APE_LOADER */
#endif /* APE_IS_SHELL_SCRIPT */

#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:	.balign	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:	.balign	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
.balign	__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() */

#if SupportsWindows() || SupportsMetal()
/*                             ââââ
                        âââââââââââââââââ
                       ââââââââââââââââââââ
                      ââââââââââââââââââââ  âââ
                      âââââââââââââââââââ   âââââââ        ââââââ
                     ââââââââââââââââââââ  âââââââââââââââââââââ
                    ââââââââââââââââââââ   âââââââââââââââââââââ
                    ââââââââââââââââââââ  âââââââââââââââââââââ
                   ââââââââââââââââââââ  ââââââââââââââââââââââ
                   ââââââ      âââââââ   âââââââââââââââââââââ
                                    ââ  âââââââââââââââââââââ
                   âââââââââââââââ      âââââââââââââââââââââ
                 ââââââââââââââââââââ     ââââââââââââââââââ
                ââââââââââââââââââââ   ââ      ââââââ
                ââââââââââââââââââââ  âââââââ         âââââ   ââââââââââââ
               ââââââââââââââââââââ  ââââââââââââââââââââââ           ââââ
               âââââââââââââââââââ   âââââââââââââââââââââ            âââ
              ââââââââââââââââââââ  âââââââââââââââââââââ            âââ
              âââââââââââââââââââ   âââââââââââââââââââââ           âââ
             ââââââââââââââââââââ  âââââââââââââââââââââ           âââ
                             âââ  ââââââââââââââââââââââ          âââ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Î±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

	.section .pe.header,"a",@progbits
	.balign	__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() */

#if SupportsWindows()

	.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.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

#endif /* SupportsWindows() */

#if SupportsMetal()

	.section .piro.data.sort.metal_gdt,"aw",@progbits
	.balign	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

/*ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Î±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
	.balign	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
	.balign	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				// checks for i8086 / i8088 / i80186
	pop	%ax			// see intel manual volume 1 Â§20.1.2
	test	$0x80,%ah
	jnz	10f			// we now assume 32 bit is supported
	pushfl				// now check for i386, or early i486
	pop	%eax			// tests 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 amd64 ext cpuid thingy length
	mov	%edi,%eax
	inc	%edi
	cpuid				// leaf 0x80000000, clob ax/bx/cx/dx
	cmp	%edi,%eax
	jl	10f
	mov	%edi,%eax
	cpuid				// leaf 0x80000001, clob ax/bx/cx/dx
	mov	$1<<29|1<<20,%edi	// 29 = LM (long), 20 = NX (no exec)
	and	%edi,%edx		// we need to both, or we won't work
	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.
	.balign	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
	.balign	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:
	.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

#if SupportsWindows()
	.section .idata.ro,"a",@progbits
	.type	ape_idata_ro,@object
	.hidden	ape_idata_ro
ape_idata_ro:
	.previous
#endif /* SupportsWindows() */

	.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

#if !IsTiny()
#ifdef APE_IS_SHELL_SCRIPT

	.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

#endif /* APE_IS_SHELL_SCRIPT */
#endif /* !IsTiny() */

.end
