Home > Back-end >  return value Vs reference (in assembly)
return value Vs reference (in assembly)

Time:12-25

After taking a look at a few questions (and answers) regarding this topic, I tried the below simple code in godbolt.

#include <iostream>


class TwoInts
{
public:
    TwoInts( ) = default;

    const int& getAByRef( ) const;

    int getAByVal( ) const;

private:
    int a;
    int b;
};

const int& TwoInts::getAByRef( ) const
{
    return a;
}

int TwoInts::getAByVal( ) const
{
    return a;
}


int main( )
{
    TwoInts ti;

    const int& num1 { ti.getAByRef( ) };
    const int num2 { ti.getAByVal( ) };

    //std::cout << num1 << ' ' << num2 << '\n';
}

Now I see different codes generated for the two member functions getAByRef and getAByVal:

TwoInts::getAByRef() const:
        mov     rax, rdi
        ret
TwoInts::getAByVal() const:
        mov     eax, DWORD PTR [rdi]
        ret

I would appreciate it if someone could explain what those two different assembly instructions are doing?

CodePudding user response:

Each member function gets this as an implicit first argument. In ABI used by that particular compiler (Itanium ABI), the first argument is passed in the rdi register and a value is returned (if it's trivial, and here it is) in the rax (eax) register.

In the first case, when you return a by reference, you're actually returning an address of a. a is the first member, so its address is the same as that of the object, i.e. this. Hence, you just set rax to rdi.

In the second case, when you return a by value, you need to do actual dereferencing. That's what DWORD PTR [rdi] is doing. DWORD PTR means that you want to fetch 4 bytes (sizeof(int)).

If you put some data member before a, you'll see an additional offset added to rdi.

  • Related