C 코드를 컴파일하고 어셈블리를 볼 때 스택은 다음과 같이 거꾸로 커집니다.
_main:
pushq %rbp
movl $5, -4(%rbp)
popq %rbp
ret
-4(%rbp)
-이것은 기본 포인터 또는 스택 포인터가 실제로 메모리 주소보다 아래로 이동한다는 것을 의미합니까? 왜 그런 겁니까?
로 변경 $5, -4(%rbp)
하고 $5, +4(%rbp)
컴파일하고 코드를 실행했으며 오류가 없었습니다. 그렇다면 왜 메모리 스택에서 여전히 뒤로 가야합니까?
답변
이것은 기본 포인터 또는 스택 포인터가 실제로 메모리 주소보다 아래로 이동한다는 것을 의미합니까? 왜 그런 겁니까?
그렇습니다. push
명령어는 스택 포인터를 줄이고 스택에 쓰지만 pop
반대로는 스택에서 읽고 스택 포인터를 증가시킵니다.
이는 메모리가 제한된 머신의 경우 스택이 높고 아래쪽으로 성장한 반면 힙이 낮고 위쪽으로 늘어난 점에서 다소 역사적입니다. 힙과 스택 사이에는 “사용 가능한 메모리”의 간격이 하나만 있으며이 간격은 공유되므로 개별적으로 필요에 따라 간격이 커질 수 있습니다. 따라서 스택 및 힙 충돌시 사용 가능한 메모리가없는 경우에만 프로그램의 메모리가 부족합니다.
스택과 힙이 모두 같은 방향으로 커지면 두 개의 틈이 있고 스택은 실제로 힙의 틈으로 자랄 수 없습니다 (그 반대도 마찬가지입니다).
원래 프로세서에는 전용 스택 처리 명령이 없었습니다. 그러나 하드웨어에 스택 지원이 추가됨에 따라이 패턴은 아래로 늘어 났으며 프로세서는 오늘날에도이 패턴을 따릅니다.
64 비트 시스템에는 여러 갭을 허용하기에 충분한 주소 공간이 있다고 주장 할 수 있습니다. 증거로서 프로세스에 여러 개의 스레드가있는 경우 여러 갭이 반드시 필요한 경우입니다. 여러 갭 시스템으로 인해 성장 방향이 임의적이므로 전통 / 호환성이 규모에 영향을 미칩니다.
당신은 스택의 방향을 변경하거나 다른 전용 밀어 및 지침을 보여주고 (예를 들어, 사용을 포기하기 위해 CPU 스택 처리 지침을 변경해야 할 것 push
, pop
, call
, ret
, 등).
MIPS 명령어 세트 아키텍처에는 push
& 전용이 없으므로 pop
스택을 어느 방향 으로든 늘리는 것이 실용적입니다. 단일 스레드 프로세스를위한 1 개의 갭 메모리 레이아웃을 원할 수 있지만 스택을 위로 늘리고 힙을 늘릴 수 있습니다 아래쪽으로. 그러나 그렇게하면 일부 C varargs 코드에서 소스 또는 실제 매개 변수 전달을 조정해야 할 수 있습니다.
(사실 MIPS에는 전용 스택 처리가 없기 때문에 스택에서 튀어 나오는 데 정확한 역을 사용하고 스택을 튀어 나오게하는 한 스택에 푸시하기 위해 프리 또는 포스트 증가 또는 프리 또는 포스트 감소를 사용할 수 있습니다. 운영 체제는 선택된 스택 사용 모델을 준수합니다. 사실, 일부 임베디드 시스템 및 일부 교육 시스템에서는 MIPS 스택이 증가하고 있습니다.)
답변
특정 시스템에서 스택은 높은 메모리 주소에서 시작하여 아래쪽으로 낮은 메모리 주소로 “증가”합니다. (낮은 것에서 높은 것까지 대칭 경우도 존재합니다)
그리고 당신이 -4와 +4에서 변경했기 때문에 그것이 그것이 정확하다는 것을 의미하지는 않습니다. 실행중인 프로그램의 메모리 레이아웃은 더 복잡하고이 간단한 프로그램에서 즉시 충돌하지 않았다는 사실에 기여할 수있는 다른 많은 요소에 따라 달라집니다.
답변
스택 포인터는 할당 된 스택 메모리와 할당되지 않은 스택 메모리 사이의 경계를 가리 킵니다. 아래쪽으로 자란다는 것은 할당 된 스택 공간에서 첫 번째 구조 의 시작 을 가리키고 다른 할당 된 항목은 더 큰 주소를 따르는 것을 의미합니다. 포인터가 할당 된 구조의 시작을 가리 키도록하는 것이 다른 방법보다 훨씬 일반적입니다.
요즘 많은 시스템에는 로컬 가변 스토리지가 산재되어있는 콜 체인을 파악하기 위해 다소 안정적으로 풀 수있는 스택 프레임에 대한 별도의 레지스터 가 있습니다. 방법이 스택 프레임 레지스터가 가리키는 끝나는 몇 가지 아키텍처 수단에 설정 한 뒤에 스택 포인터와 달리 지역 변수 저장을 하기 전에 그것. 따라서이 스택 프레임 레지스터를 사용하려면 음의 인덱싱이 필요합니다.
스택 프레임과 인덱싱은 컴파일 된 컴퓨터 언어의 한 측면이므로 어셈블리 언어 프로그래머가 아닌 “부자연 스러움”을 처리해야하는 컴파일러의 코드 생성기입니다.
따라서 스택을 선택하여 아래로 자라는 좋은 역사적 이유가 있었지만 (일부 어셈블리 언어로 프로그래밍하고 적절한 스택 프레임을 설정하지 않아도 일부는 유지되지만) 가시성이 떨어졌습니다.