NWR04B: Why won't it puts?

Still trying to figure out what the hell is going on here, and why it won't print the messages I expect it to (while still printing the FIXME I stuck in at the end of the puts routine w/o any problems). I've been looking at the disassembled zImage, and I'm scratching my head. Here's the deal: shortly after power-on, the decompress_kernel routine is run:

000074 EB000915 BL      &000024D0

In C, decompress_kernel looks like this:

ulg
decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
                  int arch_id)
{
        output_data             = (uch *)output_start;  /* Points to kernel start */
        free_mem_ptr            = free_mem_ptr_p;
        free_mem_ptr_end        = free_mem_ptr_end_p;
        __machine_arch_type     = arch_id;

        puts("EMXIF");
        proc_decomp_setup();
        arch_decomp_setup();

        makecrc();
        puts("Uncompressing Linux...");
        gunzip();
        puts(" done, booting the kernel.\n");
        return output_ptr;
}

At 0x24D0, we've got some initilization, some register saving, and then the puts routine is called:

0024FC E59F0034 LDR     r0, &00002538
002500 EBFFF769 BL      &000002AC

This is the first call to puts: puts("EXMIF"); (which is FIXME backwards; I had it frontwards at first, and wanted to see if the output was any different if I changed the string; it's not). puts looks like this in C:

static void cx84200_puts(const char *s)
{
        while(*s != '\0')
                cx84200_putc(*s++);
        cx84200_putc('F');
        cx84200_putc('I');
        cx84200_putc('X');
        cx84200_putc('M');
        cx84200_putc('E');
}

(more checking to see what works) and like this in ARM assembly:

0002AC E1A0C00D MOV     ip, sp
0002B0 E92DD810 STMFD   sp!, {r4,r11,ip,lr,pc}

Save the registers for later...

0002B4 E1A04000 MOV     r4, r0
0002B8 E5D43000 LDRB    r3, [r4, #0]
0002BC E24CB004 SUB     r11, ip, #4
0002C0 E3530000 CMP     r3, #0
0002C4 0A000004 BEQ     &000002DC

r0 held the argument, and it's moved to r4. Check the first byte to see if it's zero (ie, if we're printing a null string), and jump ahead if it is. Not sure what we're doing with r11 here.

0002C8 E5D40000 LDRB    r0, [r4, #0]
0002CC EBFFFFEB BL      &00000280
0002D0 E5F43001 LDRB    r3, [r4, #1]!
0002D4 E3530000 CMP     r3, #0
0002D8 1AFFFFFA BNE     &000002C8

Load the first byte again into r0, then go to 0x280 (putc) with it. Increment r4 and see if it now points to a zero. If not, go through the routine again.

0002DC E3A00046 MOV     r0, #70
0002E0 EBFFFFE6 BL      &00000280
0002E4 E3A00049 MOV     r0, #73
0002E8 EBFFFFE4 BL      &00000280
0002EC E3A00058 MOV     r0, #88
0002F0 EBFFFFE2 BL      &00000280
0002F4 E3A0004D MOV     r0, #77
0002F8 EBFFFFE0 BL      &00000280
0002FC E3A00045 MOV     r0, #69
000300 EBFFFFDE BL      &00000280

This is the printing of FIXME at the end of puts.

000304 E59F0008 LDR     r0, &00000314
000308 E20000FF AND     r0, r0, #&FF
00030C EBFFFFDB BL      &00000280

Put 0x314 into r0, AND with 0xFF, then call putc again.

000310 E91BA810 LDMDB   r11, {r4,r11,sp,pc}
000314 00042548 ANDEQ   r2, r4, r8, ASR #10

And I think this is where we fall off the end of puts. Finally, a quick look at putc, first in C:

static int cx84200_putc(char c) {
        int i;
        int j = 10;

        CSR_WRITE(UART0_BASE, c);

    for (i= 0; i < 60000; i++)
                ;
}

(j left over from another bit of debugging) and assembly:

000280 E1A0C00D MOV     ip, sp
000284 E92DD800 STMFD   sp!, {r11,ip,lr,pc}
000288 E24CB004 SUB     r11, ip, #4
00028C E3A02CEA MOV     r2, #&EA00
000290 E2822060 ADD     r2, r2, #96
000294 E20000FF AND     r0, r0, #&FF
000298 E3A03209 MOV     r3, #&90000000
00029C E5830000 STR     r0, [r3, #0]
0002A0 E2522001 SUBS    r2, r2, #1
0002A4 1AFFFFFD BNE     &000002A0
0002A8 E91BA800 LDMDB   r11, {r11,sp,pc}

So here are my many bits of confusion:

  1. That first call to puts should have r0 pointing to EXMIF, right? Only it doesn't: 0x28A0 is where you can find this string, and r0 points to 0x2538. There's no ASCII there, and certainly no copy of the string I want. If I change the instruction so that r0 points to 0x28A0, the thing crashes badly -- just spews out hexdumps of something (presumably memory).
  2. That last call to putc from puts, where r0 points to 0x314. WTF? It explains why I'm seeing H% at the end of the strings, but as far as I can tell it certainly shouldn't be doing that. Again, there's nothing around 0x314 that would explain why we're trying to print it.
  3. And in putc, what is with AND r0, r0, #&FF? As far as I can tell, this has absolutely no effect on r0: it's a NOP.

I can only think of three things:

If anyone has any insight to share, please let me know. This is really bugging me.