티스토리 뷰

[10장. 64비트 모드로 전환하자.]를 읽다보니, kReadCPUID()함수를 어셈블리어로 작성했는데, 포인터를 다루더군요. 한번 정리할 필요가 있다고 생각되어 어셈블리어에서 포인터를 어떻게 다루는지 정리해보겠습니다.


int main()

{

...

DWORD dwEAX, dwEBX, dwECX, dwEDX;


kReadCPUID(0x80000001, &dwEAX, &dwEBX, &dwECX, &dwEDX);

..

}


현재는 32비트 보호모드 상태이고, main문에서 CPU가 IA-32e모드를 지원하는지 알아보기 위한 함수(kReadCPUID)를 호출합니다.

kReadCPUID는 어셈블리어로 작성되었습니다.


1    global kReadCPUID

2

3    SECTION .text

4

5    kReadCPUID:

6        push ebp

7        mov ebp, esp

8        push eax

9        push ebx

10       push ecx

11       push edx

12       push esi

13

14       mov eax, dword [ ebp + 8 ]

15       cpuid

16

17       mov esi, dword [ ebp + 12 ]

18       mov dword [ esi ], eax

19

20       mov esi, dword [ebp + 16 ]

21       mov dword [ esi ], ebx

....


kReadCPUID함수에서 살펴볼 부분은 17~18 Line입니다. 이 부분이 포인터에 값을 채워넣는 부분입니다. 조금 더 자세히 보겠습니다.

15 line에 cpuid를 호출하면 우리가 원하는 결과값이 eax를 저장됩니다. 우리는 eax의 데이터를 kReadCPUID의 매개변수(&dwEAX)로 넘겨주면 됩니다. 17~18 Line이 이러한 역할을 하는 코드입니다.


우선, 어셈블리어에서 [ ]에 대해서 설명하겠습니다. [ 0x1000 ]는 주소 0x1000에 들어있는 값을 말합니다. 그런데, 데이터의 크기를 가리켜 줘야겠지요? 얻고 싶은 데이터의 크기가 1바이트면 0x1000에 있는 데이터만 꺼내올 것이고 2바이트면 0x1000과 0x1001에 있는 데이터를 합쳐서 가져올 것입니다. 그러니 컴퓨터한테 '0x1000주소에서 1바이트 크기의 데이터를 가져와!'라는 명령을 dbyte [ 0x1000 ]로 줄 수 있습니다.


17 line만 해석해보면, ebp에서 + 12만큼의 주소부터 dword크기 만큼의 데이터(ebp + 12 ~ ebp + 15, 4byte)를 esi레지스터에 저장하라는 명령입니다. 여기서 dword는 4byte로 정의되어 있습니다.


그러면, 본론으로 돌아와서 eax의 데이터를 변수 dwEAX에 어떻게 저장하는지 살펴보겠습니다. 아래는 kReadCPUID함수가 호출되고 18 line까지 처리한 후의 메모리 모습입니다.


[ 그림1. 18 line까지의 메모리 구조 ]


주소 ebp + 12에 들어있는 데이터 값은 변수 dwEAX의 주소 값입니다. 그러니 17 line은 변수 dwEAX의 주소값을 esi에 넣으라는 명령입니다.

18 line은 eax의 데이터를 변수 dwEAX의 주소값이 가리키는 데이터. 곧, dwEAX를 가리킵니다. dwEAX에 eax를 넣으라는 명령이 됩니다.


이렇게 c언어의 포인터를 어셈블리어에서 어떻게 처리할 수 있는지 살펴보았습니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함