2016-09-17 2 views
2

기능에 입력 스택, 표준 프롤로그에 지역 변수를 참조하려면?방법 오프셋, 또는 RBP + 음의 오프셋 (offset)를 통해 RSP + 긍정적를 통해, <pre><code>push rbp mov rbp, rsp sub rsp, 128 ; large space for storing doubles, for example </code></pre> <p></p> 어떻게 지금 지역 변수를 참조하는 제대로

읽을 때 https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames, 실제로 이해할 수 있습니다. 씁니다.

... 특정 로컬 변수의 메모리 위치를 (적절한 오프셋을 사용하여) 결정하기 위해 esp의 값을 안정적으로 사용할 수 없습니다. 이 문제를 해결하기 위해 많은 컴파일러가 ebp 레지스터의 음수 오프셋을 사용하여 로컬 변수에 액세스합니다.

신뢰할 수없는 이유는 무엇입니까? 그 질문까지 나는이 같은 RSP를 통해 지역 변수에 접근했다 :

mov rax, [rsp+.length] ; get length of array 
mov [rsp+8], rax ; store sum at the stack 

모든 것이 아주 능숙 스택 참조에 대한 RSP를 사용하여 이동합니다.

+1

스택 포인터는 스택의 변수 주소를 결정하는 데 종종 사용할 수 있습니다.그러나이 함수가 가변 길이 배열이나'alloca()'와 동등한 것을 사용한다면 스택 포인터로부터의 오프셋을 더 이상 사용할 수 없다. – EOF

+0

@EOF, 그래서 두 경우를 제외하고 모든 경우에 rsp와 관련된 주소 지정을 사용해야합니까? –

답변

3

gcc 출력을보세요. 최적화 할 때 기본값은 이며, 함수가 가변 길이 배열을 사용하거나 스택을 16B 이상으로 정렬해야 할 때만 스택 프레임을 만듭니다.

위키 페이지는 기본적으로 잘못되었습니다. "신뢰할 수없는"무서운 이상한 물건이 없습니다. 당신이 할 수없는 유일한 시간은 어셈블 타임 상수가 아닌 양으로 RSP를 수정해야 할 때입니다. 당신이이 push rbp/mov rbp, rsp와 스택 프레임을 할 경우


그러나, 당신은 RBP-상대 주소 모드를 사용해야합니다. [rsp + 8]이 인코딩하기 위해 여분의 바이트를 사용하기 때문에 ([rbp - 8] 대) 더 효율적입니다. RSP를 기본 레지스터로 사용하는 어드레싱 모드는 인덱스 레지스터가없는 경우에도 항상 SIB 바이트가 필요합니다. RSP 상대 주소 모드를 사용

점은 저장/복원에 사용할 수있는 RBP는 (RBX 같은) 또 다른 전화에 저장 한 레지스터 있도록, 스택 프레임을 낭비 지침을 피할 수 있다는 것입니다 어떤 네가 원해.


RBP 상대 주소 지정의 또 다른 큰 이점은 RBP와 주어진 변수 간의 오프셋이 전체 기능에 대해 일정하게 유지된다는 것입니다. 컴파일러와는 달리, 우리는 인간을 괴롭히는 것은 기능 내에서 RSP를 변경하는 푸시와 팝에 의해 쉽게 혼동된다. 물론 64 비트 코드는 ABI가 레지스터에서 arg를 전달하기 때문에 프롤로그와 에필로그간에 함수 내에서 RSP를 거의 변경하지 않습니다. 프롤로그/에필로그에서 일부 통화 보존 레지스터 (예 : RBX 또는 R12-R15)를 저장/복원하는 것은 기능 내부에서 푸시/팝을하는 것보다 낫습니다 (그리고 루프 내부보다 확실히 좋습니다). 유출/재 장전이 필요할 때 무작위 접근을 위해 mov이 가장 좋습니다.

32 비트 코드에서 손으로 작성한 코드로 스택 프레임을 만드는 것이 더 적합합니다. 유지 보수성을 위해. 64 비트 코드에서는 대개별로 문제가되지 않습니다. push/pop의 여분의 쌍으로 여분의 레지스터를 저장/복원해도 stack 레이아웃은 변경되지만 스택에 전달 된 arg (예 : 값으로 큰 구조체가 있지만 const 포인터를 가져 오는 함수를 작성하는 경우)는 중요합니다. arg 대신에!).

+0

매우 유용합니다. 특히 효율성에 관해서 특히 중요합니다. 따라서 최적화 (프레임 포인터 누락)로 컴파일하는 경우 rsp 주소 지정을 인코딩하는 데 더 많은 바이트가 필요하므로 slighly 큰 코드를 얻게됩니까? –

+1

@BulatM .: 기능별로 3 또는 4 개의 명령어를 제외하고 절약하는 경우가 있습니다. 그것은 프롤로그의 1 + 3 바이트이고, 1 + 0 또는 3 바이트의 에필로그입니다. (선택 사항 인'mov rsp, rbp','pop rbp' 또는 일부 컴파일러는 1 바이트 인 LEAVE를 사용하는데, 이는 3 uops IIRC에 불과하므로 RSP가 저장된 RBP 값을 가리키고 있지 않은 경우 좋은 선택입니다 함수의 끝) –

+2

어셈블리를 직접 작성하면 로컬 변수에 스택 포인터의 고정 오프셋이 없기 때문에 스택 포인터가 추적을 유지하기 까다로울 수 있습니다. – fuz

관련 문제