2016-06-21 6 views
5

다음과 같은 의문점이 있습니다.빨간색 영역이있을 때 스택 할당이 필요한 이유는 무엇입니까?

시스템 V x86-64 ABI는 스택 프레임에서 소위 redzone이라는 고정 크기 영역 (128 바이트)을 제공합니다. 따라서 예를 들어 sub rsp, 12과 같이 사용할 필요가 없습니다. 그냥 mov [rsp-12], X을 만들면됩니다.

그러나 나는 그 생각을 이해할 수 없습니다. 왜 중요합니까? redzone없이 sub rsp, 12해야합니까? 결국, 스택 크기는 처음에 제한되어 있으므로 sub rsp, 12이 중요한 이유는 무엇입니까? 우리가 스택 맨을 따라갈 수는 있지만 그 순간 그것을 무시하자.

일부 명령어는 rsp 값 (예 : ret)을 사용하지만 그 순간에는 신경 쓰지 않습니다.

문제의 핵심은 다음과 같습니다 우리는 더 레드 존이없고 우리가했던 :

function: 
    mov [rsp-16], rcx 
    mov [rsp-32], rcx 
    mov [rsp-128], rcx 
    mov [rsp-1024], rcx 
    ret 

가와 차이가 있습니까?

function: 
    sub rsp, 1024 
    mov [rsp-16], rcx 
    mov [rsp-32], rcx 
    mov [rsp-128], rcx 
    mov [rsp-1024], rcx 
    add rsp, 1024 
    ret 
+0

여기에 표시된 두 번째 코드 스 니펫이 잘못되었습니다. 스택 포인터를 감소 시키면 함수에서 복귀하기 전에 스택 포인터를 복원해야합니다. 그래서'ret rss 앞에'add rsp, 1024'를 추가해야합니다. –

+0

어느 ABI입니까? 나는 리눅스를 가정하지만, 다른 것들도있다. Windows 64, Mac OS X 64 비트 등. –

+1

@rudy 필자가 이해하는 한, 단지 두 개의 x86-64 ABI 만 있습니다 : System V AMD64 ABI (Linux, Solaris, OS X 및 기타 POSIX에서 사용됨) 호환 운영 체제) 및 Windows에서 사용되는 Microsoft 구현. 문제는 전자에 관한 것 같습니다. –

답변

9

"빨간 영역"은 반드시 필요한 것은 아닙니다. 귀하의 관점에서 보면, 그것은 "무의미한"것으로 간주 될 수 있습니다. 빨간색 영역을 사용하여 수행 할 수있는 모든 작업은 IA-32 ABI를 대상으로 수행 한 기존 방식대로 수행 할 수도 있습니다.

다음은 AMD64 ABI는 "레드 존"에 대해 말씀입니다 : 위치 넘어

128 바이트의 영역이 확보 된 것으로 간주되며, 신호 또는 인터럽트 핸들러 수정하지 않는다 %rsp에 의해 지적했다. 따라서 함수는 함수 호출을 통해 필요하지 않은 임시 데이터에이 영역을 사용할 수 있습니다. 특히 리프 함수는 프롤로그 및 에필로그에서 스택 포인터를 조정하는 대신 전체 스택 프레임에이 영역을 사용할 수 있습니다. 이 영역을 적색 영역이라고합니다.

레드 존의 진짜 목적은 최적화 같습니다. 그 존재는 코드가 rsp 아래의 128 바이트가 신호 또는 인터럽트 핸들러에 의해 비동기 적으로 구속되지 않는다고 가정하여 코드를 스크래치 공간으로 사용할 수있게합니다. 따라서 스택 포인터를 rsp으로 이동하여 스택에 스크래치 공간을 명시 적으로 생성 할 필요가 없습니다. rsp을 감소 및 복원하라는 지침을 이제는 생략 할 수 있으므로 시간과 공간을 절약 할 수 있으므로 최적화 작업입니다. 당신이 는 AMD64이 할 수있는 (그리고 IA-32와 함께 할 필요가있을 것이다) 동안

그래서 예 :

function: 
    push rbp      ; standard "prologue" to save the 
    mov rbp, rsp     ; original value of rsp 

    sub rsp, 32     ; reserve scratch area on stack 
    mov QWORD PTR [rsp], rcx ; copy rcx into our scratch area 
    mov QWORD PTR [rsp+8], rdx ; copy rdx into our scratch area 

    ; ...do something that clobbers rcx and rdx... 

    mov rcx, [rsp]    ; retrieve original value of rcx from our scratch area 
    mov rdx, [rsp+8]    ; retrieve original value of rdx from our scratch area 
    add rsp, 32     ; give back the stack space we used as scratch area 

    pop rbp      ; standard "epilogue" to restore rsp 
    ret 

을 우리는 우리의 경우에 그것을 할 수 없습니다 필요을 우리는 스크래치 영역으로 빨간 영역을 사용할 수 있기 때문에 128 바이트의 스크래치 영역 만 필요합니다.우리는 더 이상 스택 포인터를 감소 할 필요가 없기 때문에

또한, 우리는 저장 (프롤로그와 에필로그에서) rbp를 복원하는 것이 필요하고, 또한 자유롭게 기본 포인터 (대신 rbp을의)로 rsp을 사용할 수 있습니다 또 다른 범용 레지스터로 사용하기 위해 rbp을 올려라! , 기술적으로 ABI가 허용하는대로 -O1으로 활성화 됨) 또한 컴파일러가 동일한 장점을 가지고 프롤로그 및 에필로그 섹션을 삭제할 수있게합니다. 그러나, 빨간색 영역이 없으면 스택 공간을 예약하기 위해 스택 포인터를 조정해야 할 필요가 없습니다.)

그러나 ABI는 신호 및 인터럽트 처리기와 같은 비동기 적 요소가 빨간색 영역을 수정하지 않는다는 것을 보장합니다. 다른 함수를 호출하면 적색 영역의 값이 손상 될 수 있으므로 리프 함수 (함수 호출 트리의 "리프"에있는 것처럼 다른 함수를 호출하지 않는 함수)를 제외하면 특히 유용하지 않습니다. .


마지막 점 다음 Windows x64 ABIdeviates slightly from the AMD64 ABI used on other operating systems. 특히 "레드 존 (red zone)"에 대한 개념이 없다. rsp 이상의 영역은 일시적으로 간주되며 언제든지 덮어 쓸 수 있습니다. 대신 발신자가 스택에 home address space을 할당해야하며, 레지스터 전달 매개 변수 중 하나를 유출해야하는 경우 호출 수신자가 사용할 수 있습니다.

+0

좋아, 이제는 분명하다. 그래서, 나는 우리 프로세스의 신호/인터럽트 처리기가 (실제로 OS가 제공하는)'rsp'를 취하여 사용한다는 것을 이해합니다. 그리고, 실제로'rsp '아래에 뭔가가있을 때 문제를 만들 수 있습니다. 분명히 레드 존이없는 상황입니다. 네? – Gilgamesz

+1

신호 또는 인터럽트 처리기 *는 빨간색 영역을 사용할 수 없습니다. 그것은 ABI가 보장합니다. –

3

예에서 잘못된 방향으로 오프셋을 적용 했으므로 이것이 의미가 없습니다. 코드는 아래의 아래의 스택 포인터에 액세스하면 안됩니다. 이는 정의되지 않습니다. 빨간색 영역은 스택 포인터 아래 첫 번째 128 바이트 을 보호합니다. 두 번째 예를 읽어야합니다

function: 
    sub rsp, 1024 
    mov [rsp+16], rcx 
    mov [rsp+32], rcx 
    mov [rsp+128], rcx 
    mov [rsp+1016], rcx 
    add rsp, 1024 
    ret 

다음은 스택을 조정할 필요없이 주소를 스택 포인터 아래 를 사용할 수있는 128 바이트까지 함수가 필요 스크래치 공간의 크기는 경우 :이 최적화입니다 . 비교 :

레드 존 사용하여 같은 코드와
function:  // Not using red-zone. 
    sub rsp, 128 
    mov [rsp+120], rcx 
    add rsp, 128 
    ret 

: 컴파일러 프레임에서 음의 오프셋을 생성하기 때문에 스택 포인터의 오프셋에 대한 혼란이 일반적으로 발생

function:  // Using the red-zone, no adjustment of stack 
    mov [rsp-8], rcx 
    ret 

을 (RBP를), 스택에서 양의 오프셋 (RSP)이 아닙니다.

+1

'-fomit-frame-pointer'는 리눅스를 대상으로하는 gcc의 기본값이며, -O1 이상입니다. 보통 '-O0' 결과물에있는'rbp'의 오프셋 만 볼 수 있습니다. 이것은보기에별로 재미 있지 않습니다. 재미있는 사실은'-128'이'rsp'로부터의 최대 1 바이트 변위이기 때문에 레드 존의 크기가 선택되었습니다. –

+0

나는 그것이 디폴트가되었다는 것을 몰랐다. 나는 내가 보는 것보다 나이다. – Amoss

+0

@Peter, 부호없는 바이트가 255의 최대 값을 취할 수 있기 때문에 왜 255 바이트가 아닌가? –