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.