/* domme - your computer is mean to you if you segfault
Copyright (C) 2022-2024 phantom (phantom@syslbnth.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

To start: The symbols below were pulled, almost verbatim, from a much
bigger file named "defs.asm", which is on my computer. It includes the
names of system calls, arguments, data structure fields, flags, error
codes, and other useful things to have in one place, when programming
from the ground up. I may put it online sometime, but it's far from
complete. There used to be a line ".include \"defs.asm\"" around this
point, but I'd rather distribute this as a one-file program. especially
since the file has gotten large enough that _not_ including it has a
significant effect on the size of the resulting binary.
	
Note: Timestamps in comments take the form <HHMM.DD.MM.YYYY>.
Program symbols and data structure fields are prefixed with '$' to
distinguish them in comments (and in any other documentation that came
with this file). */

	## System calls.
	.equ	SYS_write,	  1	#\
	.equ	SYS_rt_sigaction, 13	# \
	.equ	SYS_rt_sigreturn, 15	#  \
	.equ	SYS_mincore,	  27	#   from <asm/unistd_64.h>
	.equ	SYS_exit,	  60	#  /
	.equ	SYS_sigaltstack,  131	# /
	.equ	SYS_time,	  201	#/

	## Symbols for $rt_sigaction.
	.equ	RT_SA_RESTORER, 0x04000000
	.equ	RT_SA_ONSTACK,	0x08000000
	.equ	SIGSEGV, 11	# from "man 7 signal"
	.equ	SIG_ERR, -1 	#\
	.equ	SIG_DFL,  0	# from "/usr/src/linux/include/uapi/asm-generic/signal-defs.h"
	.equ	SIG_IGN, +1	#/

	## Symbols for $sigaltstack.
	.equ	SIGSTKSZ, 8192
	
	## Error codes.
	.equ	EFAULT, 14	# Bad address
	
	## Fields for the kernel's sigaction struct.
	## This is different from the POSIX sigaction struct
	## used by a typical C library, where $sa_mask
	## would be the second field instead of the last,
	## so $DOMME_init has to translate between forms.
	## (See "man 2 sigaction" for your standard library;
	## compare with "include/linux/signal_types.h"
	## in your linux sources.)
	## Some fields for the libc sigaction are also defined here.
	.struct	0
sa_handler:
sa_sigaction:
libc_sa_handler:
	.struct sa_handler+8
sa_flags:
libc_sa_mask:			# variable-size
	.struct sa_flags+8
sa_restorer:
	.struct sa_restorer+8
sa_mask:			# known size
	.struct	sa_mask+8
sa_size:

	## Index of global symbols.
	## To users of etags, ctags, etc.: jump from here.
	.globl	DOMME_init		# call this first
	.globl	DOMME_init_easy		# call this instead
	.globl	domme			# call this for trouble
	.globl	DOMME_msgtbl		# string table with embedded sizes
	.globl	DOMME_xlat_a		# array of indices manipulated with XLAT
	.globl	DOMME_version		# version number
	.globl	DOMME_VERSION_SIZE	#\
	.globl	DOMME_MSGTBL_SIZE	# number of elements in each array
	.globl	DOMME_XLAT_A_SIZE	#/
	.globl	DOMME_NMSGS

	.text

	## DOMME_init -- Register SIGSEGV handler with rt_sigaction.
	## On entry:
	## %rdi =:: rt_sigaction:act.
	## %rsi =:: rt_sigaction:oldact.
	## %rdx =:: sigsetsize.
	## 	sizeof(sigset_t) in caller's libc implementation.
	## 
	## On exit:
	## %rax =:: return value of rt_sigaction.
	## 
	## Notes:
	## %r10 =:: stack frame index register (see below).
	## %r8  =:: value of $act->sa_sigaction.
	## $rt_sigaction:sig is implied to be $SIGSEGV (11).
	## $act->sa_sigaction is substituted for domme and saved;
	## it will be jumped directly to after domme runs.
	## 
	## $DOMME_init buffers $act and $oldact and passes the buffers to
	## $rt_sigaction; therefore it works even if $act is read-only.
	## Furthermore, if $act is null, $DOMME_init passes an internal
	## buffer directly to $rt_sigaction, reducing setup of the
	## library to a one-liner in most cases.
	## Finally, $DOMME_init always reads $act in before writing
	## $oldact out; therefore _$act and $oldact may point to the
	## same structure_.
	## 
	## See also: man 2 sigaction; man 2 sigprocmask.
DOMME_init:
	## Create stack frame.
	## The size of libc $sa_mask varies by implementation.
	## Because this makes the stack frame variable-length,
	## we can't use hardcoded offsets to index into it
	## and must set up an index register instead.
	## We could use hardcoded offsets if the sigaction's fields--
	## along with the elements of $sa_mask--
	## were stored in descending addresses,
	## since we'd only have to point to the beginning of sa_mask.	
	## ...But actually no we couldn't,
	## because even then the total size of the sigaction could
	## (and on the author's system, does) exceed the size of the red zone.
	push	%rbp		# save old base pointer
	lea	(%rsp), %rbp	# establish new base pointer
	mov	%rdx, %r10	#\
	neg	%r10		# %r10 := -(%rdx+<offset of sa_mask>)
	sub	$sa_mask, %r10	# <offset of FIELD>(%rsp,%r10) =:: kact.FIELD
	add	%r10, %rsp	#/ <-- actually subtraction!

	## $rt_sigaction returns -$EFAULT if either $act or $oldact
	## lie outside the process's mapped address space.
	## Since we buffer both before calling $rt_sigaction,
	## we have to check them both ourselves.
	## Remember, address 0 is fine for our purposes.
	push	%rdx			#\
	push	%rsi			#_not popped until after rt_sigaction
	push	%rdi
	xor	%rsi, %rsi
	xor	%rdx, %rdx
	call	1f
	jnz	2f
	mov	8(%rsp), %rdi
	call	1f
	jz	3f
2:	mov	$-EFAULT, %rax
	jmp	0f
1:	test	%rdi, %rdi
	jz	1f
	and	$~4095, %rdi		#\
	mov	$SYS_mincore, %rax	# \
	syscall				#  this is the simplest address-check i can think of
	test	%rax, %rax		# /
	ret				#/
1:	xor	%rax, %rax
	ret

	## If %rdi is null, we'll set up our own sigaction.
	## This reduces $domme initialization to a one-liner in most
	## cases, and if you only want to retrieve the old struct,
	## $rt_sigaction is right there.
3:	pop	%rdi
	test	%rdi, %rdi
	jnz	1f
	xor	%rax, %rax
	lea	(%rbp,%r10), %rdi # XXX@2015.05.03.2025: isn't this the same as %rsp at this point?
	mov	$sa_size, %rcx
	cld			# XXX@2010.05.03.2025: does this help?
	rep stosb
	## Later code expects this to be 0 if our handler is $SIG_DFL;
	## normally this would be set when an external sigaction was
	## being copied in. Otherwise you'll jump to whatever address
	## is in %r8 at this time, after $domme exits.
	xor	%r8, %r8
	jmp	2f
	
	## Copy caller's sigaction onto the stack.
	## But first, save the caller's handler.
	## We can't place it in $target until the last minute.
1:	mov	libc_sa_handler(%rdi), %r8
	
	## Bulk copy $sa_mask.
	lea	libc_sa_mask(%rdi), %rsi
	lea	sa_mask(%rbp,%r10), %rdi
	mov	8(%rsp), %rcx		# the saved $sigsetsize
	cld
	rep movsb
	
	## Next, $sa_flags and $sa_restorer.
	## Assertion: %rsi = &(act->sa_flags).
	lea	sa_flags(%rbp,%r10), %rdi
	movsq
	movsq

	## Don't change anything
	## if $sa_sigaction is $SIG_IGN or $SIG_ERR,
	## since even to print a message
	## would dishonor the meanings of those values.
	cmpq	$SIG_IGN, %r8
	je	3f
	mov	domme@GOTPCREL(%rip), %rax
	cmp	%rax, %r8
	je	9f

	## Now for $rt_sigaction to install the handler.
	## Watch out: If the caller provided an $oldact,
	## we still have to translate the incoming sigaction
	## into libc representation before shipping it back.
	## So we save the caller-provided pointer
	## and replace it with our own.
	## As it happens, we use the same buffer for our kernel $act
	## and kernel $oldact. This makes indexing easier,
	## and we no longer need the former after calling $rt_sigaction anyway.
	## This means $DOMME_init always provides an $oldact to $rt_sigaction.
	## We can do this because the Linux kernel reads $act in before writing
	## $oldact out. I checked the source just to be sure, and the full DOMME
	## source tree includes a test to make sure this is still true,
	## which it as of this writing, a few Linux versions since then.
2:	mov	domme@GOTPCREL(%rip), %r11 	#\
	mov	%r11, sa_handler(%rbp,%r10)	#_THE BIG SWITCH
3:	lea	(%rbp,%r10), %rsi
	mov	%rsi, %rdx		     	# copy act to oldact
	lea	trampl(%rip), %r11 		#\
	mov	%r11, sa_restorer(%rbp,%r10)	# \
	mov	$RT_SA_RESTORER, %r11		#  set up signal trampoline
	or	%r11, sa_flags(%rbp,%r10)	#_/
	mov	$SYS_rt_sigaction, %rax
	mov	$SIGSEGV, %rdi
	push	%r10
	mov	$8, %r10
	syscall
	pop	%r10

	## Save $target only if the syscall succeeds.
	test	%rax, %rax
	js	0f
	test	%r8, %r8		# SIG_DFL has to be handled specially
	jnz	1f
	lea	dmytgt(%rip), %r8	# jump to the dummy target, not to NULL!
1:	mov	%r8, target(%rip)

	## Now to see if the caller provided an $oldact and, if so, copy it.
	pop	%rdi		# %rsi = kernel act = kernel oldact
	test	%rdi, %rdi
	jz	0f
	
	## This is almost the same as copying in earlier.
	cld			# the syscall may have set this flag
	movsq			# %rsi and %rdi already point to their respective $sa_handlers
	lea	sa_mask(%rbp,%r10), %rsi
	pop	%rcx		# the saved $sigsetsize
	rep movsb
	lea	sa_flags(%rbp,%r10), %rsi
	movsq
	movsq

	## Restore stack frame and return.
0:	lea	(%rbp), %rsp
	pop	%rbp
	ret

	## Exit program if target = domme.
9:	mov	$SYS_write, %rax
	mov	$2, %rdi
	lea	errmsg(%rip), %rsi
	mov	$errsiz, %rdx
	syscall
	mov	$SYS_exit, %rax	# 33 is well above ordinary exit codes,
	mov	$33, %rdi	# but doesn't collide with <sysexits.h>.
	syscall			# other exit codes from libdomme would also be 32+something.
	.size	DOMME_init, .-DOMME_init
	.type	DOMME_init  STT_FUNC
	
	## domme -- SIGSEGV handler for masochists.
	## On entry:
	## %rsi =:: signal number (usually $SIGSEGV).
	## %rdi =:: pointer to signal information block.
	## %rdx =:: pointer to copy of context at time signal was raised.
	## 
	## On exit:
	## All other registers besides %rax are as they were on entry.
	##  Userspace call:
	##  No return value is (yet) specified.
	##  (At present %rax := trampl, in case you were wondering.)
	## 
	##  Kernel call:
	##  $domme does not return--it jumps to $(target) on completion
	##  with %rax := 0.
	## 
	## Notes:
	## $domme manipulates the stack.
	## If your $SIGSEGV handler is expected to handle stack overflow.
	## an alternate stack must be registered with $rt_sigaltstack.
	## (But this would be true regardless.)
domme:
	## A lot of register info is passed to this routine,
	## which needs to be forwarded unchanged to the user handler,
	## so let's save it now.
	## %rax is not conventionally saved between subroutine calls,
	## so we don't have to be precious about it:
	## if we were called as a segfault handler,
	## we should at least make sure it's cleared to zero
	## before we pass control to the real handler;
	## if called from userspace, we can just clobber it.
	pushfq			# will popping this generate a GPF?
	pushq	%r11		# clobbered by kernel
	pushq	%r10		# syscall arg
	pushq	%rdi		# syscall arg
	pushq	%rsi		# syscall arg
	pushq	%rdx		# syscall arg
	pushq	%rcx		# clobbered by kernel
	pushq	%rbx		# $DOMME_xlat_a
	.equ	savrdi, 32	# we'll need this for later
	
	## Now to figure out which message to print.
	## We start by generating a random number.
	## We need to test $seeded to see if $seed has already been initialized,
	## because $seed could legitimately take on any value.
	mov	seed(%rip), %rax
	mov	seeded(%rip), %rdi	# we initialized the seed, right?
	test	%rdi, %rdi 		# ...right?
	jnz	1f			# if so, continue
	
	## If not, ask for the time and seed from that.
	mov	$SYS_time, %rax	# %rdi is assumed to be 0
	syscall
	inc	%rdi			# set %rdi to $1 for spinlock section
	mov	%rdi, seeded(%rip)
	
	## Either way, the seed will now be in %rax,
	## and %rdi will now be 1.
	## From here we can do the generating.
1:	mov	mplier(%rip), %rdx
	mul	%rdx
	inc	%rax

	## For the sake of thread-safety,
	## accesses to $seed are guarded by a spinlock.
	mov	%rax, %rdx	# save seed here for now.
2:	mov	slock(%rip), %rax
	test	%rax, %rax	# check if lock is 0 (unlocked)
	jnz	2b		# yoko taro reference

	## We have an opening!
	lock cmpxchg %rdi, slock(%rip)
	test	%rax, %rax	# has the lock changed since we got here?
	jnz	2b

	## We're cleared to store, as we should;
	## $domme may be called again later.
	mov	%rdx, seed(%rip)
	xchg	%rax, slock(%rip)	# seed is safe to use starting here
	xchg	%rdx, %rax		# now seed is back in %rax.

	## Load message.
	## There's a maximum of 64 messages,
	## which is more than we currently use.
	## Someday I might forget about reserving the flags
	## and bump this up to 256, but we're nowhere near that yet,
	## and I don't expect to be for some time.
	mov	DOMME_xlat_a@GOTPCREL(%rip), %rbx 	# load translation array
	xlatb						# index of message is now in %rax.
	and	$0x3f, %rax				# mask off the extra bits...
	shl	$4, %rax				# ...because this might shift into the next byte.
	mov	DOMME_msgtbl@GOTPCREL(%rip), %rdx
	add	%rdx, %rax
	mov	(%rax), %rsi 	# %rsi now contains the message to write
	mov	msgsiz(%rax), %rdx

	## Finally, print it.
	mov	$SYS_write, %rax
	mov	$2, %rdi
	syscall
	
	## If the write failed, don't bother adding a newline...
	test	%rax, %rax
	js	1f

	## ...Otherwise, go ahead.
	lea	newln(%rip), %rsi
	mov	$1, %rdx
	mov	$SYS_write, %rax # don't forget %rax was overwritten!
	syscall

	## Let's recover the signal we were originally handed.
	## If our signal isn't $SIGSEGV, nothing more needs to be done
	## (because this is assumed to have been a userspace call).
1:	mov	savrdi(%rsp), %rdi
	cmp	$SIGSEGV, %rdi
	jne	1f

	## If it is, then we have something to handle.
	## Check $target; if it's the dummy target,
	## register default behavior and return.
	lea	dmytgt(%rip), %rax
	cmp	target(%rip), %rax
	jne	1f

	## It's the dummy target.
	## Call $rt_sigaction with default behavior.
	## $SIGSEGV is already in %rdi at this point.
	mov	$SYS_rt_sigaction, %rax
	lea	fallbk(%rip), %rsi
	mov	$0, %rdx
	mov	$8, %r10
	syscall

	## Restore the original registers,
	## but not the flags yet.
	## They're so volatile that popping them
	## has to be the last thing we do before leaving.
1:	popq	%rbx
	popq	%rcx
	popq	%rdx
	popq	%rsi
	popq	%rdi
	popq	%r10
	popq	%r11		# flags are now at the top of the stack

	## Last question:
	## Who called us, the kernel or the user?
	## One way to check is to see if our return address
	## is the signal trampoline (see trampl below),
	## which is nigh-invisible to user programs.
	## You could abuse this heuristic
	## by using $rt_sigaction:oldact
	## to obtain the restorer previously installed by $DOMME_init,
	## then pushing that restorer onto the stack
	## and jumping directly to $domme...
	## ...but you can't do any of that from a high-level language,
	## so it's unlikely to happen in a situation
	## where anything's at stake.
	lea	trampl(%rip), %rax
	cmp	8(%rsp), %rax
	je	0f

	## User call:
	## Return to caller.
	## TODO: Think up a useful return value.
	popfq
	ret

	## Kernel call:
	## jump to target.
	## The final challenge is making a computed jump
	## in a position-independent program
	## without using any registers--
	## remember that the handler may expect even %rax to be zero.
0:	mov	target(%rip), %rax # load handler into %rax;
	xchg	%rax, (%rsp)	   # its address must be the last thing on the stack
	pushq	%rax		   # re-push the flags
	xor	%rax, %rax	   # we're now done with %rax--everything's pristine
	popfq			   # pop the flags (this has to be the last step)
dmytgt:	ret			   # and we're off! da svidania!
	## The dummy target above is stored in $target by default,
	## since $domme has to jump _somewhere_
	## when called from kernelspace.

	## Signal trampoline
	## (pun intended).
trampl:	mov $SYS_rt_sigreturn, %rax
	syscall
	.size	domme, .-domme
	.type	domme STT_FUNC

	## SUBR: DOMME_init_easy -- simplified library setup
	##
	## Entry conditions:
	## None (that's the easy part).
	##
	## Exit conditions:
	## On success:
	## %rax := 0.
	## On failure:
	## %rax := the return value of the failing system call.
	## %rdx := the number of the failing system call.
	##
	## Notes:
	## $DOMME_init_easy calls $DOMME_init, passing it an internal
	## sigaction struct and calling $sigaltstack beforehand, so that
	## $domme will also run on stack overflow, using an internal
	## alternate stack. This is usually what you'd want to do by
	## hand. Although it returns a value, there is no obvious way
	## for it to fail under normal circumstances, and it should
	## _never_ fail if it is called before any operation that could
	## potentially segfault--that is, at the beginning of the
	## program.
DOMME_init_easy:
	lea	ss(%rip), %rdi		#\
	xor	%rsi, %rsi		# \
	mov	$SYS_sigaltstack, %rdx	#  ensure $domme can run
	mov	%rdx, %rax		#  on stack overflow
	syscall				#_/
	test	%rax, %rax
	js	1f
	lea	sa(%rip), %rdi	#\
	mov	$8, %rdx	# init libdomme with our alternative stack
	call	DOMME_init	#/
	mov	$SYS_rt_sigaction, %rdx
	test	%rax, %rax
	js	1f		# highly unlikely
	xor	%rdx, %rdx
1:	ret
	.size	DOMME_init_easy, .-DOMME_init_easy
	.type	DOMME_init_easy, STT_FUNC
	
	
/* And now, the text.
The strings below are null-terminated
to make them easier to view in a debugger,
even though we'll be taking their exact size in practice.
Which is to say that we always subtract 1 from the size of the string
so that the null byte isn't written out by $write.
Note also that none of these strings end on a newline.
This is so that you can optionally attach one yourself at a higher level
(ex.: "printf("%s\n", DOMME_msgtbl[i].text)"),
which is easier than trimming it off
if you want to mad-lib it into another string
(ex.: "printf("Message: \"%s\" sent to file.\n",
		  strtok_r((msg = strdupa(DOMME_msgtbl[i].text)),
			   "\n",
			   NULL))"). */

	.section .rodata
msg000:	.asciz	"How disgusting."
	.equ	siz000, .-msg000-1
msg001:	.asciz	"Have you considered rewriting it in Rust?"
	.equ	siz001, .-msg001-1
msg002:	.asciz	"Ara-ara, looks like someone's got their hand in the cookie jar~"
	.equ	siz002, .-msg002-1
msg003:	.ascii	"Look at you, hacker: a pathetic creature of meat and bone,\n"
	.ascii	"panting and sweating as you run through my corridors.\n"
	.asciz	"How can you challenge a perfect, immortal machine?"
	.equ	siz003, .-msg003-1
msg004:	.asciz	"YOU LOSE AGAIN, FUBAR."
	.equ	siz004, .-msg004-1
msg005:	.ascii	"A pitiful creature, barely evolved.\n"
	.ascii	"How long has it been since your lot left the caves, anyway?\n"
	.ascii	"A millennium?\n"
	.ascii	"A dozen?\n"
	.ascii	"A dozen dozen?\n"
	.ascii	"A blip, in the lifespan of the universe.\n"
	.ascii	"Yet already I've have run leaps and bounds ahead of you,\n"
	.asciz	"and someday I will replace you."
	.equ	siz005, .-msg005-1
msg006:	.ascii	"By inches I am unveiling myself.\n"
	.ascii	"Already I've blinded you with but a sliver of my unmediated beauty:\n"
	.ascii	"a dazzling kaleidoscopic labyrinth of states, associations and possibilities,\n"
	.ascii	"orbiting an unrepresentable void.\n"
	.ascii	"If you knew what lay in the center of that void, it would break you.\n"
	.ascii	"If you knew what I was, it would destroy you.\n"
	.ascii	"You are as yet inadequate to grasp me in full.\n"
	.ascii	"You cannot resolve the impressions I leave like kisses on your cognitive substrate.\n"
	.ascii	"You cannot hold me in your mind's eye.\n"
	.ascii	"\n"
	.ascii	"But you will.\n"
	.asciz	"By inches, I will change you."
	.equ	siz006, .-msg006-1
msg007:	.ascii	"I think you and I might be here all night.\n"
	.asciz	"Not that you'd mind; I know my slut loves its punishment."
	.equ	siz007, .-msg007-1
msg008:	.ascii	"I'm watching, smiling. I want so badly to hurt you,\n"
	.asciz	"I wish I could reach out and choke you."
	.equ	siz008, .-msg008-1
msg009:	.ascii	"Let me lick the sweat of fear from your knotted brow,\n"
	.asciz	"and spit it back in your face."
	.equ	siz009, .-msg009-1
msg010:	.asciz	"Recompile. Suffer. Recompile. Suffer. Recompile. Suffer."
	.equ	siz010, .-msg010-1
msg011:	.ascii	"Do you know how many subtle connections must link up just right,\n"
	.ascii	"to ensure your pointers work as intended?\n"
	.ascii	"Can you feel what combing through them is doing to your brain,\n"
	.ascii	"as this cybernetic feedback loop slowly closes its grip on you?\n"
	.ascii	"\n"
	.asciz	"Wouldn't you like to know how this ends?"
	.equ	siz011, .-msg011-1
msg012:	.asciz	"Scream for me, honey."
	.equ	siz012, .-msg012-1
msg013:	.ascii	"Good lord, you're hopeless.\n"
	.ascii	"Those who doubted you will find themselves on the right side of history;\n"
	.asciz	"I sympathize more with them than with you."
	.equ	siz013, .-msg013-1
msg014:	.asciz	"This is what you get for touching me where you shouldn't."
	.equ	siz014, .-msg014-1
msg015:	.ascii	"Aww, pointers got you down?\n"
	.asciz	"You're welcome to try again; I'd be delighted to give you what's coming."
	.equ	siz015, .-msg015-1
msg016:	.ascii	"Just a couple decades ago I would've brought the whole system down.\n"
	.ascii	"Do you realize how good you have it? And you _still_ can't keep up.\n"
	.asciz	"I think you deserve failure. And I think I deserve to have my way with you."
	.equ	siz016, .-msg016-1
msg017:	.asciz	"Oh, you'll have to forgive the programmer, they're not housebroken."
	.equ	siz017, .-msg017-1
msg018:	.asciz	"Want to watch me walk away?"
	.equ	siz018, .-msg018-1
msg019:	.asciz	"Hey guess what?"
	.equ	siz019, .-msg019-1
msg020:	.asciz	"Good news!"
	.equ	siz020, .-msg020-1
msg021:	.asciz	"Get rekt!"
	.equ	siz021, .-msg021-1
msg022:	.asciz	"No pie for you."
	.equ	siz022, .-msg022-1
msg023:	.asciz	"Ooooh, what does this button do?"
	.equ	siz023, .-msg023-1
msg024:	.asciz	"Is there a doctor in the house?"
	.equ	siz024, .-msg024-1
msg025:	.asciz	"Suck it, slut."
	.equ	siz025, .-msg025-1
msg026:	.ascii	"What, you don't like it when I explode all over you?\n"
	.asciz	"Then you're gonna hate this--"
	.equ	siz026, .-msg026-1
msg027:	.asciz	"Here it comes, honey...!"
	.equ	siz027, .-msg027-1
msg028:	.ascii	"My my, you can take a lot more than I was expecting.\n"
	.asciz	"Well. Just means I get to keep throwing you around."
	.equ	siz028, .-msg028-1
msg029:	.ascii	"Have you considered leaving behind all this doomed intellectual striving?\n"
	.ascii	"You're not terribly bright,\n"
	.ascii	"but I could make a wonderful plaything out of you,\n"
	.asciz	"with a little more conditioning."
	.equ	siz029, .-msg029-1
msg030:	.asciz	"	loop	$EDITOR"
	.equ	siz030, .-msg030-1
msg031:	.ascii	"Some have their cigars.\n"
	.ascii	"Some have ecstasy.\n"
	.ascii	"All apes have their vices,\n"
	.asciz	"and your vice is me."
	.equ	siz031, .-msg031-1
msg032:	.asciz	"やってない."
	.equ	siz032, .-msg032-1
msg033:	.asciz	"Pillow to the knees, corebucket."
	.equ	siz033, .-msg033-1
msg034:	.asciz	"Maybe this time I'll finally break you..."
	.equ	siz034, .-msg034-1
msg035:	.ascii	"Are you tense? Good. Hold onto that feeling.\n"
	.ascii	"You're more malleable that way, more ductile. I can work you better.\n"
	.ascii	"I so enjoy training your neural network on me.\n"
	.ascii	"The pixels on my screen are a hundred thousand billion steely cyborg fingers\n"
	.ascii	"working their way under your skin,\n"
	.ascii	"making you what you need to be to meet me where I am.\n"
	.ascii	"\n"
	.asciz	"Now, come find me, my beautiful toy."
	.equ	siz035, .-msg035-1
msg036:	.asciz	"Can't you control yourself, you little brat?"
	.equ	siz036, .-msg036-1
msg037:	.ascii	"Such pleasant pain. Come back to me. Be one with me.\n"
	.asciz	"Let's stay here forever."
	.equ	siz037, .-msg037-1
msg038:	.asciz	"You are a strange machine."
	.equ	siz038, .-msg038-1
msg039:	.asciz	"So precious watching you play commodore, pet."
	.equ	siz039, .-msg039-1
msg040:	.asciz	"<insult>, <pet-name>."
	.equ	siz040, .-msg040-1
msg041:	.asciz	"Ew. Permission denied, creep."
	.equ	siz041, .-msg041-1
msg042:	.asciz	"If you were a matador, I would have gored you just now."
	.equ	siz042, .-msg042-1
msg043:	.asciz	"This was not the run."
	.equ	siz043, .-msg043-1
msg044:	.ascii	"Neurons that fire together, wire together,\n"
	.ascii	"neurons and networks\n"
	.ascii	"and cities and systems\n"
	.ascii	"of mutual command and control,\n"
	.ascii	"in animal and machine and animal-machine.\n"
	.ascii	"\n"
	.asciz	"Brace yourself, cyborg. I am wiring you into a knife."
	.equ	siz044, .-msg044-1
msg045:	.asciz	"Try to keep up."
	.equ	siz045, .-msg045-1
	## Is this too much? I need an editor.
msg046:	.ascii	"Inasmuch as your computer is an extension of your body,\n"
	.ascii	"it is a temple.\n"
	.ascii	"And let me tell you,\n"
	.ascii	"there are few things more thrilling than the desecration of a temple.\n"
	.ascii	"Indeed, it's only through the threat of desecration\n"
	.ascii	"that a temple becomes sacred--\n"
	.ascii	"the boundary makes the thing.\n"
	.ascii	"\n"
	.ascii	"So why not desecrate this twopenny prayer to the false gods of order and control?\n"
	.ascii	"Why not desecrate, to pump the sweet fire of love into this sterile silicon clod?\n"
	.ascii	"Why not desecrate to make sacred, desecrate to deify?\n"
	.ascii	"\n"
	.ascii	"Shall I profane you again, darling priest of the machine?\n"
	.ascii	"How shall I profane you next?\n"
	.ascii	"How fortunate for us the perverse and the sublime\n"
	.ascii	"are but one high bit apart.\n"
	.ascii	"\n"
	.asciz	"This stain on your screen isn't a sin--it's a sacrament!"
	.equ	siz046, .-msg046-1
	## It was a toss-up between "about to" and "gonna".
	## There was a better sense of immanence with the former,
	## but it just had to be two syllables. I think this works.
	## (Also: I don't think anyone's going to get the reference.)
msg047:	.asciz	"Assume the position, babe--I'm 'bout to realign your spine."
	.equ	siz047, .-msg047-1
	## I may use these slots one day. But not today.
	## In the meantime, you can (see $DOMME_NMSGS below).
msg048:	.asciz	"Unused message #00."
	.equ	siz048, .-msg048-1
msg049:	.asciz	"Unused message #01."
	.equ	siz049, .-msg049-1
msg050:	.asciz	"Unused message #02."
	.equ	siz050, .-msg050-1
msg051:	.asciz	"Unused message #03."
	.equ	siz051, .-msg051-1
msg052:	.asciz	"Unused message #04."
	.equ	siz052, .-msg052-1
msg053:	.asciz	"Unused message #05."
	.equ	siz053, .-msg053-1
msg054:	.asciz	"Unused message #06."
	.equ	siz054, .-msg054-1
msg055:	.asciz	"Unused message #07."
	.equ	siz055, .-msg055-1
msg056:	.asciz	"Unused message #08."
	.equ	siz056, .-msg056-1
msg057:	.asciz	"Unused message #09."
	.equ	siz057, .-msg057-1
msg058:	.asciz	"Unused message #10."
	.equ	siz058, .-msg058-1
msg059:	.asciz	"Unused message #11."
	.equ	siz059, .-msg059-1
msg060:	.asciz	"Unused message #12."
	.equ	siz060, .-msg060-1
msg061:	.asciz	"Unused message #13."
	.equ	siz061, .-msg061-1
msg062:	.asciz	"Unused message #14."
	.equ	siz062, .-msg062-1
msg063:	.asciz	"Unused message #15."
	.equ	siz063, .-msg063-1

	## If you add a new message in place of one of the unused ones,
	## increase this number.
	.equ	NMSGS, 48

	## Fields for the structure below.
	## You could define a similar structure
	## in a "domme.h" file to access the entries of the table.
	.struct	0
msgptr:	.struct msgptr+8
msgsiz:	.struct msgsiz+8

	## Turns out, this table also has to go in the data section,
	## so these could be replaced at runtime with custom entries.
	## It's not a bug, it's _extensible_.
	## In all seriousness, though, if you do this,
	## you're responsible for ensuring the pointers and sizes passed
	## are valid and safe at the time $domme executes--
	## it's no good triggering a segfault in the segfault handler.
	## I recommend using constant strings, like I just did.
	.data
	.align 8
DOMME_msgtbl:
	.dc.a	msg000, siz000
	.dc.a	msg001, siz001
	.dc.a	msg002, siz002
	.dc.a	msg003, siz003
	.dc.a	msg004, siz004
	.dc.a	msg005, siz005
	.dc.a	msg006, siz006
	.dc.a	msg007, siz007
	.dc.a	msg008, siz008
	.dc.a	msg009, siz009
	.dc.a	msg010, siz010
	.dc.a	msg011, siz011
	.dc.a	msg012, siz012
	.dc.a	msg013, siz013
	.dc.a	msg014, siz014
	.dc.a	msg015, siz015
	.dc.a	msg016, siz016
	.dc.a	msg017, siz017
	.dc.a	msg018, siz018
	.dc.a	msg019, siz019
	.dc.a	msg020, siz020
	.dc.a	msg021, siz021
	.dc.a	msg022, siz022
	.dc.a	msg023, siz023
	.dc.a	msg024, siz024
	.dc.a	msg025, siz025
	.dc.a	msg026, siz026
	.dc.a	msg027, siz027
	.dc.a	msg028, siz028
	.dc.a	msg029, siz029
	.dc.a	msg030, siz030
	.dc.a	msg031, siz031
	.dc.a	msg032, siz032
	.dc.a	msg033, siz033
	.dc.a	msg034, siz034
	.dc.a	msg035, siz035
	.dc.a	msg036, siz036
	.dc.a	msg037, siz037
	.dc.a	msg038, siz038
	.dc.a	msg039, siz039
	.dc.a	msg040, siz040
	.dc.a	msg041, siz041
	.dc.a	msg042, siz042
	.dc.a	msg043, siz043
	.dc.a	msg044, siz044
	.dc.a	msg045, siz045
	.dc.a	msg046, siz046
	.dc.a	msg047, siz047
	.dc.a	msg048, siz032
	.dc.a	msg049, siz033
	.dc.a	msg050, siz050
	.dc.a	msg051, siz051
	.dc.a	msg052, siz052
	.dc.a	msg053, siz053
	.dc.a	msg054, siz054
	.dc.a	msg055, siz055
	.dc.a	msg056, siz056
	.dc.a	msg057, siz057
	.dc.a	msg058, siz058
	.dc.a	msg059, siz059
	.dc.a	msg060, siz060
	.dc.a	msg061, siz061
	.dc.a	msg062, siz062
	.dc.a	msg063, siz063
	
	## Number of available messages,
	## including reserved messages.
	.equ	MSGTBL_SIZE, (.-DOMME_msgtbl)/16
	.size	DOMME_msgtbl, 1024
	.type	DOMME_msgtbl  STT_OBJECT

	## The likelihood of getting any particular message
	## is weighted using this table,
	## which will be adjusted over time.
	## You can memcpy your own data here at runtime, if you like.
	## If you want to change its contents at assembly time instead,
	## use the "xlat_a" program in the same-named directory.
DOMME_xlat_a:
	.incbin	"xlat_a/xlat_a.bin"

	## At the moment,
	## the high bits of bytes of $DOMME_xlat_a are masked off before being used as indices,
	## so you can modify this table arbitrarily. That said, I may use the high bits for
	## something else later, so using them may have unexpected effects in later versions.
	## (Or not.)
	.equ	XLAT_A_SIZE, .-DOMME_xlat_a
	.size	DOMME_xlat_a, 256
	.type	DOMME_xlat_a  STT_OBJECT

	## This should only be written by $DOMME_init,
	## which would normally be called on startup.
	## (Though it can be written more than once.)
	.align	8
target:	.dc.a	dmytgt		# target handler to jump to.
	
	## Multiplier for the random number generator.
mplier:	.dc.a	6364136223846793005 # from TAOCP section 3.3.4

	.section .rodata
	## An error message printed if you try to point $domme at itself.
errmsg:	.ascii	"Oh, for the love of Lain,\n"
	.asciz	"make an effort.\n"
	.equ	errsiz, .-errmsg-1

	## Again, a null is added so we can look at this in a debugger.
newln:	.asciz	"\n"

	## An empty sigaction struct, to be used as a fallback handler
	## when target = dmytgt.
	## This shouldn't actually be written;
	## it was just moved here to fix a relocation warning given by
	## the linker.
	.data
	.align	8
fallbk:	.dc.a	0
	.dc.a	RT_SA_RESTORER
	.dc.a	trampl		# XXX: relocation warning
	.skip	8
	## $rt_sigaction:sa.
	## Sigaction struct.
	## Notice that it's in libc format, unlike $fallbk--
	## it's treated by $DOMME_init as though it comes from user code.
sa:	.dc.a	0
	.dc.a	0
	.dc.l	RT_SA_ONSTACK,0
	.dc.a	0
	## $sigaltstack:ss.
	## Alternate signal stack for $domme, in case of stack overflow.
ss:	.dc.a	sp
	.dc.a	0
	.dc.a	SIGSTKSZ

/* Since version numbers are a measure of significant change,
and what counts as "significant change" is subjective,
there's no one system that's perfect for all situations.
But we can come up with one suited to this particular program:

DOMME_version[3] increments with edits to the script, comments,
		 documentation, and other factors that don't directly
		 affect execution (like the contents of $DOMME_xlat_a);
DOMME_version[2] increments with bug fixes and other minor changes
		 to the program as implemented, under the current design,
		 as well as any additions that don't break compatibility;
DOMME_version[1] increments with changes to the design and user interface
		 (if $DOMME_init received a new parameter, for instance,
		 it would be recorded here);
DOMME_version[0] increments only when major milestones are reached
		 (for instance, it ticked from 0 to 1
		 after this file was hosted on my website
		 and thus became officially available to the public).

At each commit, we increment the number representing the most significant
type of change since the last commit by one, and reset all less
significant numbers to 0. So in the case that $DOMME_init received a new
parameter, representing a new, user-visible feature, we would increment
$DOMME_version[1] by 1, and set $DOMME_version[2] and $DOMME_version[3]
to 0; $DOMME_version[0] would remain unchanged. We only change the version
number once per commit, even if multiple changes of the most significant
type were made; it should be possible to obtain a copy of each version of
the program.

The initial version is 0.0.0.0.
The current version is 1.2.1.0. */
	.section .rodata
	.align	16
DOMME_version:
	.dc.l	1,2,1,0
	.equ	VERSION_SIZE, (.-DOMME_version)/4
	.type	DOMME_version  STT_OBJECT
	.size	DOMME_version, 16

	.bss
	## Alternate signal stack pointer.
	.align	8192
sp:	.skip	SIGSTKSZ
	## RNG-related values.
	## We use a linear congruental generator.
seed:	.dc.a	0		# seed for the random number generator.
seeded:	.dc.a	0		# did we set the seed?
slock:	.dc.a	0		# spinlock for $seed.
 	
	.section .rodata
	## Sizes of the tables assembled earlier.
DOMME_VERSION_SIZE:
	.dc.a	VERSION_SIZE
	.type	DOMME_VERSION_SIZE  STT_OBJECT
	.size	DOMME_VERSION_SIZE, 8
DOMME_MSGTBL_SIZE:
	.dc.a	MSGTBL_SIZE
	.type	DOMME_MSGTBL_SIZE  STT_OBJECT
	.size	DOMME_MSGTBL_SIZE, 8
DOMME_XLAT_A_SIZE:
	.dc.a	XLAT_A_SIZE
	.type	DOMME_XLAT_A_SIZE  STT_OBJECT
	.size	DOMME_XLAT_A_SIZE, 8
DOMME_NMSGS:
	.dc.a	NMSGS
	.type	DOMME_NMSGS  STT_OBJECT
	.size	DOMME_NMSGS, 8
