스택이 일반적으로 아래쪽으로 커지는 이유는 무엇입니까?


95

개인적으로 익숙한 아키텍처 (x86, 6502 등)에서 스택은 일반적으로 아래로 커집니다 (즉, 스택에 푸시 된 모든 항목은 증가 된 SP가 아닌 감소 된 SP가됩니다).

이것에 대한 역사적 근거가 궁금합니다. 통합 된 주소 공간에서는 데이터 세그먼트의 반대쪽 끝에서 스택을 시작하는 것이 편리하다는 것을 알고 있습니다 (예를 들어). 따라서 두면이 중간에서 충돌하는 경우에만 문제가 발생합니다. 하지만 왜 스택이 전통적으로 최상위 부분을 차지합니까? 특히 이것이 "개념적"모델의 반대 인 점을 감안할 때?

(또한 6502 아키텍처에서 스택은 단일 256 바이트 페이지로 제한되어 있어도 아래쪽으로 성장하며이 방향 선택은 임의적으로 보입니다.)

답변:


52

역사적 근거에 관해서는 확실히 말할 수 없습니다 (제가 디자인하지 않았기 때문에). 이 문제에 대한 내 생각 은 초기 CPU가 원래 프로그램 카운터를 0으로 설정했고 다른 쪽 끝에서 스택을 시작하고 코드가 자연스럽게 위로 성장하기 때문에 아래로 성장하려는 자연스러운 욕망이었습니다.

제쳐두고, 리셋시 프로그램 카운터를 0으로 설정하는 것은 모든 초기 CPU에 해당하는 것은 아닙니다 . 예를 들어 Motorola 6809는 주소에서 프로그램 카운터를 가져 오므 0xfffe/f로 해당 주소 (일반적으로 ROM에 국한되지 않음)에 제공된 항목에 따라 임의의 위치에서 실행할 수 있습니다.

일부 역사적 시스템이 수행하는 첫 번째 작업 중 하나는 기록 된 동일한 값을 다시 읽을 위치를 찾을 때까지 메모리를 스캔하여 실제 RAM이 설치된 것을 알 수 있도록하는 것입니다 (예 : 64K 주소 공간이있는 z80). 64K 또는 RAM이 반드시 필요하지는 않았습니다. 사실 64K는 초기 에 방대 했을 것 입니다.) 최상위 실제 주소를 찾으면 스택 포인터를 적절하게 설정하고 서브 루틴 호출을 시작할 수 있습니다. 이 스캔은 일반적으로 시작의 일부로 ROM에서 코드를 실행하는 CPU에 의해 수행됩니다.

스택 성장과 관련하여 모든 스택이 아래쪽으로 성장하는 것은 아닙니다 . 자세한 내용 은 이 답변 을 참조하십시오.


1
나는 Z80 RAM 감지 전략 이야기를 좋아합니다. 텍스트 세그먼트가 위쪽으로 늘어남에 따라 배치된다는 것은 이해가갑니다. 과거의 프로그래머는 스택보다 그 의미를 다루는 데 다소 직접적인 접촉을 가졌습니다. paxdiablo에게 감사합니다. 스택 구현의 대체 형식 집합에 대한 포인터도 매우 흥미 롭습니다.
Ben Zotto 2010 년

초기 메모리는 크기를 알릴 수있는 방법이없고 수동으로 계산해야합니까?
phuclv 2015 년

1
@ LưuVĩnhPhúc, 나는 당신이 내 뒤에 한 세대 (또는 두 세대)라고 가정해야합니다. 나는 여전히 TRS-80 모델 3 방법을 기억하고있다. 날짜와 시간 은 사용자 가 부팅 할 때 물어 보는 것이다 . 메모리의 상한값을 설정하는 메모리 스캐너를 갖는 것은 그날의 최첨단 기술로 간주되었습니다. :-) Windows가 부팅 할 때마다 시간 또는 보유한 메모리 양을 요청하면 어떻게 될지 상상할 수 있습니까?
paxdiablo 2015 년

1
실제로 Zilog Z80 문서에 따르면 PC 레지스터를 0000h로 설정하고 실행하면 부품이 시작됩니다. 인터럽트 모드를 0으로 설정하고 인터럽트를 비활성화하며 I 및 R 레지스터도 0으로 설정합니다. 그 후 실행을 시작합니다. 0000h에 코드 실행을 시작합니다. 해당 코드는 서브 루틴을 호출하거나 인터럽트를 활성화하기 전에 스택 포인터를 초기화해야합니다. 설명하는대로 작동하는 Z80을 판매하는 공급 업체는 무엇입니까?
MikeB 2015

1
마이크, 미안 해요 더 명확 했어야 했어요 CPU가 메모리를 스캔했다고 말했을 때 이것이 CPU 자체의 기능이라는 의미는 아닙니다. 실제로 ROM의 프로그램에서 제어되었습니다. 명확히하겠습니다.
paxdiablo

21

내가 들었던 한 가지 좋은 설명은 과거에 일부 기계는 서명되지 않은 오프셋 만 가질 수 있었기 때문에 스택이 아래쪽으로 커져서 네거티브 오프셋을 가짜로 만드는 추가 명령을 잃지 않고 로컬을 공격 할 수 있기를 원한다는 것입니다.


7

Stanley Mazor (4004 및 8080 설계자)는 "Intel Microprocessors : 8008 to 8086" 에서 8080 (그리고 결국 8086)에 대해 스택 성장 방향이 어떻게 선택되었는지 설명합니다 .

스택 포인터는 사용자 프로그램에서 스택으로의 인덱싱 (양수 인덱싱)을 단순화하고 전면 패널에서 스택의 내용을 간단하게 표시하기 위해 "내리막"(스택이 더 낮은 메모리로 이동)을 실행하도록 선택되었습니다.


6

한 가지 가능한 이유는 정렬을 단순화하기 때문일 수 있습니다. 4 바이트 경계에 배치해야하는 스택에 로컬 변수를 배치하는 경우 스택 포인터에서 객체의 크기를 뺀 다음 두 개의 하위 비트를 0으로 제거하여 올바르게 정렬 된 주소를 얻을 수 있습니다. 스택이 위로 커지면 정렬을 확인하는 것이 약간 까다로워집니다.


1
컴퓨터는 빼지 않습니다. 그들은 2의 칭찬을 더합니다. 빼기로하는 모든 것은 실제로 더하여 수행됩니다. 컴퓨터에는 감산기가 아니라 가산기가 있습니다.
jww

1
@jww-차이가없는 구별입니다. 나는 컴퓨터가 단지 빼기 만 더하지 않는다고 주장 할 수도있다! 이 답변의 목적 상 실제로는 중요하지 않지만 대부분의 ALU는 동일한 성능으로 덧셈과 뺄셈을 모두 지원 하는 회로 를 사용 합니다 . 즉, A - B개념적으로 구현 될 수 있지만 A + (-B)(즉,에 대한 별도의 부정 단계 B) 실제로는 그렇지 않습니다.
BeeOnRope

@jww 당신의 nitpick은 초기 컴퓨터에서 잘못되었습니다. 2의 보수가 승리하는 데 시간이 좀 걸렸고, 성공할 때까지 1의 보수와 부호와 크기를 사용하는 컴퓨터가 있었고 대신 다른 것들을 사용했습니다. 이러한 구현으로 더하기와 빼기의 이점이있을 수 있습니다. 따라서 추가 정보가없는 경우이를 스택 방향과 같은 주소 지정 체계 선택에 영향을주는 가능한 요인으로 배제하는 것은 잘못된 것입니다.
mtraceur

4

IIRC 힙이 위쪽으로 커지기 때문에 스택이 아래쪽으로 커집니다. 그 반대 일 수도 있습니다.


5
상향 성장하는 힙은 경우에 따라 효율적인 재 할당을 허용하지만 하향 성장하는 힙은 거의 불가능합니다.
Peter Cordes dec.

@PeterCordes 왜?
Yashas

3
@Yashas : 복사하지 않고 매핑을 확장하려면 개체 뒤에realloc(3) 더 많은 공간이 필요 하기 때문 입니다. 임의의 사용되지 않은 공간이 뒤따를 때 동일한 객체의 반복적 인 재 할당이 가능합니다.
Peter Cordes 2018 년

2

순전히 디자인 결정이라고 생각합니다. 그들 모두가 아래로 성장하는 것은 아닙니다 . 다른 아키텍처에서의 스택 성장 방향에 대한 좋은 논의는 이 SO 스레드 를 참조하십시오 .


1

이 대회는 IBM 704와 그 악명 높은 "감소 레지스터"에서 시작되었다고 생각합니다. 현대 연설 명령의 오프셋 필드를 부를 것이다, 그러나 요점은 그들이 갔다이다 다운 , 하지 까지 .


1

2c 만 더 :

언급 된 모든 역사적 근거를 넘어서는 현대 프로세서에서 유효한 이유가 없다고 확신합니다. 모든 프로세서는 서명 된 오프셋을 취할 수 있으며, 여러 스레드를 처리하기 시작한 이후로 힙 / 스택 거리를 최대화하는 것은 다소 문제가됩니다.

저는 개인적으로 이것이 보안 설계 결함이라고 생각합니다. 예를 들어 x64 아키텍처의 설계자가 스택 성장 방향을 바꾸었다면 대부분의 스택 버퍼 오버플로가 제거되었을 것입니다. 이는 일종의 큰 문제입니다. (현이 위로 자라기 때문에).


0

확실하지는 않지만 예전에 VAX / VMS를위한 프로그래밍을했습니다. 나는 메모리의 한 부분 (힙 ??)이 올라가고 스택이 내려가는 것을 기억하는 것 같습니다. 두 사람이 만났을 때 당신은 기억이 부족했습니다.


1
이것은 사실이지만 왜 힙이 위쪽으로 성장하고 반대 방향이 아닌 이유는 무엇입니까?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 2015-04-22

0

최소 임베디드 시스템에서 내림차순 스택 증가의 한 가지 장점은 단일 RAM 청크를 페이지 O와 페이지 1에 중복 매핑 할 수있어 0x000에서 시작하여 0 페이지 변수를 할당하고 스택을 0x1FF에서 아래쪽으로 확장하여 최대 변수를 덮어 쓰기 전에 커야하는 양.

6502의 원래 설계 목표 중 하나는 예를 들어 6530과 결합하여 1KB의 프로그램 ROM, 타이머, I / O 및 64 바이트의 RAM을 공유하는 2 칩 마이크로 컨트롤러 시스템을 만드는 것이 었습니다. 스택과 페이지 제로 변수 사이. 이에 비해 8080 또는 6800을 기반으로 한 당시 최소 임베디드 시스템은 4 개 또는 5 개의 칩이 될 것입니다.

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