호출 규약

Calling convention

호출 규약(calling convention)은 컴퓨터 과학에서 서브루틴이나 함수가 호출자로부터 매개변수를 받는 방법과 결과를 반환하는 방법에 대한 구현 수준(저수준) 체계입니다.일부 코드가 함수를 호출할 때 해당 함수에 매개 변수가 전달되는 위치와 방법, 해당 함수에서 결과가 반환되는 위치와 방법에 대한 설계 선택이 이루어졌으며, 이러한 전송은 일반적으로 특정 레지스터를 통해 또는 호출 스택스택 프레임 내에서 수행됩니다.기능 호출을 준비하는 작업과 기능이 완료된 후 환경을 복원하는 작업을 호출자와 호출자가 어떻게 나누어 수행하는지에 대한 설계 선택 사항이 있습니다.일부 호출 규칙은 모든 함수를 호출하는 방법을 지정합니다.이러한 기능을 사용하여 전체 프로그램을 정확하고 안정적으로 실행할 수 있도록 모든 기능 호출에 올바른 호출 규칙을 사용해야 합니다.

서론

호출 규약은 일반적으로 ABI(Application Binary Interface)의 일부로 간주됩니다.

관련개념

매개 변수 및 반환 값의 이름 또는 의미는 ABI 및 호출 규약과 관련된 별도의 개념인 API(Application Programming Interface)에 정의됩니다.전달된 구조와 객체 내의 구성원 이름도 ABI가 아닌 API의 일부로 간주됩니다.때때로 API는 함수에 대한 호출 규약을 지정하기 위해 키워드를 포함합니다.

호출 규약은 일반적으로 동적으로 할당된 구조물 및 객체의 수명 처리에 대한 정보를 포함하지 않습니다.호출 규칙은 바이트 순서나 구조 패킹과 같이 구조 및 객체 내의 항목 레이아웃을 지정하지 않습니다.일부 언어의 경우 호출 규칙에 오류 또는 예외 처리에 대한 세부 정보(예: Go, Java)가 포함되어 있고 다른 언어의 경우에는 그렇지 않습니다(예: C++).원격 프로시저 호출의 경우 Marshalling이라는 유사한 개념이 있습니다.호출 규약은 특정 프로그래밍 언어의 평가 전략과 관련이 있을 수 있지만 대부분의 경우 그 일부로 간주되지 않습니다.평가 전략은 일반적으로 더 높은 추상화 수준에서 정의되며 특정 언어의 컴파일러의 낮은 수준의 구현 세부 사항이 아닌 언어의 일부로 간주되기 때문입니다.

서로 다른 호출 규약

호출 규약은 다음과 다를 수 있습니다.

  • 매개 변수가 배치되는 위치.옵션에는 레지스터, 콜 스택, 둘 다의 혼합 또는 다른 메모리 구조가 포함됩니다.
  • 매개 변수가 전달되는 순서입니다.옵션에는 왼쪽에서 오른쪽으로의 순서, 오른쪽에서 왼쪽으로의 순서 또는 더 복잡한 것이 있습니다.
  • 변수 개수의 인수(변수 함수)를 사용하는 함수의 처리 방법.옵션에는 순서대로 전달(첫 번째 매개 변수가 명백한 위치에 있다고 가정)되거나 배열의 변수 부분이 포함됩니다.
  • 반환 값이 호출자로부터 호출자에게 다시 전달되는 방법.옵션에는 스택, 레지스터 또는 힙에 할당된 것에 대한 참조가 포함됩니다.
  • 여러 레지스터, 스택 프레임 내에서 또는 메모리를 참조하여 여러 개의 레지스터를 분할하여 처리하는 길이 또는 복잡한 값입니다.
  • 호출자가 반환될 때 호출자가 호출했을 때와 동일한 값을 갖는 것이 보장되는 레지스터입니다.이 레지스터들은 저장되거나 보존된다고 하므로 휘발성이 없습니다.
  • 함수 호출 후 설정 및 정리 작업이 호출자와 호출자 사이에서 어떻게 구분되는지 여부특히 스택 프레임이 복원되어 호출자가 호출자가 종료된 후에도 계속할 수 있는 방법입니다.
  • 인수를 설명하는 메타데이터의 전달 여부 및 전달 방법
  • 서브루틴이 종료될 때 스택 프레임을 복원하는 데 사용되는 프레임 포인터의 이전 값이 저장됩니다.옵션에는 콜 스택 내에 포함되거나 특정 레지스터에 포함됩니다.
  • 루틴의 비로컬 데이터 액세스를 위한 정적 스코프 링크가 배치된 경우(일반적으로 스택 프레임의 하나 이상의 위치에 있지만 때로는 일반 레지스터 또는 일부 아키텍처의 경우 특수 목적 레지스터에)
  • 객체 지향 언어의 경우 함수의 객체가 참조되는 방식

하나의 플랫폼 내에 있는 호출 규약

때로는 여러 호출 규약이 하나의 플랫폼에 나타나기도 하는데, 주어진 플랫폼과 언어 구현에서 호출 규약을 선택할 수 있습니다.그 이유로는 성능, 다른 인기 언어의 관습에 대한 적응, 다양한 "컴퓨팅 플랫폼"에 의해 부과되는 제한 또는 관습 등이 있습니다.

많은 아키텍처에는 널리 사용되는 하나의 호출 규칙만 있으며, 종종 설계자가 제안합니다.SPARC, MIPS 및 RISC-V를 포함한 RISC의 경우 이 호출 규칙에 기반한 레지스터 이름이 종종 사용됩니다.예를 들어, MIPS 레지스터$4통해.$7"ABI 이름"을 가지고 있습니다.$a0통해.$a3, 표준 호출 규칙에서 매개 변수 전달에 대한 사용을 반영합니다. (RISC CPU에는 동등한 범용 레지스터가 많이 있으므로 일반적으로 숫자 외에 다른 이름을 지정할 하드웨어 이유가 없습니다.)

특정 프로그램 언어의 호출 규약은 기본 플랫폼, OS 또는 링크되는 일부 라이브러리의 호출 규약과 다를 수 있습니다.예를 들어 32비트 Windows에서는 운영 체제 호출에 stdcall 호출 규약이 있는 반면, cdecl 호출 규약을 실행하는 많은 C 프로그램에서는 cdecl 호출 규약을 사용합니다.이러한 호출 규약의 차이를 수용하기 위해 컴파일러는 주어진 함수에 대한 호출 규약을 지정하는 키워드를 허용하는 경우가 많습니다.함수 선언에는 사용할 호출 규약을 나타내는 플랫폼별 키워드가 추가로 포함됩니다.올바르게 처리되면 컴파일러는 적절한 방식으로 함수를 호출할 코드를 생성합니다.

일부 언어에서는 함수에 대한 호출 규약을 해당 함수와 함께 지정할 수 있습니다. 다른 언어에는 일부 호출 규약이 있지만 해당 언어의 사용자로부터 숨겨지므로 일반적으로 프로그래머가 고려하지 않습니다.

건축물

x86 (32비트)

x86 아키텍처의 32비트 버전은 다양한 호출 규약과 함께 사용됩니다.아키텍처 레지스터의 수가 적고 단순성과 작은 코드 크기에 대한 역사적인 초점 때문에 많은 x86 호출 규약이 스택의 인수를 통과합니다.반환 값(또는 반환 값에 대한 포인터)이 레지스터에 반환됩니다.일부 규약에서는 성능을 향상시킬 수 있는 처음 몇 개의 매개 변수에 대해 레지스터를 사용하며, 특히 매우 자주 호출되는 짧고 간단한 리프 루틴(즉, 다른 루틴을 호출하지 않는 루틴)에 대해 성능을 향상시킬 수 있습니다.

통화 예제:

 밀다 EAX            ; 어느 정도의 등록 결과를 내다  밀다 dword [EBP+20] ; 일부 메모리 변수 전달(FASM/TASM 구문)  밀다 3              ; 일정한 거리를 넘기다  불러 계산을 하다           ; 반환된 결과는 현재 EAX에 있습니다. 

일반적인 호출자 구조: (단순한 절차에서 아래 지침의 일부 또는 전부(레트 제외)가 최적화될 수 있음).일부 규약에서는 매개 변수 공간이 할당된 채로 일반을 사용합니다.ret대신에ret imm16. 그 경우에, 전화를 건 사람은add esp,12이 예에서, 그렇지 않으면 ESP로의 변경을 처리합니다.

계산:   밀다 EBP            ; 이전 프레임 포인터 저장   움직이다 EBP,ESP         ; 새 프레임 포인터 가져오기   후보선수 ESP,현지 규모의   ; 현지인을 위해 스택 공간 예약   .   .                   ; 계산 수행, 결과를 EAX에 남깁니다.   .   움직이다 ESP,EBP         ; 현지인을 위한 여유 공간   펑펑 EBP             ; 이전 프레임 포인터 복원   레트 파라마 크기의       ; 여유 파라미터 공간 및 반환. 

x86-64

x86-64, AMD64 및 Intel 64로 알려진 64비트 버전의 x86 아키텍처는 일반적으로 두 가지 호출 순서를 가지고 있습니다.마이크로소프트에 의해 정의된 하나의 호출 시퀀스는 윈도우에서 사용되며, AMD64 System V ABI에 명시된 다른 호출 시퀀스는 유닉스 계열 시스템과 OpenVMS에 의해 사용됩니다. x86-64는 16비트 x86보다 더 많은 범용 레지스터를 가지고 있기 때문에 두 규약 모두 레지스터의 몇 가지 인수를 통과합니다.

ARM (A32)

표준 32비트 ARM 호출 규약은 15개의 범용 레지스터를 다음과 같이 할당합니다.

  • r15: 프로그램 카운터(명령어 세트 사양에 따라).
  • r14: 링크 레지스터.서브루틴 호출에 사용되는 BL 명령어는 반송 주소를 이 레지스터에 저장합니다.
  • r13: 스택 포인터."썸" 작동 모드의 푸시/팝 명령은 이 레지스터만 사용합니다.
  • r12: 절차 내 호출 스크래치 레지스터
  • r4 ~ r11: 지역 변수.
  • r0 ~ r3: 서브루틴에 전달된 인수 값과 서브루틴에서 반환된 결과입니다.

반환되는 값의 유형이 너무 커서 r0 또는 r3에 맞지 않거나 컴파일 시 크기를 정적으로 결정할 수 없는 경우 호출자는 실행 시 해당 값에 대한 공간을 할당하고 r0의 해당 공간에 포인터를 전달해야 합니다.

서브루틴은 r4~r11과 스택 포인터의 내용을 보존해야 합니다(아마도 함수 프롤로그의 스택에 저장한 다음 스크래치 공간으로 사용한 다음 함수 에필로그의 스택에서 복원함).특히, 다른 서브루틴들을 호출하는 서브루틴들은 다른 서브루틴들을 호출하기 전에 리턴 주소를 링크 레지스터 r14에 스택에 저장해야 합니다.그러나 이러한 서브루틴은 해당 값을 r14로 반환할 필요는 없으며, 반환하기 위해 해당 값을 프로그램 카운터인 r15로 로드하기만 하면 됩니다.

ARM 호출 규칙은 완전 하강 스택을 사용하도록 규정합니다.또한 스택 포인터는 항상 4바이트 정렬되어야 하며 공용 인터페이스가 있는 함수 호출 시에는 항상 8바이트 정렬되어야 합니다.[1]

이 호출 규칙은 "일반적인" ARM 서브루틴을 다음과 같이 합니다.

  • 프롤로그에서 r4 또는 r11을 스택에 푸시하고 r14의 리턴 어드레스를 스택에 푸시합니다(이것은 하나의 STM 명령으로 할 수 있습니다);
  • 전달된 인수(r0 ~ r3)를 로컬 스크래치 레지스터(r4 ~ r11)에 복사합니다.
  • 나머지 로컬 스크래치 레지스터에 다른 로컬 변수 할당(r4 ~ r11);
  • 계산을 수행하고 필요에 따라 다른 서브루틴을 BL을 사용하여 호출합니다. r0 ~ r3, r12 및 r14가 보존되지 않는다고 가정합니다.
  • 결과를 r0에 넣습니다.
  • 에필로그에서 스택에서 r4 ~ r11을 당기고 프로그램 카운터 r15로 리턴 주소를 당깁니다.이것은 하나의 LDM 명령으로 수행할 수 있습니다.

ARM (A64)

64비트 ARM(AArch64) 호출 규칙은 31개의 범용 레지스터를 다음과 같이 할당합니다.[2]

  • x31 (SP) : 맥락에 따라 스택 포인터 또는 영 레지스터
  • x30 (LR): 서브루틴에서 복귀할 때 사용하는 프로시저 링크 레지스터.
  • x29 (FP): 프레임 포인터.
  • x19 ~ x28: 캘리 저장.
  • x18 (PR): 플랫폼 레지스터일부 운영 체제별 특수 용도로 사용되거나 추가 발신자가 저장한 레지스터에 사용됩니다.
  • x16(IP0) 및 x17(IP1):절차 내 호출 스크래치 레지스터.
  • x9 ~ x15: 로컬 변수, 발신자 저장
  • x8(XR): 간접반납값 주소
  • x0 ~ x7: 서브루틴에서 전달된 인수 값과 반환된 결과입니다.

x로 시작하는 모든 레지스터에는 w로 시작하는 32비트 레지스터가 있습니다.따라서 32비트 x0을 w0이라고 합니다.

마찬가지로 32개의 부동 소수점 레지스터는 다음과 같이 할당됩니다.[3]

  • v0 ~ v7: 하위 루틴에서 전달된 인수 값과 반환된 결과입니다.
  • v8 ~ v15: calllee- saved이지만 하위 64비트만 보존하면 됩니다.
  • v16 ~ v31: 로컬 변수, 발신자 저장

POWER, PowerPC, Power ISA

POWER, PowerPCPower ISA 아키텍처에는 많은 레지스터가 있으므로 대부분의 함수는 단일 레벨 호출을 위한 레지스터의 모든 인수를 전달할 수 있습니다.추가 인수는 스택에 전달되며 레지스터 기반 인수를 위한 공간도 멀티 레벨 호출이 사용되고 레지스터를 저장해야 할 경우 호출된 함수에 대한 편의로 스택에 항상 할당됩니다.이것은 또한 다음과 같은 다양한 함수에 사용됩니다.printf(), 함수의 인수를 배열로 액세스해야 하는 경우.모든 절차 언어에 대해 단일 호출 규약이 사용됩니다.

분기 및 링크 명령어는 반송 주소를 범용 레지스터와 별도의 특수 링크 레지스터에 저장합니다. 루틴은 링크 레지스터를 대상 주소로 사용하는 분기 명령어와 함께 호출자에게 반환됩니다.리프 루틴은 링크 레지스터를 저장하거나 복원할 필요가 없습니다. 리프가 아닌 루틴은 다른 루틴으로 호출하기 전에 반환 주소를 저장하고 반환 주소를 복원해야 합니다. 특수 목적 레지스터에서 이동 명령을 사용하여 링크 레지스터를 범용 레지스터로 이동한 다음 필요한 경우 다음에 저장합니다.스택 및 스택에 저장된 경우 저장된 링크 레지스터 값을 범용 레지스터에 로드한 다음 Move To Special Purpose Register 명령을 사용하여 저장된 링크 레지스터 값을 포함하는 레지스터를 링크 레지스터로 이동하여 복원하는 것을 특징으로 하는 방법.

MIPS

O32ABI는[4] MIPS용의 원래 시스템 V ABI라는 지위 때문에 가장 일반적으로 사용되는 ABI입니다.[5]이것은 엄격하게 스택 기반이며 레지스터는 4개의 레지스터만 있습니다.$a0-$a3인수를 전달할 수 있습니다.16개의 레지스터만 있는 고풍스러운 부동 소수점 모델과 함께 이러한 지각된 느림은 다른 많은 호출 규약의 확산을 부추겼습니다.ABI는 1990년에 구체화되었고 1994년 이후로 한 번도 업데이트되지 않았습니다.32비트 MIPS에 대해서만 정의되지만 GCC는 O64라는 64비트 변형을 만들었습니다.[6]

64비트의 경우 실리콘 그래픽스의 N64 ABI(Nintendo 64와는 무관)가 가장 일반적으로 사용됩니다.가장 중요한 개선점은 인수 통과를 위해 8개의 레지스터를 사용할 수 있다는 것입니다. 또한 부동 소수점 레지스터의 수를 32개로 늘립니다.x32 ABI와 유사하게 작은 코드에 32비트 포인터를 사용하는 N32라는 ILP32 버전도 있습니다.둘 다 CPU의 64비트 모드에서 실행됩니다.[6]

O32를 N32와 더 유사한 32비트 ABI로 대체하려는 몇 가지 시도가 있었습니다.1995년에 열린 컨퍼런스에서 MIPS EABI가 떠올랐는데, 32비트 버전이 상당히 비슷했습니다.[7]EABI는 MIPS Technologies가 반환 값을 위해 인수 레지스터를 추가로 재사용하는 보다 근본적인 "NUBI" ABI를 제안하도록 영감을 주었습니다.[8]MIPS EABI는 GCC에서 지원하지만 LLVM은 지원하지 않으며 NUBI도 지원하지 않습니다.

O32 및 N32/N64 모두에 대해 반환 주소는 a에 저장됩니다.$ra등록하세요.를 사용하여 자동으로 설정됩니다.JAL(jump 및 링크) 또는JALR(jump 및 링크 레지스터) 지침.스택이 아래쪽으로 늘어납니다.

SPARC

SPARC 아키텍처는 대부분의 RISC 아키텍처와 달리 레지스터 윈도우에 구축되어 있습니다.각 레지스터 창에는 24개의 액세스 가능한 레지스터가 있습니다. 8개는 "인" 레지스터(%i0-%i7), 8개는 "로컬" 레지스터(%l0-%l7), 8개는 "아웃" 레지스터(%o0-%o7)입니다."in" 레지스터는 호출되는 함수에 인수를 전달하는 데 사용되며, 추가 인수는 스택에 푸시해야 합니다.그러나 공간은 항상 잠재적 레지스터 윈도우 오버플로, 로컬 변수 및 (32비트 SPARC에서) 구조물을 값별로 반환하기 위해 호출된 함수에 의해 할당됩니다.함수를 호출하려면 함수를 호출할 인수를 "out" 레지스터에 배치합니다. 함수가 호출되면 "out" 레지스터가 "in" 레지스터가 되고 호출된 함수는 "in" 레지스터의 인수에 액세스합니다.호출된 함수가 완료되면 반환 값이 첫 번째 "in" 레지스터에 배치되며, 이 레지스터는 호출된 함수가 반환될 때 첫 번째 "out" 레지스터가 됩니다.

대부분의 최신 유닉스 계열 시스템이 [9]따르는 System V ABI는 %i0 ~ %i5 레지스터에서 처음 6개의 인수를 통과시켜 프레임 포인터에 %i6, 반환 주소에 %i7을 예약합니다.

IBM System/360 및 그 후속 제품

IBM System/360은 하드웨어 스택이 없는 또 다른 아키텍처입니다.아래의 예는 64비트 z/아키텍처를 도입하기 에 OS/360과 그 후속 프로그램에서 사용한 호출 규약을 보여줍니다. 시스템/360의 다른 운영 체제는 다른 호출 규약을 가질 수 있습니다.

통화 프로그램:

LA 1,ARGS Load 인수 목록 주소 L 15,=A(SUB) 호출된 루틴으로 서브루틴 주소 BALR 14,15 분기 로드...ARGS DCA(FIRST) 첫 번째 인수 DCA(Second)의 주소...DCA(THRD)+X'80000000' 마지막 인수2

호출된 프로그램:

SUB EQU * 서브프로그램의 진입점입니다.

표준 진입 순서:

*,153 STM 14,12,12(13) Save registers4 ST 13,SAVE+4 Save caller's save address LA 12,SAVE Chain save area ST 12,8(13) LR 13,12 ...

표준 반송 순서:

L 13,SAVE+45 LM 14,12,12(13) L 15,RETVAL6 BR 14 발신자 복귀 SAVE DS 18F 저장 영역7

주의:

  1. BALR명령어는 첫 번째 인수(register 14)에 의해 지정된 레지스터에 다음 명령어의 주소(반환 주소)를 저장하고 레지스터 15의 두 번째 인수 주소로 분기합니다.
  2. 호출자는 레지스터 1에 있는 인수 주소 목록의 주소를 전달합니다.마지막 주소에는 목록의 끝을 나타내는 상위 비트가 설정되어 있습니다.따라서 이 규칙을 사용하는 프로그램은 31비트 주소 지정으로 제한됩니다.
  3. 호출된 루틴의 주소는 레지스터 15에 있습니다.일반적으로 이것은 다른 레지스터에 로드되며 레지스터 15는 기본 레지스터로 사용되지 않습니다.
  4. STM명령어는 레지스터 13이 가리키는 저장 영역이라고 불리는 호출자에 의해 제공되는 72바이트 영역에 레지스터 14, 15, 그리고 0부터 12까지 저장합니다.호출된 루틴은 호출된 서브루틴에서 사용할 수 있는 고유한 저장 영역을 제공합니다. 이 영역의 주소는 루틴 전체에 걸쳐 보통 레지스터 13에 유지됩니다.다음 지시사항STM이 저장 영역을 발신자의 저장 영역에 연결하는 순방향 및 역방향 체인 업데이트.
  5. 반환 순서는 발신자의 레지스터를 복원합니다.
  6. 레지스터 15는 일반적으로 반환 값을 전달하는 데 사용됩니다.
  7. 선언하기savearea호출된 루틴에서 정적으로 재진입하지 않고 recursive하지 않습니다. 재진입 프로그램은 동적을 사용합니다.savearea, 운영 체제에서 획득하여 반환할 때 자유로워지거나 호출 프로그램에 의해 전달되는 저장소에 저장됩니다.

Linux에서 사용되는 System[10]/390 ABI와 z/Architecture ABI에서:[11]

  • 레지스터 0과 레지스터 1은 휘발성입니다.
  • 레지스터 2 및 레지스터 3은 파라미터 전달 및 반환 값에 사용됩니다.
  • 레지스터 4 및 레지스터 5는 파라미터 전달에도 사용됩니다.
  • 레지스터 6은 파라미터 전달에 사용되며, 호출자가 저장하고 복원해야 합니다.
  • 레지스터 7~13은 호출자가 사용하기 위한 것이며, 호출자가 저장하고 복원해야 합니다.
  • 반송 주소는 레지스터 14가 사용됩니다.
  • 레지스터 15가 스택 포인터로 사용됩니다.
  • 부동 소수점 레지스터 0과 2는 매개 변수 전달 및 반환 값에 사용됩니다.
  • 부동 소수점 레지스터 4와 6은 호출자가 사용하기 위한 것이며 호출자가 저장하고 복원해야 합니다.
  • z/Architecture에서 부동 소수점 레지스터 1, 3, 5, 7~15는 호출자가 사용하기 위한 것입니다.
  • 액세스 레지스터 0은(는) 시스템용으로 예약되어 있습니다.
  • 발신자가 액세스 레지스터 1~15를 사용할 수 있습니다.

추가 인수가 스택에 전달됩니다.

슈퍼에이치

등록하세요 윈도우 CE 5.0 gcc 르네사스
R0 값을 반환합니다.어셈블리 유사 명령을 확장하기 위한 임시.8/16비트 작업을 위한 암시적 소스/대상.보존되지 않았습니다. 반환 값, 발신자 저장 변수/임시.보장되지 않음
R1..R3 임시 레지스터 역할을 합니다.보존되지 않았습니다. 호출자가 스크래치를 저장했습니다.구조 주소(호출자 저장, 기본값) 변수/임시.보장되지 않음
R4..R7 정수 인수의 처음 네 단어.인수 빌드 영역은 R4 ~ R7 홀딩 인수가 유출될 수 있는 공간을 제공합니다.보존되지 않았습니다. 파라미터 전달, 발신자 저장 논쟁들.장담할 수 없습니다.
R8..R13 영구 레지스터 역할을 합니다.보존. 콜리 세이브즈 변수/임시.보장된.
R14 기본 프레임 포인터. (R8-R13은 프레임 포인터, 리프 루틴은 R1-R3을 프레임 포인터로 사용할 수 있습니다.)보존. 프레임 포인터, FP, 호출 저장 변수/임시.보장된.
R15 스택 포인터 또는 영구 레지스터 역할을 합니다.보존. 스택 포인터, SP, 호출 저장 스택 포인터.보장된.

참고: "보존된" 적립금은 저축을 호출하기 위해 사용되며, "보장된" 적립금도 마찬가지입니다.

68k

모토로라 68000 시리즈의 가장 일반적인 호출 규약은 다음과 같습니다.[12][13][14][15]

  • d0, d1, a0 및 a1은 스크래치 레지스터입니다.
  • 다른 레지스터는 모두 호출기에 저장됩니다.
  • a6는 컴파일러 옵션에 의해 비활성화될 수 있는 프레임 포인터입니다.
  • 매개 변수가 오른쪽에서 왼쪽으로 스택에 푸시됩니다.
  • 반환값은 d0에 저장됩니다.

IBM 1130

IBM 1130은 16비트 워드 어드레싱이 가능한 작은 기계였습니다.그것은 단지 6개의 레지스터와 조건 표시기만 있었고, 스택은 없었습니다.레지스터는 IAR(Instruction Address Register), ACC(Accumulator), EXT(Accumulator Extension) 및 3개의 인덱스 레지스터 X1-X3입니다.호출 프로그램은 ACC, EXT, X1, X2를 저장하는 역할을 합니다.[16]서브루틴을 호출하기 위한 두가지 유사 연산이 있습니다.CALL메인 프로그램과 직접 연결된 reloc할 수 없는 서브루틴을 코딩합니다.LIBF재배치 가능한 라이브러리 서브루틴을 전송 벡터를 통해 호출합니다.[17]두 의사-ops 모두 분기저장소 IAR()로 확인)BSI) 다음 명령어의 주소를 유효 주소(EA)에 저장하고 EA+1로 분기하는 기계어 명령어.

논쟁은 다음을 따릅니다.BSI—일반적으로 인수의 한 단어 주소입니다. 호출된 루틴은 반환 시 인수를 건너뛸 수 있도록 예상되는 인수의 수를 알아야 합니다.또는 레지스터에서 인수를 전달할 수도 있습니다.함수 루틴은 실수 인수에 대한 ACC 또는 실수 유사 누적기(FAC)라고 하는 메모리 위치에서 결과를 반환했습니다.서브루틴의 첫번째 위치에 저장된 IAR 값에 대한 오프셋을 사용하여 인수 및 반환 주소를 처리했습니다.

*                  1130 서브루틴 예제 ENT SUB "SUB"를 외부 진입점 SUB DC 0 Reserved word 진입점에서 기존에 코딩된 "DC *-*" * 서브루틴 코드는 여기서 시작합니다 * 반환 주소 LDX I 1 SUB Load X1에서 첫 번째 인수의 주소로 간접적으로 주소를 로드할 수 있다는 주장이 있는 경우...*                   반환 시퀀스 LD RES 정수를 ACC로 로드합니다 * 인수가 제공되지 않은 경우 저장된 반환 주소 BI SUB 인수가 제공되지 않은 경우 END SUB로 간접 분기합니다.

IBM 1130, CDC 6600PDP-8(세 대의 컴퓨터 모두 1965년에 도입됨)의 서브루틴은 서브루틴의 첫 번째 위치에 반환 주소를 저장합니다.[18]

머신 아키텍처 외부의 호출 규약

나사산 코드

스레드 코드는 호출된 코드에 대한 기능 호출 후 설정 및 정리에 대한 모든 책임을 부여합니다.호출 코드는 호출할 서브루틴 목록만 표시합니다.이렇게 하면 모든 기능 설정 및 정리 코드가 함수를 호출하는 여러 곳이 아니라 한 곳(함수의 프롤로그 및 에필로그)에 놓이게 됩니다.이것은 스레드 코드를 가장 콤팩트한 호출 규약으로 만듭니다.

스레드 코드가 스택의 모든 인수를 통과합니다.모든 반환 값은 스택에서 반환됩니다.이로 인해 레지스터에 더 많은 값을 유지하는 호출 규칙보다 기본 구현 속도가 느려집니다.그러나 레지스터의 여러 최상위 스택 값, 특히 반환 주소를 캐시하는 스레드 코드 구현은 항상 반환 주소를 스택에 푸시하고 팝업하는 서브루틴 호출 규약보다 일반적으로 빠릅니다.[19][20][21]

PL/I

PL/I 언어로 작성된 프로그램의 기본 호출 규칙은 모든 인수를 참조로 전달하지만, 다른 규칙은 선택적으로 지정될 수 있습니다.인수는 컴파일러와 플랫폼마다 다르게 처리되지만 일반적으로 인수 주소는 메모리의 인수 목록을 통해 전달됩니다.숨겨진 최종 주소는 반환 값을 포함하는 영역을 가리킬 수 있습니다.PL/I에서 지원하는 다양한 데이터 유형 때문에 데이터 디스크립터는 예를 들어 문자 또는 비트 문자열의 길이, 배열(도프 벡터)의 치수 및 경계, 또는 데이터 구조의 레이아웃 및 내용을 정의하기 위해 전달될 수도 있습니다.더미 인수는 상수이거나 호출된 프로시저가 예상하는 인수 유형과 일치하지 않는 인수에 대해 생성됩니다.

참고 항목

참고문헌

  1. ^ "Procedure Call Standard for the ARM Architecture". 2021.
  2. ^ "Parameters in general-purpose registers". ARM Cortex-A Series Programmer’s Guide for ARMv8-A. Retrieved 12 November 2020.
  3. ^ "Parameters in NEON and floating-point registers". developer.arm.com. Retrieved 13 November 2020.
  4. ^ "MIPS32 Instruction Set Quick Reference".
  5. ^ Sweetman, Dominic. See MIPS Run (2 ed.). Morgan Kaufmann Publishers. ISBN 0-12088-421-6.
  6. ^ a b "MIPS ABI History".
  7. ^ Christopher, Eric (11 June 2003). "mips eabi documentation". binutils@sources.redhat.com (Mailing list). Retrieved 19 June 2020.
  8. ^ "NUBI".
  9. ^ System V Application Binary Interface SPARC Processor Supplement (3 ed.).
  10. ^ "S/390 ELF Application Binary Interface Supplement".
  11. ^ "zSeries ELF Application Binary Interface Supplement".
  12. ^ Smith, Dr. Mike. "SHARC (21k) and 68k Register Comparison".
  13. ^ XGCC: The Gnu C/C++ Language System for Embedded Development (PDF). Embedded Support Tools Corporation. 2000. p. 59.
  14. ^ "COLDFIRE/68K: ThreadX for the Freescale ColdFire Family". Archived from the original on 2015-10-02.
  15. ^ Moshovos, Andreas. "Subroutines Continued: Passing Arguments, Returning Values and Allocating Local Variables". all registers except d0, d1, a0, a1 and a7 should be preserved across a call.
  16. ^ IBM Corporation (1967). IBM 1130 Disk Monitor System, Version 2 System Introduction (C26-3709-0) (PDF). p. 67. Retrieved 21 December 2014.
  17. ^ IBM Corporation (1968). IBM 1130 Assembler Language (C26-5927-4) (PDF). pp. 24–25.
  18. ^ Smotherman, Mark (2004). "Subroutine and procedure call support: Early history".
  19. ^ Rodriguez, Brad. "Moving Forth, Part 1: Design Decisions in the Forth Kernel". On the 6809 or Zilog Super8, DTC is faster than STC.
  20. ^ Ertl, Anton. "Speed of various interpreter dispatch techniques".
  21. ^ Zaleski, Mathew (2008). "Chapter 4: Design and Implementation of Efficient Interpretation". YETI: a graduallY Extensible Trace Interpreter. Although direct-threaded interpreters are known to have poor branch prediction properties... the latency of a call and return may be greater than an indirect jump.

외부 링크