programing

C/C++의 서로 다른 호출 규약은 무엇이며 각각의 의미는 무엇입니까?

mailnote 2023. 11. 2. 22:02
반응형

C/C++의 서로 다른 호출 규약은 무엇이며 각각의 의미는 무엇입니까?

C/C++에는 다양한 호출 규약이 있습니다.stdcall,extern,pascal, 등. 이러한 호출 규약은 몇 개이며, 각각의 의미는 무엇입니까?이것들을 설명하는 링크가 있습니까?

간단한 답변:저는 cdecl, stdcall, fastcall을 사용합니다. 저는 패스트콜을 거의 사용하지 않습니다. stdcall은 Windows API 함수를 호출하는 데 사용됩니다.

자세한 답변 (Wikipedia에서 도난):

cdecl - cdecl에서는 서브루틴 인수가 스택에 전달됩니다.정수 값과 메모리 주소는 EAX 레지스터에, 부동 소수점 값은 ST0 x87 레지스터에 반환됩니다.레지스터 EAX, ECX 및 EDX는 호출자 저장되고 나머지는 호출자 저장됩니다.x87 부동 소수점 레지스터 ST0 ~ ST7은 새 함수를 호출할 때 비어 있어야 하며(팝핑 또는 해제), 함수를 종료할 때 ST1 ~ ST7은 비어 있어야 합니다.값을 반환할 때 사용하지 않을 경우 ST0도 비워 두어야 합니다.

syscall - 인수가 오른쪽에서 왼쪽으로 밀린다는 점에서 cdecl과 유사합니다.EAX, ECX 및 EDX는 보존되지 않습니다.매개 변수 목록의 크기는 이중 단어로 AL로 전달됩니다.

pascal - 매개 변수는 왼쪽에서 오른쪽으로 순서대로 스택에 푸시되며(cdecl의 opposite), 호출자는 반환 전에 스택의 밸런싱을 담당합니다.

stdcall - stdcall[4] 호출 규칙은 호출자가 스택 정리를 담당하지만 매개 변수는 _cdecl 호출 규칙에서처럼 오른쪽에서 왼쪽 순서로 스택에 푸시됩니다.레지스터 EAX, ECX, EDX는 기능 내에서 사용할 수 있도록 지정되어 있습니다.반환 값은 EAX 레지스터에 저장됩니다.

fastcall - __fastcall convention(일명 __msfastcall)은 ECX 및 EDX에 맞는 처음 두 개의 인수(왼쪽에서 오른쪽으로 평가됨)를 전달합니다. 나머지 인수는 오른쪽에서 왼쪽으로 스택에 푸시됩니다.

vectorcall - Visual Studio 2013에서 마이크로소프트는 게임, 그래픽, 비디오/오디오, 코덱 개발자들의 효율성 문제에 대응하여 __vectorcall 호출 규약을 도입하였습니다.[7] IA-32 및 x64 코드의 경우 __벡터 호출은 __fastcall 및 원래 x64 호출 규약과 유사하지만 SIMD 레지스터를 사용하여 전달 벡터 인수를 지원하도록 확장합니다.x64의 경우, 처음 6개의 인수 중 하나가 벡터 타입일 때(float, double, __m128, __m256 등), 해당 XMM/YMM 레지스터를 통해 전달됩니다.마찬가지로 IA-32의 경우 위치에 관계없이 벡터 타입 인수에 대해 최대 6개의 XMM/YMM 레지스터가 왼쪽에서 오른쪽으로 순차적으로 할당됩니다.또한 __vectorcall은 동일한 6개의 레지스터를 사용하여 최대 4개의 동일한 벡터 타입으로만 구성된 합성 타입인 HVA(homogeneous vector aggregate) 값 전달을 지원합니다.벡터 타입 인수를 위해 레지스터가 할당되면 사용되지 않은 레지스터는 위치에 관계없이 왼쪽에서 오른쪽으로 HVA 인수에 할당됩니다.결과 벡터 유형 및 HVA 값은 처음 4개의 XMM/YMM 레지스터를 사용하여 반환됩니다.

safecall - n Microsoft Windows의 델파이 및 Free Pascal, safecall 호출 규약은 COM(Component Object Model) 오류 처리를 캡슐화하므로 예외는 호출자에게 유출되지 않고 COM/OLE에서 요구하는 대로 HRESULT 반환 값으로 보고됩니다.델파이 코드에서 안심콜 기능을 호출할 때도 반환된 HRESULT를 자동으로 확인하고 필요시 예외를 제기합니다.

안전 호출 규칙은 예외가 (FS:[0] 대신) HR 결과로서 EAX의 호출자에게 다시 전달되는 반면, 함수 결과는 스택의 참조를 통해 최종 "out" 매개 변수인 것처럼 전달된다는 점을 제외하고는 stdc 호출 규칙과 동일합니다.델파이에서 델파이 기능을 호출할 때, 이 호출 규칙은 다른 호출 규칙과 마찬가지로 나타납니다. 왜냐하면 예외는 EAX에서 다시 전달되지만 호출자에 의해 적절한 예외로 자동으로 다시 변환되기 때문입니다.다른 언어로 작성된 COM 개체를 사용할 경우 HR 결과는 자동으로 예외로 상향되며 Get 함수에 대한 결과는 매개 변수가 아닌 결과에 있습니다.안전한 호출로 델파이에서 COM 객체를 생성할 경우, 예외는 정상적으로 제기될 수 있지만 다른 언어의 HR 결과로 볼 수 있으므로 HR 결과에 대해 걱정할 필요가 없습니다.

Microsoft X64 Calling Convention - Microsoft x64 Calling Convention[12][13]은 Windows 및 사전 부팅 UEFI에서 수행됩니다(x86-64의 롱 모드의 경우).레지스터 RCX, RDX, R8, R9를 처음 4개의 정수 또는 포인터 인수(순으로)에 사용하고, XMM0, XMM1, XMM2, XMM3를 부동 소수점 인수에 사용합니다.추가 인수가 스택(오른쪽에서 왼쪽)에 푸시됩니다.정수 반환 값(x86과 유사)은 64비트 이하인 경우 RAX로 반환됩니다.부동 소수점 반환 값은 XMM0으로 반환됩니다. 64비트 미만의 파라미터는 0으로 확장되지 않으며, 높은 비트는 0으로 확장되지 않습니다.

Windows 컨텍스트에서 x64 아키텍처를 컴파일할 때(Microsoft 툴을 사용하든 비Microsoft 툴을 사용하든 간에), 여기에 설명된 호출 규칙은 하나뿐입니다. 따라서 stdcall, cdecl, fastcall 등이 모두 동일하게 적용됩니다.

Microsoft x64 호출 규칙에서 함수를 호출하기 직전에 스택에 32바이트의 "섀도 공간"을 할당하고 호출 후 스택을 팝업하는 것은 호출자의 책임입니다.그림자 공간은 RCX, RDX, R8 및 R9,[14]를 유출하는 데 사용되지만 파라미터가 4개 미만인 기능도 모든 기능에서 사용할 수 있어야 합니다.

레지스터 RAX, RCX, RDX, R8, R9, R10, R11은 휘발성으로 간주됩니다(호출자 저장).[15]

레지스터 RBX, RBP, RDI, RSI, RSP, R12, R13, R14 및 R15는 비휘발성으로 간주됩니다.[15]

예를 들어, 5개의 정수 인수를 사용하는 함수는 레지스터에서 첫 번째부터 네 번째까지 차지하고, 다섯 번째는 그림자 공간의 맨 위에 푸시됩니다.따라서 호출된 함수가 입력되면 스택은 반환 주소(상승 순서)에 이어 섀도 스페이스(32바이트)에 이어 다섯 번째 매개 변수로 구성됩니다.

x86-64에서 Visual Studio 2008은 XMM6 및 XMM7에 부동 소수점 번호를 저장합니다. 따라서 x86-64의 경우 사용자 작성 어셈블리 언어 루틴이 XMM6 및 XMM7을 유지해야 합니다(XMM6 및 XMM7을 유지할 필요가 없었던 x86과 비교).즉, x86에서 x86-64로 포팅될 때 XMM6 및 XMM7을 함수 이전/후에 저장/복원하기 위해 사용자가 작성한 어셈블리 언어 루틴을 업데이트해야 합니다.

Standard C나 Standard C++ 모두 이러한 개념이 없습니다. 특정 컴파일러, 링커 및/또는 운영 체제의 기능이므로 관심 있는 특정 기술을 실제로 표시해야 합니다.

스탠다드 C++는 기본적으로 다음 두 가지가 있습니다.extern "C"그리고.extern "C++". 후자가 기본이고, 이 전자는 C 코드에 링크해야 할 때 사용됩니다.컴파일러는 "C"와 "C++" 이외의 다른 문자열을 정의할 수 있습니다.예를 들어, 파스칼 형제와 호환되는 컴파일러는 다음과 같이 정의할 수 있습니다.extern "Pascal".

안타깝게도 일부 컴파일러들이 키워드를 대신 발명했습니다.이 경우 컴파일러 설명서를 참조하십시오.

이것들은 콜 스택에 파라미터를 어떤 순서로 넣을 것인지, 그리고 언제 값에 의한 콜 및/또는 참조 시맨틱스에 의한 콜을 사용할 것인지에 관한 것입니다.다국어 프로그래밍을 단순화하기 위한 컴파일러별 확장자입니다.

특정 라이브러리, 특히 Win32 API의 기능을 호출하는 데 필요한 플랫폼별 확장 기능입니다.MSVC의 옵션이 x86의 윈도우에 대한 사실상의 표준이지만, 이들은 비표준적이고 각 컴파일러에 특정적입니다.일반적으로 필요한 라이브러리는 헤더 파일에 이러한 파일을 선언하고 투명하게 작업합니다.그들 사이의 주요 차이점은 C가 역사적으로 어떤 유형이든 다양한 수의 인수를 허용하는 덜 효율적인 규약을 사용한 반면, 윈도우와 대부분의 다른 언어들은 다르게 사용했다는 것입니다.그러나 왼손 또는 오른손으로 밀거나 발신자 또는 호출된 기능을 정리하는 등의 많은 차이가 상당히 자의적이었습니다.

이들은 64비트 코드와 대부분 무관합니다. 호출 규약을 둘러싼 신성한 전쟁은 이러한 플랫폼에서 결코 일어나지 않았습니다.

함수에 이 중 하나를 추가해야 하는 몇 가지 일반적인 경우가 있습니다.다른 언어로 작성된 모듈(그리고 때로는 다른 C++ 컴파일러)과 링크해야 하는 C++ 모듈은extern "C"호환성에 대한 명명 규칙.콜백 함수는 호출자와 동일한 호출 규약을 사용해야 하는데, Windows API의 경우 다음과 같습니다.CALLBACK, 기본값이 아닙니다.공유 라이브러리는 내부적으로 사용하는 것과 다른 호출 규약을 사용하여 기능을 내보내야 하거나 다음을 사용해야 할 수 있습니다.__cdecl기본값이 변경되는 경우 명시적입니다.성능이 향상될 수도 있고 그렇지 않을 수도 있습니다.__fastcall일부 플랫폼에서는: 그것은 대부분 하나 또는 두 개의 매개변수로 짧은 리프 함수의 속도를 높이며, 일부 프로그램을 느리게 만들 수 있습니다.

fastcall이 최적화되어 있지만 아무도 사용하지 않습니다.

언급URL : https://stackoverflow.com/questions/949862/what-are-the-different-calling-conventions-in-c-c-and-what-do-each-mean

반응형