0

The following small C code contains a swap function called by main.

Surprisingly, when I'd inspected the assembly code produced by the compiler, I've realized that, somehow, the compiler understands my intention (realizes the outcome of the code) and then tries to achieve the correct result without entering into the swap function (possible reason being 'in the name of optimization'). Assembly code even does not use variables; it just once prints 3 and 5; then 5 and 3.

However, my true intention was to inspect the assembly and to understand how arguments are passed from one function to another (I'm trying to learn assembly). I've tried to compile without optimization (removing the -O3 directive) and it worked but this time assembly code exploded from 28 lines to 54.

My question: Is there a gcc compiler directive to force the compiler to create the assembly code in a way I want to inspect (ie. arguments pushed into the stack and passed to functions this way)?

This is the compiler explorer link of the code.

This is main.c

#include <stdio.h>
#include <stdlib.h>

void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main(int argc, char **argv) {
    int x = 3, y = 5;
    printf("(1) =>   x = %d   y = %d\n\n", x, y);
    swap(&x, &y);
    printf("(2) =>   x = %d   y = %d\n\n", x, y);
    return (0);
}

and this is the assembly created by the compiler:

swap(int*, int*):
        movl    (%rdi), %eax    # *a_2(D), t
        movl    (%rsi), %edx    # *b_4(D), D.3500
        movl    %edx, (%rdi)    # D.3500, *a_2(D)
        movl    %eax, (%rsi)    # t, *b_4(D)
        ret
.LC0:
        .string "(1) =>   x = %d   y = %d\n\n"
.LC1:
        .string "(2) =>   x = %d   y = %d\n\n"
main:
        subq    $8, %rsp        #,
        movl    $5, %ecx        #,
        movl    $3, %edx        #,
        movl    $.LC0, %esi     #,
        movl    $1, %edi        #,
        xorl    %eax, %eax      #
        call    __printf_chk    #
        movl    $3, %ecx        #,
        movl    $5, %edx        #,
        movl    $.LC1, %esi     #,
        movl    $1, %edi        #,
        xorl    %eax, %eax      #
        call    __printf_chk    #
        xorl    %eax, %eax      #
        addq    $8, %rsp        #,
        ret
ssd
  • 2,340
  • 5
  • 19
  • 37
  • 1
    Just declare `swap` but don't define it. That was GCC, or any other compiler, won't be able to inline it. – Ross Ridge Feb 20 '16 at 17:55
  • 1
    I'd like to make the observation that you are generating 64-bit code and the [System V 64-Bit Linux ABI](http://www.x86-64.org/documentation/abi.pdf) will pass arguments in registers (and if need be on the stack). Maybe you were intending to generate 32-bit code where the convention is to generally pass parameters on the stack? – Michael Petch Feb 20 '16 at 18:01
  • 1
    And if you are interested in 32-bit code you can add `-m32` to the gcc compiler options. – Michael Petch Feb 20 '16 at 18:02
  • In the 64-bit Linux calling convention the first parameter in your example is passed in _RDI_ and the second parameter in _RSI_ – Michael Petch Feb 20 '16 at 18:04
  • @MichaelPetch: I've got two tricks, one from the duplicate link and one from your comment: `-m32` and `-fno-inline` together worked for me. Thank you. – ssd Feb 20 '16 at 18:06
  • I don't necessarily consider this a duplicate of the other because the issue goes beyond just the optimization of inline. It is also about the difference between ABIs and calling convention. – Michael Petch Feb 20 '16 at 18:10

0 Answers0