ABOUT ME

-

Today
-
Yesterday
-
Total
-
choco@desktop:~/tistory
$ 정보처리기사 요점정리
1과목 2과목 3과목 4과목 5과목 실기

$ Linux Kernel
Power Management DVFS
  • 컴퓨터 언어 이해하기 - 바이너리
    자료구조&알고리즘 2018. 9. 2. 13:27

    16진수 표현법 이해하기

    visual studio code에 .c 확장자 파일을 만들고


    # include <stdio.h>

    # include <windows.h>


    int main(void){

    system("pause");

    printf('%d\n',1212);

    system pause;

    }


    위와 같이 적어준다. 그리고 cmd 창에서 이 파일을 실행해본다.

    stdio.h는 standard input, output의 줄임말로 컴퓨터의 표준 입출력을 담당하는 모니터와 키보드가 할 수 있는 일을

    시키는 함수들을 사용할 수 있게 하기 위해 미리 불러와야한다.

    include가 import 같이 불러오는 일을 하는 거라고 생각하면 된다.

    <stdio.h>를 불러오기 않으면 printf 기능을 쓸 수 없다.


    windows.h 또한 시스템 입출력에 관여하는 것으로, 이게 없으면 system이라고 썼을 때,

    system이 무엇인지 찾이 못한다.


    + h는 header의 줄임말로 헤더 파일들이라는 것을 의미

    헤더파일은 일종의 메뉴판처럼 생각하면 되고, 실제 함수들은 다른 곳에 들어가 있다!

    내가 필요한 printf, sum...이런 애들의 이름만 헤더 파일에 모여있다.

    http://programfrall.tistory.com/20


    그리고 메모장에 다음과 같이 작성해본다.


    1234

    한글


    HxD (헥스 에디터) 라는 프로그램을 사용하면 내가 만든 파일을 컴퓨터가 이해하는 언어로 열어볼 수 있다.

    (HxD 화면 예시 출처: http://wiinemo.tistory.com/1214) - 나중에 메모장에 넣은 결과물로 사진 대체할 것

    숫자는 0~9까지 간 다음에 10부터는 알파벳으로 표현한다. 10은 A가 되고, 쭉 가서 15번지는 F가 된다. F다음에는 10으로 표현한다.

    이건 16진수 표현법이기 때문에 10이 나오면 16번지라고 이해할 수 있을 것이다.


    Q. 왜 100의 절반이 80?

    123 = 3 x 10^0 + 2 x 10^1 + 1 x 10^2 일반적 10진수 표현방법

    0x123 = 3 x 16^0 + 2 x 16^1 + 1 x 16^3 이것은 16진수 표현방법

    0xFF = 15 x 16^0 + 15 x 16^1 + 0x 16^2 이기 때문에 1만 더해주면 FF에서 100으로 넘어가게 된다.

    0x80과 0x80을 아래로 더해보면 0x100인데, 8과 8은 더해서 16이지만 16은 표현할 수 없으므로 10이 되는 것이다. 그러면 한 자리가 올라가게 된다. 80과 80을 더하면 100이 된다.


    인코딩

    숫자 4개를 표현한 후에는 0D 0A가 나타나는데 이것은 줄바꿈을 의미한다. 윈도우에서는 0D 0A라고 하고 리눅스에서는 0D라고만 한다.

    그런데 HxD에서 "한" 위치에 보이는 숫자는 python에서 ord("한") 이라고 쳤을 때 보이는 숫자와 다른데, 그것은 인코딩이 다르기 때문이다.

    아마 인코딩 방법인 ANSI와 euc-kr의 차이일 것으로 추측된다.


    그리고 또 파일을 utf-8로 바꿔서 저장해보면, 이번에는 ED라는 것이 등장한다.

    일반적으로 숫자는 0x30 ~ 주소값을 가지고 있고, 대문자 영어는 0x41~ 이고 소문자 영어는 0x61~이다. 아스키 코드는 0x7F ( =127 ) 까지만 문자가 담겨있다. (아마 7bits라서 (2^7 = 128) 0~127까지 표현할 수 있는 걸로 추측된다) 그 뒤에 0x80부터 나머지 80 정도 칸이 비어있는데, 그걸 다 채워도 16진수로는 0xFF 이후로는 더이상 담을 수가 없다. 80+80 은 100이 된다. (16진수라서 16이 되면 위로 하나 넘어간다) 그래서 다른 문자열을 표현하려면 확장문자를 표현하는 ED를 붙여준다. 영어는 한 바이트로 표현이 되지만 한글은 두 바이트가 필요하다. 그래서 ED가 붙으면 뒤로 두 바이트가 더 있다는 것을 알게 된다. 그러면 한 바이트로 숫자를 표현하고, 두 바이트로 글자를 표현하고 이런식으로 달라지는 것을 멀티바이트 인코딩이라고 한다. 반대로 0x0030 -> '0', 0x0061 -> 'a' 무조건 이렇게 표현하는 것을 고정 인코딩이라고 부른다.


    - ED는 extended digit의 줄임말인가?

    - 아마 파이썬은 고정바이트 인코딩

    - 0x0030이면 숫자는 표현하는데 제한이 있나? 가 아니라 숫자는 어차피 한 바이트만 차지하는 0~9까지밖에 없고 나머지 자리에는 다른 문자, 기호들이 들어가있다.


    문자열 인코딩 개념 정리

    http://onlywis.tistory.com/2


    멀티바이트 인코딩과 고정 인코딩을 결정하는 것은 디코더가 한다. 디코더가 무엇이냐에 따라 달라지는 것이다.

    대표적인 인코딩 방식은 다음과 같다.

    ANSI

    UTF-8: 제일 많이 쓰고 영어랑 같이 나타낼 때 편하다

    CP949: 한글만 표현할 때 사용

    ≒MS949: CP949와 동일하게 인코딩, 디코딩을 해도 오류가 나지 않는다.


    아마 CP949는 멀티 방식이라 오류가 많이 나는 것으로 알고 있다. 영어는 UTF-8이 호환이 잘 된다. 그래서 뭔가 잘 모르겠는데 밤샘을 하고 싶지는 않다 하면 UTF-8을 선택하면 된다. 엑셀은 CP949로 기본 인코딩이 되고 MAC은 UTF-8로 되고... 그런식이다.


    인터넷 데이터랑 디스크에 저장할 때도 모두 인코딩이 필요하다. cf) 출력, 저장할 때 쓰는 cmd는 윈도우의 코어랑 이야기하는 shell이다.


    고정은 A | B | C |가 여기라는 걸 안다. 하지만 멀티는 모른다. C 다음에 끝나는 지점이 저기라는 것을 모른다. 고정의 단점은 용량을 많이 차지한다는 것이지만 알기가 쉽다.


    예를 들어, 0X0061 |    |    |    | 이런 식으로 되어있다면 처음 접근 주소에서 일정 바이트를 더해서 4번째 주소로 100% 접근 가능하다.

    하지만 가변의 경우 A |   |   |   |   | 뭐가 들어갔는지에 따라 네번째 문자의 위치가 달라진다. 가변은 하나하나 읽어야 알기 때문에 연산이 많다. 연산 횟수가 다르다. 고정은 연산 횟수가 적다. 그래서 UTF-8은 고정이 되어 있으니 더 빠르고 잘 된다. 밤샘하지 않는다! 여기서 말한 주소는 메모리 주소일 수도 있고, 하드디스크 주소일 수도 있다.


    메모리와 데이터 이해하기 (리버싱)

    [Disk       ] * 헥사에디터 화면에 보면 file offset이라는 내용이 있었는데, 거기있는 데이터들이 디스크에 저장된 애들이라는 걸 뜻한다.

    [File offset]

    |  |    |  | 이런 선을 BUS (버스) 라고 부른다.

    [Memory]

       |   | 이것도 BUS이다. 64개의 버스 선이 있으면 64비트 컴퓨터가 되는 것이다. (64비트와 32비트를 결정)

    [CPU] 


    * 선이 많으면 통신이 빠르다.


    [CPU] 에는 ㅁ ㅁ 여러 개 레지스터가 달려있다. 서로 간 연결이 된 레지스터가 있고 연결되지 않은 레지스터가 있다. 범용 레지스터는 아무때나 쓸 수 있다.


    헥사에디터로 까보면 E0 03 2... 이런 식으로 가는데, E0은 어셈블리어이다. CD80 이런 애들이 보이는데 0x30이 숫자, 0x41이 A 0x61이 a이면 26을 더해봤자 80이 되지는 않는다. 이런 애들이 박혀있는 것은 인코딩을 UTF-8로 바꿔도 뭐가 나오지 않는다. 이것은 CPU 명령어이기 때문이다! CPU instruction이라고 한다. CD80이것 자체가 어셈블리어이다. INT80은 interrupt의 줄임말로 멈추라는 뜻이다. (software interrupt) print하는 거에 해당하는 어셈블리어도 있다.


    메모리와 저장공간을 볼 수 있는 것을 디버거라고 한다. 다음은 x64dbg 의 예시 화면이다. 64비트 프로그램을 여는 디버거이다. x32 dbg도 따로 있어서 32비트 짜리는 여는 법이 다르다.

    (x64dbg 화면 예시 출처: http://reverseengineeringtips.blogspot.com/2015/01/an-introduction-to-x64dbg.html)

     

    화면 구성은 <기계어>  |   <어셈블리어> 이런 형태로 되어있다. 어셈블리어 중에서 Extended instruction pointer는 다음에 실행해야할 명령어가 존재하는 주소의 값이 저장된다. (http://securityfactory.tistory.com/182) 그래서 'E8 주소' 이런 식으로 적으면 그 주소가 적히고 해당 주소로 이동하게 할 수 있다. 주소 말고 앞뒤로 이동하게도 할 수 있다. 위에부터 순차적으로 메모리상의 코드를 따라가다가 어셈블리어를 만나면 해당 주소로 이동하는 것이다.


    그리고 주소에서 쌓인 값은 스택에 거꾸로 쌓여 올라간다. 값이 저장되어야 Printf에 빵! 하고 출력될 것이다. printf는 가변길이 함수라서 printf("%d. %d", 3.5); 이런 식으로 인자 3개도 가능하다. 그런데 첫 번째 인자가 제일 마지막에 들어가 있다. 그래서 자료구조의 스택이 필요한 것이다. 밑에붙어 쌓아놓고 위에서부터 하나씩 빼갈 것이기 때문이다.


    지금 주소값은 8자리로 되어있다. 4 byte니까 4 x 8 = 32 bit이다. 2^32로 표현되는 것인데, (옛날에는 16비트컴이 있었다) 2^32는 4기가 = 42억이다. 주소가 4 기가 바이트만 인식할 수 있는데, 그것을 넘어가면 인식하지 못한다. FFFF = 11111인데 맨 앞자리가 1이면 음수이다. 그러면 뒤로 가는 것을 뜻한다. MSB는 most significant bit의 약자로 부호를 결정한다. 1이 세팅되면 음수를 뜻하고 0이면 양수를 뜻한다. 그래서 주소값은 4GB를 표현할 수 있어도 -2GB를 뛰거나 +2GB로 뛰어서 이동하게 된다. 조금 뛸 때는 상대적인 주소 (지금으로부터 앞, 뒤 이런식) 로 이동할 수 있는데, 많이 뛸 때는 절대적인 주소로 이동해야 할 것이다. 32 비트 CPU인데 만약 OS가 64비트이다 하면 가상의 주소를 만들어내야 하기 때문에 느려지게 된다. 


    32비트 컴퓨터는 어차피 4G 까지밖에 인식을 못하기 때문에 (메모리를) 더 꽂아도 소용이 없었다. 그런데 64비트가 되면 더 꽂을 수가 있다. (키로/메가/기가/테라/페타/...) 2의 64승은 진짜 크다! 더이상 컴퓨터가 어떻게 되도 상대주소값으로 다 표현이 가능하다. x86은 32비트를 의미하고 x64는 64비트를 의미한다.


    파일을 다시 64 비트로 컴파일하고 새로 열었다. 메모장으로 열었을 때 "MZ"로 시작하면 프로그램이라는 것을 의미한다. "PK"로 시작하는 것은 apk 파일인데, zip 파일이랑 똑같은 것이다. 악성 코드를 열어봤는데 안에 MZ를 품고 있으면 아 이상한데 실행파일이구나?? 하는 것을 알 수 있다. 그리고 디버거에서 아까랑 달리 오른쪽 상단에 레지스터 개수가 늘어난 것을 볼 수 있다.


    main에 .reloc이라는 것이 있는데 이것은 주소를 재배치해준다. 재배치한 값이 reloc에 저장이 된다. <주소 p File> | <Data> 이렇게 생긴 창을 찾아가야 reloc을 볼 수 있다. 20억 = 2 기가바이트인데, 운영체제가 2GB를 쓰고, 우리가 나머지 2GB를 쓴다. reloc을 쓰는데 2 가지 이유가 있다. 1) 보안상의 이유로 재배치를 해준다. 해커가 데이터가 있는 주소값을 너무 쉽게 알지 못하도록 2) 기능상의 이유가 있다. 프로그램을 불렀는데 영역을 추가하고 싶으면 .reloc을 써서 재배치를 다 아래로 내려주면 영역이 늘어난다. 


    Extended stack point라고 지금 push에 들어가 있는 pointer가 있다. 준비된 데이터가 스택 포인트에 있다는 것을 알려준다. EIP는 메모리에서 현재 주소 (명령어가 어딘지)로 메모리상에서 어디있는지를 가리키고 있는데, ESP는 스택의 어디를 가리키고 있다. ESP를 EBP (Extended base pointer)에 넣는 동작을 해서 이제 밑에 것을 가리키게 된다. A, B, C, D는 범용 레지스터로 아무데나 다 쓴다. EBP, ESP를 봤고, ESI는 주로 문자를 복사할 때 쓴다. (Extended Source Index)이고, EDI는 목적지의 주소를 말한다. (Extended destination Index) 


    문자열을 복사하면 이런 식으로 복사가 되어야 한다.

    <Source>           <Destination>

    ㅁ ㅁ ㅁ ㅁ               ㅁ ㅁ ㅁ ㅁ 

    ESI                            EDI

    ESI에 있는 것을 읽어서 EDI에 넣고, 그다음 ESI의 주소값을 증가시켜서 읽어서 하나 넣는다. 숫자는 범용 레지스터에서 다루고 문자는 얘네들로 다루도록 한게 원래 설계된 것이다. 숫자는 int, double, float 형으로 한 덩어리만 복사하면 되는데, 문자열은 길이가 얼마가 될지도 모르고 문자는 0x6164...쭉 가다가 00 만나서 null 바이트를 만나야 끝나는데, 계속 길어지니까 언제 끝날지 모른다. 통째로 복사할 수 없으니 이렇게 하나씩 복사하도록 설계된 것이다. 


    기계랑 완전 맞닿아 있는 부분이라서 기계어라고 부른다. Opcode = 어셈블리어이다. 동사, 목적어 중에 동사라고 생각하면 된다. E8 은 new call인데, E8 주소 이렇게 쓰면 이동해라, 주소 이렇게 되는 것이다. 반도체에 이렇게 설계를 해놓았다. 이전 컴퓨터는 16비트라고 했는데, 레지스터가 A x 16 이었다. 그런데 지금 본 것은 EA x 32 크기를 봤고, 여기서 더 나아가면 64 비트에서는 RA x 64 이런 식으로 표시한다. ESP, EBP도 RSP, RBP 이런 식으로 표현된다. 그리고 특수목적의 레지스터가 더 들어간다. 32 비트 레지스터에서 float과 double (실수)이 있을 때, double은 32비트를 다 쓰고 float은 32비트의 반만 쓴다. 그래서 다 안 쓰이기 때문에 추가적인 명령어가 들어가게 된다.


    Little endian vs. Big endian

    Little endian 방식은 일반적인 PC에 많이 쓴다. Intel에서 이런 식으로 저장을 한다. 반면 Big endian은 IBM에서 이런 식으로 저장을 한다. Little endian은 한번 뒤집으니까 속도가 느릴 것이다. 서버와 PC의 차이점이라고 볼 수 있다. Big endian은 IBM 컴퓨터나 서버 같은데에서 웹 통신할 때 값을 그대로 쏴준다. 속도가 빠르다. 먼저 Little endian 방식을 보면 캐릭터는 저장하면 하나하나 들어가는데 숫자는 거꾸로 들어간다. 캐릭터는 뒤집을 공간이 없고 숫자는 뒤집을 공간이 있다. 

    00 00 04 BC 를 little endian 방식으로 넣으면

    BC 04 00 00 이 된다. (BC 문자 아님 ㅋㅋㅋㅋ !!!! 숫자임!!!!! 지금 숫자가 04/BC가 BC/04로 뒤집힌 거!!!)

    이렇게 뒤집으면 실수를 해도 끝엘 잘라버릴 수 있으니까 intel은 이런 방식을 사용한다. 그러나 IBM은 굳이 그렇게 해야 하나 뒤집기가 불편하다 해서 4 바이트의 데이터가 있으면 (실제 숫자 1212) 뒤집지 않는다. 문자가 뒤집히지 않는 이유는 문자는 1 바이트 형태이기 때문이다. 

    a b c d

    61 62 63 64 가 있을 때 big endian 방식도 little endian 방식도

    61 62 63 64 그대로 나온다. 문자는 1 byte가 하나이므로 뒤집어도 어차피 그것 그대로이다. 61을 뒤집으면 61인 것이다. (하나를 뒤집어봤자 하나...) 그런데 int는 4 byte라서 뒤집을 수가 있다.


    해킹의 기초

    여기서 해킹의 기초가 나오게 된다. 디버깅이 가능하다는 건 프로그램을 조작할 수 있다는 것이다. (1) 디버거를 이용해서 print 함수의 %d에 들어갈 것을 BCBC로 바꿔주면 BCBC에 해당하는 48316이 대신 출력이 되는 걸 볼 수 있다. 


    * 이런 식으로 (악성) 코드를 분석하는 것을 리버싱이라고 한다.


    OA: line feed

    OD: carriage return (이건 첫부분으로 포인터를 돌아가게 하는 것이다)

    이걸 합치면 한 라인을 다 끝내면 내려가고 내려간 줄에서 제일 앞으로 다시 가는 것이다. 그래야 다음줄 첫번째부터 읽으니까!


    윈도우는 이렇게 표현방식을 쓰는데 리눅스면 OA만 쓰면 다 한다. (지금 코드에서 원래 OD OA인데, OA만 보이는데 그건 아마 컴파일러 최적화 기능이 작동한 것 같다)


    (2) I'm groot를 어딘가에 써 놓고 그 주소값을 %d에 들어갈 주소값에 대신 써준다.그러면 I'm groot가 출력된다.


    (3) pause 대신 cmd.exe를 넣으면 관리자 권한을 얻을 수 있다. 그러면 dir 을 써서 파일들을 카피한다거나가 가능하다. system이라는 것은 command 창을 말한다. 


    + 빠른 포맷은 원래 데이터가 들어있는 주소를 그대로 둔다. 반면 느린 포맷은 000으로 초기값을 다 설정하니까 느린 것이다. 그래서 빠른 포맷은 데이터가 남아있어서 보안에 취약하다.


    리눅스나 맥도 이런 식으로 해킹이 가능하다. /bin/bash 혹은 /bin/sh 에 접근하면 된다.


    printf가 원하는 방식은 (%s, "abcd")일 때 이것을 해석해서 s가 나오면 뒤에 포인터를 읽어오라고 시키고, %d면 뒤가 숫자인 것이니까 그대로 스택에 숫자가 들어간다. 


    visual studio code 를 다음과 같이 작성한다. (중간 몇 줄 생략됨)

    # include <windows.h>

    int main()

    {

    MessageBoxA(Null,"제목입니다","내용입니다,",0);

    return 0;

    }

    그리고 코드가 달라짐에 따라 디버거에서의 내용도 달라진 것을 확인한다.



    메모리의 작동 방식

    * Disk와 메모리 사이 연결선, 버스가 길기도 하고 원래 Disk가 느려서 둘 사이 데이터 전송이 느리다. CPU와 메모리 사이에도 연결이 느리다. 길이가 긴 버스는 저항이 세니까 전송이 느릴 수밖에 없다.


    또한 메모리 반도체는 기억을 저장하는 방법이 flip flop 방법을 쓴다. flip flop은 전자구조인데 XOR이다. 켜져있을 때와 꺼져있을 때의 상태가 바뀌어서 달라진다. 한 번 지나가면 달라진다. (그래서 메모리가 덮어씌워지는 것. 꺼지고 켜지는 것은 아마 부품을 말하는 것 같다.) 전력이 끊겨도 flip flop에 무슨 프로그램이 돌아가는지 덤프가 뜬다. MZ, PK... PDF 로 파일들을 찾을 수 있다. 복구하기 어렵게 만들려면 암호를 걸어서 암호화를 해야 한다.


    Disk는 자기데이터 방식을 사용한다. 하드디스크가 느린 이유는 플로피 디스크는 진짜 CD에 긁으면서 저장을 했다. 아마 지금도 자기 유도 방식으로 왔다갔다 하면서 물리적으로 쓰고 있을 것이다. 물리적인 이유로 느리다.


    Disk에 저장되면 프로그램이고 메모리에 올라가면 프로시저라고 부른다. 이걸 CPU가 하나씩 맛보고 즐기고 한다. CPU = IC칩 인터그레이트 서킷이다. 좋은 재료를 써서 성능을 높인 것이다. (메모리이지만) 반도체를 적층을 많이해서 밀도가 높아서 성능이 빠르다. 그걸 삼성이 잘한다. 나노미터 단위로 20층 단위로 쌓는다고 한다. 


    Dos는 한 번에 하나씩 밖에 일을 못한다. 그런데 윈도우에 어떻게 창이 여러개 보일까? 디스크에 복사를 하기 때문이다. 시분할을 할 수 있기 때문에 멀티 스레딩도 가능해진다.


    CPU - <컨텍스트 스위칭> - 메모리 - <페이징> - 디스크 과정이 이루어진다. 

    CPU에 있는 걸 메모리에 저장했다가 왔다가 갔다가 하면서 동시에 여러 작업이 되는 것처럼 할 수 있다. 메모리와 디스크도 마찬가지.

    프로그램 안에 CPU와 레지스터 내용이 저장된다. EIP는 메모리에서 다음에 어떤 걸 할지를 저장하는 것이다. 프로그램마다 할 장소가 다 있는 것인데, 거기에 해커가 EIP를 바꿔버리면 다른 주소로 이동하게 되고, 다른 주소에 가서 시스템 권한을 얻도록 할 수 있는 것이다.


    CD 80, INT 80 (Interrupt 80) 은 시스템 함수 그자체였다. c는 0x63이고, d는 0x64이고... 이런식으로 system('cmd.exe') 이렇게 shell 코드를 직접 적어줄 수가 있다. INT80 0x63 0x64 ... 이런 식으로... 리눅스는 CD80 대신에 /bin/bash/나 /bin/sh에 해당하는 코드를 넣어준다. 


    CPU가 인텔거니까 어셈블리어를 찾으면 IA32는 32비트 운영체제의 인텔 아키텍처, CPU 아키텍처로 찾아보면 된다. 1byte로 모든 레지스터를 나타내기 힘드니까 동사가 길어질 수 있는데 찾아보니 64비트는 구글에서 IA64 문서를 찾아서 열어보면 거의 똑같다. 


    opcode map이라는게 있는데 appendix B를 보면 된다. jump [ 주소 ] -> [CPU] 넘어가는 것을 fetch, 실행한다고 한다. CPU에서 jump가 가져온 코드가 가리키는 포인터로 바꿔야 하고 그 주소를 EIP에 넣어준다. 이미 명령어대로 작동할 수 있게 회로가 설계되어있다. (CPU 1 clock, 한 클럭에 이렇게 돌아간다)


    printf("%d\n",1212) 이것을 실행하면

    push 04BC 가 들어가게 되고, (숫자 1212가 스택에 들어간다)

    push 0x주소 (이게 pointer이다) 이렇게 들어간 것을 볼 수 있다.

    char* pABC = "%d\n" 하면 우변에 있는 이것 자체가 주소가 된다. 그러면 컴파일 할 때 주소가 들어간다.

    printf(pABC를 하면 "%d\n"의 동작을 해준다 - 어차피 여기에는 주소가 들어가는 자리이기 때문.)


    배열과 호환이 된다는 이유가 pABC[3] 이렇게 하면 배열 자체도 포인터이기 때문이다. pABC 라고만 써도 이미 주소를 가리키고 있는 것이고 0번지를 뜻한다. pABC[3]은 int라면 한 단위에 4바이트니까 12 바이트 뒤로 가게 되고, 문자라면 3만큼 가면 3 바이트 뒤에 가게 된다. 


    * 아까 본 디버그 화면에서 메모리는 디스크에 내려온 값이 아니라 실제 메모리를 보여주고 있는게 맞다. 메모리에서 바로 모니터 출력이 가능하기 때문이다. 레지스터 부분은 CPU가 바로 모니터에 출력할 수는 없으므로 사실 컨텍스트 스위칭된 값이다. 컨텍스트 스위칭과 페이징은 운영체제 (=커널) 가 일을 한다. 운영체제가 메모리에 2G나 차지하고 있는 이유도 그것이 이런 일을 해주는 프로그램이기 때문이다. 컴퓨터가 켜지면 실행되는 프로그램이라 MZ의 한 종류일 뿐이다.


    그리고 CMOS와 BIOS (basic input output system)가 있는데, CMOS는 하드웨어와 관련이 있고 BIOS는 소프트웨어와 관련이 있다. CMOS는 Complementary metal-oxide-semiconductor이다. (CPU의 반도체라는 것!) BIOS는 각 회사마다 다른 CPU를 장착하기 때문에 소프트웨어도 다를 수밖에 없다. 그래서 DEL키를 눌러야 들어가는 곳, F12키를 눌러야 들어갈 수 있는 곳들이 있고 화면 구성도 다르다.


    처음에 컴퓨터가 켜지면 CMOS의 소프트웨어인 BIOS가 오류가 없는지 체크하고 온도를 체크한다. 아마 F70인가 하는게 제일 처음 실행되는데 처음에 운영체제가 어딨는지 찾아 실행하고~ 이런 식으로 쭉 실행이 된다. (Mater boot record, MBR이 맨 처음 읽히는 영역으로 설치된 OS 실행시키는 부트 로더를 포함하고 있다)

    댓글

Designed by Tistory.