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 명령어는 한 메모리에서 다른 메모리 위치로 데이터를 직접 이동하는데 사용 할 수 없다.
- 대신, 메모리 피연산자에 값을 할당하기 전에 소스 피연산자의 값을 레지스터로 이동해야 한다.
.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비트로 확장한다.
- 이 명령은 부호없는 정수에만 사용된다.
- 첫번째 피연산자(레지스터)는 대상이고, 두번째 피연산자는 소스이다.
- 소스 피연산자는 상수일 수 없다.
.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바이트 인데 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 variablelahf 명령어는 operand를 필요로 하지 않는다.
4 - 2 레지스터에서 다시 status flag로 옮겨주는 명령어 SAHF
SAHF(상태 플레그에 AH 저장)
- 다시 예시
mov ah,saveflags ;load saved flags into AH
sahf ;copy into Flags register5. XCHG 명령 (exchange data)

- 두 피연산자의 내용을 교환한다.
- 뒤에 리터럴(immediate operands )을 혀용하지 않는것을 제외하면 mov명령어와 규칙은 동일하다.
- 상수는 메모리상에 저장공간에 있는것이 아니므로
- 메모리 교환 예시 (val1 과 val2 위치 교환)
mov ax, val1
xchg ax, val2
mov val1, ax6. 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 = 200hdouble word의 경우
.data
arrayD DWORD 10000h,20000h
.code
mov eax, arrayD ;EAX = 10000h
mov eax,[arrayD+4] ;EAX = 20000hUploaded by N2T
728x90
'CSE > system programing' 카테고리의 다른 글
| [시스템 프로그래밍 6-2] 어셈블리어 데이터 관련 연산자와 간접 주소방식 (1) | 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 |





