본문 바로가기
  • 오늘도 신나게
나의 생각

소프트웨어의 정체를 이해하라.

by 앵그리선반장 2024. 8. 15.

흔히 프로그래머는 코딩을 통해 소프트웨어를 만드는 사람들을 말합니다.
그런 프로그래머들조차도 진정 소프트웨어가 뭐냐는 질문에 얼마나 올바른 답을 할 수 있을지 모르겠네요.
그래서 소프트웨어가 무엇인지 좀 더 명확하게 이해를 돕고자 글을 써 봅니다.

하드웨어라 하면 무엇이 떠오르나요? 
PC의 메인보드가 떠오르시나요? 아니면 SMPS 같은 회로물이 떠오르시나요?
하드웨어는 PC와 같이 소프트웨어를 구동시킬 수 있는 것과, 회로 자체적으로 기능을 갖는것 으로 크게 나눌 수 있겠습니다. 위 문장에서 PC 의 메인보드와 같은 하드웨어가 바로 소프트웨어를 구동 시킬 수 있는 것에 속합니다.
그렇다면 어떻게 소프트웨어를 구동시키는 걸 까요?
바로 CPU 가 있기 때문입니다.
모든 것은 이 CPU를 통해 이루어집니다.

CPU 구조

주변에 있는 메모리, 하드디스크, 그래픽카드, 사운드카드... 등등은 전부 이 CPU님? 의 일을 돕기 위한 부하들입니다.
뭐.. 최근에는 그래픽카드가 CPU 보다 권력이 좀 세지고 있지만, 어쨌든 CPU의 명령을 받습니다.
마치.. 왜소한 대통령의 명령을 따르는 거대한 군사조직과 같은 느낌? 

위 그림 CPU 구조를 보면 Arithmetic Logic Unit이라는 부분이 있습니다.
이 부분이 사실상 CPU의 핵심이며, 산술연산, 논리연산, 비교 연산, 비트이동 연산 등등 간단해 보이지만, 모든 연산의 최말단은 여기까지 와서 이 단순해 보이는 연산들로 처리가 됩니다.
그렇다면 어떤 연산을 이 ALU까지 보내고 다시 결과를 받아서 되돌려 주는 역할을 하는 무엇인가가 있어야겠죠?
그 일을 하는 것이 Control Unit입니다. 이 Control Unit 은 메모리에서 명령어를 가져와 해석하고 ALU에 연산을 요청한 후 결과를 다시 메모리에 저장해 주는 역할을 합니다.
명령어를 메모리에서 가져온다고 했는데요. 그렇다면 이 메모리는 무엇일까요? 하드 디스크 인가??
아닙니다. 바로 내부의 초고속으로 동작되는 레지스터 라 불리는 저장 공간입니다.
프로그램 카운터라는 것은 이 레지스터에 순서대로 저장된 명령어의 실행 순서를 가리킵니다.
이 프로그램 카운터가 가리키는 명령어를 Control Unit 이 가져와 분석하고 ALU로 보내는 것이죠.
그럼 DDR 같은 우리가 아는 메모리는 뭘까요?
바로 소프트웨어가 실행되면 먼저 DDR로 올라가 있다가 OS의 스케쥴링에 의해 스레드 단위로 나눠진 소프트웨어의 작은 실행 코드들이 이 레지스터로 옮겨져 실행됩니다. 즉 DDR 은 실행 소프트웨어의 임시 저장소입니다. 놀랍죠?
OS 나 스케쥴링에 대한 이야기는 일단 스킵하겠습니다.

자, 이제 여기서 아주 중요한 부분이 나왔습니다.
바로 명령어입니다.,
DDR에 저장되어 있던 소프트웨어의 코드가 레지스터로 옮겨지고 그것을 컨트롤러가 가져다가 ALU로 전달해 준다고 했는데요. 그때 컨트롤러는 명령어를 해석한다고 했습니다. 그렇다면, 명령어는 아무거나 넣어도 되는가?라는 의문이 듭니다. 예를 들어 "밥 먹어"라는 명령어를 컨트롤러가 해석할 수 있을까요?  아니겠죠. 이것이 바로 소프트웨어가 무엇인지에 대한 이해의 핵심으로 이어지는 입구입니다.
이 명령어는 놀랍게도 CPU 마다 다릅니다. 
이제는 누구나 다 알듯이 컴퓨터의 명령어는 0,1 로만 구성돼 있습니다.
물론 0,1 이 숫자료 입력되는 건 아닙니다. CPU 내부에서 사용되는 전압을 기준으로 일정 이상의 전압을 1, 일정 이하의 전압을 0으로 처리합니다. 이 부분은 회로에 대한 이야기니 여기까지만 하겠습니다.
어쨌든 컨트롤러 또한 0과 1의 조합으로 된 명령어를 받아 처리합니다.
예를 들어 100110110을 '더하기' 라는 명령으로 정했다면, 컨트롤러는 ALU 에게 이 명령어를 넣어주고 두개의 숫자 1100 , 0011 을 넣어 준다면 결과로 1111 이라는 값을 되돌려 받게 되는거죠. ALU 가 받아들이고 처리하는 이 명령어는 회로적으로 결정돼 있습니다. ALU 는 그저 100110110 을 받고 나서 다음에 입력되는 두 값을 더하고 되돌려 주는 물리적 동작을 하도록 전자회로가 구성돼 있는 것입니다. 이때 명령어 하나를 넣고, 다음 값을 넣고, 다음 값을 넣고,.. 을 구분 짓기 위해 타이밍을 맞춰줘야 하는데요 이것이 바로 시스템 클럭입니다. 
어쨌든 이렇게 정해진 명령어를 바로 "명령어 셋" 이라고 합니다. 모든 CPU 에는 이 명령어셋이 회로적으로 만들어져 있고, 소프트웨어는 바로 이 명령어 셋의 조합입니다.

명령어 셋은 전부 이처럼 0과 1로 구성된 도저히 한눈에 보고는 이해도 안 되고 기억도 못할 형태인데 어떻게 원하는 결과가 나오도록 저것을 순서대로 배열하는 걸까요? 놀랍게도 컴퓨터가 만들어진 초창기에는 어쩔 수 없이 이 0과 1로 구성된 명령어를 조합해서 원하는 명령을 만들어 내서 직접 입력을 했다고 해요.  무시무시합니다. 이것을 보고 기계어 라고 합니다. 
그런데. 이것은 인간이 도저히 사용이 불가능할 정도로 어려웠죠, 그래서 각 0과 1로 조합된 명령어들에 해당하는 알파벳 조합과 기호를 만들었어요. 이것이 바로 어셈블리 언어입니다.
일단 어셈블리 언어로 조합을 해서 원하는 기능을 만든 다음, 각 알파벳과 기호들을 매칭된 기계어로 바꾸면 원하는 기능이 구현되는 것 이죠. 이것이 바로 컴파일러의 시작입니다. 컴파일러는 변환이라는 말이죠. 
그래서 어셈블리 언어가 나온 후 소프트에의 발전은 가속되었습니다.
시간이 지나 어셈블리 언어조차조 학습이 어렵고 코딩이 쉽지 않다는 것을 알게 되었고, 보다 인간의 언어에 가까운 프로그램 언어들이 필요해졌습니다. 그래서 나온 것들이 현재의 C 언어 같은 하드웨어 제어에 최적화되었다는 언어입니다.

위에서 기계어는 어셈블리 언어와 1:1로 매칭이 되어 있다고 했습니다.  그렇다면 C 언어는 어떨까요?
바로 어셈블리 언어의 조합으로 만들어진 특정 명령어들과 매칭이 되어 있습니다. 1:1 매칭이 아닌 조합의 형태로 변환이 된다는 뜻이고 이것을 보고 추상화 라고 합니다.

예를 들어 
C 언어의 명령어 A = B+C;  를 어셈블리언어로 변환하면,
move eax, [B];
add eax, [C];
move [A], eax ;
와 같은 형태로 변환이 됩니다. 결과는 같지만 명령의 형태는 1:1 이 아니라 그 결과가 같도록 조합된 것뿐입니다.
이처럼 C 언어를 어셈블리 언어로 변환하는 것을 컴파일이라 하고 그 기능을 하는 것을 컴파일러 라고 합니다.
사실 위에서 어셈블리 언어를 기계어로 변환하는 것을 컴파일러라 했지만 그것은 사실 어셈블 이라 하고, 그 역할을 하는 것을 어셈블러 라 합니다. 필자가 위에서 말하고자 했던 것은 컴파일러의 시초가 바로 이 어셈블이라는 의미를 전달하고자 한 것입니다.

자, 이제 C 언어로 코딩된 코드는 컴파일러를 통해 어셈블리언어로 변환되고, 어셈블리어로 변환된 코드는 다시 어셈블러를 통해 기계어로 변환된다는 것을 알았습니다.
우리가 흔히 쓰는 C,C++ 언어는 바로 이런 것이고, 이 언어로 만들어진 코드의 조합이 결국 기계어의 조합으로 변환되어 실행 되는 것이 바로 소프트 웨어입니다.

그렇다면, 웹 프로그램은 뭔가요?
웹이 구동되는 원리를 전부 설명할 순 없지만, 하드웨어적 측면만 고려해 하나씩 아래로 내려가 봅시다.
예를 들어 HTML 코드 중 <hr>이라는 코드를 우리가 만들었다고 합시다.
이것은 웹 브라우저의 화면에서 가로로 줄을 하나 긋는 역할을 합니다.
그렇다면 HTML 코드가 최종적 기계어로 변환되어 실행되는 것일까요? 아닙니다.
바로 최종적 기계어로 변환되는 부분은 웹 브라우저입니다.
이미 웹 브라우저는 C/C++로 만들어져 컴파일 되고, 어셈블 되어 메모리에 올려진 상태이며,
<hr> 이라는 HTML 명령어가 들어오면 그 명령어를 웹 브라우저에서 해석 한 후 해당되는 명령어를 처리 해야 한다는 명령을 OS 에게 전달하며, OS 는 이 명령와 다른 소프트웨어의 명령어들중 어떤 것을 먼저 처리할지 스케쥴링 한 다음 작은 조각으로 나눠 메모리에서 레지스터로, 컨트롤러에서 ALU까지 전달하여 처리된 후 그 처리된 결과 값을 그래픽 카드로 전달하고 그래픽 카드는 그것을 전기신호로 바뀌어 화면에 한 줄 긋는 역할을 하죠.
사실 웹 브라우저가 <hr> 코드를 해석하는 과정,  os 에게 명령을 전달하는 과정과 os가 스케쥴리 하는 것 마저도 모두 최종 기계어 형태로 alu 를 거쳐 실행되어 집니다. 말 그대로 모~~든 동작 하나하나가 기계어로 변환되어 동작 됩니다.
단지 HTML 만이 웹 브라우저에서 해석 되므로 그 자체가 기계어로 변환되지 않는다는 뜻 입니다.
그래서 HTML 같은 웹 프로그램은 변환(컴파일) 되지 않고 해석(인터프리터) 되는 언어라 합니다.
웹 브라우저가 해석을 하죠. 실제로 기계어로 변환되어 기계(CPU) 를 동작 시키는 명령어 들은 웹 브라우저와 OS(Operating System) 에 포함된 명령어들 입니다.

이렇게 웹 프로그램은 웹 브라우저라는 소프트웨어를 통해 동작되므로 CPU를 직접 적으로 구동하지 않습니다.
이런 개념을 계층 구조라 하며,  레이어로 나눠 져 있다 라고 표현 합니다.  계층 간에 구분되어 직접적으로 영향을 주지 않는 구조를 말하지요.

최근 가장 많은 프로그래머는 아마도 웹 프로그래머나 모바일 프로그래머가 아닐까 싶은데요.
이 모바일 프로그래머들도 대부분 하드웨어를 직접적으로 제어하지 않는 상위 계층의 언어들입니다.
저같은 임베디드 프로그래머는 하드웨어를 직접 제어하는 소프트웨어를 만드는 것이고요.

여기까지 소프트웨어에 대한 이해를 돕기 위해 주저리주저리 해봤습니다.
도움이 되셨길 바랍니다.

댓글