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

//	APE Loader Executable Structure
//	Linux, FreeBSD, NetBSD, OpenBSD

	.balign	8
ehdr:	.ascii	"\177ELF"
	.byte	ELFCLASS64
	.byte	ELFDATA2LSB
	.byte	1
	.byte	ELFOSABI_FREEBSD
	.quad	0
	.word	ET_EXEC			# e_type
	.word	EM_NEXGEN32E		# e_machine
	.long	1			# e_version
	.quad	_start			# e_entry
	.quad	phdrs - ehdr		# e_phoff
	.quad	0			# e_shoff
	.long	0			# e_flags
	.word	64			# e_ehsize
	.word	56			# e_phentsize
	.word	4			# e_phnum
	.word	0			# e_shentsize
	.word	0			# e_shnum
	.word	0			# e_shstrndx
	.endobj	ehdr,globl

	.balign	8
phdrs:	.long	PT_LOAD			# p_type
	.long	PF_R|PF_X		# p_flags
	.quad	0			# p_offset
	.quad	ehdr			# p_vaddr
	.quad	ehdr			# p_paddr
	.quad	filesz			# p_filesz
	.quad	filesz			# p_memsz
	.quad	PAGESIZE		# p_align

	.long	PT_LOAD			# p_type
	.long	PF_R|PF_W		# p_flags
	.quad	0			# p_offset
	.quad	bss			# p_vaddr
	.quad	bss			# p_paddr
	.quad	0			# p_filesz
	.quad	bsssize			# p_memsz
	.quad	PAGESIZE		# p_align

	.long	PT_GNU_STACK		# p_type
	.long	PF_R|PF_W		# p_flags
	.quad	0			# p_offset
	.quad	0			# p_vaddr
	.quad	0			# p_paddr
	.quad	0			# p_filesz
	.quad	0			# p_memsz
	.quad	16			# p_align

	.long	PT_NOTE			# p_type
	.long	PF_R			# p_flags
	.quad	note - ehdr		# p_offset
	.quad	note			# p_vaddr
	.quad	note			# p_paddr
	.quad	notesize		# p_filesz
	.quad	notesize		# p_memsz
	.quad	8			# p_align
	.endobj	phdrs

note:	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"OpenBSD"
2:	.balign	4
3:	.long	0
4:	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"NetBSD"
2:	.balign	4
3:	.long	901000000
4:	.endobj	note
	notesize = . - note

	.balign	64,0				# for ape.S dd
	.org	0x180				# for ape.S dd

//	APE Loader XNU Header
//
//	This header is dd'd backwards by the APE shell script when
//	running on Mac OS X.
//
//	@see	ape/ape.S
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
	.quad	ehdr				# vaddr
	.quad	4096				# memsz
	.quad	0				# file offset
	.quad	filesz				# file size
	.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
	.quad	_start				# vaddr
	.quad	textsz				# memsz
	.long	textoff				# offset
	.long	6				# align 2**6 = 64
	.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
	.quad	bss				# vaddr
	.quad	bsssize				# memsz
	.quad	0				# offset
	.quad	0				# file size
	.long	PROT_EXEC|PROT_READ|PROT_WRITE	# maxprot
	.long	PROT_READ|PROT_WRITE		# initprot
	.long	1				# segment section count
	.long	0				# flags
310:	.ascin	"__bss",16			# section name (.bss)
	.ascin	"__DATA",16
	.quad	bss				# vaddr
	.quad	bsssize				# memsz
	.long	0				# 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
	.quad	0x3fb29ee4ac6c87aa		# uuid1
	.quad	0xdd2c9bb866d9eef8		# uuid2
50:	.long	MAC_LC_UNIXTHREAD
	.long	60f-50b				# cmdsize
	.long	MAC_THREAD_NEXGEN32E		# flavaflav
	.long	(520f-510f)/4			# count
510:	.quad	0				# rax
	.quad	0				# rbx
	.quad	0				# rcx
	.quad	_HOSTXNU			# 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	macho

	.balign	64,0				# for ape.S dd
	.org	0x400				# for ape.S dd

//	Ape Loader Entrpoint
//
//	This is normally called by the operating system. However it may
//	be called by the Actually Portable Executables themselves, when
//	re-executing a program. Just do this:
//
//	    memcpy(0x200000, loader)
//	    lea handoff(%rip),%rcx
//	    lea argblock(%rip),%rsp
//	    jmp 0x200400
//
//	@see	APE_LOADER_ENTRY
//	@see	ape/loader.h
_start:

//	Hack for detecting M1 Rosetta environment.
//	https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
	cmp	$-1,%ebx
	jne	0f
	cmp	$+1,%edx
	jne	0f
	mov	$_HOSTXNU,%dl
	xor	%ecx,%ecx

0:	mov	%rsp,%rsi
	jmp	ApeLoader
	.endfn	_start,globl

//	System Call Entrpoint
//
//	This function is used by the APE loader to make system calls.
//	We also pass a reference to this function to the APE binary's
//	_start() function. It's needed because on OpenBSD, msyscall()
//	restricts which pages can issue system calls, and it can only
//	be called once. Therefore if we want to be load and re-load a
//	binary multiple times without calling the system execve(), we
//	need to be able to handover the SYSCALL function. We hardcode
//	this to a fixed address, but that shouldn't be used, since we
//	would ideally want to move it to a random page in the future.
__syscall_loader:
	clc
	syscall
	jc	1f
	ret
1:	neg	%rax
	ret
	.endfn	__syscall_loader,globl
