2014-06-20 89 views
0

爲什麼編譯器在函數調用之前放置瞭如此多的命令(查看下面的鏈接)?據我所知,它應該只在調用之前傳遞函數參數。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個OPS最後一種情況,就是超越我...

附:在我年輕的時候,通常我們會把函數參數放在堆棧中(推),而不是讀取它們(彈出)。現在,我們通過寄存器傳遞參數?

+0

64位調用約定訪問不使用推。 –

+0

@RaymondChen這是什麼?我只與舊的x80 /​​ x86 asm :) – tower120

+0

@Gluttton註冊與q(沒有)/(無法推)到堆棧?它有沒有'pushq'? – tower120

回答

3

這很正常。在彙編中,我通常只做一件事。例如,在最後一種情況下:

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

+0

只是爲了總結。我們將「this」(對象地址)傳遞給%esi,並將第一個參數傳遞給%rdi? – tower120

+0

最後一個參數(以相反順序)始終是對象地址?在我們的例子中'%esi' /'%rsi' – tower120

+1

第一個參數(在%rdi中)是對象地址(這個指針)。第二個參數(在%rsi中)是該函數的實際第一個參數(int a)。第三個參數將是實際的第二個參數,依此類推。 –