간단히 말해서 스택 프레임의 개념을 설명하십시오


200

프로그래밍 언어 디자인에서 콜 스택 에 대한 아이디어를 얻는 것 같습니다 . 그러나 스택 프레임 이 무엇인지에 대한 적절한 설명을 찾을 수 없습니다 (아마도 충분히 열심히 검색하지는 않습니다) .

그래서 누군가에게 몇 마디로 설명해달라고 부탁하고 싶습니다.

답변:


195

스택 프레임은 스택으로 푸시되는 데이터 프레임입니다. 호출 스택의 경우 스택 프레임은 함수 호출 및 해당 인수 데이터를 나타냅니다.

올바르게 기억하면 함수 반환 주소가 먼저 스택으로 푸시 된 다음 로컬 변수의 인수와 공간이 푸시됩니다. 아키텍처에 따라 다르지만 함께 "프레임"을 만듭니다. 프로세서는 각 프레임에 몇 바이트가 있는지 알고 있으며 프레임이 스택에서 밀리고 튀어 나옴에 따라 스택 포인터를 이동시킵니다.

편집하다:

높은 수준의 호출 스택과 프로세서의 호출 스택에는 큰 차이가 있습니다.

프로세서의 호출 스택에 대해 이야기 할 때 어셈블리 또는 머신 코드에서 바이트 / 워드 수준 의 주소와 값을 다루는 것에 대해 이야기하고 있습니다. 고급 언어에 대해 이야기 할 때 "호출 스택"이 있지만 런타임 환경에서 관리하는 디버깅 / 런타임 도구이므로 프로그램에 문제가 발생한 것을 높은 수준으로 기록 할 수 있습니다. 이 수준에서 줄 번호, 메소드 및 클래스 이름과 같은 것이 종종 알려져 있습니다. 프로세서가 코드를 가져올 때까지는 이러한 개념이 전혀 없습니다.


6
"프로세서는 각 프레임에 몇 바이트가 있는지 알고 있으며 프레임이 스택에서 밀리고 튀어 나오면서 그에 따라 스택 포인터를 이동시킵니다." -우리는 subbing (할당), 밀기 및 팝을 통해 스택을 조작하기 때문에 프로세서가 스택에 대해 아는 것이 의심됩니다. 그리고 여기 스택 사용 방법을 설명하는 호출 규칙이 있습니다.
Victor Polevoy

78

스택을 잘 이해하면 프로그램에서 메모리가 작동하는 방식을 이해하고 프로그램에서 메모리가 작동하는 방식을 이해하면 프로그램에서 함수가 저장되는 방식을 이해하고 프로그램에서 함수가 저장되는 방식을 이해하면 재귀 함수가 작동하는 방식을 이해할 수 있습니다. 재귀 함수의 작동 방식을 이해하면 컴파일러의 작동 방식을 이해하고 컴파일러의 작동 방식을 이해하면 마음이 컴파일러로 작동하며 프로그램을 매우 쉽게 디버깅합니다.

스택 작동 방식을 설명하겠습니다.

먼저 함수가 스택에서 어떻게 표현되는지 알아야합니다.

힙은 동적으로 할당 된 값을 저장합니다.
스택은 자동 할당 및 삭제 값을 저장합니다.

여기에 이미지 설명을 입력하십시오

예제로 이해하자 :

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(4)

이제이 프로그램의 일부를 이해하십시오.

여기에 이미지 설명을 입력하십시오

이제 스택이 무엇이고 스택 부분이 무엇인지 살펴 보겠습니다.

여기에 이미지 설명을 입력하십시오

스택 할당 :

함수의 반환 조건이 충족되면 로컬 변수를로드했는지 여부에 관계없이 스택 프레임을 사용하여 스택에서 즉시 반환됩니다. 이것은 재귀 함수가 기본 조건을 만족시키고 기본 조건 이후에 리턴 할 때마다 기본 조건이 프로그램의 "else"부분에있는 로컬 변수를로드하기를 기다리지 않음을 의미합니다. 다음 프레임이 활성화 레코드에있는 스택에서 현재 프레임을 즉시 반환합니다.

실제로 이것을보십시오 :

여기에 이미지 설명을 입력하십시오

블록의 할당 해제 :

따라서 함수가 return 문을 만나면 스택에서 현재 프레임을 삭제합니다.

스택에서 반환되는 동안 값은 스택에 할당 된 원래 순서와 반대로 반환됩니다.

여기에 이미지 설명을 입력하십시오


3
스택이 아래로 커지고 힙이 위로 커지면 다이어그램에서 다시 뒤집습니다. 정확한 도표는 여기에서
Rafael

@ Rafael 혼란스러워서 죄송합니다. 성장 방향에 대해 이야기하고 있었으며 스택 성장 방향에 대해 이야기하지 않았습니다. 성장 방향과 스택 성장 방향에는 차이가 있습니다. 여기를보십시오 stackoverflow.com/questions/1677415/…
Aaditya Ura

2
라파엘이 옳습니다. 또한 첫 번째 사진이 잘못되었습니다. 다른 것으로 교체하십시오 (Google 사진에서 "힙 스택"검색).
Nikos

따라서 올바르게 이해하면 세 번째 다이어그램 hello()에는 재귀 적으로 호출 hello()된 재귀 적으로 호출 된 3 개의 스택 프레임 이 있으며 hello()전역 프레임은 첫 번째 hello()?
Andy J

1
링크가 우리를 어디로 인도합니까? 보안에 대한 심각한 우려로 이러한 링크는 가능한 빨리 제거해야합니다.
Shivanshu

45

빠른 마무리. 어쩌면 누군가 더 나은 설명이있을 수 있습니다.

호출 스택은 하나 또는 여러 개의 스택 프레임으로 구성됩니다. 각 스택 프레임은 아직 리턴으로 종료되지 않은 함수 또는 프로 시저에 대한 호출에 해당합니다.

스택 프레임을 사용하기 위해 스레드는 두 개의 포인터를 유지합니다. 하나는 스택 포인터 (SP), 다른 하나는 프레임 포인터 (FP)입니다. SP는 항상 스택의 "맨 위"를 가리키고 FP는 항상 프레임의 "맨 위"를 가리 킵니다. 또한 스레드는 다음에 실행될 명령을 가리키는 프로그램 카운터 (PC)를 유지 관리합니다.

다음은 스택에 저장됩니다. 로컬 변수 및 임시, 현재 명령어의 실제 매개 변수 (프로 시저, 함수 등)

스택 청소와 관련하여 서로 다른 호출 규칙이 있습니다.


7
서브 루틴의 리턴 주소가 스택에 있다는 것을 잊지 마십시오.
Tony R

4
프레임 포인터는 또한 x86 용어로 기본 포인터입니다
peterchaula

1
프레임 포인터가 현재 활성화 된 프로 시저 화신의 스택 프레임의 시작을 가리킨다는 점을 강조하고 싶습니다.
Server Khalilov

13

"콜 스택은 스택 프레임으로 구성되어 있습니다 ..."—  Wikipedia

스택 프레임은 스택에 넣는 것입니다. 호출 할 서브 루틴에 대한 정보를 포함하는 데이터 구조입니다.


죄송합니다. Wiki에서 어떻게 놓쳤는 지 모르겠습니다. 감사. 동적 언어에서 함수의 지역이 정확히 알려지지 않았기 때문에 프레임 크기가 상수 값이 아니라는 것을 올바르게 이해하고 있습니까?
ikostia

프레임의 크기와 특성은 기계의 아키텍처에 따라 크게 달라집니다. 실제로 콜 스택의 패러다임은 아키텍처에 따라 다릅니다. 내가 아는 한 함수 호출마다 다른 양의 인수 데이터가 있기 때문에 항상 가변적입니다.
Tony R

스택 프레임의 크기는 조작 될 때 프로세서가 알고 있어야합니다 . 이 경우 데이터 크기가 이미 결정되었습니다. 동적 언어는 정적 언어와 같이 기계 코드로 컴파일되도록 컴파일되지만 컴파일러가 동적을 유지하고 프로세서가 "알려진"프레임 크기로 작업 할 수 있도록 적시에 수행됩니다. 고급 언어를 기계 코드 / 어셈블리와 혼동하지 마십시오.이 부분이 실제로 발생하는 곳입니다.
Tony R

글쎄, 그러나 동적 언어에는 호출 스택이 있습니까? 예를 들어, 파이썬이 어떤 프로 시저를 실행하고자한다면,이 프로 시저에 대한 데이터는 어떤 파이썬 인터프리터의 구조 안에 저장됩니다. 맞습니까? 따라서 통화 스택은 낮은 수준뿐만 아니라 존재합니다.
ikostia

그 위키 백과 기사를 약간 읽은 후, 나는 약간 수정되었습니다. 스택 프레임의 크기는 컴파일 타임에 알 수없는 상태로 유지 될 수 있습니다 . 그러나 프로세서가 스택 + 프레임 포인터로 작업 할 때는 크기가 무엇인지 알아야합니다. 크기는 다양 할 수 있지만 프로세서는 크기를 알고 있습니다.
Tony R

5

프로그래머는 스택 프레임에 대해 광범위한 용어 (단 하나의 함수 호출 만 제공하고 리턴 주소, 인수 및 로컬 변수를 유지하는 스택의 단일 엔티티)가 아니라 좁은 의미로 질문에 대해 stack frames언급 할 수 있습니다. 컴파일러 옵션의 컨텍스트.

질문의 저자가 의미했는지 여부에 관계없이 컴파일러 옵션의 측면에서 스택 프레임 개념은 매우 중요한 문제이며 다른 답변에서는 다루지 않습니다.

예를 들어, Microsoft Visual Studio 2015 C / C ++ 컴파일러에는 다음과 관련된 옵션이 있습니다 stack frames.

  • / Oy (프레임 포인터 생략)

GCC에는 다음이 있습니다.

  • -fomit-frame-pointer (프레임 포인터를 필요로하지 않는 함수에 대한 레지스터에 프레임 포인터를 유지하지 마십시오. 프레임 포인터를 저장, 설정 및 복원하는 명령을 피할 수 있으며 많은 함수에서 추가 레지스터를 사용할 수 있습니다. )

인텔 C ++ 컴파일러에는 다음이 있습니다.

  • -fomit-frame-pointer (EBP가 최적화에서 범용 레지스터로 사용되는지 결정)

다음과 같은 별칭이 있습니다.

  • / 오

델파이에는 다음과 같은 명령 행 옵션이 있습니다.

  • -$ W + (스택 프레임 생성)

컴파일러의 관점에서 볼 때 스택 프레임은 루틴시작 및 종료 코드 일 뿐이며 앵커를 스택으로 푸시합니다. 디버깅 및 예외 처리에도 사용할 수 있습니다. 디버깅 도구는 스택에 위치하는 동안 스택 데이터를 스캔하고 이러한 앵커를 사용하여 백 트레이싱 call sites할 수 있습니다. 즉, 함수 이름을 계층 적으로 호출 된 순서대로 표시합니다. 인텔 아키텍처의 경우,은 push ebp; mov ebp, esp또는 enter항목 및 mov esp, ebp; pop ebp또는 leave출구를.

그렇기 때문에 컴파일러는 컴파일러 옵션과 관련하여 스택 프레임의 내용을 이해하는 것이 매우 중요합니다. 컴파일러는이 코드를 생성할지 여부를 제어 할 수 있기 때문입니다.

경우에 따라 스택 프레임 (루틴에 대한 입력 및 종료 코드)을 컴파일러에서 생략 할 수 있으며 변수는 편리한 기본 포인터 (BP / ESP / RSP). 스택 프레임 생략 조건 : 예 :

  • 함수는 리프 함수 (즉, 다른 함수를 호출하지 않는 엔드 엔터티)입니다.
  • 시도 / 최종 또는 시도 / 제외 또는 유사한 구성이 없으며, 예외가 사용되지 않습니다.
  • 스택에서 나가는 매개 변수로 루틴이 호출되지 않습니다.
  • 이 함수에는 매개 변수가 없습니다.
  • 이 함수에는 인라인 어셈블리 코드가 없습니다.
  • 기타...

스택 프레임 (루틴의 입력 및 종료 코드)을 생략하면 코드가 더 작고 빨라질 수 있지만, 스택의 데이터를 역 추적하고 프로그래머에게 표시하는 디버거의 기능에 부정적인 영향을 줄 수도 있습니다. 다음은 함수가 시작 및 종료 코드를 가져야하는 조건을 결정하는 컴파일러 옵션입니다. 예를 들어 (a) 항상, (b) 절대, (c) 필요할 때 (조건 지정).


-1

스택 프레임은 함수 호출과 관련된 압축 정보입니다. 이 정보에는 일반적으로 함수에 전달 된 인수, 지역 변수 및 종료시 반환되는 위치가 포함됩니다. 활성화 레코드는 스택 프레임의 다른 이름입니다. 스택 프레임의 레이아웃은 제조업체에 의해 ABI에서 결정되며 ISA를 지원하는 모든 컴파일러는이 표준을 준수해야하지만 레이아웃 체계는 컴파일러에 따라 달라질 수 있습니다. 일반적으로 스택 프레임 크기는 제한되지 않지만 스택 프레임을 방해하지 않고 시스템 호출 등을 실행할 수 있도록 "빨간색 / 보호 영역"이라는 개념이 있습니다.

SP는 항상 있지만 일부 ABI (예 : ARM 및 PowerPC)에는 FP가 선택 사항입니다. 스택에 배치해야하는 인수는 SP 만 사용하여 오프셋 할 수 있습니다. 함수 호출을 위해 스택 프레임이 생성되는지 여부는 인수의 유형 및 개수, 지역 변수 및 지역 변수에 일반적으로 액세스하는 방법에 따라 다릅니다. 대부분의 ISA에서는 먼저 레지스터가 사용되며 인수 전달 전용 레지스터보다 많은 인수가있는 경우 스택에 배치됩니다 (예 : x86 ABI에는 정수 인수를 전달하는 6 개의 레지스터가 있습니다). 따라서 때때로 일부 함수는 스택에 스택 프레임을 배치 할 필요가 없으며 반환 주소 만 스택에 푸시됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.