CSAPP 독서 내용 정리 3-5 ~ 3-6

이형준·2023년 5월 2일
0

CSAPP

목록 보기
4/10

산술연산과 논리연산 ➕➖

어제 정보에 접근하고, 간단한 데이터 이동 인스트럭션에 대해 알아봤으니, 이젠 한걸음 더 나아갈 차례다. 다양한 연산이 어떤 형태를 띄고 있는지, 어떠한 인스트럭션들이 있는지 자세히 알아보자.

유효주소 적재(Load Effective Address)

유효주소 적재 leaq는 movq 인스트럭션의 변형이며, 일반적으로 간단한 산술연산을 위해서 사용한다. leaq는 메모리에서 레지스터로 읽어들이는 인스트럭션의 형태를 갖지만, 메모리를 전혀 참조하지 않는다. 책에 이렇게 적혀있는데, movq와 정확히 어떻게 다른지 헷갈려서 추가적인 공부를 했다.

mov와 lea 두 인스트럭션 모두 데이터를 이동하거나 로드하는 목적으로 사용되는 인스트럭션이지만, 그 목적과 동작 방식에서 차이가 있다. mov 인스트럭션은 메모리나 레지스터에서 값을 가져와서 다른 레지스터나 메모리에 복사해 주는 작업을 수행하는 반면, lea 인스트럭션은 주소 연산을 수행하여 계산된 메모리 주소를 다른 레지스터나 메모리에 복사해주는 작업을 수행한다. 따라서, mov 인스트럭션은 값을 가져오고 복사하는 역할에 특화되어 있고, lea 인스트럭션은 주소 연산에 특화되어 있다.

단항 및 이항 연산

단항 연산은 사진의 두 번째 그룹이다. inc, dec, neg, not 연산은 하나의 오퍼랜드가 소스와 목적지로 동시에 사용되는 단항 연산으로, 예를 들면 incq(%rsp)는 스택 탑의 8바이트 원소의 값을 증가시켜 준다.(이러한 문법들은 C의 ++, --을 연상하면 쉬울듯)

세 번째 그룹은 이항 연산자를로 구성되어 있다. 중요 포인트는 두 번째 오퍼랜드가 소스이면서 목적지로 사용된다는 것❗ C에서의 할당 연산자 x-=y 문법과 유사하다. 예를 들면,

subq %rax, %rdx

는 레지스터 %rdx에서 %rax를 뺀 값을 다시 %rdx에 할당한다. 두 번째 오퍼랜드가 소스이면서 목적지로 사용된다는 의미를 알수 있겠지? 이항 연산 인스트럭션에서는 첫 번째 오퍼랜드는 상수나 레지스터, 메모리 위치가 올 수 있다. 이건 당연하고, 두 번째는 레지스터나 메모리가 올 수 있다. 이 역시도 당연하지, 두 번째 오퍼랜드는 목적지의 역할도 해야 하므로.

쉬프트 연산

마지막 그룹은 쉬프트 연산으로 구성된다. 쉬프트하는 크기를 먼저 주고, 쉬프트할 값을 두 번째로 준다. 주목 할 점은 SAR과 SHR의 차이점이다.

  • 연산 방식
    SAR: 부호비트를 유지한 채로 오른쪽으로 비트 이동시키며, 비어 생긴 비트는 부호비트와 같은 값으로 채웁니다.
    SHR: 부호비트와 상관없이 오른쪽으로 비트 이동시키며, 비어 생긴 비트는 항상 0으로 채웁니다.
  • 응용 분야
    SAR: 부호가 있는 2의 보수 방식을 사용하는 정수형 데이터에서 오버플로우를 방지하거나 음수 값을 2로 나누는 등의 용도로 사용됩니다.
    SHR: 부호가 없는 데이터에서 빠른 2의 거듭제곱 연산을 위해 사용됩니다.
    따라서, SAR은 부호비트를 고려해야하는 정수형 데이터 처리에 유용하며, SHR은 부호와 상관없는 데이터 처리에 유용합니다.

특수 산술연산

64비트 부호형 혹은 비부호형 정수들 간의 곱셈은 결과를 표시하기 위해 128비트를 필요로 한다. 16바이트 워드를 옥토 워드(oct word)라고 한다.

i가 접두어로 붙은 인스트럭션은 Signed, 즉 부호가 있는 정수간의 연산을 나타내고, i가 존재하지 않는 연산은 부호가 없는 정수간의 연산을 나타낸다. 전자는 부호비트를 고려한 연산이 필요하여 속도가 비교적 느린 특징이 있고, 후자는 결과값이 옥토 워드 단위로 나온다는 특징이 있다.

제어문 📃

c의 일부 구문인 반복문, 스위치문은들은 데이터에 적용된 시험결과에 따라 일련의 연산이 실행되는 조건부 실행이 요구된다. 기계어 코드에서 이는 두 가지 방법으로 나뉘는데, 데이터 값들을 시험해서 이 시험 결과에 따라 데이터흐름이나 제어흐름을 변경한다. 데이터 의존성 제어흐름이 보다 일반적인 방법이므로 이것 부터 알아보자.

보통 C와 기계어 코드의 인스트럭션들은 모두 프로그램에 나타나는 순서대로 순서대로 순차적으로 실행된다. 기계어 인스트럭션들의 실행 순서는 점프(jump)인스트럭션으로 변경할 수 있다.

조건 코드

CPU에는 정수 레지스터만이 아닌 최근에 실행한 산술 또는 논리 인스트럭션에 관한 상태 정보를 저장하는 레지스터도 운영한다. 이는 조건코드 레지스터라고 한다. 자세히 알아보자.

이 레지스터는 명령어가 수행될 때마다 업데이트되며, 이전 명령어의 실행 결과를 저장합니다.

조건 코드 레지스터는 대개 프로세서의 상태 레지스터와 함께 사용되어 조건 분기 명령어에서 사용됩니다. 조건 분기 명령어는 이전 명령어의 실행 결과에 따라 분기 여부를 결정합니다. 예를 들어, "만약 레지스터 A가 0이면 분기하라"는 명령어는 조건 코드 레지스터를 사용하여 레지스터 A가 0인지 여부를 판단합니다.

조건 코드 레지스터는 대개 1비트 이상으로 구성되며, 각 비트는 특정 조건을 나타냅니다. 대표적인 조건 코드는 zero flag(ZF), carry flag(CF), overflow flag(OF), sign flag(SF) 등이 있습니다. 이들 조건 코드는 대부분의 프로세서에서 기본적으로 제공되며, 프로그래머는 이들 조건 코드를 사용하여 분기 여부를 결정할 수 있습니다.

레퍼런스: 내 친구 GPT

조건 코드에 대해 더 알아보면,

CF(Carry Flag): 캐리 플래그. 덧셈, 뺄셈, 비트 연산 등에서 발생한

  • Carry(연산 결과가 레지스터 크기를 초과할 경우 발생 or 비트연산에서의 자리올림)
  • Borrow(차감 결과가 음수일 때 발생 or 비트연산에서의 자리내림)

를 나타내는 데 사용된다. 따라서 이 플래그는 이전 연산 결과에 따라 다음 명령어의 동작을 결정하는 조건 분기 명령어에서 사용되거나, 비부호형 연산에서 오버플로우를 검출할 때 사용하곤 한다.

ZF(Zero Flag): 제로 플래그. 연산 결과가 0일 경우 1로 설정되며, 그렇지 않을 경우 0으로 설정된다. '만약 연산 결과가 0 이라면 분기하라' 는 명령어는 ZF 플래그를 사용하여 판단하게 된다.

SF(Sign Flag): 부호 플래그. 제로 플래그와 비슷한 기능을 하는데, 연산 결과가 음수일 경우 1로 설정되며, 그렇지 않은 경우 0으로 설정된다.

OF(Overflow Flag): 오버플로우 플래그. 가장 최근 연산이 양/음수의 2의 보수 오버플로우를 발생시켰는지를 표시한다. 부호 있는 연산에서 결과가 해당 데이터 타입의 범위를 벗어나는 경우 1, 아닐 경우 0으로 설정된다.

레지스터들의 변경 없이 조건 코드 값만을 수정하는, 그럼으로써 비교 및 시험 동작이 가능한 인스트럭션들이 존재한다. 대표적인 비교 및 시험 인스트럭션들이다.

CMP 인스트럭션들은 두 오퍼랜드의 차에 따라 조건 코드를 설정한다. 첫 번째 값에서 두 번째 값을 뺀 결과를 계산하고, 이 결과를 조건 코드 레지스터에 저장한다. 목적 오퍼랜드를 갱신시키지 않고 조건 코드를 설정한다는 점을 제외하고는 SUB인스트럭션과 비슷하게 동작한다.

TEST 인스트럭션들은 두 개의 값을 AND 연산한 결과를 조건 코드 레지스터에 저장한다. 목적 오퍼랜드를 변경하지 않으면서 조건 코드를 설정하는 점만 제외하고는 AND연산자와 동일하게 작동한다.

profile
저의 미약한 재능이 세상을 바꿀 수 있을 거라 믿습니다.

0개의 댓글

관련 채용 정보