grep -rni 문자열 시작위치

ex>  grep -rni stdio.h ./   
: 현재위치에서 하위디렉토리 포함하여 대소문자 구별하지 않고 stdio.h 가 들어간 파일을 찾아 파일명과 라인넘버를 출력한다.
ex>  grep -rni stdio.h /etc   
: /etc 위치에서 하위디렉토리 포함하여 대소문자 구별하지 않고 stdio.h 가 들어간 파일을 찾아 파일명과 라인넘버를 출력한다.
AND

cpu 스케쥴은 멀타프로레싱

'OS > OS 파헤치기!' 카테고리의 다른 글

5. 프로세스의 생성 사용 및 소멸  (0) 2010.09.22
4. 프로세스(process)?  (0) 2010.08.25
3. 하드웨어 보호(Hardware Protection)  (0) 2010.08.17
2장 컴퓨터 구조  (0) 2010.08.16
1장. OS란?  (0) 2010.08.12
AND

프로세스를 코드 상에서 생성 사용 소멸 하는 일은 그렇게 어려운 일은 아니다. 하지만 순차적인 프로그래밍 만을 해오던 나에게는 여러개의 프로세서가 돌아가는 환경을 이해하고 프로그래밍 하는 것에 익숙하지않다.
일단 글의 내용과 더불어 정리해 보자 
먼저 한개의 어플은 한개의 부모 프로세스로 시작을 한다 . main()자체가 부모프로세스를 생성시킨다. 
main()안에 fork()라는 콜은 자식 프로세스를 생성케 한다. 
exit() 라는 콜로 부모 프로세스 및 자식 프로세스도 소멸시킨다.

main() 
{ 
   printf("hello world\n"); 
   fork(); 
   printf("goodbye world\n"); 
} 

결과.

hello world 
goodbye world 
goodbye world
이제 다음으로 fork()로 자식 프로세스를 생성후 리던되는 값을 확인해 보도록하자.  코드를 보도록 하자
main(){
	pid_t		pid;
	printf("pid = %d \n", pid);
	printf("fork_= %d\n", fork());
}
결과는 
pid = 9331877  -- pid
fork_= 5999      - 부모 프로세스로 리턴되는 값 = 자식프로세서의 pid
fork_= 0           - 자식프로세스로 리턴되는 값
여기서 pid_t는 process id type로서 integer과도 서로 컨버전이 되는 정수값이다. 이는 바로 프로세스의 이름표이다.
한 시스템 내부의 모든 프로세스들은  각각 고유의 프로세서 id를 가지게 된다. 대부분 일정한 규칙을 가지고  id를 생성하게 되는데 몇몇 개는 시스템 차원에서 고정된값을 가지고 있기도 하다. 
위의 실행 결과에서도 볼 수 있지만, fork()는 부모 프로세스에게 자식프로세서의 pid를 리턴하고 자식프로세스에게는 0을 리턴해주게 된다. 
또한 실행 순서도 알 수 있게된다. 부모프로세스로 리턴 후 자식프로세서 로 리턴 수행
그리고 나서 다음의 코드를 보자
main() 
{ 
   pid_t   pid; 

   if((pid = fork()) == 0) 
      printf("I am a child process\n"); 
   else 서
      printf("I am a parent process\n"); 
} 

결과는 여러분도 예상했다싶이

I am a child process 
I am a parent process 
자, 다음을 분석하면 처음 if문에서  부모프로세스로 리턴되는 값을 pid에 넣고 0 이랑 같음을 비교한다. 0이랑 같지 않으므로 else가 수행되어 두번째 printf가 수행되고 , 다음으로 자식프로세스가 수행되면서 fork()의 리턴값이 0이되므로 if문안에서 첫번째 printf문을 수행하게된다.
재미있는 사실은 보통 자식 프로세스를 생성하게될 때 for문을 사용하여 쭉 생성하고 배열에 pid를 담아두어 각 요소별로 pid의 값을 제어할 수 있도록 프로그래밍 하게 된다. 또한 소스 마지막 부분에는 getpid()하는 함수를 붙여둠으로써 어떤 프로세스가 cpu를 점유하는지 쉽게 알 수 있도록 하고 있다. 
이렇게 여러개의 프로세스를 생성함에 있어서 또 한가지 중요한 개념은 바로 싱크이다. 예를 들어 부모프로세스가 홀수를 출력하고 자식 프로세서가 짝수를 출력할때 홀수다음반드시 짝수 그다음 홀수 이런식으로 프로세서들끼리의 의사소통을 통해서 이러한 순서를 맞추는 과정을 싱크라하는데,  sleep()함수를 통해서도 조절할 수 있지만 차후에 싱크라는 개념을 중요하게 다루게 될것이다. 차후에 적어보도록 하겠다. 
다음으로 차일드 프로세스의 의 용도에 대해 알아보겠다. 크게 두가지로 볼 수 있는데 
첫번째는 강력한 콜인 exec** ()이다. **에는 c,p,l,v 이렇게 네글자가 한쌍으로 조합되어 적용되는데 이는 넘겨주는 매개변수에 따라서 달라진다. 그냥 간단하게 exec콜은 지정한 디렉토리 안에 있는 바이너리를 차일드 프로세스의 몸통과 합체를 시켜버리는 즉, 프로그램 내부에서 다른 프로그램을 차일트프로세스화 시켜버리는 일을 한다. 
두번째는, 서버를 구축할 때 유용하다. 물려들어오는 여러 사용자들에게 자식 프로세스를 하나씩 발행해 주는 것이다. 
이상으로 용도에 대해 알아보았다. 
마지막으로 미아숙청 룰에 대해 이야기하고 마무리 짓도록 하겠다. 유닉스는 엄격한 룰을 가지고 있는데 그것은 바로 미아는 절대로 방치하지 않는 다는 정책이다. 쉽게 말하면 부모프로세스없는 자식프로세스는 존재하지 않도록 발견즉시 종료시켜버린다. 부모프로세스가 종료될때 무조건 자식프로세스들까지 삼족을 멸하거나, 비정상적인 부모프로세스의 종료로 인한 자식프로세스의 미아화가 발견되었을 때는 바로바로 종료시킨다. 이는 소중한 메모리공간이 미아로 가득차는 불상사를 방지하고자 하는 정책이다.




'OS > OS 파헤치기!' 카테고리의 다른 글

6. 씨피유 스케줄링  (0) 2010.09.23
4. 프로세스(process)?  (0) 2010.08.25
3. 하드웨어 보호(Hardware Protection)  (0) 2010.08.17
2장 컴퓨터 구조  (0) 2010.08.16
1장. OS란?  (0) 2010.08.12
AND

오늘 정리하는 부분은 이전의 swi 핸들러작성에 이어 IRQ핸들러를  OS타이머를 구현해 보며 작성하는 것이다. 
여기서 os 타이머의 필요성은 이해했고, OS타이머를 만들기위해 인터럽트를 이용할 것인데 이러한 인터럽트는 이전의 소프트웨어적인 인터럽트와는 달라서 외부 인터럽트이다. 따라서 IRQ 또는 FIQ로 처리하는데, 본 운영체제에서는 IRQ만들 사용하기 때문에 IRQ exception 으로 타이머를 구현할 것이다. 
따라서 먼저 인터럽트를 이용해야 하기 때문에 인터럽트에 대한 처리가 어떻게 이루어 지는지 인터럽트 컨트롤러 계층에 대해 알아야 한다. 
pxa255의 인터럽트 컨트롤러 블록 다이어그램은 데이터시트를 보면 나와있고
각 레지스터들의 기능들에 대해 알아보겠다. 데이터시트를 옆에 두고 보면 이해가 된다. 
ICLR : level 레지스터  즉, 인터럽트가 IRQ인지 FIQ인지 결정한다. 22개의 레지스터중 해당비트가 0이면  IRQ, 1이면 FIQ이다.
ICCR: control 레지스터 . 마지막 한 비트만 설정가능한데 이는 DIM 비트로서 disable idle mode라는 뜻이다.
이 부분을 이해하려면 ICCR[DIM]=0 & idle mode='1' 부분을 잘 봐야한다.  얼핏보면 헷갈린다. 해석하면 ICCR[dim]비트가 0이면 참, 1이면 거짓이고 idle mode는 1이면 참, 0이면 거짓이다. 가운데 & 연산자는 알다시피 둘다 참일때만 참인값을 내보낸다.다시말해서 ICCR[DIM]=0 & idle mode='1' 일때만 1이라는 참의 값을 낸다는 것이다. 하지만 포인트는 우리는 ICCR[DIM]비트를 0또는1로 컨트롤 하는 목적으로 써야한다는 것이다. 이해를 돕기위해 idle mode는 알아서 바뀐다고 생각하고 (idle 일때도 있고 아닐때도 있으니까 알아서 바뀌게 내버려둬...) idle mode 를 무시할지 말아야할 지만 결정하면 되는 것이다. 왜? ? ? 왜냐하면 ICCR의 목적은 idle mode의 변화로 인해 ICMR이 제 기능을 하도록 지켜주는 것이다.  
즉, idle mode가 0 이든 1이든 신경쓰지 않고 ICMR에 셋팅된 인터럽트만 받겠다고 하면(ICMR을 최고로 존중해주겠다고하면)ICCR[dim]을 1로 셋팅하면된다. 그리고 idle mode = 0일때에만(ICMR을 반 만 지켜주는....) ICMR에 셋팅된 인터럽트를 받고 싶으면 ICCR[dim]을 0으로 셋팅하면된다. 하지만 이때는 idle mode=1일때 ICMR을 무시하고 아무 인터럽트 발생시에도 다 통과시킨다 는 점을 기억하자

적어놓으니 이해가 잘된다ㅎ
ICMR: mask 레지스터, 통과시키고 싶은 인터럽트를 1로 셋팅한다. 22개의 비트중 각 비트마다 특정 인터럽트가 바인딩되어있         다
ICPR: pending 레지스터 . 인터럽트 발생시 무조건 기록한다. ICMR처럼 비트마다 특정 인터럽트가 바인딩 되어 있다. 
ICIP: IRQ 로 발생한 특정 인터럽트 비트를 기록
ICFP:FIQ 로 발생한 특정 인터럽트 비트를 기록 

인터럽트번호별 할당된 내용.

이를 바탕으로 정리해보자.
그러니까,  처음으로 인터럽트가 감지되면 해당 인터럽트를 ICPR에 무조건 기록한다. 그리고 이렇게 인터럽트가 감지되었을때, ICCR[DIM]=0 & idle mode = 1 이거나 ICMR의 해당 비트가 셋팅되어 있으면 다음단계로 이동 , ICLR에 의해 해당비트가 0이면IRQ, 1이면 FIQ인지 결정하게 되고, IRQ면 ICIP, FIQ이면 ICFP에 기록한 후 인터럽트가 프로세서로 전달하게 된다. 

그럼 여기서 내가 프로그래밍 해줘야 될게 무엇이냐?... 
 ICLR에서 IRQ인지 FIQ인지 해당비트를 셋팅해주고, 
 ICMR에서도 허용할 인터럽트비트를 활성화 시킨다. 
 ICCR[DIM]을 1로 셋팅한다. 그래야 우리가 원하는 ICMR에 허용된 비트만 받아들이게된다. 















AND

일단 이거 부터 읽고 이해해야한다. 

그리고 다음 소스를 보자.
.global navilnux_swiHandler
navilnux_swiHandler:
1;        stmfd   sp!,{r0-r12,r14}
2;        mrs      r1,spsr
3;        stmfd   sp!,{r1}
4;        bl        swiHandler
5;        ldmfd   sp!,{r1}
6;        msr     spsr_cxsf,r1
7;        ldmfd   sp!,{r0-r12,pc}^
============================
1; stmfd 는 아래와 같은 stack자료 구조가 있을때 , 예로 높은 주소 0x0c부터 낮은주소 0x00으로 와 같이 스택이 자라는 것이라고 한다. full descending이므로  stmdb와 같다. 감소하고 채우고. 이렇게 이해하면 쉽다. ㅋ 
sp d(감소) 한다 b(전에) data input 
난 여지껏 높은 주소가 아래이고 낮은 주소가  가장 위(limit)가 되어 높은 주소에서 낮은 주소로 , limit를 향해서 채워나가는 것이 스택이라고 생각했는데,  높은 주소로도 ,또는  낮은 주소로도 자랄 수 있다는 것을 알게 되었다. 
 하지만 보통 스택은  full descending으로 구현되며 위에서 보듯이 높은 주소에서 낮은 주소로 감소하고 채우고 방법을 많이 사용하게 된다. 
여기서 중요 ascending 은 sp!,{r0-r12,r14}에서 r0부터 작업하지만, descending은 r14부터 작업한다. 즉,~!~!
stmfd sp!,{r0-r12,r14} 은 sp가 4byte씩 감소하면서 r14채우고 , 감소하고 r12채우고, 감소하고 r11채우고.... 이런 식이 되는것이다. 그림으로 보면 이런식이다. 



2. arm에서는 상태레지스터를 메모리 접근 명령어의 인자로 사용불가 따라서 move to from stack status 명령어를 사용하여 r1에 복사후 
3. 스택에 넣기
4. swi핸들러 가기
5.  밑의 글은 5번 라인의 ldmfd의 내용을 보기위해 한번쯤은 당연히 생각해 보았어야 할 문제다.  밑의 글은 질의 내용인데 여러 사이트에 올렸던 질문내용이다.
///////////////////////////////////

stmfd store multiple full descending
    저장 한꺼번에쭉 꽉차게 주소감소하면서
ldmfd load multiple full descending
   꺼냄 한꺼번에쭉 꽉차게 주소감소하면서

강의를보고 이해하기로 저렇게 이해했습니다. 그러면 stmfd에서 낮은 주소방향으로 스택이 쌓여가다가 ldmfd에서도 또 낮은 주소방향으로 주소 포인터가 이동하면서 꺼내야 되는데 왜 ldmfd에서는 높은 주소방향으로 주소 포인터가 이동하면서 쌓아놨던 스택을 꺼내는 걸까요? store와 load 명령어의 동작 방식 때문에 그렇다면 st와 ld로 인해 위에 d의 의미가 감소가 아니라 증가로 바뀌는 것인가요?
단순히 push pop개념으로 이해하면 그냥 넘어가겠는데, 명령어상 문자상의 의미로는 틀린거같아서요.

ldmfa라고 해야 맞는 명령어이지 않을까요? 
왜 저렇게 쓰는지 밍모르겠어요.

다른 분은 full descending 의미는 store에서 라고 하셨는데 그 말은 st냐 ld에 따라 마지막 d의 의미가 달라진다는 말씀이신 것같은데요. 제가 생각하는게 맞나요?

또 한가지 더요.

       ldmfd는 현재 주소에서 큰  주소 방향으로 이동하는데 ,  주소가 증가하고 데이터 빼고 하는 pop 인가요? .......1
                                ""                                            ,  데이터 빼고 주소가 증가하는 pop 인가요? .......2

1번 이 맞는 것같은데... 확실한지 모르겠네요

/////////////////////////////////////

이 질문에 대한 대답은 이렇다. stmfd와 ldmfd를 명령어 적인 해석 보다는 push pop의 개념으로 이해하라! 

그렇다. 명령어적으로 해석하면 분명 내가 질문했던 내용이 포인트가 될 수 도 있다. 
하지만 이렇게 외우기로 했다. stmfd와 ldmfd를 쌍으로 push pop 으로 외우기로 했다. 
마지막 질문인 1번인지 2번인지는 아직도 모르겠다. 주소이동이니까 이동하고 빼는지 빼고 이동하는지 순서가 있을텐데....
아직까지 미지의 부분이다. 혹시라도 이 글을 읽는 다른 사람이 있다면 알려주길...

6.        msr     spsr_cxsf,r1
2번에서의 설명과 같다.상태레지스터를 메모리 접근 명령어의 인자로 사용이 불가하기 때문에 spsr_cxsf에 r1의 내용을 넣는다 . 즉 spsr은 다시 복원되는 것이다. 근데 여기서 cxsf는 상태레지스터의 4가지 영역을 모두다 복원한다는 것이다. flag, status, extension, control.

7.        ldmfd   sp!,{r0-r12,pc}^
pop명령어로 스택의 포인터값을 4바이트씩 증가시키면서 낮은 주소로 쌓아올렸던 스택값을 빼내서 r0....r12, pc 순서로 까지 복구한다. 그리고 마지막 ^ 기호는 arm어셈블리 주소지정 방식으로 메모리에 있는 값을 레지스트리에 복구하고 pc의 주소로 자동으로 분기하며 동시에 spsr의 값을 cpsr의 값으로 복사한다. 

 

AND

책 4, 5장 관련 전반적인 내용에 관한 정리이다 .
먼저 main.c 에는 
..
__asm__("swi 77");  
..
명령어가 들어있고, entry.S에는
....
_ram_entry:
        bl      main           0xa0008000
        b       _ram_entry   0xa0008004
        b       navilnux_swiHandler    0xa0008008
        b       navilnux_irqHandler     0xa000800c

.global navilnux_swiHandler
navilnux_swiHandler:
...
부트로더 에는 이미 swiHandler의 주소가 0xa0008008 가 고정되어 있는상태이고, 커널 이미지상에서도 위에서 보는 바와 같이 고정 시켜뒀다.
일단 arm에 각기다른 모드별로 사용할 수 있는 레지스트리가 다르다.
여기서 총 arm에서 사용할 수 있는 레지스트리는 37개 이다 . 어떻게 알지?.. 직접 세어봐라. 

다만 헷갈리지 말아야 할 부분을 적어보겠다. 
모드별 r0~r12번중 표시 안된건 공유, cpsr(현재 어떤모드인지)은 1개 , spsr(예전에 어떤모드였는지)은 user모드에는 필요없다. r15(pc, 다음에실행될 명령어 주소)는 공유. 기억하자!!

이제 main 함수에서 swi  라는 소프트웨어 인터럽트를 발생시키는 명령어로 인한 ISR진입과정 을  자세히 설명해 보도록 하겠다. swi 는 소프트웨어 인터럽트를 발생시키는 명령어로서 svc모드로 동작하게 된다. 

예를들자. main에서 swi 발생할때 예를 들어 설명하겠다.  

1. main에서 swi 77 명령어가 실행되면 인터럽트 발생!
2. 현재 cpsr을 svc모드의 spsr에 복사
3. r15(pc)를 svc모드의 r14(lr)에 복사
4. cpsr값을  svc모드로 바꾸기
5. r15(pc)값을 exception handler주소로 변경 여기서는 0xa0008008(위에서 부트로더와 커널에서 다~ 지정했다.부트로더에서와 커널에서의 주소지정 방법은 책에..)
========================================
요기까지가 arm코어에서 자동으로 해주는 작업이다. 
뭐... cpsr값을 개발자가 바꿔줘야 할 때도 있지만 swi여기서는 자동!
이 다음부턴 개발자가 핸들러를 짜줘야 하는 부분이다.
========================================
6. r0~r14까지 스택에 백업한다. 왜냐? 각 모드별로 따로 할당되어 있는 레지트스리가 그림에서 보듯이 있는데 svc모드는 따로 할당된게 없지 않은가(공유한다)? 일단 인터럽트 발생해서 넘어왔으니 할일을 해야한다. 그 할일을 하는것이 handler이고 여기서 지정된 곳으로 분기하게 되어 레지스트리를 사용하지 않은가? 그니까 백업해놔야한다. 어디에? 각자 지정된 스택에 (그래서 각자 r13(sp) -따로 있잖아.!!)
만약 FIQ 가 발생하면 r0~r7 , r13,r14 정도만 백업한다. 이렇게 레지스터 몇개 줄이는 것도 시간줄일 수 있다. 우선순위도 다르지만...
7. svc모드의 spsr도 스택에 백업한다.
8. ISR코드 수행한다. 즉, 위의 entry.S 코드에서
.global navilnux_swiHandler
navilnux_swiHandler:
....                             
bl   swiHandler                              <====요기   (main.c 에 함수로 정의되어 있다. bl 을 사용하면 c코드로 넘어감.)
이부분을 수행하게 되는 것이다. 이거 수행할때 레지스트리 r0~~~부터 해서 레지스트리 사용하게된다. 그래서 백업하는것이다.
9 . 작업이 끝난 후 반대로 돌려주면된다. 스택포인터는 spsr을 저장한 다음의 위치를 가리키고 있으므로 스택에서 4바이트 빼서 spsr에 다시 저장한다. arm은 4바이트씩.
10.r0~r14까지 다시 되돌려준다. 

그러니까  main.c에서 swi명령어로 인해 소프트웨어 인터럽트가 발생할 때 ISR 핸들러를 만들어 주는 과정을 요약하면
자동으로 arm코어에서 하는 과정은 놔두고

entry.S에서
.global navilnux_swiHandler
navilnux_swiHandler:
r0-r14내용을 스택에 백업
spsr 내용을 스택에 백업
bl   swiHandler 
스택의 마지막 4바이트를 spsr에 쓰기
스택에서 차례대로 r0-r14쓰기

이렇게 요약할 수 있겠다. 
천재!

ps. 2010.9.29일 추가내용
주의 arm은 기본모드가 svc란다. user모드에서 svc로 바뀌는게 아니라 모드의 변경은 없고, isr처리 과정에 중점을 두어 살펴봐야한다.







'OS > navilnux' 카테고리의 다른 글

pxa255 인터럽트 계층 이해하기  (1) 2010.09.17
exception handler 소스 분석!  (0) 2010.09.15
임베디드개발 보드의 LED 활용!  (0) 2010.09.14
2. 개발환경 테스트 에러발생  (0) 2010.09.11
1. 개발환경 구축하기  (0) 2010.09.11
AND

디버거용이다. 코드 사이에 집어넣어  거기까지 잘 동작하는 지 디버거 용으로 쓴다. 이상.!

제공되는 c 코드 보면 그냥 활용할 수 있다.
AND

나빌옹님은 ez-x5보드 위에서의 개발환경과 에뮬로의 환경을 둘다  말해주고 있는데, 앞으로 모든 얘기는 에뮬환경에서의 이야기이다. 에뮬레이터 qemu를 돌리기 위해서는 ez보드에서 제공되는 커널이미지와 , 에뮬레이터에서 돌아가는 gunstix_uboot 부트로더 를 사용하게 된다.
그런데 gumstix_uboot의 부트로더 이미지를 생성하는 과정중 이상한 에러가 발생하였다. 
failed to merge target specific data of file /usr/lib/gcc/arm-linux/3.4.3/libgcc.a(_modsi3.oS)
이걸 고치기위해 검색해 본 결과 
msoft-float 이라는 옵션의 문제였다. 

gumstix_uboot 디렉토리에 가서 grep -nR 'msoft-float' ;;; 이렇게 검색하면 gumstix_uboot/cpu/ 아래 아키텍쳐별로 주루룩 나오는데 

우리가 봐야될거는 pxa폴더이다. 즉, gumstix_uboot/cpu/pxa/config.mk 파일을 열어서 msoft-float라는 글자만 쏙 제거해준다.

그리고gumstix_uboot 로 돌아와서

make distclean
make gumstix_config
make all
을 실행하면 에러가 사라지고 부트로더 이미지 파일의 생성과 함께 평화가 찾아온다.







AND

데비안계열 패키지 관리자 쓰다보시면 알겠지만 제대로 지워지지 않은경우(뻑나서).. 현재 버전보다 낮은 버전의 프로그램을 설치하고 싶어서 지웠는데, 낮은 버전 설치안될때!!!!! 줴기랄...

이럴때 수동으로 제거할 수 있는 방법을  적어보고자 한다. 
일단 내 목표는 현재버전보다 낮은 버전의 프로그램을 설치하고 싶었기 때문에 apt-get remove로 지우고 이것저것 할거 다 해봤는데 낮은버전이 설치 안될때 설치하게끔 하는 것이므로 참고해서 보기 바란다. (기존의 상위버전을 파일하나 까지 깔끔하게 지워내는 것이 목적이 아님!!)

요기를 참고하면 대충 이해가 되지만서도 

깔끔하게 내가 정리를 하자면 간단히 3단계로 나눌 수 있겠다. 
이하 관리자 권한으로 작업한다.
1.    /var/lib/dpkg/status 의 내용을 편집한다. 해당 프로그램 이름으로 검색해서 해당 패키지관련 사항을 모두 제거 
저만큼이 하나의 패키지 관련 내용임 말안해도 이정돈 알겠지?... 척보면 척 해야지!

2. /var/lib/dpkg/available 열어서 마찬가지로 해당 프로그램 이름으로 검색해서 해당 패키지관련 사항을 모두 제거 

3. apt-get check; apt-get autoremove 와같이 이거좀 해봐야겠다... 싶은것들 해보고  패키지 설치하면 설치된다. ㅋㅋ





AND

임베디드는 개발환경 구축할 때가 가장 짜증나는 것 같다. 한번뚫어놓으면 쫙쫙인데 보드에대한 경험이 없어서인지 보드 바뀔따마다 개고생한다. 

하지만 난  보드를 사용하지 않는다. 돈이없다. 보드살돈이... ㅠ (누가 좀 주세요ㅠ)그래서 친절한 나빌옹님의 가르침을 따라 qemu 에뮬을 사용하기로 했다. 선택의 여지가 없었다. ㅋ

나빌옹님은 gcc 3.3.2  버전을 사용하시고, qemu는 0.9.1 사용하시고  실제 개발보드와 qemu를 사용한 방법 모두를 설명하고있다. 
따라서 나도 그대로 gcc 와 qemu를 버전 맞추어 사용하기로 하였다. 

현재 
몇번의 삽질의 결과 보드의 개발사에서 제공하는 툴체인을 활용하는 것이 개발환경에 아주 수월하다 판단하여 툴체인을 그대로 이용하기로 하였다. 툴체인을 쓰게되면 gcc 3.3.2도 알아서 깔아주고 간단하다. 
qemu는 패키지 관리자를 통해서 설치하지 않고 0.9.1 버전의 패키지 설치파일을 찾아서 설치했다. 여러모로 그게 더 간단하였기때문에 ㅋ   요기참고 http://packages.ubuntu.com/hardy/i386/qemu/download

대충됐다. ㅎ 이렇게 해놓으니.... 한결 수월해졌다. 이제 남은건 make뭐 이런거하면서 생기는 에러 잡아서 온전한 hello world를 일단! 일단!! qemu상에서 보는 것이다. 그게 첫번째다. 


AND