728x90
데이터 Transfer Instruction (데이터 전송 지침)
소개
- 예를 들어 메모리에서 레지스터로 옮기는 예시
- 고수준 언어에서는 컴파일러가 엄격한 데이터 타입 검사를 수행한다.
- 변수 및 데이터 불일치와 같은 오류를 방지하는 데 도움이 된다.
- 사실 기계 (CPU의 관점) 에서는 데이터의 타입은 의미가 없다.(다 같은 2진수이기 때문에)
- 따라서 CPU 관점에서는 타입은 생각하지 않고 size만이 중요하다.
- 반면 어셈블러를 사용하면 프로세서 명령어 집합이 요청하는 작업을 수행할 수 있는 한 원하는 모든 작업을 수행 할 수 있다. ( 예 : float 형에 int 형으로 연산을 할 수도 있다. - 가능하지만 엉뚱한 결과가 발생)
- 어셈블리 언어는 데이터 저장 및 머신별 세부 사항에 주의를 기울여야 한다.(프로그래머의 역활)
피연산자 유형(Operand Types)
X86 명령어 형식
[label :] mnemonic [operands] [;commnet]
[래이블] 명령어(연산자) [피연산자] [주석]
- 피연산자는 여러개 나올 수 있다.
- 대체로 첫번째로 나오는 피연산자가
destination
이 나온다. (값이 업데이트 될 녀석)
피연산자에서는 3가지 기본 유형이 있다.
- Immediate : 상수로 취급되는 표현
- Register : CPU에 명명된 레지스터 사용
- Memory : 메모리 위치를 참조한다.
명령 피연산자 표기법(Notation)
1. Direct Memory Operands (변수)
변수 이름은 데이터 세그먼트 내의 오프셋에 대한 참조이다.
예시
.data
var1 BYTE 10h
mov al var1
복습 : eax 를 반으로 자르면 AX, AX를 반으로 자르면 AH, AL로 나뉜다.
- var1의 크기속성은 바이트이며 10진수 값을 포함한다.
- 마지막 명령은 해당 값을 AL레지스터에 복사합니다.
- 예를들어 var1이 오프셋 10400h에 위치한다고 가정합니다.
- 그러면 마지막 명령어가 다음 기계 명령어로 조립된다.
mov al var1
⇒A0 00010400 이 된다.(10400은 주소값)
(주소는 4바이트) (여기서 A랑 al은 연관있는 건아니다.)
- 첫번째 바이트 : 연산코드 (opcode)
- 나머지부분 : var1의 32비트 16진수 주소
- 선택적으로 직접 피연산자와 함께 괄호를 사용할 수 있습니다.
mov al,[var1]
(이것과 mov al var1 과 같은 의미) (조금 더 명시적으로 val1에 가서 가져오라는 것을 명시하는 것.
2. mov명령어
- 소스에 있는 피연산자를 destination 피연산자로 복사한다.
- 기본 형식 :
MOV destination,source
- 대상 피연산자(
destination
)의 내용은 변경되지만, 소스 피연산자(source
)는 변경되지 않는다.
- 데이터의 오른쪽에서 오니쪽 이동은 C++ 또는 Java의 할당문과 유사하다. (A=B 같이..!)
- 대상 피연산자(
- MOV는 다음 규칙을 준수하는 한 피연산자(operand)를 매우 유연하게 사용 할 수 있다.
- 두 피연산자(operand)의 크기는 모두 같아야 한다.
- 두 피연산자 모두 메모리 피연산자가 될 수 없다. (메모리에 직접 접근할 수 없는 특징을 생각 중간에 레지스터를 거쳐가야 함)
- 명령 포인터 레지스터(IP, EIP, RIP)는 대상(destination operand) 피연산자 가 될 수 없다.
- 명령 포인터는 cpu 가 fetch 해와야 할 다음 주소를 가지게 되는 포인터이기 때문.
- 표준 MOV 명령어 형식
메모리에서 메모리로 불가
- 계속 말했듯 중요한 성질 : 단일 MOV 명령어는 한 메모리에서 다른 메모리 위치로 데이터를 직접 이동하는데 사용 할 수 없다.
- 대신, 메모리 피연산자에 값을 할당하기 전에 소스 피연산자의 값을 레지스터로 이동해야 한다.
.data
var1 WORD ?
Var2 WORD ?
.code
mov ax,varl ; 만약 여기다가 eax를 넣으면 4바이트에 2바이트인 WORD를 넣으려 해서 안된다.
mov var2,ax
서로 다른 사이즈를 카피하는 방법 Overlapping values
.data
oneByte BYTE 78h
oneWord WORD 1234h
oneDword DWORD 12345678h
.code
mov eax, 0 ; EAX = 00000000h
mov a1,oneByte ; EAX = 00000078h
mov ax,oneWord ; EAX = 00001234h
mov eax, oneDword ; EAX = 12345678h
mov ax, 0 ; EAX = 12340000h
- 다음 코드 예제는 다른 크기의 데이터를 사용하여 동일한 32비트 레지스터를 수정하는 방법을 보여준다.
- oneWord 가 AX로 이동하면 기존의 AL 값을 덮어씁니다.
- oneDword 가 eax로 이동하면 AX를 덮어쓴다.
- 마지막으로 0을 AX로 이동하면 EAX의 아래쪽 절반을 덮어쓴다.
3. Zero/sign Extension of Integers
만약 2바이트 -16을 4바이트 -16으로 바꾸고 싶은 경우
즉 작은 크기를 더 큰 크기로 복사하고 싶은 경우
- mov는 작은 데이터에서 큰 데이터로 직접 복사할 수 없다.
- 카운트(부호없음, 16비트)를 ECX(32비트)로 이동해야 한다고 가정합니다.
- ECX를 0으로 설정하고 카운트를 CX로 이동할 수 있다.
- 다만 부호있는 정수에 같은 방식을 사용하면 어떻게 해야할까?
- 따라서 시작할 때 채우는 값을 전부다 1로 채워야만한다.
F앞에 0 있는 이유 (16진수 시작이 알파벳이라면 0으로 시작해야 된다.)
- 기호확장
- 소스 피연산자(1)의 최상위 비트를 사용하여 대상 피연산자의 상위 16비트를 채우려면 ECX를 사용한다.
- 다행히도 인텔은 부호없는 정수와 부호있는 정수 모두 처리할 수 있는 MOVZX 와 MOVSX 명령어를 제공한다.
3 -1 MOVZX (move with zero-extend)
- 소스 피연산자의 내용을 대상 피연산자로 복사하고 값을 16비트 또는 32비트로 확장한다.
- 이 명령은 부호없는 정수에만 사용된다.
- 3가지 변형이 존재한다.
- 첫번째 피연산자(레지스터)는 대상이고, 두번째 피연산자는 소스이다.
- 소스 피연산자는 상수일 수 없다.
.data
byteVal BYTE 1000111b
.code
movzx ax,byteVal ;AX = 0000000010001111
- 이 명령어는 부호없는 정수라고 생각하고 연산을 진행한다.
- 사용 예시 : 16비트를 32비트, 8비트를 32비트로, 8비트를 16비트로 변경 가능
- 메모리에 있는 녀석을 사용하는 것 역시 가능하다.
3- 2 MOVSX Instruction (move with sign-extend)
- 앞에서 본 것과 같은데 0또는 1로 채워주는 역활을 한다.
- 왜 또는이냐면 음수일 수도 있고 양수일수도 있기 때문에 그것을 확인하고 처리한다.(MSB를 보고 확인)
- 이 연산은 부호있는 정수에만 사용이 된다.
4. LAHF와 SAHF 명령어
4 - 1레지스터로 flag 비트를 옮겨주는 명령어 LAHF
- LAHF (L은 load 의 약자, ah는 레지스터, F는 status flag를 의미한다.)
(status flag를 AH레지스터로 로드시킨다는 의미.)
- AH는 1바이트짜리 레지스터이다.
- AH는 1바이트 인데 flag레지스터는 32비트 즉 4바이트였다.
- 이것이 가능한 이유는 EFLAGS레지스터를 32비트 통째로 복사하는게 아니라 가장 하위에 있는 하나의 바이트만 복사를 하기 때문에 가능한 것이다.
- 가장 빈번하게 사용되는 녀석이 하위 1바이트에 몰려있기 떄문이다.
- 하위 1바이트(8bit) : Sign, Zero, Auxiliary Carry, Parity, and Carry 이다. (8개중 5개만 사용을 하고 나머지 3개는 보관되어 있다.)
- 예시
.data
saveflags BYTE ?
.code
lahf ;load flags into AH
mov saveflags,ah ;save them in a variable
lahf 명령어는 operand를 필요로 하지 않는다.
4 - 2 레지스터에서 다시 status flag로 옮겨주는 명령어 SAHF
SAHF(상태 플레그에 AH 저장)
- 다시 예시
mov ah,saveflags ;load saved flags into AH
sahf ;copy into Flags register
5. XCHG 명령 (exchange data)
- 두 피연산자의 내용을 교환한다.
- 뒤에 리터럴(immediate operands )을 혀용하지 않는것을 제외하면 mov명령어와 규칙은 동일하다.
- 상수는 메모리상에 저장공간에 있는것이 아니므로
- 역시나 mov명령어와 마친가지로 memory 에서 memory로 이동을 허용하지 않는다.
- 메모리 교환 예시 (val1 과 val2 위치 교환)
mov ax, val1
xchg ax, val2
mov val1, ax
6. Direct-Offset Operands
- 변수의 이름에 변위(displacement)를 더해주는 역활을 한다.
- 이를 통해 명시적인 레이블이 없을 수 있는 메모리 위치에 엑세스 할 수 있다.
- 레이블이 있다는 것은 변수라는 의미이다. 없다는건 배열의 다음 위치 등을 의미한다.
- 따라서 모든 어셈블리 언어에서는 모든 메모리 위치에 label이 존재할 필요는 없다.
mov a1,[arrayB+1]
;이런식으로 사용하는 것이 Direct-Offset Operand 이고
;여기서 +1 이 displacement이다.
mov a1,[arrayB+2]
offset + displacement = effective address 라고 부른다.
- 유효 주소를[]로 묶으면 해당 주소의 메모리 내용을 얻기 위해 표현식이 역 참조 되었음을 명확하게 알 수가 있다.
- 괄호는 MASM에서 필수는 아니지만 명확성을 위해 사용하는 것을 적극 권장합니다.
- MASM에서 유효주소에 대한 범위 확인기능이 내장되어있지 않다. (범위를 넘어갈 수도 있음)
- 이러면 메모리 참조 런타임 중 버그가 발생한다.(MASM이 이 에러를 찾아주지 않는다.)
6 -1 단어(WORD) 및 이중 단어(DoubleWord) 배열의 경우
- 이런경우는 +1 이런식으로 작동할 수가 없다.
- 16비트 단어배열에서 각 배열 요소의 오프셋은 이전 요소보다 2바이트 더 크다.
.data
arrayW WORD 100h, 200h, 300h
.code
mov ax, arrayW. ;AX = 100h
mov ax,[arrayW+2] ;AX = 200h
double word의 경우
.data
arrayD DWORD 10000h,20000h
.code
mov eax, arrayD ;EAX = 10000h
mov eax,[arrayD+4] ;EAX = 20000h
Uploaded by N2T
728x90
'CSE > system programing' 카테고리의 다른 글
[시스템 프로그래밍 6-2] 어셈블리어 데이터 관련 연산자와 간접 주소방식 (0) | 2023.04.06 |
---|---|
[시스템 프로그래밍 6 -1] 어셈블리어 더하기 빼기 연산과 그에 따른 flag 세팅 (0) | 2023.04.06 |
[시스템 프로그래밍 5-2] 어셈블리어 기호상수 Symbolic Constants (0) | 2023.03.30 |
[시스템 프로그래밍 5-1] 어셈블리 기본 데이터 타입 (0) | 2023.03.30 |
[시스템 프로그래밍 4강] 어셈블리 언어 문법 및 구성요소 (0) | 2023.03.30 |