This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Bug in strlen on old MIPS CPUs
- From: "Steve Legg" <smlegg at googlemail dot com>
- To: <newlib at sourceware dot org>
- Date: Tue, 21 Dec 2010 04:51:20 -0000
- Subject: Bug in strlen on old MIPS CPUs
Hi,
First, I realize that I'm maybe 10 years too late, but I have built newlib
for an R3000 based target and I've run into the following bug:
In libc\machine\mips\strlen.c there is the following inline assembler:
__asm__("" /* 32-bit MIPS targets */
" .set noreorder\n"
" .set nomacro\n"
" .globl strlen\n"
" .ent strlen\n"
"strlen:\n"
" addiu $2,$4,1\n"
"\n"
"1: lbu $3,0($4)\n"
" bnez $3,1b\n"
" addiu $4,$4,1\n"
"\n"
" jr $31\n"
" subu $2,$4,$2\n"
" .end strlen\n"
" .set macro\n"
" .set reorder\n");
Unfortunately (at least) R2000 and R3000 require a delay slot after all
loads (ie. There should be a nop or some other instruction after lbu
$3,0($4)) - so the first time round the loop the branch operates on the old
contents of $3 which if it happens to be 0 means that strlen returns 0 (or
worse, if the string happens to be empty and $3 doesn't contain 0).
Really probably the best way to fix this is just to remove the inline asm in
strlen.c - gcc is perfectly capable of optimizing such a small loop (the
code produced by the C loop has one extra instruction in the epilogue in my
tests), but: is there a #define that can be checked to see if the CPU is
R2000/R3000?
Another option is to remove the .noreorder - gas knows about delay slots and
will automatically insert one if required.
Thanks,
Steve Legg.