好吧,我調試的問題。
的問題是,在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即將發佈) –