본문 바로가기
코스웨어/12년 내장형하드웨어

[Assembly] 9월 3일 업무일지 By.정철

by 알 수 없는 사용자 2012. 9. 3.
728x90
반응형

* PUSH와 POP

push 하게 되면 ESP자리에 어떠한 값을 사용하고

ESP를 상승 시킵니다.

operand에는 레지스터, 메모리, 상수값이 올 수 있습니다.


pop을 하게 되면 ESP자리에 잇는 값을 지정된 곳으로 가져오고,

ESP를 하락 시킵니다.

operand에는 레지스터, 메모리가 올 수 있습니다.


- push와 pop은 memory to memory가 가능합니다  (예외사항)


push    ebp
push    esp
push    edx


push는 레지스터에도 적용이 가능합니다. 다만,


push    eip    eip에 접근은 불가능합니다.

eip가 undefined symbol이라고 에러 메세지를 출력하면서

컴파일을 해주지 않습니다.


pushad와 popad

pushad는 레지스터를 한꺼번에 스택으로 옯기고,

popad는 스택에 잇는 정보를 레지스터로 한꺼번에 옮긴다.

ad는 all double word를 뜻한다. (eax, ebx 등 double word를 뜻함)

d를 빼면 ax, bx 등을 푸쉬하게 된다.


<all 하게 되면 위의 순서데로 메모리에 push 됩니다>


여기서 문제 push와 pop명령에 1byte가 존재하지 않음.

char 형을 선언하면

이런 복잡하고 귀찮은 구조로 메모리에 저장되게 된다.

임베디드 처럼 메모리에 압박에 시달리거나,

수천 수만 수억명의 정보를 저장하는 일이 아닌

일반적인 상황에서는 4byte최적화하는 것이 프로그램이 유리하게 흘러가게 된다.

(물론 3byte메모리 손실은 있지만, 4G에 3byte 정도야 뭐....)


* context switching


문맥 교환
(Context Switch)이란 하나의 프로세스가 CPU를 사용 중인 상태에서 다른

프로세스가 CPU를 사용하도록 하기 위해, 이전의 프로세스의 상태(문맥)를 보관하고

새로운 프로세스의 상태를 적재하는 작업을 말한다. 한 프로세스의 문맥은 그 프로세스

프로세스 제어 블록에 기록되어 있다.


콘텍스트 스위칭은 현재 실행중인 프로세서의 레지스터 정보를 스택에 밀어 넣고

다른 프로그램 상태를 레지스터에 적재하는 작업을 말한다.



http://ko.wikipedia.org/wiki/%EB%AC%B8%EB%A7%A5_%EA%B5%90%ED%99%98

* 의문의 코드


#include <stdio.h>

void test1(intint);
void test2();

int main()
{
  int A = 100;
  int B = 200;

  printf("main  :: A = %08X\n"&A);
  printf("main  :: B = %08X\n"&B);
  
  test1(A + 1, B + 1);

  return 0;
}

void test1(int A, int B)
{
  int C = 300;

  printf("test1\n");
  printf("test1 :: A = %08X\n"&A);
  printf("test1 :: B = %08X\n"&B);
  printf("test1 :: C = %08X\n"&C);

  *(&C + 2= (int)test2;  //의문의 코드
  getchar();
  
  return ;
}

void test2()
{
  printf("test2\n");

  return ;
}


위 코드의는 그냥 흔한 코드다

다만, 우리는 test2() 함수를 호출 하지 않았다.

그렇다. 화면에 test2가 찍힐일은 없다고 믿었다.

<실행결과>

그런데 모니터에 test2가 찍혔다.................

뭥미...............


* 함수호출 구조


그림을 보고 이해를 합시다.

1. 우선 메인함수에 잇는 지역변수가 EBP에서 위로 순서 대로 생성된다.

2. 함수가 호출 된다.

3. 함수인자를 함수호출 규약에 따라 스택에 생성한다.

4. 함수 다음 EIP를 스택에 push한다.

5. EBP에 ESP를 집어 넣는다.

6. ESP를 상승 시킨다.


이 과정을 비주얼 스튜디오에서 디스어셈블해서

아주 적날하게 한번 들여다 보도록 합시다.


8:        int A = 100;
00401048   mov         dword ptr [ebp-4],64h
9:        int B = 200;
0040104F   mov         dword ptr [ebp-8],0C8h
10:
11:       printf("main  :: A = %08X\n", &A);
00401056   lea         eax,[ebp-4]
00401059   push        eax
0040105A   push        offset string "main  :: A = %08X\n" (00420034)
0040105F   call        printf (00401200)
00401064   add         esp,8
12:       printf("main  :: B = %08X\n", &B);
00401067   lea         ecx,[ebp-8]
0040106A   push        ecx
0040106B   push        offset string "main  :: B = %08X\n" (0042001c)
00401070   call        printf (00401200)
00401075   add         esp,8
13:
14:       test1(A + 1, B + 1);
00401078   mov         edx,dword ptr [ebp-8]
0040107B   add         edx,1
0040107E   push        edx
0040107F   mov         eax,dword ptr [ebp-4]
00401082   add         eax,1
00401085   push        eax
00401086   call        @ILT+0(_test1) (00401005)
0040108B   add         esp,8

8,9 번 라인은 변수 A,B에 100과 200을 삽입하는 코드 입니다.

11,12 번 라인에서 각 변수의 주소값을 출력했습니다.


이제 중요한 함수호출

ebx에 무언가를 넣습니다. ebp-8?

9번 라인을 봅시다.


9:        int B = 200;
0040104F   mov         dword ptr [ebp-8],0C8h


ebp는 스택의 베이스 즉, 가장 아랫부분 입니다.

변수 A는 스택의 가장 아랫 부분에 생깁니다. int가 4byte니까

ebp-4로 되있겠네요.

확인해 볼까요....


8:        int A = 100;
00401048   mov         dword ptr [ebp-4],64h


확실하네요. 스택 베이스 -4 부분에 100이 들어가고

스택베이스 -8부분에는 200이 들어갑니다.

고로 함수호출 부분에서 인자 B부터 스택에 밀어 넣는다는 것을 알 수 있습니다.

아마도 cdecl에 따라서 함수를 호출 하나보네요. (함수호출규약 참고)


이렇게 B와 A를 차례로 푸쉬하고

call을 하게 되는데, 이 call은 2가지 역활을 수행합니다.


1. 함수가 끝났을 떄, 다음 수행할 곳을 스택에 푸쉬합니다.

2. 함수로 점프를 하게 됩니다. (EIP = &test1)

(스택 오퍼레이션입니다 : push)


<호출 전후 비교>

-호출 전

-호출 후


ESP자리에 함수호출 다음 부분의 주소가 적혀 있습니다.

즉 함수호출할때 다음 수행 부분을 스택에 적어 보관하고 함수쪽으로 점프를 합니다.

함수실행이 끝난다음 돌아오기 위해서 입니다.


이제 함수가 수행되고 함수가 리턴될때 (ret)

1. EIP에 스택에 밀어넣은 주소를 다시 돌려 줍니다. (pop)

2. 메인함수로 다시 돌아갑니다.

(스택 오퍼레이션입니다 : pop)


* 그렇다면 의문의 코드는

고로 위의 C코드

*(&C + 2= (int)test2;는

test2함수의 주소를 리턴어드레스에 집어 넣는 것임.

그래서 호출이 없지만 test2가 호출 되었음!!



728x90