This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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.





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]