어셈블리는 매우 저급의(? - very low things, 하드웨어 레벨의) 일들을 처리할 수 있다. :
여러분이 어셈블리를 사용하면, 특정 프로세서에만 있는 레지스터나 I/O 를 바로 접근할 수 있다.(you can access machine-dependent registers and I/O)
크리티컬 섹션 등에서 데드락과 같은 일을 야기할 수 있는 여러개의 프로세스 쓰레드들의 코드 동작을 매우 정확하게(!) 컨트롤 할 수 있다. 즉, 코드 하나하나의 동작을 모두 제어하고, 여러분이 생각한 대로 움직이게 할 수 있다.(역자 주: 물론, 여기에는 그만큼의 노력과 댓가가 따른다.)
일반적인 컴파일러가 제공하는 환경과, 생성하는 코드의 규칙들을 무시한 채 작업할 수 있다. 다시 말해서, 속도의 최적화 등을 위해 메모리 할당에 관한 규칙이나, 쓰레딩, 함수 호출 규칙과 같은 것들을 일시적으로 무시하고 프로그래밍 할 수 있다.
서로 다른 규약을 사용하는 여러개의 코드들 간의 인터페이스를 구축할 수 있다. (예를 들면, 다른 컴파일러들로 생성된 코드들이 상호 작용할 수 있도록 만든다든지, low-레벨 인터페이스가 상이한 코드들의 인터페이스를 통일한다든지 하는 일 말이다.)
일반적인 고수준 언어(c 나 pascal 같은)용 컴파일러로는 생성하기 힘든 특정 프로세서의 특수한(!) 프로그래밍 모드에 접근할 수 있다. 이를테면, 인터페이스 스타트업을 위해 프로세서의 16비트 모드를 사용한다든지, 펌웨어용 프로그램을 만든다든지, 인텔 컴퓨터에서 레거시 코드(legacy code)를 만든다든지 하는 일을 어셈블리를 사용해서 할 수 있다.
또한, 코드 최적화를 제대로 시키지 못하는 나쁜(!) 컴파일러의 코드를 직접(!) 최적화 시켜서 그런 컴파일러가 생성한 느려터지고 불필요한 루프나 루틴들을 매우 빠르고, 효율적인 루프로 바꾸어 줄 수 있다. (그러나, 매우 좋은 free 컴파일러들이 있다. gcc 처럼)
여러분의 하드웨어 설정에만 완벽하게 최적화된 코드를 직접 제작할 수 있다. 그럼으로써, 범용적인 (일반적인) 호환(?)을 위한 불필요한 군살을 여러분의 코드에서 뺄 수 있다.
만약 여러분이 새로운 언어를 만들고, 그 언어를 위해 컴파일러를 만든다면, (그런 일을 하는 사람은 몇명 안되고, 또, 자주 그러지도 않지만) 여러분의 컴파일러가 최적의 코드를 생산할 수 있도록 조정할 수도 있을 것이다.
어셈블리는 매우 저수준의 언어이다. (이진 기계어 인스트럭션을 그대로 심볼화 한것에 지나지 않는다.) 이것은 다음과 같은 의미를 가진다 :
어떤 프로그램을 처음부터 어셈블리 코드를 이용하여 작성하는 일은 매우 오래 걸리고도 짜증나는 작업이다.
버그가 발생할 확률이 매우(!) 매우 높다.
게다가 버그를 추적해서 잡아내기란 끔찍할 정도로 어렵다.
여러분이 작성한 코드를 이해하기도 어려울 뿐만 아니라 수정하기도 어렵기 그지없다. 즉, 유지 보수가 어렵다.
어셈블리로 코딩을 한 결과물은 현존하거나 앞으로 개발될지도 모르는 다른 아키텍쳐의 머신으로 이식할 수 없다.
여러분이 어셈블리로 최적화시켜 작성한 코드는 여러분이 개발한 타겟이 되는 아키텍쳐와 동일한 아키텍쳐를 가지고, 또, 동일한 설정을 하고, 동일한 환경을 가진 기계에서만 수행될 것이다. 예글 들면, 인텔 계열의 프로세서들(Intel 386, 486, Pentium, PPro, PII, PIII, PIV; Cyrix 5x86, 6x86, M2; AMD K5, K6 (K6-2, K6-III), K7 (Athlon, Duron).등) 만 보더라도 다들 프로세서의 디자인이나 그 외 여러 요소들(상대적 클럭 지연시간(?), 수행속도, 용량, 캐쉬, 램, 버스, 디스크, FPU 의 존재여부, MMX, 3DNOW, SIMD확장 등등... 나열하기도 힘들다)의 차이로 인해서 프로세서마다 또, 그 주변 환경에 따라서 완벽하게 다른 최적화 테크닉이 필요하다. 게다가 프로세서의 설계/디자인은 계속적으로 변하고, 바뀌고, 발전하고 있기 때문에, 방금 나열한 목록과 또한, 여러분이 최적화시킨 코드가 최신의(!) 코드가 되기를 바라는것은 말도 안된다.
게다가, 자잘한 세밀한 부분에 신경을 쓰느라 프로그램 전체의 알고리즘이나 설계에 신경을 쓰지 못할 가능성이 다분히 존재한다.
you spend more time on a few details and can't focus on small and large algorithmic design, that are known to bring the largest part of the speed up (e.g. you might spend some time building very fast list/array manipulation primitives in assembly; only a hash table would have sped up your program much more; or, in another context, a binary tree; or some high-level structure distributed over a cluster of CPUs)
알고리즘 설계를 조금만 바꾸어도 이미 만들어둔 어셈블리 코드의 전체를 다시 만들어야 할지도 모른다.
뭐, 표준 벤치마크 등, 엄청난 수행속도가 필요하지 않은 프로그램이라면, 상용 컴파일러들이 만들어내는 어셈블리 코드도 손으로 만든것 처럼 좋은 코드를 생산한다. gcc 도 상당히 좋은 컴파일러이다.
그리고, 컴파일러 뉴스그룹 (comp.compilers) 의 moderator 인 John Levine 이 말한 내용을 인용하겠다.
"컴파일러는 복잡한 자료구조를 다루기 쉽게 도와둔다. 그리고, 컴파일러를
사용한 프로그램은 그리 지루하지도 않으며, 게다가 매우 좋은 품질의 코드를 생산해준다."
"compilers make it a lot easier to use complex data structures,
and compilers don't get bored halfway through
and generate reliably pretty good code."
컴파일러들은 거대한 프로그램 전체에 걸쳐 함수들과, 모듈들 간의 인터페이스 코드 최적화와 같은 것들을 정확하게 수행해 준다.
요약하자면, 여러분은 어셈블리가 필요한 경우를 가끔 발견할 수 있을 것이다. 그리고, 어떤 경우에는 꼭 필요하지는 않아도 어셈블리로 코딩하는 것이 유용한 경우를 발견할 수도 있을 것이며, 여러분이 그렇게 느낀다면, 그렇게 하라. 단지, 다음 사항들을 명심하고, 그렇게 한다면 좋을 것이다. :
어셈블리 코드의 사용을 최소화하라
매우 잘 정의된 인터페이스 내부로 어셈블리 코드를 캡슐화(!)하라.
여러분의 어셈블리 코드가 보다 고수준의 언어패턴으로부터 자동적으로 생성된 코드인가? (예를 들면 gcc 의 인라인 어셈블리 매크로 등과 같은)
그 프로그램들을 어셈블리 코드로 번역한 후 비교해 보라
have automatic tools translate these programs into assembly code
가능한 만큼 코드들이 최적화 되었는가(have this code be optimized if possible)
위의 사항들을 잘 체크해 보고, 최적화된 좋은 코드를 생산하는 컴파일러의 back-end 를 잘 이용하라.
All of the above, i.e. write (an extension to) an optimizing compiler back-end.
비록 운영체제 개발과 같이 어셈블리가 꼭 필요한 것처럼 보이는 경우라 할지라도 위에서 언급한 내용들을 주의깊게 생각해 본 후에 어셈블리의 사용 여부를 결정하라
리눅스의 커널 소스를 한번 보도록 하라 : 리눅스의 커널은 필요한 정말 최소(!)의 어셈블리 코드만 사용되었다. 그 결과로 빠르고, 신뢰성있고, 포터블하며, 유지보수하기 용이한 운영체제의 코드가 생성되게 되었다. 게다가 둠과 같은 게임조차도 속도 향상을 위한 일부 매우 작은 루틴을 제외하고는 대부분 c 를 이용해서 만들어졌다는 사실을 항상 상기하라.