카테고리

asm (27) bootloader_x86_grub (1) C (92) compile (11) config (76) CPP (13) CSS (1) debugging (7) gimp (1) Go (1) html (1) Java (1) JavaScript (1) kernel (19) LibreOffice (3) Linux system progamming (21) MFC (1) opencv (4) OpenGL (1) PHP (1) Python (4) qemu (29) shell (3) socket (7) troubleshooting (2) ubuntu18.04 (2) windows (1)

2018/12/16

asm 산술 연산


1. 산술 연산

산술 연산자를 위해 레지스터를 사용 하면, 산술 연산을 할 수 있다.

산술 연산의 형태는 일반적으로 다음과 같다.
operation register, value/register

첫 번째 레지스터가 연산의 대상입니다.

예를 들어:
add rax, 5
sub rbx, rax

수학 연산 리스트
동작 이름
동작 이름(서명)
설명
add a, b
-
a = a+b
sub a, b
-
a = a-b
mul reg
imul reg
rax = rax*reg
div reg
idiv reg
rax = rax/reg
neg reg
-
reg = -reg
inc reg
-
reg = reg +1
dec reg
-
reg = reg – 1
adc a, b
-
a = a+b+CF
add a, b
-
a = a-b-CF


2. ASCII

ASCII는 컴퓨터가 텍스트 문자열을 나타내는 방법.

컴퓨터는 숫자를 저장할 수 있으므로 ASCII는 숫자를 특정 문자 (문자, 숫자, 기호 등)에 매핑하는 방식으로 작동 한다.

ASCII7 비트 이진 코드를 사용 하여 문자를 나타낸다. 그러나 8 비트 1바이트 정보의 기본 단위 이기 때문에 현 컴퓨터는 일반적으로 8비트 코드인 확장 ASCII을 지원한다.

ASCII .

3. 숫자 화면 출력
다음은 09사이의 단일 숫자를 표시하기 위한 매우 간단한 서브루틴이다.

표시되는 숫자는 rax 레지스터에서 가져온다.

section .data
digit db 0,10

...

_printRAXDigit:
add rax, 48
mov [digit], al
mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 2
syscall
ret

rax 레지스터의 값은 48 씩 증가한다.
ASCII 표를 확인하면 48"0"문자 값과 매칭 되며, char형이므로 "1"문자를 표현 할 수 있다.

ASCII 코드 테이블 추가 필요
section .data
digit db 0,10
...
...

_printRAXDig:
add rax, 48 " 0을 의미 함.
mov [digit], al
mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 2
syscall
ret

rax 레지스터의 하위 바이트는 메모리 주소 "digit"로 이동
_printRAXDig:
add rax, 48 " 0을 의미 함.
mov [digit], al " 메모리 주소 이동
mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 2
syscall
ret

"digit"는 실제로 2 바이트로 정의되며, 010, 줄 바꿈 문자, 개형 문자를 의미한다. rax 레지스터의 하위 바이트를 "digit"에 로드하기 때문에 첫 번째 바이트 만 덮어 쓰며 개행 문자에는 영향을 미치지 않는다.

그런 다음 2 바이트를 화면에 출력 한다.
길이가 2로 설정되어 있기 때문에 숫자와 개행 문자가 함께 표시됨.

section .data
digit db 0, 10
...
...
...

_printRAXDigit:
add rax, 48
mov [digit], al

mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 2
syscall
ret

아래 서브 루틴을 사용하여 해당 숫자를 rax 레지스터에 로드 한 다음 서브 루틴을 호출하여 0-9 사이의 숫자를 표시 할 수 있다.

mov rax, 7
call _printRAXDigit
숫자 7을 화면에 출력 한다.

이러한 방법을 통해 산술 연산자를 빠르게 테스트 할 수 있다.
코드
출력
추론
mov rax, 6
mov rbx, 2
div rbx
call _printRAXDigit
3
rax = 6/2
mov rax, 1
add rax, 4
call _printRAXDigit
5
rax = 1+4


4. Stack
레지스터와 마찬가지로 스택은 데이터를 임시로 저장하는 또 다른 방법이다.
데이터를 스택(쌓기)에 저장하기 때문에 "스택"이라고 한다.

서류 더미를 상상해보자. 한 장의 용지를 다른 용지 위에 겹쳐 놓으면 지정된 시간에만 스택의 맨 위에 있는 용지의 내용을 볼 수 있다.

스택 중간에 있는 페이지는 위에 있는 페이지 전부를 제거하지 않고는 중간의 스택을 제거 할 수 없다.

push: 스택의 맨 위에 데이터를 추가.
pop :스택의 맨 위에서 데이터를 제거.
peek: 추가, 제거 없으며 스택을 볼때.


4.1 스택 동작
동작
효과
push reg/value
값을 스택에 밀어 넣는다.
pop reg
스택에서 값을 꺼내서 reg에 저장한다.
mov reg, [rsp]
regpeek(보기) 값을 저장한다.
참고: 일반적으로 레지스터를 사용할 수 있는 위치에서 포인터를 사용할 수도 있다.
"pop reg"대신 "pop [label]"을 사용하여 스택의 값을 메모리의 특정 위치로 직접 pop 할 수 있다.

4.2 push
Peek:NULL

Peek:4

Peek:8

Peek:3




3
8
3
4
4
4
Stack
Stack
Stack
Stack


4.3 pop
Peek:3

Peek:8

Peek:4


Peek:NULL




3
8
8
4
4
4
stack
Stack
Stack
Stack
rax:NULL
rax: 3
rax: 8
rax: 4


예제 코드
push 4
push 8
push 3

pop rax
call _printRAXDigit
pop rax
call _printRAXDigit
pop rax
call _printRAXDigit

출력 예상
3
8
4

C 언어 메모리 할당 영역 정리


1. 메모리 할당
메모리 할당
정적 메모리 할당(배열)
동적 메모리 할당

할당 된 메모리 다른 영역
code: 코드 영역
초기화 된 데이터: data 영역
초기화 되지 않은 데이터: bss 영역
Heap
스택 Stack
Segment(영역)
설명
stack 크기가 초기화에 정해지지 않는다
실행 할 때 메모리 크기가 설정된다
(메모리 크기 변화)
(메모리 크기 변화)
heep 크기가 초기화에 정해지지 않는다
실행 할 때 메모리 크기가 설정된다
BSS 영역(초기화 되지 않은 데이터) 초기화 하지 않는 변수가 위치하는 영역,
0으로 초기화된 변수의 내용도 포함한다
main(){static int a;}
컴파일 하는 순간 크기가 정해 된다.
Data 영역( 초기화 된 데이터) 초기화된 변수가 위치 하는 영역.
컴파일 하는 순간 크기가 정해진다.
CODE 영역(text) 코드가 바이너리 형식으로 위치하게 된다.
컴파일 하는 순간 크기가 정해진다.



code 영역
  • 텍스트 영역이라 하며 읽기 전용
  • 실행 가능 명령어가 있는 오브젝트 파일을 포함.
  • read-only == object file : 읽어와 실행만 한다.
  • 코드만 위치하며 컴퓨터(CPU 연산)가 읽어 실행만 하는 영역
  • 변경 하려면 재 컴파일해 오브젝트 코드를 다시 만들어야 한다.



data 영역
  • 실행시간에 변경할 수 있는 초기화 된 변수를 포함 한다.
  • 고정되어있는 Global, static, constant external 변수 초기화.
  • 컴파일 후 크기기 지정된다.
  • 이 영역의 크기는 실행 시간에 변경되지 않음.
  • 단지 초기화된 변수가 들어간다

bss 영역
  • 초기화되지 않은 Global, Static external 변수 저장 (0으로 초기화 됨)
  • 컴파일 후 크기가 지정되며, 초기화 하는 변수의 총 수량으로 크기가 설정된다.
  • 영역의 크기는 실행 시간에 변경 되지 않음.
  • 이 영역은 오브젝트 파일에서 실제 공간을 차지 하지 않는다.(Bss 영역의 길이만 저장 됨).

Object 영역
  • data 영역은 모든 자료에 대한 값을 가진다.
  • bss 영역은 초기화 하지 않는 변수의 총 수량만 가진다.

1.1 스택 메모리
다음 정보는 스택에 저장 된다.
  • 지역 변수 : 함수 안에서 사용되는 변수
  • 함수 인수의 값: 스택으로 전달되는 값
  • 리턴 주소(PC의 값): 복귀 주소 값(함수 복귀 조소 값 저장 후, 호출된 부분으로 이동 처리 후 복귀)

예제
#include <stdio.h>

int add2(int a, int b);

void main(void){
int i=5, j=7, n;

n=add2(i,j);
printf("SUM is %d\n", n);
}

int add2(int a, int b){
return (a+b)
}

2. 힙 메모리
힙 메모리의 할당된 구조
  • 함수에서 생성 하지만, 함수를 지속적으로 사용 할 때 우회해 사용된다.
  • 프로그램 코드 작성할 때 동적 메모리 할당을 해야 하는 경우에,
  • 동적 메모리 할당을 하게 코드를 작성한다.
  • 메모리가 설정되면 Heap memory 영역에 할당된다.
  • 동적 메모리의 할당과 해제 때문에 heap memory 영역의 크기가 가변적으로 변경이 된다.
  • 동적 메모리 할당을 했으면 메모리 자원 반납을 위해 꼭 해제한다.

문제점
할당 및 사용 가능한 메모리 공간 관리
할당 해제 및 가비지 수집

2.1 힙 메모리 할당
void *malloc(size_t size);
malloc(size_t size);
자료형
주소 값 0x1200
단위
void *원하는 자료형캐스팅 필요
블록
블록
Byte
  • 바이트 크기 블록 할당
  • 블록에 대 한 포인터 반환 (할당이 실패 하는 경우 NULL)

void *calloc(size_t num_elements, size_t element_size));
calloc(size_t num_elements, size_t element_size));
자료형
주소 값 0x1300
단위
void *원하는 자료형캐스팅 필요
블록 0 초기화
블록 0 초기화
Byte
  • num_elements * element_size 바이트 블록 할당
  • 모든 바이트를 0으로 초기화.
  • 블록에 대한 포인터 반환 (할당이 실패 하는 경우 NULL)

void *realloc(void *ptr, size_t new_size)
  • 블록 크기를 new_size로 변경
  • 새로운(크기 조정 된) 블록의 포인터를 반환.
  • 이전 블록의 내용은 새 할당 된 블록에 복사 될 수 있다.
  • malloc/calloc/realloc의 반환 값을 캐스팅해야 할 수도 있다.
  • int * pi = (int *) malloc (BUFFER_SIZE);
2.2 힙 메모리 할당 해제
void free(void *pointer);
이전에 할당 된 메모리에 대한 포인터 필요.
메모리 공간을 heep으로 다시 확보

기억
 할당 된 메모리가 더 이상 사용되지 않으면 해제한다.
"메모리 누수" 문제가 발생할 수 있다.
디버깅 하기 어렵다!

malloc free 예제
#include <stdio.h>
#include <stdlib.h>

void main(void){
int i, *p, n=10, m=20;

/* allocate n interger blocks */
if (( p = (int *) malloc(n * sizeof(int))) == NULL){
perror("Malloc memory allocation failed.");
exit(0);
}
for (i=0; i<n; i++){
p[i] = i;
}

/* m 블록을 p 블록의 끝에 추가한다. */
if (( p = (int *) realloc(p, (n+m) * sizeof(int))) == NULL){
perror("realloc memory allocation failed.");
exit(0);
}
for (i=n; i < n+m; i++){
p[i] = i;
}

/* 새로운 배열 출력 */
for(i=0; i<n+m; i++){
printf("%d\n", p[i];)
}

free(p); /* return p to available memory pool */
}

동적 할당을 사용하는 배열
#include <stdio.h>
#include <stdlib.h>

void main(void){
int *pS, j;
int i32Num = 20;

if((pS = (int *) malloc(i32Num * sizeof(int))) == NULL){
perror("malloc memory allocation failed.");
exit(0);
}
for(j=0; j<i32Num; j++){
pS[j] = j;
}

/* print new array */
for(j=0; j<i32Num; j++){
printf("%d\n", pS[j]);
}
free(pS);
}

#include <stdio.h>
void main(void){
int pS[20], j;
int i32Num = 20;

for(j=0; j<i32Num; j++){
pS[j] = j;
}

for(j=0; j<i32Num; j++){
printf("%d\n", pS[j]);
}
}