Discussion:
Cosure return value issue on Linux PPC64
Kaz Kylheku (libffi)
2017-05-27 16:59:36 UTC
Permalink
Hi all,

My interpreted language's test suite failed on a PPC64 Linux box
(gcc110.fsffrance.org).

The test in question uses the qsort C library function to sort a Lisp
vector, using a Lisp callback.

Unfortunately, the int return value from the callback turns to garbage.
The problem reproduces with current libffi from git.

The following test patch makes the problem go away and all tests pass:


diff --git a/src/powerpc/linux64_closure.S
b/src/powerpc/linux64_closure.S
index 6487d2a..28a191a 100644
--- a/src/powerpc/linux64_closure.S
+++ b/src/powerpc/linux64_closure.S
@@ -27,7 +27,8 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
-
+#undef __LITTLE_ENDIAN__
+#define __LITTLE_ENDIAN__ 1
.file "linux64_closure.S"

#ifdef POWERPC64


The problem is that all the big endian cases are expecting the caller to
place the return value at a displaced address. If the type is int, for
instance, the expectation is that the return value is to be stored at
*(int *)(retval + 4). If it is short, then at *(short *)(retval + 6)
and so on.

Is this documented somewhere?

My code is storing everything at just the retval base address,
regardless of size.

Cheers ...
Andrew Haley
2017-05-29 07:44:05 UTC
Permalink
Post by Kaz Kylheku (libffi)
The problem is that all the big endian cases are expecting the caller to
place the return value at a displaced address. If the type is int, for
instance, the expectation is that the return value is to be stored at
*(int *)(retval + 4). If it is short, then at *(short *)(retval + 6)
and so on.
Is this documented somewhere?
My code is storing everything at just the retval base address,
regardless of size.
On a 64-bit target, use word loads for your return values and cast them
accordingly. So, don't use

*(int *)(retval + 4)

use

(int)*retval
--
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
Tom Tromey
2017-05-29 12:31:11 UTC
Permalink
Kaz> Is this documented somewhere?

A while back I tried to document all these little oddities in the
manual. It's difficult and ABI-breaking to fix libffi to be more in
line with user expectation, but at least in the meantime the docs can be
correct...

The closure docs say:

@item ret
[...]
Otherwise, @var{fun} must fill the object to which this points,
following the same special promotion behavior as @code{ffi_call}.
That is, in most cases, @var{ret} points to an object of exactly the
size of the type specified when @var{cif} was constructed. However,
integral types narrower than the system register size are widened. In
these cases your program may assume that @var{ret} points to an
@code{ffi_arg} object.

I hope this helps, but if it's still insufficiently clear, I'd
appreciate suggestions for how to improve it.

From your other note:

Kaz> I'm not a complete idiot; I was taken for a ride by the simple
Kaz> example from some (perhaps outdated?) libffi texinfo
Kaz> documentation. This one:

You're definitely not an idiot, this has bitten many people, has been
asked on StackOverflow, has been filed as a bug in github a few times,
etc.

Alan Modra fixed up this documentation example back in 2013, according
to git blame. Seems like libffi is overdue for a release :-)

Anyway, I think the in-tree docs should be a bit clearer here. For
example they mention the promotion behavior now.

Tom
Andrew Haley
2017-05-29 15:30:50 UTC
Permalink
Post by Tom Tromey
I hope this helps, but if it's still insufficiently clear, I'd
appreciate suggestions for how to improve it.
A couple of examples would help. I find that wordage confusing.
--
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
Loading...