2009.11.03 23:59 System


우리가 cpu에서 플레그 레지스터라는 이야기를 많이 들어보셨으리라 생각합니다. 일단 어셈블리를 공부하시기로 한 이상 플레그 레지스터를 모르고 넘어간다는 일은 수동기어를 장착한 차량에서 기어바꿀줄 모르고 1단으로만 기어를 놓고 달릴줄만 아는 상황과 비슷하다고 말씀 드릴 수 있습니다. (좀 표현이 이상했나요? ^^a)

플레그레지스터는 CPU내부의 명령에 따른 결과나 명령수행방식을 설정하거나 설정되는 레지스터를 말합니다.

이 레지스터는 다음과 같은 항목으로 구성되어 있습니다. 


CF - carry flag(케리플레그) 바로 전 연산에서 자리를 넘치거나 쉬프트등으로

        밖으로 밀려난 비트값이 1일경우 1로 설정되는 플레그 

PF - Parity flag(패리티 플레그) 바로전에 연산된 값의 결과에 1인 비트수가 짝수일경우 1로 설정됨. 

AF - Adjust flag(보정 플레그) BCD 연산을 위하여 보정에 사용되는 플레그 

ZF - Zero flag(제로 플레그) 바로 위의 연산결과값이 0이 나오거나 비교시 두 값이 같으면 1로 설정 

SF - Sign flag(사인 플레그) 연산결과의 부호를 나타내며 결과값이 양수일때는 0으로 음수일때는 1로 설정 

OF - Overflow flag(오버플로우 플레그) 연산결과가 양의 정수값이나 음의 정수값 범위를 넘칠경우 설정되는 플레그, 케리플레그와 동작이 유사하여 케리플레그와 값이 일치하는 경우도 종종 있다.

이외에도 시스탬종작을 위한 IF , NT , RF , VM , IOPL 등의 플레그가 있지만 오늘 강좌하려는 범위에서

넘어가므로 생략하기로 합니다. 


 그럼 이 플레그들과 명령들과의 관계를 알아보기로 합니다. 이제부터 필요한 준비물이 있습니다. 어셈블리

책 중 CPU명령어가 자세히 나온 책을 하나 선정하여 영향받는 플레그와 영향주는 플레그항목까지 기록된

자료를 준비해 주시기 바랍니다. 어차피 어셈블리 프로그래밍을 한다면 이정도의 준비물은 있어야 합니다. 


 우리가 플레그하면 조건분기명령과 많이 연관을 짓습니다. 만약 ax 레지스터 값이 5인지를 알려면 다음과

같이 합니다. 


cmp ax , 5 
je xxx ;     ax값이 5일경우 점프할곳 
jne yyy ;   ax값이 5가 아닐경우 점프할곳 

이정도 부분까지는 대충 이혜하실수 있어야 다음 부분을 보셔도 이혜가 가시게 됩니다.

위의 명령의 경우 다음과 같이 바꿀수 있습니다.

sub ax , 5 

je xxx ;      ax값이 5일경우 점프할곳 
jne yyy ;    ax값이 5가 아닐경우 점프할곳 

대부분 어셈블리 명령을 여타언어에서의 "if"명령과 많이 연관시켜 생각하기 때문에 "if"와 매우 유사한

기능을 하는 cmp명령이 비교명령으로 생각하여 cmp 명령으로 비교연산을 하는 경우가 생깁니다.

하지만 이는 어셈블리 명령으로 다른 언어를 흉내 내려할때에 사용하는것이지 어셈블리를 무엇때문에

사용하려 하는지에 대하여 고찰해 보아야 할 필요가 있음을 느끼게 하는 대목입니다. 

일단은 먼저 명령과 플레그에 관하여 상관관계를 알아봐야 합니다. 우리거 명령표를 볼때 (좀 자세히 나온것)

영향받는 플레그와 영향주는 플레그가 표기되어 있을것입니다.

예를 들어서,

dec 명령의 경우 명령이 실행에 영향받는 플레그 - 없음

명령이 실행후에 영향주는 플레그                      - OF, SF, ZF, AF, PF 


이 뜻은 dec 명령은 실행시 실행특성에 영향을 주는 플레그는 존재 안하며 실행후 결과연산특성이

적용되는 플레그들은 OF, SF, ZF, AF, PF 가 있다는 뜻입니다. 즉 dec 명령 수행후 결과값이 음수

일경우 SF 가 1로 설정이 되고 (음수이므로) ZF는 0이 되며(0이 아니므로) PF는 결과값의 내부

패리티를 채크하여 1이 짝수개이면 1이 설정되고 홀수개면 0이 설정되게 되어 있다는 뜻입니다.

그러므로 dec 연산을 한후 사용할수 있는 조건분기명령은

dec ax 

jz xxxx ;    결과가 0이면 점프 
js xxxx ;    결과가 음수일경우 
jp xxx ;      결과가 짝수 패리티일경우 

등이 될수 있습니다. 따라서 이러한 사실들로 우리는 cmp 명령이 결과값에 영향을 안주고

플레그에만 영향을 주는 sub명령임을 알 수 있습니다. 여기서 원래라면 플레그와 음수/양수와

부호없는 수의 크기비교에 따른 플레그값의 설정을 설명해야 하지만 지면의 크기와 여러분의

공부를 위하여 여러분께 숙제로 남겨드리기로 하겠습니다. 

(헉.. 돌이 날라오는군요) 

그럼 다음으로 플레그의 용법이 조건분기에만 한하지 않음을 예로 들어보이겠습니다.

이 예중 대표적인 예가 adc 명령입니다.  우리가 64비트수치에다가 어떤 수를 더한다고

생각합니다. 하지만 우리가 쓰는 cpu는 32비트 이므로 64비트 수치를 바로 계산할수

있는 명령은 없습니다. 따라서 먼저 64비트중 하위 32비트를 덧셈을 한 후 더한값이

자리를 넘칠 경우 상위 32비트를 더할때 1을 더 더해주면 됩니다. 바로 이럴때 사용되는

것이 carry flag 입니다. 위에서 설명했듯이 케리플레그는 연산의 자리를 넘치거나 했을때

설정되는 플레그입니다. add 명령은 결과값에 대하여 carry 플레그에 영향을 주는 명령입니다.

따라서 x 라는 64비트 변수를 y라는 64비트 변수로 더한다고 할때 그 연산루틴은 다음과 같이

설정할수 있습니다. 


mov eax , dword ptr y[0] ;  먼저 y의 하위 32비트 값을 얻어서 
add dword ptr x[0] , eax ;   x의 하위 32비트에 더한다음 
mov eax , dword ptr y[4] ;  다음 y의 상위 32비특밧을 얻어서 
adc dword ptr x[4] , eax ;   이전하위 32비트의 더한 넘친자리 수 까지 더하여 x의 상위 32비트에 더한다 

여기서 질문 2가지를 하실수 있게 되실겁니다. 
Q1) adc 는 어떤 일을 하는데 하위에서 자리넘침이 있는지를 알수 있나요? 

A1) 옙, 그건 먼저 add로 연산했을 경우 add 명령은 CF (carry flag)에 결과값 영향을 끼칩니다.

carry는 연산결과가 변수타입이 표시할 수 있는 범위를 넘쳤을 경우 1로 설정되므로 두 덧셈의

결과가 dword (더블워드,32비트)를 넘쳤을 경우 1로 설정됩니다. 후에 밑에 쓰인 adc 명령은

덧셈을 하면서 CF값까지 같이 더하는 명령입니다. 즉, 바로 위쪽의 add 명령으로 인하여

자리넘침이 생겼을 경우 케리플레그값이 1이 되므로 상위 32비트를 더하면서 밑에 32비트 덧셈

결과의 자리넘침 결과(=CF)값가지 더해지게 되는 것이지요. 이해를 위하여 다음 예제를 넣겠습니다. 


ex1) 
mov eax , 0 ;eax 를 0으로 만듬 
clc ;케리플레그(CF) 를 0으로 만듬,또는 클리어한다라고 
adc eax , 0 ;표현, 그런후 adc 명령으로 eax + 0 + CF를 연산 
------------- 
결과 eax = 0 

ex2) 
mov eax , 0 ;        eax 를 0으로 만듬 
stc ;                    케리플레그(CF) 를 1로 만듬,또는 설정한다라고 
adc eax , 0 ;        표현, 그런후 adc 명령으로 eax + 0 + CF를 연산 
------------- 
결과 eax = 1 

이제 adc 명령이 이혜가 가시는지요 ^^; 

Q2) 위의 소스를 보면 하위 32비트 덧셈 명령인 add 명령과 케리플레그 의 형향을 받는

덧셈인 adc 명령사이에 mov 라는 명령이 쓰였습니다. 그렇다면 이 mov 명령의 영향에

의해서 CF값이 바뀌어 adc 명령의 수행에 이상을 주지 않을까요? 

A2) 위의 설명을 좀더 이혜할 수 있는 기회입니다. 이 설명의 제일 앞 중에 영향을 주는

플레그리스트가 각 명령별로 틀리다고 말씀 드렸을 것입니다. 다행히도 mov 명령은

CF 플레그에 영향을 받지도 주지도 않는 명령어 입니다. 따라서 mov 명령은 CF 값을

변화시키거나 하지 않습니다. 참고로 mov 명령은 영향받는 플레그도 없고 주는 플레그도 없는

명령입니다. 그러므로 add 와 adc 사이에는 CF에 영향을 주지 않는 명령이라면 얼마든지

써도 되는 것입니다. ^^ 


이번에는 어셈블리를 이용한 최적화된 조건분기를 보여드리겠습니다.

만약 x값이 y값보다 큰지, 같은지 , 작은지를 비교해야 할 경우가 생긴다고 합니다.

이럴경우 일반적으로 연산을 구현할때

if (x=y) 


        file://같을때 처리문 

else 

        if (x<y) 
       { 
                  file://x가 y보다 작을때 처리문 
        } 
        else 
       { 
                  file://x가 y보다 클때 처리문 
        } 

과 같은 비교조건문이 생기게 됩니다. 이를 컴파일하여 디스어셈블 할 경우

엄청나게 최적화되지 않은 컴파일러라면 다음과 같이 됩니다.

file://VC 6.0 디스어셈블 예

102: if (x=y) 

00402F31 mov eax,dword ptr [ebp-54h] 
00402F34 mov dword ptr [ebp-50h],eax 
00402F37 cmp dword ptr [ebp-50h],0 
00402F3B  je   CTestasmView::OnBtnAsmTest+46h (00402f46) 
103: { 
105: } 
106: else 
00402F44 jmp  CTestasmView::OnBtnAsmTest+5Eh (00402f5e) 
107: { 
108: if(x<y) 
00402F46 mov ecx,dword ptr [ebp-50h] 
00402F49 cmp ecx,dword ptr [ebp-54h] 
00402F4C jge CTestasmView::OnBtnAsmTest+57h (00402f57) 
109: { 
111: } 
112: else 
00402F55 jmp CTestasmView::OnBtnAsmTest+5Eh (00402f5e) 
113: { 
115: } 
116: } 

하지만 이를 어셈블리 코드로 고친다음 다음과 같이 할 수 있습니다. 

mov eax , y 

cmp x , eax 
jg Lvl1 ;      x가 y보다 클경우 처리 
jl Lvl2 ;       x가 y보다 작을경우 처리 
;                x와 y가 같을경우 처리 
... 
jmp CmpEnd 

Lvl1: 
... ;             x가 y보다 클경우 처리문 
jmp CmpEnd 

Lvl2: 
... ;             x가 y보다 작을경우 처리문 

CmpEnd: 


좀더 사용 명령수가 줄어들게 됩니다. 뿐만 아니라 명령처리에 대한 흐름을 원활하기

위하여 이런 분기가 일어나지 않도록 컨디션 mov 명령이 팬티엄pro부터 생겨났으므로

조건에 따라 처리해야할 변수의 갯수가 적을 경우 이런 명령을 이용하면 무분기 조건처리도

가능합니다. 물론 flag와 명령의 처리특성을 이용하신다면 무분기 조건처리에 대한 여러가지

편법 또한 이용하실수 있게 되실겁니다. 


이번 강좌또한 마치며 한말씀 드리려 합니다. 항상 기본을 하며 말씀을 드리는 것이지만

어셈블리를 사용하실때 왜 프로그램의 소스에 어셈블리를 사용하는가와 어떨때 어셈블리를

사용하고 어떨때 사용하지 않는것이 낳은지를 잘 아시는것이 좋은 프로그래머의 예라 할 수

있습니다. 아직까지도 이런 부분에서 많은 분들이 어셈블리에 대하여 많은 소음이 끊이지

않고 있습니다. 저는 따로 생각하지 않고 적어도 어셈블리는 상용프로그램에서도 많이 사용되고

있으며 무언가 필요하기 때문에 외국 고수준 프로그래머들도 사용하고 있으며 같은 로직으로

되었을때 타사제품과 좀더 경쟁력을 갖추기 위하여 나은 수행속도를 원할때 선택되는 사항이라는

점을 알아주시면 좋겠습니다. 

출처 - http://ttongfly.net/zbxe/?document_srl=45194

'System' 카테고리의 다른 글

[펌]함수 호출규약 [Calling Convention]  (0) 2010.01.01
Format String Bug  (0) 2009.12.22
Reverse Engineering Cheat-Sheet  (0) 2009.11.30
What is SVN[Subversion]?  (0) 2009.11.14
어셈블리어 명령어 정리  (3) 2009.11.06
플레그는 아무하고나 만나주지 않는다.  (0) 2009.11.03
Posted by LinkC

블로그 이미지
LinkC

태그목록

Tistory Cumulus Flash tag cloud by BLUEnLIVE requires Flash Player 9 or better.

공지사항

Yesterday49
Today11
Total323,945

달력

 « |  » 2018.12
            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          

최근에 받은 트랙백

글 보관함


. .