x64에서 4 개의 인수 레지스터 선택 -UN * X / Win64에 공통
x86에 대해 기억해야 할 사항 중 하나는 "reg number"인코딩에 대한 레지스터 이름이 명확하지 않다는 것입니다. 명령어 인코딩 측면에서 ( MOD R / M 바이트, http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm 참조 ) 레지스터 번호 0 ... 7은-순서대로- ?AX
, ?CX
, ?DX
, ?BX
, ?SP
, ?BP
, ?SI
, ?DI
.
따라서 반환 값으로 A / C / D (regs 0..2)를 선택하고 처음 두 인수 ( "고전적인"32 비트 __fastcall
규칙)를 선택하는 것은 논리적 선택입니다. 64 비트로가는 것에 관해서는 "상위"regs가 주문되고 Microsoft와 UN * X / Linux 둘 다 첫 번째로 R8
/ R9
를 사용했습니다.
염두에 유지, 마이크로 소프트의 선택 RAX
(반환 값) 및 RCX
, RDX
, R8
, R9
(인수 [0..3])를 선택하면 이해할 수있는 선택입니다 사 개 인수 레지스터.
AMD64 UN * X ABI가 RDX
이전에 선택한 이유를 모르겠습니다 RCX
.
x64에서 6 개의 인수 레지스터 선택 -UN * X 특정
RISC 아키텍처에서 UN * X는 전통적으로 레지스터에 인수 전달을 수행했습니다. 특히 처음 6 개의 인수 (최소한 PPC, SPARC, MIPS에서 그렇습니다)에 대해. AMD64 (UN * X) ABI 디자이너가 해당 아키텍처에서도 6 개의 레지스터를 사용하기로 선택한 주요 이유 중 하나 일 수 있습니다.
그래서 당신이 원하는 경우 여섯 개 에 인수를 전달하는 레지스터, 그리고 그것을 선택하는 논리이다 RCX
, RDX
, R8
그리고 R9
그들 중 네, 당신은 두 개의 다른 어떤을 선택해야합니까?
"높은"regs는 선택하기 위해 추가 명령어 접두사 바이트가 필요하므로 명령어 크기가 더 커지므로 옵션이있는 경우 선택하고 싶지 않을 것입니다. 때문에에 고전 레지스터의 암시 의 의미 RBP
와 RSP
이 사용할 수 없으며, RBX
전통적으로 겉으로 AMD64 ABI 디자이너가 불필요하게 호환되고 싶지 않았다 UN * X (전역 옵셋 테이블)에 대한 특별 사용이 있습니다.
Ergo, 유일한 선택 은 RSI
/ RDI
.
따라서 RSI
/ RDI
를 인수 레지스터로 가져와야한다면 어떤 인수 여야합니까?
그들을 arg[0]
만들고 arg[1]
몇 가지 장점이 있습니다. cHao의 의견을 참조하십시오.
?SI
그리고 ?DI
문자열 명령어 소스 / 대상 피연산자이며 cHao가 언급했듯이 인수 레지스터로 사용한다는 것은 AMD64 UN * X 호출 규칙에서 가장 간단한 strcpy()
함수가 예를 들어 repz movsb; ret
소스 / 대상 이 두 개의 CPU 명령어로만 구성 된다는 것을 의미합니다. 호출자가 주소를 올바른 레지스터에 넣었습니다. 특히 저수준 및 컴파일러 생성 "접착제"코드에 있습니다 (예를 들어 일부 C ++ 힙 할당자는 생성시 개체를 0으로 채우거나 커널에서 힙 페이지를 0으로 채우는 경우).sbrk()
, 또는 copy-on-write pagefaults) 막대한 양의 블록 복사 / 채우기를 수행하므로 소스 / 대상 주소 인수를로드하는 두 개 또는 세 개의 CPU 명령을 저장하는 데 자주 사용되는 코드에 유용합니다. "올바른"레지스터.
따라서 UN * X와 Win64는 UN * X가 의도적으로 선택한 RSI
/ RDI
레지스터 에서 두 개의 추가 인수 RCX
를 RDX
, R8
및 에서 4 개의 인수를 자연스럽게 선택하는 것에 "앞에 추가"한다는 점에서만 다릅니다 R9
.
그 너머 ...
UN * X와 Windows x64 ABI 사이에는 인수를 특정 레지스터에 매핑하는 것보다 더 많은 차이점이 있습니다. Win64에 대한 개요는 다음을 확인하십시오.
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 및 AMD64 UN * X는 스택 스페이스가 사용되는 방식에서도 현저하게 다릅니다. 예를 들어 Win64에서 호출자 는 인수 0 ... 3이 레지스터에 전달 되더라도 함수 인수에 대한 스택 공간을 할당 해야합니다 . 반면에 UN * X에서 리프 함수 (즉, 다른 함수를 호출하지 않는 함수)는 128 바이트 이하의 스택 스페이스를 할당하는 데 전혀 필요하지 않습니다 (예, 소유하고 사용할 수 있습니다. 할당하지 않고 일정량의 스택 ... 음, 커널 코드가 아니라면 멋진 버그의 원인). 이 모든 것은 특정 최적화 선택이며, 이에 대한 대부분의 이론적 근거는 원본 포스터의 위키피디아 참조가 가리키는 전체 ABI 참조에 설명되어 있습니다.