That's why C is usually preferred.

As I wrote earlier, I've been playing with m68k assembly lately. My first program looked somewhat like this:

.LFORMAT:
	.string	"%c"
	.text
	.align	2
.LENDL:
	.string	"\n"
	.text
	.align	2

	.globl	main
	.type	main, @function
main:
	link.w %a6,#-4		| allocate a stack frame		
	moveq #65,#-4(%a6)	| Move 65 (ASCII A) to an address on our
				| local address space
.L0:
	move.l #-4(%a6),-(%sp)  | push the address to the stack
	pea .LFORMAT		| push the format to the stack
	jbsr printf		| run printf
	add.l #1,#-4(%a6)	| add one to the letter
	cmpi.l #91,#-4(%a6)	| compare with 91 (ASCII Z + 1)
	jblt .L0		| if less, jump to label L0
	pea .LENDL		| push format to the stack
	jbsr printf		| run printf
	unlk %a6		| clear stack frame
	clr.l %d0		| store 0 in %d0 (return value)
	rts			| return
	.align 2
	.size	main, .-main

IOW, print out the alphabet. Nothing spectacular, and it worked. Then I decided to take it one step further, and rather than using an address in memory, I switched to using a register, which is supposed to be a tiny bit faster—even if that shouldn't be noticeable in this case:

main:
	link.w %a6,#-4		| allocate a stack frame		
	moveq #65,%d0		| Move 65 (ASCII A) to %d0
.L0:
	move.l %d0,-(%sp)	| push the address to the stack
	pea .LFORMAT		| push the format to the stack
	jbsr printf		| run printf
	add.l #1,%d0		| add one to the letter
	cmpi.l #91,%d0		| compare with 91 (ASCII Z + 1)
	jblt .L0		| if less, jump to label L0
	pea .LENDL		| push format to the stack
	jbsr printf		| run printf
	unlk %a6		| clear stack frame
	clr.l %d0		| store 0 in %d0 (return value)
	rts			| return
	.align 2
	.size	main, .-main

(that's only the main section, but please assume the rest is still there:-)

When I ran that, it bombed. It would print out the A, and then whole lines of nothingness. When I ran it inside gdb, it wouldn't even print out the A. It took me quite some time to figure out what went wrong.

main:
	link.w %a6,#-4		 | allocate a stack frame		
	moveq #65,%d7            | Move 65 (ASCII A) to %d7
.L0:
	extb.l %d7	
	move.l %d7,-(%sp)	 | push the address to the stack
	pea .LFORMAT		 | push the format to the stack
	jbsr printf		 | run printf
	add.l #1,%d7		 | add one to the letter
	cmpi.l #91,%d7		 | compare with 91 (ASCII Z + 1)
	jblt .L0		 | if less, jump to label L0
	pea .LENDL		 | push format to the stack
	jbsr printf		 | run printf
	unlk %a6		 | clear stack frame
	clr.l %d0		 | store 0 in %d0 (return value)
	rts			 | return
	.align 2
	.size	main, .-main

%d0 is used to store a function's return value. If I store my data in %d0, then the next time I call a function, that data is overwritten. Since I do call a function inside my loop, that function overwrites my data every time. Using a different register (say, %d7) fixes this.

Right. Apart from the fact that it's totally non-portable, assembly language also has quite a few quirks that you don't learn about when taught structured programming.

It'd be nice if there were a document somewhere that would explain how C functions expect to be called. I found out most of the above through trial and error, and through compiling stuff with -save-temps and looking at the result, comparing it with the 68k Programmers' Reference Manual. That works, but it's not really efficient—and not totally error-proof, too.