changeset 530:585dcb68f55d

- more doc and disas examples for x86 fastcall and non-trivial aggregates
author Tassilo Philipp
date Sat, 16 Apr 2022 12:10:02 +0200
parents fe694c7677b4
children f6430d194be6
files doc/disas_examples/x86.cdecl.disas doc/disas_examples/x86.fastcall_ms.disas doc/manual/callconvs/callconv_ppc32.tex doc/manual/callconvs/callconv_x86.tex
diffstat 4 files changed, 220 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/doc/disas_examples/x86.cdecl.disas	Thu Apr 14 21:18:02 2022 +0200
+++ b/doc/disas_examples/x86.cdecl.disas	Sat Apr 16 12:10:02 2022 +0200
@@ -775,7 +775,7 @@
 1c00095f:       8d 45 f4                lea    0xfffffff4(%ebp),%eax ; |
 1c000962:       83 00 7b                addl   $0x7b,(%eax)          ; | a += 12
 1c000965:       e8 b6 ff ff ff          call   1c000920 <f1>         ; call f1()
-1c00096a:       89 45 f0                mov    %eax,0xfffffff0(%ebp) ;
+1c00096a:       89 45 f0                mov    %eax,0xfffffff0(%ebp) ; retval (trivial struct <= 32bits, returned via eax)
 1c00096d:       8d 45 f4                lea    0xfffffff4(%ebp),%eax ; |
 1c000970:       83 28 7b                subl   $0x7b,(%eax)          ; | a -= 123
 1c000973:       8d 45 d8                lea    0xffffffd8(%ebp),%eax ; space (at top of stack) to hold non-triv retval -> eax
--- a/doc/disas_examples/x86.fastcall_ms.disas	Thu Apr 14 21:18:02 2022 +0200
+++ b/doc/disas_examples/x86.fastcall_ms.disas	Sat Apr 16 12:10:02 2022 +0200
@@ -184,5 +184,221 @@
 
 
 
+; ---------- C++ trivial and non-trivial aggrs passed to C funcs ---------->
+;
+; struct Trivial { int a; };
+; struct NonTrivial {
+;         int a;
+;         NonTrivial() : a(0) {}
+;         NonTrivial(const NonTrivial& rhs) : a(rhs.a) { }
+; };
+;
+; extern "C" {
+; 
+;     void f1(struct Trivial s)    { }
+;     void f2(struct NonTrivial s) { }
+; 
+;     void f()
+;     {
+;         struct Trivial t;
+;         struct NonTrivial n;
+;         int a=1;
+;         a += 123;
+;         f1(t);
+;         a -= 123;
+;         f2(n);
+;         a -= 12;
+;     }
+; }
+
+
+
+; output from godbolt compiler explorer w/ msvc 19.31 (/Gr for fastcall)
+
+_this$ = -4
+NonTrivial::NonTrivial(void) PROC
+        push    ebp
+        mov     ebp, esp
+        push    ecx
+        mov     DWORD PTR _this$[ebp], ecx
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     DWORD PTR [eax], 0
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     esp, ebp
+        pop     ebp
+        ret     0
+NonTrivial::NonTrivial(void) ENDP
+
+_this$ = -4
+_rhs$ = 8
+NonTrivial::NonTrivial(NonTrivial const &) PROC
+        push    ebp
+        mov     ebp, esp
+        push    ecx
+        mov     DWORD PTR _this$[ebp], ecx
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     ecx, DWORD PTR _rhs$[ebp]
+        mov     edx, DWORD PTR [ecx]
+        mov     DWORD PTR [eax], edx
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     esp, ebp
+        pop     ebp
+        ret     4
+NonTrivial::NonTrivial(NonTrivial const &) ENDP
+
+_s$ = 8
+@f1@4   PROC
+        push    ebp
+        mov     ebp, esp
+        pop     ebp
+        ret     4
+@f1@4   ENDP
+
+_s$ = 8
+@f2@4   PROC
+        push    ebp
+        mov     ebp, esp
+        pop     ebp
+        ret     4
+@f2@4   ENDP
+
+_t$ = -12
+_n$ = -8
+_a$ = -4
+@f@0    PROC
+        push    ebp                                        ;
+        mov     ebp, esp                                   ;
+        sub     esp, 12                                    ;
+        lea     ecx, DWORD PTR _n$[ebp]                    ;
+        call    NonTrivial::NonTrivial(void)               ;
+        mov     DWORD PTR _a$[ebp], 1                      ;
+        mov     eax, DWORD PTR _a$[ebp]                    ;
+        add     eax, 123                                   ;
+        mov     DWORD PTR _a$[ebp], eax                    ;
+        mov     ecx, DWORD PTR _t$[ebp]                    ;
+        push    ecx                                        ;
+        call    @f1@4                                      ;
+        mov     edx, DWORD PTR _a$[ebp]                    ;
+        sub     edx, 123                                   ;
+        mov     DWORD PTR _a$[ebp], edx                    ;
+        push    ecx                                        ;
+        mov     ecx, esp                                   ;
+        lea     eax, DWORD PTR _n$[ebp]                    ;
+        push    eax                                        ;
+        call    NonTrivial::NonTrivial(NonTrivial const &) ;
+        call    @f2@4                                      ;
+        mov     ecx, DWORD PTR _a$[ebp]                    ;
+        sub     ecx, 12                                    ;
+        mov     DWORD PTR _a$[ebp], ecx                    ;
+        mov     esp, ebp                                   ;
+        pop     ebp                                        ;
+        ret     0                                          ;
+@f@0    ENDP
+
+
+
+; ---------- C++ trivial and non-trivial aggrs as return values ---------->
+;
+; struct Trivial { int a; };
+; struct NonTrivial {
+;         int a;
+;         NonTrivial() : a(0) {}
+;         NonTrivial(const NonTrivial& rhs) : a(rhs.a) { }
+; };
+; 
+; extern "C" {
+;     struct Trivial    f1() { return Trivial(); }
+; }
+; 
+;     struct NonTrivial f2() { return NonTrivial(); }
+; 
+; extern "C" {
+;     void f()
+;     {
+;         int a=1;
+;         a += 123;
+;         struct Trivial t = f1();
+;         a -= 123;
+;         struct NonTrivial n = f2();
+;         a -= 12;
+;     }
+; }
+
+
+
+; output from godbolt compiler explorer w/ msvc 19.31 (/Gr for fastcall)
+
+_this$ = -4
+NonTrivial::NonTrivial(void) PROC
+        push    ebp
+        mov     ebp, esp
+        push    ecx
+        mov     DWORD PTR _this$[ebp], ecx
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     DWORD PTR [eax], 0
+        mov     eax, DWORD PTR _this$[ebp]
+        mov     esp, ebp
+        pop     ebp
+        ret     0
+NonTrivial::NonTrivial(void) ENDP
+
+$T1 = -4
+@f1@0   PROC
+        push    ebp
+        mov     ebp, esp
+        push    ecx
+        xor     eax, eax
+        mov     DWORD PTR $T1[ebp], eax
+        mov     eax, DWORD PTR $T1[ebp]
+        mov     esp, ebp
+        pop     ebp
+        ret     0
+@f1@0   ENDP
+
+___$ReturnUdt$ = -4
+NonTrivial f2(void) PROC
+        push    ebp                                ;
+        mov     ebp, esp                           ;
+        push    ecx                                ; ptr to hidden retval space as first arg (fastcall, in ecx)
+        mov     DWORD PTR ___$ReturnUdt$[ebp], ecx ; |
+        mov     ecx, DWORD PTR ___$ReturnUdt$[ebp] ; | a bit pointless
+        call    NonTrivial::NonTrivial(void)       ;
+        mov     eax, DWORD PTR ___$ReturnUdt$[ebp] ; return passed-in ptr ptr to hidden retval space in eax
+        mov     esp, ebp                           ;
+        pop     ebp                                ;
+        ret     0                                  ;
+NonTrivial f2(void) ENDP
+
+_n$ = -16
+_t$ = -12
+$T1 = -8
+_a$ = -4
+@f@0    PROC
+        push    ebp                     ;
+        mov     ebp, esp                ;
+        sub     esp, 16                 ;
+        mov     DWORD PTR _a$[ebp], 1   ; a = 1
+        mov     eax, DWORD PTR _a$[ebp] ; |
+        add     eax, 123                ; | a += 123
+        mov     DWORD PTR _a$[ebp], eax ; |
+        call    @f1@0                   ; call f1()
+        mov     DWORD PTR $T1[ebp], eax ; retval (trivial struct <= 32bits, returned via eax)
+        mov     ecx, DWORD PTR $T1[ebp] ; | copy of retval from stack to stack
+        mov     DWORD PTR _t$[ebp], ecx ; /
+        mov     edx, DWORD PTR _a$[ebp] ; \
+        sub     edx, 123                ; | a -= 123
+        mov     DWORD PTR _a$[ebp], edx ; |
+        lea     ecx, DWORD PTR _n$[ebp] ; hidden first arg: ptr to space for (non-trivial) retval
+        call    NonTrivial f2(void)     ; call f2()
+        mov     eax, DWORD PTR _a$[ebp] ; |
+        sub     eax, 12                 ; | a -= 12
+        mov     DWORD PTR _a$[ebp], eax ; |
+        mov     esp, ebp                ;
+        pop     ebp                     ;
+        ret     0                       ;
+@f@0    ENDP
+
+
+
 ; vim: ft=asm
 
--- a/doc/manual/callconvs/callconv_ppc32.tex	Thu Apr 14 21:18:02 2022 +0200
+++ b/doc/manual/callconvs/callconv_ppc32.tex	Sat Apr 16 12:10:02 2022 +0200
@@ -261,7 +261,7 @@
 \subsubsection{System V PPC 32-bit / Linux Standard Base version}
 
 This is in essence the same as the System V PPC 32-bit calling convention, but differs for aggregate return values:
-% @@@STRUCT make this more obvious
+% @@@AGGR could be more verbose
 
 \begin{itemize}
 \item for all aggregates, the caller allocates space, passes pointer to it to the callee as a hidden first param
--- a/doc/manual/callconvs/callconv_x86.tex	Thu Apr 14 21:18:02 2022 +0200
+++ b/doc/manual/callconvs/callconv_x86.tex	Sat Apr 16 12:10:02 2022 +0200
@@ -188,10 +188,9 @@
 \paragraph{Return values}
 
 \begin{itemize}
-\item return values of pointer or integral type (\textless=\ 32 bits) are returned via the eax register
+\item return values of pointer or integral type, as well as aggregates (structs, unions) \textless=\ 64 are returned via the eax and edx registers
 \item for {\it non-trivial} C++ aggregates, the caller allocates space, passes pointer to it to the callee as a hidden first param
 (meaning via ecx), and callee writes return value to this space; the ptr to the aggregate is returned in eax
-\item integers and aggregates (structs, unions) \textgreater\ 32 and \textless=\ 64 bits are returned via the eax and edx registers
 \item return values \textgreater\ 64 bits (e.g. aggregates) are returned by the caller allocating the space and
 passing a pointer to the callee as a new, implicit first parameter (always via the stack, never via a register)
 \item floating point types are returned via the st0 register
@@ -510,7 +509,7 @@
 \item arguments \textgreater\ 64 bits are pushed as a sequence of dwords
 \item aggregates (structs, unions) are pushed as a sequence of dwords
 \item {\it non-trivial} C++ aggregates (as defined by the language) of any size, are passed indirectly via a pointer to a copy of the aggregate
-\item stack is usually 4 byte aligned (GCC \textgreater=\ 3.x seems to use a 16byte alignement)
+\item stack is usually 4 byte aligned (GCC \textgreater=\ 3.x seems to use a 16byte alignment)
 \item the direction flag is clear on entry and must be returned clear % mention it first, above @@@
 \end{itemize}