好吧,我调试的问题。
的问题是,在LibFFI的PPC64代码包含大端不符合我的预期的情况下。
我应用这个测试补丁:
--- 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
和我所有的测试都通过了。什么__LITTLE_ENDIAN__
控制有条件包含的代码块这样的:
# case FFI_TYPE_INT
# ifdef __LITTLE_ENDIAN__
lwa %r3, RETVAL+0(%r1)
# else
lwa %r3, RETVAL+4(%r1)
# endif
mtlr %r0
addi %r1, %r1, STACKFRAME
.cfi_def_cfa_offset 0
blr
.cfi_def_cfa_offset STACKFRAME
客户端代码,在大端,有望取代存储的返回值,使之与一个8字节字的顶部对齐。
因此,要存储一个int
(四个字节),代码预计将执行*(int *)(retptr+4) = val
,而不是简单的*(int *)retptr = val
,因为我的代码正在执行。
看来,期望的是,该应用程序是应该以一个8字节字存储到的返回值而不管FFI类型的:它是一个字符,短,int或(64位)长。这就是说:
(的int64_t)retptr = VAL;/ val为字符,短,无论*/
这样的值的至少显著字节位于retptr + 7
,和因此使用该地址,如果实际类型是char
;如果它是short
等,则使用retptr + 6
等等。 FFI代码是有道理的。问题在于它不方便且不一致; FFI的论点不需要这样处理。
例如,所述int
参数在下面呼叫不是由4个字节移位;它只是写入到给定缓冲区的基址libffi
This is the TXR Lisp interactive listener of TXR 176.
Use the :quit command or type Ctrl-D on empty line to exit.
1> (with-dyn-lib nil (deffi printf "printf" int (str : int)))
#:lib-0185
2> (printf "foo %d\n" 1)
foo 1
0
但是,哦,看;返回值是假的!外部函数调用返回值也有类似的问题。
它看起来像我被一个例子一些libffi文档中上当,即此一:
#include <stdio.h>
#include <ffi.h>
int main()
{
ffi_cif cif;
ffi_type *args[1];
void *values[1];
char *s;
int rc;
/* ... abbreviated ... */
s = "This is cool!";
ffi_call(&cif, puts, &rc, values);
/* rc now holds the result of the call to puts */
/* ... */
}
事实证明,这是不正确的;其他一些libffi文档说,返回值必须使用ffi_arg
类型(其中,令人困惑的是,不用于参数)捕获。因此,我认为上述示例应该是这样做的:
ffi_arg rc_buf;
int rc;
/*...*/
s = "Turned out uncool, but we promise this is really cool now!";
ffi_call(&cif, puts, &rc_buf, values);
rc = (int) rc_buf;
您正在使用哪个版本的Valgrind?并在什么操作系统? –
@PaulFloyd好点。在Glibc 2.18的Fedora系统上,Valgrind是3.9.0。 – Kaz
是否可以使用3.12? (3.13即将发布) –