movq Source, Dest;
(q 가 붙는건 64 bit라서~)
피연산자 유형을 살펴보자 ❓🫡
immediate: 상수
register : 16개 정수 레지스터 중 하나이다.
ex. %rax, %r13,..
%rsp 는 특별한 용도로 예약되어 있다 (Stack pointer)
다른 레지스터도 특정 명령에 대해 특수한 용도로 사용될 수 있다
memory : 레지스터가 가리키는 주소에 있는 8개의 연속된 바이트 메모리
movq Operand Combinations 😎
movq
| source | dest | src,dest | C analog |
|---|---|---|---|
| imm | reg | movq $0x4,%rax | temp = 0x4; |
| mem | movq $-147, (%rax) | *p = -147; | |
| reg | reg | movq %rax,%rdx | temp2 = temp1; |
| mem | movq %rax,(%rdx) | *p = temp; | |
| mem | reg | movq (%rax),%rdx | remp=*p; |
소스가 상수인 경우, register인 경우 , 메모리인 경우로 나눠서 알아보자.
+) 상수는 공간이 아니라서 dest 는 불가해 ^^
+) Src 일 때와 Dest 일 때 역할이 달라.
src : 레지스터/메모리에 저장된 값
dst : 레지스터/메모리 공간
=> 공간에 값을 넣는다 이말이야. 🤗
몇 개 해석을 해보자면(위에서부터)
❤️movq $0x4,%rax : 상수 0x4를 레지스터 %rax 에 저장한다
❤️movq $-147, (%rax) : 상수 -147을 메모리주소 (%rax)에 저장한다.
=> _%rax가 가리키는 메모리 주소_에 값-147 이 저장되는거임
❤️movq %rax,%rdx : 레지스터 %rax 에 있는 값을? 레지스터 %rdx 로 복사한다
그니까 %rdx 레지스터에는 %rax 레지스터에 있는 값이 복사된다 이말임.
❤️movq %rax,(%rdx) :
레지스터 %rax 에 있는 값을 레지스터 %rdx 가 가리키는 메모리 주소에 저장하는 역할.
긍까 _%rdx 레지스터가 가리키는 메모리 주소_에?
%rax 레지스터에 있는 값이 저장되는거임
❤️movq (%rax),%rdx : 레지스터 %rax 가 가리키는 메모리 주소에 있는 값을 ?
레지스터 %rdx 에 복사하는 역할.
긍까 %rax 가 가리키는 메모리 주소에 있는 값이 %rdx 레지스터에 복사된다
이말임.
(괄호안은 위에서 말했듯이 그 주소 내의 값..인디
긍까 그 주소 내의 값을 ~ 이라고 되는거임)
***** 하나의 명령어로 레지스터-레지스터 전송은 가능하나
메모리-메모리 연산은 불가해요
일반적.
❤️(R) Mem[Reg[R]]
일반적인 R은 메모리의 레지스터 R에 저장된 값을 가리키는 포인터를 나타낸다.
이것은 메모리의 주소가 레지스터 R의 값에 의해 결정된다는 것을 의미한다
movq (%rcx), %rax
레지스터 R 은 메모리 주소를 지정하는 것으로 ,
C 에서는 포인터역참조와 유사하다.
movq (%rcx), %rax는 %rcx 레지스터의 내용이 가리키는 메모리 위치에 있는 값을 %rax 레지스터로 로드한다
int *ptr;
int num1 = 10;
ptr = &num1;
printf("%d\n", *ptr);
// 역참조 연산자로 num1의 메모리 주소에 접근하여값을 가져옴
C 로 비교하자면 얘 🙄랑 비슷하다고 생각하면 돼요
❤️이동 D(R) Mem[Reg[R]+D]
이동(D) 은 메모리의 레지스터 R 에 저장된 값에 오프셋을 더하는 것을 나타낸다.
이것은 메모리 주소가 레지스터 R 의 값에 오프셋 D 를 더하여 결정된다는 것을 의미한다
movq 8(%rbp),%rdx
레지스터 R 은 메모리 영역의 시작을 지정하고,
상수 이동값 D는 offset 을 지정한다.
movq 8(%rbp), %rdx 는
%rbp 레지스터에서 8 바이트 offset 에 위치한 메모리 위치값을
%rdx 레지스터에 로드한다.
그니까
8(%rbp) ==>걍 base address 인 %rbp메모리 주소에서 8 떨어진 애를 지칭
❤️일반적인 형태
D(Rb,Ri,S) Mem[Reg[Rb]+S*Reg[Ri]+D]
D: displacement로, 상수. 1,2,4 byte 와 같은 값으로 메모리 위치 조절
Rb : base register : 16개 정수 레지스터 중 하나 사용 가능
Ri: index register: %rsp 를 제외한 어느 레지스터든 가능함요
S: scale, 주소 계산에 사용되는 정수. 1,2,4,8 과 같은 2의 거듭제곱 값을 가진다(이 값들은 비트 시프트에 사용되기 때문~)
❤️특수한 경우
(Rb,Ri) Mem[Reg{Rb]+Reg{Ri]]
: 이 경우에는 Ri의 값이 스케일링되지 않고, Rb와 Ri 레지스터 값의 합으로 메모리 주소가 결정된다
D(Rb,Ri) Mem[Reg[Rb]+Reg[Ri]+D]
: 이 경우에는 상수 D가 Ri의 값과 함께 사용되며, Rb와 Ri 레지스터 값의 합에 D가 더해져 메모리 주소가 결정된다
(Rb,Ri,S) Mem[Reg[Rb]+S*Reg[Ri]]
: 이 경우에는 스케일링된 Ri의 값이 Rb와 함께 사용되며, 스케일링된 값과 Rb 레지스터 값의 합으로 메모리 주소가 결정된다
조금 더 세세하게 알아봅세다
🍎movq(%rbx,%rcx), %rax
:(rbx + rcx) == 메모리주소겠져?
그 메모리 주소 안의 값을
%rax에 옮기세요 !
🍎movq 16(%rbx, %rcx), %rax
: (rbx+rcx) + 16 에 저장된 값!! 을
rax에 저장하세요 !
🍎movq (%rbx,%rcx,8), %rax
: rbx + 8xrcx 에 저장된 값 !! 을
rax 에 저장하세요 !!
cf) movq (%rbx,%rcx,1) == (%rbx,%rcx)
1 곱하나마나니깐 ~~
leaq Src,Dst(load effective address quadword)
-- 주소 읽어오기! 가 목적입니다요.
src 는 주소 모드 표현식이고, 이 표현식이 나타내는 주소를 dst 에 설정한다.
이런 상황에서 쓴다 !
메모리 참조 없이 주소를 계산할 때.
ex. p = &x[i]; 와 같이 배열 인덱싱 연산 번역시..
형식이 x+k*y 인 산술식을 계산할 때 ( 여기서 k 는 1,2,4,or 8)
(lea ... 주소 읽어오기가 목적이었으나 산술연산에도 활용됩니당 )
two operand instructions:
🤍addq src,dest
🤍subq ..
🤍imulq(int multiply 정수곱이라는뜻)
🤍salq(shift arithmetic left quadword) dest = dest << src
🤍sarq dest = dest >>src
🤍shrq(shift right) cf) shl은 ...? left 은 왜 없성. ->left 는 msb 채우는거 딱히 의미없어서요
dest = dest >> src
이거 다 shift 연산인디 차이 그거야 arithimatic 인지 logical
( 0 걍 채우는거랑 msb 채우는거 있었자넝 .)
🤍xorq dest = dest ^ src
🤍andq dest = dest& src
🤍orq dest = dest|src
cf)인수의 순서 주의하기.
cf)imulq 제외하고는 부호 있는 정수와 부호 없는 정수에 차이가 없음요 .
왜냐구 ??
동일한 명령어가 부호 있는 정수와 부호 없는 정수 모두에 대해 산술을 수행할 수 있으니깐 ..~
결과의 해석은 연산이 수행되는 맥락에 따라 달라짐.
🤍incq dest 💙dest = dest+1
🤍decq dest 💙dest = dest-1
🤍negq dest 💙dest = -dest
🤍notq dest 💙dest = ~dest
연습을 한번 해보자 ㅇㅋ ?
long arith
(long x, long y, long z)
{
long t1 = x+y;
long t2 = z+ t1;
long t3 = x+ 4;
long t4 = y * 48;
long t5 = t3 + t4;
long rval = t2* t5;
return rval;
}
arith:
leaq (%rdi,%rsi), %rax #t1
addq %rdx,%rax #t2
leaq (%rse,%rsi,2), %rdx
salq $4, %rdx #t4
leaq 4(%rdi,%rdx), %rcx #t5
imulq %rcx, %rax #rval
ret
| register | use(s) |
|---|---|
| %rdi | argument x |
| %rsi | argument y |
| %rdx | argument z |
| %rax | t1,t2,rval |
| %rdx | t4 |
| %rcx | t5 |
연산과정해설
leaq (%rdi,%rsi), %rax:
레지스터 %rdi에 있는 값(x)과
%rsi에 있는 값(y)을 더한 결과를 %rax 레지스터에 로드합니다.
이 값은 t1에 해당합니다.
addq %rdx, %rax: 레지스터 %rdx에 있는 값(z)를 t1에 더한 결과를 %rax 레지스터에 저장합니다. 이 값은 t2에 해당합니다.
leaq (%rse,%rsi,2), %rdx: %rsi의 값을 2배한 후 %rse에 있는 값(z)과 더한 결과를 %rdx 레지스터에 로드합니다. 이 값은 t3에 해당합니다.
salq $4, %rdx: %rdx 레지스터에 있는 값에 4를 왼쪽 시프트(shift)하여 48을 얻습니다. 이 값은 t4에 해당합니다.
leaq 4(%rdi,%rdx), %rcx: %rdi에 있는 값(x)와 %rdx에 있는 값(t4)을 더한 후 4를 더한 결과를 %rcx 레지스터에 로드합니다. 이 값은 t5에 해당합니다.
imulq %rcx, %rax: t2와 t5를 곱한 결과를 %rax 레지스터에 저장합니다. 이 값은 rval에 해당합니다.
ret: 함수에서 반환합니다.