1. X86(esp, ebp) ARM(sp)가 아직 초기화 되지 않는 경우
Compiler가 각 함수에 넣어주는 Code가 있습니다.
stack에 함수의 argument 등등을 push(Prologue), pop(epilogue)하는 code인데요.
esp, ebp가 초기화 되지 않아 stack을 사용할 수 없는 경우에는
push, pop을 사용할 수 없어,
반드시!!! assembler로 작성해야 합니다.
OS의 bootloader에서 esp, ebp를 stack용도로 쓰이는 메모리에 할당한 후에
비로소 C코드를 사용하는 것을 볼 수 있습니다.
ARM에서는 그래서 그런지는 모르지만,
Link Register라는 이전 함수의 return Address를 저장하는 register가 있습니다.
그래서 Stack Register가 초기화 되기 전에도,
C코드로 작성되었을 경우에도, 1 depth의 function call은 할 수 있어요.
그래서 Bootloader의 Code의 assembly어 code가 X86에 비해 ARM이 많이 적습니다.
2. Ring 0 Level, supervisor mode의 instruction을 사용할 경우,
(Bootloader의 함수나, System Call로 호출되는 함수들이 해당될 거 같습니다.)
cache 설정(flush, clean 등등)이나, MMU 설정 등등의 경우가 해당될 거 같습니다.
3. 함수 진입 시, Register를 Full로 사용하고 싶을 경우,
ARM에서, 함수 진입시, push로 register정보를 stack에 저장하는데요.
push한 register만 실제 함수 내에서 사용합니다. push를 하지 않는 register를
사용하면 corrupt되기 때문입니다.
C Compiler가 제공하는 prologue code(push)가 적은 register만 push해서 맘에 안들면,
직접 prologue code를 작성하는 거죠.
memcpy를 구현할 때 많이 씁니다.
ARM Insturction중에 ldmia, stmia Instruction을 이용할 경우요.
cache line이나, 이런걸 고려해서 작업하죠.
4. IO, SIMD Instruction등등의 경우
앞의 분들께서 탁월하게 설명하셔서..
책에서 읽었는데
운영체제가 아예 없는 상황에서 C의 main함수를 불러오는
스타트업 이라는 코드가 있다고 합니다.
그 코드는 주로 어셈으로 만든다고 책에서는 소개하고
있더군요.
고민이 많아 고민인 애늙은이 입니다.
하드웨어를 직접
하드웨어를 직접 제어하는 루틴들이 있습니다.
컨텍스트 스위칭, IO 포트 입출력, 인터럽트 처리 등입니다.
버스를 제어하거나 원자 연산을 하는 루틴들도 하드웨어 제어와 관련이 있습니다.
리버스 엔지니어링에서는 어셈블리 코드를 보는 일이 많다고 하고
영상 분야에서는 MMX, SSE 명령어 사용과 최적화에 사용됩니다.
범용 어플리케이션보다는 약간 특별한 케이스에 사용된다고 보시면 될것 같습니다.
물론 학습적인 목적도 있는데 이건 사람마다 다르게 생각하는 문제이므로
별도로 이야기할 문제인것 같습니다.
----
섬기며 사랑하면 더 행복해집니다.
개인 홈페이지가 생겼습니다 http://caoskernel.org
어셈러브를 개편중입니다 http://www.asmlove.co.kr
PC에서의 I/O는 대부분
PC에서의 I/O는 대부분 Memory mapped I/O이기 때문에 포인터를 사용하면 C에서도 얼마든지 컨트롤 할 수 있습니다. 리눅스 등에서는 ioctl같은 시스템 콜을 사용해도 되구요. :)
--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
어떤 값의 clipping
어떤 값의 clipping 같은 코드는 어셈블리로 할 경우 훨씬 효과적으로 만들 수 있죠. -1000 에서 1000사이의 값 중 0보다 작은 값은 0으로 255보다 큰 값은 255로 만드는 식의 경우죠.
mmx/sse등에 있는 min, max operator를 사용하면 아주 간단히 구현하고 빠르게 구현할 수 있습니다.
max( min( var, 255 ), 0 )
위 코드를 단지 2인스트럭션만으로 구현 가능합니다. 메모리에서 읽어들이고 쓰는 부분까지 하면 4인스트럭션이 되겠구요.
--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
mark
mark
제가 쓰는 것은 딱 두가지 이유입니다.
1. C compiler가 없는 경우
2. C library가 최적화되어있지 않은 경우.
2번의 경우가 상당히 많습니다. 수많은 architecture에 대해서 C library가 다 최적화되어있기가 힘드니까요.
C Compiler의 도움이 필요없는 경우 등등..
1. X86(esp, ebp) ARM(sp)가 아직 초기화 되지 않는 경우
Compiler가 각 함수에 넣어주는 Code가 있습니다.
stack에 함수의 argument 등등을 push(Prologue), pop(epilogue)하는 code인데요.
esp, ebp가 초기화 되지 않아 stack을 사용할 수 없는 경우에는
push, pop을 사용할 수 없어,
반드시!!! assembler로 작성해야 합니다.
OS의 bootloader에서 esp, ebp를 stack용도로 쓰이는 메모리에 할당한 후에
비로소 C코드를 사용하는 것을 볼 수 있습니다.
ARM에서는 그래서 그런지는 모르지만,
Link Register라는 이전 함수의 return Address를 저장하는 register가 있습니다.
그래서 Stack Register가 초기화 되기 전에도,
C코드로 작성되었을 경우에도, 1 depth의 function call은 할 수 있어요.
그래서 Bootloader의 Code의 assembly어 code가 X86에 비해 ARM이 많이 적습니다.
2. Ring 0 Level, supervisor mode의 instruction을 사용할 경우,
(Bootloader의 함수나, System Call로 호출되는 함수들이 해당될 거 같습니다.)
cache 설정(flush, clean 등등)이나, MMU 설정 등등의 경우가 해당될 거 같습니다.
3. 함수 진입 시, Register를 Full로 사용하고 싶을 경우,
ARM에서, 함수 진입시, push로 register정보를 stack에 저장하는데요.
push한 register만 실제 함수 내에서 사용합니다. push를 하지 않는 register를
사용하면 corrupt되기 때문입니다.
C Compiler가 제공하는 prologue code(push)가 적은 register만 push해서 맘에 안들면,
직접 prologue code를 작성하는 거죠.
memcpy를 구현할 때 많이 씁니다.
ARM Insturction중에 ldmia, stmia Instruction을 이용할 경우요.
cache line이나, 이런걸 고려해서 작업하죠.
4. IO, SIMD Instruction등등의 경우
앞의 분들께서 탁월하게 설명하셔서..
^^ 오랜만에 보니
^^ 오랜만에 보니 기분 좋네요. ㅋㅋ
제일 보편적(?)인
제일 보편적(?)인 예는 Context switching이 아닐까요.
레지스터 레벨의 백업/리커버리 작업이 필수적인데, C로는 불가능한거라고 배운 것같은데요.
그리고, 멀티코어 프로그래밍에서도 어셈블리로만 구현이 가능한 부분이 있는걸로 알고 있습니다.
예전에 병렬처리 과목 중에 발표수업이 있었는데, 방문교수 비스무리한 사람이 천문학 자료 처리하는 부분을
멀티코어를 이용한 병렬처리 프로그래밍으로 최적화하는데 어셈블리로 할 수 밖에 없었다고 이야기하더군요.
>> the SHIFT RIGHT operator
>> the SHIFT RIGHT operator
<< the SHIFT LEFT operator
는 C에는 있습니다만,
>>> the UNSIGNED SHIFT RIGHT operator
는 C에 없지 않지 않습니까?(참고로 java에는 있습니다.)
>>> 연산을 C로 하려면 몇번 비트 연산을 해주어야 하겠습니다.
하지만, 어셈블리는 모든 종류의 비트쉬프트 연산 명령어를 갖고 있습니다.
이런 연산도 있습니다.
32bit A 와 32bit B를 더해서 32bit C를 만들때, 이때 Carry up을 Detection 하려면 물론 C로도 어떻게든 가능은 합니다만, 저는 ASM 으로 Carry up 으로 조건분기하는것이 훨씬 더 간단했던 기억이 있습니다.
--
from bzImage
It's blue paper
from bzImage
It's blue paper
사실 어셈블리로만
사실 어셈블리로만 가능한 일들의 갯수를 따지면 꽤 많습니다.
하지만 대부분 컴파일러나 운영체제에서 매크로나 랩핑 함수로 지원하기 때문에
거의 느끼지 못하고 사용하는 것입니다.
예를 들어 윈도우 API에서 memcpy 와 같은 메모리 관련 함수는 MASM으로 만들었습니다.
그리고 세마포어나 뮤텍스, 스핀락의 원자 연산을 위해서 (비트 설정이나 정수 카운터 설정 모두)
버스 제어가 필요한데 이것도 어셈블리로만 가능합니다.
예전에 제 블로그에도 썼지만 처음 프로그래밍을 배울 때 고급언어만 배운 학생들이
사회에 진출해서 다양한 문제에 직면했을 때
이런 시스템적인 이해가 부족해서 어려움을 겪는 일이 많다고 들었습니다.
Great Code나 코드 최적화, 보안 관련 책들을 보면
어셈블리 언어를 조금만 알고 읽을 정도만 되면 쉽게 이해할 수 있는 것들을
추상적으로 설명하기 위해 길게 설명하는 경우가 있습니다.
앞으로 어셈러브 운영 방향을 보다 쉽게 어셈블리를 익히고
친숙해지도록 하는데 중점을 두려고 합니다.
EMU8086과 같이 좋은 툴도 조사하고 관련 문서나 소개 자료도 만들고요.
근데 왜 저는 갑자기 홍보를 하고 있을까요? 죄송합니다..;;
----
섬기며 사랑하면 더 행복해집니다.
개인 홈페이지가 생겼습니다 http://caoskernel.org
어셈러브를 개편중입니다 http://www.asmlove.co.kr
최적화를 위해선 필요할 수 있습니다.
꼭 SIMD등이 아니더라도, multi thread programming / multi process programming 등에서는 최적화를 위해 사용될 수 있습니다.
memory barrier, atomic operation, spinlock 등등을 구현하려면 OS 에서 wrapper 를 제공하지 않는다면 직접 assembler 로 작성할 수 밖에 없습니다.