어셈블리어

어셈블리어(Assembly)는 OPCODE테이블이라는 것을 참조하여 기계어와 1:1 대응이 되며[1] 직접 치환이 가능한 저급언어 중 하나이다. 이런 언어 특성으로 아키텍쳐에 따라 명령어의 형태와 구조가 달라지며, 기계 종속적이다. 즉 다른 프로세서 (예를 들면 ARM이라던가..)에서 프로그래밍을 하려면 그 아키텍쳐에 맞는 어셈블리를 알아야 한다.

극혐이다. IA-32를 드디어 다 뗐구나 했는데 대학 과제가 ARM...

많은 사람들이 어셈블리어를 어려운 것이라고 치부하지만 생각보다 어렵지 않다. 다만 외울게 많아.. 하지만 어렵지 않다는 건 어디까지나 익숙한 아키텍처의 경우에 한하고, 수많은 아키텍처 별로 명령어 집합이나 그 구현이 다 다르기 때문에 쉽다고 예단할 수만은 없다. 보통 x86 IA32 계열의 명령어 셋을 배우고 쉽다고 느낄 수 있지만, RISC 계열의 셋이나 아니면 파이프라인 구성 등을 고려해서 디자인하는 경우 매우 복잡해지기 마련이다.

장점[편집 | 원본 편집]

  • 가독성

위에서 밝혔듯이 아무리 기계어와 1:1대응이 된다고 하더라도 프로그래밍 언어인 이상 기계어보다는 확실히 읽기가 쉽다. 8B ECmov ebp,esp 정도로 바뀌는 것이지만 숫자의 나열보다는 쉬운편.

  • 주석처리

기계어에는 주석을 달 수 없지만 어셈블리에서는 ;(세미콜론)으로 주석을 달 수 있다는 것도 기계어와의 큰 차별점이다. 겨우 주석가지고 뭘 그러냐 싶겠지만 프로그래밍 경험, 그중에서 특히 팀 프로젝트 경험이 있는 사람들은 모두 알겠지만 몇 천줄이 넘어가는 대규모 프로젝트에서의 주석은 필수적이다.

  • 강력한 Low-Level 접근성

어셈블리어는 모체 자체가 기계어기 때문에 H/W에 직접적으로 접근 할 수 있다. (애초에 기본적으로 어셈블리에서 주어주는 임시공간이 CPU안의 레지스터라는 메모리다.) 그 특징중 하나가 H/W Interrupt라는 것인데, 이 인터럽트는 Exception으로 대표되는 S/W Interrupt와 다르게 H/W의 기능과 역할 수행 등에 사용되는 인터럽트다. 어셈블리에서는 이러한 H/W인터럽트를 호출하는 방식으로 H/W의 기능수행을 직접 지할 수 있다.(어셈블리 코드를 보면 INT 00h라고 적힌게 바로 이 인터럽트다. 참고로 이러한 H/W 인터럽트들은 16bit real-mode에서만 작동하는 종류가 많다. 고급 어셈블 환경에서 인터럽트 호출하고 안 된다고 뒷목잡지 말자)

  • 직접적인 메모리 관리

사실 Low-Level 접근성과 비슷한 내용이지만, 약간은 다른 점이 있어 따로 서술한다. 일단은 C언어에서 메모리에 직접 접근을 하려면 불편하게 포인터(*)를 사용해서 접근 해야 하고, 한 JAVA쯤 되는 고급언어까지 올라가게 되면은 아예 메모리에 직접 접근을 할 수 있는 방법이 없다. 그에 반해 어셈블리는 포인터도 필요 없이 그냥 메모리 주소를 적어주면 바로 접근이 된다.
남들이 물어물어 메모리에 접근할 때, 주소 찍고 바로 접근하는 어셈블리!
또, 이러한 메모리 접근성이 있기에 어셈블리만이 짤 수 있는 프로그램이 있는데, 바로 운영체제이다. 그냥 간단하게 BIOS가 읽어오는 커널 시작영역에 코드 세그먼트를 때려박으면 그게바로 커널이고 자신만의 운영체제가 되는 것이다.

  • 최적화

모든 프로그래밍 언어들은 컴파일러를 거쳐 어셈블리/기계어 코드로 변환이 되게 되는데, 아무리 파서의 성능이 좋다 하더라도 기본적으로 기계다. 즉, 몇몇 알고리즘의 경우에는 개발자가 원하는 형태의 출력을 하지 않거나, 혹은 원하는 만큼의 퍼포먼스를 수행하지 못하는 경우가 많다. 이럴 때, 해당 부분을 인라인 어셈블로 처리해서 직접적인 프로그램 수행을 지시해줄 수 있다. 하지만 이러한 추세도 바뀌어 가고 있다. 요즘 컴파일러의 성능은 단순 번역을 넘어서서 개발자가 약간 퍼포먼스가 떨어지게 구현해도 직접 최적화까지 해주는 레벨이 되었다. 안타깝지만, 가면 갈수록 어셈블리 프로그래머의 살길은 좁아지고 있다는 것.

하지만 이러한 장점들 만큼이나 단점도 많다.

단점[편집 | 원본 편집]

  • 가독성

장점 란에서 이미 가독성을 들었지만 어디까지나 그건 기계어기준이지 고급언어기준이 아니다. 간략하게 C와 비교를 해보자. C언어의 경우 "Hello World"를 출력하려면

#include <stdio.h>
int main(){
    printn("Hello World\n");
    return 0;
}

이정도만 해줘도 충분하다. 게다가 알아들을 수 있는 영어 단어가 나오기 때문에 알아듣기도 쉽다. 반면 어셈블리어(ARM 어셈블러 기준)로 작성할 경우

1000 REM Hello World using a mix of BBC Basic and ARM assembler
1010 DIM org 100
1020 OS_Write0 = &2
1030 FOR pass=0 TO 3 STEP 3
1040 PROCasm(pass,org)
1050 NEXT pass
1060 CALL org
1070 END
1080
2000 DEF PROCasm(pass,org)
2010 P%=org
2020 [ OPT pass
2030 ADR    R0, message
2040 SWI    OS_Write0
2050 MOV    PC, R14
2060 .message
2070 EQUS   "Hello, World!" + CHR$(0)
2080 ALIGN
2090 ]
2100 ENDPROC

와 같이 긴(...) 코드가 나온다. 한마디로 생산성이 개판에 수렴한다는 것.

소스코드의 줄 숫자에 따라 돈을 받아먹는 프로젝트에서 돈 받아먹기 좋다

  • 기계종속적

위에서 언급했듯이 '아키텍쳐에 따라 명령어의 형태와 구조가 달라지기 때문에' 아키텍쳐가 바뀔때마다, '거기에 맞는 어셈블리어'를 새로 배워야 한다.

  • 어렵다

기계어보다는 쉽지만, 여전히 CJava와 대비해서 어려운 편이다.

  • 유지보수도 어렵다.

읽기도 어려운데, 유지보수가 쉬울리 없다.

사용처[편집 | 원본 편집]

임베디드 시스템 등지에 사용된다. 이쪽은 C나 Java로 프로그래밍 하기에는 메모리가 부족한지라(여유가 있다면 C로도 작성은 하지만), 어셈블리어로 코드를 작성하게 된다.

참고문서[편집 | 원본 편집]

각주

  1. 단, "완벽히" 대응되지는 않는다. 어셈블리어를 변환하는 어셈블러의 특성에 따라 바이너리 코드가 달라진다,