jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 3.5 산술 및 논리 연산
    1. 3.5.1 유효 주소 적재
      1. 요점
    2. 3.5.2 단항 및 이항 연산
      1. 요점
    3. 3.5.3 시프트 연산
      1. 요점
    4. 3.5.4 토의
      1. 요점
    5. 3.5.5 특수 산술 연산
      1. 요점

csapp


겨우 하루? 안했는데 간만인 기분이다


할게 졸라게 많으니 가능한 간략하게 중요한 포인트만 기록하겠다



3.5 산술 및 논리 연산

연산들은 보통 명령어 $Class$인데 그 이유는 명령아가 피연산자에 따라 여러가지 변형을 가질 수 있기 때문이다

근데 leaq 명령어는 그런거 없다 한다

예시)

  • add 명령어 $class$의 경우

    • addb : 바이트(byte) 연산

    • addw : 워드(word, 2바이트) 연산

    • addl : 더블워드(double word, 4바이트) 연산

    • addq : 쿼드워드(quad word, 8바이트) 연산

등 이렇게 가질 수 있다

보통 이렇게 네 가지 크기의 데이터에 대해 명령어를 갖는다 한다

나눠진 네그룹

  1. 유효 주소 계산(load effective address)

  2. 단항 연산(unary)

  3. 이항 연산(binary)

  4. 시프트 연산(shifts)

  • 이항 연산은 두 개의 피연산자를 가지며,
    덧셉, 곱셈 등

  • 단항 연산은 한 개의 피연산자를 가진다
    $|n| = \pm n$ 과 같이 절댓값 등



그리고 여기서 다룰 정수 산술 연산 명령어들에 대한

표를 여기에 넣어놓겠다

명령어 효과 설명  
leaq S, D $D ← \&S$ 유효 주소 적재(load effective address)  
inc D $D ← D + 1$ 증가(increment)  
dec D $D ← D − 1$ 감소(decrement)  
neg D $D ← -D$ 부호 반전(negate)  
not D $D ← ~D$ 비트 반전(complement)  
add S, D $D ← D + S$ 덧셈(add)  
sub S, D $D ← D − S$ 뺄셈(subtract)  
imul S, D $D ← D × S$ 곱셈(multiply)  
xor S, D $D ← D ^ S$ 배타적 논리합(Exclusive-or, XOR)  
or S, D $D ← D | S$ 논리합(OR)  
and S, D $D ← D \& S$ 논리곱(AND)  
sal k, D $D ← D « k$ 왼쪽 시프트(left shift, sal과 shl은 동일)  
shl k, D $D ← D « k$ 왼쪽 시프트(left shift)  
sar k, D $D ← D »A k$ 산술적 오른쪽 시프트(arithmetic right shift)  
shr k, D $D ← D »L k$ 논리적 오른쪽 시프트(logical right shift)  



3.5.1 유효 주소 적재

leaq명령어가 왜 변형없는지 알려준다

이유는 메모리의 값을 참조하는게 아닌

단순히 그 주소만 갖고 오기 떄문이다

movq와 비교하자면

  • movq는 메모리 주소에 있는 값을 레지스터에 가져온다

  • leaq는 메모리 주소 계산식의 결과(즉, 주소 자체) 만 레지스터에 넣어준다
    (실제로 그 주소의 값에는 접근하지 않음)



요점

메모리 참조 형식의 주소 계산식 결과만을 레지스터에 저장하는 leaq 명령어는 포인터 연산, 배열 인덱스 산술 등 복잡한 주소 산술을 효율적으로 수행한다



3.5.2 단항 및 이항 연산

단항연산의 예시와 이항연산 알려준다

incq (%rsp)

이 경우 단항 연산으로 값을 1만큼 증가시킨다


이항 연산은
두 번째 피연산자가 소스이자 목적지 역할이다

x -= y랑 비슷하단다 (C에서)

단, 중요한건 첫번째 오는게 소스, 두번째가 목적지다

subq %rax, %rdx

위의 경우 %rdx 레지스터 값을 %rax만큼 감소시킨다는 뜻이다

주의할 점은 둘다 메모리나 레지스터 위치가 될 수 있지만

둘 다 메모리 위치이면 안된다는거다

그리고 두번째가 메모리 위치일 경우엔 저장 위치가 바뀐 것이기에
메모리 읽기 뿐 아니라 메모리 쓰기까지 작동해서
속도와 비용측면에서 차이가 발생한다



요점

단항 연산(unary)은 하나의 피연산자에, 이항 연산(binary)은 두 번째 피연산자에 결과를 저장하며, 이 순서와 ATT 어셈블리의 피연산자 순서를 주의해야 한다



3.5.3 시프트 연산

처음은 시프트 양 그다음 시프트할 값이 지정된다

시프트 연산이 뭔지는 알테니 스킵하겠다

연산뒤에 붙는 단위에 따라 시프트 단위도 바뀐다


salshl은 ㄹㅇ 똑같다

sarshr하고 라임 맞추려고 2개인거 뿐임

sal shl모두 오른쪽에서 0으로만 채운다

그치만 sar shr은 다르다

  • sar산술적 시프트 (부호 비트 복사로 채움)

    • Shift Arithmetic Right의 약자
  • shr논리적 시프트 (0으로 채움)

    • Shift Right의 약자
      (Logical Shift Right을 걍 관례적으로 Shift Right으로 부른다고 한다)

로 차이점이 존재한다



요점

왼쪽/오른쪽 시프트 연산은 즉시값이나 %cl 레지스터로 시프트 양을 지정하며, 산술/논리적 오른쪽 시프트는 부호 비트 처리에서 차이가 있다. salshl은 동작이 완전히 같다



3.5.4 토의

부호 없는 산술 연산이나 2의 보수 산술 연산이나 대부분 걍 쓰면 된다

shr, sar과 같은 오른쪽 시프트 연산자만 조심해주면 되는데

2의 보수 방식이기에 이도 큰 차이 없이 연산 가능하다

이것이 2의 보수방식이 선호되는 이유다

2의 보수 방식이 뭔지 모른다면 아래로

🔽🔽🔽🔽🔽

2의 보수 방식



요점

대부분의 산술·논리 명령은 부호/무부호 구분 없이 동작하며, 오른쪽 시프트만 부호에 따라 명령이 달라지고, 컴파일러는 여러 연산을 위해 레지스터 재활용 및 값을 이동시킨다



3.5.5 특수 산술 연산

128비트 곱셈·나눗셈은 한 번에 처리할 수 없기 때문에,
x86-64에서는 %rdx:%rax 레지스터 쌍을 하나의 128비트 값처럼 취급해서 연산을 수행한다

  • imulq, mulq : %rax와 소스(레지스터/메모리/즉시값)의 곱을 계산해서

    • 결과 하위 64비트는 %rax,

    • 상위 64비트는 %rdx에 저장한다.

  • idivq, divq : 128비트 피제수(%rdx:%rax)를 소스(레지스터/메모리/즉시값)로 나눔

    • 몫은 %rax,

    • 나머지는 %rdx에 저장

  • cqto : %rax의 부호 비트를 %rdx로 확장해서,

    • 64비트 값을 128비트 값(나눗셈 준비용)으로 만든다.


이 방식 덕분에 64비트 CPU에서도
128비트 곱셈·나눗셈(부호/무부호 모두)을 기본 명령으로 안전하게 처리할 수 있다.



요점

128비트 곱셈/나눗셈은 %rdx:%rax 쌍으로 고정 처리하며, 곱셈은 mulq/imulq, 나눗셈은 divq/idivq, 부호 확장은 cqto로 준비한다
(부호/무부호 연산 모두 지원됨)