int function (int a, int b) 을 호출할 때result = function (1,2) 같은 방식으로 이 함수를 사용할 수 있습니다.그러나 고급 언어가 컴퓨터가 식별할 수 있는 기계 코드로 컴파일되었을 때 문제가 하나 드러났다. CPU에서 컴퓨터는 함수 호출에 몇 개, 어떤 파라미터가 필요한지 알 수 없고 하드웨어도 이 파라미터를 저장할 수 없다.즉, 컴퓨터는 이 함수에 어떻게 매개 변수를 전달하는지 모른다. 매개 변수를 전달하는 작업은 반드시 함수 호출자와 함수 자체가 조화를 이루어야 한다.이를 위해 컴퓨터는 인자 전달을 지원하기 위해 창고라고 불리는 데이터 구조를 제공했다.창고는 선진적인 데이터 구조로 창고에 저장 구역과 창고 꼭대기 바늘이 있다.창고 꼭대기 바늘은 창고에서 사용할 수 있는 첫 번째 데이터 항목을 가리킨다.사용자는 창고 위에 있는 방향 창고에 데이터를 추가할 수 있습니다. 이 동작을 창고 압축(Push)이라고 합니다. 창고를 압축한 후에 창고 지붕은 자동으로 데이터 항목이 추가된 위치가 되고 창고 지붕 바늘도 수정됩니다.사용자도 창고에서 창고 꼭대기를 가져갈 수 있는데 팝업 창고(pop)라고 부른다. 창고가 나오면 창고 꼭대기 아래의 요소가 창고 꼭대기로 변하고 창고 꼭대기 바늘이 수정된다.함수 호출을 할 때 호출자는 순서대로 매개 변수를 압축한 다음에 함수를 호출합니다. 함수가 호출된 후에 창고에서 데이터를 얻고 계산합니다.함수 계산이 끝난 후, 또는 호출자, 또는 함수 자체가 창고를 수정하여 창고를 원래의 상태로 복원합니다.매개 변수 전달에서 두 가지 중요한 문제는 반드시 명확하게 설명해야 한다. 매개 변수의 개수가 하나보다 많을 때 어떤 순서에 따라 매개 변수를 창고 함수에 눌러 호출한 후에 누가 창고를 고급 언어에 복원하고 함수 호출 약정을 통해 이 두 가지 문제를 설명한다.흔히 볼 수 있는 호출 약정은 다음과 같다. stdcallcdeclfastcallthiscallnakedcallstdcall 호출 약정 stdcall은 초기에 흔히 볼 수 있는 교수용 컴퓨터 프로그램 설계 언어이기 때문에 문법이 엄격하고 사용하는 함수 호출 약정은 stdcall이다.icrosoft C++ 시리즈의 C/C++ 컴파일러에서는 PASCAL 매크로로 이 호출 약정을 설명하는데, 유사한 매크로는 WINAPI와 CALLBACK도 있다.stdcall 호출 약정 성명의 문법은 (전문의 그 함수를 예로 들면): int__stdcallfunction(inta, intb)stdcall의 호출 약속은 다음과 같다. 1) 파라미터가 오른쪽에서 왼쪽으로 눌러 창고에 들어가고, 2) 함수 자체가 창고를 수정한다. 3) 함수 이름은 자동으로 전도된 밑줄을 붙이고, 뒤에 @ 기호를 따라간다. 그 다음에 파라미터의 사이즈를 따라간다. 상기 함수를 예로 들면 파라미터 b는 먼저 창고에 눌러지고, 그 다음에 파라미터 a,함수 호출function(1,2) 호출처에서 어셈블리 언어로 번역하면push2 두 번째 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자 인자[ebp+8H] 창고에 ebp가 위치를 가리키기 전에 ebp, cs:eip, a, b, ebp+8이 aadd eax를 가리키고, [ebp+0CH] 창고에 ebp+12곳이 bmov esp를 저장하고, ebp가 esppop ebpret 8을 복원하여 컴파일할 때 이 함수의 이름은 _로 번역됨function@8서로 다른 컴파일러가 컴파일의 통용성을 제공하기 위해 자신의 어셈블리 코드를 삽입할 수 있음을 주의하십시오. 그러나 대체적인 코드는 이렇습니다.그 중에서 함수 시작 부분에서esp를 ebp에 보존하고 함수 종료 복구는 컴파일러가 자주 사용하는 방법입니다.함수 호출을 보면 2와 1은 순서대로push에 의해 창고에 들어가고, 함수에서는 ebp(즉 함수에 들어갔을 때의 창고 바늘)에 대한 편이량 접근 매개 변수를 통과한다.함수가 끝난 후,ret8은 8바이트의 창고를 정리하고, 함수는 스스로 창고를 복구했습니다.cdecl 호출 약정 cdecl 호출 약정은 C 호출 약정이라고도 부른다. C 언어의 부족한 호출 약정이다. 그의 정의 문법은 int function(int a, int b)//꾸미지 않으면 C 호출 약정 int__cdeclfunction(inta, intb)///C 호출 약정이 본문을 쓸 때 예상을 벗어났습니다. cdecl 호출 약정의 매개 변수 압축 순서는 stdcall과 같고 매개 변수는 먼저 왼쪽으로 압축되어 창고에 들어가는 것을 발견했습니다.다른 것은 함수 자체가 창고를 정리하지 않고 호출자가 창고를 정리하는 것을 책임진다는 것이다.이러한 변화로 인해 C 호출 약정 허용 함수의 매개 변수의 개수는 고정되지 않고 이것도 C 언어의 큰 특색이다.앞의function 함수에 대해 cdecl를 사용한 후의 인코딩은: 호출처push1push2callfunctionaddesp, 8 주의: 여기 호출자가 복구 창고에서 호출된 함수_function에서push ebp는 ebp 레지스터를 저장합니다. 이 레지스터는 창고의 창고 꼭대기 바늘을 저장하는 데 사용됩니다. 함수가 종료될 때 mov ebp를 복구할 수 있습니다. esp 저장 창고 바늘 mov eax, [ebp + 8H] 창고의 ebp가 가리키는 위치를 순서대로 저장하기 전에 ebp, cs:eip, a, b, b, ebp +8가 가리키는 aadd eax, [ebp + 0CH] 창고 중 ebp + 12곳에 bmov esp를 저장합니다.이 수식은 자동으로 함수 이름 앞에 선도적인 밑줄을 긋기 때문에 함수 이름은 기호표에 _로 기록된다function, 하지만 나는 컴파일할 때 이런 변화를 보지 못한 것 같다.매개 변수는 오른쪽에서 왼쪽 순서에 따라 창고를 누르기 때문에 최초의 매개 변수는 창고 꼭대기에 가장 가까운 위치에 있기 때문에 부정확한 개수 매개 변수를 사용할 때 첫 번째 매개 변수가 창고에 있는 위치를 알 수 있다. 부정확한 매개 변수 개수는 첫 번째 후자의 후속적인 명확한 매개 변수에 따라 확정할 수 있다면 부정확한 매개 변수를 사용할 수 있다. 예를 들어 CRT의sprintf 함수에 대해정의: int sprintf(char* buffer,const char* format,...)모든 부정확한 매개 변수는format을 통해 확정할 수 있기 때문에 부정확한 개수의 매개 변수를 사용하는 것은 문제없다.fastcallfastcall 호출 약정은 stdcall과 유사합니다. 함수의 첫 번째와 두 번째 DWORD 매개 변수(또는 사이즈가 더 작은 것)는 ecx와 edx를 통해 전달되고, 다른 매개 변수는 오른쪽에서 왼쪽으로 순서대로 압축된 함수를 통해 창고 함수 이름 수정 규칙과 stdcall의 성명 문법은 다음과 같습니다. intfastcall function(int a, int b)thiscallthiscall은 명확하게 가리킬 수 없는 유일한 함수 수식입니다.thiscall은 키워드가 아니기 때문이다.이것은 C++ 클래스 구성원 함수의 기본 호출 규칙입니다.구성원 함수 호출에this 바늘이 하나 더 있기 때문에 특수하게 처리해야 합니다.thiscall은 매개 변수가 오른쪽에서 왼쪽으로 창고에 들어가면 매개 변수의 개수가 확정되면this 바늘은ecx를 통해 피호출자에게 전달됩니다.매개 변수의 개수가 확실하지 않으면,this 바늘은 모든 매개 변수가 압축된 후에 압축됩니다.매개 변수의 개수가 정해지지 않은 경우 호출자는 창고를 정리합니다. 그렇지 않으면 함수는 이 호출 약속을 설명하기 위해 다음과 같은 종류와 사용 코드를 정의합니다.
1class A
2{
3public:
4int function1(int a,int b);
5int function2(int a,...);
6};
7int A::function1 (int a,int b)
8{
9return a+b;
10}
11#include
12int A::function2(int a,...)
13{
14 va_list ap;
15 va_start(ap,a);
16int i;
17int result = 0;
18for(i = 0 i < a i ++)
19 {
20 result += va_arg(ap,int);
21 }
22return result;
23}
24void callee()
25{
26 A a;
27 a.function1 (1,2);
28 a.function2(3,1,2,3);
29 }
callee 함수는 어셈블리로 번역된 후://함수 function1 호출 0401C1D push 200401C1F push 100401C21 lea ecx, [ebp-8] 00401C24 call function1 주의, 여기 this가 입고되지 않았습니다//함수 function2 호출 00401C29 push 300401C2B push 200401C2D push 100401C2F push 300401C31 lea eax, [ebp-8] 여기 도입 this 지침 00401C34 push eax 00401C35 call function 200C3A add esp, 14h,매개 변수의 개수가 고정된 경우, 이것은 stdcall과 유사하고, 정해진 시간에 cdeclnakedcall과 유사합니다. 이것은 매우 보기 드문 호출 약속입니다. 일반 프로그래머들은 사용하지 말라고 권장합니다.컴파일러는 이 함수에 초기화와 코드 정리를 추가하지 않습니다. 더 특수한 것은return으로 반환값을 되돌릴 수 없고, 삽입 어셈블리로만 결과를 되돌릴 수 있습니다.이것은 일반적으로 실제 모드 드라이버 설계에 사용되며, 화합을 구하는 덧셈 프로그램을 정의한다고 가정하면:__declspec (naked) int add (int a, int b) {_asm mov eax, a__asm add eax, b__asm ret} 이 함수는 현식 return 반환 값이 없습니다. 반환은 eax 레지스터 수정을 통해 이루어지며, 함수를 종료하는 ret 명령까지도 현식 삽입해야 합니다.위 코드는 어셈블리로 번역된 후:moveax,[ebp+8]addeax,[ebp+12]ret8 이 수식은 __와stdcall 및 cdecl를 결합하여 사용하는 코드입니다. 앞에는 cdecl와 결합하여 사용하는 코드이고, stdcall과 결합된 코드는:__declspec(naked) int __stdcallfunction(inta, intb) {_asm mov eax, a_asm add eax, b_asm ret 8//뒤에 있는 8} 이 함수가 호출되면 일반적인 cdecl 및 stdcall 호출 함수와 일치합니다.함수 호출 약정으로 인한 흔한 문제 정의된 약정과 사용된 약정이 일치하지 않으면 창고가 파괴되어 심각한 문제를 초래할 수 있습니다. 다음은 두 가지 흔한 문제입니다. 함수 원형 성명과 함수체 정의가 일치하지 않는 DLL이 함수를 가져올 때 서로 다른 함수 약정을 성명한 후자의 예를 들어 우리가 dll종에서 함수를 다음과 같이 성명했다고 가정합니다: _declspec(dllexport) int func(int a,int b);//주의, 여기는 stdcall이 없습니다. cdecl 사용 시 코드는 typedef int(*WINAPI DLLFUNC)func(int a, int b)입니다.hLib = LoadLibrary(...);DLLFUNC func = (DLLFUNC)GetProcAddress(...)//호출약정result=func(1,2);//오류가 발생했습니다. 호출자가 WINAPI의 의미를 이해하지 못했기 때문에 이 수식이 추가되었습니다. 상기 코드는 창고가 파괴될 것입니다. MFC가 컴파일할 때 삽입한 checkesp 함수는 창고가 파괴되었다는 것을 알려 줍니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다: