Returning back to asm and coding in general, got an issue with what's probably an obvious mistake but I'm stumped non-the-less.

kputs("Testing");
;
;	Print a single character to screen
;
kputchar:
	; assumes the register ax will contain the character to print
	mov edx, [SCREEN]	; edx = screen
	
	; or ax and colour to give a word correct for screen memory
	; E.G. character 'A' (0x41) and colour black background white text
	; (0x0F00) becomes 0x0F41
	or ax, [COLOUR]
	mov WORD[edx], ax	; copy ax to memory pointed to by edx
	
	; increment edx by 2 (I.E. point framebuffer to
	; place in memory 2 bytes higher than before
	add edx, 2
	mov [SCREEN], edx
	
	
	ret
	
	
;
;	Print a string to screen
;
kputs:
	
	; get our first argument address into esi
	
	push ebp
	
	mov ebp, esp
	mov esi, [ebp + 8]
	
	; assumes string address was moved to esi correctly
	xor eax, eax		; eax = 0
	lodsb				; load next character
	
	; if al = 0 end
	or al, al
	jz .kputsend
	
	;mov ax, 'A'
	call kputchar
	jmp kputs
	
.kputsend:
	call knewline
	
	pop ebp
	ret

I get a string of random ASCII characters, uncommenting mov ax, 'A' gives me a line of A's so I know my code works fine, it's obviously just something I'm doing wrong grabbing the argument off the stack.

It might be worth noting I have no debug tools that I know of available as I'm not doing this inside any operating system, hence why I'm asking rather than debugging.

If anyone can point out the mistake for me I'd be really happy!

Something is wrong here:

kputs:
	; get our first argument address into esi
	push ebp
	...
	jmp kputs

What state is the stack in when the end of string is reached?

It might be worth noting I have no debug tools that I know of available

gdb works fine in a sandbox (not to mention of a remote debug session).

This question has already been answered. Start a new discussion instead.