2014-03-06 1 views
4

많은 호출 규칙이 [e] bx가 수신자를 위해 보존되어야한다고 주장했습니다.x86 어셈블리 - 호출 규칙에서 [e] bx가 보존되는 이유는 무엇입니까?

이제는 피 호출자의 스택을 엉망으로 만들 수 있기 때문에 왜 [e] sp 또는 [e] bp와 같은 것을 보존 할 수 있는지 이해할 수 있습니다. 특히주의를 기울이지 않으면 피 호출자의 지시 사항을 어길 수 있기 때문에 왜 당신이 [e] si 또는 [e] 디를 보존해야하는지 이해할 수 있습니다.

[e] bx? 지구상에서 무엇이 [e] bx에 대해 그렇게 중요합니까? 여러 호출 규칙이 함수 호출을 통해 유지되어야한다고 주장하는 특별한 이유가 무엇입니까?

[e] bx로 엉망으로 생길 수있는 미묘한 버그/잡아가 있습니까?

예를 들어 [e] bx를 수정하는 것이 [e] dx 또는 [e] cx를 수정하는 것보다 피 호출자에게 더 큰 영향을 미칩니 까?

왜 그렇게 많은 전화 규칙이 보존을 위해 나와 있는지 이해할 수 없습니다.

답변

6

는 모든 레지스터 보존을위한 좋은 후보를합니다

no (e)ax -- Implicitly used in some instructions; Return value 
no (e)dx -- edx:eax is implicity used in cdq, div, mul and in return values 

    (e)bx -- generic register, usable in 16-bit addressing modes (base) 
    (e)cx -- shift-counts, used in loop, rep 

    (e)si -- movs operations, usable in 16-bit addressing modes (index) 
    (e)di -- movs operations, usable in 16-bit addressing modes (index) 

Must (e)bp -- frame pointer, usable in 16-bit addressing modes (base) 
Must (e)sp -- stack pointer, not addressable in 8086 (other than push/pop) 

테이블을 보면, 두 레지스터 보존 할 좋은 이유가 있고이 이유가 보존 될 수 없습니다 있습니다. 누산기 = (e) ax. 짧은 인코딩으로 인해 가장 자주 사용되는 레지스터입니다. SI, DI는 논리 레지스터 쌍을 만듭니다 - REP MOVS 및 기타 문자열 연산에서 모두 휴지통입니다.

반호 평소/발신자 저장 패러다임에서 기본적으로 bx/cx가 si/di보다 선호되는 경우에만 토론이 진행됩니다. 다른 호출 규칙에서는 쓰레기 수있는 EDX, EAX 및 ECX 만 있습니다.

EBX에는 최신 코드 (예 : CMPXGH8B/CMPXGH16B)와 여전히 관련이있는 몇 가지 모호한 암시 적 사용이 있지만 32/64 비트 코드에서 가장 특수한 레지스터는 아닙니다.

EBX는 비 휘발성 레지스터가 아니라 EBX가 구체적으로 필요하기 때문에 EBX를 저장/복원해야하는 경우는 드물기 때문에 통화 보존 레지스터를 선택하는 것이 좋습니다. Brett Hale의 답변에 따르면, EBX는 ABI에서 필요로하는 전역 오프셋 테이블 (GOT) 포인터에 대한 좋은 선택입니다.

16 비트 모드에서 주소 지정 모드는 [BP|BX + DI|SI + disp8/disp16]의 (모든 하위 집합으로) 제한되었으므로 BX는 확실히 특별합니다.

+0

일부 컴파일러 (예 : Microsoft)는 프레임 포인터를 사용하지 않도록 설정할 수 있습니다.이 경우 ebp는 여분의 레지스터가되지만 피 호출자가 저장해야하는지 여부는 알 수 없습니다. – rcgldr

+0

사실입니다. 그러나 디버그 (또는 레거시 타겟)에서 컴파일 할 때 서브 루틴이 bp를 쓰레트 수 있도록 허용하면 심각한 페널티가 발생할 수 있습니다. 더 나은 프로그래밍 패러다임은 bp를 입력 할 때 저장하고 종료 할 때 항상 호출하기 전에 저장하는 대신 저장하는 것입니다. –

+0

언급 한 바와 같이, eax, ecx 및 edx는 호출자가 저장되는 경우 (필요한 경우) 나머지 ebp를 포함하여 레지스터가 저장되거나 수정되지 않습니다. 난 단지 프레임 포인터없이 푸시 ebp, 평소 mov ebp, esp 필요하지 않을 것이라고 지적했다. – rcgldr

5

이것은 어떤 레지스터도 저장하지 않고 모두 저장하는 것의 절충안입니다. 아무 것도 저장하지 않거나 모두 저장하는 것이 제안되었을 수 있지만 극단적 인 경우 내용을 메모리 (스택)에 복사하여 발생하는 비효율을 초래합니다. 일부 레지스터가 보존되고 일부 레지스터가 허용되도록 선택하면 평균 함수 호출의 비용이 줄어 듭니다.

+0

나는 그것을 이해할 수있다. 그러나 왜 [e] bx가 구체적인가? [e] dx와 같은 등록 기관이 그 타협에 대해서도 잘 해줬습니까? – thebennybox

+3

아마도 우연 일지 모르지만 bx, si, di 및 bp는 16 비트 코드에서 유효한 주소를 형성하는 데 사용할 수있는 레지스터입니다. –

+2

@FrankKotler는 이에 동의하는 경향이 있습니다. 원래 간접 어드레싱은'base '가'bx' /'bp' (따라서'b'')와'index''si' /'di'를 갖는'mov tgt, [base + index + off] '(그러므로''나는''). 따라서 주소 지정/스택 액세스 (BX, BP, SP, SI 및 DI)가 필요한 모든 규정을 유지하는 것이 바람직합니다. 'BP' /'SP'를'예약어'로 생각하면'AX','CX','DX'가 피 호출자가되고'BX'와'SI'가 반으로 나누어집니다. ', 'DI'는 호출자 소유입니다. –

4

i386 ELF ABI의 주된 이유 중 하나는 ebx이 위치 독립적 코드 (PIC)에 대한 전역 오프셋 테이블 (GOT) 레지스터의 주소를 보유한다는 것입니다. 자세한 내용은 사양의 3-35 페이지를 참조하십시오. 예를 들어, 공유 라이브러리 코드가 모든 함수 호출이 반환 된 후에 GOT를 복원해야한다면 극단적 인면에서 혼란을 겪을 것입니다.

+2

'bx '의 절약 전통은 DOS C 컴파일러와 Win16/Win32 ABI에 의해 이루어졌다. –

+0

EBX는 정수 레지스터의 가장 일반적인 목적이므로, 그 전통이 아니더라도 최상의 선택이 될 것입니다. (프레임 포인터를 신경 쓰지 않는다면 EBP도 좋은 선택이 될 것입니다.) 이것이 SysV i386 ABI에서 여전히 호출 보존 된 이유 중 일부입니다. 나는이 점을 포함하기 위해 Aki의 대답을 편집했다. –

+2

@IgorSkochinsky MS-DOS C 컴파일러에서 사용되는 것을 포함하여 대부분의 16 비트 호출 규칙은 Microsoft와 Borland 's는 함수 호출에서 BX를 보존하지 않았습니다. 몇 가지 16 비트 호출 규칙은이를 레지스터 매개 변수 및/또는 포인터에 대한 반환 값으로 사용했습니다. –