E D R , A S I H C RSS

기계어

last modified: 2015-04-03 10:00:19 by Contributors

Machine Code. 프로그래밍 언어의 하나. 언어라고 하기엔 거시기하다.

  • 상위항목: 프로그래밍 언어/종류
좋은 만 있다면 키보드가 매우 간단해도 된다(...) 그래도 백스페이스 키는 주지...

Contents

1. 개요
2. 배울 수 있는 방법
3. 기계어의 간단한(?) 예
4. 생산성
4.1. 어셈블리 vs 기계어
4.2. 생산성 vs 최적화
5. 여담
6. 픽션

1. 개요

인간에게 가장 난해한 프로그래밍 언어지만, 이건 재미를 위해서 만든 게 아니라, 모든 컴퓨터 작동의 핵심이다!

컴퓨터, 정확히는 CPU에게 던져주면 바로 해독할 수 있는 유일한 언어 되시겠다. 쉽게 말해 기계의 언어. 비트단위로 표기하기 때문에 01로만 표현된다. 그 때문에 간단한 연산문도 작성하면 옆으로 길게 늘어져 개떡같은 가독성을 자랑한다. 좀 더 보기 쉽게 16진수로 변환하여 보여주기도 하는데 압도적인 길이가 줄어서 마음에 안정감만 줄 뿐, 거지같은 가독성은 마찬가지이다. 어떤 기계어의 경우 2진수에서 16진수로 가도 오히려 가독성이 떨어지기도 한다. 물론 ASCII나 유니코드로 변환하면 이 거지같은 가독성은 극단을 달린다(…). 그리고 궁극적으로 코드를 던져줘도 "그래서 하고 싶은 말이 뭐냐?"란 반응이 나올 정도로 해독하기가 심히 골룸스럽다. 하지만 고대(그러니까, 컴퓨터 시대 초창기)에는 이걸 컴퓨터처럼 해독하는 작자들도 많이 있었다고 한다. 대표적으로 이 아저씨라거나. 이 의사분, 물론 이 분야의 원조 굇수기계어가 아닌 다른 언어를 쓰는 것조차 못마땅해 했다. 기계는 기계와 말이 통하는가보다

가독성은 0에 수렴하고 배우기도 힘들고 생산성도 심하게 낮다. 또 CPU 종류, CPU의 아키텍처에 따라서 같은 동작을 수행하는 코드라고 할지라도 완전히 다른 0과 1의 나열이 될 수 있기 때문에 이식성도 거지같다.[1] 간단히 CPU 바꾸면 기존에 작성한 기계어 코드가 안 돌아갈 수도 있다. 아주 기본적인 연산자들은 서로 호환이 되는 편이라서 운이 좋으면 돌아갈 수도 있으나 어지간한 수준의 프로그램들의 경우 호환될 확률이 한없이 0에 수렴한다. 이 때문에 CPU를 제작하는 업체에서는 새로운 CPU 아키텍쳐를 공개하고나면 기계어 코드를 함께 뿌린다. 일반인이 알아들을 수 있게 비유하자면, NDS 게임을 에뮬레이터 없이 PC에서 돌릴 수 없는 것과 같은 이치다.

프로그램 작동을 키보드 치는 것에 비유하자면, 기계어는 그걸 키보드의 특정 부위를 누르시오로 표현하는 것이라고 볼 수 있다. 예를 들어 "리그베다 위키"라는 문장을 치기 위해 ㄹ을 눌러야 한다면, ㄹ을 입력하라는 말을 "키보드 중앙에서 좌로 3cm 밑으로 0.5cm을 누르시오"같이 표현하는 것이다. 상식적으로 그딴 식으로 얘기하는데 누가 그걸 "아, ㄹ을 누르겠구나"라고 생각하겠는가(...) 게다가 키보드라는 게 크기도 제각각 모양도 제각각이므로 키보드를 바꿨을 때도 ㄹ이 그 자리에 있다는 보장이 전혀 없으며, 일일이 "키보드 중앙에서 좌로 3cm 밑으로 0.5cm"이라고 설명하기도 힘들다. 따라서 가독성도 거지같고 호환성도 낮으며 생산성도 거지같은 특성을 지닌다. 하지만 결국 ㄹ을 입력하려면 (최소한 그 키보드에서는) "좌로 3cm 밑으로 0.5cm 지점을 누르는" 행위가 반드시 필요하다. 따라서 기계어는 프로그램 작동의 가장 근본적인 부분인 것이다.[2]

유니코드아스키 코드같은 코드와는 또 다르다. 이런 코드는 데이터를 지정하는 일련번호에 해당하는 숫자를 정의한 거다.

사실 컴퓨터 아키텍쳐를 연구하는 사람이 아니라면 직접 접해볼 기회는 거의 없다. 다만 매트릭스에서처럼 영상에서 뭔가 디지털스러움(?)을 어필하고 싶을때 배경에 촤르륵 하며 흘려보내는데 쓰이긴 한다.

이 문제를 커버하기 위해서 등장한 것이 어셈블리어. 어셈블리어의 경우에는 모든 기계어 코드와 1:1로 대응되는 형태로 되어있다. 문제는 어셈블리어도 상당히 난해하고 생산성이 떨어지다보니 점점 사람이 보고 이해하기 쉽고, 생산성이 높은 프로그래밍 언어들이 개발되기 시작하였다,

2. 배울 수 있는 방법

컴퓨터공학과에서 컴퓨터 구조론 및 어셈블리어를 배우면 된다.

전문적으로 기계어를 가르치는 학교나 학원은 존재하지 않는다. 시대가 어느땐데 정 배우고 싶다면 해당 CPU제조사의 홈페이지의 매뉴얼에 아주 자세하게 서술되어있으므로 그걸 보고 공부하도록 하자.물론 영어다 CPU가 제공하는 인스트럭션(기계어 단위)중 자주 쓰는 인스트럭션 몇십개 정도를 외운다면 아주 불가능한 것은 아니다. 물론 어셈블러를 쓰는 것이 훨씬 빠르고 건강에 이롭다.

대학교에서 컴퓨터 전공이라면 컴퓨터 아키텍쳐에 관해 배울 때 맛만 보는 수준으로 배울 수 있다. 그리고 학교에 시스템 프로그래밍과 관련된 과목이 있으면 상당히 친숙해지게 된다. 시장 영향력이 강한 x86이나 ARM을 주로 다루는 편이다.

물론 16진수로 된 인스트럭션들을 생으로 보진 않고 번역된 어셈블리어를 통하여 공부하게 된다. 어셈블리어와 기계어는 1:1로 대응관계가 있기 때문에 어셈블리어를 공부하는 것만으로도 기계어를 알 수 있고 무엇보다 훠~~~얼씬 보기 편하기 때문에 일반적인 경우 기계어를 생으로 쓸일은 없다고 해도 과언이 아니다. 물론 전혀 없는 건 절대 아니다. 자신의 코드를 스스로 바꿔서 전염하는 다형성 바이러스를 분석하거나 제작(!)할 때 순수 기계어 포맷에 대한 지식이 필요하긴 하다. 더 접하기 쉬운 예를 들자면 에뮬레이터나 버추얼라이저를 구현하기 위해서도 필요하다. 각각의 아키텍처에 맞는 기계어 코드를 경우의 수에 따라 번역해줘야 하므로[3] 기계어로 모든 걸 코딩할 일은 없다해도 어쨌든 싱싱한 생 기계어를 쓰긴 써야 한다. 이런 것들을 하다보면 C언어가 세상에 존재하는것은 신의 축복이었단 사실을 깨닫게 된다. 물론 이 생각은 컴파일러를 배울때 깨진다(…).

3. 기계어의 간단한(?) 예

x = 10+2
y = x+4

이 표현을 MIPS라는 아키텍처의 기계어로 옮기면 다음과 같다.

001001 11101 11101 1111111111111000
001000 00001 00000 0000000000001010
001000 00001 00001 0000000000000010
101011 11101 00001 0000000000000000
001000 00010 00001 0000000000000100
101011 11101 00010 0000000000000100
001001 11101 11101 0000000000001000

토나온다.
가독성을 높이기 위해서 보통은 4자리씩 끊어서 16진수로 표현한다. 그래서 그렇게 써보자면 다음과 같다.

27BDFFF8
2020000A
20210002
AFA10000
20410004
AFA20004
27BD0008

보기는 좀 편하지만 그래봤자 여전히 뭔 소린지 알 수 없다.[4] 이걸 빠르게 읽어나갈수 있다면 당신은 머리안에 CPU가 장착된 자렘인일지도 모른다...

다음은 리눅스 환경, x86 아키텍쳐를 이용한 hello world 코드.출처(breadbox의 코드)

7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 02 00 03 00 01 00 00 00 35 40 B3 04 2C 00 00 00 00 00 00 00 00 00 00 00 34 00 20 00 01 00 00 00 00 00 00 00 00 40 B3 04 B2 0C EB 1C 62 00 00 00 62 00 00 00 05 00 00 00 00 10 00 00 48 65 6C 6C 6F 20 77 6F 72 6C 64 0A B9 4C 40 B3 04 93 CD 80 EB FB

이게 무슨 소리야!

4. 생산성

4.1. 어셈블리 vs 기계어

실상은 어셈블리어나 기계어나 속도는 똑같다[5]

부연설명을 하자면 프로그래밍 언어를 CPU에서 읽고 해독하려면 기계어로 번역해야만 하는데, 어셈블리어는 위에 언급했듯 명령어가 기계어와 1:1 대응된다.

즉, 성능을 위해 기계어로 된 프로그램을 최적화하는 거나 어셈블리어로 된 프로그램을 최적화하는 거나 결국 똑같다는 얘기. 때문에 최적화를 위해 어셈블리어로 코딩하는 일은 간혹 있지만 최적화를 위해 기계어를 쓰는 사람은 이 세상에 존재하지 않는다.뭐 에드삭(최초의 폰 노이만 구조 사용컴퓨터)수준 컴퓨터라면 몰라도 그리고 프로그래머들은 알겠지만 성급한 최적화는 만악의 근원이다. 진짜로.

4.2. 생산성 vs 최적화

현대에 기계어가 쓰이지 않는 이유는, 생산성이 낮기 때문이다. 쉽게 비유하자면, 현대의 고급 프로그래밍 언어는 포크레인 같은 것이며 기계어는 종삽 같은 수준이다. 땅을 파는게 목적이라면 굳이 포크레인을 내버려두고 모종삽으로 깨작깨작 거려야 할 이유가 없다. 물론, 모종삽이 필요한 상황도 있기는 있지만, 아쉽게도 현재로서는 매우 제한적이다. 아쉽다고?

일단 무엇보다도 그냥 딱 보면 알겠지만 타이핑해야 하는 문자의 개수가 어셈블리어나 고급언어 쪽이 훨씬 적다. 거기에 타이핑만 많으면 다행이고, 코딩 시 항상 나오는 불가항력을 고려하면... 안습. 한 마디로 CPU를 직접 제어해야 할 필요성 없이 복잡한 프로그램을 기계어로 짜는 것은 그냥 '잉여짓'이다.

심지어 c를 이용해서 프로그램을 짜도 처리속도차이는 기계어와 몇 배 정도밖에 안난다. NASA 미션 같이 극단적으로 낮은 성능을 커버하기 위해 어셈블리로 쥐어짜야하는 경우를 제외한다면, 같은 시간복잡도라면 컴퓨터 과학에서 몇배 차이는 크지 않다. 즉 0.003초든 0.006초든 충분히 빠르다.

오히려 0.006초를 0.003초로 만들기 위한 댓가가 3주 걸려 만들 것을 3달 걸려 만드는 것이라면 결코 이득이라고 할 수 없다. 그리고 초짜면 컴파일한 결과가 더 빠를 수도 있다. 오히려 3주 걸려 만들 것을 3일만에 만들기 위해 C언어보다 몇십배 느린 고생산성 언어를 쓰는 판국.

7,80년대에는 아직 어셈블리나 기계어를 직접 건드리기도 했는데 이 당시는 개인용 PC의 CPU가 느려터졌기 때문에 최적화를 할 필요가 있었던 것이다. 그리고 최근에는 컴파일러 기술도 발전했기 때문에 잘 모르면서 어설프게 손으로 최적화 하는 것보다 컴파일러가 만들어준 코드를 믿는 쪽이 더 낫다.

5. 여담

훨씬 복잡한 예제들을 보고 싶다면 계산기나 메모장의 실행파일을 텍스트 에디터로 열어보자. 메모장으로 열면 외계어 폭풍에 절로 몸사리 칠 것이다(……). 심지어는 C 처음 배울 때 만드는 HelloWorld 예제조차 열어보면 수십수백줄은 사뿐히 넘어주신다.[6]


6. 픽션

헛소리 시리즈쿠나기사 토모가 프로그래밍할 때 쓰는 언어가 이 기계어라는 설정이다. 쿠나기사 토모의 PC는 메인보드부터 자작이고 OS도 자작[7]이라, 기계어로 코딩하는 것도 딱히 이상하지는 않다. 쿠나기사가 사용하는 CPU가 현재 가장 많이 사용되는 IBM x86이나 암드 x86-64와 구조가 같을 거라는 보장 자체가 없기 때문이다. 아키텍처가 다른 CPU + 자작 OS 환경에서 본인이 어셈블리나 고급언어를 만들어 두지 않았다면 닥치고 기계어로 코딩하는 수밖에 없을 수도 있다. 근데 작중에서는 가상머신 쓴다...?

뭐, 사실 CPU를 자작한다는 말은 등장하지 않았기 때문에 반박하려면 얼마든지 반박할 수 있긴 하다.[8] 그런데 이걸 두고 현실성이 없는 설정이니 뭐니 하면서 비판하는 것은 다소 억지스러운데, 애초에 메인 보드를 자작하는 19세 여자아이라는 설정 자체가 현실성이 있는 설정이 아니라는 점을 상기하자. 애초에 헛소리 시리즈는 고증이 필요한 현실성에 크게 의미를 두는 작품도 아니다. 소녀를 암살단으로 키우는 고등학교 따위가 나오는 작품인데 뭐.

Warhammer 40,000의 설정에서 기계교 테크프리스트들은 Lingua-technis라는 이진 코드로 된 언어를 사용한다고 한다. 쉽게 말해 몸에 기계를 박아넣고 기계어로 대화한다. 자연어에 존재하는 오류 없이 복잡한 기술 자료를 파일을 보내는 것 처럼 아주 간편하게 통신할 수 있기 때문이라고 한다. 언어 자체에 ECC가 포함되어있다. 인간 컴퓨터 오오 외부인이 해독하려 해도 기계교 안에서만 내려져오는 전승을 통해 (2차대전 당시 나바호족 언어 암호마냥) 추가로 암호화가 걸려있어서 아직 문법조차 밖으로 알려지지 않았다고 한다.
----
  • [1] 당연히 operator도 다르고, operand가 2개인 아키텍쳐도 있고 3개인 아키텍쳐도 있으며, 어디서부터 어디까지가operator고 operand인지도 다르고, 애초에 16비트 아키텍쳐인지 32비트인지 64비트인지에 따라서 명령어의 비트 길이부터(!) 다르다. 어셈블리어 코드 형태로 보면 뭐 ADD SUB같은 기본적 명령어는 거의 똑같은 형태니 비슷하다고도 생각할 수 있겠지만 비트스트림으로 보면 이건 뭐...
  • [2] 여기서 더 나아가 'ㄹ을 누르시오' 수준으로 추상화시킨 게 어셈블리라고 볼 수 있다. 이를 더 사람이 알기 쉽게 '리그베다 위키 라고 입력하시오' 수준으로 나아간게 흔히 말하는 고급 프로그래밍 언어이며, 타자 숙련도에 의한 손의 빠르기, 타법의 효율성 등은 컴파일러의 성능이라고 볼 수 있겠다.
  • [3] 당연하게도 에뮬레이터나 버추얼라이저로 수행해야 하는 파일들은 친절하게 어셈블리어 따위로 구성돼있지 않다.
  • [4] 예로 든 MIPS 아키텍쳐의 경우는 각각의 2진수 필드들이 깔끔하게 4비트나 8비트로 떨어지지도 않기 때문에(MIPS의 R-type 명령어(가산 계열 명령어)들은 op필드 6비트, rs/rt/rd 필드 5비트, shamt필드 5비트, funct필드 6비트로 구성되어 있다.) 오히려 16진수로 표현하면 뭔 소리인지 더욱 알기 힘들다.
  • [5] Reversing: Secrets of Reverse Engineering 中.
  • [6] 하지만 엄밀히 말하면 실행파일(윈도에선 .exe 파일)은 기계어만으로 되어 있는 게 아니라, PE 이미지라고 해서 운영체제가 램에 올릴 때 참고하는 정보들도 함께 들어있는 파일이다. 이 외에도 여러 이미지 형태가 있다.
  • [7] 작중에서는 일단 가상머신을 함께 사용하는 것으로 보인다.
  • [8] 가령 자작 OS와 메인보드라고 해봤자 x86 구조의 CPU를 사용하고 적당히 리눅스 계열 자작OS를 사용하는 것뿐일수도 있고 그렇게 보면 고급언어를 얼마든지 사용할 수 있다. 그러나 자세한 설정이 나오지 않은 한 이렇게 생각하는 것 자체가 AD HOC이다. 작가가 기계어 쓴다는데 뭐 어쩌라고(...).

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2015-04-03 10:00:19
Processing time 0.1401 sec