프로세스 생성 함수 -------------------------------------------------------------------------------------------

윈도우에는 CreateProcess함수가 있다.

이 크리에이트 프로세스를 사용하여 프로세스를 생성하는 프로세스를 가리켜 부모 프로세스(Parent Process)라고 하고 이 함수를 통해서 생성된 프로세스를 자식 프로세스(Child Process)라고 한다.


함수의 원형을 살펴보자.

BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);

뭔가... 많다. 인자값을 한번 살펴보자.

------------------------

1. __in_opt LPCTSTR lpApplicationName,                  

-> 생성할 프로세스의 실행파일 이름을 인자로 전달.

------------------------

2. __inout_opt LPTSTR lpCommandLine,                    

-> main 함수에 있는 argc, argv라는 이름으로 문자열의 개수와 문자열이 전달된다. 1.번을 NULL로 했을경우 이곳에서 실행파일의 이름을 전달할 수도 있다. 이러한 경우 실행파일의 이름은 표준검색경로를 기준으로 찾게 된다.

------------------------

3. __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,

-> 프로세스의 보안속성을 지정한다. NULL로 선언하면 Default속성으로 지정된다.

------------------------

4. __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,

-> 쓰레드의 보안속성을 지정할때 사용된다. NULL을 전달할 경우 Default속성으로 지정된다.

------------------------

5. __in BOOL bInheritHandles,

-> 전달인자가 TRUE인경우 생성되는 자식 프로세스는 부모프로세스가 소유한 핸들중 일부(상속가능한 녀석들)을 상속한다.

------------------------
6. __in DWORD dwCreationFlags,

-> 생성하는 프로세스의 특성(특히 우선순위)을 결정지을 때 사용되는 옵션이다. 일반적으로 0으로 설정한다.

------------------------
7. __in_opt LPVOID lpEnvironment,

-> 프로세스마다 Environment Block 라는 메모리 블록을 관리한다. 이블록을 통해서 프로세스가 실행에 필요로 하는 문자열을 저장할수 있다. NULL로 지정할 경우 자식프로세스는 부모프로세스의 환경 블록에 저장되어 있는 문자열을 복사하게 된다.

------------------------
8. __in_opt LPCTSTR lpCurrentDirectory,

-> 생성하는 프로세스의 현재 디렉토리를 설정한다. 인자는 디렉토리 정보를 포함하는 완전 경로 형태로 구성되어야 한다. NULL이 전달될 경우 부모프로세스의 현재 디렉토리가 새로 생성하는 자식 프로세스의 현재 디렉토리가 된다.

------------------------

9. __in LPSTARTUPINFO lpStartupInfo,

-> STARTUPINFO 구조체 변수를 초기화한 다음 이 변수의 포인터를 인자로 전달한다. STARTUPINFO내용은 추후 설명

------------------------

10. __out LPPROCESS_INFORMATION lpProcessInformation

-> 생성하는 프로세스 정보를 얻기 위해 사용되는 인자이다. PROCESS_INFORMATION구조체 변수의 주소값을 인자로 전달한다.

------------------------


현재디렉토리(Current Directory)? ------------------------------------------------------------------------------

#include <iostream> 같은 전처리 명령등에서 완전경로(c: 에서부터 지금 사용하려면 파일이나 폴더가 있는 경로를 모두 포함한 값)를 사용하지 않고 파일 참조가 가능했다.

현재디렉토리라는 개념은 일반적으로 실행하려는 프로그램의 실행파일이 존재하는 폴더를 의미한다.

DWORD GetCurrendtDirectory(DWORD nBufferLength, LPTSTR lpBuffer) 함수로 확인이 가능하다.

첫번째는 두번째 인자값의 무낮열 길이를 정보를 넣고 두번째 정보는 정보를 담을 문자열 포인터를 넣으면 된다.

현재 디렉토리는 BOOL CurrendtDirectory(LPCTSTR lpPathName) 함수로 선언이 가능하고 변경하길 원하는 디렉토리 경로명만 넣으면 된다.


Posted by JJOREG

프로세스를 이해해보자 ---------------------------------------------------------------------------------------------------------

여러분이 게임을 즐기기위해서 어떤 실행파일과 그에 관련된 제반 파일들을 프로그램이라고 한다.

이제 실행을 위해서 실행파일을 더블클릭한 순간 프로그램의 실행을 위해서 메인메모리(RAM)에 할당이 이루어지 이고 이 메모리 공간에 바이너리 코드가 올라가면서 프로그램은 프로세스라고 불리게 된다. 

프로세스랑 실행중에 있는 프로그램을 의미한다.

프로세스가 되면 메인메모리에 프로세스를 위한 메모리 공간이 할당되며 메모리 공간의 구조는 다음과 같다.



프로세스의 메모리 구성 ---------------------------------------------------------------------------------------

CODE 영역 : 실행파일을 구성하는 명령어들이 올라가는 영역

DATA 영역 : 전역변수나 STATIC 변수의 할당을 위해서 존재하는 영역

HEAP 영역 : 동적할당을 위해서 존재하는 힙영역

STATK 영역 : 지역변수 할당과 함수호출시 전달되는 인자값들의 저장을 위해서 존재하는 영역

이중 STATK 영역은 점점 위로 차오르고(함수호출이 많아지게 되면) HEAP 영역은 (동적할당이 많아질수록)아래로 증가하게 된다.


프로세스와 CPU레지스트 --------------------------------------------------------------------------------------

프로그램 실행을 위해서는 레지스터들이 절대적으로 필요하며, 어떤 프로그램을 실행하면 CPU의 레지스터들은 현재 실행중인 프로그램을 위한 데이터들로 채워진다. 그러므로 레지스터의 상태또한 프로세스의 일부로 포함시켜서 말할수가 있다.


프로세스의 스케줄링과 상태변화---------------------------------------------------------------------------------

윈도우프로그램을 생각해보면 동시에 여러개의 프로그램이 실행되기도 합니다. 게임을 하면서 음성채팅을 할수도 있고 메신저를 동시에 켤 수도 있는 이유는 무엇일까?

이유는 간단하다. CPU가 여러개의 프로그램을 사용자가 느낄 수 없을 정도로 고속으로 번갈아가며 실행시킨다. CPU란 기본적으로 순차적으로 진행된다. 그러므로 여러개의 프로세스가 실행중이라고 해서 세개의 프로세스가 CPU를 동시에 차지하고 실행되는 것은 아니다.

그렇게 되면 A B C의 세가지 프로세스가 실행중이라고 할때 어떤 순서로 어떻게 실행될까를 결정해야 한다.

이렇게 프로세스의 CPU할당 순서 및 방법을 결정짓는 것을 스케줄링(Scheduling)이라고 한다.

그리고 이때 사용하는 알고리즘을 스케줄링 알고리즘(Scheduling Algorithms) 이라고 한다.

이러한 스케줄링은 소프트웨어적으로 동시에 프로세스를 실행할 수 있는 운영체제마다 구현되어 있다.


프로세스의 상태 ----------------------------------------------------------------------------------------------

프로세스에서 하는 가장 큰 일중 하나는 I/0(입력 및 출력)이다. 자신에게 할당된 메모리에 입력과 출력을 하는 동안 CPU가 쉴수는 없으므로 스케줄러를 통해서 다른 프로세스가 실행되도록 한다. 즉 CPU가 잠시도 쉬지않게 하기 위해서 지속적으로 프로세스의 실행순서를 조정해야 한다.

이를 가능하게 하는 것은 프로세스의 상태를 주는 것이다.

이 상태를 구분짓자면 StartReady, Running, Blocked, Exit의 세가지 상태가 있다.

A B C라는 프로세스가 있을때 각 프로세스는 Start와 동시에 Ready상태에 들어간다. Ready상태는 스케줄러에게 실행되기는 요청하고 있는 상태라고 보면 된다. 그리고 Ready상태는 스케줄러에게 관리되고 있다는 것을 의미하기도 한다.

스케줄러는 각 Ready상태의 프로세스중 하나를 선택하여 Running상태로 변경한다. 이 Running상태가 되어야 프로세스가 실행되고 있다고 볼 수 있다. 

하지만 하나의 프로세스가 Running이라는 것은 다른 프로세스들은 Ready상태라는 것을 의미하고 각 프로세스가 스케줄링 알고리즘에 의해서 언젠가는 Running상태가 되어야 한다는 것을 의미한다. 그리고 각 프로세스마다 그에 대한 순서가 필요하다. 순서가 없다면 프로세스들이 뒤죽박죽으로 실행될 것이기 때문이다.

이러한 현재 Ready상태의 프로세스들의 Running이 되어야할 순서를 우선순위(Priority)라고 한다.

마지막으로 Blocked상태는 이름처럼 프로세스가 실행을 멈추는 상태다. 일반적으로 데이터 입출력에 관련된 일을 하는 경우에 발생한다.

이렇게 한 프로그램이 Blocked상태에 들어가면 이 시간중에는 CPU가 쉬게 할수 없으므로 현재 Ready인 녀석중 한녀석을 선택해서 Running상태로 변경해 줘야 한다.

그리고 이런 Blocked상태에서 종료를 하게 되면 Exit 즉 프로세서가 소멸된 상태가 된다    

그림으로 보자면 이와 같다.


컨텍스트 스위칭 ----------------------------------------------------------------------------------------------

-- 프로세스와 CPU레지스트 항목중에서 --

프로그램 실행을 위해서는 레지스터들이 절대적으로 필요하며, 어떤 프로그램을 실행하면 CPU의 레지스터들은 현재 실행중인 프로그램을 위한 데이터들로 채워진다. 

라는 구분이 기억나는가? 당연히 CPU는 현재 프로세스되는 녀석들의 데이터를 가지고 있어야 한다. Ready상태인 프로세스는 언젠가는 Running상태가 되어야 하고 당연히 이때 CPU는 Running상태의 프로세스의 데이터들로 채워져야 한다.

그를 위해서 이와 같이 메모리에 있는 프로세스의 데이터를 교체하는 것을 컨텍스트 스위칭이라고 한다.

하지만 이렇게 헤지스터의 데이터를 통채로 교체하는 작업은 당연히 CPU에 큰 부담을 주므로 프로그래머라면 자신이 개발하는 프로그램의 성격에 따라서 이를 고려하여 프로그래밍 해야 한다.

Posted by JJOREG

내가 직접 다이렉트로 CPU에게 일을 시켜보려면? -----------------------------------------------------------------

1. 프로그래머가 직접 CPU의 시스템을 디자인해야 한다.

2. 프로그래머가 CPU를 디자인한다는 것은 CPU의 구성요소 중에서 레지스터와 매우 밀접한 관계가 있다.

2-1. 레지스터를 몇비트로 구성할 것인가?

2-2. 몇개 정도로 레지스터를 구성할 것인가?

2-3. 레지스터를 무슨 용도로 사용할 것인가?

여기에서는 레지스터를 R0부터 R7까지 사용한다고 생각하고 시작해 보겠습니다.

결론은 CPU에게 어떠한 일을 시킬수 있는 명령어를 만들어야 한다.


명령어는 모두 2진수로 이루어진다 ------------------------------------------------------------------------------

CPU에 명령을 하기위해서는 덧셈 뺄셈등도 2진수로 정의해야 합니다.

001 덧셈 ADD

010 뺄셈 SUB

011 곱셈 MUL

100 나눗셈 DIV

 그리고 이런식으로 되는거죠

명  령  어

설                                               명

Data Transfer

MOV

Move

데이터 이동 (전송)

PUSH

Push

오퍼랜드의 내용을 스택에 쌓는다

POP

Pop

스택으로부터 값을 뽑아낸다.

XCHG

Exchange Register/memory with Register

첫 번째 오퍼랜드와 두 번째 오퍼랜드 교환

IN

Input from AL/AX to Fixed port

오퍼랜드로 지시된 포트로부터 AX에 데이터 입력

OUT

Output from AL/AX to Fixed port

오퍼랜드가 지시한 포트로 AX의 데이터 출력

XLAT

Translate byte to AL

BX:AL이 지시한 데이블의 내용을 AL로 로드

LEA

Load Effective Address to Register

메모리의 오프셋값을 레지스터로 로드

LDS

Load Pointer to DS

REG←(MEM), DS←(MEM+2)

LES

Load Pointer ti ES

REG←(MEM), ES←(MEM+2)

LAHF

Load AH with Flags

플래그의 내용을 AH의 특정 비트로 로드

SAHF

Store AH into Flags

AH의 특정 비트가 플래그 레지스터로 전송

PUSHF

Push Flags

플래그 레지스터의 내용을 스택에 쌓음

POPF

Pop Flags

스택으로부터 플래그 레지스터로 뽑음

Arithmetic

ADD

Add

캐리를 포함하지 않은 덧셈

SBB

Subtract with Borrow

캐리를 포함한 뺄셈

DEC

Decrement

오퍼랜드 내용을 1 감소

NEG

Change Sign

오퍼랜드의 2의 보수, 즉 부호 반전

CMP

Compare

두 개의 오퍼랜드를 비교한다

ADC

Add with Carry

캐리를 포함한 덧셈

INC

Increment

오퍼랜드 내용을 1 증가

AAA

ASCII adjust for Add

덧셈 결과 AL값을 UNPACK 10진수로 보정

DAA

Decimal adjust for Add

덧셈 결과의 AL값을 PACK 10진수로 보정

SUB

Subtract

캐리를 포함하지 않은 뺄셈

AAS

ASCII adjust for Subtract

뺄셈 결과 AL값을 UNPACK 10진수로 보정

DAS

Decimal adjust for Subtract

뺄셈 결과의 AL값을 PACK 10진수로 보정

MUL

Multiply (Unsigned)

AX와 오퍼랜드를 곱셈하여 결과를 AX 또는 DX:AX에 저장

IMUL

Integer Multiply (Signed)

부호화된 곱셈

AAM

ASCII adjust for Multiply

곱셈 결과 AX값을 UNPACK 10진수로 보정

DIV

Divide (Unsigned)

AX 또는 DX:AX 내용을 오퍼랜드로 나눔. 몫은 AL, AX 나머지는 AH, DX로 저장

IDIV

Integer Divide (Signed)

부호화된 나눗셈

AAD

ASCII adjust for Divide

나눗셈 결과 AX값을 UNPACK 10진수로 보정

CBW

Convert byte to word

AL의 바이트 데이터를 부호 비트를 포함하여 AX 워드로 확장

CWD

Convert word to double word

AX의 워드 데이터를 부호를 포함하여 DX:AX의 더블 워드로 변환

Logic

NOT

Invert

오퍼랜드의 1의 보수, 즉 비트 반전

SHL/SAL

Shift logical / arithmetic Left

왼쪽으로 오퍼랜드만큼 자리 이동 (최하위 비트는 0)

SHR

Shift logical Right

오른쪽으로 오퍼랜드만큼 자리 이동 (최상위 비트 0)

SAR

Shift arithmetic Right

오른쪽 자리이동, 최상위 비트는 유지

ROL

Rotate Left

왼쪽으로 오퍼랜드만큼 회전 이동

ROR

Rotate Right

오른쪽으로 오퍼랜드만큼 회전 이동

RCL

Rotate through Carry Left

캐리를 포함하여 왼쪽으로 오퍼랜드만큼 회전 이동

RCR

Rotate through Carry Right

캐리를 포함하여 오른쪽으로 오퍼랜드만큼 회전 이동

AND

And

논리 AND

TEST

And function to Flags, no result

첫 번째 오퍼랜드와 두 번째 오퍼랜드를 AND하여 그 결과로 플래그 세트

OR

Or

논리 OR

XOR

Exclusive Or

배타 논리 합 (OR)

String Manipulation

REP

Repeat

REP 뒤에 오는 스트링 명령을 CX가 0이 될 때까지 반복

MOVS

Move String

DS:SI가 지시한 메모리 데이터를 ES:DI가지시한 메모리로 전송

CMPS

Compare String

DS:SI와 ES:DI의 내용을 비교하고 결과에 따라 플래그 설정

SCAS

Scan String

AL 또는 AX와 ES:DI가 지시한 메모리 내용 비교하고 결과에 따라 플래그 설정

LODS

Load String

SI 내용을 AL 또는 AX로 로드

STOS

Store String

AL 또는 AX를 ES:DI가 지시하는 메모리에 저장

Control Transfer

CALL

Call

프로시저 호출

JMP

Unconditional Jump

무조건 분기

RET

Return from CALL

CALL로 스택에 PUSH된 주소로 복귀

JE/JZ

Jump on Equal / Zero

결과가 0이면 분기

JL/JNGE

Jump on Less / not Greater or Equal

결과가 작으면 분기 (부호화된 수)

JB/JNAE

Jump on Below / not Above or Equal

결과가 작으면 분기 (부호화 안 된 수)

JBE/JNA

Jump on Below or Equal / not Above

결과가 작거나 같으면 분기 (부호화 안 된 수)

JP/JPE

Jump on Parity / Parity Even

패리티 플레그가 1이면 분기

JO

Jump on Overflow

오버플로가 발생하면 분기

JS

Jump on Sign

부호 플레그가 1이면 분기

JNE/JNZ

Jump on not Equal / not Zero

결과가 0이 아니면 분기

JNL/JGE

Jump on not Less / Greater or Equal

결과가 크거나 같으면 분기 (부호화된 수)

JNLE/JG

Jump on not Less or Equal / Greater

결과가 크면 분기 (부호화된 수)

JNB/JAE

Jump on not Below / Above or Equal

결과가 크거나 같으면 분기 (부호화 안 된 수)

JNBE/JA

Jump on not Below or Equal / Above

결과가 크면 분기 (부호화 안 된 수)

JNP/JPO

Jump on not Parity / Parity odd

패리티 플레그가 0이면 분기

JNO

Jump on not Overflow

오버플로우가 아닌 경우 분기

JNS

Jump on not Sign

부호 플레그가 0이면 분기

LOOP

Loop CX times

CX를 1감소하면서 0이 될 때까지 지정된 라벨로 분기

LOOPZ/LOOPE

Loop while Zero / Equal

제로 플레그가 1이고 CX&#8800;0이면 지정된 라벨로 분기

LOOPNZ/LOOPNE

Loop while not Zero / not Equal

제로 플레그가 0이고 CX&#8800;0이면 지정된 라벨로 분기

JCXZ

Jump on CX Zero

CX가 0이면 분기

INT

Interrupt

인터럽트 실행

INTO

Interrupt on Overflow

오버플로우가 발생하면 인터럽트 실행

IRET

Interrupt Return

인터럽트 복귀 (리턴)

Processor Control

CLC

Clear Carry

캐리 플레그 클리어

CMC

Complement Carry

캐리 플레그를 반전

CLD

Clear Direction

디렉션 플레그를 클리어

CLI

Clear Interrupt

인터럽트 플레그를 클리어

HLT

Halt

정지

LOCK

Bus Lock prefix


STC

Set Carry

캐리 플레그 셋

NOP

No operation


STD

Set Direction

디렉션 플레그 셋

STI

Set Interrupt

인터럽트 인에이블 플레그 셋

WAIT

Wait

프로세서를 일지 정지 상태로 한다

ESC

Escape to External device

이스케이프 명령

 

8086 지시어

 

지시어

내                                  용

형                                  식

SEGMENT
-
END

어셈블리 프로그램은 한 개 이상의 세그먼트들로 구성된다. SEGMENT 지시어는 하나의 세그먼트를 정의한다.

segname SEGMENT ; 세그먼트 시작
&#8942; ; 세그먼트 내용
segname ENDS ; 세그먼트 끝

PROC
-
ENDP

매크로 어셈블리에서는 프로그램의 실행 부분을 모듈로 작성할 수 있다. 이 모듈을 프로시저(Procedure)라 부르며, PROC 지시어가 이를 정의한다.

procname PROC ; 프로시저의 시작
&#8942; ; 프로시저의 내용
procname ENDP ; 프로시저의 끝

ASSUME

어셈블러에게 세그먼트 레지스터와 사용자가 작성한 세그먼트의 이름을 연결시킨다.

ASSUME SS:stack_segname,
DS:data_segname,
CS:code_segname,
ES:extra_segname

END

전제 프로그램의 끝을 나타냄

END

데이터 정의 지시어 : 프로그램에서 데이터를 저장할 기억 장소를 정의, 초기값 부여

DB

Define Byte

name DB 초기값

DW

Define Word

name DW 초기값

DD

Define Double Word

name DD 초기값

DQ

Define Quad Word

name DQ 초기값

DT

Define Ten Bytes

name DT 초기값

EQU

변수 이름에 데이터값이나 문자열 정의

name EQU 데이터값/문자열

=

EQU와 달리 정의된 값을 변경 가능


EVEN

어셈블리시 이 지시어가 사용되는 곳의 주소가 짝수로 되도록 함


PAGE

어셈블리 리스트의 형식을 결정

PAGE [length][,width]

TITLE

어셈블리 리스트의 각 페이지에 제목 출력

TITLE text



결과건 과정이건 결국에는 어딘가에 저장되어야 한다. --------------------------------------------------------------

R0부터 R7까지 명령어가 있다면 결국 그녀석들도 데이터가 됩니다. 어딘가에 저장되어야 하는데 결국 레지스터입니다.

R0 000

R1 001

R2 010

R3 011

R4 100

R5 101

R6 110

R7 111

이런식으로 레지스터를 표현합니다.

이를 조합해보면 

ADD R2 R1 7식으로 표현이 됩니다. 풀어보자면

   ADD    R2    R3   0111

    001    010   011   111

  더해라 R2에 R3과  7을 더한 결과를 저장해라

  식으로 표현이 됩니다.


RISC CISC. ----------------------------------------------------------------------------------------------

CPU의 명령어 체계는 

복잡하지만 다양한 명령을 내릴수 있는 CISC구조

RISC 짧고 규격화된 길이를 가진 명령어를 빠르게 처리하게 만들어진 RISC구조가 존재합니다.

RISC 구조는 짧고 자주쓰이는 명령어를 규격화시켜서 사용하기 때문에 한 클럭당 2개 이상의 명령어를 동시 처리가 가능하다고 합니다.


LOAD STORE명령어 ------------------------------------------------------------------------------------------

LOAD : 레지스터와 메인메모리 사이에서 데이터를 전송할 수 있는 명령어중 메인메모리에서 레지스터로 데이터를 옮기는 명령어.

STORE : LOAD와 반대로 레지스터에서 메인메모리로 데이터를 옮기는 명령어.


DIRECT INDIRECT명령어 -------------------------------------------------------------------------------------

LOAD나 STORE명령어는 주소값을 써넣을수 있는 공간이 적어 메인메모리의 모든 공간을 다 지정할수가 없습니다.(말그대로 물리적인 한계)

그래서 DIRECT는 말그대로 레지스터에서 가리킬수 있는 주소공간을 그대로 지정하는 방식이고

INDIRECT모드는 그에 한단계를 더했다고 보면 됩니다. 레지스터에 쓰여져있는 주소에 저장된 주소값을 통해서 LOAD STORE명령을 수행하는 방식입니다. (즉 메모리 공간이 주소를 저장하고 그 값을 참조해서 다른 메모리의 값을 참조하게 됩니다.)



Posted by JJOREG

64비트 컴퓨터란? ---------------------------------------------------------------------------------------------

컴퓨터의 모든 연산처리를 주소값(가상이건 물리적이건) 데이터는주소가 붙고 당연히 그 주소의 값은 0과1로 이루어진 2진데이터 입니다. 32비트 컴퓨터라는 것은 0과 1로 이루어진 숫자들을 주소로 사용할때.

0x00000000000000000000000000000000으로 주소를 표현할수 있는 녀석을 말합니다.

그럼 64비트 컴퓨터란?

0x0000000000000000000000000000000000000000000000000000000000000000 이만큼으로 주소를 표현할 수 있는 녀석을 의미합니다.

보면 간단해 보이지만 이것이 실제 프로그램등에 무슨 영향을 끼치는지 알아봐야 합니다.

메인메모리인 RAM에 있는 데이터를 불러오거나 할때 XX번지에 있는 데이터를 가져와! 라고 CPU가 명령을 내리는데 이때 이 XX번지의 한계가 32비트임을 의미합니다. 32비트로 표현할수 있는 주소값의 한계는 4GB인거죠. 즉 우리가 램을 8기가를 달아봐야 주소값으로 4GB까지의 주소만 표현할수 있기 때문에 나머지 4기가는 버려야 합니다. 32개의 비트가 0x11111111111111111111111111111111 까지 주소를 표현하면 주소값에 대한 물리적 한계에 도달하는 것입니다.

그래서 나온게 64비트입니다. 이 녀석은 말그대로 0x1111111111111111111111111111111111111111111111111111111111111111 까지 주소를 표현할 수 있죠 무려 16테라까지 주소를 표현할수가 있습니다.

물론 단순히 주소만이 아닙니다. 한번에 전달받고 처리할수있는 비트가 32비트이냐 64비트이냐는 굉장히 큰차이 이며 CPU의 처리능력 역시 향상되게 됩니다. 


대체 뭐가 달라지는거지? --------------------------------------------------------------------------------------

C++에서 포인터는 컴퓨터의 능력에 따라서 그 크기가 달라집니다. 32비트 컴퓨터에서는 4바이트였던 녀석이지만 64비트에서는 당연히 그 2배인 8바이트로 증가하게 됩니다.

단순히 용량만 증가하는 것이 아니라 그에 맞는 자료형 또한 정의되어야 합니다. __int64는 정수형 int를 대체하고 8바이트를 차치하게 됩니다. 하지만 모든 컴퓨터가 64비트 컴퓨터는 아니므로 필요에 따라서 유동적으로 프로그래밍이 가능하게 구성해야 합니다. 역시나 매크로를 사용하면 손쉽게 표현이 가능해 집니다.


#if definde(_WIN64)

 typedef    __int64    LONG_PTR;

 typedef    unsigned __int64    LONG_PTR;

 typedef    __int64    INT_PTR;

 typedef    unsigned __int64    UINT_PTR;

#else

 typedef    long    LONG_PTR;

 typedef    unsigned long    LONG_PTR;

 typedef    int    INT_PTR;

 typedef    unsigned int    UINT_PTR;

#endif


식으로 상황에 맞춰서 사용이 가능하게 해야합니다.

Posted by JJOREG

문자셋의 종류와 특성---------------------------------------------------------------------------------------

아스키코드 -> 쉽게 생각하자 1바이트로 표현가능한 문자수를 표현하기 위핸 규약이다. 256개의 문자를 표현이 가능하다.

유니코드 -> 2바이트로 표현가능한 문자규약을 의미한다. 65536개의 문자를 표현이 가능하다.


SBCS MBCS WBCS------------------------------------------------------------------------------------

SBCS(single byte character set) = 문자를 표현함에 있어서 1바이트로 표현하는 방식을 의미한다.

MBCS(multi byte character set) = 어떨때는 1바이트 어떨때는 2바이트로 표현하는 방식을 의미한다.

WBCS(wide byte character set) = 유니코드처럼 모든 문자를 2바이트로 처리하는 문자세를 의미한다.

  현재로서는 SBCS문자열 처리방식은 거의 사용하지 않고 내가 사용하는 녀석도 WBCS를 통한 문자열 처리를 이용하고 있다 하지만 항상 예외는 있으니 SBCS를 포함한다고 볼수있는 MBCS와 WBCS를 모두 지원하는 프로그래밍 방법에 대해서 기술한다. 


MBCS WBCS--------------------------------------------------------------------------------------------

문자열 처리에 있어서 WBCS는 MBCS와 문자열에 대한 선언 자체가 다르다.

MBCS는 char을 통해서 문자열을 선언하고

WBCS는 wchar_t를 통해서 문자열을 선언한다.

마찬가지로 문자열을 처리하는 함수들또한 다르다.

간단히 문자열의 길이를 반환해주는 함수를 보면

strlen은 sbcs용 함수이다.

wcslen은 wbcs용 함수이다.

이런 함수들을 어떻게하면 각기 맞게 해줄까? 


MBCS WBCS를 동시에 지원하기 위한 전처리문장선언--------------------------------------------------------------

#ifdef UNICODE

 typedef WCHAR      TCHAR;

 typedef LPWSTR     LPTSTR;

 typedef LPCWSTR   LPCTSTR;

#else

 typedef CHAR         TCHAR;

 typedef LPSTR        LPTSTR;

 typedef LPCSTR      LPCTSTR;

#endif


#ifdef의 의미를 안다면 간단한 내용. 같은 자료형이지만 #define로 정의된 내용에 따라서 각각 자료형을 다르게 정의하면 된다.

Posted by JJOREG

컴퓨터 하드웨어의 구성.---------------------------------------------------------------------------------------

  컴퓨터 하드웨어와 시스템 프로그래밍을 게임프로그래머가 왜 공부해야 하는가. 

  부터 시작한다면 책에 써있는 바가 아닌 내 생각을 이야기해보고 싶다.

  이는 우리가 무엇을 이용하여 결과를 낼 수 있느냐에 대한 근본을 배우는 것이다. 우리가 코드를 만들어 내는 곳은 결국 컴퓨터이고 컴퓨터는 는 우리의 코드를 자신이 알아들을수 있는 언어를 통해서 이해한다. 컴퓨터를 이해하면 우리의 코드의 깊은 곳을 이해할 수 있다. 단순히 코드를 통해서 화면에 발생하는 움직임이 아니라 좀더 깊은 의도를 파악하고 그저 사용하기만 했던 코드들도 다른 방향에서 바라볼수 있는 시각을 가지게 된다.

  이는 핸드폰게임 개발자가 핸드폰의 하드웨어적인 한계에 대해서 알아야 하는 것과 같다. 보드게임을 만드는 사람은 자신의 말과 자신이 사용할 수 있는 재료에 대해서 알아야 하는 것과 같고 TRPG를 만드는 사람은 일반적인 사람의 사고능력과 성격에 대해서 흥미등에 대해서 탐구해야하는 것과 같다고 볼 수 있다.


 CPU의 개요.------------------------------------------------------------------------------------------------

  CPU란? 우리가 흔히 말하는 중앙처리 장치. CPU는 프로그램의 실행에 대해서 핵심적인 역할을 담당하므로 개인용PC라는 플랫폼을 기반으로 개발을 진행하는 소프트웨어 프로그래머라면 당연히 CPU에 대해서 좀더 구체적으로 이해하려는 노력이 필요하다.


 메인메모리와 입출력 버스--------------------------------------------------------------------------------------

  메인메모리(Main Memory) = 컴파일이 완료된 코드가 올라가서 실행되는 영역이다. 좀더 쉽게 이야기한다면 게임아이콘을 더블클릭하면 하드디스크의 데이터가 바로 이곳으로 올라가서 게임이 실행되게 된다고 생각하면 된다.

 입출력버스(I/O BUS) = 컴퓨터를 구성하는 구성요소들 사이에서 데이터를 주고받기 위해서 사용하는 경로이다. 종류에 따라서 다음과 같이 분류된다. 어드레스버스(Address Bus), 데이터버스(Data Bus), 컨트롤버스(Control Bus) 


  CPU의 구조------------------------------------------------------------------------------------------------

  ALU(Arithmetic Logic Unit) = 말그대로 컴퓨터연산의 기본이 되는 주체이다. 덧셈이나 뺄셈같은 산술연산과 AND OR같은 논리연산을 실행한다.

  컨트롤 유닛(Control Unit) = 하지만 ALU는 10001111000이런녀석이 덧셈을 하라는 건지 뭘하라는 건지 잘 알아듣지 못한데 이것을 ALU가 알아들을수 있게 해석하여 ALU가 작동하게 도와주는 것이 컨트롤 유닛이다. 요약하자면 CPU가 처리해야할 명령어들을 해석한다.

 "덧셈이군 뺄셈이군 논리연산이군 ALU야 내가 해석한대로 연산을 실행하렴."

  레지스터(Register Set) = ALU와 컨트롤유닛이 처리하기 이전에 잠깐 2진데이터(바이너리 데이터 Binary Data)를 저장해 두는 역할을 한다. CPU에 따라서 16비트 32비트 64비트를 저장이 가능하다. 또한 CPU에 따라서 종류와 개수가 다양하다.

  버스인터페이스(Bus Interface) = 명령어와 데이터들을 입출력버스를 통해 CPU로 이송해주는 녀석이 필요하다. 버스인터페이스는 입출력버스의 통신방식을 이해하고 있는 녀석이 필요하고 이를 통해서 입출력버스에 데이터를 받아오거나 혹은 입출력버스에 데이터를 송수신할 수 있는 녀석이 필요한데 그게 이녀석이다.


  클럭신호 ------------------------------------------------------------------------------------------------

  데이터를 전송하는 속력은 CPU가 연산하는 속력과 동일하다고 할수가 없다. CPU가 처리하는 속력에 맞춰 모든 주변기기가 동기화 해줘야 한다고 생각하면 된다. 즉 한번 입력되면 다음 한번은 출력하고 한쪽이 늦어진다면 입력이나 출력하는 쪽에서 CPU의 클럭신호에 맞춰서 자신의 연산을 늦추거나 낮춰 모든 연산이 한번에 돌아가게 해줘야 한다는 것이다. 이는 CPU의 처리는 순차적으로 실행되어야 함을 의미한다.


  프로그램의 실행과정 -----------------------------------------------------------------------------------------

  전처리기 -> 컴파일러 -> 어셈블러 -> 링커

  전처리기에 의한 치관작업 -> #define이나 #include 같은 지시자의 지시에 따라서 소스코드를 치환하고

  컴파일러에 의한 번역 ->  우리가 고급언어로 짠 코드들을 컴파일러가 어셈블리코드로 번역해준다음

  어셈블러에 의한 바이너리코드 생성 -> 10010101010110식으로 코드를 2진수하 시킨다. 그리고 이것을 0001은 덧셈 0010은 뺄셈 따른 녀석은 곱셈등으로 생성해준다.

  링커에 의한 연결과 결함. 메모리상에 존재하는 명령어를 cpu로 옮겨서 실제적으로 실행되어야 하는 실행파일로 만들어 준다. 그리고 이 실행파일은 Fetch Decode Execition이라는 과정을 거치게 된다.


  Fetch Decode Execition ------------------------------------------------------------------------------------

  Fetch = 메모리상의 존재하는 명령어를 cpu로 가져오고

  Decode = 가져다 놓은 명령어를 cpu가 해석한다음

  Execition = 명령어 대로 cpu가 실행하게 된다.


  Fetch 이녀석이 어떻게 명령어를 옮기지?------------------------------------------------------------------------

  어드레스버스(Address Bus), 데이터버스(Data Bus), 컨트롤버스(Control Bus)  우리가 나설 차례군!

  데이터버스 : 이름 그대로 데이터를 이동하기 위해서 필요한 버스이다. 이때 데이터는 명령어 연산에 필요한 피연산자가 될수도 있다. 

  어드레스버스  : 데이터는 주소가 있다고 생각하면 편하다. x 번지에 데이터1, xx번지에 있는 데이터2 그 주소값을 이동시키기 위해서 필요한 버스이다.

  컨트롤버스 : cpu가 원하는 바를 메모리에 전달할때 사용되는 버스이다. 데이터를 보냅니다. 데이터를 주세요 등등 말그대로 cpu가 메모리에 필요한 용건을 말할때 역할을 해주는 버스를 의미한다.



Posted by JJOREG