데이터 기초
어셈블러(asembler) : =번역기.
비트(bit - binary digit) : 0 또는 1의 두가지 값만 가질 수 있는 측정 단위
바이트(Byte) : 여덟개의 비트로 구성된 데이터의 양을 나타내는 단위
- 음수를 나타낼 때는 2의 보수를 사용함
- 0x를 붙인 16진수를 유용하게 사용함
8 bit = 1 byte
16 bit = 2 byte = 1 word
32 bit = 4 byte = 2 word = 1 dword(double-word)
64 bit = 8 byte = 4 word = 1 qword(quad-word)
레지스터 기초
레지스터 : 데이터를 임시적으로 저장하는 역할
CPU 내에 있기 때문에 거리가 짧아 처리속도가 매우 빠름
- rax = 64비트 / eax = 32비트 / ax = 16비트 / ah, al = 8비트
mov 레지스터명, 값
: 레지스터에 값을 저장mov 레지스터1, 레지스터2
: 레지스터2에 저장되어있는 값을 레지스터1에 저장
변수와 레지스터
data
영역에는 초기화 된 데이터를 사용
[변수이름] [크기] [초기값]
- ex)
a db 0x11
,c dd 0x33333333
- db = 1, dw = 2, dd = 4, dq = 8 (바이트기준)
bss
영역에는 초기화되지 않은 데이터를 사용
[변수이름] [크기] [개수]
- ex)
e resb 10
,f resq 64
- resb = 1, resw = 2, resd = 4, resq = 8 (바이트기준)
data
영역과 bss
영역이 나뉘어져있는 이유 : 초기화되지 않은 변수는 초기값을 저장할 필요가 없으므로 실행파일의 크기가 작아짐
mov 레지스터 변수명
으로 사용시 변수의 주소값이 레지스터에 저장됨mov 레지스터, [변수명]
으로 사용시 변수 자체의 값이 레지스터에 저장됨
- 단, 크기를 지정하지 않았을시 설정한 레지스터와 같은 크기만큼 읽어들임
- 원하는 크기만큼 읽고싶을 때는 레지스터 크기를 조절하는 방법을 사용할 수 있음
move [변수명], 크기지정 값
또는 move [변수명], 레지스터명
으로 변수에 값을 지정할 수 있음
ex) mov [a], byte 0x55
, mov [a], word 0x6666
, `mov [a], cl
문자와 엔디안
문자는 아스키코드를 활용해서 읽음
동일한 데이터라고 해도 어떻게 분석하고 받아들이냐에 따라 다른 의미가 될 수 있음
리틀 엔디안 : 대부분 사용, 메모리 주소가 증가함에 따라 변수가 거꾸로 저장됨
- 캐스팅(데이터의 크기가 큰 자료형에서 작은 자료형으로 바꾸는 것)에 유리
빅 엔디안 : 변수가 메모리 주소 증가에 맞추어 순서대로 저장됨
- 숫자 비교에 유리
사칙연산
더하기 : add a, b
- a는 레지스터 또는 메모리
- b는 레지스터 또는 메모리 또는 상수
- 단, 메모리를 사용할 때는
[]
로 주소가 아닌 값을 받아와아하며 a와 b 모두 메모리일 수는 없음 - 메모리에 상수를 더할 때는 더할 상수의 크기를 지정해줘야함
빼기 : sub a, b
, add와 동일함
곱하기 : mul reg
- 곱해지는 레지스터의 크기에 따라 작동이 달라짐
mul bl
= al * bl, 연산 결과는 ax에 저장됨mul bx
= ax * bx, 연산 결과는 상위 16비트가 dx, 하위 16비트가 ax에 저장됨
나누기 : div reg
- 나눠지는 레지스터의 크기에 따라 작동이 달라짐
div bl
= ax / bl, 연선 결과는 몫이 al에, 나머지가 ah에 저장됨
시프트 연산과 논리 연산
산술 시프트(shift)에서는 부호를 나타내는 최상위비트는 그대로 유지됨shl 레지스터, 값
또는 shr 레지스터, 값
의 형태로 사용
시프트 연산으로 곱셈 및 나눗셈을 간편하게 할 수 있음
게임서버에서 ObjectID를 만들 때도 유용하게 사용
논리 연산에는 not
, and
, or
, xor
이 있음
not A
: 하나에 조건에 대해 0이면 1, 1이면 0A and B
: 둘다 1이면 1, 나머지는 0A or B
: 둘중 하나라도 1이면 1, 아니면 0A xor B
: 둘다 1이거나 둘다 0이면 0, 아니면 1and al, bl
,not al
등의 형태로 사용
비트플래그(bitflag)에 사용xor
을 두번 사용시 원래 값으로 돌아오는 특성이 있으므로 암호학에서 유용하게 사용함xor
을 자기 자신으로 사용시 모든 값이 0으로 대입되기 때문에 오류 체크 등에 사용함
분기문
특정 조건에 따라서 코드 흐름을 제어
cmp dst, src
의 형태로 사용, dst
가 기준
비교를 한 결과물은 Flag Register에 저장cmp
결과에 따라 Flag Register의 각 비트가 경우에 맞게 변환되고, 아래의 jmp
등의 연산자들이 그 비트를 참조하여 조건을 판별함
jmp/je/jne/jg/jge... [label]
의 형태로 이동
jmp
: 무조건 점프je
: JumpEqulas, 같으면 점프jne
: JumpNotEquals, 다르면 점프jg
: JumpGreater, 크면 점프jge
: JumpGreaterEquals, 크거나 같으면 점프- ...
mov ax, 100
mov bl, 2
div bl
cmp ah, 1
je LABEL_ODD
mov rcx, 1
jmp LABEL_EVEN
LABEL_ODD:
mov rcx, 0
LABEL_EVEN:
PRINT_HEX 1, rcx
NEWLINE
반복문
특정 조건을 만족할때까지 반복해서 실행
mov ecx, 10
LABEL_LOOF:
PRINT_STRING msg
NEWLINE
dec ecx
cmp ecx, 0
jne LABEL_LOOF
mov eax, 100
xor ebx, ebx ; = mov ebx, 0
xor ecx, ecx
LABEL_SUM:
inc ecx, 1
add ebx, ecx
cmp ecx, eax
jne LABEL_SUM
PRINT_DEC 4, ebx
NEWLINE
cmp
와 jmp
를 사용하여 반복문 생성 가능
mov ecx, 100
xor ebx, ebx
LABEL_LOOP_SUM:
add ebx, ecx
loop LABEL_LOOP_SUM
PRINT_DEC 4, ebx
NEWLINE
loop [라벨]
을 사용하여 반복문 생성 가능
해당 구문을 만나면 ecx
레지스터가 하나 줄어드는 것을 이용해 반복
배열과 주소
배열 : 동일한 타입의 데이터 묶음
- 배열을 구성하는 각 값을 배열 요소(element)라고 함
- 배열의 위치를 가리키는 숫자를(index)라고 함
a db 0x01, 0x02, 0x03, 0x04
,b times 5 dw 1
,num resb 10
등의 형태로 사용
xor ecx, ecx
LABEL_PRINT_LOOP:
PRINT_HEX 1, [a+ecx]
NEWLINE
inc ecx, 1
cmp ecx, 5
jne LABEL_PRINT_LOOP
a db 0x01, 0x02, 0x03, 0x04
xor ecx, ecx
LABEL_PRINT_LOOP:
PRINT_HEX 2, [b+ecx*2]
NEWLINE
inc ecx, 1
cmp ecx, 5
jne LABEL_PRINT_LOOP
b times 5 dw 1
시작 주소를 기준으로 인덱스 * 크기만큼을 이동하는 방식이 많이 사용됨
함수 기초
어셈블리에서는 함수보다 프로시저(procedure)라는 용어를 더 많이 사용함
CMAIN:
call PRINT_MSG
ret
PRINT_MSG:
PRINT_STRING msg
NEWLINE
ret
함수로 하나의 기능 단위를 관리할 수 있음
MAX:
cmp eax, ebx
jg L1
mov ecx, ebx
jmp L2
L1:
mov ecx, eax
L2:
ret
인자의 개수가 늘어난다면 위와 같은 방법으로는 구현이 힘들어짐
레지스터에 이미 중요한 값이 저장되어있었다면 문제가 생길 수 있기 때문에 데이터 영역의 변수를 활용할 수도 있으나, 여전히 영구적인 메모리를 사용하기에 낭비가 발생함
즉, 함수에는 유효 범위 / 정리 / 유동적인 유효 범위 확장의 개념이 필요하기 때문에 이를 만족시킬 수 있는 스택(stack)이라는 메모리 영역을 사용
- 함수가 사용하는 일종의 메모장
- 매개변수 전달, 돌아갈 주소 관리에 사용됨
스택 메모리
CODE / DATA / BSS / HEAP / STACK
스택은 높은 주소에서 시작됨
함수 호출시 매개변수 / 반환 주소값 / 지역 변수가 스택에 쌓임
포인터 레지스터
- ip(Instruction Pointer) : 다음 수행 명령어의 위치
- sp(Stack Pointer) : 현재 스택의 top 위치
- bp(Base Pointer) : 스택 상대주소 계산용
push
로 데이터를 스택에 저장하고, pop
으로 꺼내옴
단, pop
의 경우 실제로 저장되어있는 데이터를 제거하지는 않고 top을 가리키는 포인터인 sp
의 위치만 조정함
mov rbp, rsp
push 1
push 2
call MAX
PRINT_DEC 8, rax
NEWLINE
add rsp, 16
MAX:
push rbp
mov rbp, rsp
mov rax, [rbp+16]
mov rbx, [rbp+24]
cmp rax, rbx
jg L1
mov ra, rbx
L1:
pop rbp
ret
rbp
에는 sp
의 주소를 고정시켜 상대주소를 계산하는데 용이하게 사용bp
를 관리하는 일련의 과정을 스택 프레임이라고 함
스택 프레임에는 넘겨준 인자 뿐만 아니라 리턴주소, 이전 함수가 사용하던 스택 프레임 공간을 알기 위한 bp
값 등이 있음
'개인공부 > Rookiss C++ 프로그래밍 입문' 카테고리의 다른 글
Chapter 6 - 객체지향 여행 (0) | 2023.03.29 |
---|---|
Chapter 5 - 포인터 (0) | 2023.03.29 |
Chapter 4 - 함수 (0) | 2023.03.29 |
Chapter 3 - 코드의 흐름 제어 (0) | 2023.03.29 |
Chapter 2 - 데이터 갖고 놀기 (0) | 2023.03.29 |
댓글