gcc가 x64 시스템에서 매개 변수를 어떻게 전달하는지,linux,mac,iOS 적용

9948 단어
전편에서는 vc(windows) 플랫폼이 x64 체계에서 c 함수의 참조 방식을 소개했다.이 편은 gcc(클래스linux,mac) 플랫폼이 x64에서 c 함수가 어떻게 참조되는지 소개할 것이다.시간과 편폭을 절약하기 위해 먼저 10개의 매개 변수가 있는 함수를 정의한다. 매개 변수 유형은 내장 유형을 포함한다.
int foo(char c, short s, int i, long l, long long ll, char* p, //  6   ,           
      void** pp, float f, void* x, double d);

어셈블러 호출
foo('c', 0, 1, 2, 3, (char*)0x4, (void**)0x5, 1.f, (void*)6, 2.f);
0x000000000040067b <+55>:    movsd  0x2d5(%rip),%xmm0        # 0x400958 <__dso_handle+8>    double d = 2.f
   0x0000000000400683 <+63>:    movq   $0x6,0x8(%rsp)        # (void*) 6
   0x000000000040068c <+72>:    movq   $0x5,(%rsp)        # (void**) 0x5
   0x0000000000400694 <+80>:    movapd %xmm0,%xmm1
   0x0000000000400698 <+84>:    movss  0x2c0(%rip),%xmm0        # 0x400960 <__dso_handle+16>    float f = 1.f
   0x00000000004006a0 <+92>:    mov    $0x4,%r9d        # (char*) 0x4
   0x00000000004006a6 <+98>:    mov    $0x3,%r8d        # (long long) 3
0x00000000004006ac <+104>:    mov    $0x2,%ecx        # (long) 2
   0x00000000004006b1 <+109>:    mov    $0x1,%edx        # (int) 1
   0x00000000004006b6 <+114>:    mov    $0x0,%esi        # (short) 0
   0x00000000004006bb <+119>:    mov    $0x63,%edi        # (char) 'c'
   0x00000000004006c0 <+124>:    callq  0x4005c4 <_Z3foocsilxPcPPvfS0_d>

데이터 유형은 두 종류로 나뉘는데 부동점과 비부동점형이다.내가 전하는 실제 매개 변수도 이 두 종류에 따라 점차적으로 증가한다.비부동 소수점 매개 변수는 각각'c', 0, 1, 2, 3, (char*) 0x4, (void**) 0x5, (void*) 6이다.먼저 6개의 우선순위를 rdi,rsi,rdx,rcx,r8,r9로 순서대로 배열합니다.남은 (void**) 5, (void*) 6.부동 소수점 매개 변수는 각각 1이다.f, 2.f. xmm0, xmm1로 순서대로 배치합니다.마지막으로 두 가지 종류를 레지스터에 넣을 수 없는 나머지 매개 변수를 오른쪽에서 왼쪽으로 순서대로 창고에 넣습니다.
 
다음은 슈퍼 무적 다중 매개 변수의 함수를 다시 정의하여 모든 전송 레지스터를 사용하여 제 분석을 증명합니다.
int foo2(char c, short s, int i, long l, long long ll, char* p, 
        void** pp, float f, void* x, double d,                     //      foo    
        float xmm2, float xmm3, float xmm4, float xmm5, float xmm6, float xmm7,     //   6            
        float xmmUnknow);

어셈블러 호출
foo2('c', 0, 1, 2, 3, (char*)4, (void**)5, 1.f, (void*)6, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, (float)i);
0x00000000004006c5 <+129>:    cvtsi2ssl -0xc(%rbp),%xmm0
   0x00000000004006ca <+134>:    movsd  0x286(%rip),%xmm1        # 0x400958 <__dso_handle+8>
   0x00000000004006d2 <+142>:    movss  %xmm0,0x10(%rsp)        # ***              
   0x00000000004006d8 <+148>:    movq   $0x6,0x8(%rsp)        # ***  foo   
   0x00000000004006e1 <+157>:    movq   $0x5,(%rsp)        # ***  foo  
   0x00000000004006e9 <+165>:    movss  0x273(%rip),%xmm7        # 0x400964 <__dso_handle+20>
   0x00000000004006f1 <+173>:    movss  0x26f(%rip),%xmm6        # 0x400968 <__dso_handle+24>
   0x00000000004006f9 <+181>:    movss  0x26b(%rip),%xmm5        # 0x40096c <__dso_handle+28>
   0x0000000000400701 <+189>:    movss  0x267(%rip),%xmm4        # 0x400970 <__dso_handle+32>
   0x0000000000400709 <+197>:    movss  0x263(%rip),%xmm3        # 0x400974 <__dso_handle+36>
   0x0000000000400711 <+205>:    movss  0x25f(%rip),%xmm2        # 0x400978 <__dso_handle+40>
0x0000000000400719 <+213>:    movss  0x23f(%rip),%xmm0        # 0x400960 <__dso_handle+16>
   0x0000000000400721 <+221>:    mov    $0x4,%r9d
   0x0000000000400727 <+227>:    mov    $0x3,%r8d
   0x000000000040072d <+233>:    mov    $0x2,%ecx
   0x0000000000400732 <+238>:    mov    $0x1,%edx
   0x0000000000400737 <+243>:    mov    $0x0,%esi
   0x000000000040073c <+248>:    mov    $0x63,%edi
   0x0000000000400741 <+253>:    callq  0x4005f5 <_Z4foo2csilxPcPPvfS0_dfffffff>

비부동 소수점 매개 변수는 각각'c', 0, 1, 2, 3, (char*) 0x4, (void**) 0x5, (void*) 6이다.먼저 6개의 우선순위를 rdi,rsi,rdx,rcx,r8,r9로 순서대로 배열합니다.남은 (void**) 5, (void*) 6.부동 소수점 매개 변수는 각각 1이다.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, (float)i. xmm0-xmm7로 순서대로 배정하고 나머지는 (float)i입니다.마지막으로 두 가지 유형을 레지스터에 넣을 수 없는 나머지 매개 변수는 (void**)5, (void*)6, (float)i로 오른쪽에서 왼쪽으로 순서대로 입고됩니다.
 
마지막으로 나는 이 편을 끝으로 gcc가 임시 대상을 어떻게 전달하는지 특례를 선택했다.
struct point {float x,y;};
struct obj
{
        int i;
        float f[8];
        void foo(point pt)
        {
                f[2] += pt.x;
                f[3] *= pt.y;
        }
};

어셈블러 호출
obj j;
 point pt;
 j.foo(pt);
0x000000000040078d <+329>:    movq   -0x20(%rbp),%xmm0    
   0x0000000000400792 <+334>:    lea    -0x50(%rbp),%rax
   0x0000000000400796 <+338>:    mov    %rax,%rdi
   0x0000000000400799 <+341>:    callq  0x400814 <_ZN3obj3fooE5point>

rdi가 무엇인지 모두가 알고 있습니다. 나머지 매개 변수 캐리어는 xmm0입니다.다시 한 번 함수 정의를 보면 매개 변수는 임시 대상이고 대상 정의를 보면point 구조체는 두 개의 단일 부동점으로 모두 64위를 차지한다.xmm 레지스터는 4개의 단일 부동점 데이터를 저장할 수 있다.다음은 구성원 함수foo의 반집성을 보면 딱 증명된다.
Dump of assembler code for function _ZN3obj3fooE5point:
   0x0000000000400814 <+0>:    push   %rbp
   0x0000000000400815 <+1>:    mov    %rsp,%rbp
   0x0000000000400818 <+4>:    mov    %rdi,-0x8(%rbp)
   0x000000000040081c <+8>:    movq   %xmm0,-0x10(%rbp)    #  64        
   0x0000000000400821 <+13>:    mov    -0x8(%rbp),%rax
   0x0000000000400825 <+17>:    movss  0xc(%rax),%xmm1
   0x000000000040082a <+22>:    movss  -0x10(%rbp),%xmm0    # pt.x
   0x000000000040082f <+27>:    addss  %xmm1,%xmm0
   0x0000000000400833 <+31>:    mov    -0x8(%rbp),%rax
   0x0000000000400837 <+35>:    movss  %xmm0,0xc(%rax)
   0x000000000040083c <+40>:    mov    -0x8(%rbp),%rax
   0x0000000000400840 <+44>:    movss  0x10(%rax),%xmm1
   0x0000000000400845 <+49>:    movss  -0xc(%rbp),%xmm0        # pt.y
   0x000000000040084a <+54>:    mulss  %xmm1,%xmm0
   0x000000000040084e <+58>:    mov    -0x8(%rbp),%rax
   0x0000000000400852 <+62>:    movss  %xmm0,0x10(%rax)
   0x0000000000400857 <+67>:    leaveq 
   0x0000000000400858 <+68>:    retq   
End of assembler dump.

 
지금까지 저는 x64 시스템의 세 가지 상용 플랫폼이 c/c++/objc 프로그래밍에 사용되는 참조 방식을 세 편으로 소개했습니다.전편에서 lldb 디버깅을 통해 맥 플랫폼 아래 x64 전참을 소개한다.중편, windbg 디버깅을 통해 윈도우즈 플랫폼 아래 x64 전참을 소개한다.다음 편은 gdb 디버깅을 통해 gcc(클래스linux) 플랫폼에서 x64 전참을 소개하는데 이 편은 맥,ios에도 적용된다.
 
예고: 뒤에 어셈블리 분석objc 프로그램에 들어갈 것입니다.

좋은 웹페이지 즐겨찾기