Search code examples
cgccassemblymingwcalling-convention

gcc mingw gives garbage output when combining with assembly


My gcc:Thread model: posix

gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)

I'm trying to create a simple application which sums two numbers with two files saberi.c and saberi.s using gcc and intel syntax where saberi means sum.

saberi.c

#include <stdio.h>
int saberi(int a, int b);
int main()
{   
    int a, b;
    scanf("%d %d", &a, &b);
    printf("Sum is: %d\n", saberi(a, b));
    return 0;
}

saberi.s

.intel_syntax noprefix
.text
    .globl saberi
saberi:
    enter 0,0
    mov eax, edi
    add eax, esi
    leave
    ret

I then do gcc saberi.c saberi.s and when I open the executable and type any two numbers for example(1 and 2) and I get a random value as the sum.


Solution

  • The MinGW compiler compiles by default for the Windows target. Meaning the compiler follows the Windows ABI and windows calling convention. The first two integer arguments are passed in rcx and rdx instead of rdi and rsi as in the System V ABI.

    You can verify by generating the assembly for saberi.c as -

    gcc -S saberi.c -o saberi_compiled.s
    

    You will see that before calling saberi, the compiler moves the arguments in ecx and edx.

    So your saberi.s should be changed to -

    intel_syntax noprefix
    .text
        .globl saberi
    saberi:
        enter 0,0
        mov eax, ecx
        add eax, edx
        leave
        ret
    

    And you should get correct results.

    The other option is to tell the compiler to use the System V ABI while calling saberi. This can be done in gcc (MinGW) using sysv_abi attribute for the saberi function as -

    int saberi(int a, int b) __attribute__((sysv_abi));
    

    Then you can keep your assembly the same. This method is useful when you want to write assembly that is portable across platforms. But of course it is limited to only gcc.