On 386 when a function returns a struct the pointer to the return value is passed as a hidden first parameter, and the function is supposed to "ret 4" to pop the hidden parameter when returning to the caller. The implementation of reflect.MakeFunc in libgo was not doing that. This patch fixes the problem. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu, in both 32-bit and 64-bit mode. Committed to mainline and 4.8 branch.
Ian
diff -r fa6c22b293e8 libgo/go/reflect/makefunc_386.S --- a/libgo/go/reflect/makefunc_386.S Tue Nov 26 16:49:31 2013 -0800 +++ b/libgo/go/reflect/makefunc_386.S Sat Nov 30 09:05:42 2013 -0800 @@ -26,8 +26,11 @@ esp uint32 // 0x0 eax uint32 // 0x4 st0 uint64 // 0x8 + rs int32 // 0x10 } - */ + The rs field is set by the function to a non-zero value if + the function takes a struct hidden pointer that must be + popped off the stack. */ pushl %ebp .LCFI0: @@ -73,12 +76,19 @@ movsd -16(%ebp), %xmm0 #endif + movl -8(%ebp), %edx + addl $36, %esp popl %ebx .LCFI3: popl %ebp .LCFI4: + + testl %edx,%edx + jne 1f ret +1: + ret $4 .LFE1: #ifdef __ELF__ .size reflect.makeFuncStub, . - reflect.makeFuncStub diff -r fa6c22b293e8 libgo/go/reflect/makefuncgo_386.go --- a/libgo/go/reflect/makefuncgo_386.go Tue Nov 26 16:49:31 2013 -0800 +++ b/libgo/go/reflect/makefuncgo_386.go Sat Nov 30 09:05:42 2013 -0800 @@ -16,6 +16,7 @@ esp uint32 eax uint32 // Value to return in %eax. st0 uint64 // Value to return in %st(0). + sr int32 // Set to non-zero if hidden struct pointer. } // MakeFuncStubGo implements the 386 calling convention for MakeFunc. @@ -56,10 +57,12 @@ in := make([]Value, 0, len(ftyp.in)) ap := uintptr(regs.esp) + regs.sr = 0 var retPtr unsafe.Pointer if retStruct { retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap)) ap += ptrSize + regs.sr = 1 } for _, rt := range ftyp.in {