dekar

[스크랩] [어셈블리어] 어셈블리 초급 기초 #2

전설비 2009. 2. 20. 15:01
주인장 왈) 첨부되어있는 문서는 조합형으로 작성되어 있습니다.
 

작성자 : 정태식
출처 : http://blog.naver.com/zoware.do

 
----------------------------------------------------------
 [19] 제목 : [초급-보충] 논리연산에 대해서...
 올린이 : 까망벌레(정태식  )    94/12/12 23:53    읽음 : 303  관련자료 없음
강좌가 늦어진 점에 대해 사과 드립니다.
제가 곧 군대를 가기 때문에 이런 저런 일 좀 처리하다 보니 
2주일 정도 전혀 못들어 오게 �었습니다.
그럼 계속 해서...
이번에는 논리 연산 명령에 대해 알아 보도록
하겠습니다.
아마 대부분 여러분들은 고등학교 과정에서 논리 연산에 대해 간략히 배워
보셨을 줄로 압니다. 
즉 논리 연산에는 다음과 같은 명령들이 있는데...
    AND
    OR
    NOT
    XOR
위와 같은 네개가 컴퓨터에서 대표적으로 쓰이는 논리연산 명령어들 입니다.
그럼 우선 하나하나 자세하게 설명을 해 나가겠습니다.
학교에서 배울때는 'T,F'라는 것을 많이 사용 하였는데요, PC에서는 이 'T,F'
라는 것 대신에 프로세서가 알아 먹을 수 있는 내용인 숫자로 바꾸어 연산이
되어 집니다. 즉 프로세서가 알 수 있는 숫자는 2진수 밖에 없으므로 이 
'T,F'를 2진수로 대치시켜 사용 하도록 합니다. 
논리 연산에서는 'T,F'두개인 것과 같이 2진수 또한 '0,1'이라는 두개의 숫자만이
존재 합니다. 그럼 쉽죠? 
  T ( TRUE )  = 1
  F ( FULSE ) = 0
위와 같이 정의를 하면 논리 연산도 식은죽 먹기...
첫째로 AND에 대해서...
우선 AND연산에 대한 진리표를 작성해 보도록 하겠습니다.
 ;-----------------;
 ; X ; Y ; X AND Y ;
 ;-----------------;
 ; F ; F ;    F    ;
 ; F ; T ;    F    ;
 ; T ; F ;    F    ;
 ; T ; T ;    T    ;
 ;-----------------;
위와 같은 진리표를 얻습니다. 
( 헤..다 아신다구 해도 혹시나 까먹으셨을지도 모르시는 분들을 위해... )
AND 라는 것은 위에서 보면 알 수 있듯이 두개의 오퍼랜드 ( 피연산자 )를 필요로
하는 논리 연산 명령어 입니다. 위의 진리표에서는 두 개의 피 연산자가 바로 
'X' 와 'Y'가 되는 것이겠죠. 이 AND라는 것은 두 개의 오퍼랜드 모두 참 값
( 'T'라는 값 ) 을 가져야만 결과값이 참( T )이 되는 것을 알 수 있습니다.
이제 기억이 조금씩 되살아 나실라나 모르겠네요.
그럼 이 진리표를 조금 바꾸어서 이를 2진수의 숫자 0 과 1 이라는 숫자로 바꾸어
다시 그려 보도록 하겠습니다.
 ;-----------------;
 ; X ; Y ; X AND Y ;
 ;-----------------;
 ; 0 ; 0 ;    0    ;
 ; 0 ; 1 ;    0    ;
 ; 1 ; 0 ;    0    ;
 ; 1 ; 1 ;    1    ;
 ;-----------------;
위와 같이 변환이 되어 집니다. 즉 전에 말씀 드렸다 시피 
    T 는 1
    F 는 0
으로 각각 바꾸어 주기만 하면 됩니다.
그럼 이제 이 AND 연산 명령이 PC 상에서 어떻게 사용 되며 어떠한 처리를 하는지,
그리고 어느때 이러한 연산 명령이 필요한지 간단히 알아 보도록 하겠습니다.
이제까지 연산 처리 명령은 모두 1비트 크기의 연산 명령으로 제한된 예를 보였
습니다. 하지만 이 AND 연산이라는 것이 1비트 연산만을 하기 위한 것이라고 
한다면... '푸~~~' 하고 한숨만 나오겠죠...
그럼 다음과 같은 것을 봅시다.
    X = 00101101
    Y = 10110110
( 이 숫자들의 값은 모두 2진수 입니다.
  즉, X 의 값은 원래 45 이고 Y는 182 인데, 이 값들을 모두 2진수로 바꾸어 
  논리 연산을 하는데 알아보기 편하도록 했습니다. )
위와 같이 X,Y 의 값을 정의 하였다고 해 보죠.
그럼 학교 수학 시간에 배운 개념을 날려 버리고 새롭게 PC차원의 논리 연산으로 
들어가서 위의 두 변수의 값들을 AND연산을 해 보도록 하겠습니다.
    AND    X,Y
앗! 위의 것은 무슨 뜻이냐고요?
원래의 의미는 'X   AND   Y'와 같은 의미를 지닙니다. 하지만 PC상에서 사용하는
문법을 따르기 위해 위와 같은 표기를 하게 된 것입니다.
즉 'X 값과 Y 두개의 값을 서로 AND 연산 시켜라'라는 명령어가 되는 것입니다.
그럼 결과 값은 어떤게 나오는지 살펴 보죠.
        00101101   <-- X 값
        10110110   <-- Y 값
   AND )________
         결과값
( 후후...이거 결과 값 찾는데 어지간히 뜸을 들이는군요.. )
위와 같이 자리수를 서로 맞추어 다시 써 보았습니다.
좀 더 편한 설명을 위해 각각의 자리수에 번호를 메겨 부르기 편하도록 해 보죠 
위의 변수들의 값들은 모두 1바이트의 크기를 갖습니다. 즉 비트수로 따지면
8개의 비트수를 갖는 숫자라고 할 수 있습니다.
그럼 각각의 비트마다 번호 ( 순번 )을 매겨 보도록 하겠습니다.
 ;-----------------------------------------------;
 ;  0  ;  0  ;  1  ;  0  ;  1  ;  1  ;  0  ;  1  ; <---  X값
 ;-----------------------------------------------;
   7번   6번   5번   4번   3번   2번   1번   0번    비트
위와 같이 매길 수 있습니다. ( 매길 수 있습니다가 아니고 사실 위와 같이 
매기도록 되어 있습니다.)
조금 핵갈리실지도 모르지만 가장 죄측의 비트 번호가 '8'이 아닌 '7'이 된다는
사실에 주의를 해 주세요. 사실 비트수가 모두 8개 이어서 가장 높은 자리의 비트
번호가 '8'이어야 할 꺼 같지만 ( 1 부터 8 까지 ) PC 상에서는 이 '0' 이라는
숫자가 더 끼어들게 되어 가장 낮은 자리의 비트 번호는 '0'이 되고 가장 높은
자리의 비트수가 바로 '7'이 되어 집니다. ( 0 부터 7 까지 모두 8개의 비트 )
그럼 위의 연산 결과값을 하나하나 찾아 나가보도록 하겠습니다.
X,Y 두개의 변수에서 각각의 자리수를 이미 맞추어 놓았습니다. 즉, X의 7번 비트는
Y의 7번 비트, X의 5번 비트는 Y의 5번 비트....등등 각각의 비트자릿수를 맞추어
놓습니다. 
그리고 이 맞추어진 것에 따라 하나씩 (1 비트씩) 따로따로 연산을 하여 결과값도
마찬가지로 각각 비트의 자릿수를 맞추어서 써 주면 됩니다.
알아 보기 쉽도록 표를 하나 그려 보도록 하겠습니다.
 ;--------------------------------;
 ; 비트 번호 ; X ; Y ; AND    X,Y ;  
 ;--------------------------------;
 ;     0     ; 1 ; 0 ;     0      ;
 ;     1     ; 0 ; 1 ;     0      ;
 ;     2     ; 1 ; 1 ;     1      ;
 ;     3     ; 1 ; 0 ;     0      ;
 ;     4     ; 0 ; 1 ;     0      ;
 ;     5     ; 1 ; 1 ;     1      ;
 ;     6     ; 0 ; 0 ;     0      ;
 ;     7     ; 0 ; 1 ;     0      ;
 ;--------------------------------;
위와 같이 됩니다. 각각의 비트번호 대로 1비트씩 따로 짤라내어 하나씩 연산을
한 결과를 얻게 되는 것이지요.
그래서 위와 같은 예의 결과 값은 바로 
  00100100  
이 되는 것입니다.
그럼 이와 같은 것을 직접 어셈블리 명령어를 사용해서 프로그래밍을 해 보도록
하겠습니다.
    X = 00101101
    Y = 10110110
    X  AND  Y    = ??
'??'라는 값을 얻기위한 어셈블리 프로그래밍은,
    MOV    AX, 00101101B
    MOV    BX, 10110110B
    AND    AX, BX
간단하죠?
MOV 에 의해 AX에는 원래의 X값을, BX에는 원래의 Y값을 넣어주었습니다.
그리고 다음의 'AND'명령에 의해 AX와 BX의 값을 서로 AND 시켜 주었습니다.
앗! 근데 연산의 결과 값이 과연 어디에 들어가나요?
그건 역시나 'AX'레지스터에 들어가게 됩니다. 
즉 'AND    AX,BX'는 AX레지스터와 BX레지스터에 들어 있는 값들을 서로 논리연산
'AND'를 수행 한 후에 그 결과 값을 다시 AX레지스터에 넣어라! 라는 뜻이 됩니다.
만약 'AND    BX,AX'라고 한다면 똥 같은 값이지만 그 결과 값을 AX레지스터가 아닌
BX레지스터에 넣게 되는 것이지요.
그럼 과연 이러한 연산이 어디에 쓰이는가.
간단한 한 예를 보도록 하겠습니다.
인터럽트 11(16진수 11임)을 호출할 때를 보도록 하겠습니다.
( 인터럽트에 관한 설명은 나중에 따로 하겠습니다. 여기서는 그냥 그려러니...하구
  넘어 가세요 )
이 인터럽트를 호출하게 되면 프로세서는 지금 PC의 주변기기의 연결상태를
체크하여 그 정보를 넘겨 줍니다. 그 정보는 AX레지스터로 넘겨 주게 됩니다.
사실 연결장치의 정보는 한가지가 아닌 여러가지의 연결장치들의 상태를
넘겨주게 되는데, AX레지스터에 이 모든 정보들이 다아 담겨져 있습니다.
  플로피 드라이브의 설치 유무
  코프로 세서의 유무
  16K RAM 블럭의 수
  비디오 모드
  플로피 드라이브 갯수
  DMA 칩(CHIP)의 사용
  RS - 232 카드의 수
  게임 포트 수
  직렬 프린터의 설치
  모뎀 설치
  설치된 프린터의 수
위와 같은 11개에 대한 정보가 하나의 레지스터인 AX레지스터에 모두 담겨져 나오게
됩니다. 그럼 과연 그것이 어떻게 가능 할까요? 그것은 바로 위와 같은 정보들이 
따로따로 각각의 지정된 고유의 비트들을 차지하여 정보를 전달하게 됩니다.
비트 번호
    0     플로피 드라이브의 설치 유무
    1     코프로 세서의 유무
  2 - 3   16K RAM 블럭의 수
  4 - 5   비디오 모드
  6 - 7   플로피 드라이브 갯수
    8     DMA 칩(CHIP)의 사용
  9 - 11  RS - 232 카드의 수
    12    게임 포트 수
    13    직렬 프린터의 설치
    13    모뎀 설치
 14 - 15  설치된 프린터의 수
위와 같이 각각의 비트들에 그 주변 기기들의 상태들에 대한 정보를 넣게 됩니다.
가령 인터럽트 11번을 사용하여 얻어낸 AX레지스터의 값이 다음과 같다고 해 보죠.
    0110000010101111 ( 2진수 입니다. 16진수로는 60AF 가 됩니다. )
이걸 좀 더 알아보기 편하도록 박스를 그려 구분해 보도록 하겠습니다.
;---------------------------------------------------------------;
; 0 ; 1 ; 1 ; 0 ; 0 ; 0 ; 0 ; 0 ; 1 ; 0 ; 1 ; 0 ; 1 ; 1 ; 1 ; 1 ;
;---------------------------------------------------------------;
  F   E   D   C   B   A   9   8   7   6   5   4   3   2   1   0   <- 비트 번호
( 위의 비트 번호에서 영문자는 16진수 표기를 따랐기 때문 입니다. )
위와 같이 정리 될 수 있습니다.
그럼 이제 이 값들에서 필요한 정보를 알아 내도록 해 보겠습니다.
;--------------------------------------------------------------;
;비트번호;     내           용        ; 값 ;   결과의 내용     ;
;--------------------------------------------------------------;
;   0    ;플로피 드라이브의 설치 유무 ;  1 ; 있음              ;  
;   1    ;코프로 세서의 유무          ;  1 ; 있음              ;
; 2 - 3  ;16K RAM 블럭의 수           ; 11 ; 3개               ;
; 4 - 5  ;비디오 모드                 ; 10 ; 80X25 COLOR MODE  ;
; 6 - 7  ;플로피 드라이브 갯수        ; 10 ; 2개               ;
;   8    ;DMA 칩(CHIP)의 사용         ;  0 ; 없음              ;
; 9 - B  ;RS - 232 카드의 수          ;  0 ; 없음              ;
;   C    ;게임 포트 수                ;  0 ; 없음              ;  
;   D    ;직렬 프린터의 설치          ;  1 ; 있음              ; 
;   D    ;모뎀 설치                   ;  1 ; 있음              ;
; E - F  ;설치된 프린터의 수          ; 01 ; 1개               ;
;--------------------------------------------------------------;
이와 같습니다.
즉, 비트 단위로 그 결과를 알아 낼 수 있는 것입니다.
하지만 여기서 만약 프로피 드라이브의 갯수를 알고 싶은데, 과연 어떻게 
이리저리 섞여 있는 정보들 중에 원하는 정보를 따로 분리해 뽑아 낼수 있을까요.
다시 말해 AX레지스터는 전부 16개의 비트로 구성이 되어 있는데 이 중에서 
우리가 원하는 비트 번호인 6번 부터 7번 까지의 비트안에 있는 내용을 뽑아 올 수
있겠습니까?
여기서 바로 AND라는 연산 명령이 사용 됩니다.
다음과 같이 해 보도록 하죠.
    AND      AX, 0000000011000000B
그럼 원래의 AX레지스터에는 0110000010101111 이라는 2진수 값이 들어 있었습니다.
        0110000010101111   <-- 인터럽트 호출로 얻은 정보 값
        0000000011000000   
   AND )________________
            결과 값
이와 같이 하게 되면 결과 값은 
         0000000010000000
이 되는 것을 쉽게 알 수 있습니다. 이것은 바로 플로피 드라이브의 갯수를
담고있는 비트 번호만이 그대로 남아 있고 나머지는 모두 0으로 세트 되는 현상을
가져 오게 되는 것이지요. 이렇게 따로 비트의 내용을 뽑아 올때 AND연산을 많이 
사용하게 됩니다.
둘째로 OR에 대해 알아 보도록 하겠습니다.
 ;-----------------;
 ; X ; Y ; X  OR Y ;
 ;-----------------;
 ; 0 ; 0 ;    0    ;
 ; 0 ; 1 ;    1    ;
 ; 1 ; 0 ;    1    ;
 ; 1 ; 1 ;    1    ;
 ;-----------------;
.
진리 표는 위와 같습니다.
간단히 연산 결과만을 보여 드리고 다음으로 넘어 가겠습니다.
        X = 01001011
        Y = 10011010
        X   OR   Y   =   11011011
위와 같이 됩니다. 즉 두개의 오퍼랜드 중 하나라도 '1'이 라는 값이 있으면 
그 결과는 1이 되는 것입니다. ( 물론 1비트씩 따로 연산이 되어 집니다. )
이 OR이라는 명령어는 어떨때 쓰이느냐...하믄
바로 비트 중에 나머지 부분은 그냥 놔 두고 원하는 부분만을 '1'로 세트하고
싶을 때에 사용하게 됩니다.
;---------------------------------------------------------------;
; 0 ; 1 ; 1 ; 0 ; 0 ; 0 ; 0 ; 0 ; 1 ; 0 ; 1 ; 0 ; 1 ; 1 ; 1 ; 1 ;
;---------------------------------------------------------------;
  F   E   D   C   B   A   9   8   7   6   5   4   3   2   1   0   <- 비트 번호
위의 예에서 만약 비트 번호 9번이랑 8번을 모두 1로 세트하고 싶다면,
    OR      AX, 0000001100000000B
이와 같이 하면 비트 번호 9번이랑 8번은 모두 1로 세트가 되고 나머지는 변화없이
그대로 남게 됩니다.
다음은 NOT 인가요?
이건 너무 간단해서 ....
부정 한다는 뜻입니다.
단 이것은 오퍼랜드가 하나밖에 올 수 없다는 것입니다.
생각해 보면 당연한 얘기지만 말이죠...
       X = 01001101
       NOT    X  =  10110010
각 비트들의 값이 모두 거꾸로 전환이 된 것을 알 수 있습니다.
즉, '0'은 '1'로
    '1'은 '0'으로
각각 변환이 된 것을 알 수 있습니다.
이렇게 NOT는 각각의 비트별로 그 값을 '0'이면 '1', '1'이면 '0' 으로 바꾸는 
기능을 하여 줍니다.
이제 XOR로 넘어오죠..
이 XOR이라는 것은 EXCLUSIVE - OR  뜻으로 다음 진리표를 보면,
 ;-----------------;
 ; X ; Y ; X XOR Y ;
 ;-----------------;
 ; 0 ; 0 ;    0    ;
 ; 0 ; 1 ;    1    ;
 ; 1 ; 0 ;    1    ;
 ; 1 ; 1 ;    0    ;
 ;-----------------;
이와 같은 진리표가 됩니다.
또 예를 보도록 하죠.
      X = 01101101
      Y = 10111001
      X    XOR    Y   =   11010100
즉 다시 말해 두 개의 오퍼랜드를 비교 하여 각 비트 별로 그 값이 같으면 ( 모두
'1' 또는 '0' 이면 ) 결과 값은 0이 되고, 두 비교 대상의 값이 서로 다른 값이면
( '0'과 '1', 또는 '1'과 '0' 이면 ) 그 결과값은 1이 되는 것입니다.
이것은 생각보다 꽤 많이 사용되어 지는 연산 명령어 입니다.
그 이유는 어떠한 레지스터의 값을 깨끝이 ( 값을 0으로 해 주는것 ) 하고자 할 때
일단은 다음과 같은 방법이 있음을 알 수 있습니다.
1,    MOV    AX, 00  <-- AX 에 0 을 대입
2,    SUB    AX, AX  <-- AX값에 AX값을 빼어 AX에 넣어줌 ( AX - AX = 0 )
3,    AND    AX, 00  <-- AND연산으로 AX레지스터의 값을 0으로 만들어 줌
4,    OR     AX,0FFH <-- AX 값을 모두 1로 세트한 다음 ( 비트단위 )
      NOT    AX          이것의 부정(NOT)을 취하여 0으로 세트
5,    XOR    AX, AX  <-- AX 값을 AX와 XOR연산 시킴
일단은 위의 다섯 가지를 보도록 하죠.
이 다섯 가지 경우 모두 AX레지스터의 값을 0으로 세트하여 주는 어셈블리 
명령어들 입니다. 
사실 이 다섯 가지 중, 어떤것을 사용 해도 별 상관은 없습니다.
하지만 가장 많이 사용 되고, 또한 가장 권장할 만한 방법은 바로 다섯번째의 경우인
    XOR    AX, AX
입니다. 그 이유는 바로 어셈블리 프로그래밍을 하는 가장 중요한 이유중의 하나인
속도 차원의 문제 입니다.
대충 비교를 하자면, 덧셈이나 뺄셈 명령은 곱셈이나 나눗셈 명령보단 훨씬 속도가
빠릅니다. 
그리고 여기에 논리 연산명령은 덧셈, 뺄셈 명령보다, 그리고 이동 명령인 'MOV'보다
훨씬 빠른 속도를 나타냅니다.
물론 쉬프트 명령이라는 것 또한 못지 않게 빠른 속도를 나타냅니다만, 이 것은
아직 설명을 하지 않았기 때문에 넘어 가기로 하고...
그런 속도 문제 때문에 XOR은 어떠한 레지스터의 값을 0으로 세팅 하는데 아주
많이 사용 됩니다.
 [23] 제목 : 디버그(DEBUG.EXE) 정리 -전편-
 올린이 : 영원의별(이세원  )    95/01/10 18:58    읽음 : 455  관련자료 없음
안녕하세요.
디버그에관해 자세히 그리고 분명히 언급된 책이 별로 없더군요.
그래서 한번 꾸며보았습니다.
너무 길어서 둘로 나누어 올립니다.
많은 도움이 되시길...
                       디버그(DEBUG.EXE)의 사용법.
        디버그라는 뜻은 프로그램의 버그  즉 오류를 찾아낸다는 뜻이다.프로그
램을 완성하고 실행시키면 예상치도 않은  버그가 발생하는수가 간혹있다.  이런 
경우에 프로그램을 부분적으로 실행해보고  오류를 찾아내야 하는데 그런 작용을 
전문적으로 해주는 프로그래머에게는 필수의 도구가 바로 도스의 디버그(DEBUG.E
XE) 이다. 정확한 명칭은 디버거(DEBUGER)  라고 해야하나 도스의 화일로서 제공
되는 이름은 이름은 디버그이다.
        그러나 지금은 프로그램의 덩치가  워낙 커지고 또한 고급언어로 작성되
는지라 프로그램의 정확한 흐름을 아는것은  대단히 어렵다. 프로그래머 조차 라
이브러리의 내용을 모른다는 이야기다.  따라서 고급언어로 만들어진 프로그램을 
디버거로 오류를 찾아내는것은 어렵다. 그런 이유로 고급언어에서는 통합환경 내
에서 자체적으로 오류를 찾도록해주는 자체 디버거를 가지고 있는 형편이다.
        이 디버거는 예전의 어셈블리어로 프로그램을 작성하던때에 진가를 발휘
하던 프로그램이었으나 지금은 그런  목적보다도 컴퓨터의 시스템을 직접 조작하
는데 많이 쓰인다.
        디버거를 기동하고 디버거 프롬프트 상에서  '?' 를 입력하면 다음과 같
은 도움말이 출력된다.
+-------------------------------------------------------------------------+
|       -?                                                               |
|       assemble     A [address]                                          |
|       compare      C range address                                      |
|       dump         D [range]                                            |
|       enter        E address [list]                                     |
|       fill         F range list                                         |
|       go           G [=address] [addresses]                             |
|       hex          H value1 value2                                      |
|       input        I port                                               |
|       load         L [address] [drive] [firstsector] [number]           |
|       move         M range address                                      |
|       name         N [pathname] [arglist]                               |
|       output       O port byte                                          |
|       proceed      P [=address] [number]                                |
|       quit         Q                                                    |
|       register     R [register]                                         |
|       search       S range list                                         |
|       trace        T [=address] [value]                                 |
|       unassemble   U [range]                                            |
|       write        W [address] [drive] [firstsector] [number]           |
|       allocate expanded memory        XA [#pages]                       |
|       deallocate expanded memory      XD [handle]                       |
|       map expanded memory pages       XM [Lpage] [Ppage] [handle]       |
|       display expanded memory status  XS                                |
|       -                                                                 |
+-------------------------------------------------------------------------+
        1.      A (어셈블)
A 명령은 어셈블하여 메모리에 직접 기계어 코드를 만들다. 다만 1행마다 어셈블
하는 기능이므로 레이블을 사용할 수는 없다.
형식)   A [어드레스]
어드레스는 메모리내의 오프셋번지 또는 세그먼트와 오프셋의 번지이다.
세그먼트번지를 생략하면 현재의  CS 레지스터가 세그먼트값이되고 IP레지스터의 
값이 오프셋 번지가 된다.
-A 100 
154D:0100 MOV AH,4C 
154D:0102 INT 21 
154D:0104
    .
    .
        2.      C (비교)
C 명령은 메모리의 내용을 비교하고 달라져 있는 부분을 표시한다.
세그먼트가 생략된 경우에는 DS 세그먼트의 값으로 정해진다.
형식)   C [개시어드레스 종료어드레스]
        C [개시어드레스] L [길이]
1234:0000 ∼ 1234:000F 까지를 현재의 DS:0010 부터 시작해서
비교한다.
-c 1234:0 f 10 
1234:0000  ED  B1  154D:0010
1234:0001  75  0F  154D:0011
1234:0002  05  17  154D:0012
1234:0003  E8  03  154D:0013
1234:0004  26  B1  154D:0014
1234:0005  00  0F  154D:0015
1234:0006  EB  FA  154D:0016
1234:0007  03  0E  154D:0017
1234:0008  E8  01  154D:0018
1234:0009  B0  01  154D:0019
1234:000B  72  00  154D:001B
1234:000C  08  02  154D:001C
1234:000D  5A  FF  154D:001D
1234:000E  E8  FF  154D:001E
1234:000F  05  FF  154D:001F
-
1234:0000 부터 10H개 만큼 현재의 DS:0010 부터 비교한다.
이것은 결과적으로 위와 같은 내용을 출력한다.
-c 1234:0 l10 10 
1234:0000  ED  B1  154D:0010
1234:0001  75  0F  154D:0011
1234:0002  05  17  154D:0012
1234:0003  E8  03  154D:0013
1234:0004  26  B1  154D:0014
1234:0005  00  0F  154D:0015
1234:0006  EB  FA  154D:0016
1234:0007  03  0E  154D:0017
1234:0008  E8  01  154D:0018
1234:0009  B0  01  154D:0019
1234:000B  72  00  154D:001B
1234:000C  08  02  154D:001C
1234:000D  5A  FF  154D:001D
1234:000E  E8  FF  154D:001E
1234:000F  05  FF  154D:001F
-
        3.      D (덤프)
D 명령은 메모리의 내용을 16진수와 아스키문자로 나타낸다.
디폴트 세그먼트는 DS세그먼트이고 한번에 128바이트를 출력한다. 또한 덤프후에
또다시 D 명령을 치면 연속해서 메모리의 내용을 출력한다.
덤프명령은 아스키 문자도 출력하는데 아스키 128번 이후의 문자는 출력하지 못
하고 '.' 으로 표현한다. 그런 이유로 한글은 출력해도 알아볼수가 없다.
형식)   D
        D [어드레스]
-D 
154D:0100  0F 00 B9 8A FF F3 AE 47-61 03 1F 8B C3 48 12 B1   .......Ga....H..
154D:0110  04 8B C6 F7 0A 0A D0 D3-48 DA 2B D0 34 00 3C 15   ........H.+.4.<.
154D:0120  00 DB D2 D3 E0 03 F0 8E-DA 8B C7 16 C2 B6 01 16   ................
154D:0130  C0 16 F8 8E C2 AC 8A D0-00 00 4E AD 8B C8 46 8A   ..........N...F.
154D:0140  C2 24 FE 3C B0 75 05 AC-F3 AA A0 0A EB 06 3C B2   .$.<.u........<.
154D:0150  75 6D 6D 13 A8 01 50 14-74 B1 BE 32 01 8D 8B 1E   umm...P.t..2....
154D:0160  8E FC 12 A8 33 D2 29 E3-13 8B C2 03 C3 69 02 00   ....3.)......i..
154D:0170  0B F8 83 FF FF 74 11 26-01 1D E2 F3 81 00 94 FA   .....t.&........
오프셋번지 FFH 이후의 메모리의 내용을 출력한다.
-D FF 
154D:00F0                                               00                  .
154D:0100  0F 00 B9 8A FF F3 AE 47-61 03 1F 8B C3 48 12 B1   .......Ga....H..
154D:0110  04 8B C6 F7 0A 0A D0 D3-48 DA 2B D0 34 00 3C 15   ........H.+.4.<.
154D:0120  00 DB D2 D3 E0 03 F0 8E-DA 8B C7 16 C2 B6 01 16   ................
154D:0130  C0 16 F8 8E C2 AC 8A D0-00 00 4E AD 8B C8 46 8A   ..........N...F.
154D:0140  C2 24 FE 3C B0 75 05 AC-F3 AA A0 0A EB 06 3C B2   .$.<.u........<.
154D:0150  75 6D 6D 13 A8 01 50 14-74 B1 BE 32 01 8D 8B 1E   umm...P.t..2....
154D:0160  8E FC 12 A8 33 D2 29 E3-13 8B C2 03 C3 69 02 00   ....3.)......i..
154D:0170  0B F8 83 FF FF 74 11 26-01 1D E2 F3 81 00 94      .....t.&.......
특정 메모리번지인 1100:0000 의 메모리의 내용을 출력한다.(세그먼트 값과
오프셋 값을 설정한다.)
-D 1100:0 
1100:0000  C3 C6 06 22 4A 00 E8 D0-FF 33 DB BF 07 57 E8 E8   ..."J....3...W..
1100:0010  EE 74 1F 8B 2E 1C 4A 57-53 E8 B3 F2 5B 5F 89 15   .t....JWS...[_..
1100:0020  89 45 02 83 C7 05 43 83-FB 0B 75 E2 BA F4 4B E9   .E....C...u...K.
1100:0030  D8 F5 89 1E AC 56 8B CB-E3 12 BF 07 57 1E 26 C5   .....V......W.&.
1100:0040  35 83 C7 04 A4 C6 44 FF-CC E2 F3 1F 8B 16 8E 4A   5.....D........J
1100:0050  89 16 1C 4A 8B 16 90 4A-89 16 1E 4A C7 06 AE 56   ...J...J...J...V
1100:0060  01 00 E9 EC FD B4 37 32-C0 CD 21 2E 88 16 75 56   ......72..!...uV
1100:0070  AC E8 C4 F6 74 05 E8 D2-F6 75 F5 4E C3 E8 08 F0   ....t....u.N....
-
        4.     E (엔터)
메모리의 내용을 세트한다.
이는 새로이 특정 메모리의 내용을 설정하는것을 말한다.
형식)   E[개시어드레스 리스트]
-e B800:0100                           ----- ①
B800:0100 20.31                        ----- ②
① EB800:0100 의 내용을 출력시킨다.
② 20H 의 값을 '31' 로 바꾼다.
이명령은 또한 메모리에 문자열의 입력도 가능하다.
EB800:100 의 번지에 문자열을 입력한다. 중간중간의 '7' 은 문자의 속성이다.
결과적으로 화면 우측 상단에 'I AM A BOY' 라고 출력된다.
-e B800:100 'I' 7 ' ' 7 'A' 7 'M' 7 ' ' 7 'A' 7 ' ' 7 'B' 7 'O' 7 'Y' 
-                                               I AM A BOY
        5.     F (채움)
F 명령은 메모리를 지정한 데이타로 채운다.
형식)   F[어드레스 리스트]
-f b800:0 ff 31                         ----- ①
-f b800:0 ff 31,32,33                   ----- ②
-f b800:0 ff 'i am a boy'               ----- ③
-
① B800:0000 ∼ B800:00FF 까지 31H 로 채운다.
② B800:0000 ∼ B800:00FF 까지 31H,32H,33H 로 채운다.
③ B800:0000 ∼ B800:00FF 까지 'i am a boy' 로 채운다.
또한 이 명령을 이용해서 메모리의 특정 부분의 데이타를 소거하는데 쓸수있다.
-fb800:0 ffff 0         -----  B800:0000 ∼ B800:FFFF 까지를 0H 로 채운다.
        6.     G (실행개시)
G 명령은 메모리에 로드된 프로그램의 실행을 개시한다.
형식)   G                               ---- ①
        G [=시작점 중지점]              ---- ②
① 현재의 CS:IP 로부터 프로그램을 시작한다.
② 시작번지에서 중지번지 바로 앞번지까지 프로그램이 진행된다.
C:\ASM>debug small.com 
-g 
Ex) small file1 file2
Program terminated normally
-
C:\ASM>debug small.com 
-g=100 215 
Ex) small file1 file2
AX=0924  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0215   NV UP EI PL ZR NA PE NC
155E:0215 B44C          MOV     AH,4C
-g 
Program terminated normally
-
다음은 디버거로 웜부팅을 해보는 재미있는 예이다.
부트 스트랩 로더를 기동하는 프로그램을 CS:100H 로 복사하고 G 명령으로
실행 시켜본다.
C:\ASM>debug 
-m ffff:0 f 100 
-d 100 
154D:0100  EA F4 04 A6 02 30 34 2F-33 30 2F 39 30 00 FC 00   .....04/30/90...
154D:0110  04 8B C6 F7 0A 0A D0 D3-48 DA 2B D0 34 00 3C 15   ........H.+.4.<.
154D:0120  00 DB D2 D3 E0 03 F0 8E-DA 8B C7 16 C2 B6 01 16   ................
154D:0130  C0 16 F8 8E C2 AC 8A D0-00 00 4E AD 8B C8 46 8A   ..........N...F.
154D:0140  C2 24 FE 3C B0 75 05 AC-F3 AA A0 0A EB 06 3C B2   .$.<.u........<.
154D:0150  75 6D 6D 13 A8 01 50 14-74 B1 BE 32 01 8D 8B 1E   umm...P.t..2....
154D:0160  8E FC 12 A8 33 D2 29 E3-13 8B C2 03 C3 69 02 00   ....3.)......i..
154D:0170  0B F8 83 FF FF 74 11 26-01 1D E2 F3 81 00 94 FA   .....t.&........
-g 
        7.     H (합과차)
H 명령은 16진수끼리의  합과 차를 계산하여 표시해준다.
좌측의 값이 합이고 우측의 값이 차이다.
형식)   H[값1 값2]
-H 12 11 
0023  0001
-H FF00 EF12 
EE12  0FEE
-H 23 12 
0035  0011
-
        8.     I (인풋)
I 명령은 I/O PORT 에서 1 바이트의 데이타를 입력하여 표시한다.
8086의 포트 어드레스는 0H ∼ 0FFFFH 의 범위에 있기때문에 포트 어드레스의
지정도 16비트로 한다.
형식)   I[포트어드레스]
        9.     L (로드)
L 명령은 화일이나 디스크의 내용을 메모리에 로드한다.
형식)   L [어드레스]                                    ---- ①
        L [어드레스 드라이브 레코드번호 섹터수]         ---- ②
① 화일을 로드할때 쓰인다. 단 FCB 에 세트된 이름이 로드 되므로 사전에
   N 명령을 하여야한다.
   어드레스를 생략하면 CS:100H 에서 로드된다.
② 디스크의 특정 섹터를 로드할때 쓰인다.
+--------------------+-------------------------------------------+
|       어드레스     |       로드 시키는 메모리의 번지           |
+--------------------+-------------------------------------------+
|       드라이브     |       0=A,1=B,2=C,3=D 드라이브            |
+--------------------+-------------------------------------------+
|       레코드번호   |       읽는 디스크의 레코드 번호           |
+--------------------+-------------------------------------------+
|       섹터수       |       읽는 디스크의 섹터수                |
+--------------------+-------------------------------------------+
다음은 디버거 내에서 'small.com' 을 로드하는 예이다.
C:\ASM>debug 
-n small.com 
-l 
-d 
155E:0100  A0 80 00 3C 00 75 22 EB-16 45 78 29 20 73 6D 61   ...<.u"..Ex) sma
155E:0110  6C 6C 20 66 69 6C 65 31-20 66 69 6C 65 32 24 B4   ll file1 file2$.
155E:0120  09 BA 09 01 CD 21 E9 EC-00 8A 0E 80 00 B5 00 49   .....!.........I
155E:0130  49 BE 82 00 BF AC 02 AC-3C 20 74 03 AA E2 F8 B0   I.......< t.....
155E:0140  00 AA BF D5 02 F3 A4 B0-00 AA B4 3D BA AC 02 B0   ...........=....
155E:0150  00 CD 21 72 5E A3 A8 02-B4 3D BA D5 02 B0 00 CD   ..!r^....=......
155E:0160  21 72 1B EB 0F 41 6C 72-65 61 64 79 20 65 78 69   !r...Already exi
155E:0170  73 74 2E 24 B4 09 BA 65-01 CD 21 E9 97 00 B4 3C   st.$...e..!....<
-
다음은 하드 디스크(C 드라이브) 의 부트 영역을 로드한 예이다.
C:\ASM>debug 
-l 100 2 0 1 
-d 
154D:0100  EB 3C 90 4D 53 44 4F 53-35 2E 30 00 02 08 01 00   .<.MSDOS5.0.....
154D:0110  02 00 02 00 00 F8 A2 00-2E 00 08 00 2E 00 00 00   ................
154D:0120  72 10 05 00 80 00 29 79-59 E8 1C 20 20 20 20 20   r.....)yY..
154D:0130  20 20 20 20 20 20 46 41-54 31 36 20 20 20 FA 33         FAT16   .3
154D:0140  C0 8E D0 BC 00 7C 16 07-BB 78 00 36 C5 37 1E 56   .....|...x.6.7.V
154D:0150  16 53 BF 3E 7C B9 0B 00-FC F3 A4 06 1F C6 45 FE   .S.>|.........E.
154D:0160  0F 8B 0E 18 7C 88 4D F9-89 47 02 C7 07 3E 7C FB   ....|.M..G...>|.
154D:0170  CD 13 72 79 33 C0 39 06-13 7C 74 08 8B 0E 13 7C   ..ry3.9..|t....|
-
        10.    M (무브)
M 명령은 메모리의 내용을 다른 위치에 복사한다.
형식)   M [범위 번지]
다은은 'small.com' 의 내용중에 'Ex) small file1 file2' 의 부분을
다른 번지로 복사시키는 예이다.
C:\ASM>debug small.com 
-d 
155E:0100  A0 80 00 3C 00 75 22 EB-16 45 78 29 20 73 6D 61   ...<.u"..Ex) sma
155E:0110  6C 6C 20 66 69 6C 65 31-20 66 69 6C 65 32 24 B4   ll file1 file2$.
155E:0120  09 BA 09 01 CD 21 E9 EC-00 8A 0E 80 00 B5 00 49   .....!.........I
155E:0130  49 BE 82 00 BF AC 02 AC-3C 20 74 03 AA E2 F8 B0   I.......< t.....
155E:0140  00 AA BF D5 02 F3 A4 B0-00 AA B4 3D BA AC 02 B0   ...........=....
155E:0150  00 CD 21 72 5E A3 A8 02-B4 3D BA D5 02 B0 00 CD   ..!r^....=......
155E:0160  21 72 1B EB 0F 41 6C 72-65 61 64 79 20 65 78 69   !r...Already exi
155E:0170  73 74 2E 24 B4 09 BA 65-01 CD 21 E9 97 00 B4 3C   st.$...e..!....<
-m 109 11d 140 
-d 100 
155E:0100  A0 80 00 3C 00 75 22 EB-16 45 78 29 20 73 6D 61   ...<.u"..Ex) sma
155E:0110  6C 6C 20 66 69 6C 65 31-20 66 69 6C 65 32 24 B4   ll file1 file2$.
155E:0120  09 BA 09 01 CD 21 E9 EC-00 8A 0E 80 00 B5 00 49   .....!.........I
155E:0130  49 BE 82 00 BF AC 02 AC-3C 20 74 03 AA E2 F8 B0   I.......< t.....
155E:0140  45 78 29 20 73 6D 61 6C-6C 20 66 69 6C 65 31 20   Ex) small file1
155E:0150  66 69 6C 65 32 A3 A8 02-B4 3D BA D5 02 B0 00 CD   file2....=......
155E:0160  21 72 1B EB 0F 41 6C 72-65 61 64 79 20 65 78 69   !r...Already exi
155E:0170  73 74 2E 24 B4 09 BA 65-01 CD 21 E9 97 00 B4 3C   st.$...e..!....<
-
 [25] 제목 : 디버그(DEBUG.EXE) 정리 -후편-
 올린이 : 영원의별(이세원  )    95/01/10 20:33    읽음 : 293  관련자료 없음
        11.    N (네임)
N 명령은 실행파일의 이름을 수정하거나 파라메터를 지정한다.
결과로 FCB가 세트된다.
+----------------------------------------------------------+
|       FCB                                                |
+----------------------------------------------------------+
|       CS:5C   첫 번째 파일을 위한 파일 제어블럭          |
|       CS:6C   두 번째 파일을 위한 파일 제어블럭          |
|       CS:80   파라메터 길이                              |
|       CS:81   파라메터 시작 위치                         |
+----------------------------------------------------------+
형식)   N [패스네임 파라메터]
다음은 디버거 내에서 'small.asm' 을 어셈블하고 링크하는 과정이다.
C:\ASM>debug 
-n masm.exe 
-l 
-n small; 
-g 
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987.  All rights reserved.
  51448 + 383976 Bytes symbol space free
      0 Warning Errors
      0 Severe  Errors
Program terminated normally
-n link.exe 
-l 
-n small; 
-g 
Microsoft (R) Overlay Linker  Version 3.60
Copyright (C) Microsoft Corp 1983-1987.  All rights reserved.
LINK : warning L4021: no stack segment
Program terminated normally
-n c:\dos\exe2bin.exe 
-l 
-n small.exe 
-g 
Program terminated normally
-
        12.    O (아웃풋)
O 명령은 I/O 포트에 데이타를 출력한다.
형식)   O [포트어드레스 바이트데이타]
        13.    P (진행)
P 명령은 프로그램을 로드한 상태에서 실제로 프로그램을 한명령씩 실행 시키
는 것이다. 따라서 오히려 T 명령보다 정확하게 프로그램을 추적할수 있다.
형식)   P                               ---- ①
        P [=어드레스]                   ---- ②
        P [=어드레스,넘버]              ---- ③
        P [넘버]                        ---- ④
① 현재의 CS:IP 에서 실행 시킨다.
② IP 의 값을 지정해준 번지에서부터 실행한다.
③ IP 의 값과 실행시킬 명령의 갯수만큼 실행한다.
④ 실행시킬 명령의 갯수만큼 실행한다.
C:\ASM>debug small.com 
-p 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0103   NV UP EI PL NZ NA PO NC
155E:0103 3C00          CMP     AL,00
-p=110 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0002
DS=155E  ES=155E  SS=155E  CS=155E  IP=0115   NV UP EI PL ZR NA PE NC
155E:0115 6C            DB      6C
-p=100 
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0103   NV UP EI PL ZR NA PE NC
155E:0103 3C00          CMP     AL,00
-
-p=110,4 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0002
DS=155E  ES=155E  SS=155E  CS=155E  IP=0115   NV UP EI PL ZR NA PE NC
155E:0115 6C            DB      6C
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0119   NV UP EI PL ZR NA PE NC
155E:0119 66            DB      66
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0121   OV UP EI PL NZ NA PE CY
155E:0121 BA0901        MOV     DX,0109
AX=0000  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0124   OV UP EI PL NZ NA PE CY
155E:0124 CD21          INT     21
-
-p4 
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0105   NV UP EI PL ZR NA PE NC
155E:0105 7522          JNZ     0129
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0107   NV UP EI PL ZR NA PE NC
155E:0107 EB16          JMP     011F
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=011F   NV UP EI PL ZR NA PE NC
155E:011F B409          MOV     AH,09
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=C640  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0121   NV UP EI PL ZR NA PE NC
155E:0121 BA0901        MOV     DX,0109
-
        14.    Q (종료)
Q 명령은 디버거를 종료하고 도스로 빠져나간다.
Ctrl-C 또는 Ctrl-Break 으로는 빠져나갈 수 없다.
형식)   Q
        15.     R (레지스터)
R 명령은 현재의 레지스터의 내용을 보여준다.
형식)   R                               ---- ①
        R [레지스터]                    ---- ②
        R [F]                           ---- ③
① 단지 레지스터의 내용을 나타낸다.
② 레지스터의 내용을 나타내고 새로이 설정할 수 있다.
   레지스터는 AX,BX,CX,DX,SP,BP,SI,DI,DS,ES,SS,CS,IP,이다.
③ F 는 프래그 레지스터이다.
   프래그 
 治뵀痼 각 프래그가 나타내는것은 다음과 같다.
   만약 프래그를 변경하려면 새로이 코드를 입력한다.
+----------------------------+----------------+---------------+
|       Flag name            |      설정      |      해제     |
+----------------------------+----------------+---------------+
|       Overflow             |       OV       |       NV      |
|       Drection             |       DN       |       UP      |
|       Interrupt            |       EL       |       DL      |
|       Sign                 |       NG       |       PL      |
|       Zero                 |       ZR       |       NZ      |
|       Auxiliary Carry      |       AC       |       NA      |
|       Parity               |       PE       |       PO      |
|       Carry                |       CY       |       NC      |
+----------------------------+----------------+---------------+
C:\ASM>debug small.com 
-r 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0100   NV UP EI PL NZ NA PO NC
155E:0100 A08000        MOV     AL,[0080]                          DS:0080=00
-r ax            ---- ①
AX 0000           ---- ②
:100             ---- ③
-r 
AX=0100  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0100   NV UP EI PL NZ NA PO NC
155E:0100 A08000        MOV     AL,[0080]                          DS:0080=00
-r f             ---- ④
NV UP EI PL NZ NA PO NC  -ov cy          ---- ⑤
-r f 
OV UP EI PL NZ NA PO CY  -
-r 
AX=0100  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0100   OV UP EI PL NZ NA PO CY
155E:0100 A08000        MOV     AL,[0080]                          DS:0080=00
-
① AX 레지스터의 내용을 보인다.
② AX 레지스터의 내용
③ 새로이 AX 레지스터의 내용을 설정한다.
④ 프래그 레지스터의 내용을 보인다.
⑤ 오버플로우 프래그와 캐리 플래그의 내용을 변경한다.
        16.     S (검색)
S 명령은 메모리내의 특정한 데이타를 찾아내고 발견된 어드레스를 표시한다.
형식)   S ['문자,문자열']
앞에서 만들어 보았던 SMALL.COM 의 메시지인 'Ex) small file1 file2' 중에서
'small' 을 찾아내보자.
C:\ASM>small 
Ex) small file1 file2                   ---- ①
C:\ASM>debug small.com                 ---- ②
-r                                     ---- ③
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0100   NV UP EI PL NZ NA PO NC
155E:0100 A08000        MOV     AL,[0080]                          DS:0080=00
-s 155e:100 'small'                    ---- ④
155E:010D                               ---- ⑤
-
① small.com 의 메시지이다.
② small.com 을 디버거로 로드한다.
③ R 명령으로 CS:IP 의 값을 알아낸다.
④ 155E:100(CS:IP) 에서부터 'small' 의 문자열을 검색한다.
⑤ 문자열을 찾아낸 메모리의 번지
        17.     T (트레이스)
T 명령은 프로그램을 1 명령씩 실행하고 그때의 레지스터의 값,프래그의 상태
,명령을 표시해준다.
형식)   T                                ---- ①
        T [=개시어드레스]                ---- ②
        T [=개시어드레스 횟수]           ---- ③
① 현재의 CS:IP 의 값에서 1 명령씩 수행한다.
② 개시 어드레스에서 부터 1 면령씩 수행한다.
③ 개시 어드레스에서 부터 횟수만큼 수행한다.
C:\ASM>debug small.com 
-t 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0103   NV UP EI PL NZ NA PO NC
155E:0103 3C00          CMP     AL,00
-t 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0105   NV UP EI PL ZR NA PE NC
155E:0105 7522          JNZ     0129
-t 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=0107   NV UP EI PL ZR NA PE NC
155E:0107 EB16          JMP     011F
-t 
AX=0000  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=155E  ES=155E  SS=155E  CS=155E  IP=011F   NV UP EI PL ZR NA PE NC
155E:011F B409          MOV     AH,09
-
-t=110 
AX=0900  BX=0000  CX=01FF  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0002
DS=155E  ES=155E  SS=155E  CS=155E  IP=0115   NV UP EI PL ZR NA PE NC
155E:0115 6C            DB      6C
-
-t=110 5 
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0001
DS=155E  ES=155E  SS=155E  CS=155E  IP=0111   NV UP EI PL ZR NA PE NC
155E:0111 6C            DB      6C
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0002
DS=155E  ES=155E  SS=155E  CS=155E  IP=0112   NV UP EI PL ZR NA PE NC
155E:0112 206669        AND     [BP+69],AH                         SS:0069=00
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0002
DS=155E  ES=155E  SS=155E  CS=155E  IP=0115   NV UP EI PL ZR NA PE NC
155E:0115 6C            DB      6C
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0116   NV UP EI PL ZR NA PE NC
155E:0116 65            DB      65
AX=0900  BX=0000  CX=01FF  DX=0109  SP=FFFE  BP=0000  SI=0000  DI=0003
DS=155E  ES=155E  SS=155E  CS=155E  IP=0119   NV UP EI NG NZ NA PE NC
155E:0119 66            DB      66
-
        18.     U (역 어셈블)
U 명령은 기계어를 역 어셈블해준다.
이 명령에 의해 역 어셈블된 코드는 정확한 프로그램의 코드가 아니다.
디버거는 명령코드인지 아니면 데이타 인지를 가리지 않고 무조건 역어셈블
하기 때문이다. 따라서 대게 점프 명령이후의 역어셈코드는 데이타인 경우가
많다.
형식)   U                               ---- ①
        U [범위]                        ---- ②
        U [개시어드레스]                ---- ③
① CS:IP 로부터 32바이트를 역어셈블한다.
② 범위로 정해진만큼 역어셈블한다.
③ 개시 어드레스로부터 이후 32바이트를 역어셈블한다.
C:\ASM>debug small.com 
CS:IP 로부터 32바이트를 역 어셈블한다.
-U 
155E:0100 A08000        MOV     AL,[0080]
155E:0103 3C00          CMP     AL,00
155E:0105 7522          JNZ     0129
155E:0107 EB16          JMP     011F
155E:0109 45            INC     BP
155E:010A 7829          JS      0135
155E:010C 20736D        AND     [BP+DI+6D],DH
155E:010F 61            DB      61
155E:0110 6C            DB      6C
155E:0111 6C            DB      6C
155E:0112 206669        AND     [BP+69],AH
155E:0115 6C            DB      6C
155E:0116 65            DB      65
155E:0117 3120          XOR     [BX+SI],SP
155E:0119 66            DB      66
155E:011A 69            DB      69
155E:011B 6C            DB      6C
155E:011C 65            DB      65
155E:011D 3224          XOR     AH,[SI]
155E:011F B409          MOV     AH,09
-
CS:100 ∼ 110 의 내용을 역 어셈블한다.
-u 100 110 
155E:0100 A08000        MOV     AL,[0080]
155E:0103 3C00          CMP     AL,00
155E:0105 7522          JNZ     0129
155E:0107 EB16          JMP     011F
155E:0109 45            INC     BP
155E:010A 7829          JS      0135
155E:010C 20736D        AND     [BP+DI+6D],DH
155E:010F 61            DB      61
155E:0110 6C            DB      6C
-
CS:200 이후 32바이트를 역 어셈블한다.
-u 200 
155E:0200 73E4          JNB     01E6
155E:0202 B43E          MOV     AH,3E
155E:0204 8B1EA802      MOV     BX,[02A8]
155E:0208 CD21          INT     21
155E:020A B43E          MOV     AH,3E
155E:020C 8B1EAA02      MOV     BX,[02AA]
155E:0210 CD21          INT     21
155E:0212 E85300        CALL    0268
155E:0215 B44C          MOV     AH,4C
155E:0217 CD21          INT     21
155E:0219 EB0C          JMP     0227
155E:021B 52            PUSH    DX
155E:021C 65            DB      65
155E:021D 61            DB      61
155E:021E 64            DB      64
155E:021F 206572        AND     [DI+72],AH
-
        19.     W (쓰기)
W 명령은 메모리의 내용을 화일이나 임의의 섹터에 써 넣는다.
형식)   W [어드레스]
        W [어드레스 드라이브번호 레코드번호 섹터수]
다음은 디버그를 이용해서 컴퓨터를 리부팅 시켜주는 잘 알려진 프로그램을
만들어본다. 이 부팅은 웜 부팅이고 메모리를 검사하지 않는다.
C:\ASM>debug reboot.com 
File not found
-a 100 
154D:0100 mov   ax,40                  ---- ①
154D:0103 mov   ds,ax                  ---- ②
154D:0105 mov   ax,1234                ---- ③
154D:0108 mov   [72],ax                ---- ④
154D:010B jmp   ffff:0                 ---- ⑤
154D:0110 
-r cx                                  ---- ⑥
CX 0000
:10                                    ---- ⑦
-w 
Writing 00010 bytes
-q 
① AX 에 40H 를 넣는다.
② DS 에 AX 를 복사한다.
   이것은 결국 DS 를 설정하는 작업이다. (DS=40H)
③ AX 에 1234H 를 넣는다.
④ DS:72H 에 1234H 를 넣는다.
   이것은 DS:72H 에 워드 1234H 를 넣으면 웜부팅시에 메모리 검사를 생략하기
   때문이다.
⑤ 부트 스트랩 프로그램으로 분기
⑥ CX 레지스터를 새로 작성하기 위함이다.
⑦ CX 에 10H 를 넣는다.
   이것은 W 명령시에 CX 레지스터의 값 만큼 쓰기 때문이다.
이상입니다.
어땠어요? 괜찮았죠?
워드로 뽑아두시면 좋은 교재가 될것입니다.
안녕히계세요.
 [26] 제목 : [예고] 강좌를 시작하기 전에...
 올린이 : natali  (박선근  )    95/01/20 02:18    읽음 : 165  관련자료 없음
 안녕하세요.. 나탈리 박선근입니다.
 어셈블리 강좌를 시작하기 전에 알려드릴 것과 부탁하고픈 것이
 있어서 그 예고편을 올립니다.
 이번에 하게될 어셈블리 강좌는 어셈블리 소스를 분석하는 형식으로
 진행하게 됩니다. 그런데 강좌에 쓸 재료가 너무 부족한 형편입니다.
 구상하기는 바이러스 코드를 분석해 보려고 했는데 그 소스를 얻기가
 그리 쉬운 일이 아니군요.
 바이너리라도 있다면 좋겠지만 그것도 없어서 오늘 자료실을 이곳 저곳
 뒤졌습니다만 한 건도 못올렸습니다.
 강좌에 쓰일 만한 재료감을 갖고 계신 분은 제게 좀 보내 주세요.
 바이러스 코드가 아니라도 괜찮습니다. 다만, 그래픽 프로그램이나
 상업용 프로그램의 락 같은 것은 사절하겠습니다.
 보내주신 코드가 강좌에 쓰일지는 모릅니다. 그건 제가 코드를 보고
 강좌에 쓰일 만한 내용인가를 결정합니다.
 그럼 관심있는 분의 도움을 바라면서 이만...
 [28] 제목 : [강좌] 어셈블리 소스분석 <1>
 올린이 : natali  (박선근  )    95/01/24 19:14    읽음 : 451  관련자료 없음
=============================================================================
어셈블리 < 1 >  - Source 분석을 중심으로 -
                                             작성: 박선근(NATALI), 1995.01.
* 간편화를 위해 경어를 사용하지 않았습니다.
* TASM 1.0 이상 또는 MASM 5.0이상의 어셈블러가 필요합니다.
-----------------------------------------------------------------------------
<> 어셈블리가 필요한 이유 <>
=============================================================================
[ 어셈블리의 효용성 ]
어셈블리어는 인간이 이해할 수 있는 유일한(?) 저수준 언어이다.
예전의 거의 대부분의 우수한 프로그램들은 어셈블리로 제작되었었고, 지금도 어셈
블리는 여전히 중요한 언어임에 틀림없다.
그러나 어셈블리어가 표현과 판독의 어려움이 있고 프로그램 개발에 투자해야 하는
노력의 비대함으로 점차적으로 그 소용이 미진해 지고 있는 것 또한 사실이다.
현재  고급언어 중에서 가장 최적의 코드를 생성하는 것으로 평가되는  C언어 역시
궁극에는 어셈블리의 범주에 포함됨에도 불구하고 마치 어셈블리가  C를 위해 있는
듯한 착각을 일으킬 만큼 어셈블리의 사용층은 엷어졌고,  대신 C의 사용층은 그만
큼 두터워 졌다.  그러나, 전혀 새로운 유형의 시스템과 언어가 나오지 않는 한 어
셈블리는 여전히 최적의 코드를 생성하는 언어로 존재할 것이고, 또 사용될 것이다
(현재의 모든 시스템은 0과 1의 표현에 의존하는 기계어를 그 
 �瓮 삼고있다
그런 점에서 어셈블리는 기계어를 대신하는 가장 간결한 코드를 생성한다. 그러나
만약 시스템이 인간의 말을 바로 이해하는 이른 바 '인공지능'이 현실화 된다면 더
이상 어셈블리를 사용하여 복잡한 프로그래밍을 할 이유는 없을 것이다. 말하는 것
이 곧 프로그램이 될테니까...)
많은 프로그램들이 C를 통해 구현되고 있다. 그러나 전문적인 프로그래머는 결코
C 하나에 의존하지 않는다. C가 편리하기는 하지만 결코 최적의 코드를 생성하지는
못한다는 것을 잘 알고 있기 때문이다. 그렇다고 해서 어셈블리만을 사용하지도 않
는다. 그건 너무나 비경제적이다.
가장 좋은 방법은, C와 어셈블리를 병용하는 것이다. 이런 것이 있다.
데이타베이스를 구축하는데 굳이 C나 어셈블리를 사용할 필요는 없다. 이미 데이타
베이스를 위한 전문적인 언어들이 있다.  클리퍼나 폭스프로 등의 쉽게 데이타베이
스를 구축할 수 있는 언어들이 개발되어 있는 것이다. 쉽게 할 수 있는데  굳이 어
렵게 할 이유는 없는 것이다.  그런데, 기계를 제어하는 프로그램을 만드는데 클리
퍼나 폭스프로 만을 사용할 수 있겠는가? 어려운 일이다. 이럴 땐 오히려 C나 어셈
블리를 사용하는 것이 경제적이다. 그렇다면, 데이타베이스내에서 기계를 제어해야
한다면 어떻게 해야 하는가?  데이타베이스 구축 부분은 데이타베이스를 위한 전용
언어를 사용하고,  기계제어하는  부분은 또 그에 적합한 언어를 사용하여 그 둘을
결합한다면 일은 보다 수월해 질 것이다.
C와 어셈블리를 병용하는 것도 이러한 내용과 맥락을 같이 한다.
보다 빠른 실행 속도가 요구되는 부분은 빠른 처리가 가능한 언어로,  그다지 속도
는 요구되지 않지만 어셈블리와 같은 복잡한 언어로는 구현하기 까다로운 부분은
표현이 보다 쉬운 언어로 작성하여 그 둘을 결합하는 것이다.
그런 점에서, 어셈블리는 어떤 언어보다도 빠른 처리를 가능하게 한다.  이것이 어
셈블리가 구현이 어려운 중에도 꾸준히 사용되고 있는 가장 유력한 이유이며, 어셈
블리의 효용성이 여기에 있는 것이다.
[ 어셈블리를 배우는데 필요한 것들 ]
본 강좌를 보시는 데는 아래의 사항을 준비하고 있으면 도움이 된다.
        - 디버거(Debugger)
          프로그래밍을 하는데 있어서 필수적인 것이다.
          자신의 손에 익은 디버거가 있다면 좋겠지만 그렇지 못하다면 먼저 디버
          거의 사용을 익히는 것이 좋겠다.
          디버거는 여러 종류가 있는데 가장 간단한 형태로는 도스에 함께 제공되
          는 debug가 있고, 볼랜드의 Turbo Debugger와 MS의 Code View 등이 가장
          많이 사용되고 있다. 이 강좌는 Turbo Debugger와 Code View가 구입하기
          어려운 점을 감안하여 도스의 debug를 표준 디버거로 사용할 것이다.
          debug의 상세한 사용 방법은 메뉴얼을 참고하시기 바라고,  이 강좌에서
          는 debug의 명령어 사용에 관한 일체의 설명을 하지 않는다.
        - 소서(Sourcer)
          이 프로그램은 어셈블리 source를 얻을 수 있도록 하는 역어셈블러이다.
          'V Communication'이라는 곳 (회사 이름이 정확한지 모르겠다)에서 나온
          프로그램인데 아마 쉐어일 것이다. 이 프로그램이 있다면 좋은 일이겠으
          나 없어도 상관없다. 역어셈블 코드는 도스의 debug를 통해서도 얻을 수
          있기 때문이다. debug로 역어셈블 코드를 얻는 방법은 따로 설명을 드리
          겠다.
        - 프린터(Printer)
          프린터가 없다면 상당히 곤란하다. 수백, 수천 line의 어셈블리 코드를
          화면만 통해서 보기는 무척 힘든 까닭이다. 한  화면에 나타낼 수 있는
          line의 수가 너무 작기 때문에 전체적인 윤곽을 잡기가 무척 어렵다.
          이 때는 프린트해 놓고 보아야 한다. 프린터가 없다면 비상한 기억력(?)
          과 어떤 유혹도 뿌리치고 컴퓨터 모니터에 집중할 수 있는 무서운(?) 인
          내력이 요구될 것이다.
[ debug를 통해 역어셈블 코드를 얻는 방법 ]
debug는 간이 어셈블러라고도 불릴 만큼 나름대로 독특한 기능을 보유하고 있다.
직접 어셈블리 코드를 써넣을 수 있을 뿐만 아니라 메모리의 내용을 역어셈블해 볼
수도 있다. 역어셈블된 코드를 화일이나 프린터로 출력하기 위해서는 도스의 필터
기능을 이용하면 된다.
        우선 다음과 같은 간단한 내용의 텍스트 화일을 작성해 두자.
        u 100 200               <- 모든 .COM프로그램은 100h번지에서 시작된다.
        q                       <- 반드시 'q(Q)'가 있어야 한다.
                                   그렇지 않으면 필터에서 빠져 나오질 못한다.
        이 화일의 이름을 "dump.dat"라고 하자.
        이제 명령행 상에서 다음과 같이 입력한다.
        C:\>debug command.com < dump.dat > command.a
        명령을 입력하고 잠시 기다렸다가 디렉토리를 보면 'command.a'가 새로
        생성되었을 것이다.
        이 화일의 내용을 보면 어셈블리 코드가 들었을 텐데, 이는 위의 일련의
        동작을 통해 필터처리된 command.com의 CS:0100h~CS:0200h 범위의 역어셈
        블리 코드이다. command.com의 모든 내용을 역어셈블 하자면 전체 프로그
        램의 크기 만큼 처리하면 될 것이다(하지만 이런 일은 하지 말기 바란다.
        아래에 실험을 위한 보다 작은 프로그램을 예로 들었다)
        이런 방법으로, 다소 답답한 감이 있지만 sourcer없이 debug를 통해 어셈
        블리 코드를 얻게 된다.
[ debug를 통해 역어셈블리 코드를 얻는 간단한 실험 ]
궁금증을 해소하기 위해 간단한 실험을 해보도록 하자. debug를 기동시키고 다음과
같이 입력한다.
        C:\>debug
        -a
        jmp     110
        db      'Hello, World!$'
        mov     dx,102
        mov     ah,9
        int     21
        mov     ax,4c00
        int     21
        <ENTER>
        -nhello.com
        -rcx
        1c
        -w
        -q
위의 내용을 모두 입력했다면 debug에서 빠져 나와 있을 것이다.
디렉토리를 보면 'hello.com'이 새로이 생성되어 있을 것인데, 이 프로그램은 실행
할 수 있다. 실행하면 화면에 'Hello, World!'를 출력한다.  위의 프로그램을 이젠
거꾸로 역어셈블 해보자.
        다음과 같은 내용의 'dump.dat'화일을 작성한다.
        u 100 11c
        q
        이제 도스상에서 다음을 입력하자.
        C:\>debug hello.com < dump.dat > hello.asm
        생성된 'hello.asm'을 보면 위에서 입력할 때와는 조금 다름을 알 수 있다
        다른 부분은  'Hello, World!$'를 찾을 수 없는 것인데 대신 'DB ...'라는
        내용이나 입력하지 않았던 명령등을 볼 수 있을 것이다.
        CS:0100 JMP     0110            ; 데이타 부분을 건너뜀      ----+
                                        ;                               |
        CS:0102 DEC     AX              ; 이 부분이 'Hello, World!$'    |
                DB      65              ;       "          "            |
                DB      6C              ;       "          "            |
                DB      6C              ;       "          "            |
                DB      6F              ;       "          "            |
                SUB     AL,20           ;       "          "            |
                PUSH    DI              ;       "          "            |
                DB      6F              ;       "          "            |
                JB      0179            ;       "          "            |
                DB      64              ;       "          "            |
                AND     [SI],SP         ;       "          "            |
                                        ;                               |
        CS:0110 MOV     DX,0102         ; 문자열 출력 부분          <---+
                MOV     AH,09
                INT     21
        CS:0117 MOV     AX,4C00         ; 종료처리
                INT     21
        이 프로그램의 경우는 직접 작성한 것이므로 정확히 데이타가 어디에서 어
        디까지라는 것을 알 수 있었지만 자신이 작성하지 않은 어떤 임의의  프로
        그램을 역어셈블한다면 그런 것들을 어떻게 알 수 있을까?
        힘든 일이지만, 그런 내용을 파악하는 것이 바로 '분석'의 묘미이다. 많은
        경우에 그러한 내용을 판단하는 것은  분석자의 직관(?)이나  경험에 의해
        파악된다. 위의 프로그램의 예에서는 'jmp'에 의해 아예 데이타 부분을 건
        너 뛰고 있다. 그리고, 도스의 문자열 출력 함수인 09h는 DX에  출력할 문
        자열의 옵셋을 가지며 그 문자열의  끝은 반드시 '$'이다.  이러한 점으로
        미루어 볼 때, 옵셋 102h에서 10Fh까지는 실행할 수 없는  데이타 임을 짐
        작하여 알 수 있다(정말일까?)
        물론, 현재로썬 필자가 이렇게 말하니 '그런것 같다..' 하는 생각을 할 것
        이다.  하지만 실전(?)에서는 간단한 문제가 아니다. 수천라인(어셈블리에
        서 수백라인 넘기기는 쉬운 일이다)의 코드에서  어떻게 간단할 수 있겠는
        가? 어려운 일이다.
[ 강좌를 시작하기 전의 문제점들... ]
본 강좌에서는 지금 그렇게 어려운 일을 해보려고 한다. 강좌가 어떻게 진행될지는
글을 쓰고 있는 본인으로써도 예측할 수 없다.
예고편에서 알려 드렸듯이, 분석해 볼만한 어셈블리 소스를 구하는 일이 그다지 쉬
운 일이 아니다(분석하기도 어려운데 재료마저 구하기 어렵다).  가장 구히기 쉬운
코드는  '바이러스'라고 생각되서(이건 저작권 문제에 크게 신경쓰지 않아도 된다)
몇분이 보내주신 바이러스 코드를 살펴 봤다. 그런데 필자가 바이러스에 대해 아는
게 없어서 인지는 모르겠으나 다음과 같은 생각을 하게 되었다.
        - 바이러스 코드들은 한결 같이 쓰잘데 없는(?) 기교를  많이 부려서 눈을
          어지럽게 했다(물론 숨기려는 의도가 있는 것들이니 그럴 것이다).
        - 우연인지,  아니면 바이러스 코드의 정통성(?)인지는 모르겠으나 비슷한
          형태가 많았다 (어떤 모범적인(?) 바이러스의 변종들이었던지...). 나름
          대로 조금씩 변화를  가지기는 했으나 그건 조금 장난친 것에 지나지 않
          았다(예를 들자면,  상주하는 코드의 크기를 조금 다르게 한다던가 내부
          적으로 사용하는 바이러스 인식 코드를 다르게 한 내용들.... 만약 모든
          바이러스가 이런 형편이라면 바이러스  만든 사람들은 더 늦기 전에  바
          이러스에 대한 생각일랑 싹 지우고 그  시간에 좀 더 유용한 프로그램을
          구상하는게 좋지 않을까?)
        - 크기가 적어도  2,000~3,000 바이트 정도가 되니 역어셈블  코드로는 약
          20~30페이지(프린트했을 때) 정도의  제법 큰 코드가 되었다 (이 정도면
          하나 분석하는데 몇일이 걸려야 할까? 그것도 온라인 강좌로...)
어떤 코드는 약 2~3페이지 정도의 작은 분량도 있었는데 그건 바이러스가 아니었다
바이러스라고 설명되어 있기는 했으나 일반적인  바이러스 코드가 가지는 특성들을
구비하지 못한 것들이었고, 분석할 만한 내용이 못되었다(너무 간단해서...)
강좌를 시작하기 전에 간추려 본 문제점들은 다음과 같다.
        - 바이러스 코드의 기교가 너무 혼란스러워서, 이런 것들을 강좌에서 다룰
          만큼 가치가 있을까 하는 의문이 생기며,  그런 기교들이 어셈블리에 대
          한 이해를 목적으로 하는 본 강좌의 목적과 어느 정도  부합되는가 하는
          당위성에 대한 회의(?).
        - 이런 바이러스 코드의 분석이 반드시 좋은 결과만을 줄 수 있을까?
          바이러스 코드를 살펴본 바로는 변종이 많은 것 같은데  이 강좌가 그런
          변종의 발생을 촉진하는 결과가 되지는 않을까?
        - 이 강좌가 온라인인 관계로, 20~30 페이지나 되는 분량의 어셈블리 코드
          가 너무 부담스럽다.
바이러스 코드를 분석한다고 할 때, 가장 우려되는 점은 두번째의 경우이다.
'해커'라는 말이 공공연히 나쁜 의미로 해석되고 말해지는 요즈음의 추세이고 보면
예측할 수 있는 가장 최악의 경우는  또다른 변종 바이러스가 나올 수 있다는 것이
다. 필자는 그런 결과를 원치 않는다.
그래서 본 강좌에서는 바이러스 코드에 대해서 만큼은 전체  소스를 소개하는 대신
부분적으로 사용된 기교들을 분석하는 방법을 취한다.  물론 바이러스 코드가 아니
라면 모든 내용에 대한 분석을 시도할 것이다.
본 강좌의 목적이 어셈블리를 배우고자 하는데 있으므로 부분적으로 발췌된 내용을
분석하더라도 그곳에서 얻을 것은 많다. 물론 이러한 방법은 전체적인 흐름에 대한
이해면에서는 다소의 부족한 점이 있을 것이다. 이점은 다른 소스를 분석하는 것으
로 대신할 것이다. 본 강좌를 보시는 분들은 이같은 필자의 고충(?)을 이해해 주셨
으면 고맙겠다.
 [29] 제목 : [목록] 어셈블리 강좌 목록입니다..
 올린이 : 아꾸    (하성욱  )    95/02/05 00:51    읽음 : 126  관련자료 없음
                  ASSEMBLER 강좌 목록
                ━━━━━━━━━━━━━━━━
     아이디   이름    제목                              게시판 번호
 ─────────────────────────────────
    까망벌레 정태식   [초급-기초] 맛보기...                    3
    까망벌레 정태식   [초급-기초] 메모리에 대해서           4~ 5
    까망벌레 정태식   [초급-기초] 레지스터에 대해서            6
    까망벌레 정태식   [초급-실습] 프로그램 하나(소스&설명   7~ 8 
    까망벌레 정태식   [초급-보충] 스텍?                        9  
    까망벌레 정태식   [초급-실습] 프로그램 두울            10~11 
    까망벌레 정태식   [초금-명령] MOV 에 대해                 12  
    까망벌레 정태식   [초급-실습] 프로그램 세엣               15  
    까망벌레 정태식   [초급-보충] 변수 선언에 대하여          16  
    까망벌레 정태식   [초급-보충] 주소지정방식에 대하여...    17  
    까망벌레 정태식   [초급-보충] 프로시져 및 스텍의 변화에   18
    까망벌레 정태식   [초급-보충] 논리연산에 대해서...        19  
    영원의별 이세원   디버그(DEBUG.EXE) 정리               23,25 
    natali   박선근   [강좌] 어셈블리 소스분석 <1>            28
 ─────────────────────────────────
 2/4일짜 까지의 어셈블리 강좌란 목록입니다.
 [30] 제목 : [강좌] 어셈블리 소스분석 <2>
 올린이 : natali  (박선근  )    95/02/08 20:48    읽음 : 308  관련자료 없음
=============================================================================
어셈블리 < 2 >  - Source 분석을 중심으로 -
                                             작성: 박선근(NATALI), 1995.02.
* 간편화를 위해 경어를 사용하지 않았습니다.
* TASM 1.0 이상 또는 MASM 5.0이상의 어셈블러가 필요합니다.
-----------------------------------------------------------------------------
<> 첫번째 프로그램 - Disk Monitor <>
=============================================================================
[ 변명 ... ]
서비스 이용료가 연체된 줄 모르고 있다가 설연휴 지나고서야 알았습니다. 나우는
그 달 25일까지 이용료를 내지 않으면 다음 달 1일에 사용중지 된다는 군요.
음.. 전 그 사실을 전혀 모르고 있다가 연휴 끝나는 날 접속해보니... 흘~
이래저래 첫 강좌 올리고 근 2주일이 지나버렸군요.  이에 죄송한 말씀을 드리고,
강좌를 시작하기 전에 여러분께 한가지 당부하고 싶은 것이 있습니다.
근래 며칠 동안 이번 강좌의 내용에 대해 많은 생각을 했었습니다. '바이러스분석'
이라는 것 때문이었죠.  강좌의 서두에서 분명히 본 강좌의 목적이 '바이러스분석'
에 있는 것이 아니라  '다양한 어셈블리 표현을 익히는'데 있다는 것을 밝혔었습니
다만 많은 분들이 강좌의 목적에 대한 부분을 지나치신 것 같습니다.  바이러스 코
드를 분석하는 일은 본 강좌에서 주요 줄거리가 못됩니다.  제가 강좌를 위해서 프
로그램을 직접 작성하고 그 내용을  소개할 수도  있겠지만 그건 너무 많은 시간을
소모하게 되기 때문에 조금 편리한  방향에서 저작권 문제에 지장이 없는 바이러스
이야기가 나온 것입니다.  그런데 많은 분들이 제가 한번도 들어 본적이 없는 수많
은 바이러스에 대한 질문을 하셨고 또 그것들을 분석해 달라고 자료를 보내 주셨습
니다. 이번 일로 많은 분들이 바이러스에 대한 관심이 크다는 것과 저 또한 여러가
지를 알게 된 것도 사실이지만 그 보다는 '변형바이러스'에 대한 걱정이 더 큽니다
제가  살펴 본 바로는 우리나라에서 제작된 거의 대부분의 바이러스들이 외국의 것
을 변형한 것이었습니다. 모방은 창조의 어머니라지만 글쎄요... 이런 경우에도 그
런 말이 정당할 것 같지는 않습니다.
그래서 이런 저런 고민 끝에 본 강좌에서는 바이러스 코드를 분석하더라도 전체 내
용은 소개하지 않습니다. 특별하거나 독특한 표현이 있다면 그런 부분 만을 개별적
으로 소개할 것입니다. 바이러스 코드가 아닐 때는 전체 소스를 소개할 것입니다.
본 강좌의 목적이 '바이러스 분석'에 있지 않음을 다시 한번 분명히 밝히고 오해없
기를 바라며 두번째 강좌를 시작하겠습니다.
[ 어셈블리 프로그래밍 시의 주의점들 ]
어셈블리 프로그래밍은 여타의 고급 언어 프로그래밍에서는 신경쓰지 않아도 될 많
은 내용을 프로그래머가 일일이 신경써 주어야 한다. 이러한 내용은 보다 섬세하고
강력한 프로그램을 작성할 수 있는 요소가 되지만,  다른 면으로는 매우 성가신 문
제가 아닐 수 없다. 어셈블리 프로그래밍에서 발생할 수 있는 중요하면서도 성가신
몇가지 문제점들을 정리해 보았다.
- 스택(Stack)
  스택의 크기는 '적당한 것'이 좋다. 그러나 적당한 크기의 스택을 설정하기란 상
  당히 신경쓰이는 일이다. 그래서 일반적으로 어느 정도의 여유를 두고 스택을 결
  정하게 된다. 어떤 경우에, 스택이 모자란다고 해도 프로그램이 정상적으로 수행
  될 수가 있는데 이는 스택의 넘친 부분이 다행히 프로그램의 수행에 지장이 없었
  기 때문이다. 그러나 이것은 명백한 버그이며, 프로그램이 언제 심각한 에러를
  발생할지 모르는 잠재적인 폭주 가능성을 안고 있는 것이다. 이런 이유로 스택은
  '어느 정도 여유를 갖고' 결정되는 것이 안전하다고 할 수 있다. COM파일의 경우
  코드,데이타,스택이 모두 하나의 세그먼트 안에 있으므로 스택의 사용은 더욱 조
  심스럽게 행해져야 한다. 코드나 데이타 세그먼트의 크기가 커짐에  따라 그만큼
  스택의 크기가 줄어 들기 때문이다.
- 레지스터(Register)
  어셈블리 프로그래밍에서 레지스터의 사용은 빼놓을 수 없는 부분인 만큼 중요성
  또한 크다.  그러나 레지스터는 사용 빈도나 중요성에 비해 크기가 너무 작고 일
  시적이다.  그러므로 레지스터의 내용이 보관될 필요가 있고 다른 일을 수행하는
  과정에서 그 내용이 변경될 가능성이 있다면 그 전에 적절한 장소에 보관해 두어
  야 한다.
- 변수/데이타의 참조
  다음에 나타낸 어셈블리 표현들에서 DX가 가지는 값은 무엇일까?
        VALUE   DW      1234H
    (1) MOV     DX, VALUE
    (2) MOV     DX, [VALUE]
    (3) MOV     DX, OFFSET VALUE
  (1)과 (2)는 결과가 동일하고 (3)은 다르다.
    (1), (2) : DX = 1234H
         (3) : DX = 1234H가 있는 메모리상의 주소(Offset Address)
  표현 (1), (2), (3)은 지루한(?) 어셈블리 프로그래밍에서 때때로  혼동할 수 있
  는 소지를 갖고 있다. 고급언어 프로그래밍에서도 마찬가지 이겠지만, 훌륭한 프
  로그래머가 되기 위해서는  어중간한 표현을 삼가하고 명확한 표현방법을 익히는
  데 힘써는 것이 중요하다. 더우기 VALUE와 [VALUE]의 경우는 동일한 결과를 갖지
  만 전자 보다는 후자가 보다 명백하게 '값'의 의미를 강조하고 있다.
- LABEL의 사용과 함수 구성
  어셈블리 프로그램에 있어서 함수로 처리해야  할 부분과  분기 명령을 사용해서
  강제적으로 이동해야 할 부분을 구분하는 일은  프로그램의  최적화에 큰 영향을
  끼칠 수 있으므로 신중히 처리해야 한다.
보다 기본적인 문제들이 더 있지만 여기서 모든 내용을 언급하지는 않는다. 강좌가
진행되면서 그런 내용들이 부분적으로 다루어 질 것이다.
[ 첫번째 프로그램 - DISKMON.ASM ]
다음의 어셈블리 코드는 이세원(영원의별)님이 보내주신 프로그램을 역어셈블하고,
TASM과 MASM에서 어셈블될 수 있도록 필자가 함수/라벨등을 적절히 구분한 것이다.
프로그램의 내용이 신선하고, 본 강좌에서 처음으로 분석하게 될 프로그램인 만큼
가벼운 마음으로 풀어 볼 수 있는 내용으로 생각되어 소개한다.
참고로, 이 프로그램은 램상주 프로그램인데 이세원님이 보내주신 원래의 프로그램
인 DISKMON.COM의 크기는 783바이트였으며 램에 상주하면 624바이트의 메모리를 차
지하게 되어 있었다. 그러나, 여기에 소개된 소스를 어셈블해보면 아시겠지만 파일
의 크기는 803바이트(MASM=803바이트, TASM=802바이트), 램상주시의 메모리 차지는
640바이트로 변경되었다. 변경(추가)된 부분은 뒤에서 알려드리겠다.
;---------------------------------------------------------------------------
; DISKMON.COM, Disk Monitor
;
; To build      MASM /ML diskmon;
;               LINK diskmon;
;               EXE2BIN diskmon.exe diskmon.com
;               -------------------------------
;               TASM /ml diskmon
;               TLINK /t diskmon       <- '/t'는 링크하고 바로 COM파일을 생성
;
; 이 프로그램은 INT 21h의 31h함수를 이용해서 메모리에 상주하며, 바이오스의 디
; 스크 인터럽트인 INT 13h를 가로채고 디스크 작업의 상태를 화면상단, 우측에 표
; 시한다. 디스크 작업의 상태는 '디스크ID-작업-진행과정'의 형태로 표시한다.
;
;       디스크ID = 'A', 'B', 'C', 'D'중의 하나
;       작업     = 'R'ead, 'W'rite, 'V'erify, 'F'ormat중의 하나
;       진행과정 = 바람개비의 형태를 표시('|', '/', '-', '\')
;
; 처음 프로그램을 실행하면 메모리에 상주하며, 다시 한번 프로그램을 실행하면
; 상주를 해제한다. 별도의 옵션은 없다.
;
; 각 소스라인에 대한 상세한 설명은 별도로 하도록 하고 우선 소스를 살펴보자.
; 라인번호는 설명을 위해 편의상 붙인 것이므로 어셈블할 때는 라인번호를 제거
; 해야 한다.
;
0001    PSP_ENV_SEG     EQU     2CH
0002    VIDEO_OFF       EQU     9AH
0003    
0004    ;----------------------------------------------------------------------
0005                    .MODEL  SMALL
0006    
0007                    .CODE
0008    
0009                    ORG     100h
0010    
0011    ;----------------------------------------------------------------------
0012    
0013    DiskMonitor     PROC    FAR
0014                    JMP     InstallCheck
0015    
0016    Author          DB      'Copyright (C) Yi,se-won.'
0017    KeepInt13h      DD      ?
0018    KeepInt60h      DD      ?
0019    VideoSeg        DW      0B000H                  ; 칼라이면 800h를 더함
0020    SiteBuffer      DB      0, 0, 0, 0, 0, 0
0021    DriveID         DB      0, 70H                  ; 70H는 문자 색상값이다
0022    CurrentJob      DB      0, 70H                  ;      "       "
0023    CurrentSite     DB      7CH, 70H                ;      "       "
0024    DiskMonitor     ENDP
0025    
0026    ;----------------------------------------------------------------------
0027    ; New handler for INT 60h
0028    
0029    NewInt60h       PROC    FAR
0030                    PUSHF
0031                    CALL    DWORD PTR CS:[KeepInt60h]
0032                    IRET
0033    NewInt60h       ENDP
0034    
0035    ;----------------------------------------------------------------------
0036    ; New handler for INT 13h
0037    
0038    NewInt13h       PROC    FAR
0039                    PUSHF
0040                    CLI                     ; 이 작업을 진행하는 동안의
0041                                            ; 인터럽트를 금지한다
0042                    PUSH    SS              ; 레지스터들을 대피시킨다
0043                    PUSH    SP
0044                    PUSH    BP
0045                    PUSH    AX
0046                    PUSH    BX
0047                    PUSH    CX
0048                    PUSH    DX
0049                    PUSH    SI
0050                    PUSH    DI
0051                    PUSH    ES
0052                    PUSH    DS
0053    
0054                    PUSH    CS                      ; CS를 DS에 복사한다
0055                    POP     DS
0056    
0057                    CALL    CheckDriveID
0058                    CALL    CheckCurJob
0059                    CALL    CheckCurSite
0060                    CALL    StoreCurSite
0061                    CALL    PutDriveID
0062    
0063                    POP     DS
0064                    POP     ES
0065                    POP     DI
0066                    POP     SI
0067                    POP     DX
0068                    POP     CX
0069                    POP     BX
0070                    POP     AX
0071                    POP     BP
0072                    POP     SP
0073                    POP     SS
0074                    POPF
0075    
0076                    PUSHF
0077                    CALL    DWORD PTR CS:[KeepInt13h]
0078    
0079                    PUSHF
0080                    CLI
0081    
0082                    PUSH    SS
0083                    PUSH    SP
0084                    PUSH    BP
0085                    PUSH    AX
0086                    PUSH    BX
0087                    PUSH    CX
0088                    PUSH    DX
0089                    PUSH    SI
0090                    PUSH    DI
0091                    PUSH    ES
0092                    PUSH    DS
0093    
0094                    CALL    PutCurSite
0095    
0096                    POP     DS
0097                    POP     ES
0098                    POP     DI
0099                    POP     SI
0100                    POP     DX
0101                    POP     CX
0102                    POP     BX
0103                    POP     AX
0104                    POP     BP
0105                    POP     SP
0106                    POP     SS
0107                    POPF
0108    
0109                    RETF    2                       ; 아직 POP되지 않은
0110    NewInt13h       ENDP                            ; FLAG 레지스터를 위해
0111    
0112    ;----------------------------------------------------------------------
0113    
0114    CheckDriveID    PROC    NEAR
0115                    CMP     DL,0
0116                    JE      DRIVE_A
0117                    CMP     DL,1
0118                    JE      DRIVE_B
0119                    CMP     DL,80H
0120                    JE      DRIVE_C
0121                    CMP     DL,81H
0122                    JE      DRIVE_D
0123                    RET
0124    DRIVE_A:
0125                    MOV     [DriveID],41H           ; 'A'
0126                    RET
0127    DRIVE_B:
0128                    MOV     [DriveID],42H           ; 'B'
0129                    RET
0130    DRIVE_C:
0131                    MOV     [DriveID],43H           ; 'C'
0132                    RET
0133    DRIVE_D:
0134                    MOV     [DriveID],44H           ; 'D'
0135                    RET
0136    CheckDriveID    ENDP
0137    
0138    ;----------------------------------------------------------------------
0139    
0140    CheckCurJob     PROC    NEAR
0141                    CMP     AH,2
0142                    JE      READ_DISK
0143                    CMP     AH,3
0144                    JE      WRITE_DISK
0145                    CMP     AH,4
0146                    JE      VERIFY_DISK
0147                    CMP     AH,5
0148                    JE      FORMAT_DISK
0149                    CMP     AH,6
0150                    JE      FORMAT_DISK
0151                    CMP     AH,7
0152                    JE      FORMAT_DISK
0153                    CMP     AH,0AH
0154                    JE      READ_DISK
0155                    CMP     AH,0BH
0156                    JE      WRITE_DISK
0157                    RET
0158    READ_DISK:
0159                    MOV     [CurrentJob],52H        ; 'R'
0160                    RET
0161    WRITE_DISK:
0162                    MOV     [CurrentJob],57H        ; 'W'
0163                    RET
0164    VERIFY_DISK:
0165                    MOV     [CurrentJob],56H        ; 'V'
0166                    RET
0167    FORMAT_DISK:
0168                    MOV     [CurrentJob],46H        ; 'F'
0169                    RET
0170    CheckCurJob     ENDP
0171    
0172    ;----------------------------------------------------------------------
0173    ; CurrentSite의 최초값은 '|'이다.
0174    CheckCurSite    PROC    NEAR
0175                    CMP     CurrentSite,7CH         ; '|'
0176                    JE      SITE_2
0177                    CMP     CurrentSite,2FH         ; '/'
0178                    JE      SITE_3
0179                    CMP     CurrentSite,2DH         ; '-'
0180                    JE      SITE_4
0181                    MOV     CurrentSite,7CH         ; '|'
0182                    RET
0183    SITE_2:
0184                    MOV     [CurrentSite],2FH       ; '/'
0185                    RET
0186    SITE_3:
0187                    MOV     [CurrentSite],2DH       ; '-'
0188                    RET
0189    SITE_4:
0190                    MOV     [CurrentSite],5CH       ; '\'
0191                    RET
0192    CheckCurSite    ENDP
0193    
0194    ;----------------------------------------------------------------------
0195    
0196    PutDriveID      PROC    NEAR
0197                    PUSH    CS
0198                    POP     DS
0199                    MOV     SI,OFFSET DriveID
0200                    MOV     AX,CS:[VideoSeg]
0201                    MOV     ES,AX           ; ES = 0B800h또는 0B000h
0202                    MOV     DI,VIDEO_OFF    ; DI = 9Ah(=154)
0203                    MOV     CX,3
0204                    REP     MOVSW           ; Copy to ES:DI from DS:SI
0205                    RET                     ; '문자+속성'을 위해 워드복사
0206    PutDriveID      ENDP
0207    
0208    ;----------------------------------------------------------------------
0209    
0210    StoreCurSite    PROC    NEAR
0211                    PUSH    CS
0212                    POP     ES
0213                    MOV     DI,OFFSET SiteBuffer
0214                    MOV     AX,CS:[VideoSeg]
0215                    MOV     DS,AX
0216                    MOV     SI,VIDEO_OFF
0217                    MOV     CX,3
0218                    REP     MOVSW
0219                    RET
0220    StoreCurSite    ENDP
0221    
0222    ;----------------------------------------------------------------------
0223    
0224    PutCurSite      PROC    NEAR
0225                    PUSH    CS
0226                    POP     DS
0227                    MOV     SI,OFFSET SiteBuffer
0228                    MOV     AX,CS:[VideoSeg]
0229                    MOV     ES,AX
0230                    MOV     DI,VIDEO_OFF
0231                    MOV     CX,3
0232                    REP     MOVSW
0233                    RET
0234    PutCurSite      ENDP
0235    
0236    TSR_BLOCK       EQU     $               ; TSR_BLOCK = 이곳의 옵셋
0237    
0238    ;----------------------------------------------------------------------
0239    
0240    InstallMsg      DB      0DH, 0AH
0241                    DB      '旼컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴 '
0242                    DB      0DH, 0AH
0243                    DB      ' Disk monitor.                            '
0244                    DB      0DH, 0AH
0245                    DB      ' Copyright (C) Yi, se - won.  1994.11     '
0246                    DB      0DH, 0AH
0247                    DB      '읕컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴 '
0248                    DB      0DH, 0AH
0249                    DB      ' Installed.'
0250                    DB      7, 0DH, 0AH, '$'
0251    RemoveMsg       DB      0DH, 0AH, ' Disk monitor'
0252                    DB      0DH, 0AH, ' Removed.'
0253                    DB      7, 0DH, 0AH, '$'
0254    NotRemoveMsg    DB      0DH, 0AH, ' Disk monitor'
0255                    DB      0DH, 0AH
0256                    DB      ' Not removed.'
0257                    DB      7, 0DH, 0AH, '$'
0258    
0259    ;----------------------------------------------------------------------
0260    
0261    InstallCheck:
0262                    MOV     AX,3560H                ; 인터럽트 벡터 얻기
0263                    INT     21H                     ; ES:BX = Seg:Ofs
0264                    CMP     WORD PTR ES:[Author],6F43H      ; 'Co'인가?
0265                    JNE     InstallTSR                      ; Author의 옵셋
0266                                                            ; 은 103h이다
0267                    MOV     AX,3513H
0268                    INT     21H
0269                    CMP     WORD PTR ES:[Author],6F43H      ; 한번 더 확인
0270                    JE      RemoveTSR
0271    
0272                    MOV     DX,OFFSET NotRemoveMsg
0273                    MOV     AH,9
0274                    INT     21H
0275    
0276                    INT     20H                             ; 프로그램 종료
0277    RemoveTSR:
0278                    PUSH    DS
0279    
0280                    MOV     AX,2513H                ; 인터럽트 벡터 설정
0281                    MOV     DX,WORD PTR ES:[KeepInt13h]     ; 옵셋
0282                    MOV     DS,WORD PTR ES:[KeepInt13h+2]   ; 세그먼트
0283                    INT     21H
0284    
0285                    MOV     AX,2560H
0286                    MOV     DX,WORD PTR ES:[KeepInt60h]     ; 옵셋
0287                    MOV     DS,WORD PTR ES:[KeepInt60h+2]   ; 세그먼트
0288                    INT     21H
0289    
0290                    POP     DS
0291    
0292                    MOV     AH,49H          ; 메모리 해제, ES=해제할 메모리
0293                    INT     21H             ; 블럭의 세그먼트
0294    
0295                    MOV     DX,OFFSET RemoveMsg
0296                    MOV     AH,9
0297                    INT     21H
0298    
0299                    INT     20H             ; 프로그램 종료
0300    
0301    InstallTSR:
0302                    MOV     AH,0FH          ; 비디오 모드 얻기
0303                    INT     10H
0304                    CMP     AL,7            ; 흑백인가?
0305                    JE      Settings        ; 그렇다면 VideoSeg=0B000h
0306                    ADD     CS:[VideoSeg],800H   ; 아니면 VideoSeg=0B800h
0307    Settings:
0308                    MOV     AX,3560H
0309                    INT     21H
0310    
0311                    MOV     WORD PTR CS:[KeepInt60h],BX     ; 옵셋 보관
0312                    MOV     WORD PTR CS:[KeepInt60h+2],ES   ; 세그먼트 보관
0313    
0314                    MOV     AX,2560H
0315                    MOV     DX,OFFSET NewInt60h     ; 새로운 핸들러 설치
0316                    INT     21H
0317    
0318                    MOV     AX,3513H
0319                    INT     21H
0320    
0321                    MOV     WORD PTR CS:[KeepInt13h],BX     ; 옵셋 보관
0322                    MOV     WORD PTR CS:[KeepInt13h+2],ES   ; 세그먼트 보관
0323    
0324                    MOV     AX,2513H
0325                    MOV     DX,OFFSET NewInt13h     ; 새로운 핸들러 설치
0326                    INT     21H
0327    
0328                    MOV     AH,49H
0329                    MOV     ES,CS:[PSP_ENV_SEG]
0330                    INT     21H
0331    
0332                    MOV     AH,9
0333                    MOV     DX,OFFSET InstallMsg
0334                    INT     21H
0335    
0336                    LEA     DX,TSR_BLOCK
0337                    ADD     DX, 0Fh
0338                    MOV     CL, 4
0339                    SHR     DX, CL
0340    
0341                    MOV     AX,3100H
0342                    INT     21H
0343    
0344    ;----------------------------------------------------------------------
0345    
0346                    END     DiskMonitor             ; Entry point
이 프로그램의 전체적인 흐름을 살펴보자.
                      ┌───────┐
                      │프로그램 시작 │
                      └───┬───┘
                              │
                              ▽
              ┌───────────────┐Yes
              │      이미 설치되었는가?      ├──┐
              └───────┬───────┘    │
                              │No                  │
                              ▽                    │
              ┌───────────────┐    │
              │ 원래의 인터럽트 핸들러 저장  │    │
        ┌──┤ 새로운 인터럽트 핸들러 설치  │    │
        │    │       메모리 할당/램상주     │    │
        │    └───────────────┘    │
        │    ┌───────────────┐    │
        │    │ 원래의 인터럽트 핸들러 복구  │◁─┘
        │    │   메모리 해제/램상주 해제    │
        │    └───────┬───────┘
        │                    │
        │                    ▽
        │            ┌───────┐
        └─────▷│프로그램 종료 │
                      └───────┘
전체 흐름도에서 보는 바와 같이 어셈블리 소스가 약 300여 라인이나 되는 것에 비
해 하는 일은 매우 간단하다.  하지만 이런 일을 하는 프로그램을 고급언어로 작성
한다면 최적화 된다고 해도 메모리에 상주하는 크기가 적어도  5~6,000바이트는 될
것이다(예를 들어서 C와 같은 언어). 그러나 어셈블리로 작성된 이 프로그램은 640
바이트 만을 차지할 뿐이다.
위의 흐름도를 통해 프로그램이 전체적인 윤곽을 알 수 있었을 것이다.  이제 프로
그램의 세부적인 내용을 보자. 각 라인 단위로 설명한다.
0001      : PSP의 옵셋 2Ch에는 프로그램의 환경 블럭에 대한 세그먼트 주소가 저
            장되어 있다(Word).  프로그램이 메모리에 상주하기 전에 자신에게 할
            당되었던 환경블럭을 메모리에서 해제하게 되는데  이 부분은 다시 설
            명된다.
0002      : 이 프로그램에서는 현재의 디스크 작업 상태를 화면의 최상단, 최우측
            에 표시한다.  화면상의 임의의 위치 (X,Y)에 대응되는 비디오 메모리
            를 계산하기 위해서는 다음과 같이 한다.
                임의의 위치 (X, Y)에 대응되는 비디오 메모리 주소
                문자주소 = (Y*160)+(X*2)
                속성주소 = (Y*160)+(X*2)+1
            이 계산에 따르면 9Ah(154)는 화면상의 (X, Y) = (77, 0)의 좌표를 지
            정하는 것임을 알 수 있다. 이 값은 뒤에서 비디오 메모리의 세그먼트
            주소에 더해진다.
0005      : 메모리 모델을 SMALL로 설정하도록 한다. SMALL 모델은 코드 세그먼트
            와 데이타 세그먼트를 각각 한 개씩 가질 수 있다.
0007      : 코드세그먼트의 경계를 설정한다.  간이 코드 세그먼트 지시어에 의해
            생성된 세그먼트의 이름은 기본적으로 '_TEXT'가 된다.
0009      : 초기 명령 포인터(Instruction Point, IP)를 100h로 설정한다.
            모든 COM 프로그램은 100h번지로 부터 시작된다.
0014      : 초기 CS:IP 위치에는 반드시 실행 가능한 코드가 있어야 한다.
            만약 여기에 실행 코드가 아닌 어떤 데이타가 오더라도 CPU는 그것이
            데이타임을 알아보지 못한다.
0016~0023 : 메모리 상주 후에 사용하게 될 변수들을 정의한다.
        Author      : 프로그램 제작자에 대한 정보
        KeepInt13h  : 원래의 INT 13h의 주소 보관용
        KeepInt60h  : 원래의 INT 60h의 주소 보관용
        VideoSeg    : 비디오 메모리의 세그먼트 주소(Default=0B000H, 흑백화면)
        SiteBuffer  : 디스크 동작 상태를 저장할 버퍼
                      CurrentJob과 CurrentSite를 합친 문자열
                      예) R|, R/, R-, R\        <- 읽기 작업중...
                          F|, F/, F-, F\        <- 초기화 작업중...
        DriveID     : 드라이브 ID = 'A', 'B', 'C', or 'D'
        CurrentJob  : 현재의 작업 = 읽기('R'), 쓰기('W')
                                    검사('V'), 초기화('F')
        CurrentSite : 바람개비 모양(Default='|')
0029~0033 : INT 60h에 대한 새로운 핸들러.
            프로그램이 메모리에 상주한 후 새로운 핸들러의  세그먼트 주소는 메
            모리에 상주한 프로그램의 CS와 동일하다.   이 점을 이용해서 메모리
            상주 여부를 확인한다.  라인 0031의 표현은 원래,
                CALL    CS:[KeepInt60h]
            이었으나 뜻을 명확히 하기 위해 변경되었다.
0038~0110 : INT 13h에 대한 새로운 핸들러.
            바이오스를 통한 디스크 입출력이 있을 때 마다 이 핸들러가 호출되고
            핸들러는 INT 13h가 호출될 때의 레지스터를 검사해서 어떤 작업을 할
            것인지를 파악하게 된다. 라인 0054~0055는 DS의 값을 CS의 값으로 대
            치하는 작업인데 이는 다음과 같이 표현될 수 있다.
                MOV     DX,CS
                MOV     DS,DX
            즉,  세그먼트 레지스트 끼리의 직접적인 교환은 할 수 없으므로 범용
            레지스터를 통해 CS를 DS로 복사하는 것이다. 그러나 이 방법은 PUSH,
            POP에 의한 복사방법 보다 코드의 크기가 크며 CPU 사이클도 늦다.
0114~0136 : 작업이 진행될 디스크의 ID를 검사하고 DriveID에 보관한다.
0140~0170 : INT 13h로 넘겨진 레지스터에서 AH를 검사하면 어떤 작업을 하게될 지
            알 수 있다.  이를 검사하고 각 작업에 따라 'R', 'W', 'V', 'F' 중의
            한가지를 CurrentJob에 보관한다.
0174~0192 : 바람개비의 종류를 결정한다.  바람개비는 '|', '/', '-', '\'를 차례
            대로 출력하여 구현한다. 이 값은 CurrentSite에 저장된다.
0196~0206 : 드라이브 ID('A', 'B',..)를 화면의 최상단 우측(Y=0, X=77)에 출력한
            한다. ES:DI = 비디오세그먼트:009Ah
0210~0220 : 작업의 유형과 선택된 바람개비 모양을 SiteBuffer에 저장한다.
0224~0234 : SiteBuffer에 저장된 문자열을 비디오세그먼트:009Ah에 출력한다.
0236      : 메모리에 상주시킬 영역의 크기(바이트 단위)를 계산하기  편리하도록
            하기 위해 사용되었다. '$'은 한 세그먼트 내에서 '그곳 까지의 거리'
            인 옵셋의 개념과 동일하므로 그 값은 16비트 범위(0~64KB)에 있다.
            즉, 이 프로그램은 CS:0000~CS:TSR_BLOCK 영역을 메모리에 상주시키게
            된다. 이 부분은 역어셈블한 코드에서는 찾을 수 없다. 필자가 프로그
            램의 앞뒤를 맞추어 보고 임의로 삽입했다.
0240~0257 : 프로그램의 설치/제거시에 보야줄 메세지를 정의한다.
0261~0276 : 프로그램이 이미 메모리에 설치되어 있는지를 검사하고 이미 설치되어
            있다면 상주를 해제하는 곳으로, 그렇지 않다면 설치하는 곳으로 분기
            한다. 프로그램의 설치 여부는 앞서 이미 언급한 바 있지만 INT 60h의
            새로운 핸들러의 세그먼트 주소를 v얻고 그 세그먼트의 103h옵셋을 조
            사하는 것이다. 103h옵셋에는 'Copyright..'라는 문자열이 있고 이 문
            자열의 머릿부분인 'Co'는 워드 단위로 읽었을 때 6F43h가  되므로 이
            를 확인한다. 만약 6F42h가 아니라면 아직 설치되지 않은 것으로 간주
            하여 설치처리를 하게되며, 6F43h라면 확인을 위해 다시 한번 INT 13h
            의 세그먼트를 얻고 그 세그먼트의 103h옵셋과 6F43h를 비교하여 동일
            하다면 이미 설치된 것으로 간주하여 상주 해제 부분으로 분기한다.
            INT 13h의 새로운 핸들러 세그먼트는 INT 60h의 새로운 핸들러 세그먼
            트와 동일하다.
0277~0299 : 메모리 상주를 해제하기 위해 보관해 두었던 원래의  인터럽트 핸들러
            벡터를 복구하고 상주를 위해 할당되었던 메모리를 해제한다.
0301~0342 :  비디오 메모리에 디스크의 작업 상태를 써야 하므로  비디오 메모리의
            세그먼트를 계산하기 위해(칼라는 0B800h, 흑백은 0B000h로 다르다)
            비디오 모드를 얻고 칼라이면  VideoSeg(Default=0B000h)에 800h를 더
            한 후 메모리에 상주하기 위해 INT 13h,INT 60h의 새로운 핸들러를 설
            치하고 상주하게될 메모리 블럭 (바이트 단위를 패러그래프 단위로 환
            산)을 할당한다. 라인 0328~0330의 표현,
                MOV     AH,49H
                MOV     ES,CS:[PSP_ENV_SEG]
                INT     21H
            은 이 프로그램이 실행되면서 생성된 환경영역(Default=384바이트)을
            해제한다. 프로그램이 실행되면 도스는 그 프로그램을 위한 환경영역과
            프로그램 자체를 위한 프로그램영역을 할당한다. 메모리 상주 프로그램
            의 경우 상주를 해제할 때는 프로그램영역과 환경영역을 모두 해제해
            주어야 하는데 이 프로그램에서는 환경영역을 미리 해제하고 있다.
            라인 0336~0342는 메모리 상주를 위해 상주할 코드의 크기를 계산한다.
                LEA     DX,TSR_BLOCK    ; TSR_BLOCK의 유효주소(옵셋)을 얻는다.
                                        ; 상주하게 될 영역은 옵셋 0에서
                                        ; TSR_BLOCK까지의 바이트 크기와 PSP의
                                        ; 256바이트를 합해서 계산된다. 그러나
                                        ; COM 프로그램은 같은 세그먼트 내에
                                        ; PSP를 가지고 있으므로(옵셋 0~FFh)
                                        ; 단순히 TSR_BLOCK까지의 바이트 길이만
                                        ; 계산된다. EXE프로그램이라면 PSP의 크
                                        ; 기인 100h가 더해져야할 것이다.
                ADD     DX, 0Fh         ; DX는 메모리에 상주할 프로그램의 크기
                                        ; 가 바이트 단위로 저장되어 있다.
                                        ; 이 값을 패러그래프 단위로 변환하기
                                        ; 위해서는 4로 나누어 주게 되는데  그
                                        ; 때의 소실되는 나머지 값을 보정하기
                                        ; 위해서 0Fh를 더해 주었다.
                                        ; 이 부분은 원래의 원래 코드에는 없는
                                        ; 내용이다. 원래의 프로그램에서는 DX에
                                        ; 바로 패러그래프 단위의 메모리 크기가
                                        ; 저장되었었는데 이는 아마도  EQU를 사
                                        ; 용해서 앞부분에서 미리 계산되었기 때
                                        ; 문일 것으로 추측된다.
                MOV     CL, 4
                SHR     DX, CL          ; 바이트 단위의 길이를 패러그래프 단위
                                        ; 로 환산하기 위해 DX를 우측으로 4비트
                                        ; 시프트한다(DX / 4).
                MOV     AX,3100H        ; 메모리 상주후 종료 서비스, 복귀코드=0
                INT     21H
0346      : 프로그램의 진입점(Entry point)을 명시한다.
어셈블리 소스와 설명 부분을 따로 프린트한 후 라인번호를 비교하면서 보는 것이 편
리할 것이다.
프로그램은 비교적 간단한 내용이므로 이제 막 어셈블리를 배우기 시작하는 초보가
아니라면 이해하는데는 별 어려움이 없을 것으로 생각된다.
 [31] 제목 : 소스분석<2>에서분석된프로그램의제작자입니다.
 올린이 : 영원의별(이세원  )    95/02/17 00:38    읽음 : 223  관련자료 없음
       안녕하세요.
         박선근님(ID:natali)의 [강좌] 어셈블리 소스분석 <2> 에서  분석된
       프로그램 (diskmon.com)의 제작자 이세원 입니다.
         먼저 선근님의 놀라운 코드 분석력에 경탄을 마지  않습니다.  물론
       코드는 소서로 뽑아낼 수 있으나 제작자의 코드 의도를 정확히 파악한
       다는것은 결코 쉬운것이 아니기 때문입니다.
         밑의 강좌 내용중에 극히 일부 제작자의 본래 의도와 약간 다른  해
       석이 있었는데 단지, 제작자가 살아있는 이유로 이를  보충할까  합니
       다.(하는게 낫겠죠? 선근님?)
         이 프로그램을 만들게된 동기는 iomon.com 이나 노턴 유티리티의 di
       skmon.exe가 디스크의 움직임을 화면에 표시해 주지만 뭔가 부족한 점
       이 있어 보다 확실한 디스크의 움직임을 구현해보기 위해서 였습니다.
       그것은 단지, 재미있는 화면 출력으로 끝나는것이 아니라 디스크의 섬
       세한 움직임을 포착하여 디스크 작동상의 오류나 어떤 변화를  찾아내
       기 위해서 였습니다.
         제작기간은 총 7일 가량 소요 되었습니다. 처음에 화면의 구성과 프
       로그램의 흐름을 잡아 몇시간만에 완성된 프로그램을 제작하여 시험하
       는데, 알 수 없는 이유로 A나 B드라이브를 읽을때 디스켓이 끼워져 있
       지 않았는데도 A나 B드라이브로 넘어갔습니 다. 저로서는 도무지 이유
       를 알 수가 없었습니다. 이 문제는 선근님의 코드 분석에도  밝혀지지
       가 않았습니다.(선근님 소스 109 라인) 결국 이 문제로  오랜  고민을
       하게 되었는데 우연히 디스크 인터럽트의 복귀과정에서 스택의 워드를
       하나 더 pop 해야함을 알게 되었습니다. (보통의 사용자 인터럽트  핸
       들러에서의 복귀는 iret 으로 스택의 3워드를 비워야하나 디스크 인터
       럽트만 유난히 4워드를 비워야 합니다.) 이것이 109 라인의 'retf  2'
       인 이유입니다.
         그리고 이것은 기술적인 문제이지만, 프로그램을 메모리에 상주시키
       기전에 먼저 환경블럭을 해제하는것이 좋습니다.  왜냐하면  가능한한
       램상주 프로그램은 메모리를 덜 차지해야하기 때문입니다.
         그리고 이것은 보충입니다만, 램상주 프로그램의  경우에  메모리에
       상주시킬 프로그램 일부분의 크기를 계산하는 방법은  매우  간단합니
       다. 그것은 상주시킬 부분까지의 레이블에서 start 레이블을 빼고  다
       시 256byte를 더합니다.(256은 psp의 크기) 거기에 15바이트를 더합니
       다. (패러그래프 단위로 나눌때 완전히 포함되게하기 위해서)  그리고
       패러그래프 단위인 16으로 나눕니다. - 이것은 도스인터럽트 21h 함수
       번호 31h인 경우 입니다.
         그러나 더욱 간단히 프로그램을 메모리에 상주시키고자 한다면 도스
       인터럽트 27h를 쓰십시오. 위의 방법(int  21h,ah=31h)이  프로그램의
       크기를 위에서부터 측정하는 방법이라면 int 27h는 반대로 프로그램의
       크기를 밑에서부터 측정합니다. 즉 메모리에서  제거하고자  하는부분
       이하를 dx에 넣고 호출만하면 됩니다. 이 차이는 방법의 차이일뿐이고
       기능에서의 차이는 없습니다. (int 21h,ah=31h는  패러그래프  단위로
       램상주시키고, int 27h는 바이트 단위로 램상주 시키기 때문에 방법의
       차이가 생겨난것 입니다.) 그리고 이러한 계산은  어셈블러가  어셈블
       시(pass 1)에 계산하기 때문에 프로그래머는 신경쓰지 않아도  됩니다
       .(하나의 세그먼트 단위로 절대번지를 계산해서 자동으로 넣어주므로)
         그리고 int 60h를 후킹한 이유는, 이 프로그램을 상주시킨후에 다른
       int 13h를 후킹하는 프로그램이 있었다고 할때, 이 프로그램을 메모리
       에서 제거하면 디스크 인터럽트는 아작납니다.(매우 큰 사고임)  따라
       서 이 프로그램의 제거시에 이 프로그램 이후에 디스크 인터럽트를 후
       킹한 프로그램이 있었는가를 알아보기 위해서 인식자를 int 60h에  숨
       겨 두었던것 입니다. (다른 프로그램에서 int 60h를 후킹할 이유가 없
       으므로...)
         끝으로 이 프로그램의 원 소스(흔히 하는말로 오리지날 쏘쓰~)를 공
       개합니다. 그리고 별 볼일 없는 프로그램임에도 불구하고 분석을 해주
       신 선근님에게 다시한번 감사 드립니다.
;===========================================================================
;       DISKMON
;       디스크의 움직임을 관찰한다.
;==========================================================================
include macro.inc
color           =       01110000b                 ;흰색바탕에 검은색글자
code    segment
        assume  cs:code
org     100h
start:
        jmp     begin
copyright       db      'Copyright (C) Yi,se-won.' ;인식자는 Co 이다.
old_13h         dd      ?
old_60h         dd      ?
video_buffer    dw      0b000h                    ;칼라 비디오 버퍼
old_screen      db      6       dup(0)            ;본래의 화면 저장소
drive           db      ?
                db      color
status          db      ?
                db      color
speed           db      '|'                       ;바람개비 초기치
                db      color
;-------------------------
; user interrupt handler
;-------------------------
new_60h:                                          ;인식자 검사를 위한
        pushf                                     ;사용자 인터럽트 핸들러
        call    cs:old_60h
        iret
;------------------------
; disk interrupt handler
;------------------------
new_13h:
        pushf
        cli
        push    ss
        push    sp
        push    bp
        push_register
        push    es
        push    ds
        push    cs
        pop     ds
perform:
        call    drive_check                       ;드라이브 체크
        call    status_check                      ;디스크 체크
        call    rotation_count                    ;바람개비 상태 체크
        call    screen_save                       ;본래화면 저장
        call    monitor                           ;화면 출력
        pop     ds
        pop     es
        pop_register
        pop     bp
        pop     sp
        pop     ss
        popf
        pushf
        call    cs:old_13h
next:
        pushf
        cli
        push    ss
        push    sp
        push    bp
        push_register
        push    es
        push    ds
        call    screen_recover
        pop     ds
        pop     es
        pop_register
        pop     bp
        pop     sp
        pop     ss
        popf
        retf    2                                 ;스택의 4바이트를 비운다.
drive_check:                                      ;드라이브를 체크한다.
        cmp     dl,0
        je      a_drive
        cmp     dl,1
        je      b_drive
        cmp     dl,80h
        je      c_drive
        cmp     dl,81h
        je      d_drive
drive_check_exit:
        ret
a_drive:
        mov     ds:drive,'A'
        ret
b_drive:
        mov     ds:drive,'B'
        ret
c_drive:
        mov     ds:drive,'C'
        ret
d_drive:
        mov     ds:drive,'D'
        ret
status_check:
        cmp     ah,2
        je      read
        cmp     ah,3
        je      write
        cmp     ah,4
        je      verify
        cmp     ah,5
        je      format
        cmp     ah,6
        je      format
        cmp     ah,7
        je      format
        cmp     ah,0ah
        je      read
        cmp     ah,0bh
        je      write
status_check_exit:
        ret
read:
        mov     ds:status,'R'
        ret
write:
        mov     ds:status,'W'
        ret
verify:
        mov     ds:status,'V'
        ret
format:
        mov     ds:status,'F'
        ret
rotation_count:
        cmp     ds:speed,'|'
        je      rotation_1
        cmp     ds:speed,'/'
        je      rotation_2
        cmp     ds:speed,'-'
        je      rotation_3
        mov     ds:speed,'|'
        ret
rotation_1:
        mov     ds:speed,'/'
        ret
rotation_2:
        mov     ds:speed,'-'
        ret
rotation_3:
        mov     ds:speed,'\'
        ret
monitor:                                          ;디스크의 상태를 화면
        push    cs                                ;출력한다.
        pop     ds
        mov     si,offset drive
        mov     ax,cs:video_buffer
        mov     es,ax
        mov     di,154
        mov     cx,3
        rep     movsw
        ret
screen_save:
        push    cs
        pop     es
        mov     di,offset es:old_screen
        mov     ax,cs:video_buffer
        mov     ds,ax
        mov     si,154
        mov     cx,3
        rep     movsw
        ret
screen_recover:                                   ;본래의 화면을 복구한다.
        push    cs
        pop     ds
        mov     si,offset ds:old_screen
        mov     ax,cs:video_buffer
        mov     es,ax
        mov     di,154
        mov     cx,3
        rep     movsw
        ret
install_msg     db      13,10,'┌────────────────────┐'
                db      13,10,'│ Disk monitor.                          │'
                db      13,10,'│ Copyright (C) Yi, se - won.  1994.11   │'
                db      13,10,'└────────────────────┘'
                db      13,10,' Installed.',7
                db      13,10,'$'
removed_msg     db      13,10,' Disk monitor'
                db      13,10,' Removed.',7
                db      13,10,'$'
no_remove_msg   db      13,10,' Disk monitor'
                db      13,10,' Not removed.',7
                db      13,10,'$'
begin:
        mov     ax,3560h                          ;인식자를 위한 인터럽트에서
        int     21h                               ;인식자를 검사한다.
        cmp     word ptr es:copyright,6f43h       ;만약 인식자가 없다면
        jne     install                           ;인스톨한다.
disk_vector_check:
        mov     ax,3513h                          ;디스크 인터럽트에서
        int     21h                               ;인식자를 검사한다.
        cmp     word ptr es:copyright,6f43h       ;인식자가 있다면 프로그램을
        je      remove                            ;메모리에서 제거한다.
no_remove:                                        ;만약 인식자가 없다면 다른
        mov     dx,offset no_remove_msg           ;프로그램이 디스크 인터럽트를
        mov     ah,9                              ;후킹한 것이므로 프로그램을
        int     21h                               ;메모리에서 제거할 수 없다.
                                                  ;
        int     20h
remove:                                           ;이미 메모리에 상주하므로
        push    ds                                ;프로그램을 제거한다.
        mov     ax,2513h
        mov     dx,word ptr es:old_13h
        mov     ds,word ptr es:old_13h[2]
        int     21h
        mov     ax,2560h
        mov     dx,word ptr es:old_60h
        mov     ds,word ptr es:old_60h[2]
        int     21h
        pop     ds
        mov     ah,49h
        int     21h
        mov     dx,offset removed_msg
        mov     ah,9
        int     21h
        int     20h
install:                                          ;프로그램을 인스톨한다.
        mov     ah,0fh                            ;현재의 비디오모드를 검사하고
        int     10h                               ;모노크롬이면 color_m 로
                                                  ;점프한다.
        cmp     al,7
        jne     color_m
hooking:
        mov     ax,3560h                          ;인식자를 위한 사용자
        int     21h                               ;인터럽트를 후킹한다.
        mov     word ptr old_60h,bx
        mov     word ptr old_60h[2],es
        mov     ax,2560h
        mov     dx,offset new_60h
        int     21h
        mov     ax,3513h                          ;디스크 인터럽트 후킹
        int     21h
        mov     word ptr old_13h,bx
        mov     word ptr old_13h[2],es
        mov     ax,2513h
        mov     dx,offset new_13h
        int     21h
        mov     ah,49h
        mov     es,cs:[2ch]
        int     21h
        mov     ah,9
        mov     dx,offset install_msg
        int     21h
        mov     ah,31h                            ;메모리 상주 종료.
        mov     dx,(install_msg-start+256+15)/16
        int     21h
color_m:                                          ;모노크롬 모니터를 위한
        add     cs:video_buffer,800h              ;비디오 버퍼 설정
        jmp     hooking
code    ends
        end     start
 [32] 제목 : [참고] 어셈블리 참고 책들..
 올린이 : onestep (류창균  )    95/02/18 13:19    읽음 : 325  관련자료 없음
Fri 29 Jan 93  8:34
By: Yousuf Khan
To: All
Re: FAQ: Books on Assembler
------------------------------------------------------------------------
Q2) I want to learn assembler, what books should I read?
                                  ***
A2) Various people have found these books useful to them:
                                General
                                =======
Beginner:
---------
-"Assembly Language from Square One", Jeff Duntemann, Scott Foresman IBM
Comptuter Books. ISBN 0-673-38590-6.
-"Assembly Language for the IBM PC", Kip R. Irvine, ISBN 0-02-359840-9
-"Mastering Turbo Assembler", by Tom Swan, Hayden Books, 1989.
ISBN 0-672-48435-8.
-"Assembly Language and Systems Programming for the IBM PC and
Compatables", Karen A. Lemone, Little, Brown, & Co. ISBN 0-316-52069-1.
-"Assembly Language Primer for the IBM PC/XT", Robert Lafore,
Plume/Waite.
-"Using Assembly Language", Allen L. Wyatt Sr., Que 1990.
ISBN 0-88022-464-9.
Intermediate:
-------------
-"The Zen of Assembly", Michael Abrash, Scott Foresman Publ.
-"Assembly Language Primer for the IBM PC/XT"
-"IBM Microcomputers: A Programmer's Handbook", Julio Sanchez and Maria
P. Canton, McGraw-Hill. ISBN 0-07-054594-4.
-"Programmer's Problem Solver for the IBM PC, XT, and AT", Robert
Jourdain, Prentice Hall 1986. ISBN 0-89303-787-7.
-"IBM PC ASSEMBLER LANGUAGE AND PROGRAMMING", Peter Abel, 1987,
Prentice-Hall, hardcover (college text). ISBN 0-13-448143-7.
Advanced:
---------
-"80386: A Programming and Design Handbook", 2nd ed., Penn & Don Brumm,
TAB Books. ISBN 0-8306-3237-9.
-"80486 Programming", Penn & Don Brumm and Leo J. Scanlon, McGraw-Hill.
ISBN 0-8306-3577-7.
-"ADVANCED ASSEMBLY LANGUAGE", Steven Holzner and Peter Norton Computing,
Inc., Brady Books/Simon and Schuster. ISBN 0-13-658774-7.
                             Video Graphics
                             ==============
Intermediate:
-------------
-"Programmer's Guide to PC & PS/2 Video Systems", Richard Wilton,
Microsoft Press. ISBN 1-55615-103-9.
Advanced:
---------
-"Power Graphics Programming", Michael Abrash, Que Corporation. ISBN
0-88022-500-9
-"Programmers Guide to the EGA and VGA cards", 2nd Ed., Richard F.
Ferraro, Addison-Wesley Publishing Co. ISBN 0-201-57025-4.
-"Advanced Programmers Guide to the EGA/VGA", George Sutty and Steve
Blair, Brady Books/Prentice Hall Trade. ISBN 0-13-729039-X.
                         References/Specialized
                         ======================
Intermediate:
-------------
-"Undocumented DOS", Andrew Schulman, Raymond J. Michels, Jim Kyle, Tim
Paterson, David Maxey, and Ralf Brown, Addison-Wesley. ISBN
0-201-57064-5.
-"DOS Programmer's Reference", 2nd Edition, Terry Dettmann, QUE.
ISBN 0-88022-458-4.
Advanced:
---------
-"386SX Microprocessor Programmer's Reference Manual", Intel Corp.,
McGraw-Hill. ISBN 0-07-881673-4.
-"i486 Microprocessor Programmer's Reference Manual", Intel Corporation,
McGraw-Hill. ISBN 0-07-881674-2.
-"The Programmer's PC Sourcebook", Thom Hogan, Microsoft Press. ISBN
1-55615-321-X.
-"System BIOS for IBM PCs, Compatables, and EISA Computers", 2nd Ed.,
Phoenix Technologies Ltd., Addison Wesley. ISBN 0-201-57760-7.
-"PC Magazine Programmers Technical Reference: The Processor and
Coprocessor", Robert L. Hummel, Ziff-Davis Press. ISBN 1-56276-016-5.
-"Mastering Serial Communications", Peter W. Gofton, Sybex 1986.  ISBN
0-89588-180-2.
-"DOS Programmer's Reference", 2nd Ed.
-"MS-DOS Programmer's Reference", MS Press. ISBN 1-555615-329-5.
from CG.
 [33] 제목 : 스택(STACK)에 관한 연구
 올린이 : 영원의별(이세원  )    95/03/22 23:11    읽음 : 135  관련자료 없음
                스택 (Stack)
        1.      스택이란.
        스택은 프로그램에서 사용하는  조금 특별한 데이타를 저
장하는 아주 특별한 영역이다.   그 영역은 스택 세그먼트이고 스
택 세그먼트 레지스터가 그곳의 위치를 가리킨다.
        스택이라는 이름은  식당에서 접시를  쌓아두는 장치에서 
유래했다고 한다.  이 장치의 특징을 한가지  예로 들어 설명하겠
다. 커피 전문점에 가면  커피잔을 전기열로 말리는 장치가 있다. 
이곳에 커피잔을 씻어 올려 놓는다. 그리고 다음에 씻은잔은 먼저 
올려놓은 잔 위에 올려놓는다. 이런 동작들을 반복한다면 가장 먼
저 씻은잔이 가장 밑에  놓여 있게 된다. 반대로 이번에는 손님이 
와서 커피잔이 나가게 되었을때는 맨 위에 놓인잔이 가장 먼저 손
님에게 나가게 된다. 물론 이 방법은 손님에게는 합리적이지 못하
다. 맨 밑의 잔이 손님에게 나간다면 그 잔은 얼마나 먼지를 덮어
쓰고 있는지 종업원 조차 알수 없기 때문이다.
        이런 식으로 가장 먼저  들어온 데이타가 가장 늦게 나가
는 다시말해 가장 최근에 저장된 데이타가 가장 먼저 사용되는 그
런 형태이다. 이러한 구조를 가지고 있으므로 당연히 가장 최근에 
들어온 데이타의 위치를 알수 있는 지시자를 가지고 있다. 그것이 
바로 스택 포인터이다. 스택 포인터는 스택 영역에서 다음에 저장
할 위치를 가리키고 있다. 즉  PUSH 를 하게 되면 현재의 스택 포
인터가 가리키는 위치에 데이타가 저장되는것이다. 스택에 데이타
를 저장했으면 다음에 저장할 데이타의 스택에서의 위치를 알려주
기 위해서 스택 포인터의 값은 2 감소한다. 스택에서 데이타를 꺼
내는 명령은  POP 이다. 또한 POP  명령으로 데이타를 거낸후에는
스택 포인터는 2 증가한다. 2씩 감소하고 2씩 증가하는 이유는 스
택에는 워드단위(2 BYTE)로 저장하기 때문이다.
        2.      스택을 만든 이유
        일반적으로 데이타는 별도의  데이타 영역을 두어 그곳에 
저장한다. 스택에 저장할 이유가 없다. 그러나 스택에 저장을하면 
여러가지 이득을 볼 수  있다. 프로그램에는 프로그램을 종료할때
까지 보존해야할 데이타가 있는가 하면 일시적으로 사용하고는 버
리는 데이타가 있다. 이런  일시적인 데이타조차 메모리의 데이타
영역에 보존한다면 메모리를 낭비하는 결과를 초래할수도있다. 따
라서 이런 데이타는 스택에 저장한다. 또한 스택을 이용한 데이타
의 이동은 매우 효과적이다. PUSH  와 POP 은 한쌍으로 쓰여서 데
이타를 아주 빠르게 복사할수 있다.
        고급언어의 경우 전자의 경우 즉 일시적으로 쓰이는 데이
타를 스택에 저장하는 것은  필수적이다. 고급언어는 구조상 라이
브러리를 써야만하고 이과정에서  프로그램에 소용되는 변수의 갯
수가 많아진다. 그런 이유로 지역변수는 스택을 이용한 조작이 불
가피하기 때문이다. 그러나 어셈블리어는 데이타의 이용이란 측면
에서는 아주 자유롭다.   프로그래머가 데이타의 저장되는 위치와
그 양을 모두 알기 때문이다. 반면에 고급언어에서는 그것을 아는
것이 거의 불가능하다.
**************************************************************
주석)
지역변수 (Local variable, Internal variable)
지역변수는 하나의  독립된 서브 프로그램  내에서만 쓰는 변수를
말한다. 그러므로 이 변수는 서브 프로그램의 종료와 함께 제거된
다.
전역변수 (Global variable, External variable)
전역 변수는 주 프로그램 서브 프로그램 모두 사용할수 있는 변수
를 말한다. 따라서 전체  프로그램이 종료할때가지 메모리에 남아
있는다.
        * 위의 두개념은 고급언에서만 존재한다.
**************************************************************
        3.      스택 포인터의 감소
        위에서 잠깐 언급한 스택 포인터의 값이 감소하는 이유는 
무엇일까 ?  스택에 데이타가 저장될때마다  메모리에서의 번지는 
오히려 2바이트씩 감소한다. 정상적인 경우 즉 메모리에 데이타가
저장되는 경우에 메모리의  번지는 증가해야함에도 불구하고 스택
에서는 반대의 현상을 보인다. 그 이유는 프로그램의 형태와 무관
하지 않을 것이다. 컴퓨터에서  실행화일이라 부르는 화일은 확장
명이 COM 아니면  EXE 이다. 즉 컴퓨터는  확장명이 COM 또는 EXE 
이면 무조건 메모리에 로드하고 실행해버린다. 이중 COM 프로그램
이 스택과 관련이 깊다. 앞에서도 언급이 되었지만 COM 형의 프로
그램에는 세그먼트 재배치에관한  헤더가 없다. 다시말해 .COM 형
의 프로그램은 하나의 세그먼트만을 사용하고 그에 따라서 프로그
램과 관계되는 네개의 세그먼트가 시작하는곳이 모두 같은 번지이
다. 그런데 임시적인 데이타를  스택에 저장한다고하여 스택 세그
먼트의 시작점에서부터 데이타를  저장한다면 프로그램 코드와 데
이타가 들어있는 메모리에  모두 '덮어써버리는' 결과를 초래하고 
말것이다. 물론 그렇게 되면 프로그램은 엉망이 되어버린다. 그러
므로 프로그램에서 사용하는 한정된  64KB 의 메모리 영역중에 그
래도 비교적 사용가능성이  드문 64 KB 의  끝부분 부터 데이타를 
저장해 내려온다면 프로그램의 코드나 데이타와 중복 사용될 가능
성이 적어질것이다. 이런 연유에서  스택 포인터는 프로그램이 시
작할때부터 스택 세그먼트의 가장 끝부분을 가리키고 있는것이다. 
그러나 만약 프로그램의  크기가 커서 거의 64  KB 의 끝부분까지
도달한다면 문제는 달라진다. 이경우에는 프로그램에서 저절로 설
정되는 스택 포인터를 사용하면  않되고 별도의 스택 영역을 확보
하고 스택 포인터도 이에 맞게 고쳐써야 할것이다.
        4.      스택의 호출번지 저장
        스택의 데이타  저장구조 즉 가장  늦게 저장된 데이타가 
가장먼저 사용되는 구조를 이용해 서브 프로그램의 호출시에 호출
한 프로그램에로의  복귀번지를 저장하는데 사용한다.  즉 현재의 
프로그램에서 서브 프로그램을  호출하는 경우에 호출하려는 서브 
프로그램이 현재의 세그먼트 내에  있으면 IP 값만 저장하고 현재
의 세그먼트 밖에 있으면 CS 와 IP 의 값을 스택에 저장한다.
        이러한 스택에 저장하는  방법은 생각해보면 합리적이다. 
서브 프로그램으로 제어가 넘어가기전에 현재의 CS 와 IP 의 값을 
만약에 데이타 영역에  저장했다고하고 제어를 서브 프로그램으로 
넘겼다고 하자. 그리고 서브 프로그램의 수행을 마치고 본래의 프
로그램으로 돌아가려 한다면  어떻게 CS 와 IP  를 저장한 번지를 
찾을수 있을까 ? 물론  서브 프로그램이 어셈블리어로 제작된다면 
별로 문제 될것은 없다.  어셈블리어는 데이타에 관한한 자유롭기 
때문에 프로그래머가 데이타의 위치를 임의로 설정 하는것이 가능
하다. 그러나 고급언어에서는 문제가 전혀 다르다. 일단 고급언어
로 작성된 프로그램내로  들어오게되면 메모리의 번지를 알아내는
것이 결코 쉽지않다. 많은  라이브러리가 결합된 형태의 고급언어
프로그램은 프로그래머 조차 레지스터의  움직임을 알 수 없기 때
문이다. 그러나 이러한 프로그램도  스택 영역은 변함이 없으므로
(스택은 하나이므로) 이곳에  데이타를 저장한다면 안전할것이다. 
마찬가지로 메인 프로그램에서  서브 프로그램으로 인수를 전달할
때에도 스택을 이용한다. 이것은  일종의 약속이다. 즉 언어를 막
론하고 스택의 영역은 변함이  없으므로 이곳을 통해 데이타를 교
환한다는것이다. 물론 반대로도  해석이 가능하다 '프로그램과 프
로그램간의 데이타 교환은 스택을  이용한다. 그러므로 스택 영역
은 변경하지 않는다.' 스택에 관하여 마치 닭이 먼저냐 알이 먼저
냐 하는식의 얘기가 되었으나 결론은 분명하다. 즉 '프로그램간의 
데이타 교환이나 호출한  프로그램에로의 복귀번지는 스택에 저장
한다' 하는것이 약속이라는 것이다.
            FFFFH      +--------------------+
                       |         0H         |
            FFFEH      +--------------------+      최초의 SP
                       |       DATA 1       |
            FFFCH      +--------------------+
                       |       DATA 2       |
            FFFAH      +--------------------+
                       |       DATA 3       |
            FFF8H      +--------------------+
                       |       DATA 4       |
            FFF6H      +--------------------+      현재의 SP
                       |                    |
                       |                    |
                           .COM 형의 스택
        최초의 SP 는 FFFEH 이고 SS  의 값은 CS 와 동일하다. 이
것은 .COM형의 프로그램은 하나의 세그먼트  값만을 가질수 없다는
이유에서 비롯된것이다. 그후 스택에 데이타가 하나씩 저장 될  때
마다 SP 의 값은 2 바이트 씩 감소하여 FFFCH,FFFAH,FFF8H 로 떨어
졌으며 데이타가 4개  저장될때 FFF6H 의 값을 가지게 되었다.
            0000H      +--------------------+      최초의 SP
                       |       DATA 1       |
            FFFEH      +--------------------+
                       |       DATA 2       |
            FFFCH      +--------------------+
                       |       DATA 3       |
            FFFAH      +--------------------+
                       |       DATA 4       |
            FFF8H      +--------------------+      현재의 SP
                       |                    |
                       |                    |
               스택영역을 설정하지 않은 .EXE 형의 스택
       최초의 SP 값은 0000H 이고 데이타가 하나씩 저장될때마다
역시 2바이트씩 감소한다. 0000H 에서 FFFEH 로 바뀌는 것에 의아
해 할수도 있다. 그 이유는 다음과 같다.   .EXE 형의 프로그램이
시작될때 이때는 SS와 CS의 값은 같다.  따라서 SS:SP 는 PSP:100
H 를 가리키고 있다.  그러나 데이타가 스택에  저장되기 전에 SS
의 값은 다시 설정되고 그후부터는  정상적으로 SP는 SS  의 끝에
서부터 내려로기 때문에 어느 세그먼트의 영역과도 겹치지 않는다.
 [34] 제목 : [소스] 보호모드 진입코드
 올린이 : yunix   (유경상  )    95/03/25 02:41    읽음 : 160  관련자료 없음
안녕하세요 yunix 입니다.
제가 32비트 프로그래밍 강좌를 하고 있는데.....
과연 386 보호모드로 진입하기 위해서는 어떠한 일들을 해야 하는 지
궁금해 하는 분들이 있으신것 같아 여기 간단한(?) 프로그램을 올려봅니다.
소스가 약간 길군요. 잘 분석해 보시고 질문을 하시면 성의껏 답변해 드리겠읍니다.
스스로 부딛혀보고 생각해 보는 것이 실력향상에 도움이... :)
참고로 Loner는 제 call-sign 입니다.
컴파일러는 tasm을 �구요. 아마 masm으로도 되리라 믿습니다.
링크하실때는 /3 옵션을 꼭 주셔야 합니당...
주석이 모두 영어군요... 짭...
제 콩글리쉬 실력을 마음껏 감상하십시요. :)
(   제길... 영어를 10년 넘게 공부했는데 ... 이게 뭐야 !
    우리나라 교육.... 문제야 ! )
    ---------------------------------------------------------------
;*
;*  File : enter.asm
;*
;*  enter.asm : entering protected mode code.
;*
;*  This code is used in [booting]. It will set up gdt and idt, and
;*  print some message.
;*  Once entered protected mode, we cannot go back to dos because we
;*  destory gdt,idt etc., which is used by dos memory manager like
;*  EMM386, QEMM386, 386MAX ....
;*  After execution this, you should power down your computer.
;*  This NEVER harm your computer.
;*
;*  [Extention]
;*  I will write a new code that read gnu program in real mode and enter
;*  protected mode using this code for running the gnu program.
;*  the gnu program is written with djgpp or gpp on the linux, which
;*  is allowed no dos function call, no bios call. This will be primitive
;*  operating system of mine. Isn't it wonderful?
;*
;*  Assembler : any assembler compatiable with MASM 5.0
;*
;*
;*      Copyright (C) 1994, Yu, Kyoung Sang
;*
;*              Wed  11-02-1994  02:07:30 written by Loner
;*
.386p
text        segment use16
        assume  cs:text,ds:data,ss:stk
;*
;* Let's DO IT !!!!
;*
enter_prot:
;*
;* check if operation mode is protected mode.
;*
        smsw    ax
        and ax,1
        jz  ready_to_enter
;*
;* hum... operation mode is already protected mode. memory manager like
;* EMM386 or QEMM may control 386. if we touch cr0(msw),idt, or gdt to enter
;* protected mode, the memory manager will complain and kill our program.
;* let's find other way. how about go back to real mode ?
;* but it need touch cr0(msw) and it is not allowed.
;* when processor is reset, it will operate in real mode. ok... let's reset
;* processor ! and jump to ready_to_enter. how ?
;* there is back door to go back in real mode. write 5 or 10 to shutdown
;* status byte of CMOS and set seg:off to jump at 040:0067 after reset.
;* then, when processor is reset, POST of BIOS will jump to address
;* where we write at 0040:0067. How funny it is !
;*
;* NOTE :
;*      after reset, you may not use some interrupt which memory
;*      manager have interceptted.
;*
        cli
        mov al,0fh      ; offset of shutdown status byte of CMOS
        out 70h,al      ; write offset
        mov al,10       ; after reset, jump where 40:67 point.
        out 71h,al
        mov ax,40h      ; set magic address(40:67)
        mov es,ax
        mov bx,67h
        mov ax,offset ready_to_enter
        mov es:[bx],ax  ; write address to jump after reset
        mov ax,cs
        mov es:[bx+2],ax
        mov cx,10       ; for safe reset, repeat 10 times
_reset:
        mov al,0feh     ; reset cmd ....
        out 64h,al      ; reset !!
        call    wait_8042   ; program control will never reach here
__die:      jmp __die
;*
;* now.... do some initialization to enter...
;*
ready_to_enter:
        mov ax,data
        mov ds,ax
;*
;* disabled interrupt will not be enabled until everything(idt) is ready.
;*
        cli
        mov ax,stk
        mov ss,ax
        mov sp,offset stk_ptr
;*
;* ok. segment initialzation is done. now, let's disable NMI.
;*
        mov al,80h      ; disable NMI
        out 70h,al
;*
;* all right. let's enable A20 line.
;* if A20 line is not enabled, we cannot access high memory area (10000h)
;*
        call    wait_8042   ; wait until 8042 is ready to read
        mov al,0d1h     ; d1h = write a byte to output port
        out 64h,al
        call    wait_8042   ; wait until 8042 reads a command
        mov al,0dfh     ; Gate A20 enable !
        out 60h,al
        call    wait_8042   ; wait until 8042 reads a data
;*
;* now, set gdt pointer.
;* gdt base is needed in format of 32bit linear address. so we should change
;* 20bit address of gdt to 32bit linear address.
;* save 32bit data segment pointer for later use (message ouput)
;*
        mov ax,ds
        shl ax,4
        mov bx,ax
        mov ax,ds
        shr ax,12
        push    ax
        push    bx      ; ax:bx=32bit data segment base
        add bx,offset gdt
        adc ax,0
        mov word ptr gdt_ptr+2,bx
        mov word ptr gdt_ptr+4,ax
;*
;* set far jump address as 32bit form into si,di register
;*
        mov ax,text_32
        shl ax,4
        mov bx,ax
        mov ax,text_32
        shr ax,12
        add bx,offset start_32
        adc ax,0            ; ax:bx => 32 bit linear pointer
        mov cs:jmp_addr,bx
        mov cs:jmp_addr+2,ax
;*
;* we shoud save stack pointer as 32bit form. because once entering protected
;* mode, stack pointer should be initialized again.
;*
        mov ax,ss
        shl ax,4
        mov dx,ax
        mov ax,ss
        shr ax,12
        add dx,sp
        adc ax,0
        mov cx,ax
;*
;* load gdt and idt onto descriptor table registers (gdtr,idtr)
;*
           lidt    pword ptr idt_ptr
           lgdt    pword ptr gdt_ptr
;*
;* ok. everythings are ready. now we are entering protected mode !
;*
        mov ax,1        ; set proctected mode bit
        lmsw    ax      ; now !!!
        jmp $+2     ; flush instruction prefetch queue.
;*
;* now, we are in protected mode. before do somthing, initialzing segment
;* register and do far jump to change cs register
;*
        mov bx,18h
        mov ds,bx
        mov ss,bx
        mov es,bx
        db  66h,0eah    ;   jmp far 10h:start_32
jmp_addr    dw  0h
        dw  0h
        dw  10h
;*
;* if input buffer is full, wait until 8042 reads from it.
;*
wait_8042:  in  al,064h     ; read 8042 status register
        test    al,02h      ; 8042 reads a byte from input buffer?
        jnz wait_8042
        ret
text        ends
.386p
text_32     segment use32
        assume  cs:text_32
;*
;* OK... we have succeeded !
;* you can do somthing in protected mode!
;* I will just output 'Hello ...' on the screen.
;*
start_32:
        mov ax,cx       ; cx:dx= 32bit stack pointer
        shl eax,16
        mov ax,dx
        mov esp,eax
;*
;* foolish check is done. check that A20 is REALLY enabled.
;*
        xor eax,eax
        mov ebx,0
        mov ecx,100000h
check_a20:  inc eax
        mov ebx,eax
        cmp eax,ecx
        jz  check_a20
;*
;* clear screen
;*
        mov ecx,80*25   ; clear screen
        mov ax,0820h    ; blank with black backgournd
        mov ebx,0b8000h ; text vram address
clear_screen:   mov [ebx],ax
        inc ebx
        inc ebx
        loop    clear_screen
;*
;* output message. message is in data segment. so we needs 32bit pointer of
;* message. we have already saved 32bit pointer of data segment on the stack.
;*
        pop esi     ; get 32bit data segment base
        mov eax,0       ; clear upper word
        mov ax,offset data:message  ; message offset
        add esi,eax     ; esi<- 32bit data segment
        mov ebx,0b8820h+54  ; screen position
        mov ah,1eh      ; yellow/blue attribute
output_msg: mov al,[esi]
        or  al,al       ; null character ?
        jz  end_msg
        mov [ebx],ax    ; output character
        inc esi     ; next pointer
        inc ebx     ; next screen position
        inc ebx
        jmp output_msg
end_msg:
;*
;* everything is done. we can go back to real mode but
;* we can't go back to dos. so...
;*
die:        jmp short die   ; die...
text_32     ends
data        segment use16
gdt_ptr     dw  4*8-1       ; limit of gdt
        dw  0,0
idt_ptr     dw  0,0,0       ; empty idt
gdt     dw  0,0,0,0     ; null descriptor
        dw  0,0,0,0     ; unused
        dw  07ffh       ; limit 8MB ((2047+1)*4096)
        dw  0000h       ; base = 00000000h
        dw  9a00h       ; present,dpl=0,exec/read code segment
        dw  00c0h       ; granularity=4KB, 32bit
        dw  07ffh       ; limit 8MB
        dw  0000h       ; base = 00000000h
        dw  9200h       ; present,dpl=0,read/write data segment
        dw  00c0h       ; graularity=4KB, 32bit
message     db  'Hello 386 world !'
        db  0
data        ends
stk     segment use16
stack_area  db  512 dup (0) ; stack area
stk_ptr     label
        db  16  dup (0) ; for dummy byte
stk     ends
        end
 [38] 제목 : MASM 6.1의 조건문 정리.
 올린이 : 영원의별(이세원  )    95/04/22 18:26    읽음 :  64  관련자료 없음
MASM 6.1 의 조건문 입니다.
이 조건문들을 통해서 고급언어 흉내를 낼 수 가 있지요.
예전에 만들어 두었던 것인데 그때가 그립군요.
이제 다시는 프로그램 만들기가 쉽지 않을듯 합니다.
프린터로 뽑아서 고이 간직하세요...
MASM 6.x 는 고급언어에서나 볼 수 있었던 여러가지 조건문을 사용할 수 있게
되었다. 블럭 구조의 이들 조건문의 연산자는 다음과 같다.
┌────────┬──────────────────┐
│    연산자      │                 의미               │
├────────┼──────────────────┤
│      ==        │             같으면                 │
│      !=        │             같지 않으면            │
│      >         │             크면                   │
│      >=        │             크거나 같으면          │
│      <         │             작으면                 │
│      <=        │             작거나 같으면          │
│      &         │             BIT TEST               │
│      !         │             NOT                    │
│      &&        │             AND                    │
│      ||        │             OR                     │
└────────┴──────────────────┘
        1        .IF,.IFELSE,.ELSE,.ENDIF
이 블럭 구조문은 .IF 에서 시작하여 .ENDIF 에서 끝난다. 따라서 조건을 만족
했으면 .ENDIF 이후의 명령을 수행하게된다.
형식)
        .IF     조건식
                명령어
        .ELSE
                명령어
        .ENDIF
먼저 조건을주고 조건에 맞으면 다음 문장을 수행하고 빠져나간다. 그러나 조건과
맞지 않으면 .ELSEIF 이후의 문장을 수행하고 빠져나간다.
        .IF     조건식
                명령어
        .ELSEIF
                명령어
        .ELSEIF
                명령어
        .ELSEIF
                명령어
               .
               .
               .
        .ENDIF
이 구조식도 위와 위와 별 차이가 없다. 먼저 조건을 비교하고 만족하면 밑의
명령을 수핸하고 빠져나가고 만족하지 않으면 다음 조건과 비교한다. 다음조건
과 비교해서 만족하면 밑의 명령을 수행하고 빠져나가고 만족하지 않으면 다음
조건과 비교한다.....
code    segment
        assume  cs:code
org     100h
start:
        mov     cx,100
        .if     cx==10                 ;─── ①
        mov     ah,9                   ;─┐
        mov     dx,offset msg1         ;  ├─ ②
        int     21h                    ;─┘
        .else                          ;─── ③
        mov     ah,9
        mov     dx,offset msg2
        int     21h
        .endif                         ;─── ③
        mov  ah,4ch                    ;─── ⑤
        int  21h
msg1    db     'msg1$'
msg2    db     'msg2$'
code    ends
        end     start
① 만약 CX 가 10이면 ② 를 수행하고 그렇지 않다면 ③으로 간다.
② 'msg1' 을 출력하고 ⑤ 로 간다.
③ 'msg2' 를 출력하고 ⑤ 로 간다.
④ 이 블럭 구조문의 끝
⑤ 프로그램을 종료한다.
이 프로그램을 어셈블하여 디버깅을 해본다.
C:\MASM61\BIN>debug sam2.com 
-u 
186F:0100 B96400        MOV     CX,0064
186F:0103 83F964        CMP     CX,+64
186F:0106 7509          JNZ     0111
186F:0108 B409          MOV     AH,09
186F:010A BA1C01        MOV     DX,011C
186F:010D CD21          INT     21
186F:010F EB07          JMP     0118
186F:0111 B409          MOV     AH,09
186F:0113 BA2101        MOV     DX,0121
186F:0116 CD21          INT     21
186F:0118 B44C          MOV     AH,4C
186F:011A CD21          INT     21
186F:011C 6D            DB      6D
186F:011D 7367          JNB     0186
186F:011F 3124          XOR     [SI],SP
-
막상 디버깅을 해보명 역시 우리의 소스 프로그램과 약간 다르게 기계어로
번역 되었음을 알 수 있다. 하지만 우리가 의도했던대로의 결과를 나타내고 있다.
        2   .WHILE,.ENDW
이 블럭 구조문은 .WHILE 에서 시작하여 .ENDW 로 끝난다.
먼저 조건을 주고 그 조건이 만족될 때까지 밑의 명령을 반복 수행한다.
형식)   .WHILE  조건식
                명령어
        .ENDW
code    segment
        assume  cs:code
org     100h
start:
        mov     dx,10                   ;①
        .while  dx > 0                  ;②
        dec     dx                      ;③
        .endw                           ;④
        mov     ah,4ch
        int     21h
code    ends
        end     start
① DX 에 10을 넣는다.
② DX 가 10보다 큰 동안 밑의 명령을 수행한다.
③ DX 의 값을 1 감소한다.
④ .WHILE 블럭 구조문의 끝
다음은 이 프로그램을 어셈블링하여 디버깅한것이다.
C:\MASM61\BIN>debug sam3.com 
-u 
186F:0100 BA0A00        MOV     DX,000A
186F:0103 EB01          JMP     0106     ─┐
186F:0105 4A            DEC     DX         ├─ ①
186F:0106 83FA00        CMP     DX,+00     │
186F:0109 77FA          JA      0105     ─┘
186F:010B B44C          MOV     AH,4C
186F:010D CD21          INT     21
186F:010F 7C4E          JL      015F
186F:0111 8700          XCHG    AX,[BX+SI]
186F:0113 004E92        ADD     [BP-6E],CL
186F:0116 4E            DEC     SI
186F:0117 9D            POPF
186F:0118 4E            DEC     SI
186F:0119 A84E          TEST    AL,4E
186F:011B B34E          MOV     BL,4E
186F:011D BE4EC9        MOV     SI,C94E
-
① 의 내용이 .WHILE 블럭 구조문에 의해 생성된 기계어 코드이다.
        3   .REPEAT,.UNTIL,.UNTILCXZ
형식)   .REPEAT
                명령어
        .UNTIL  조건식
.UNTIL 의 조건이 만족 될때까지 .REPEAT 밑의 명령을 반복 수행한다.
        .REPEAT
                명령어
        .UNTILCXZ
        .UNTIL  조건식
.UNTIL 의 조건이 만족 될때까지 .REPEAT 밑의 멸영을 반복수행 하다가 만약
CX 의 값이 0이되면 빠져나간다.
code    segment
        assume  cs:code
org     100h
start:
        .repeat                     ----①
        inc     si
        .until  si == 10            ----②
        mov     cx,10               ----③
        .repeat                     ----④
        inc     di
        dec     cx                  ----⑤
        .untilcxz                   ----⑥
        mov     ah,4ch
        int     21h
code    ends
        end     start
① .REPEAT 블럭문의 시작
② SI 가 10 이 뚜때까지 반복 수행한다.
③ CX 의 초기값으로 10을 넣는다.
④ .REPEAT 블럭문의 시작
⑤ CX 의 값을 1 감소 시킨다.
⑥ 만약 CX 의 값이 0이면 빠져 나간다.
C:\MASM61\BIN>debug sam4.com 
-u 
186F:0100 46            INC     SI         ──┐
186F:0101 83FE0A        CMP     SI,+0A         ├─ ①
186F:0104 75FA          JNZ     0100       ──┘
186F:0106 B90A00        MOV     CX,000A    ──┐
186F:0109 47            INC     DI             ├─ ②
186F:010A 49            DEC     CX             │
186F:010B E2FC          LOOP    0109       ──┘
186F:010D B44C          MOV     AH,4C
186F:010F CD21          INT     21
186F:0111 8700          XCHG    AX,[BX+SI]
186F:0113 004E92        ADD     [BP-6E],CL
186F:0116 4E            DEC     SI
186F:0117 9D            POPF
186F:0118 4E            DEC     SI
186F:0119 A84E          TEST    AL,4E
186F:011B B34E          MOV     BL,4E
186F:011D BE4EC9        MOV     SI,C94E
-
① .REPEAT 문에 의해서 SI 가 10이 될때까지 반복한다.
② .REPEAT 문에 .UNTILCXZ 가 삽입된 관계로 LOOP 명령어가 출현하였다.
        4   .BREAK,.CONTINUE
.BREAK 은 .WHILE/.ENDW 나 .REPEAT/.UNTIL/.UNTILCXZ 문의 루프를 도중에
빠져나오게 하고 .CONTINUE 은 .WHILE/.ENDW 나 .REPEAT/.UNTIL/.UNTILCXZ 문의
루프를 계속 실행시키게한다.
형식)
        .BREAK
        .BREAK          .IF 조건식
        .CONTINUE
        .CONTINUE       .IF 조건식
code    segment
        assume  cs:code
org     100h
start:
        .while  dx!=100              ---①
        inc     ax
        .if     ax==100              ---②
        .break                       ---③
        inc     si
        .endif
        inc     dx
        .endw
        mov     ah,4ch
        int     21h
code    ends
        end     start
① DX 가 100이 아닌동안 밑의 명령을 반복 수행한다.
② 만약 AX 가 100 이면 밑의 명령을 수행한다.
③ 이 명령에 의해 .WHILE 블럭 루프문을 완전히 빠져나간다.
C:\MASM61\BIN>debug sam5.com 
-u 
1A7C:0100 EB0A          JMP     010C
1A7C:0102 40            INC     AX
1A7C:0103 83F864        CMP     AX,+64
1A7C:0106 7503          JNZ     010B
1A7C:0108 EB07          JMP     0111            ----①
1A7C:010A 46            INC     SI
1A7C:010B 42            INC     DX
1A7C:010C 83FA64        CMP     DX,+64
1A7C:010F 75F1          JNZ     0102
1A7C:0111 B44C          MOV     AH,4C
1A7C:0113 CD21          INT     21
1A7C:0115 92            XCHG    DX,AX
1A7C:0116 4E            DEC     SI
1A7C:0117 9D            POPF
1A7C:0118 4E            DEC     SI
1A7C:0119 A84E          TEST    AL,4E
1A7C:011B B34E          MOV     BL,4E
1A7C:011D BE4EC9        MOV     SI,C94E
-
① .BREAK 문이 나타난 명령코드이다.
 [40] 제목 : [소스] 부팅시간을 기록하는 bootlog.asm
 올린이 : 영원의별(이세원  )    95/04/22 19:20    읽음 :  45  관련자료 없음
;┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
;┃     bootlog.asm                                                        ┃
;┃     날짜및 시각을 화일에 순차로 입력하는 프로그램.                     ┃
;┠────────────────────────────────────┨
;┃     자기 컴퓨터의 부팅시간을 기록하는 프로그램은 수 없이 많습니다.     ┃
;┃     하지만 이 프로그램 만큼 작고 그리고 빠르게 기록하는                ┃
;┃     프로그램은 없을 겁니다.                                            ┃
;┃     왜냐구요? 어셈블리로 만들었으니까요...                             ┃
;┃     어셈블리를 공부하시는 분에게 도움이 되길 빌며...                   ┃
;┃     앞으로 가끔 그동안 제가 만들었던 어셈유틸의 소스를 올리겠습니다.   ┃
;┃     마지막으로 .EXE 형의 프로그램입니다.                               ┃
;┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
        dosseg
data    segment
year            dw      ?
month_date      dw      ?
a_day           dw      ?
time            dw      ?
second          dw      ?
temp_1          db      ?
temp_2          db      ?
temp_3          db      ?
temp_4          db      ?
now_year        db      4       dup('y')
                db      '.'
now_month       db      2       dup('m')
                db      '.'
now_date        db      2       dup('d')
                db      '  '
now_time        db      2       dup('t')
                db      ':'
now_minute      db      2       dup('m')
                db      ':'
now_second      db      2       dup('s')
                db      13,10
write_error_msg         db      'Write error.$'
open_error_msg          db      'Open error.$'
pointer_error_msg       db      'Pointer error.$'
path_name       db      'c:\bootlog',0             ;화일이름(아스키즈 문자열)
handle          dw      ?
data    ends
stack   segment stack
        db      100h dup(0)
stack   ends        
code    segment
        assume  cs:code,ds:data,ss:stack
start:
        mov     ax,data
        mov     ds,ax
        push    ds                              ;ES 를  DS 에 맞춘다.
        pop     es
;---------------------
;날짜및 요일 읽어내기
;---------------------
read_date:
        mov     ah,2ah                          ;년,월,일을 구한다.
        int     21h
        mov     year,cx                         ;year
        mov     month_date,dx                   ;month & date
        mov     ax,year
        call    div_1                           ;나누기 수행
        mov     cx,4                            ;year
        mov     si,offset temp_1                ;년도를 저장한다.
        mov     di,offset now_year
        rep     movsb
        mov     ax,month_date
        call    div_2                           ;나누기 수행
        mov     cx,2                            ;month
        mov     si,offset temp_1                ;월을 저장한다.
        mov     di,offset now_month
        rep     movsb
        mov     cx,2                            ;date
        mov     si,offset temp_3                ;일을 저장한다
        mov     di,offset now_date
        rep     movsb
;----------------
; 시각 읽어내기 
;----------------
        mov     ah,2ch                          ;시각 구하기
        int     21h
        mov     time,cx                         ;time
        mov     second,dx                       ;second
        mov     ax,time
        call    div_2                           ;나누기 수행
        mov     cx,2                            ;시간저장
        mov     si,offset temp_1
        mov     di,offset now_time
        rep     movsb
        mov     cx,2                            ;분저장
        mov     si,offset temp_3
        mov     di,offset now_minute
        rep     movsb
        mov     ax,second
        call    div_2                           ;나누기 수행
        mov     cx,2                            ;초저장
        mov     si,offset temp_1
        mov     di,offset now_second
        rep     movsb
;---------------------
; 화일 오픈 및 쓰기
;---------------------
file_open:
        mov     ah,3dh                          ;화일오픈
        mov     dx,offset path_name             ;화일명
        mov     al,1                            ;쓰기전용
        int     21h
        jc      file_creat                      ;오픈에 실패하면 화일을 만든다.
        mov     handle,ax                       ;핸들을 저장한다.
        mov     ah,42h                          ;화일 포인터의 설정
        mov     al,2                            ;이동 오프셍을 화일의
                                                ;끝에다 더한다.
        mov     bx,handle                       ;핸들번호
        mov     cx,0                            ;이동 바이트 상위 값
        mov     dx,0                            ;이동 바이트 하위 값
        int     21h
        jc      pointer_error                   ;캐리발생하면 포인터에라
        mov     ah,40h                          ;화일쓰기
        mov     dx,offset now_year              ;출력버퍼 번지
        mov     cx,22                           ;써넣을 바이트수
        mov     bx,handle                       ;핸들번호
        int     21h
        jnc     file_close                      ;캐리가 발생안하면
                                                ;화일을 닫아라.
        mov     ah,9                            ;쓰기에라 메시지출력
        mov     dx,offset write_error_msg
        int     21h
        jmp     file_close
file_creat:
        mov     ah,3ch                          ;화일생성
        mov     dx,offset path_name             ;화일명
        mov     cx,0                            ;정상속성
        int     21h
        jnc     file_open                       ;캐리가 발생안하면 오픈하라
        mov     ah,9                            ;오픈에라 메시지 출력
        mov     dx,offset open_error_msg
        int     21h
        jmp     exit
pointer_error:
        mov     ah,9                            ;포인터 에라 메시지출력
        mov     dx,offset pointer_error_msg
        int     21h
file_close:
        mov     ah,3eh                          ;화일닫기.
        mov     bx,handle                       ;핸들번호
        int     21h
exit:
        mov     ah,4ch
        int     21h
;-------------------
; 연결된 숫자 변환 
;-------------------
div_1:
        mov     bl,100                          ;젯수 100
        div     bl                              ;100으로 나누기
        push    ax                              ;100으로 나눗값 보존
        mov     bl,10                           ;젯수 10
        mov     ah,0                            ;몫을 다시 10으로 나눈다.
        div     bl
        add     al,30h
        mov     temp_1,al                       ;1000단위 저장
        add     ah,30h
        mov     temp_2,ah                       ;100단위 저장
        pop     ax                              ;100으로 나눈값 복구
        xchg    ah,al                           ;100으로 나눈값의 나머지를
        mov     ah,0                            ;다시 나누기위해
        div     bl                              ;다시 10으로 나눈다
        add     al,30h
        mov     temp_3,al                       ;10단위 저장
        add     ah,30h
        mov     temp_4,ah                       ;1단위 저장
        ret
;--------------------
; 분리된 숫자 계산 
;--------------------
div_2:
        push    ax
        xchg    ah,al                           ;ah,al을 따로 나누기위해
        mov     ah,0
        mov     bl,10                           ;젯수 10
        div     bl                              ;10으로 나눈다
        add     al,30h
        mov     temp_1,al                       ;몫 저장
        add     ah,30h
        mov     temp_2,ah                       ;나머지 저장
        pop     ax
        mov     ah,0
        div     bl
        add     al,30h
        mov     temp_3,al                       ;몫 저장
        add     ah,30h
        mov     temp_4,ah                       ;나머지 저장.
        ret
code    ends        
        end     start                           ;진입접
 [41] 제목 : [새내기 연재] 어셈블러가 도대체 뭐길래
 올린이 : hanuly님(조광현  )    95/04/23 21:19    읽음 : 114  관련자료 있음(TL)
어셈블러?? 어셈블러?! 어셈블러!? 어셈블러!
─────────────────────
      Copyright(c)1995,.Sir hanuly        ┍━┯━━━━━━━━━━━━━┑
   어셈 새내기를 위한 어셈 기초 연재...   │Ⅰ│어셈블러가 도대체 뭐길래..│
                                          ┕━┷━━━━━━━━━━━━━┙
 ★ 기억하세요!
  * 저의 비주얼 베이직 연재를 읽어보신 분들은 아시겠지만, 내용이 '잡담 형식'
  으로 꾸며지다가, 때로는, 교습 형식으로 꾸며지는 등의 이상한 진행 형태를 취
  하고 있습니다.
  * 이 연재는 어셈블러를 처음 배우시는 분들을 위해 마련되었습니다.
  * 개인적 질문 편지는, 되도록 '삼가'해주시고, '묻고 답하기' 란을 이용해주셨
  으면 합니다.
  * 내용상의 오류가 발견된 경우는 언제든지 편지로 연락주시기 바랍니다. 제 아
  이디는 아시죠? 'hanuly님'입니다.
  * 본 내용을 제 허가 없이 베끼거나(!), 복사(?)하는 행위를 하시면, 제가 화낼
  거예요.. 그리고, 저작권법에 의거(?)해 고소할거예요.. (히히.. 돈버는거 좋아
  하는 리님..)
  * 본 내용의 소스들은 거의 다 Macro Assembler 5.x를 기준으로 작업합니다. 공
  개자료실에 등록되어 있습니다.
  * 필요한 파일들..
      masm.exe
      link.exe
   exe2bin.??? <-이름을 까먹었어요...
                 그리고, 즐기는 에디터...('산'이나, 'UEdit'나, 도스의 'edit'
                 같은..)
─────────────────────────────어셈블러는 어렵다?
 안녕하세요? 하누리님입니다.
 어셈블러는 어렵다는 말씀을 많이 하시더군요... 게다가...많은 분들이 공부하다
가 중간에 포기하십니다. 물론, 어셈블러는 어려워요...(...) 인터럽트를 직접 건
드리고 놀아야(?) 합니다. 하드웨어, CPU 원리...
 ..맞아요.. 어셈블러를 배우는 것은 영어를 배우는 것과 비슷하다고 해야겠군요.
영어를 배울때는 단어와 숙어를 열심히 외움과 동시에, 문법도 연구합니다.. 게다
가, 사고 방식, 환경까지...
 어셈블러는 그렇지만, 영어보다 쉬워요. printf...int.. 엄청나게 많은 단어들..
(C나, Basic, Pascal 같은 고급 언어들은 다 그렇죠..뭐..) 언제 외우노.. 그쵸?
 그렇지만, 어셈블러는 mov, int, add등의 몇개의 명령어만 배우면 됩니다. 문화
방식 이해하기도 쉽고(미국이나, 영어의 문화 방식 같은..)..
 어셈블러는 아는대로 써먹을 수 있다는 것이 장점일수도 있겠군요. 물론, 이 연
재와, 앞으로 올라올 연재들을 학습한다고 해서, 다 깨닫는 것은 절대 아니겠죠!
 그렇지만, 어셈블러로 쬐끄만 프로그램은 짤 수 있을거예요(저도 바라고.. 당신
도 바라고.. 우리도 바라는 목표입니다).
 영어를 배울려면, "영어에 대해서, 학교에서 배우는 것" 보다는, "미국에 가서,
직접 경험하고 느끼는 것"이 훨씬 효과적입니다. 어셈블러도... 시스템이 다운되
고, CMOS가 날아가고..(우리는 그정도로 극단적인 기법은 학습하지 않아요... 그
러한 것들을 하려면, 다른 분들의 강좌를 읽으셔야 겠죠..) 아무튼, 실제로 느껴
서 하는 것이 가장 중요하다는 거.. 아시죠? 어셈은 그럴때 더욱 더 나의 친구로
다가오게 되는 것입니다.
 자, 우리 어셈 새내기들... 화이팅을 외치며.. 조그만 시작을.. 하자구요..
 ¤ 명언 : 시작이 반이랍니다.
─────────────────────────────── 어셈이 뭐꼬?
 자, 여기서 처음부터 어셈블러(이하, '어셈'이라고 부릅니다)를 배우려고, 하시
는 분들은 손 들어보시겠어요?
 당신도, 남대문에서 과일 파시는 아저씨도, 손을 내리고 계시는 군요..어! 그런
데.. 저쪽에서는 국민학생 같아 보이는 학생들이 손을 들고 있네요... 아.. 학교
에서 벌을 받고 있었군요.. 
 어셈을 처음부터 배우려는 분들은 아주 극소수입니다. 물론이죠! 극소수죠.
 베이직이나, 씨나, 파스칼이나.. 다른 언어를 먼저 배우고, 어셈을 배우는 것이
보통입죠. 네..
 원래 컴퓨터는 고철덩어리죠. 2진수만 받아들이죠.. 꺼졌다 켜졌다... 아시리라
생각되는 군요.. 세게.. 약하게는 해당되지 않습죠(디지탈 형식이다..).
 게다가, 컴퓨터의 머리는 꼭 자기가 기계인 것을 티를 낸답니다, 기계어만을 받
아들일줄 안답니다.
 그래서, 수치 비교도 사실 컴의 머리(CPU:중앙처리장치)로서는 엄청난 작업을..
거치는 겁니다.
 그래서, 고급언어는 하나의 문장으로 처리되는 것이... 어셈-기계어와 1대 1로
대응하는 언어-에서는 복잡해지고.. 기계어는... 꼬로로로록..(거품내는 소리)
 예를 들어서.. 1+2+3을 계산합니다.
 Basic은요..
    abc = 1+2+3
 C는요..... 
    abc = 1+2+3;
 어셈은요...
    mov abc,1
    add abc,2
    add abc,3
 기계어는요...
    (저도 잘모릅니다. ... ★... 하지만, 엄청 복잡하다는 것은 아시리라.. 악!
    돌이,.,.,.)
 고급언어(씨나, 베이직)은 한줄이면 끝나죠. 어셈은요.. 에고.. 석줄씩이나..
기계어는... 아시리라...
 그렇지만, CPU는 한번에 하나만 더할줄 압니다. 즉,
 a=1+2
  ┌─┐
  │1│→ 넣어요.. CPU에..
  └─┘           ┌─┐
                   │1│이 CPU에 기억됩니다.
                   └─┘
  ┌─┐  
  │2│->넣어요.. 더하라는 신호도..
  └─┘           ┌┬┐
                   │3┤이 기억됩니다.
                   └─┘
  이런 구조이기에.. 1+2+3을 계산할때 석줄이 필요했던 것입니다.
─────────────────────────────────어셈이 뭐꼬?
 이 정도로만 해 두죠... 어셈에대해서 이해하셨으리라 믿습니다.
 1+2를 더했던 것과 같이, CPU의 계산 방식처럼, 한번에 하나를 더하는... 기계어와
1대 1로 대응하는.. (모 학습지처럼, 기계와 눈높이를 맞추고 있는) 언어가 바로 어
셈입니다.
 숫자를 더하는 예를 들어서 설명드렸고요..
 다음에는... 맛보기 예제를 하나 만들어보도록 하죠..
 그럼 안녕히! 노력이 있으면, 결과가 있기 마련입니다.
 [42] 제목 : [새내기 연재] 어셈으로 만든 첫 프로그램
 올린이 : hanuly님(조광현  )    95/05/02 00:15    읽음 :  88  관련자료 있음(TL)
어셈블러?? 어셈블러?! 어셈블러!? 어셈블러!
─────────────────────
      Copyright(c)1995,.Sir hanuly        ┍━┯━━━━━━━━━━━━━┑
   어셈 새내기를 위한 어셈 기초 연재...   │Ⅱ│어셈으로 만든 첫 프로그램.│
              1995. 5. 2                  ┕━┷━━━━━━━━━━━━━┙
 ★ 기억하세요!
  * 이 연재는 어셈블러를 처음 배우시는 분들을 위해 마련되었습니다.
  * 개인적 질문 편지는, 되도록 '삼가'해주시고, '묻고 답하기' 란을 이용해주셨
  으면 합니다.
  * 내용상의 오류가 발견된 경우는 언제든지 편지로 연락주시기 바랍니다. 제 아
  이디는 아시죠? 'hanuly님'입니다.
  * 본 내용을 제 허가 없이 베끼거나(!), 복사(?)하는 행위를 하시면, 제가 화낼
  거예요.. 그리고, 저작권법에 의거(?)해 고소할거예요.. (히히.. 돈버는거 좋아
  하는 리님..)
  * 본 내용의 소스들은 거의 다 Macro Assembler 5.x를 기준으로 작업합니다. 매
  크로 어셈블러 5.x는 공개 자료실에 등록되어 있습니다.
────────────────────────────────어셈블이라..
 안녕하세요? 하누리님입니다.
 우리는 지난번에, 어셈블러가 도대체 뭔지에 대해서, 이야기를 했었죠. 어셈블러
를 배우는 것은 영어를 배우는 것, 영어를 배울때는 단어, 숙어, 문법.. 미국놈들
의 사고 방식, 환경 등까지 배워야 이해를 할 수 있다고 했었죠!
 오늘은 간단한 프로그램(?)을 만들어봄으로서, 어셈블러의 프로그래밍 개념에 대
해서 조금만 맛 보도록 할 것입니다. 아무튼, 노력만 한다면, 결과는 분명히 좋을
거라고 생각해요...
 씨나, 파스칼의 컴파일이라는 작업을 아시겠지요. 그러나, 어셈으로 소스를 코딩
하고, obj로 변환시키는 건, 컴파일한다고 하면 망신살이 뻗친다는 사실을 기억하
세요~!
 어셈블에 대해서 들어보셨는지요.  어셈블리어 소스를 기계어로 바꿔주는 과정이
라고 생각하시면 쉽습니다. 컴파일 정도에 견주어보시면 됩니다. 그리고, 이 어셈
블 과정을 해주는 것이 바로 이름하여 '어셈블러' 입니다.
────────────────────────어셈으로 프로그램을 짜는데..
 어셈 프로그램을 만들때는 보통 다음과 같이 하게 됩니다.
 1> 프로그램의 작성해야겠다!
  우선 시작을 위해서는 어떤 프로그램을 짤 것인지 목표를 정해야 겠죠?
 2> 에디터로 소스 프로그램을..
  산이나, Uedit등으로 소스를 작성합니다. → 저장함으로 ?.ASM이 만들어졌겠죠.
 3> masm이나, tasm으로 어셈블합니다. IF 실패?=True 그렇다면.. 1,2번으로..
    성공이라면.. obj파일이 생성되었겠죠!
 4> link나 tlink로 링크! If 실패?=True 그렇다면 1,2,3번...
    성공이면 .EXE.COM파일 생성!
 5> 실행테스트! if 실패?=True 그렇다면 2번...(논리적 오류이므로, 제작자의
    알고리듬 실수일 가능성이 제일 높습니다.)
 6> 성공?! -> 완성이닷!
────────────────────────────── 나의 첫 프로그램
 자, 어셈에 대한 개괄적 이해를 하게 되셨으리라 믿고(광현아! 설명도 x떡같이 해
놓고는 무슨 소리얏!! 끄아아~!), 간단한 다음과 같은 소스를 준비해 보았습니다.
 우리가, 터보씨를 배웠을때 맨처음 작성했던 프로그램이죠..
 "Hello, World!"라는 문자열을 출력하는 것입니다.  main안에서 printf만 써도 될
것 같은데.. 어셈이라는 점을 명심하시고..
┌hello.asm ───────────────────────────────┐
│  DOSSEG                                                                │
│  .MODEL SMALL               ;메모리 모델을 SMALL로!                    │
│                                                                        │
│  .STACK 100h                ;스택을 잡아둡니다.                        │
│                                                                        │
│  .DATA                                                                 │
│message db 'Hello, World!',13,10,'$' ;메세지는 바로...이것!             │
│                                                                        │
│.CODE                                                                   │
│                                                                        │
│mov ax,@data                  ;DS 초기화...                             │
│mov ds,ax                                                               │
│                                                                        │
│mov ah,9                      ;메세지를 화면에 찍는 부분                │
│mov dx,offset message                                                   │
│int 21h                                                                 │
│                                                                        │
│mov ah,4ch                    ;끝내는 부분..                            │
│int 21h                                                                 │
│                                                                        │
│END                                                                     │
└────────────────────────────────────┘   
 자, 다 작성하셨다면 (전문가 같이 보이게 하는 말로)어셈블링 시켜볼까요?
 masm이 준비되셨겠죠? 저는 분명히 5.0정도로도 충분하다고 말씀드렸습니다~!
┌────────────────────────────────────┐
│                                                                        │
│C:\LANG\MASM>masm hello←                                               │
│Microsoft (R) Macro Assembler Version 5.10                              │
│Copyright (C) Microsoft Corp 1981, 1988,   All right reserved.          │
│                                                                        │
│Object filename [hello.obj] : ← ;엔터로 그냥 넘어가세요.. 신경쓰지말고.│
│Source Listing  [NUL.LST] : ← ;소스가 어쩌구저쩌군요..그냥 무시합시다~!│
│Cross-reference [NUL.CRF] : ← ; 냠냠.. 그냥 넘어갑시다~!               │
│                                                                        │
│ ????? + ?????? Bytes symbol space free                                 │
│                                                                        │
│  0 Warning Errors                                                      │
│  0 Severe  Errors                                                      │
│                                                                        │
└────────────────────────────────────┘
 이렇게 되었다면 성공~! 그런데, 여기서 끝나면 바보.. 링킹해야죠..(연결??)
┌─────────────────────────────────────┐
│C:\LANG\MASM>link hello←                                                 │
│Microsoft (R) Overlay Linker. .... 어쩌구...                              │
│                                                                          │
│Run File [HELLO.EXE] : ←                                                 │
│                                                                          │
│List ...  : ←                                                            │
│Library...: ←                                                            │
│                                                                          │ 
└─────────────────────────────────────┘
 이런식으로 넘기면 hello.exe가 만들어집니다.
 자, 실행해보시죠?!
 그리고.. 결과는??
 간단한 맛배기 였습니다. 
─────────────────────────────────────결론
 우리는 이 소스를 구경하고 입력해봄으로써, 어셈블러에 대해서 어느정도의 파악은
할수 있었습니다.
 다음에는 뭘할까요? 좀 따분한 내용을 다루도록 하죠. 그럼 이만...
-------------------------------
함께누리는 넓은 하늘아래 우리를 모으는 한울타리..  그리고, 상대방을 존중
할줄아는 그러한 말가짐새... 하누리님은 그러한 뜻을 가지고 있습니다.
출력이 끝났습니다. [Enter]를 누르십시오.
출처 : Nohave Name's Money Blog
글쓴이 : 이름없음 원글보기
메모 :