
; Public Domain

; test run command: ; .; .

%include "lmacros3.mac"
%include "eld.mac"
%include "eldcall.mac"
%include "elddata.mac"

	cpu 8086

	addsection RELOCATEDDATA, nobits vstart=_ELD_RELOC_VSTART
relocateddata:

	addsection HEADER, start=0

	istruc ELD_HEADERX
at eldhxHeader
		; ELD executable header
	istruc ELD_HEADER
at eldhSignature,	db "ELD1"
			db 0,0,0
			db 26
at eldhCodeOffset,	dd CODEOFFSET
at eldhCodeImageLength,	dw code_size
at eldhCodeAllocLength,	dw 0
at eldhDataOffset,	dd DATAOFFSET
at eldhDataImageLength,	dw data_size
at eldhDataAllocLength,	dw total_data_size - data_size
at eldhCodeEntrypoint,	dw linker - code
at eldhReserved
at eldhExtensionSize,	dw header_extension_end - $$
	iend
at eldhxDescriptionOffset,	dd description
header_extension_end:
	iend

description:		asciz "Compare ELDs with differing linker options."


	align 16, db 0

CODEOFFSET equ $ - $$
	addsection CODE, follows=HEADER vstart=_ELD_CODE_VSTART
%define CODEFIXUP - code + 0
code:
		; ELD instance header
	istruc ELD_INSTANCE
at eldiStartCode
at eldiEndCode
at eldiStartData
at eldiEndData
at eldiIdentifier,	fill 8, 32, db "ELDCOMP"
at eldiListing,		asciz _ELD_LISTING
	iend

start:
	push ss
	pop es
	extcallcall skipcomma
	dec si
	mov bx, commands
internaldatarelocation
	mov al, ';'
	mov di, word [bx]
.loop:
	inc di
	cmp al, ';'
	jne @FF
@@:
	lodsb
	extcallcall iseol?
	je @F
	stosb
	jmp @B

@@:
	mov al, 13
	stosb
	mov cx, di
	sub cx, word [bx]
	dec cx
	dec cx
	mov di, word [bx]
	mov byte [di], cl
	dec si
	lodsb
	inc bx
	inc bx
	mov di, word [bx]
	test di, di
	jnz .loop


run:
	call clear_eld_space
	mov word [data_original], bx	; data
internaldatarelocation
	mov word [code_original], dx	; code
internaldatarelocation

	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as resident

	push word [relocateddata]
linkdatarelocation ext_inject_handler
	push word [relocateddata]
linkdatarelocation savesp
	push word [relocateddata]
linkdatarelocation throwsp
	mov word [eld_sp], sp
internaldatarelocation
	mov word [relocateddata], sp
linkdatarelocation savesp
	mov word [relocateddata], sp
linkdatarelocation throwsp

	mov word [relocateddata], .inject
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	extcallcall cmd3

.inject:
	mov bx, [step]
internaldatarelocation
	cmp bx, 4
	je .checksum
	cmp bx, 8 + 4
	jne @F
.checksum:
	mov si, word [data_original]
internaldatarelocation
	mov cx, word [relocateddata]
linkdatarelocation extdata_used
	add cx, word [relocateddata]
linkdatarelocation extdata
	sub cx, si
	mov word [word results + 0 + bx - 4], cx
internaldatarelocation
	xchg bx, dx
	push si
	push cx
	call zz_hash
	pop ax
	pop si
	xchg bx, dx
	mov word [word results + 2 + bx - 4], dx
internaldatarelocation
	mov cx, 1
	call [savedata_dispatch]
internaldatarelocation

	mov si, word [code_original]
internaldatarelocation
	mov cx, word [relocateddata]
linkdatarelocation extseg_used
	sub cx, si
	mov word [word results + 4 + bx - 4], cx
internaldatarelocation
	call get_es_ext

	push di
	xor ax, ax
.loop_listing:
	cmp word [relocateddata], ax
linkdatarelocation extseg_used
	jbe .no_listing
	mov di, ax
	cmp word [es:di + eldiStartCode], ax
	jne .no_listing
	cmp ax, si
	je .listing
	mov ax, word [es:di + eldiEndCode]
	add di, 32
	jc .no_listing
	cmp ax, di
	jb .no_listing
	jmp .loop_listing

.listing:
	push cx
	mov cx, words(eldiListing_size)
	lea di, [di + eldiListing]
	rep stosw
	pop cx
.no_listing:
	pop di

	 push es
	 pop ds
	xchg bx, dx
	push si
	push cx
	call zz_hash
	pop ax
	pop si
	xchg bx, dx
	mov word [ss:word results + 6 + bx - 4], dx
internaldatarelocation
	 push ss
	 pop es
	mov cx, 1
	call [ss:savecode_dispatch]
internaldatarelocation
	 push ss
	 pop ds

@@:
	cmp bx, 8
	jne @F

	push bx
	call clear_eld_space
	 push ss
	 pop es
	pop bx
@@:

	add word [step], strict byte 2
internaldatarelocation -3
	mov di, relocateddata + 1
linkdatarelocation line_in
	mov si, [word bx + commands]
internaldatarelocation
	test si, si
	jz .finish
	mov word [relocateddata], .inject
linkdatarelocation ext_inject_handler, -4
internalcoderelocation

.common:
	extcallcall yy_reset_buf
	push di
	mov cx, words(256)
	rep movsw
	pop si
	inc si
	extcall skipwhite

	extcall cmd3_injected

.finish:
%if 0
	mov si, reclaimcommand
	mov word [relocateddata], .return
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	jmp .common
%elif 0
	mov word [relocateddata], .return
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	extcall cmd3
%endif

.return:
	mov sp, word [eld_sp]
internaldatarelocation
	pop word [relocateddata]
linkdatarelocation throwsp
	pop word [relocateddata]
linkdatarelocation savesp
	pop word [relocateddata]
linkdatarelocation ext_inject_handler
	call get_es_ext
	clropt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as free
	 push ss
	 pop es

	mov si, results
internaldatarelocation
	mov bx, 2
@@:
	mov cx, 4
	mov di, relocateddata
linkdatarelocation line_out
@@:
	lodsw
	extcallcall hexword
	mov al, 32
	stosb
	loop @B
	push bx
	extcallcall trimputs
	pop bx
	dec bx
	jnz @BB

	mov si, results
internaldatarelocation
	mov di, results + 8
internaldatarelocation
	mov ax, [si]
	cmpsw
	je @FF
	ja @F
	mov ax, [di - 2]
@@:
	mov word [savedata_dispatch], savedata
internaldatarelocation -4
internalcoderelocation
	mov dx, msg.mismatch.datalen
internaldatarelocation
	extcallcall putsz
@@:
	cmpsw
	je @F
	mov word [savedata_dispatch], savedata
internaldatarelocation -4
internalcoderelocation
	mov dx, msg.mismatch.datahash
internaldatarelocation
	extcallcall putsz
@@:
	mov word [savedata_length], ax
internaldatarelocation

	mov ax, [si]
	cmpsw
	je @FF
	ja @F
	mov ax, [di - 2]
@@:
	mov word [savecode_dispatch], savecode
internaldatarelocation -4
internalcoderelocation
	mov dx, msg.mismatch.codelen
internaldatarelocation
	extcallcall putsz
@@:
	cmpsw
	je @F
	mov word [savecode_dispatch], savecode
internaldatarelocation -4
internalcoderelocation
	mov dx, msg.mismatch.codehash
internaldatarelocation
	extcallcall putsz
@@:
	mov word [savecode_length], ax
internaldatarelocation


rerun:
	rol byte [rerunning], 1
internaldatarelocation
	jc compare

	xor cx, cx			; cx = 0, get sizes
	xor ax, ax			; (NC)
	call near [savedata_dispatch]
internaldatarelocation
	call near [savecode_dispatch]
internaldatarelocation
	jnc end

	not byte [rerunning]
internaldatarelocation

	mov bx, ax
	add bx, word [savedata_length]
internaldatarelocation
	mov dx, word [cs:code + eldiEndData]
internalcoderelocation
	sub dx, word [relocateddata]
linkdatarelocation extdata
	cmp dx, word [relocateddata]
linkdatarelocation extdata_used
	je @F
	mov ax, 0E2Fh
	extcallcall setrc
	mov dx, msg.notcontiguous
internaldatarelocation
	extcallcall putsz
	jmp end

@@:
	neg dx
	add dx, word [relocateddata]
linkdatarelocation extdata_size
	cmp bx, dx
	jbe @F
	mov ax, 0E30h
	extcallcall setrc
	mov dx, msg.notenough
internaldatarelocation
	extcallcall putsz
	jmp end

@@:
	call get_es_ext
	mov di, word [es:code + eldiEndData]
internalcoderelocation
	add word [es:code + eldiEndData], ax
internalcoderelocation
	add word [relocateddata], ax
linkdatarelocation extdata_used
	 push ss
	 pop es
	push di
	xchg cx, ax
	mov al, 0
	rep stosb		; clear our buffers
	pop ax			; ax -> buffers

		; cx = 0
	call near [savedata_dispatch]
internaldatarelocation
	call near [savecode_dispatch]
internaldatarelocation		; find offsets for each used buffer

	and word [step], strict byte 0
internaldatarelocation -3
	jmp run


compare:
	mov cx, 2
	call near [savedata_dispatch]
internaldatarelocation
	mov cx, 2
	call near [savecode_dispatch]
internaldatarelocation		; compare buffers
	jmp end


empty:
	retn


uninstall_table:
	lframe
	lenter
	lvar word, table
	 push si

	rol byte [ss:si + htInstalled], 1
	jnc .next_table		; --> (NC)
	xor bx, bx		; = 0 (no prior, modify handler)
	mov di, word [ss:si + htEntry]	; di -> us
	mov si, word [ss:si + htHandler]; -> handler
	mov si, word [ss:si]	; si -> first
	test si, si		; none installed ?
	jz .error		; error -->

.loop:
	cmp di, si		; found ?
	je .bx			; yes, use bx -->
	mov bx, si		; bx -> prior handler
	lodsw			; skip entrypoint jmp strict short
	lodsb			; get first byte of chainer
	cmp al, 0E9h		; expecting jmp near ?
	jne .error		; no, error -->
	lodsw			; get rel16 displacement
	add si, ax		; -> next handler
	jmp .loop

.bx:
	test bx, bx		; any prior ?
	jnz .bxnz		; yes -->
	scasw			; skip entrypoint jmp strict short
	cmp byte [di], 0E8h	; is it a call to cmd3_not_ext ?
	jne @F			; no -->
				; yes, reset ext_command_handler to zero
.setbx:
	mov si, word [bp + ?table]
	mov si, word [ss:si + htHandler]; -> handler
	mov word [ss:si], bx
	jmp .done

@@:
	cmp byte [di], 0E9h	; validate
	jne .error		; failure -->
	inc di			; -> rel16 displacement
	mov bx, word [di]	; get displacement
	scasw			; -> after jmp near
	add bx, di		; -> next handler
	jmp .setbx		; set ext_command_handler to next

.bxnz:
	mov si, bx		; -> prior handler with us as downlink
	xchg di, si		; si -> ours, di -> prior
	cmpsw			; skip entrypoint jmp strict short
	movsb			; copy 0E8h/0E9h
	lodsw			; ax = near rel16 displacement
	add ax, si		; add in our base (= absolute offset)
	sub ax, di
	dec ax
	dec ax			; subtract new base (= relative displacement)
	stosw			; store new rel16 displacement
	movsw			; jmp strict short
	movsw			; linkcall target
	movsb			; trailer
.done:
	mov si, word [bp + ?table]
	not byte [ss:si + htInstalled]
	clc
.next_table:
@@:
	lleave
	retn

.error:
	stc
	jmp @B


		; INP:	ax -> buffer 1
		;	bx -> buffer 2
		;	cx = length
		;	dx -> message
commoncompare:
	lframe none
	lenter
	lvar word, buffer1
	 push ax
	lvar word, buffer2
	 push bx
	lvar word, length
	 push cx
	extcallcall putsz
	mov di, relocateddata
linkdatarelocation line_out
	call hexword
	mov si, msg.compare.1
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, word [bp + ?buffer2]
	call hexword
	mov si, msg.compare.2
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, word [bp + ?length]
	call hexword
	extcallcall putsline_crlf

	mov di, comparebuffer + 1
internaldatarelocation
	mov si, msg.compare.3
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, ss
	call hexword
	mov al, ':'
	stosb
	mov ax, word [bp + ?buffer1]
	call hexword
	mov si, msg.compare.4
internaldatarelocation
	extcallcall copy_single_counted_string
	mov ax, word [bp + ?length]
	call hexword
	mov al, 32
	stosb
	mov ax, ss
	call hexword
	mov al, ':'
	stosb
	mov ax, word [bp + ?buffer2]
	call hexword
	mov al, 13
	stosb
	xchg ax, di
	sub ax, comparebuffer + 2
internaldatarelocation
	mov byte [comparebuffer], al
internaldatarelocation

	call get_es_ext
	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as resident

	mov bx, word [relocateddata]
linkdatarelocation ext_puts_handler
				; -> prior
	mov di, puts_handler	; -> our handler
internalcoderelocation
	test bx, bx		; installing as first ?
	jz .only_first		; yes, simple --> (leave as extcall puts_ext_done)
	scasw			; skip entrypoint jmp strict short
	mov al, 0E9h		; = jmp near opcode
	stosb			; store
	xchg ax, bx		; ax -> next handler
	sub ax, di
	dec ax
	dec ax			; ax = ax - (di + 2)
	stosw			; store our downlink as rel16 displacement

.only_first:
	mov word [relocateddata], puts_handler
linkdatarelocation ext_puts_handler, -4
internalcoderelocation		; -> our entrypoint
	not byte [putstable + htInstalled]
internaldatarelocation

	lvar word, injecthandler
	push word [relocateddata]
linkdatarelocation ext_inject_handler
	lvar word, savesp
	push word [relocateddata]
linkdatarelocation savesp
	lvar word, throwsp
	push word [relocateddata]
linkdatarelocation throwsp
	lvar word, bp
	push bp
	mov word [eld_sp], sp
internaldatarelocation
	mov word [relocateddata], sp
linkdatarelocation savesp
	mov word [relocateddata], sp
linkdatarelocation throwsp

	mov word [relocateddata], .inject
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	extcallcall cmd3

.inject:
	mov si, comparebuffer
internaldatarelocation
	mov di, relocateddata + 1
linkdatarelocation line_in

	extcallcall yy_reset_buf
	push di
	mov cx, words(256)
	rep movsw
	pop si
	inc si
	extcall skipwhite

	mov word [relocateddata], .finish
linkdatarelocation ext_inject_handler, -4
internalcoderelocation
	extcall cmd3_injected

.finish:
	mov sp, word [eld_sp]
internaldatarelocation
	pop bp
	pop word [relocateddata]
linkdatarelocation throwsp
	pop word [relocateddata]
linkdatarelocation savesp
	pop word [relocateddata]
linkdatarelocation ext_inject_handler
	call get_es_ext

	push es
	pop ds
	mov si, putstable
internaldatarelocation
	call uninstall_table
	push ss
	pop ds
	jnc @F

	 push ss
	 pop es
	mov ax, 0E31h
	extcallcall setrc
	mov dx, msg.putserror
internaldatarelocation
	extcallcall putsz
	extcallcall cmd3

@@:
	clropt [es:code + eldiFlags], eldifResident
internalcoderelocation -3		; mark block as free
	 push ss
	 pop es
	lleave code
	retn


puts_handler:
.:
	jmp strict short .entry
.chain:
	extcall puts_ext_done, required	; must NOT be extcallcall
	times 10 - ($ - .) nop
.entry:
	push si
	push di
	push ax
	push es
	push dx
	push bp
	mov bp, word [eld_sp]
internaldatarelocation
	mov bp, [bp]
	push word [bp + ?buffer1]
	push word [bp + ?buffer2]
	lframe 0, nested
	lpar word, messagelength
	lpar word, messagesegment
	lpar word, messageoffset
	lpar word, bp
	lpar word, buffer1
	lpar word, buffer2
	lenter

	cmp ax, 4 + 1 + 4 + 2 + 2 + 2 + 2 + 2 + 4 + 1 + 4 + 2
	je @F	;seg col ofs bl dig bl dig bl seg col ofs eol
	cmp ax, 4 + 1 + 8 + 2 + 2 + 2 + 2 + 2 + 4 + 1 + 8 + 2
	jne .not;seg col ofs bl dig bl dig bl seg col ofs eol
@@:

	mov di, putsbuffer
internaldatarelocation
	push di
	mov ax, ss
	 push ss
	 pop es
	extcallcall hexword
	mov al, ':'
	stosb
	pop si			; ds:si -> buffer
	mov cx, 5
	mov di, dx		; di -> puts input
	mov es, word [bp + ?messagesegment]
				; es:di -> input
	repe cmpsb
	jne .not		; mismatch
	cmp word [es:di], "00"	; 32-bit offset prefix ?
	jne @F
	cmp word [es:di + 2], "00"
	jne @F			; no -->
	add di, 4		; yes, skip it
@@:
	xchg si, di
	push es
	push ds
	pop es
	pop ds			; ds:si -> input offset left, es => ss
	mov cx, 4
	xor bx, bx
	mov di, putsbuffer	; es:di -> buffer
internaldatarelocation
@@:
	lodsb
	extcallcall getnyb
	jc .not
	add bx, bx
	add bx, bx
	add bx, bx
	add bx, bx		; times 16
	mov ah, 0
	add bx, ax		; add in next hexit
	loop @B			; process 4 hexits -->
	sub bx, word [bp + ?buffer1]
	xchg ax, bx
	extcallcall hexword	; write offset adjusted
	mov ax, 2020h
	stosw			; blanks

	mov si, word [bp + ?messageoffset]
				; ds:si -> message
	mov cx, word [bp + ?messagelength]
				; cx = length (harden against overflow)
	db __TEST_IMM8		; (skip stosb)
@@:
	stosb
	lodsb			; load next byte
	cmp al, 13		; end of line ?
	loopne @B		; not yet, store it -->
	sub si, 5		; 1 for CR, 4 for offset (low) word as hex
	mov ax, 2020h
	stosw			; more blanks
	mov cx, 4
	xor bx, bx
@@:
	lodsb
	extcallcall getnyb
	jc .not
	add bx, bx
	add bx, bx
	add bx, bx
	add bx, bx		; times 16
	mov ah, 0
	add bx, ax		; add in next hexit
	loop @B			; process 4 hexits -->
	sub bx, word [bp + ?buffer2]
	xchg ax, bx
	extcallcall hexword	; write offset adjusted

	mov ax, 13 | 10 << 8
	stosw
	mov ax, di		; ax -> behind new line
	mov dx, putsbuffer	; es:dx -> buffer
internaldatarelocation
	sub ax, dx		; ax = length
	push ss
	pop ds			; ds = ss
	mov cx, .chain		; -> our chaining entry
internalcoderelocation
	clc
	extcallcall puts_ext_next	; call subsequent puts handlers
	stc			; do not display
	jmp .leave

.not:
	clc
.leave:
	lleave
	pop ax
	pop ax			; (discard)
	 push ss
	 pop ds			; reset ds
	pop bp
	pop dx
	pop es
	pop ax
	pop di
	pop si
	jnc .chain		; chain if to display -->
	extcall puts_ext_done, required
				; directly jump back to debugger, CY

	lleave ctx


savedata:
	jcxz .size_and_offsets
	loop .compare

.write:
	mov di, [savedata_offset_1]
internaldatarelocation
	cmp bx, 4
	je @F
	mov di, [savedata_offset_2]
internaldatarelocation
@@:
	xchg cx, ax
	cmp cx, word [savedata_length]
internaldatarelocation
	jbe @F
	mov cx, word [savedata_length]
internaldatarelocation
@@:
	rep movsb
	retn

.size_and_offsets:
	mov word [savedata_offset_1], ax
internaldatarelocation
	add ax, word [savedata_length]
internaldatarelocation
	jc overflow
	mov word [savedata_offset_2], ax
internaldatarelocation
	add ax, word [savedata_length]
internaldatarelocation
	jc overflow
	stc
	retn

.compare:
	mov ax, word [savedata_offset_1]
internaldatarelocation
	mov bx, word [savedata_offset_2]
internaldatarelocation
	mov cx, word [savedata_length]
internaldatarelocation
	mov dx, msg.data
internaldatarelocation
	jmp commoncompare


savecode:
	jcxz .size_and_offsets
	loop .compare

		; NB ds != ss
.write:
	mov di, [ss:savecode_offset_1]
internaldatarelocation
	cmp bx, 4
	je @F
	mov di, [ss:savecode_offset_2]
internaldatarelocation
@@:
	xchg cx, ax
	cmp cx, word [ss:savecode_length]
internaldatarelocation
	jbe @F
	mov cx, word [ss:savecode_length]
internaldatarelocation
@@:
	rep movsb
	retn

.size_and_offsets:
	mov word [savecode_offset_1], ax
internaldatarelocation
	add ax, word [savecode_length]
internaldatarelocation
	jc overflow
	mov word [savecode_offset_2], ax
internaldatarelocation
	add ax, word [savecode_length]
internaldatarelocation
	jc overflow
	stc
	retn

.compare:
	mov ax, word [savecode_offset_1]
internaldatarelocation
	mov bx, word [savecode_offset_2]
internaldatarelocation
	mov cx, word [savecode_length]
internaldatarelocation
	mov dx, msg.code
internaldatarelocation
	jmp commoncompare


overflow:
	mov ax, 0E32h
	extcallcall setrc
	mov dx, msg.overflow
internaldatarelocation
	extcallcall putsz

end:
	testopt [ss:relocateddata], 1
linkdatarelocation options7, -3
	jnz .skip

	call get_es_ext
	mov ax, word [cs:code + eldiEndData]
internalcoderelocation			; ax -> our data end
	mov bx, 32			; prepare to keep 32 Bytes
	push ax
	sub ax, [relocateddata]		; ax = index into data behind our end
linkdatarelocation extdata
	cmp word [relocateddata], ax	; are we last ?
linkdatarelocation extdata_used
	pop ax
	jne @F				; no, keep >= 32 Bytes of instance -->
	xor bx, bx			; remember to free instance completely
	sub ax, word [cs:code + eldiStartData]
internalcoderelocation			; get our length
	sub word [relocateddata], ax	; subtract from use counter
linkdatarelocation extdata_used
	xor ax, ax			; zero out our data references
					;  (in case we keep the instance)
	mov word [es:code + eldiStartData], ax
internalcoderelocation
	mov word [es:code + eldiEndData], ax
internalcoderelocation
@@:

	mov dx, word [cs:code + eldiStartCode]
internalcoderelocation
	add dx, bx			; -> behind to keep (= start if no data)
	mov ax, word [cs:code + eldiEndCode]
internalcoderelocation
	cmp word [relocateddata], ax	; at end ?
linkdatarelocation extseg_used
	jne @F				; no, keep block as is -->
	mov word [es:code + eldiEndCode], dx
internalcoderelocation			; modify end to -> behind to keep
	sub ax, word [cs:code + eldiStartCode]
internalcoderelocation			; = original length
	sub ax, bx			; = how much to free
	sub word [relocateddata], ax	; subtract from use counter
linkdatarelocation extseg_used
@@:

.skip:
	extcallcall cmd3


get_es_ext:
	mov es, word [relocateddata]
linkdatarelocation extdssel
	extcall ispm
	jz @F
	mov es, word [relocateddata]
linkdatarelocation extseg
@@:
	retn


clear_eld_space:
	 push ss
	 pop es
	mov di, word [relocateddata]
linkdatarelocation extdata_used
	mov cx, word [relocateddata]
linkdatarelocation extdata_size
	sub cx, di
	add di, word [relocateddata]
linkdatarelocation extdata
	mov bx, di
	mov al, 0
	rep stosb

	call get_es_ext
	mov di, word [relocateddata]
linkdatarelocation extseg_used
	mov cx, word [relocateddata]
linkdatarelocation extseg_size
	sub cx, di
	mov dx, di
	mov al, 0
	rep stosb
	retn


		; INP:	ds:si -> string to hash
		;	cx = length of string (may be zero)
		; OUT:	bx = hash value computed
		; CHG:	ax, si, cx
		; STT:	UP
zz_hash:
	mov bx, 1

		; INP:	ds:si -> string to hash
		;	cx = length of string (may be zero)
		;	bx = initial hash value
		; OUT:	bx = hash value computed
		; CHG:	ax, si, cx
		; STT:	UP
.bx_init:
	jcxz .end
.loop:
	xor ax, ax
	lodsb
	sub ax, bx
	push cx
	mov cl, 5
	shl bx, cl
	pop cx
	add bx, ax
	loop .loop
.end:
	retn


DATAOFFSET equ CODEOFFSET + code_size
	addsection DATA, follows=CODE vstart=_ELD_DATA_VSTART
%define DATAFIXUP - datastart + 0
datastart:

	struc HOOKTABLE
htEntry:		resw 1
htHandler:		resw 1
htInstalled:		resw 1
	endstruc

	align 2, db 0
putstable:
	istruc HOOKTABLE
at htEntry,		dw puts_handler
internalcoderelocation
at htHandler,		dw relocateddata
linkdatarelocation ext_puts_handler
at htInstalled,		dw 0
	iend


msg:
.mismatch.datalen:	asciz "Data length mismatch",13,10
.mismatch.datahash:	asciz "Data hash mismatch",13,10
.mismatch.codelen:	asciz "Code length mismatch",13,10
.mismatch.codehash:	asciz "Code hash mismatch",13,10

.putserror:	asciz "ELDCOMP: Unable to uninstall puts handler! Staying resident as zombie.",13,10
.notenough:	asciz "Not enough ELD data space left!",13,10
.overflow:	asciz "Overflow!",13,10
.notcontiguous:	asciz "Free data space is not contiguous!",13,10
.code:		asciz "Comparing code, left="
.data:		asciz "Comparing data, left="
.compare.1:	counted " right="
.compare.2:	counted " length="
.compare.3:	counted "c "
.compare.4:	counted " l "

rerunning:		db 0

	align 2, db 0
results:
	times 8 dw 0

savedata_dispatch:	dw empty
internalcoderelocation
savedata_length:	dw 0
savedata_offset_1:	dw 0
savedata_offset_2:	dw 0

savecode_dispatch:	dw empty
internalcoderelocation
savecode_length:	dw 0
savecode_offset_1:	dw 0
savecode_offset_2:	dw 0

	align 2, db 0
commands:
	dw install_command_1
internaldatarelocation
	dw status_command_1
internaldatarelocation
	dw uninstall_command_1
internaldatarelocation
	dw reclaim_command_1
internaldatarelocation

	dw install_command_2
internaldatarelocation
	dw status_command_2
internaldatarelocation
	dw uninstall_command_2
internaldatarelocation
	dw reclaim_command_2
internaldatarelocation
	dw 0

step:	dw 0

%if 0
reclaimcommand:
	counted "ext reclaim.eld"
	db 13
%endif

uinit_data:

	align 16, db 0
data_size equ $ - datastart

	absolute uinit_data
	alignb 2
eld_sp:
	resw 1
code_original:
	resw 1
data_original:
	resw 1

comparebuffer:
	resb 64

putsbuffer:
install_command_1:
	resb 256
status_command_1:
	resb 256
uninstall_command_1:
	resb 256
reclaim_command_1:
	resb 256
install_command_2:
	resb 256
status_command_2:
	resb 256
uninstall_command_2:
	resb 256
reclaim_command_2:
	resb 256

	alignb 16
uinit_data_end:

total_data_size equ $ - datastart
%assign _DATA_SIZE total_data_size

	usesection CODE

%include "eldlink.asm"

	align 16
code_size equ $ - code
