이것은 인텔 플랫폼의 BP / EBP / RBP 레지스터에 관한 것입니다. 이 레지스터는 스택 세그먼트로 기본 설정됩니다 (스택 세그먼트에 액세스하기 위해 특별한 접두사가 필요하지 않음).
EBP는 스택 내에서 데이터 구조, 변수 및 동적으로 할당 된 작업 공간에 액세스하기위한 최상의 레지스터 선택입니다. EBP는 현재 TOS가 아닌 스택의 고정 지점을 기준으로 스택의 요소에 액세스하는 데 자주 사용됩니다. 일반적으로 현재 프로 시저에 대해 설정된 현재 스택 프레임의 기본 주소를 식별합니다. EBP가 오프셋 계산에서 기준 레지스터로 사용되는 경우 오프셋은 현재 스택 세그먼트 (즉, SS가 현재 선택한 세그먼트)에서 자동으로 계산됩니다. SS를 명시 적으로 지정할 필요가 없기 때문에 이러한 경우 명령어 인코딩이 더 효율적입니다. EBP는 다른 세그먼트 레지스터를 통해 주소를 지정할 수있는 세그먼트로 인덱싱하는 데 사용할 수도 있습니다.
(출처 -http : //css.csail.mit.edu/6.858/2017/readings/i386/s02_03.htm )
대부분의 32 비트 플랫폼에서 데이터 세그먼트와 스택 세그먼트가 동일하기 때문에 EBP / RBP와 스택의 연관은 더 이상 문제가되지 않습니다. 64 비트 플랫폼에서도 마찬가지입니다. AMD가 2003 년에 도입 한 x86-64 아키텍처는 64 비트 모드에서 세분화 지원을 크게 중단했습니다. 세그먼트 레지스터 중 4 개 : CS, SS, DS 및 ES가 0으로 강제 설정됩니다. x86 32 비트 및 64 비트 플랫폼의 이러한 상황은 본질적으로 EBP / RBP 레지스터를 메모리에 액세스하는 프로세서 명령에서 접두사없이 사용할 수 있음을 의미합니다.
따라서 작성한 컴파일러 옵션을 사용하면 BP / EBP / RBP를 다른 수단 (예 : 지역 변수 보유)에 사용할 수 있습니다.
"이렇게하면 프레임 포인터를 저장, 설정 및 복원하는 지침이 필요하지 않습니다."는 각 기능의 항목에 다음 코드를 사용하지 않는 것을 의미합니다.
push ebp
mov ebp, esp
또는 enter
Intel 80286 및 80386 프로세서에서 매우 유용한 명령입니다.
또한 함수가 반환되기 전에 다음 코드가 사용됩니다.
mov esp, ebp
pop ebp
또는 leave
지시.
디버깅 도구는 스택 데이터를 스캔하고 이러한 푸시 된 EBP 레지스터 데이터를 찾는 동안 사용할 수 있습니다 call sites
. 즉, 함수 이름과 인수를 계층 적으로 호출 된 순서대로 표시합니다.
프로그래머는 포괄적 인 용어 (단 하나의 함수 호출 만 제공하고 반환 주소, 인수 및 지역 변수를 유지하는 스택의 단일 엔티티)가 아니라 좁은 의미에서 스택 프레임에 대해 질문 할 수 있습니다 stack frames
. 컴파일러 옵션의 컨텍스트. 컴파일러의 관점에서 스택 프레임은 루틴에 대한 시작 및 종료 코드 일 뿐이며 앵커를 스택에 푸시합니다. 이는 디버깅 및 예외 처리에도 사용할 수 있습니다. 디버깅 도구는 스택 데이터를 스캔하고 이러한 앵커를 역 추적에 사용할 수 call sites
있으며, 스택에서 위치를 찾는 동안 즉, 계층 적으로 호출 된 순서대로 함수 이름을 표시 할 수 있습니다.
그렇기 때문에 컴파일러가이 코드를 생성할지 여부를 제어 할 수 있기 때문에 컴파일러 옵션 측면에서 스택 프레임이 무엇인지 프로그래머에게 이해하는 것이 매우 중요합니다.
경우에 따라 스택 프레임 (루틴의 시작 및 종료 코드)은 컴파일러에서 생략 할 수 있으며 변수는 편리한 기본 포인터 (BP /)가 아닌 스택 포인터 (SP / ESP / RSP)를 통해 직접 액세스됩니다. ESP / RSP). 컴파일러가 일부 함수에 대해 스택 프레임을 생략하는 조건은 다를 수 있습니다. 예를 들면 다음과 같습니다. (1) 함수가 리프 함수입니다 (즉, 다른 함수를 호출하지 않는 최종 엔터티); (2) 예외가 사용되지 않습니다. (3) 스택에서 나가는 매개 변수로 루틴이 호출되지 않습니다. (4) 함수에 매개 변수가 없습니다.
스택 프레임 (루틴의 진입 및 종료 코드)을 생략하면 코드가 더 작고 빨라질 수 있지만 스택의 데이터를 역 추적하고 프로그래머에게 표시하는 디버거의 기능에 부정적인 영향을 미칠 수 있습니다. 컴파일러가 스택 프레임 진입 및 종료 코드를 제공하기 위해 함수가 충족해야하는 조건을 결정하는 컴파일러 옵션입니다. 예를 들어 컴파일러는 (a) 항상, (b) 전혀, (c) 필요할 때 (조건 지정) 경우 함수에 이러한 시작 및 종료 코드를 추가하는 옵션을 가질 수 있습니다.
일반성에서 특수성으로 돌아 가기 : -fomit-frame-pointer
GCC 컴파일러 옵션을 사용할 경우 루틴에 대한 시작 및 종료 코드와 추가 레지스터가 있으면 이길 수 있습니다 (기본적으로 자체적으로 또는 다른 사용자에 의해 암시 적으로 켜져 있지 않는 한). 이 경우 이미 EBP / RBP 레지스터를 사용하여 이득을 얻고 있으며 이미 암시 적으로 켜져있는 경우이 옵션을 명시 적으로 지정하여 추가 이득을 얻을 수 없습니다. 그러나 16 비트 및 32 비트 모드에서 BP 레지스터는 AX가 가진 (AL 및 AH)와 같이 8 비트 부분에 액세스 할 수 없습니다.
이 옵션은 컴파일러가 최적화에서 EBP를 범용 레지스터로 사용하도록 허용하는 것 외에도 디버깅을 복잡하게하는 스택 프레임에 대한 종료 및 진입 코드 생성을 방지하기 때문에 GCC 문서에 명시 적으로 명시되어 있습니다 (비정상적으로 굵은 글꼴로 강조) 스타일)이 옵션을 활성화하면 일부 컴퓨터에서는 디버깅이 불가능합니다.
디버깅 또는 최적화와 관련된 다른 컴파일러 옵션은 암시 적으로 -fomit-frame-pointer
옵션을 켜거나 끌 수 있습니다.
다른 옵션 -fomit-frame-pointer
이 x86 플랫폼에 미치는 영향 에 대한 공식 정보는 gcc.gnu.org에서 찾지 못했습니다 . https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html 다음 사항 만 명시합니다.
-O는 또한 디버깅을 방해하지 않는 시스템에서 -fomit-frame-pointer를 켭니다.
따라서 x86 플랫폼 에서 단일 옵션으로 컴파일하는 경우 켜질 것인지 여부 는 설명서 자체에서 명확하지 않습니다 . 경험적으로 테스트 할 수 있지만이 경우 GCC 개발자는 사전 통보없이이 옵션의 동작을 변경하지 않겠다는 약속이 없습니다.-fomit-frame-pointer
-O
그러나 Peter Cordes 는 -fomit-frame-pointer
x86-16 플랫폼과 x86-32 / 64 플랫폼 간의 기본 설정에 차이가 있음을 주석에서 지적했습니다 .
이 옵션 은 GCC뿐만 아니라 인텔 C ++ 컴파일러 15.0-fomit-frame-pointer
과도 관련 이 있습니다 .
인텔 컴파일러의 경우이 옵션에는 별칭이 /Oy
있습니다.
다음은 인텔이 작성한 내용입니다.
이러한 옵션은 EBP가 최적화에서 범용 레지스터로 사용되는지 여부를 결정합니다. 옵션 -fomit-frame-pointer 및 / Oy를 사용하면이 사용이 가능합니다. 옵션 -fno-omit-frame-pointer 및 / Oy- 허용하지 않습니다.
일부 디버거는 EBP가 스택 프레임 포인터로 사용되기를 기대하며 그렇지 않으면 스택 역 추적을 생성 할 수 없습니다. -fno-omit-frame-pointer 및 / Oy- 옵션은 디버거가 다음을 수행하지 않고도 스택 역 추적을 생성 할 수 있도록 모든 함수에 대한 스택 프레임 포인터로 EBP를 유지하고 사용하는 코드를 생성하도록 컴파일러에 지시합니다.
-fno-omit-frame-pointer의 경우 : -O0으로 최적화 해제 / Oy-의 경우 : / O1, / O2 또는 / O3 최적화 해제 -fno-omit-frame-pointer 옵션은 옵션을 지정할 때 설정됩니다. O0 또는 -g 옵션. -fomit-frame-pointer 옵션은 -O1, -O2 또는 -O3 옵션을 지정할 때 설정됩니다.
/ Oy 옵션은 / O1, / O2 또는 / O3 옵션을 지정할 때 설정됩니다. / Od 옵션을 지정하면 / Oy- 옵션이 설정됩니다.
-fno-omit-frame-pointer 또는 / Oy- 옵션을 사용하면 사용 가능한 범용 레지스터 수가 1 개 줄어들고 코드 효율성이 약간 떨어질 수 있습니다.
참고 Linux * 시스템의 경우 : 현재 GCC 3.2 예외 처리에 문제가 있습니다. 따라서 인텔 컴파일러는 GCC 3.2가 C ++ 용으로 설치되고 예외 처리가 켜져있는 경우 (기본값)이 옵션을 무시합니다.
위의 인용문은 GCC가 아닌 인텔 C ++ 15 컴파일러에만 해당됩니다.