https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81943
Bug ID: 81943 Summary: Wrong ABI in class methods returning structs for the Windows amd64 target Product: gcc Version: 7.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: blaffablaffa at gmail dot com Target Milestone: --- test case: struct retstruct{ int a; }; struct badABI{ retstruct f(int arg){ retstruct ret; ret.a = arg; arg++; return ret; } }; int main(){ badABI test; auto testret = test.f(234); }; g++ assembly output (x86_64-w64-mingw32-g++ -S -std=c++11 -o main.S main.cpp) around the badABI::f call: leaq -1(%rbp), %rax movl $234, %edx #2nd arg, int movq %rax, %rcx #1st arg, this pointer call _ZN6badABI1fEi movl %eax, -8(%rbp) #returned struct in eax cl.exe (version 19, Visual Studio 2017) output: mov r8d, 234 ; 000000eaH #3rd argument, int lea rdx, QWORD PTR testret$[rsp] #2nd argument, return buffer lea rcx, QWORD PTR test$[rsp] #1st argument, this pointer call badABI::f Note that this is not fixed by -fpcc-struct-return, because the this pointer and the hidden return struct buffer pointer are inverted: leaq -8(%rbp), %rax leaq -1(%rbp), %rdx #2nd argument, this pointer movl $234, %r8d #3rd argument, int movq %rax, %rcx #1st argument, return buffer call _ZN6badABI1fEi As far as I know this last convention isn't used anywhere on windows, so it's completely wrong. On the other hand, the first convention appears to follow the specifications for small struct returns (https://msdn.microsoft.com/en-us/library/7572ztz4(v=vs.120).aspx), but I can't explain why the latest cl.exe does not appear to use it. There are projects where this discrepancy has been taken into account, the one I know of is https://github.com/SteamRE/open-steamworks : it is a reverse engineering of the Steamworks SDK (started when it wasn't public), and they have a number of instances (see for example https://github.com/SteamRE/open-steamworks/blob/master/Open%20Steamworks/ISteamUser017.h#L44 macro STEAMWORKS_STRUCT_RETURN_0) where the return of structs is fixed by actually returning void and passing a reference to the return buffer. clang appears to emit the right assembly when using -cc1 -triplet x86_64-pc-windows-msvc18.0.0 (default of clang-cl): leaq 48(%rsp), %rcx #1st argument, this pointer leaq 40(%rsp), %rdx #2nd argument, return buffer movl $234, %r8d #3rd argument, int callq "?f@badABI@@QEAA?AUretstruct@@H@Z" excerpt of badABI::f: movq %rdx, %rax #return buffer pointer in rax (correct as per microsoft ABI) movl %r8d, 12(%rsp) movq %rcx, (%rsp) movl 12(%rsp), %r8d movl %r8d, (%rdx) movl 12(%rsp), %r8d addl $1, %r8d movl %r8d, 12(%rsp)