Bug awareness - finding the address of arguments is a NoNo

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
SANiK
Posts: 29
Joined: Tue Jul 05, 2005 5:25 am

Bug awareness - finding the address of arguments is a NoNo

Post by SANiK »

Err, to save you guys a bunch of debug time, be aware that PSPlink causes random bugs when trying to print a float.
The bug results in PSPlink crashing.
Usbhostfs reports an invalid magic error.

The bug is caused by TyRaNid attempting to find the address of a function argument... although, the PSP uses registers to store/pass arguments, hence the bug.

The bug is in the float printing code of PSPlink, hence avoid printing floats in PSPlink.

And never try to get the address of a function argument!
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

Could you be more specific where that code is that tries to find the adress of an argument/print floats, that is faulty?
Can't seem to find that part.
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
User avatar
jbit
Site Admin
Posts: 293
Joined: Sat May 28, 2005 3:11 am
Location: København, Danmark
Contact:

Re: Bug awareness - finding the address of arguments is a No

Post by jbit »

SANiK wrote:And never try to get the address of a function argument!
Erm, why exactly... GCC will automatically store the register on the stack and give that address if you try to get the address of a function argument. The following output is from ee-gcc, but should be similar on PSP compiler...

Original C code:

Code: Select all

void somefunc&#40;int blah&#41;
&#123;
    someotherfunc&#40;&blah&#41;;
&#125;
Unoptimized assembly code (with some annotations ;)

Code: Select all

00000020 <somefunc>&#58;
  20&#58;   addiu   sp,sp,-48
  24&#58;   sd  ra,32&#40;sp&#41;
  28&#58;   sd  s8,16&#40;sp&#41;
  2c&#58;   move    s8,sp
  30&#58;   sw  a0,0&#40;s8&#41;    ; value of "blah" is stored on the stack
  34&#58;   jal 0 <someotherfunc>
  38&#58;   move    a0,s8    ; arg0 for someotherfunc is set to the address of "blah" on the stack
  3c&#58;   move    sp,s8
  40&#58;   ld  ra,32&#40;sp&#41;
  44&#58;   ld  s8,16&#40;sp&#41;
  48&#58;   jr  ra
  4c&#58;   addiu   sp,sp,48
EDIT:I should point out the above ASM is raw MIPS asm, so "move a0,s8" is in the branch delay slot for JAL, therefore it's execution is completed before the branch is completed.
chp
Posts: 313
Joined: Wed Jun 23, 2004 7:16 am

Post by chp »

Also, a printf(char* buf, ...)-style function is a varargs-function, which will store the value before '...' on the stack, because it will need to get the address to 'buf' before it starts processing the format-string. I assume it was a function similar to this that you were using?
GE Dominator
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

It does seem to be true that the PSP compiler is broken, it tries to store the value onto the stack but doesn't actually do so until after the code which uses the value. However I fail to see why it would actually die completely, and at any rate I don't fucking care.
SANiK
Posts: 29
Joined: Tue Jul 05, 2005 5:25 am

Post by SANiK »

jbit - The PSPcompiler has its issues =/

chp/Raphael - The bug is in the PSPLink code which handles the conversion of floats to string, and not within the function printf() itself

/*Taken from util.c*/

Code: Select all

static int is_inf&#40;float val&#41;
&#123;
        void *p;
        unsigned int conv;
        int sign;
        int exp;
        int mantissa;

BUG&#58; p = &#40;void *&#41; &val;
        conv = *&#40;&#40;unsigned int *&#41; p&#41;;
        sign = &#40;conv >> 31&#41; & 1;

        exp = &#40;conv >> 23&#41; & 0xff;
        mantissa = conv & 0x7fffff;

        if&#40;&#40;exp == 255&#41; && &#40;mantissa == 0&#41;&#41;
        &#123;
                if&#40;sign&#41;
                &#123;
                        return -1;
                &#125;
                else
                &#123;
                        return 1;
                &#125;
        &#125;

        return 0;
&#125;
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

Code: Select all

static int is_inf&#40;float val&#41;
&#123;
	void *p;
	unsigned int conv;
	int sign;
	int exp;
	int mantissa;

	p = &#40;void *&#41; &val;
	conv = *&#40;&#40;unsigned int *&#41; p&#41;;
	sign = &#40;conv >> 31&#41; & 1;

	exp = &#40;conv >> 23&#41; & 0xff;
	mantissa = conv & 0x7fffff;

	if&#40;&#40;exp == 255&#41; && &#40;mantissa == 0&#41;&#41;
	&#123;
		if&#40;sign&#41;
		&#123;
			return -1;
		&#125;
		else
		&#123;
			return 1;
		&#125;
	&#125;

	return 0;
&#125;


int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
	float x = rand&#40;&#41;/32768.f;
	if &#40;is_inf&#40;x&#41;&#41;
	&#123;
		printf&#40;"IsINF\n"&#41;;
	&#125;

	sceKernelExitGame&#40;&#41;;
	return&#40;0&#41;;
&#125;
Compiled with same flags as psplink results in the following compiler output:

Code: Select all

$LC1&#58;
	.ascii	"IsINF\012\000"
 #NO_APP
	.section	.rodata.cst4,"aM",@progbits,4
	.align	2
$LC0&#58;
	.word	939524096
	.text
	.align	2
	.globl	main
	.ent	main
main&#58;
	.frame	$sp,16,$31		# vars= 8, regs= 1/0, args= 0, gp= 0
	.mask	0x80000000,-8
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	
	addiu	$sp,$sp,-16
	sw	$31,8&#40;$sp&#41;
	jal	rand
	nop

	mtc1	$2,$f0
	lui	$2,%hi&#40;$LC0&#41;
	cvt.s.w	$f1,$f0
	lwc1	$f0,%lo&#40;$LC0&#41;&#40;$2&#41;
	lw	$3,0&#40;$sp&#41;          # !WRONG
	li	$2,8323072			# 0x7f0000
	mul.s	$f1,$f1,$f0
	ori	$2,$2,0xffff
	and	$5,$3,$2
	ext	$3,$3,23,8
	li	$2,255			# 0xff
	bne	$3,$2,$L2
	swc1	$f1,0&#40;$sp&#41;          # !WRONG

	lui	$4,%hi&#40;$LC1&#41;
	bne	$5,$0,$L2
	addiu	$4,$4,%lo&#40;$LC1&#41;

	jal	printf
	nop

$L2&#58;
	jal	sceKernelExitGame
	nop

	lw	$31,8&#40;$sp&#41;
	move	$2,$0
	j	$31
	addiu	$sp,$sp,16

As Tyranid said, gcc tries to put the float on stack and pop as integer register to do the conversion. However, it puts it in wrong order, hence this code produces wrong results.
Funnily enough, with -O1 it puts them in correct order, but not with any optimization value.

Correct result is given with this code in any case though:

Code: Select all

static int is_inf&#40;float val&#41;
&#123;
	unsigned int conv;
	int sign;
	int exp;
	int mantissa;

	asm&#40;"mfc1 %0, %1\n"&#58;"=r"&#40;conv&#41;&#58;"f"&#40;val&#41;&#41;;
	sign = &#40;conv >> 31&#41; & 1;

	exp = &#40;conv >> 23&#41; & 0xff;
	mantissa = conv & 0x7fffff;

	if&#40;&#40;exp == 255&#41; && &#40;mantissa == 0&#41;&#41;
	&#123;
		if&#40;sign&#41;
		&#123;
			return -1;
		&#125;
		else
		&#123;
			return 1;
		&#125;
	&#125;

	return 0;
&#125;
Here's a patch for PSPLINKUSB (plus a small fix for VFPU disasm with prefixes) - I could probably commit it myself, but I don't feel like I should be messing on Tyranids repository:

Code: Select all

Index&#58; psplink/util.c
===================================================================
--- psplink/util.c	&#40;revision 2280&#41;
+++ psplink/util.c	&#40;working copy&#41;
@@ -860,14 +860,16 @@
 
 static int is_nan&#40;float val&#41;
 &#123;
-	void *p;
+	//void *p;
 	unsigned int conv;
 	int sign;
 	int exp;
 	int mantissa;
 
-	p = &#40;void *&#41; &val;
-	conv = *&#40;&#40;unsigned int *&#41; p&#41;;
+	/*p = &#40;void *&#41; &val;
+	conv = *&#40;&#40;unsigned int *&#41; p&#41;;*/
+	// Help stupid GCC compiler
+	asm&#40;"mfc1 %0, %1\n"&#58;"=r"&#40;conv&#41;&#58;"f"&#40;val&#41;&#41;;
 	sign = &#40;conv >> 31&#41; & 1;
 
 	exp = &#40;conv >> 23&#41; & 0xff;
@@ -883,14 +885,16 @@
 
 static int is_inf&#40;float val&#41;
 &#123;
-	void *p;
+	//void *p;
 	unsigned int conv;
 	int sign;
 	int exp;
 	int mantissa;
 
-	p = &#40;void *&#41; &val;
-	conv = *&#40;&#40;unsigned int *&#41; p&#41;;
+	/*p = &#40;void *&#41; &val;
+	conv = *&#40;&#40;unsigned int *&#41; p&#41;;*/
+	// Help stupid GCC compiler
+	asm&#40;"mfc1 %0, %1\n"&#58;"=r"&#40;conv&#41;&#58;"f"&#40;val&#41;&#41;;
 	sign = &#40;conv >> 31&#41; & 1;
 
 	exp = &#40;conv >> 23&#41; & 0xff;
Index&#58; pspsh/disasm.C
===================================================================
--- pspsh/disasm.C	&#40;revision 2280&#41;
+++ pspsh/disasm.C	&#40;working copy&#41;
@@ -1149,7 +1149,7 @@
 // &#91;hlide&#93; added pfx_sat_names
 static const char * const pfx_sat_names&#91;4&#93; =
 &#123;
-  "",  "&#91;0&#58;1&#93;",  "",  "&#91;-1&#58;1&#93;"
+  "",  "0&#58;1",  "",  "-1&#58;1"
 &#125;;
 
 /* VFPU prefix instruction operands.  The *_SH_* values really specify where
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki

Alexander Berl
Post Reply