2010년 1월 25일 월요일

13장 - 어셈블리 초등 산수

13장 - 어셈블리 초등 산수

이번 장은 앞에서 배운 것들을 떠올려 아주 흔하게 일어날 수 있는 기초적인 산술 연산 (특히 대수, algebra)을 다룬다. 수학 공식을 코딩하고
싶을 때가 있으며, 알고리즘을 구현하거나 분석할 경우가 있기 마련이니, 여기서 다룰 내용은 기초적이면서도 귀중한 배경지식으로 작용할
유사 코드이다.

* 변수 선언

변수는 데이터를 할당 (assignment)하는 용도로 사용되며, "name type value"형식으로 선언한다. 이렇게 선언된 변수는 운영체제가
메모리를 할당하며, 원한다면 이 변수에 특정 값을 지정해줄 수 있다.

- 예,

  var db 30                               ; var 라는 바이트 변수를 선언하여 십진수 30으로 초기화했다.
  var dw ?                                ; var 라는 워드형 변수를 선언하여 초기화를 하지 않았다. var는 00 00이 된다.
  var dd 5 dup (0)                        ; var 라는 더블워드 원소가 5개인 배열의 각 원소를 0 으로 초기화한다.
  var db "Hello, World!", 0Dh, 0Ah, '$'   ; var 라는 문자 배열 (스트링)이 H ~ !, 0Dh, 0Ah, '$'가 낮은 주소(옵셋)부터 초기화된다.
 
* 할당된 값 로드

변수는 CPU에 로드되기 전까지는 단지 공간을 확보하는 용도에 불과하며, 연산을 위해서는 CPU 레지스터에 로드되어야 한다. 사용되지 않는 변수는
선언할 필요가 없다. 선언된 변수는 mov 명령으로 로드한다.

  var db 12h                  ; byte 변수가 하나 선언되었으며, 값이 12h로 초기화되었다.

  mov al, var                 ; byte 변수를 byte 레지스터로 로드한다. al = 12h
  mov bx, word ptr [var]      ; byte로 선언된 변수를 word 레지스터로 로드한다. 값이 다를 때는 type ptr 지시어를 써주고, []는 내용을
                              ; 의미하며, bl = 12h, bh = garbage를 가진다. 작은 레지스터에 큰 type의 메모리를 로드할 순 없다.
 
* 할당된 값 리셋

  var db 12h

  mov cl, 34h                         ; cl에 정해준 값 (34h)으로 var는 리셋되며, var = 34h가 된다.
  mov var, cl                         ; 이 값은 프로그램이 실행되는 동안 유지되며, 종료하고 재 실행하면 다시 12h로 리셋된다.
 

위에서 다룬 것들은 값 (value)을 할당하는 것이지만, 주소 (address)를 할당할 수 있다.

* A = address of mem

mov a, offset [mem]
= lea a, mem 

* 로드 - 갱신 - 저장 (load-op-save)

mov 명령은 "mem-to-mem" 연산을 허용치 않는다. 반면 movs 명령은 "mem-to-mem"연산이 가능하다. 그러므로 만약 mov로 어떤 메모리 값을 로드해서
갱신하여 새로 저장한다면, 갱신 따로 저장 따로 해줘야한다. 즉, 다른 값이 메모리에 복사되는 것이다.

  mov al, val
  mov mem, val                 ; mem = val 할당 (mem-to-mem)
 
하지만, mov 명령은 "imm-to-mem" 형식이 가능하므로 메모리 값에 상수를 직접할당할 수 있다.

  mov mem, imm                 ; mem = imm
 
* A = B + C                                     * A = B - C

  mov ax, B                     ; 로드            mov bx, B
  add ax, C                     ; 연산            sub bx, C
  mov A, ax                     ; 저장            mov A, bx
 
* A = B * C                                     * A = B / C

  mov ax, B               ; 로드                  mov ax, B
  xor dx, dx              ; 상위 소거             cwd
  mov bx, C               ; 로드                  mov bx, C
  mul/imul bx             ; 연산                  div/idiv bx
  mov [mem], dx           ; 상위 저장             mov [mem], ax           ; 몫 저장
  mov [mem+2], ax         ; 하위 저장             mov [mem+2], dx         ; 나머지 저장
 
* A = - A

  neg ax
  =
  not ax
  add ax, 1

* X op1 Y op2 형태: 이 연산을 하려면 우선 순위를 고려해 머릿속에 괄호를 그려두고 연산하면 된다. 

 
* A = A - B - C                                   * A = A - (B + C)

  mov ax, A                                         mov ax, B
  sub ax, B                                         add ax, C
  sub ax, C                                         sub A, ax
  mov A, ax
 
* A = A - (B - C) = A - B + C

  mov ax, B
  sub ax, C
  sub A, ax
 
* A = A + B * C

  mov bx, C
  mov ax, B
  mul/imul bx
  mov ax, A
  add ax, bx                      ; 하위 무시, 선 곱셈 후 덧셈
  mov [memA], ax

  또는,
 
  mov ax, B
  mul C
  add ax, A
  mov [memA], ax
 
* A = A / B - C                                    * A = A / B * C

  mov ax, X                                          mov ax, A
  cwd                                                cwd
  div/idiv B                                         mul/imul C
  sub ax, C                                          div/idiv C
  mov [memA], ax                                     mov [memA], ax
 
* A = 2N * 8 (mul대신 shl로)

  mov al, 5
  mov bl, al        ; 복사

  add al, al        ; N * 2
  mov cl, 3         ; N * 8
  shl bl, cl        ;
  add al, bl        ; 2N + 8N

* A = B * (3/4)

  mov al, 55
  mov bl, al        ; 복사

  mov cl, 2
  shr bl, cl        ; 1/4

  sub al, bl        ; 55 * (1 - 1/4)
 
 
* A = (B + C) * (D + E)

  mov ax, B
  add ax, C
  mov cx, ax         ; cx = B + C
 
  mov ax, D
  add ax, E          ; ax = D + E
  imul cx
  mov [memA], ax
 

* (x + y) / (x - y)


  mov al, x                   ; al = x
  mov bl, y                   ; bl = y

  mov cl, al                  ; cl = al = x, copy
  add al, bl                  ; al = x + y

  sub cl, bl                  ; cl = x - y

  mov ah, 0                   ; sign extension
  div al, cl                  ; al = (x + y) / (x - y)
 
* C = A logical B :

  mov ax, A
  and/or/xor ax, B
  mov C, ax
 
* B = (NOT A) and 1

  mov ax, A
  not ax
  and ax, 1
  mov B, ax


 * 2차 방정식 : ax ^ 2 + bx + c

수학에서 2차 방정식은 대입 값이 무제한이지만, 전산에서는 값을 제한해야하며 항상 오버플로를 감안해야하며, 어떤 항 (coeffient)이 제일 많이
쓰이는지를 고려하여 이를 활용한다. 위의 식에서는 x가 가장 많이 사용되고, 여기서는 오버플로, 상위워드는 무시하기로 한다.
a = 1, b = 2, c = 3, x = 4, y = ax^2 + bx + C

.model small
.stack 100h
.data
vara dw 1
varb dw 2
varc dw 3
varx dw 4
.code
main proc
  mov ax, @data
  mov ds, ax
 
  mov bx, varx
  mov ax, bx
  cwd
  mul bx            ; x ^ 2
  mov dx, vara      ; ignore hiword
  mul dx
  mov cx, ax        ; cx = partial product
 
  mov ax, varb
  mul bx
  add cx, ax        ; ax ^ 2 + bx
 
  mov ax, varc
  add cx, ax        ; ax ^ 2 + bx + c
 
 
exit:
  mov ax, 4C00h
  int 21h
main endp
end main

* max & min : mov - cmp - jmp 조합으로 쉽게 구할 수 있다.

.model small
.stack 100h
.data
vara dw 1
varb dw 2
varc dw 3
vard dw 4
.code
main proc
  mov ax, @data
  mov ds, ax
 
  mov ax, vara
  mov bx, varb
 
  cmp ax, bx                ; if (a > b)
  jbe L1
  jmp L2
 
L1:
  xchg ax, bx               ; ax = max
 
L2:

  mov cx, varc
  mov dx, vard
 
  cmp cx, dx                ; if (a < b)
  jae L3
  jmp L4
 
L3:
  xchg cx, dx               ; cx = min
 
L4:
 
 
exit:
  mov ax, 4C00h
  int 21h
main endp
end main

이는 분기 타겟 버퍼 (BTB)를 활성화하므로 다음처럼 분기 처리를 하지 않고 강제로 세팅해줄 수 있다. (source from : assembly gems)

;Summary:       eax = min (eax, ecx) (both eax and ecx unsigned)
;Compatibility: 386+
;Notes:     8 bytes, 4 clocks (P5), destroys ecx and edx
    sub    ecx, eax    ; ecx = n2 - n1
    sbb    edx, edx    ; edx = (n1 > n2) ? -1 : 0
    and    ecx, edx    ; ecx = (n1 > n2) ? (n2 - n1) : 0
    add    eax, ecx    ; eax += (n1 > n2) ? (n2 - n1) : 0
; Standard cmp/jbe/mov takes 2-8 clocks on P5 and 1-17 on P6

;Summary:       eax = max (eax, ecx) (both eax and ecx unsigned)
;Compatibility: 386+
;Notes:     9 bytes, 5 clocks (P5), destroys ecx and edx
    sub    ecx, eax    ; ecx = n2 - n1
    cmc            ; cf = n1 <= n2
    sbb    edx, edx    ; edx = (n1 > n2) ? 0 : -1
    and    ecx, edx    ; ecx = (n1 > n2) ? 0 : (n2 - n1)
    add    eax, ecx    ; eax += (n1 > n2) ? 0 : (n2 - n1)
; Standard cmp/jae/mov takes 2-8 clocks on P5 and 1-17 on P6

* 평균 구하기: (A + B) / 2


  mov ax, a           ; unsigned average            mov ax, a             ; signed average
  mov bx, b                                         mov bx, b
 
  add ax, bx                                        xor ax, bx
  rcr ax, 1                                         sar ax, 1
                                                    and ax, bx
                                                    add ax, bx



.model small
.stack 100h
.data
vara dw 1
varb dw 2
varc dw 3
vard dw 4
.code
main proc
  mov ax, @data
  mov ds, ax
 
  mov ax, vara
  mov bx, varb
 
  sub bx, ax              ; min
  sbb dx, dx
  and bx, dx
  add ax, bx
 
  mov ax, varc
  mov bx, vard
 
  sub bx, ax               ; max
  cmc
  sbb dx, dx
  and bx, dx
  add ax, bx
 
  mov ax, vara
  mov bx, varb
  add ax, bx                ; unsigned average
  rcr ax, 1
 
  mov ax, varc
  mov bx, vard
 
  xor ax, bx                ; signed average
  sar ax, 1
  and ax, bx
  add ax, bx
 
exit:
  mov ax, 4C00h
  int 21h
main endp
end main

댓글 없음:

댓글 쓰기

블로그 보관함