Windows 64가 x86-64의 다른 OS와 다른 호출 규칙을 사용하는 이유는 무엇입니까?
AMD에는 x86-64에서 사용하는 호출 규칙을 설명하는 ABI 사양이 있습니다.자체 x86-64 호출 규칙을 가진 Windows를 제외하고 모든 OS가 이 규칙을 따릅니다. 왜일까요?
이 차이에 대한 기술적, 역사적 또는 정치적 이유를 아는 사람이 있는가? 아니면 순전히 NIHsyndrome의 문제인가?
대한 수 하지만, 를 들어 가 OS인 이유는.rcx - rdx - r8 - r9 - rest on stack
은 다 쓰는 rdi - rsi - rdx - rcx - r8 - r9 - rest on stack
추신: 이러한 호출 규칙이 일반적으로 어떻게 다른지 알고 있으며, 필요한 경우 세부 정보를 어디서 찾아야 하는지 알고 있습니다.내가 알고 싶은 건 그 이유야
편집: 방법은 위키피디아 항목 및 링크 등을 참조하십시오.
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개의 32bit )에 A/C/D(regs 0)의 설정.__fastcall
컨벤션)은 논리적인 선택입니다., 「 와 의 양쪽 64비트, Microsoft 의 UN*X/Linux 의 양쪽 모두를 으로 하고 .R8
R9
첫 번째로.
유의하여 마이크로소프트가한 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」RAX
(반환값)RCX
,RDX
,R8
,R9
(크기[0]3 ] )는 인수에 4개의 레지스터를 선택할 경우 이해할 수 있는 선택입니다.
가 AMD64 UN*X ABI를 선택한 알 수 . »RDX
전에RCX
.
x64에서 6개의 인수 레지스터 선택 - UN*X 고유
UN*X는 RISC 아키텍처에서는 지금까지 레지스터에 인수를 전달해 왔습니다.구체적으로는 첫 번째 6개의 인수(적어도 PPC, SPARC, MIPS)에 대해서입니다.이것이 AMD64(UN*X) ABI 설계자가 아키텍처에 6개의 레지스터를 사용하는 주요 이유 중 하나입니다.
따라서 6개의 레지스터가 인수를 전달하고 싶다면 다음 중 하나를 선택하는 것이 논리적입니다.RCX
,RDX
,R8
★★★★★★★★★★★★★★★★★」R9
중 2개는 어떤 요?
"높은" 규칙은 명령 접두사 바이트를 추가로 선택해야 하므로 명령 크기 풋프린트가 더 크기 때문에 옵션이 있는 경우 이 중 하나를 선택하지 않습니다.의 암묵적인 의미 때문에 고전 레지스터의RBP
★★★★★★★★★★★★★★★★★」RSP
안 되고, 건 안 되고요.RBX
AMD64 ABI 설계자는 불필요하게 호환성을 잃고 싶지 않았던 것 같은 UN*X(글로벌 오프셋 테이블)에 특별한 용도를 가지고 있습니다.
에르고, 유일한 선택은RSI
RDI
.
꼭 RSI
RDI
인수가 등록되면 어떤 인수가 되어야 합니까?
을 만들다arg[0]
★★★★★★★★★★★★★★★★★」arg[1]
몇 가지 장점이 있습니다.cHao 글 c c 。
?SI
★★★★★★★★★★★★★★★★★」?DI
는 문자열 source설명한 바와 같이 규약에서는 한 가장 한 문자열 "source/destination 오퍼랜드"를 합니다.cHao에서 설명한 바와 같이 인수 레지스터로 사용하는 것은 AMD64 UN*X 호출 규약에서는 가능한 한 간단한 명령어 source/destination operands입니다.strcpy()
이 은 2개의 명령으로 .repz movsb; ret
발신자/타깃 주소가 발신자에 의해 올바른 레지스터에 입력되어 있기 때문입니다. 및 에 의해 생성된 를 들어 일부 할당자가 구축 경우나 제로 "글루"가 있습니다.sbrk()
대량의 블록 카피/필을 사용하기 때문에, 이러한 소스/타깃 주소 인수를 「올바른」레지스터에 로드하는 2~3개의 CPU 명령을 보존하기 위해서 자주 사용되는 코드에 도움이 됩니다.
UNX】[] [UN*X]에서두 개의 추가 인수를 점에서 입니다.RSI
/RDI
,됩니다.RCX
,RDX
,R8
★★★★★★★★★★★★★★★★★」R9
.
그 이상은...
UN*X와 Windows x64 ABI 사이에는 특정 레지스터에 대한 인수 매핑보다 더 많은 차이가 있습니다.Win64 의 개요에 대해서는, 다음을 확인해 주세요.
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64와 AMD64 UN*X는 스택스페이스의 사용방법도 현저하게 다릅니다.예를 들어 Win64에서는 arg 0...3이 레지스터로 전달되어도 호출자는 함수 인수에 스택스페이스를 할당해야 합니다.한편 UN*X에서는 리프 함수(다른 함수를 호출하지 않는 함수)는 스택스페이스를 128바이트 이하로 할당할 필요가 없습니다(예, 할당하지 않고 일정량의 스택을 소유하여 사용할 수 있습니다). 단, 커널 코드가 아닌 한 nifty 버그의 원인이 됩니다.이 모든 것은 특정 최적화 선택이며, 그 근거의 대부분은 원본 포스터의 위키피디아 참조가 가리키는 전체 ABI 참조에 설명되어 있다.
IDK Windows가 이 작업을 수행하는 이유.추측은 이 답변의 끝을 참조하십시오.SysV 호출 규약이 어떻게 결정되었는지 궁금해서 메일링 리스트 아카이브에 들어가 보니 깔끔한 것이 있었습니다.
AMD 64 메일링 리스트의 오래된 스레드 중 일부를 읽어보면 재미있습니다.AMD의 아키텍트가 액티브하게 대응하고 있기 때문입니다.레지스터 이름을 선택하는 것은 어려운 부분 중 하나였습니다: AMD는 원래 8개의 레지스터 r0-r7의 이름을 바꾸거나 새로운 레지스터를 호출하는 것을 고려했습니다.
또, 커널 개발로부터의 피드백에 의해서, 원래의 설계를 사용할 수 없게 한 것이 특정되었습니다.이것이 AMD가 실제 칩을 출시하기 전에 명령어를 업데이트한 방법입니다.2000년 후반에는 인텔이 AMD64를 채택하지 않을 것이라는 가정도 흥미로웠습니다.
SysV(Linux) 호출 규약과 발신자 보존과 발신자 보존의 레지스터 수에 대한 결정은 2000년 11월 Jan Hubicka(gcc 개발자)에 의해 처음 이루어졌다.SPEC2000을 컴파일하여 코드 사이즈와 명령의 수를 조사했습니다.이러한 논의의 흐름은 SO 질문에 대한 답변 및 코멘트와 같은 아이디어의 일부를 중심으로 전개됩니다.두 번째 스레드에서 그는 현재 시퀀스를 최적이며 희망적으로 최종적인 것으로 제안했으며, 일부 대안보다 작은 코드를 생성했습니다.
그는 "글로벌"이라는 용어를 콜프리저브드 레지스터를 의미하며, 사용할 경우 푸시/팝해야 합니다.
의 rdi
,rsi
,rdx
는 다음과 같은.
- 을, 「」를하는 함수는 다음과 같습니다.
memset
arg 、 C )) ( gcc ) rep ( gcc ) 。 rbx
는, (「」, 「2」, 「」) 없이 한 2개의 콜 프리저브 (「REX」, 「」)가 있기 에, 콜 프리저브 .rbx
★★★★★★★★★★★★★★★★★」rbp
는 승리입니다.Rep 출력/disputs는 모든합니다."(rep string, shift count, mul/div 출multiple / 은multiplemultiple multiplemultiple 른multiple 른른 른 ( 른 ( 른 ( 른 ( 른 ( 른 ( 른 ( ( ( ( (- 일반적인 명령으로 강제로 사용하는 레지스터는 모두 콜프리저브되어 있지 않기 때문에(앞의 포인트 참조), 변수 카운트 시프트 또는 분할을 사용하는 함수는 함수 arg를 다른 곳으로 이동해야 하지만 호출자의 값을 저장하거나 복원할 필요는 없습니다.
cmpxchg16b
★★★★★★★★★★★★★★★★★」cpuid
RBX는 RBX를 사용합니다cmpxchg16b
AMD64는 원래 제품이 아니었지만 RBX는 여전히 확실한 선택이었을 것입니다.cmpxchg8b
에 의해 되었습니다.cmpxchg
) -
RCX는 EAX와 같은 특수한 용도로 일반적으로 사용되는 레지스터이기 때문에 시퀀스에서 누락되는 것은 같은 목적이 있기 때문에 시퀀스 초기에 회피하려고 합니다.또한 syscall에는 사용할 수 없으며 syscall 시퀀스를 함수 호출 시퀀스와 최대한 일치시키고 싶습니다.
(배경:syscall
sysret
수 없이 파괴하다rcx
함께)rip
및 )의 개요r11
함께)RFLAGS
알 수 rcx
때syscall
을(를) 실행하다.
는 ABI되었습니다.단, ABI는 ABI의 는 ABI입니다.r10
rcx
libc 래퍼의 기능은 다음과 같습니다.mmap(2)
수 있다mov %rcx, %r10
mov $0x9, %eax
syscall
.
i386 Linux에서 사용되는SysV 호출 규약은 Window의 32비트 __vectorcall에 비해 형편없다는 점에 유의하십시오.스택 상의 모든 것을 통과시키고 작은 구조체가 아닌 int64에만 반환됩니다.그것과의 호환성을 유지하기 위해 약간의 노력을 기울인 것은 놀랄 일이 아니다.안 될 이유가 없을 때, 그들은 그것을 지키기 위해rbx
원래의 8에 다른 것을 가지는 것(REX 프리픽스가 필요 없음)이 좋다고 판단했기 때문에, 콜프리저브드(call-preserved)로 되어 있습니다.
ABI를 최적화하는 것은 다른 어떤 고려사항보다 장기적으로 훨씬 더 중요하다.나는 그들이 꽤 잘했다고 생각한다.다른 규칙에 있는 다른 필드 대신 레지스터에 채워진 구조물을 반환하는 것에 대해 확신이 서지 않습니다.실제 현장에서 작업하지 않고 가치별로 코드를 전달하는 것이 이 방법으로 성공하지만, 포장을 푸는 추가 작업은 어리석게 느껴집니다.그들은 더 많은 정수 리턴 레지스터를 가지고 있을 수 있었다rdx:rax
4개의 멤버를 가진 구조체를 반환하면 rdi, rsi, rdx, rax 등으로 반환할 수 있습니다.
SSE2는 정수에 대해 작동할 수 있기 때문에 벡터 규칙에서 정수를 통과하는 것을 고려했습니다.다행히 그들은 그렇게 하지 않았다.정수는 포인터 오프셋으로 자주 사용되며 스택메모리로의 왕복은 매우 저렴합니다.또한 SSE2 명령어는 정수 명령어보다 코드바이트가 더 많이 소요됩니다.
는, 를 1 1 개로 할 나, 2 ABI 를 할 수 있는 , 비트와 으로 억제하는 로 하고 .이것은, asm을 1대씩 포토 할 필요가 있는 유저에게 있어서, 또는 몇개의 asm을 사용할 수 있는 유저의 이익을 위해서입니다.#ifdef
같은 소스라도 32비트 또는 64비트 버전의 함수를 쉽게 구축할 수 있도록 합니다.
툴 체인의 변경을 최소화하는 것은 어려울 것 같습니다.x86-64 컴파일러에는 어떤 레지스터가 무엇에 사용되는지, 호출 규약이 무엇인지에 대한 별도의 테이블이 필요합니다.32비트와의 오버랩이 적다고 해서 툴 체인 코드 크기/복잡도가 크게 줄어들지는 않습니다.
(Matthew Kerner와 Neil Padgett이 쓴 "현대 64비트 컴퓨팅의 역사"에 나오는) 마이크로소프트는 IA64 아키텍처에 관해 인텔과 강력한 파트너였기 때문에 초기 AMD64에 대해 공식적으로 언급하지 않았습니다.이것은, 유닉스와 Windows의 양쪽 모두를 사용하기 위해서, GCC 엔지니어와 함께 ABI로 작업하는 것에 대해서 오픈을 하고 있었다고 해도, 아직 공식적으로 서포트하지 않았던 AMD64의 대처에 대해서는 공개적으로 서포트하는 것을 의미하고, 인텔을 화나게 했을 가능성이 있다고 생각합니다.
게다가 그 당시 마이크로소프트는 오픈 소스 프로젝트에 우호적인 경향이 전혀 없었습니다.Linux나 GCC는 절대 아닙니다.
그럼 왜 ABI에 협조했을까요?나는 ABI가 단지 거의 동시에 그리고 격리된 상태에서 설계되었기 때문에 다르다고 추측한다.
「현대 64비트 컴퓨팅의 역사」의 또 다른 인용구는 다음과 같습니다.
Microsoft의 공동작업과 병행하여 AMD는 오픈 소스 커뮤니티에도 관여하여 칩을 준비했습니다.AMD는 도구 체인 작업에 대해 Code Warcery 및 SuSE와 계약을 체결했습니다(Red Hat은 이미 IA64 도구 체인 포트에서 인텔과 계약을 체결했습니다).러셀은 SuSE가 C와 FORTRAN 컴파일러를, 코드 주술이 파스칼 컴파일러를 생산했다고 설명했다.웨버는 이 회사가 리눅스 포트를 준비하기 위해 리눅스 커뮤니티와도 협력했다고 설명했다.이 대처는 매우 중요했습니다.Microsoft가 AMD64 Windows의 대처에 계속 투자하는 인센티브가 되어 칩이 출시되면 중요한 OS가 되고 있던 Linux를 이용할 수 있게 되었습니다.
Weber는 Linux 작업이 AMD64의 성공에 절대적으로 중요하다고까지 말했습니다.이는 Linux를 통해 AMD가 필요에 따라 다른 회사의 도움 없이 엔드 투 엔드 시스템을 만들 수 있었기 때문입니다.이 가능성으로 인해 AMD는 다른 파트너들이 손을 떼더라도 최악의 생존 전략을 수립할 수 있었고, 결국 다른 파트너들은 뒤쳐질 것을 우려하여 계속 관여하게 되었습니다.
이는 AMD조차 MS와 Unix 간의 협력이 반드시 가장 중요하다고 생각하지 않았지만 Unix/Linux를 지원하는 것이 매우 중요하다고 느꼈음을 나타냅니다.어느 한 쪽이나 양쪽이 타협하거나 협력하도록 설득하는 것조차 그들을 짜증나게 하는 노력이나 위험(?)을 할 가치가 없는 것은 아닐까?아마 AMD는 공통의 ABI를 제안하는 것조차 칩이 준비되었을 때 소프트웨어 지원을 준비한다는 보다 중요한 목표를 지연시키거나 지연시킬 수 있다고 생각했을 것입니다.
추측입니다만, ABI가 다른 주된 이유는, MS와 Unix/Linux측이 제휴하지 않았던 정치적 이유라고 생각합니다만, AMD는 그것을 문제 삼지 않았습니다.
Win32는 ESI 및 EDI에 고유한 용도를 가지고 있으며, 이러한 용도는 수정하지 않아야 합니다(또는 적어도 API를 호출하기 전에 복원해야 합니다).64비트 코드가 RSI 및 RDI와 같은 기능을 한다고 생각합니다.그러면 함수 인수를 전달하는 데 사용되지 않는 이유가 설명됩니다.
RCX와 RDX가 바뀌는 이유는 알 수 없습니다.
언급URL : https://stackoverflow.com/questions/4429398/why-does-windows64-use-a-different-calling-convention-from-all-other-oses-on-x86
'programing' 카테고리의 다른 글
Azure 웹사이트는 정적 JS/CSS를 처리하는 속도가 느리지만 바이너리가 아니다. (0) | 2023.04.23 |
---|---|
Azure DocumentDB 소유자 리소스가 없습니다. (0) | 2023.04.23 |
특정 행에서 아래로 열을 요약합니다. (0) | 2023.04.23 |
Azure Web 작업 vs 스케줄러 (0) | 2023.04.23 |
필드의 숫자 값을 기준으로 파일을 정렬하려면 어떻게 해야 합니까? (0) | 2023.04.23 |