developer tip

gcc 옵션 -fomit-frame-pointer 이해하기

copycodes 2020. 10. 22. 08:10
반응형

gcc 옵션 -fomit-frame-pointer 이해하기


나는 Google에 gcc옵션 의 의미를 알려달라고 요청했으며 -fomit-frame-pointer, 그러면 아래 설명으로 리디렉션됩니다.

-fomit-frame-pointer

프레임 포인터가 필요하지 않은 함수에 대해서는 레지스터에 프레임 포인터를 유지하지 마십시오. 이렇게하면 프레임 포인터를 저장, 설정 및 복원하는 지침이 필요하지 않습니다. 또한 많은 기능에서 추가 레지스터를 사용할 수 있습니다. 또한 일부 컴퓨터에서는 디버깅이 불가능합니다.

각 기능에 대한 지식에 따라 모든 로컬 변수와 일부 추가 정보를 유지하기 위해 프로세스 메모리 스택에 활성화 레코드가 생성됩니다. 이 프레임 포인터가 함수의 활성화 레코드 주소를 의미하기를 바랍니다.

이 경우, 레지스터에 프레임 포인터를 유지할 필요가없는 함수 유형은 무엇입니까? 이 정보를 얻으면 프레임 포인터가 레지스터에 유지되지 않으면 일부 명령어가 이진으로 생략되기 때문에 가능한 경우이를 기반으로 새 함수를 설계하려고합니다. 이것은 많은 기능이있는 어플리케이션에서 성능을 현저하게 향상시킬 것입니다.


대부분의 작은 함수에는 프레임 포인터가 필요하지 않습니다. 큰 함수에는 프레임 포인터가 필요할 수 있습니다.

실제로 컴파일러가 스택이 사용되는 방식과 스택의 위치 (로컬 변수, 현재 함수에 전달 된 인수 및 호출 될 함수를 준비중인 인수)를 추적하는 데 얼마나 잘 관리되는지에 대한 것입니다. 프레임 포인터가 필요하거나 필요하지 않은 함수를 특성화하는 것이 쉽지 않다고 생각합니다 (기술적으로 프레임 포인터를 갖는 함수는 없습니다. 컴파일러가 복잡성을 줄이기 위해 필요하다고 판단하는 경우 기타 코드 ").

코딩 전략의 일부로 "함수에 프레임 포인터가 없도록 만들려고 시도"해서는 안된다고 생각합니다. 제가 말했듯이 간단한 함수에는 필요하지 않으므로을 사용 -fomit-frame-pointer하면 하나 이상의 레지스터를 사용할 수 있습니다. 레지스터 할당 자에 대해, 기능에 대한 진입 / 종료에 대한 1-3 명령을 저장합니다. 함수에 프레임 포인터가 필요한 경우 컴파일러가 프레임 포인터를 사용하지 않는 것보다 더 나은 옵션이라고 결정하기 때문입니다. 프레임 포인터없이 함수를 사용하는 것이 목표가 아니라 정확하고 빠르게 작동하는 코드를 갖는 것이 목표입니다.

"프레임 포인터가 없음"은 더 나은 성능을 제공해야하지만 엄청난 개선을 제공하는 마법의 총알은 아닙니다. 특히 처음 시작할 레지스터가 16 개있는 x86-64에서는 그렇지 않습니다. 32 비트 x86에서는 레지스터가 8 개 뿐이며 그중 하나는 스택 포인터이고 다른 하나를 프레임 포인터로 차지한다는 것은 레지스터 공간의 25 %를 차지한다는 것을 의미합니다. 이를 12.5 %로 변경하는 것은 상당히 개선 된 것입니다. 물론 64 비트 용으로 컴파일하는 것도 많은 도움이 될 것입니다.


이것은 인텔 플랫폼의 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

또는 enterIntel 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-pointerGCC 컴파일러 옵션을 사용하는 경우 루틴에 대한 시작 및 종료 코드와 추가 레지스터가 있으면 이길 수 있습니다 (기본적으로 자체적으로 또는 다른 이 경우 이미 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 also turns on -fomit-frame-pointer on machines where doing so does not interfere with debugging.

So it is not clear from the documentation per se whether -fomit-frame-pointer will be turned on if you just compile with a single -O option on x86 platform. It may be tested empirically, but in this case there is no commitment from the GCC developers to not change the behavior of this option in future without notice.

However, Peter Cordes has pointed out in comments that there is a difference for the default settings of the -fomit-frame-pointer between x86-16 platforms and x86-32/64 platforms.

This option -- -fomit-frame-pointer -- is also relevant to the Intel C++ Compiler 15.0, not only to the GCC:

For the Intel Compiler, this option has an alias /Oy.

Here is what Intel wrote about it:

These options determine whether EBP is used as a general-purpose register in optimizations. Options -fomit-frame-pointer and /Oy allow this use. Options -fno-omit-frame-pointer and /Oy- disallow it.

Some debuggers expect EBP to be used as a stack frame pointer, and cannot produce a stack backtrace unless this is so. The -fno-omit-frame-pointer and /Oy- options direct the compiler to generate code that maintains and uses EBP as a stack frame pointer for all functions so that a debugger can still produce a stack backtrace without doing the following:

For -fno-omit-frame-pointer: turning off optimizations with -O0 For /Oy-: turning off /O1, /O2, or /O3 optimizations The -fno-omit-frame-pointer option is set when you specify option -O0 or the -g option. The -fomit-frame-pointer option is set when you specify option -O1, -O2, or -O3.

The /Oy option is set when you specify the /O1, /O2, or /O3 option. Option /Oy- is set when you specify the /Od option.

Using the -fno-omit-frame-pointer or /Oy- option reduces the number of available general-purpose registers by 1 and can result in slightly less efficient code.

NOTE For Linux* systems: There is currently an issue with GCC 3.2 exception handling. Therefore, the Intel compiler ignores this option when GCC 3.2 is installed for C++ and exception handling is turned on (the default).

Please be aware that the above quote is only relevant for the Intel C++ 15 compiler, not to GCC.

참고URL : https://stackoverflow.com/questions/14666665/trying-to-understand-gcc-option-fomit-frame-pointer

반응형