반복 출력, REPEAT 디렉티브 & 연산자, 링크드 리스트 예제
반복 블럭은 어셈블리어 구문들을 여러번 반복하게 해주는 '디렉티브'이다. 이들의 특징은 반복횟수가 상수에 의해 결정된다는 것이다. 이들은 우리가 흔히 아는 반복문과는 약간 다르다. 지금 말하는 반복 블럭은 일종의 매크로와 같은 역할을 하는 것임을 깊이 새기기 바란다.
반복 블럭에는 WHILE, REPEAT, FOR, FORC 등이 있는데, 대표적으로 숫자에 적용되어 가장 자주 쓰이는 REPEAT에 대해서 알아보자.
다른 반복 디렉티브들은 수식, 심볼, 문자에 대해 반복하는 반면, REPEAT 디렉티브는 상수수식의 값만큼 반복하기 때문에, 그만큼 쓰임새가 크다.
| REPEAT 상수수식 구문들... ENDM |
| .data array LABEL DWORD iVal = 10 REPEAT 100 DWORD iVal iVal = iVal + 10 ENDM |
| array DWORD 10, 20, 30, 40, ... 1000 |
이 연산자는 조금은 특이한 연산자이다. 예제를 먼저 살펴보자.
| list WORD 10, 20, 30, 40 ListSize = ($ - list) / 2 ; ListSIze는 4 |
본회에서 배운 내용을 복습하는 의미에서 링크드리스트를 사용하는 간단한 프로그램을 작성해 보겠다.
링크드 리스트(Linked List)는 연결리스트라고도 하며, 각각의 노드를 포인터를 이용하여 연결함을로써 구현된다. 그림 2와 같은 구조를 떠올리면 이해하기 쉬울 것이다.(사실 여기까지 강좌를 읽으며 이해하고 계신 분이라면 충분히 알고 있을 것이다.) 그림 2는 단방향의 링크드리스트를 나타낸다.
이제 구조체를 정의해 보자. 구조체의 정의는 너무나도 간단하다.
| ListNode STRUCT NodeData DWORD ? ; 노드의 데이터값을 갖는다. NodePtr DWORD ? ; 다음 노드의 주소를 갖는다. ListNode ENDS |
| TotalNodeCount = 15 NULL = 0 Counter = 0 .data LinkedList LABEL DWORD ; (1) REPEAT TotalNodeCount ; (2) Counter = Counter + 1 ; (3) ListNode <Counter, ($ + (Counter * SIZEOF ListNode))> ENDM ListNode <0, NULL> ; (4) 꼬리노드 |
(1) 먼저 LABEL디렉티브가 나왔는데, LABEL디렉티브 뒤에 나온 DWORD는 형식적인 것이다. 왜냐하면 나중에 사용할 때는 어차피 ListNode인 것처럼 사용하기 때문이다. LinkedList라는 데이터 레이블은 링크드리스트 첫 번째 노드에 대한 데이터 레이블로 쓰이게 된다.
(2) REPEAT디렉티브는 첫 번째 인자의 상수값만큼(여기서는 15) 루프를 돌리게 된다.
(3) 따라서 Count가 1씩 증가되면서 15개의 ListNode가 선언된다. 위 코드에서는 선언과 동시에 초기화를 시켜주고 있는데, 두 번째 필드에서는 ($ + (Counter * SIZEOF ListNode))을 이용하여 다음 노드의 오프셋을 얻어온다. $값은 LinkedList레이블이 가리키는 오프셋을 갖고, REPEAT블럭 내에서 변하지 않는다. 왜냐하면 루프가 돌기 이전에 $연산자가 계산되기 때문이다.
(3) 결과적으로, 꼬리노드를 포함한 16개의 노드가 모두 연결된다.
이제 본격적으로 main프로시져를 정의해 보겠다. 다음의 코드는 데이터 영역에서 만든 링크드 리스트를 탐색하며 각각의 NodeData를 찍고난 후 종료한다.
| .code main PROC ; (1) mov esi, OFFSET LinkedList ; NodeData 필드의 모든 정수들을 보여준다. NextNode: ; (2)꼬리노드인지 체크해 본다. mov eax, (ListNode PTR [esi]) .NextPtr cmp eax, NULL je quit ; (3)NodeData를 출력한다. mov eax, (ListNode PTR [esi]) .NodeData call WriteDec call Crlf ; (4)포인터를 다음 노드로 옮긴다. mov esi, (ListNode PTR [esi]) .NextPtr jmp NextNode quit: exit main ENDP END main |
(2) 루프를 계속 돌 것인지를 결정하는 부분이다. esi가 가리키는 주소에 존재하는 ListNode형 구조체변수의 NextPtr이라는 필드를 읽어서 eax에 넣는다. 물론 eax에 넣는 이유는 NULL인지 판단하기 위해서다. NextPtr필드가 NULL이라는 것은 더이상 다음 노드가 없다는 뜻이기 때문이다. 만약 NULL이라면 quit레이블로 점프하여 프로그램을 종료하게 된다.(NULL은 데이터 영역에서 정의한 기호상수이며 0과 같다.)
(3) esi가 가리키는 주소에 존재하는 ListNode형 구조체변수의 NodeData필드의 값을 eax에 읽어들인 뒤, 해당 데이터를 출력하고 개행문자를 출력한다. 개행문자는 우리가 텍스트 에디터에서 엔터를 누를 때와 같은 효과를 내는 문자이다.
(4) 현재 esi가 가리키는 ListNode형 구조체변수의 NextPtr필드 값을 다시 esi에 복사해 넣는다. 따라서 esi는 다음 노드의 주소를 갖게 될 것이다. 그 다음 다시 NextNode레이블로 돌아가서 지금까지 해온 과정((2)~(4))을 반복한다.
이번 회에서는 구조체와 매크로에 대해 배워보았다. 적어도 한 가지의 고급언어를 프로그래밍해보신 여러분들은 어셈블리어를 보면서 자신이 다뤘던 프로그래밍 언어들이 어떻게해서 어셈블리어로 구현될지에 대해서도 머릿속에 조금씩 떠오르리라 믿는다. 다음 회에서는 32비트 윈도우즈 프로그래밍을 간단히 배워볼 것이다. 그러나 직접 어셈블리어로 윈도우 프로그래밍을 하는 것은 단지 창 하나 띄워보는 정도로 그치고, IA-32의 메모리 관리방법에 좀더 중점을 두고 집필할 예정이다. 이쪽을 배우는 것이 좀더 여러분에게 도움이 될 것 같아서이다. 다음 회에는 좀더 흥미로운 주제로 여러분에게 다가갈 생각이다. 그럼 이만 줄이겠다.
- CPU 레지스터 (0)2007/03/15
- 반복 출력, REPEAT 디렉티브 & 연산자, 링크드 리... (0)2006/07/10
- UNION 사용하기, 매크로란? 매크로 정의하기, 매크... (0)2006/07/10
- 구조체란? 구조체 선언, 구조체 변수 사용하기 (0)2006/07/10
- 버블소트 (0)2006/07/10

수안이의 컴퓨터 연구실



Leave your greetings.