관리 메뉴

IT 컴퓨터공학 자료실

중급편 7. 스택과 자동 변수 본문

컴퓨터공학/포인터

중급편 7. 스택과 자동 변수

윤맨1 2015. 6. 30. 11:20

                                       포인터 토대가 된 책

                                        스택과 자동 변수

malloc (3)는 메모리를 확보하고, malloc (3)을 설명 할 때 언급했다. 그러나 하나의 프로세스가 사용하는 메모리에는 여러 종류가있다. 표준 UNIX에서는 가상 메모리와 함께 다음 레이아웃 메모리가 사용된다.

00000000 여유 메모리 (NULL 포인터에 의한 참조를 검출한다)
00001000 코드 세그먼트 (CS)의 시작
00001FFF 코드 세그먼트 (CS)의 종료
00002000 데이터 세그먼트 (DS)의 시작
0000FFFF 데이터 세그먼트 (DS)의 종료
00010000 공간의 시작
FFFFC000 스택 탑
FFFFFFFF 스택의 바닥

여기서 중요한 것은 "스택"이다. 데이터에는 두 가지의 구별이있다. 비유로 말하는 것이 좋겠다.

예를 들어 기업의 회계 아르바이트를한다고 생각하자. 이때 장부 및 절차와 메모장과 계산기를 모아 일을 시작하는 것이다. 절차는 어떤 순서로 일을 해야할지가 적혀있다. 그래서 절차가 "코드 세그먼트 '에 해당한다. 계산기는 실제 계산하기 때문에 CPU에 해당한다. 여기에서 장부는 계산 된 결과를 내보낼 것이며, 마음대로 써도 아무도 못해 메모장과는 전혀 다른 점에 유의하기 바란다. 즉, 장부는 이미 데이터가 준비되어 있으며, 최종 결과를 쓸 것이다. 이 "장부"이 데이터 세그먼트에 해당한다. 반면 마음대로 사용해 좋은 것이 '메모장'이다. 이 스택 세그먼트에 해당한다.

는 과정은 어떻게 스택 세그먼트를 사용하는 것이다. 대략 4 가지 방법이있다.

  1. 함수의 자동 변수를 확보한다.
  2. 함수에 주어진 인수를 놓아 둔다.
  3. 함수를 호출 할 때 함수의 반환 시설을 기록해 둔다.
  4. 식 평가시 레지스터에두고 수없는 데이터를 임시 저장한다.

이 중 4 번째 기능은 컴파일러 동작에 대한 자세한에서 포함되기 때문에, 여기에서는 논의한다. 그러나 이른바 '자동 변수 "이 스택에 할당되는 것이다. "자동 변수"는 함수 안에서만 유효하며 함수에서 빠져 나오면 자동으로 삭제된다는 식으로 C 언어 교과서에 써있다. 이것은 메모장 인 스택의 사용 방법에서 비롯됩니다.

스택 정보 과학에서 매우 중요한 데이터 형이기도하다. 이것은 위에 순서대로 쌓여 간다 "선반"을 이미지하면 ​​좋다. 함수 A가 불린 단계에서는 다음과 같은 스택이 구성된다.

FFFFBFC0 함수 A의 자동 변수 (그리고 새로운 스택 상단)
FFFFBFE8 함수 A가 return하는 앞
FFFFBFF0 함수 A의 인수
FFFFC000 (원래 스택 상단)
FFFFFFFF 스택의 바닥
(메모리 이미지 A)

또한 함수 A에서의 함수 B를 호출하면 다음과 같이된다.

FFFFBFA0 함수 B의 자동 변수 (그리고 새로운 스택 상단)
FFFFBFB0 함수 B의 return하는 대상 (함수 A의 CS의 주소가된다)
FFFFBFB8 함수 B의 인수
FFFFBFC0 함수 A의 자동 변수
FFFFBFE8 함수 A가 return하는 앞
FFFFBFF0 함수 A의 인수
FFFFC000 (원래 스택 상단)
FFFFFFFF 스택의 바닥
(메모리 이미지 B)

즉, 스택 위쪽으로 뻗어 나간다. 여기서 함수 B에서 return 그러자했을 것입니다. 그러면 메모리 이미지 A로 돌아 오게된다. 사실, 스택 관리 효율성 문제에서 메모리 내용을 삭제하지 않는다. 그래서 다음 코드는 전혀 틀립니다 작동하지 않을 것이며, 전혀 위험한 코드 써야 아니지만, 달릴지도 모른다.

#include <stdio.h>
char * sub ()
{
    / * 자동 변수이며, 스택에 확보 * /
    char str [] = { "This is Wrong!"};  
    / * 스택 위를 가리키는 포인터를 반환 * /
    return str;      
}

void main ()
{
     int i;
     char s [20];
     char * q;

    / * q는 함수 sub에서 확보 된 이미 무효
     스택의 주소가 입력 * /
     q = sub ();  
     for (i = 0; i <20; i ++) {
          / * 유효하지 않은 것 스택에 값을 유효한
          스택에 복사 * /
          s [i] = * q ++;  
     }
     / * 달려야 ​​아니지만, 작동 * /
     printf ( "% s \ n", s);  
}

gcc로 컴파일하면 "warning : function returns address of local variable"라는 경고가 나오지만, 실제로 Linux에서 실행 해 보면 "This is Wrong!"가 표시됩니다.이 경고는 역시 "함수가 지역 변수의 주소를 반환하고있다"는 경고이다.

그러나 메인 함수를 다음과 같이 고쳐 쓰면 제대로 움직이지 않는다.

void main ()
{
     / * 작동하지 않고 쓰레기를 출력하기 * /
     printf ( "% s \ n", sub ());  
}

이것은 왜 일까하고 말하면, 제 1의 예에서는 비활성화 된 스택을 덮어 같은 함수를 호출하기 전에 비활성화 된 스택에서 유효한 스택에 문자열을 게시하여 다음 스택을 덮어 쓰기 함수 printf (3)을 호출하고 있지만, 제 2의 예에서는 직접 printf (3)을 호출하므로, 함수 sub ()의 반환 주소는 벌써 printf (3) 자동 변수로 사용 자매, "This is Wrong!"문자열이 사라 떠나 버린 있기 때문이다. (만약을 위해, 제 1의 예는 움직 였지만 전혀 잘못된 프로그램이다. 절대로 흉내 내고는한다.)

그래서 자신이 사용하는 포인터가 "무엇을"가리키는 것인가라는 것을 프로그래머는 항상 염두에 두지 않으면 안된다. 이 '무엇을'에, 그것은 스택인가, DS인지, 혹은 malloc (3)에서 확보 된 메모리인지하는 것이 포함되어야하고 이러한 혼합 같은 배열은 혼란 전이기 때문에 절대적으로 만들어야 아니다. . 덧붙여서, malloc (3)을 확보하는 메모리는 DS에도 스택도없이 DS의 마지막에서 스택 상단까지의 '여유 메모리'영역에 해당 세그먼트를 malloc (3)을 확보한다. 이 컴파일러 용어로는 '힙 메모리'라고 부른다.

것은 이런 것도있을 수있다.

void sub ()
{
    char str [80] = 
       {여기에 기계어로 프로그램을 작성했습니다};
    (int *) str [88] = (int) str;
}

예를 들어, str이 가리키는 스택 주소가 0xFFFF8000 이라며 그 8 바이트 후 함수 sub ()의 return 주소가 적혀 있다고하자. 이때 그 주소에 str 자신의 주소를 주었다고한다. 그러면이 함수를 호출 해 원래대로 돌아갈 때 재 작성된 return 주소로 돌아 가려고한다. 즉, 배열 str 안의 코드를 프로그램이라고 믿고 실행하려고한다. 사실은 이것이 유명한 Internet Worm 사건에서 사용 된 같은 해킹 사건에 사용되는 기술이며, 공격자가 제공 한 코드를 억지로 실행시키는 사악한 기술이다. 그러나 현재는 메모리의 실행 플래그가 이런 기술은 사용할 수 없게되어있는 경우도있다. 현대적인 프로그램은 어떻게 이것이 동작 하든지, 이런 사악한 기술은 사용해서는 안된다.

이 예를 나타낸 것은 C 언어의 포인터라는 것이 얼마나 쉽게 폭주를 일으키는 충돌의 근원이되는 하는지를 나타 내기 위해서이다. 포인터는 강력한 기능이지만, 그것을 사용하는 경우에는 상당한주의가 필요함을 명기하기 바란다.