
; flat assembler interface for Linux x64
; Copyright (c) 1999-2022, Tomasz Grysztar.
; All rights reserved.

O_ACCMODE  = 0003o
O_RDONLY   = 0000o
O_WRONLY   = 0001o
O_RDWR	   = 0002o
O_CREAT    = 0100o
O_EXCL	   = 0200o
O_NOCTTY   = 0400o
O_TRUNC    = 1000o
O_APPEND   = 2000o
O_NONBLOCK = 4000o

S_ISUID    = 4000o
S_ISGID    = 2000o
S_ISVTX    = 1000o
S_IRUSR    = 0400o
S_IWUSR    = 0200o
S_IXUSR    = 0100o
S_IRGRP    = 0040o
S_IWGRP    = 0020o
S_IXGRP    = 0010o
S_IROTH    = 0004o
S_IWOTH    = 0002o
S_IXOTH    = 0001o

init_memory:
	mov	eax,esp
	and	eax,not 0FFFh
	add	eax,1000h-10000h
	mov	[stack_limit],eax
	xor	edi,edi
	mov	eax,12
	syscall
	mov	ecx,[memory_setting]
	shl	ecx,10
	jnz	allocate_memory
	mov	ecx,1000000h
      allocate_memory:
	mov	r9d,eax
	cmp	rax,r9
	jne	high_brk
	mov	[additional_memory],eax
	lea	edi,[eax+ecx]
	mov	eax,12
	syscall
	mov	r9d,eax
	cmp	rax,r9
	jne	no_low_memory
	mov	[memory_end],eax
	sub	eax,[additional_memory]
	shr	eax,2
	add	eax,[additional_memory]
	mov	[additional_memory_end],eax
	mov	[memory_start],eax
	ret
      high_brk:
	xor	r9d,r9d
	or	r8,-1
	mov	r10d,62h		; MAP_PRIVATE + MAP_ANONYMOUS + MAP_32BIT
	mov	edx,3			; PROT_READ + PROT_WRITE
	mov	esi,ecx
	xor	edi,edi
	mov	eax,9			; sys_mmap
	syscall
	cmp	eax,-1
	je	mmap_with_hint
	mov	r9d,eax
	cmp	rax,r9
	jne	mmap_unusable
	add	r9d,esi
	jnc	mmap_ok
      mmap_unusable:
	mov	rdi,rax
	mov	eax,11			; sys_munmap
	syscall
      mmap_with_hint:
	mov	r10d,22h		; MAP_PRIVATE + MAP_ANONYMOUS
	mov	edx,3			; PROT_READ + PROT_WRITE
	mov	edi,480000h
	mov	eax,9			; sys_mmap
	syscall
	cmp	eax,-1
	je	no_low_memory
	mov	r9d,eax
	cmp	rax,r9
	jne	no_low_memory
	add	r9d,esi
	jnc	mmap_ok
      no_low_memory:
	mov	esi,lf
	call	display_string
	push	_no_low_memory
	jmp	fatal_error
      mmap_ok:
	mov	[additional_memory],eax
	lea	edi,[eax+esi]
	mov	[memory_end],edi
	shr	esi,2
	add	eax,esi
	mov	[additional_memory_end],eax
	mov	[memory_start],eax
	ret

exit_program:
	movzx	edi,al
	mov	eax,60
	syscall

get_environment_variable:
	mov	ecx,esi
	mov	rbx,[environment]
      next_variable:
	mov	rsi,[rbx]
	test	rsi,rsi
	jz	no_environment_variable
	add	rbx,8
      compare_variable_names:
	mov	edx,ecx
      compare_character:
	lodsb
	mov	ah,[edx]
	inc	edx
	cmp	al,'='
	je	end_of_variable_name
	or	ah,ah
	jz	next_variable
	sub	ah,al
	jz	compare_character
	cmp	ah,20h
	jne	next_variable
	cmp	al,41h
	jb	next_variable
	cmp	al,5Ah
	jna	compare_character
	jmp	next_variable
      no_environment_variable:
	ret
      end_of_variable_name:
	or	ah,ah
	jnz	next_variable
      copy_variable_value:
	lodsb
	cmp	edi,[memory_end]
	jae	out_of_memory
	stosb
	or	al,al
	jnz	copy_variable_value
	dec	edi
	ret

open:
	mov	r12d,esi
	mov	r13d,edi
	call	adapt_path
	mov	eax,2
	mov	edi,buffer
	mov	esi,O_RDONLY
	xor	edx,edx
	syscall
	mov	esi,r12d
	mov	edi,r13d
	test	eax,eax
	js	file_error
	mov	ebx,eax
	clc
	ret
    adapt_path:
	mov	esi,edx
	mov	edi,buffer
      copy_path:
	lods	byte [esi]
	cmp	al,'\'
	jne	path_char_ok
	mov	al,'/'
      path_char_ok:
	stos	byte [edi]
	or	al,al
	jnz	copy_path
	cmp	edi,buffer+1000h
	ja	out_of_memory
	ret
create:
	mov	r12d,esi
	mov	r13d,edi
	mov	r15d,edx
	call	adapt_path
	mov	edi,buffer
	mov	esi,O_CREAT+O_TRUNC+O_WRONLY
	mov	edx,S_IRUSR+S_IWUSR+S_IRGRP+S_IROTH
	cmp	r15d,[output_file]
	jne	do_create
	cmp	[output_format],5
	jne	do_create
	bt	[format_flags],0
	jnc	do_create
	or	edx,S_IXUSR+S_IXGRP+S_IXOTH
      do_create:
	mov	eax,2
	syscall
	mov	esi,r12d
	mov	edi,r13d
	test	eax,eax
	js	file_error
	mov	ebx,eax
	clc
	ret
close:
	mov	r13d,edi
	mov	edi,ebx
	mov	eax,3
	syscall
	mov	edi,r13d
	ret
read:
	mov	r12d,esi
	mov	r13d,edi
	mov	eax,0
	mov	edi,ebx
	mov	esi,edx
	mov	edx,ecx
	syscall
	mov	ecx,edx
	mov	edx,esi
	mov	esi,r12d
	mov	edi,r13d
	test	eax,eax
	js	file_error
	cmp	eax,ecx
	jne	file_error
	clc
	ret
    file_error:
	stc
	ret
write:
	mov	r12d,esi
	mov	r13d,edi
	mov	eax,1
	mov	edi,ebx
	mov	esi,edx
	mov	edx,ecx
	syscall
	mov	ecx,edx
	mov	edx,esi
	mov	esi,r12d
	mov	edi,r13d
	test	eax,eax
	js	file_error
	clc
	ret
lseek:
	mov	r12d,esi
	mov	r13d,edi
	mov	edi,ebx
	mov	esi,edx
	xor	edx,edx
	mov	dl,al
	mov	eax,8
	syscall
	mov	esi,r12d
	mov	edi,r13d
	cmp	eax,-1
	je	file_error
	clc
	ret

display_string:
	mov	edi,esi
	mov	edx,esi
	or	ecx,-1
	xor	al,al
	repne	scasb
	neg	ecx
	sub	ecx,2
	mov	eax,1
	mov	edi,[con_handle]
	mov	esi,edx
	mov	edx,ecx
	syscall
	ret
display_character:
	mov	r12d,esi
	mov	r13d,edi
	mov	[character],dl
	mov	eax,1
	mov	edi,[con_handle]
	mov	esi,character
	mov	edx,1
	syscall
	mov	esi,r12d
	mov	edi,r13d
	ret
display_number:
	mov	r14d,ebx
	mov	ecx,1000000000
	xor	edx,edx
	xor	bl,bl
      display_loop:
	div	ecx
	mov	r15d,edx
	cmp	ecx,1
	je	display_digit
	or	bl,bl
	jnz	display_digit
	or	al,al
	jz	digit_ok
	not	bl
      display_digit:
	mov	dl,al
	add	dl,30h
	mov	r10d,ecx
	call	display_character
	mov	ecx,r10d
      digit_ok:
	mov	eax,ecx
	xor	edx,edx
	mov	ecx,10
	div	ecx
	mov	ecx,eax
	mov	eax,r15d
	or	ecx,ecx
	jnz	display_loop
	mov	ebx,r14d
	ret

display_user_messages:
	mov	[displayed_count],0
	call	show_display_buffer
	cmp	[displayed_count],0
	je	line_break_ok
	cmp	[last_displayed],0Ah
	je	line_break_ok
	mov	dl,0Ah
	call	display_character
      line_break_ok:
	ret
display_block:
	jecxz	block_displayed
	add	[displayed_count],ecx
	mov	al,[esi+ecx-1]
	mov	[last_displayed],al
	mov	r13d,edi
	mov	eax,1
	mov	edi,[con_handle]
	mov	edx,ecx
	syscall
	mov	edi,r13d
      block_displayed:
	ret

fatal_error:
	mov	[con_handle],2
	mov	esi,error_prefix
	call	display_string
	pop	esi
	call	display_string
	mov	esi,error_suffix
	call	display_string
	mov	al,0FFh
	jmp	exit_program
assembler_error:
	mov	[con_handle],2
	call	display_user_messages
	mov	ebx,[current_line]
	test	ebx,ebx
	jz	display_error_message
	push	dword 0
      get_error_lines:
	mov	eax,[ebx]
	cmp	byte [eax],0
	je	get_next_error_line
	push	ebx
	test	byte [ebx+7],80h
	jz	display_error_line
	mov	edx,ebx
      find_definition_origin:
	mov	edx,[edx+12]
	test	byte [edx+7],80h
	jnz	find_definition_origin
	push	edx
      get_next_error_line:
	mov	ebx,[ebx+8]
	jmp	get_error_lines
      display_error_line:
	mov	esi,[ebx]
	call	display_string
	mov	esi,line_number_start
	call	display_string
	mov	eax,[ebx+4]
	and	eax,7FFFFFFFh
	call	display_number
	mov	dl,']'
	call	display_character
	pop	esi
	cmp	ebx,esi
	je	line_number_ok
	mov	dl,20h
	call	display_character
	push	esi
	mov	esi,[esi]
	movzx	ecx,byte [esi]
	inc	esi
	call	display_block
	mov	esi,line_number_start
	call	display_string
	pop	esi
	mov	eax,[esi+4]
	and	eax,7FFFFFFFh
	call	display_number
	mov	dl,']'
	call	display_character
      line_number_ok:
	mov	esi,line_data_start
	call	display_string
	mov	esi,ebx
	mov	edx,[esi]
	call	open
	mov	al,2
	xor	edx,edx
	call	lseek
	mov	edx,[esi+8]
	sub	eax,edx
	jz	line_data_displayed
	push	eax
	xor	al,al
	call	lseek
	mov	ecx,[esp]
	mov	edx,[additional_memory]
	lea	eax,[edx+ecx]
	cmp	eax,[additional_memory_end]
	ja	out_of_memory
	call	read
	call	close
	pop	ecx
	mov	esi,[additional_memory]
      get_line_data:
	mov	al,[esi]
	cmp	al,0Ah
	je	display_line_data
	cmp	al,0Dh
	je	display_line_data
	cmp	al,1Ah
	je	display_line_data
	or	al,al
	jz	display_line_data
	inc	esi
	loop	get_line_data
      display_line_data:
	mov	ecx,esi
	mov	esi,[additional_memory]
	sub	ecx,esi
	call	display_block
      line_data_displayed:
	mov	esi,lf
	call	display_string
	pop	ebx
	or	ebx,ebx
	jnz	display_error_line
	cmp	[preprocessing_done],0
	je	display_error_message
	mov	esi,preprocessed_instruction_prefix
	call	display_string
	mov	esi,[current_line]
	add	esi,16
	mov	edi,[additional_memory]
	xor	dl,dl
      convert_instruction:
	lodsb
	cmp	al,1Ah
	je	copy_symbol
	cmp	al,22h
	je	copy_symbol
	cmp	al,3Bh
	je	instruction_converted
	stosb
	or	al,al
	jz	instruction_converted
	xor	dl,dl
	jmp	convert_instruction
      copy_symbol:
	or	dl,dl
	jz	space_ok
	mov	byte [edi],20h
	inc	edi
      space_ok:
	cmp	al,22h
	je	quoted
	lodsb
	movzx	ecx,al
	rep	movsb
	or	dl,-1
	jmp	convert_instruction
      quoted:
	mov	al,27h
	stosb
	lodsd
	mov	ecx,eax
	jecxz	quoted_copied
      copy_quoted:
	lodsb
	stosb
	cmp	al,27h
	jne	quote_ok
	stosb
      quote_ok:
	loop	copy_quoted
      quoted_copied:
	mov	al,27h
	stosb
	or	dl,-1
	jmp	convert_instruction
      instruction_converted:
	xor	al,al
	stosb
	mov	esi,[additional_memory]
	call	display_string
	mov	esi,lf
	call	display_string
      display_error_message:
	mov	esi,error_prefix
	call	display_string
	pop	esi
	call	display_string
	mov	esi,error_suffix
	call	display_string
	mov	al,2
	jmp	exit_program

make_timestamp:
	mov	r13d,edi
	mov	eax,201
	mov	edi,timestamp
	syscall
	mov	eax,dword [timestamp]
	mov	edx,dword [timestamp+4]
	mov	edi,r13d
	ret

error_prefix db 'error: ',0
error_suffix db '.'
lf db 0xA,0
line_number_start db ' [',0
line_data_start db ':',0xA,0
preprocessed_instruction_prefix db 'processed: ',0
