gcc — вызов функции компилятора C ++

Почему компилятор ставит так много команд перед вызовом функции (посмотрите на ссылку ниже)? Как я понимаю, он должен передавать только параметры функции перед вызовом.

struct A{
int c = 5;
void test(unsigned int a){
a++;
c++;
}
};

struct C{
int k =2;
A a;
};

struct D{
int k =2;
C c;
};

struct B{
int k =2;
D d;
};

void test(unsigned int a){
a++;
}

B *b = new B();
A *ae = new A();

int main()
{
int a = 1;
A ai;
B bi;
C ci;

// 2 operations (why not pop/push ?)
// movl   -36(%rbp), %eax
// movl   %eax, %edi
// call   test(unsigned int)
test(a);

// 4 operations (why 4? we pass something else?)
// movl   -36(%rbp), %edx
// leaq   -48(%rbp), %rax
// movl   %edx, %esi
// movq   %rax, %rdi
// call   A::test(unsigned int)
ai.test(a);
ae->test(a);// 5 operations before call (what a hell is going here?, why that "addq" ?)
// movl   -36(%rbp), %eax
// leaq   -32(%rbp), %rdx
// addq   $4, %rdx
// movl   %eax, %esi
// movq   %rdx, %rdi
// call   A::test(unsigned int)
ci.a.test(a);
bi.d.c.a.test(a);
b->d.c.a.test(a);
// no matter how long this chain will be - it will always took 5 operations
}

http://goo.gl/smFSA6

Почему, когда мы вызываем участника класса, для подготовки к вызову потребовалось 4 дополнительные команды? Мы загружаем адрес объекта для регистрации, а?

И последний случай с 5 опс, просто за мной …

Постскриптум Во времена моей юности мы обычно помещали функциональные параметры в стек (push), а не читали их (pop). Теперь что, мы пропускаем параметры через регистры?

0

Решение

Это нормально. В сборке я обычно занимаюсь только одним делом. например в последнем случае:

movl   -36(%rbp), %eax       ; move a to %eax
leaq   -32(%rbp), %rdx       ; move & ci  to %rdx
addq   $4, %rdx              ; set %rdx to ci->a = ci + offset of a
movl   %eax, %esi            ; move a from %eax to %esi (second parameter)
movq   %rdx, %rdi            ; move ci->a from %rdx to %rdi (first parameter)
call   A::test(unsigned int) ; call A::test

В 64-битных системах Linux параметры функции больше не передаются в стеке, первые 6 целочисленных параметров передаются в %rdi, %rsi, %rdx, %rcx, %r8, %r9 регистры. Значения с плавающей точкой используют %xmm0%xmm7 регистры, а остальные переносятся в стек.

Конечно, локальные переменные находятся в стеке и доступны через %rbp

3

Другие решения