본문 바로가기

IT/Intel 16bit Assembly

x86 16bit 어셈블리(Assembly) 예제 정리 - 4

/* 
written by kaspy (kaspyx@gmail.com)
*/ 

문득 어셈블리 언어를 보다보면 자주쓰지 않는 만큼 해깔릴수 있는것들이 많은것 같아서 정리해보았다. 특히 주소 연산 mov [100], 10 같은것들
많이 사용되지 않는 16bit 어셈블리어지만 레지스터 크기나 명령어 이름만 조금 바꾼 형태로 익힌다면 32bit도 그리 어렵지는 않을것이다.

이번에는 비교 및 분기문, 특수연산 등으로 정리하였다.

JG 및 JA 명령어

예제)

  1. mov bl, 5
  2. cmp al, bl
  3. jg 0188
  4. ja 018a
  5.  
  6. ;bl 레지스터에 5를 저장하고 al과 비교하여 클 경우 018a 주소로 번지시킵니다.
  7. ;여기서 jg 구문에서 점프하지 않고 ja에서 한 이유는 jg는 부호있는 검사를 하여 al의 값은 음수가 됩니다.
  8. ;이때는 al이 bl 보다 작으며 ja 로 비교했을 경우는 부호없는 비교이기 때문에
  9. ;al은 ff로 비교하게되고 참이기 때문에 018a 번지로 점프합니다.


JL 명령어

예제)

  1. cmp al, bl
  2. jl 198
  3.  
  4. ;al과 bl을 비교하여 al이 작을 경우 198번지로 이동합니다.
  5. ;jl 은 부호있는 음수로 비교하기 때문에 al레지스터는 ff가 아니라 -7f입니다.
  6. ;bl = 5 이기 때문에 작다는 조건을 만족하고 198번지로 이동합니다.


JL JA JG 명령어

예제)

  1. cmp al, bl
  2. jl 01aa
  3. ja 01ac
  4. jg 01ae
  5.  
  6. ;al과 bl을 비교해서 참값이 되면 해당번지로 점프시킵니다.
  7. ;여기서 jl 은 부호있는 비교이기 때문에 bl은 ff가 아니라 -7f이고 al은 5이기 때문에 조건을 만족하지 않습니다.
  8. ;ja는 부호없는 비교이며 이때는 bl이 ff이므로 조건을 만족하지 않아 점프하지 않고
  9. ;jg는 부호있는 비교이므로 al은 5 그리고 bl은 -7f 와 비교하여 al이 더크기 때문에 1ae번지로 점프합니다.


LOOP 명령어

예제)

  1. mov cx, 8
  2. inc ax
  3. loop 01b6
  4.  
  5. ;cx레지스터가 0이 될 때까지 감소 시키면서 (loop)01b6 번지를 반복합니다.
  6. ;01b6번지는 inc ax이며 8번 반복하여 ax가 8이 되었습니다.


SHR 명령어

예제)

  1. shr bh, 1
  2.  
  3. ;bh 레지스터를 오른쪽으로 1만큼 쉬프트 연산합니다.


AND, NOT, OR, XOR 명령어

예제)

  1. and al, bl
  2. not al
  3. or al, bl
  4. xor al, bl
  5.  
  6. ;해당 레지스터와 al <- al 연산 bl
  7. ;논리연산 and, not, or, xor를 수행합니다.
  8. ;not은 1이면 0으로 0은 1로 바꿉니다.


LODSB 명령어

예제)

  1. lodsb
  2.  
  3. ;ax의 하위 1바이트 al 레지스터에 ds 세그먼트 오프셋 si 의 값을 저장합니다. 즉
  4. ;al <- ds:si

REPZ, STOSW 명령어

예제)

  1. mov cx, 07d0
  2. repz
  3. stosw
  4.  
  5. ;cx에 07d0를 저장하고 repz 와 stosw를 실행하면 cx레지스터를 0이 될 때까지 1씩 감소시키며
  6. ;반대로 di는 2byte(1word) 증가시키며 ax의 값을 es:di 의 주소값에에 복사를 합니다.
  7. ;es의 b800 주소값은 Video ram이 시작되는 부분으로 여기의 값을 수정하면 화면을 제어할수 있습니다.
  8. ;es:0000부터 es:0fa0 까지 20과 07을 저장합니다.


명령어 응용

예제)

  1. lea si, arr1
  2. mov di, 160*10 + 2*30
  3. lp: lodsb
  4.    mov ah, 7
  5.    stosw
  6.    loop lp
  7.  
  8. ;arr1은 "hello" 라는 문자열이 저장되어있는 있음
  9. ;si에 arr1배열의 시작주소를 si에 넣고 160 *10 + 2*30 (화면의 정중앙)의 값을 di에 저장합니다.
  10. ;lodsb를 하면 ds:si 의 값을 al에 1byte 저장하고 ah에는 7을 저장합니다. 그리고
  11. ;stosw를 하면 문자열 hello문자열을 차례대로 가져와서 stosw를 통해 화면의 정중앙에 문자열을 출력해줍니다.
  12. ;이상하게 es:di 의 값이 stosw을 통해 의도적으로 바뀌지 않았는데 이는 화면이 수시로 바뀌는 특성 때문에 그런거 같습니다.
  13. ;또한 메모리 시작주소 b800h 영역은 프롬프트상에서 비디오 출력 메모리 공간임을 추측할수 있었습니다.

추가**

  1. mov ah, 9
  2. int 21h
  3. ; 이명령을 추가로 실행시켜주면 아래와 같은 문자열이 출력됨


* 관련 링크 참조

http://kaspyx.tistory.com/entry/16bit-Assembly-예제-정리-1

http://kaspyx.tistory.com/entry/16bit-Assembly-예제-정리-2

http://kaspyx.tistory.com/entry/16bit-Assembly-예제-정리-3