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
댓글 없음:
댓글 쓰기