<div dir="ltr"><div> Hi Balazs,</div><div>I confirm what you observe.</div><div>If I compile the source with:</div><div><br></div><div> clang --shared -o libalientest.so -Os alientest.c</div><div><br></div><div>then disassemble with:</div><div><br></div><div> objdump -D libalientest.so | less</div><div><br></div><div>I get this:</div><div><br></div><div> 000000000000057c <atv>:<br> 57c: c3 retq <br><br> 000000000000057d <at34>:<br> 57d: f2 0f 10 05 1b 00 00 movsd 0x1b(%rip),%xmm0 # 5a0 <_fini+0x10><br> 584: 00 <br> 585: f2 0f 10 0d 1b 00 00 movsd 0x1b(%rip),%xmm1 # 5a8 <_fini+0x18><br> 58c: 00 <br> 58d: c3 retq <br></div><div><br></div><div>Code is highly suspicious for atv...<br></div><div>at34 just load the constants in dregs, then do nothing (inline atv).</div><div>So this does not work as advertized...</div><div><br></div><div>The non optimized version is very convoluted:</div><div><br></div><div>0000000000000580 <atv>:<br> 580: 55 push %rbp<br> 581: 48 89 e5 mov %rsp,%rbp<br> 584: f2 0f 11 45 e8 movsd %xmm0,-0x18(%rbp)<br> 589: f2 0f 11 4d e0 movsd %xmm1,-0x20(%rbp)<br> 58e: f2 0f 10 45 e8 movsd -0x18(%rbp),%xmm0<br> 593: f2 0f 11 45 d0 movsd %xmm0,-0x30(%rbp)<br> 598: f2 0f 10 45 e0 movsd -0x20(%rbp),%xmm0<br> 59d: f2 0f 11 45 d8 movsd %xmm0,-0x28(%rbp)<br> 5a2: 0f 10 45 d0 movups -0x30(%rbp),%xmm0<br> 5a6: 0f 29 45 f0 movaps %xmm0,-0x10(%rbp)<br> 5aa: f2 0f 10 45 f0 movsd -0x10(%rbp),%xmm0<br> 5af: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1<br> 5b4: 5d pop %rbp<br> 5b5: c3 retq <br> 5b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)<br> 5bd: 00 00 00 <br><br>00000000000005c0 <at34>:<br> 5c0: 55 push %rbp<br> 5c1: 48 89 e5 mov %rsp,%rbp<br> 5c4: 48 83 ec 10 sub $0x10,%rsp<br> 5c8: f2 0f 10 05 38 00 00 movsd 0x38(%rip),%xmm0 # 608 <_fini+0x10><br> 5cf: 00 <br> 5d0: f2 0f 10 0d 38 00 00 movsd 0x38(%rip),%xmm1 # 610 <_fini+0x18><br> 5d7: 00 <br> 5d8: e8 a3 ff ff ff callq 580 <atv><br> 5dd: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp)<br> 5e2: f2 0f 11 4d f8 movsd %xmm1,-0x8(%rbp)<br> 5e7: f2 0f 10 45 f0 movsd -0x10(%rbp),%xmm0<br> 5ec: f2 0f 10 4d f8 movsd -0x8(%rbp),%xmm1<br> 5f1: 48 83 c4 10 add $0x10,%rsp<br> 5f5: 5d pop %rbp<br> 5f6: c3 retq <br></div><div>
<div><br></div><div>It's clear that the resulting structure is passed via first 2 dregs (xmm0 and xmm1).<br></div><div>Doesn't it qualify as a clang bug? Or is our interpretation of ABI erroneous?</div>
</div><div>I would opt for the later...<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le mar. 5 nov. 2019 à 23:54, Balázs Kósi <<a href="mailto:rebmekop@gmail.com">rebmekop@gmail.com</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Hi all,</div><div><br></div><div>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.</div><div><br></div><div>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].<br></div><div><br></div><div>Here is a minimal example calling a C function returning a struct with two doubles:<br></div><div><br></div><div>at34 := Alien lookup: 'at34' inLibrary: 'libalientest.so'.<br>at34 primFFICallResult: nil with: (r := Alien newC: 16) pointer.<br>vec := (r doubleAt: 1) @ (r doubleAt: 9). r free. vec " 0.0@0.0 "<br></div><div><br></div><div>returns 0.0@0.0 instead of 3.0@4.0<br></div><div><br></div><div>the C code goes like this:<br></div><div><br></div><div>typedef struct atvect{double x, y;} atvect;</div><div><br></div><div>atvect atv(double x, double y) {<br> atvect v = {x, y};<br> return v;<br>}<br></div><div><br></div><div>atvect at34() {<br> return atv(3.0, 4.0);<br>}</div><div><br></div><div>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.</div><div><br></div><div>What am I missing?<br></div><div><br></div><div>Thanks, Balázs</div><div><br></div><div>[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 ... ". <br></div><div><br></div><div><a href="https://wiki.squeak.org/squeak/uploads/6100/Alien%20FFI.2.pdf" target="_blank">https://wiki.squeak.org/squeak/uploads/6100/Alien%20FFI.2.pdf</a></div><div><br></div><div>[2] <a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/a8a1dc1e33267e0fa2dab22959e41d0a072420d9/platforms/Cross/plugins/IA32ABI/dax64business.h#L92" target="_blank">https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/a8a1dc1e33267e0fa2dab22959e41d0a072420d9/platforms/Cross/plugins/IA32ABI/dax64business.h#L92</a></div><div><br></div><div>[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<br>argument to the function. In effect, this address becomes a “hidden” first ar-<br>gument. This storage must not overlap any data visible to the callee through<br>other names than this argument. <br></div><div>On return %rax will contain the address that has been passed in by the<br>caller in %rdi."</div><div><br></div><div> <a href="https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf" target="_blank">https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf</a> p.24.<br></div></div>
<br>
</blockquote></div>