Hi all, I'm having trouble with calling struct returning functions with alien on a 64bit linux vm using the hidden first argument mechanism [1]. The function gets called, but the result is not copied into the struct pointed by the hidden argument. I tried to debug what happens with gdb, but everything looks fine, except not getting the result back. The address is copied into %rdi (regs[0]) in dax64business.h:92 [2], which is exactly what the spec says [3]. Here is a minimal example calling a C function returning a struct with two doubles: at34 := Alien lookup: 'at34' inLibrary: 'libalientest.so'. at34 primFFICallResult: nil with: (r := Alien newC: 16) pointer. vec := (r doubleAt: 1) @ (r doubleAt: 9). r free. vec " 0.0@0.0 " returns 0.0@0.0 instead of 3.0@4.0 the C code goes like this: typedef struct atvect{double x, y;} atvect; atvect atv(double x, double y) { atvect v = {x, y}; return v; } atvect at34() { return atv(3.0, 4.0); } The vm is sqcogspur64linuxht 5.0-201910291408. The image is a recent trunk image (update: #19142), image format 68021 (64 bit). Alien is Alien-Core-TorstenBergmann.101.mcz. What am I missing? Thanks, Balázs [1] "The rules for structure results vary slightly by platform. Most functions returning structures expect a “hidden” first parameter holding the result struct’s address. Because the FFI provides no abstraction one must pass this parameter explicitly. ... On linux all struct results are re-turned through the hidden first argument mechanism ... ". [3] "2. If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first ar- gument. This storage must not overlap any data visible to the callee through other names than this argument. On return %rax will contain the address that has been passed in by the caller in %rdi." |
Hi Balazs, I confirm what you observe. If I compile the source with: clang --shared -o libalientest.so -Os alientest.c then disassemble with: objdump -D libalientest.so | less I get this: 000000000000057c <atv>: 57c: c3 retq 000000000000057d <at34>: 57d: f2 0f 10 05 1b 00 00 movsd 0x1b(%rip),%xmm0 # 5a0 <_fini+0x10> 584: 00 585: f2 0f 10 0d 1b 00 00 movsd 0x1b(%rip),%xmm1 # 5a8 <_fini+0x18> 58c: 00 58d: c3 retq Code is highly suspicious for atv... at34 just load the constants in dregs, then do nothing (inline atv). So this does not work as advertized... The non optimized version is very convoluted: 0000000000000580 <atv>: 580: 55 push %rbp 581: 48 89 e5 mov %rsp,%rbp 584: f2 0f 11 45 e8 movsd %xmm0,-0x18(%rbp) 589: f2 0f 11 4d e0 movsd %xmm1,-0x20(%rbp) 58e: f2 0f 10 45 e8 movsd -0x18(%rbp),%xmm0 593: f2 0f 11 45 d0 movsd %xmm0,-0x30(%rbp) 598: f2 0f 10 45 e0 movsd -0x20(%rbp),%xmm0 59d: f2 0f 11 45 d8 movsd %xmm0,-0x28(%rbp) 5a2: 0f 10 45 d0 movups -0x30(%rbp),%xmm0 5a6: 0f 29 45 f0 movaps %xmm0,-0x10(%rbp) 5aa: f2 0f 10 45 f0 movsd -0x10(%rbp),%xmm0 5af: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1 5b4: 5d pop %rbp 5b5: c3 retq 5b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 5bd: 00 00 00 00000000000005c0 <at34>: 5c0: 55 push %rbp 5c1: 48 89 e5 mov %rsp,%rbp 5c4: 48 83 ec 10 sub $0x10,%rsp 5c8: f2 0f 10 05 38 00 00 movsd 0x38(%rip),%xmm0 # 608 <_fini+0x10> 5cf: 00 5d0: f2 0f 10 0d 38 00 00 movsd 0x38(%rip),%xmm1 # 610 <_fini+0x18> 5d7: 00 5d8: e8 a3 ff ff ff callq 580 <atv> 5dd: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp) 5e2: f2 0f 11 4d f8 movsd %xmm1,-0x8(%rbp) 5e7: f2 0f 10 45 f0 movsd -0x10(%rbp),%xmm0 5ec: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1 5f1: 48 83 c4 10 add $0x10,%rsp 5f5: 5d pop %rbp 5f6: c3 retq It's clear that the resulting structure is passed via first 2 dregs (xmm0 and xmm1). Doesn't it qualify as a clang bug? Or is our interpretation of ABI erroneous?
I would opt for the later... Le mar. 5 nov. 2019 à 23:54, Balázs Kósi <[hidden email]> a écrit :
|
Wikipedia tells that ou assumptions are wrong: or if you prefer going to the reference: You'll see that the rules are quite complex! Notably, page 21, the structure has class MEMORY if longer than eight eightbyte (that's 64 bytes !). So you should open bug report on Smalltalk side... And we lack many tests... Le mer. 6 nov. 2019 à 13:56, Nicolas Cellier <[hidden email]> a écrit :
|
because it won't be solved that easily... It might take some time. Le mer. 6 nov. 2019 à 14:16, Nicolas Cellier <[hidden email]> a écrit :
|
Free forum by Nabble | Edit this page |