2013년 11월 16일 토요일

[번역] CAN 통신 해킹하기 : 통신규약 (Protocols)

[출처 : http://hackaday.com/2013/10/29/can-hacking-protocols/]


 우리는 CAN 통신의 기초지식을 알아보고 CAN 데이터베이스가 어떻게 작동하는지 살펴보았다. 지금 우리는 CAN에서 통상 사용되는 몇 가지 통신규약을 살펴볼 것이다.

 지난 글에서 우리는 메세지의 각 bit가 특정 의미를 가지게 되는 CAN 데이터베이스에 대헛 살펴 보았다. 예를 들면, ID 0x400인 CAN 메세지의 첫 번째 bit는 현재 엔젠이 켜져 있는지 아닌지를 표현해준다.

 그러나, 좀 더 복잡한 통신에 대해선 우리는 통신규약(protocol)의 사용이 필요하다.  이것은 데이터를 주고 받기 위한 구조에 동의함으로써 많은 의미를 하나의 단일 CAN ID에 부여할 수 있습니다.

OBD-II

 자동차 운전석에 앉은 다음 여러분의 왼쪽 무릎 주위를 살펴보자. 여러분은 위의 사진과 같은 커넥터를 찾을 수 있을 것이다. 이것이 OBD-II 커넥터이다.

 OBD-II 통신규약은 CAN 통신과는 별개의 것이다. 이 규약은 CAN 뿐만아니라 UART, PWM 채널 위에서도 구현 될 수 있다. OBD-II는 California Air resources Board가 1991년에 캘리포니아에서 판매되는 모든 자동차를 위한 진단용 통신규약으로 요구하였을때 출현하게 되었다. 이거은 새로운 자동차에서 CAN 통신 위해서 통상 구현되었기 때문에 이 커넥터는 여러분에게 최소한 자동차의 CAN 통신 버스에 접속할 수 있는 하나의 통로가 되어 준다.

 OBD-II는 자동차의 파라미터와 오류코드를 읽는데 사용된다. 다양한 OBD-II 모드의 사용으로 여러분은 자동차의 상태에 관한 파라미터 IDs(PIDs)들이 포함하는 정보를 읽을 수 있다. Wikipedia는 OBD-II 모드와 PIDs에 관한 대단한 글들을 가지고 있다.

 OBD-II에 관한 많은 정보들은 이글 밖에 있다. 그리고 여러분은 오류코드를 읽고 성가신 엔진 점검 경고들을 지울 수 있는 20달러 이하의 도구를 구매 할 수 있다. OBD-II에 관한 자세한 사항에 대해서 알아보는 대신, 이것의 독재자(big brother)에 대해서 이야기 해보도록 하자.

하나로 통합된 진단 서비스(Unified Diagnostic Services)

 많은 자동차 광들은 OBD-II에 친숙 하지만, 많은 이들은 Unified Diagnostic Service(UDS)에 대해서 들어보지 못했을 것이다. 이것은 불행이다. 왜냐하면, OBD-II는 그져 UDS의 한 부분이기 때문이다. OBD-II는 단지 제한된 서비스만 제공하는 반면, UDS는 제조사와 기술자들이 사용하는 진단 규약이다. 이것은 진단하고, 보정하고, 펌웨어를 굽는데 필요한 모든 종류의 서비스를 제공한다. 

 UDS는 한 Byte의 Service ID(SID)와 인지되어지는 ReadDataByIdentifier와 TransferData 같은 다양한 종류의 서비스를 가지고 있다. 0x0F로 시작하는 SIDs들은 OBD-II를 위해서 예약되어 있고 나머지는 표준에 의해서 혹은 제조사에 의해서 정의 된다. 여기에 표준 UDS 서비스의 리스트와 그들의 헥사코드 지시자들이 있다.

  • DiagnosticSessionControl – 10 hex
  • ECUReset – 11 hex
  • SecurityAccess – 27 hex
  • CommunicationControl – 28 hex
  • TesterPresent – 3E hex
  • AccessTimingParameter – 83 hex
  • SecuredDataTransmission – 84 hex
  • ControlDTCSetting – 85 hex
  • ResponseOnEvent – 86 hex
  • LinkControl – 87 hex
  • ReadDataByIdentifier – 22 hex
  • ReadMemoryByAddress – 23 hex
  • ReadScalingDataByIdentifier – 24 hex
  • ReadDataByPeriodicIdentifier – 2A hex
  • DynamicallyDefineDataIdentifier – 2C hex
  • WriteDataByIdentifier – 2E hex
  • WriteMemoryByAddress – 3D hex
  • ClearDiagnosticInformation – 14 hex
  • ReadDTCInformation – 19 hex
  • InputOutputControlByIdentifier – 2F hex
  • RoutineControl – 31 hex
  • RequestDownload – 34 hex
  • RequestUpload – 35 hex
  • TransferData – 36 hex
  • RequestTransferExit – 37 hex
 UDS는 제어기에 데이터를 보내는데 frame 구조를 사용한다. Single Frame(SF)들은 모든 데이터가 6byte에 적합한 짧은 메세지를 위한 것이다. 만약 데이터가 길어 지게되면, FirstFrame(FF)는 전송을 시작하기 위해 보내진 다음 Consecutive Frames(CF)가 데이터를 가지고 보내진다. 여기에 frame들이 어떻게 구조화 되었는지를 보여주는 형태가 있다.

SF, FF 그리고 CF 메세지들의 구조

 OBD-II는 단지 첫 번째 frame 구조만 사용하지만, 다른 것들은 펌웨어 다운로드 같은 긴 데이터를 위해서 유용하다.

 어떻게 모든 서비스들이 동작하는지를 들여다 보기 위해서 여러분들은 ISO 14229의 복사본이 필요할 것이다. 불행하게도 PDF만 구하는데도 250달러 정도를 지불해야할 것이다. USD로 통신할 수 있는 도구들은 매우 비싸다. 그러나 이러한 기초적인 지식을 가지고 있다면 여러분은 신호선로에서 무슨 일이 일어나는지를 들여다 볼 수 있을 것이다.

OpenXC

 UDS가 개방되지 않은 통신규약인 반면, Ford사의 연구자들은 자동차와 연동하기 위한 개방된 platform을 구축하는데 힘써 왔다. 그 결과가 OpenXC Platform이다. OpenXC는 CAN위에서 Ford사의 차량으로 부터의 데이터를 읽는 통신규약이다.

 이것을 사용하기 위해서 여러분은 차량 인터페이스를 필요로 한다. chipKIT은 Ford사의 오픈 소스 펌웨어와 사용되어 질 수 있다. 아니면 그 대체용으로 여러분은 CrossChasm로 부터의 사전에 구축된 솔루션을 살 수 도 있다. 한번 차량 인터페이스를 구축되고 연동되면, 여러분은 안드로이드나 Python APIs를 이용해서 데이터에 접근할 수 있다. 우리는 지난 글에서 몇 가지 OpenXC hacks on Hackaday 것을 마련해 두었다. 

 자동차 제조사가 오픈소스를 수용하는 것을 보는 것은 대단한 일이다. 그리고 Ford사는 희망적으로 이 platform에서의 작업을 계속하고 있다. 이러한 사실은 OpenXC의 통신규약이 단지 읽고 아주 작은 메세지 그룹만으로 제한되어 있다는 것을 의미 한다.

 지금 현재 우리는 통신규약에 대한 모든 것들을 알아 보았다. 이제는 CAN 하드웨어를 만들어 보아야할 시간이 되었다. 다음 주에 우리는 여러분 자신의 프로젝트에 CAN을 사용하기 위해서 어떤 하드웨어가 필요한지 살펴 볼 것이다.

[번역] CAN 통신 해킹하기 : 차량 내 네트워크

[출처 : http://hackaday.com/2013/10/22/can-hacking-the-in-vehicle-network/]

 지난 시간에 우리는 차량 내 네트워크가 어떻게 CAN 통신 위에서 작동하는지에 대해서 논의 하였다. 이제는 그 통신 규약과 어떻게 자동차 산업에서 사용되는지에 대해서 살펴볼 것이다.

신호선로(The Bus)

 하드웨어적인 측면에서 두 가지 종류의 CAN이 존재한다: 고속 통신이 가능한 상호 반전 선로 방식(differential) 그리고 단일 선로 방식. 상호 반전 선로는 두 개의 신호선을 사용하고 1Mbps까지의 속도로 동작 가능하다. 단일 선로는 한개의 신호선위에서 동작하고 낮은 속도이지만, 저렴하게 구현할 수 있다. 상호 반전 선로 방식은 엔진 제어 같은 좀 중요한 분야에서 사용되고, 단일 선로 방식은 HVAC나 유리창 제어 같은 덜 중요한 분야에 사용된다.

 많은 제어기들은 다중-master 설정에서 동일 신호선로에 연결할 수 있다. 모든 메세지들은 신호선로를 통해 모든 제어기에 전달 된다. 

매우 단순화된 차량내 네트워크

CAN 메세지의 구조

  소프트웨어적인 관점에서 CAN 메세지는 3개의 부분으로 구성된다: 구분자(ID), 데이터 길이 코드, 그리고 8byte까지의 데이터.

 구분자(ID)는 메세지가 무엇을 의미하는지 누가 보내는 것이지를 지정하는데 사용된다. 보통은 표준 ID들은 11bit이지만, 29bit의 확장된 형태의 ID도 있다. ID는 또한 우선 순위도 정의한다. ID 값의 낮고 높음이 메세지의 우선순위가 된다.

 데이터이 길이 코드(DLC)는 4bit이고 메세지에 얼마나 많은 byte가 있게 될 것이지를 지정한다. 어떤 분야에서 8값을 갖는 DLC가 항상 사용되고 사용되지 않는 byte들은 0값으로 채워지곤한다. 

 마지막으로 8byte의 데이터는 실제적으로 정보를 포함한다. 정보의 의미는 메세지의 ID와 DLC에서 지정되는 길이로부터 추정되어 진다. 

의미 해석과 데이터베이스 (Decoding & Databases)

 8byte의 데이터를 이해하기 위해서 제어기는 데이터를 엔진 RPM, 기름 수위, 혹은 브레이크의 위치 같은 신호로 해석한다. 각각의 신호는 8byte 이외에 정정을 위한 bit를 선택하는데 사용되어 지는 시작 bit와 마지막 bit를 갖는다. 아무런 정보가 없는 신호가 신호선로에 보내지면, 대신 모든 제어기들은 앞서 보내진 신호와 메세지의 형태에 동의하게 된다. 아래는 신호 테이블과 샘플 메세지의 도표화된 형태를 보여주고 있다.
메세지를 형성하는 CAN 신호들의 테이블

단순한 CAN 메세지의 형태

 신호들과 메세지에 동의하는 제어기를 프로그램하는데 도움이 되기 위해서 CAN 데이터베이스가 사용된다. 이 데이터베이스는 모든 메세지와 신호의 정의들을 포함하고 있다. 가장 많이 사용되는 형식은 Vector사에 의해서 제작된 사유화된 형태이지만 ASCII 코드에 기반한 DBC이다. DBC 변경도구인 CANDB++는 공짜(as in beer ?)이다. 데이터베이스들은 메세지를 해석할 수 있는 코드를 자동 생성하는데 사용된다.

 수중에 데이터베이스 파일을 넣게 되면 여러분들은 CAN 신호선을 쉽게 엿볼 수 있고 모든 종류의 데이터를 해석 할 수 있다. 단적인 예가 우리가 작성한 해킹인 운전대의 버튼을 위한 신호 엿보기(sniffed the bus for steering wheel button presses)이다. 여러분은 또한 신호선로에 속임수 데이터를 보내서 어떤 제어기 인척 만들 수도 있다. 예를 들면, 여러분은 계기판에 거짓 엔진 RPM 정보를 보낼 수도 있다.


아니야, 이 차는 8000 RPM 까지 정말로 올라 갈 수 없어.

 정상 운행중에 발생하는 통신의 대부분은 데이터베이스를 해석하는데 할여된다. 그러나, 진단 분야를 위해서 사용되어지는 특별한 통신 규약들이 있다. 다음에 우리는 이러한 통신 규약들이 어떻게 동작 하는지를 알아 보고, 그것을 가지고 어떤 재미있는 것을 할 수 있을 것이다.



[번역] CAN 통신 해킹하기 : 소개

[출처 : http://hackaday.com/2013/10/21/can-hacking-introductions/]

October 21, 2013 by Eric Evenchick


 우리는 지금 CAN에 대한 새로운 연재물과 자동차 해킹을 소개하려 한다. 먼저, 우리는 CAN 통신을 소개하고 어떻게 자동차 안에서 네트워크가 작동하는지에 대해서 논의 할 것이다.

 1986년에 Bosch사는 Controller Area Network 통신 규약을 소개하였다. 이것은  차량 제어기 사이에 이루어지는 자동차내의 네트워크를 위해 특별히 고안되었다. CAN 통신은 차량, 산업, 그리고 로봇 분야에서 네트워크 제어기로써 일반적인 옵션이 되었다. 2008년을 시작으로 미국에서 팔리는 모든 자동차는 CAN을 사용해야 한다.

 현대의 자동차들은 특수한 작업을 다루도록 고안된 제어기 (예를 들면, 차문 제어 모듈은 잠금과 창문 제어를 담당한다.) 를 가진 분산제어시스템(distributed control systems)이다. CAN 통신은 이 제어기들이 통신 가능하도록 해준다. 또한, 외부 시스템들이 차량내 네트워크에 접속함으로써 진단 작업을 수행할 수 있도록 해준다.

 자동차 안에서 이루어지는 CAN 통신의 여러가지 예들은 다음과 같다:


  • 회전 속도가 표시되는 종합 계기판(instrument cluster)에 현재의 엔진 속도를 보내는 엔진 제어 모듈
  • 유리창을 움직이기 위해 차문 제어기에 메세지를 보내는 운전자의 차문 제어기
  • 진단 도구로 부터 보내지는 제어기를 위한 펌웨어 변경
 CAN은 보통 통신 내용이 숨겨져야 하는 곳을 제외한 약간 혹은 필요없는 보안에 사용된다. 우리는 통신 내용을 보고 해석하기 위해서 CAN to USB 변환기를 사용할 수 있다. 또한 위조된 메시지를 보내거나 진단 조치를 수행하기 위해서 이러한 도구들을 사용할 수 있다. 불행하게도, CAN을 다루는 대부분의 도구들은 비공개 되어 있다. 그리고 매우 비싸다. 진단 규약은 엄연히 표준이지만, 비공개 되어 있는  것들이다. 이것들은 International Organization for Standardization 에서 구매해야 한다.

 다음에는 우리는 CAN 통신의 frame의 구조를 들여다 보고, 어떻게 통신 내용이 버스에 복조되는지 알아 볼 것이다.

[그림은 Wikipedia로 부터 가져옴]




2013년 11월 14일 목요일

Netduino plus2를 위한 JTAG 프로그래머 ST-LINK/V2의 변환기판 제작.

예전에는 JTAG 장비들이 고가였으나 현재 3만원정도만 주면 구입이 가능한 상품이 나오고 있다. 그 대표적인 것이 STmicrossystem 사의 ST-LINK/V2이다. digikey와 mouser같은 부품 공급처에서 $30달러 이하로 구할 수 있다.

 하지만, 지금 가지고 있는 Netduino plus 2의 JTAG 핀피치는 1.25mm로 ST-LINK/V2가 2.54mm 인 핀피치와 다르고 핀배치도 완전 다르다.

위에서 바라본 stink-v2의 JTAG 핀배치. 출처 : http://www.wvshare.com/product/ST-LINK-V2-STM32.htm

위의 사진은 ST-LINK/V2의 JTAG 핀아웃이다. 그리고 아래의 그림은 Netduino plus 2의 JTAG 핀아웃이다.

뒤에서 바라본 Netduino plus 2의 JTAG 핀 배치. 출처: http://netduino.com/netduinoplus2/schematic.pdf 

우선 Netduino 보드는 위에 다른 보드를 연결하면 리셋 버튼 누르기가 불가능하여 변환 기판에 추가적으로 리셋 버튼을 만들어서 /RESET_MCU와 STM32_RESET을 함께 연결하도록 하였고, 3.3V 전원이 ST-LINK/V2와 Netduino 보드 둘다에서 생성되기 때문에 연결해 줄 필요는 없지만, 혹시나 보드에 전원 인가 없이 개발 보드의 펌웨어 수정이 가능하도록 STLINK-V2에서 보드로 전원을 공급할 수 있게 점퍼를 하나 만들어 두었다. 다음은 1.25mm피치의 양면 기판을 이용해서 만들어 본 변환 보드이다.









2013년 11월 11일 월요일

[작업중] stm32f405rg를 위한 startup code 와 링커 스크립트 분석

 임베디드 시스템에서 어셈블리 언어가 아닌 C 언어를 사용하기위해서 사전에 처리해 주어야 하는 작업들이 존재한다. 이 부분에 대해서는 여러가지 복잡한 것들이 많이 존재하지만, 새로운 CPU를 사용하려고 하거나 메모리를 구체적으로 어떻게 관리하는지 알아 보려면 반드시 알아두고 넘어 가야 하는 것이다.

 C언어로 된 바이너리 코드를 실행하려면 이 바이너리 코드가 메모리의 어느 부분에서 실행되는지 그리고 코드에서 사용하는 각종 변수와 스텍 그리고 힙이라고 하는 동적 메모리 할당 영역을 램의 어느 부분에 할당하고 값을 어떻게 초기화 해야하는지 결정해야 한다. 여기에 덧붙여  CPU에서 발생하는 인터럽트를 처리하고자 한다면 인터럽트 벡터의 위치와 각종 인터럽트 벡터의 초기화를 해 주어야한다.

위와 같은 네 가지 과정은 C 언어 코드자체만으로는 구현이 불가능하다. 이 기능들은 원래 시스템 OS에서 관리해 주어야 하지만, 임베디드 시스템의 경우 사용자가 알아서 처리해야한다. 그래서 C언어로 임베디드 시스템 프로그램을 하려고 한다면 불가피하게 startup 코드와 linker script를 작성해야한다. 물론 이런 것을 편리하게 하나의 툴로 판매하는 회사 IAR, Keil 등등이 있지만, 자유소프트웨어인 gcc와 연관된 도구를 사용하고자 한다면 사용자가 작성해야 한다.

 그럼 간단히 startup 코드와 linker script가 하는 일에 대해서 살펴보자. startup 코드는 C 언어를 사용하기 이전에 필요한 스택 레지스터 초기화, 동적할당 영역을 '0'으로 초기화, 클럭 설정, 인터럽트 벡터의 지정 및 cpu에 달려 있는 메모리의 위치지정을 위한 레지스터 설정과 같은 기초적인 cpu의 초기화 작업을 수행한다. 그리고 linker script는 기본적으로 컴파일된 모든 오브젝트 파일들을 하나로 모아서 하나의 실행 가능한 출력파일로 합성하는 기능을 수행한다. 그리고 좀 더 구체적으로는 startup에서 설정한 메모리의 구성에 따라서 컴파일된 모든 오브젝트파일의 각 세그먼트들을 재배치 시키고, 실행 가능한 출력 파일을 어떻게 구성할 것인지에 대한 설정을 수행한다.

 다시 정리해서 위의 과정을 좀 더 기능적으로 구분해 보자면 다음과 같다.

 1. C언어의 바이너리 코드가 적재될 메모리의 위치 지정  
 2. 변수, 스텍, 그리고 동적 메모리 할당 영역의 위치 지정  
 3. 스텍 레지스터 및, 스텍 그리고 동적 메모리 할당 영역의 초기화  
 4. 인터럽트 벡터의 위치 지정  
 5. 인터럽트 벡터 레지스터 초기화 및 인터럽트 벡터의 초기화  


 위의 기능은 컴파일러와 어셈블리 언어에  의존적이기 때문에 이해하기에 쉽지가 않다. 나도 마찬가지이기 때문에 기존에 완성되어 있던 것을 더듬어 가는 방법으로 설명해 보고자 한다. 앞으로 사용할 코드는 gcc 기반의 크로스 컴파일러에 기반하고 그 코드는 다음의 주소에서 가져왔음을 밝혀둔다.

http://git.munts.com/arm-mcu/gcc/stm32f4/

 위의 주소에 있는 파일 중에서 살펴볼 것은 stm32f405rg.S와 stm32f405rg.ld이다. stm32f405rg.S는 소위 말하는 런타임 라이브러리라고 하는 것이고 stm32f405rg.ld는 링크 스크립트라고 하는 바이너리 코드의 코드영역, 데이터 영역, 그리고 스텍영역을 어디에 배치할지를 지정하는 스크립트 코드이다.

stm32f405rg.ld의 분석

 gcc 컴파일러의 링크 기능이 요구하는 기능은 시스템에 메모리의 구성이 어떻게 되며, C언어가 컴파일된후 코드 영역과 데이터 영역, 그리고 스텍 영역그리고 C++언어에서 추가적으로 생성하는 영역을 시스템 메모리의 어느 영역에 배치할 것이지를 요구한다.

메모리의 구성

 먼저, 시스템의 메모리 구성이 어떻게 되는지는 다음과 같이 지정한다.

 MEMORY  
 {  
  flash (rx) : ORIGIN = 0x00000000, LENGTH = 1024K  
  ram (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K  
  ccm (rwx)  : ORIGIN = 0x10000000, LENGTH = 64K  
 }  

 위와 같이 세 종류의 메모리가 지정되고 있다. 각종 메모리를 지정하는 방식은 다음과 같다.

 메모리이름 (특성) : ORIGIN = 시작주소, LENGTH = 메모리의크기  

 메모리 이름은 알아 보기 쉬운 아무 것이든 가능하고 특성은 rwx같은 약자로 지정이 가능하다. 이들은 각각 Readable, Writable, 그리고 eXecutable의 약자로 읽기, 쓰기, 실행가능의 특성을 이야기 한다. 이 부분은 반드시 사용하고자 하는 CPU의 데이터 시트를 살펴보아야 한다.

 stm32f405rg의 데이터 시트를 살펴보면 다음과 같이 메모리의 구성을 알려주고 있다.

STM32F405RG의 내부 메모리 구성

 위의 그림에서 보듯이 stm32f405rg는 32bits로 지정가능한 영역인 4Gbyte영역을 8개의 512Mbyte 단위의 블럭으로 쪼개서 관리한다. 앞의 두 블럭을 제외한 나머지 영역은 외장 메모리 혹은 내장된 모든 주변장치들에 접근하는데 사용된다.

 아무튼 지금 현시점에서 중요한 것은 최하위 주소에 있는 두 블럭이다.

 다시 되돌아 가서 주소 블럭 0의 0x00000000에서 0x000FFFFF에 해당하는 영역은 1024Kbyte의 크기를 가지고 있고 첨삭된 내용을 보자면 Flash로 명칭되고 BOOT 핀을 어떻게 설정하느냐에 따라서 SRAM으로 설정될 수 도 있다고 되어 있다.

 좀 더 자세히 이야기 하자면 기본적으로 해당 영역은 읽고 실행만이 가능한 Flash로 되어 있고 BOOT 핀을 변경하면 SRAM을 위한 영역으로 변경가능하다는 이야기 이다. 이러한 기능이 왜 필요한지는 컴파일과 다운로드로 이어지는 지겨운 개발 과정을 거쳐 보았다면 충분히 이해가 가능할 것이다. 나와 같이 개념없이 개발하는 개발자에게 펌웨어 개발 과정은 컴파일하고 Flash 메모리에 굽는 과정이 솔직히 대부분이라고도 할 수 있다. 그래서 정상적으로 쓰는데 시간이 소요되는 Flash 메모리 보다 SRAM을 위의 위치에 배치 시키면 펌웨어 개발에 많은 도움이 될 수 있다.

 그럼 BOOT 핀들의 기능을 살펴보도록 하자.

stm32f405rg의 데이터 시트에 있는 부트 모드에 대한 설명

잠시 해석을 해보자면,
시작시, BOOT 핀들은 다음의 세 가지 부팅 옵션중 하나를 선택하는데 사용된다.
 * Flash로 부터 부팅하기,  
 * System memory로 부터 부팅하기,  
 * 그리고 마지막으로 내장된 SRAM으로 부터 부팅하기  
부트로더가 system memory에 위치하고 있고 USART1(PA9/PA10 핀), USART3(PC10/PC11 핀 혹은 PB10/PB11 핀), CAN2 (PB5/PB13 핀), 그리고 DFU (device firmware upgrade)를 통한 디바이스 모드의 USB OTG FS (PA11/PA12 핀)을 이용해서 Flash 메모리를 재 프로그래밍하는데 사용된다.

 즉, STmicrosystem에서 제공하는 부트로더가 이미 system memory에 내장되어 있고, 이 부트로더는 USART1, USART3, 그리고 CAN2, 디바이스 모드의 USB OTG FS를 통하여 새로운 펌웨어를 다운로드하여 Flash 메모리에 꿉어 주는 기능을 하고 있다는 이야기 이다.

 해당 system memory는 0x1fff000에서 0x1fff7a0f에 위치한다. 그리고 첨삭 내용을 보자면 OTP방식으로 CPU가 제조될때 한번만 기록이 가능한 것으로 추정된다.

그리고 BOOT 핀들의 설정에 따른 모드 변환은 다음과 같이 할 수 있다.

stm32f405rg의 BOOT 핀 설정에 따른 부트 모드의 변화

 어쨌든, "flash (rx)  : ORIGIN = 0x00000000, LENGTH = 1024K" 는 설명이 된 것 같다.

"ccm (rwx)   : ORIGIN = 0x10000000, LENGTH = 64K"에 해당하는 CCM이라는 처음 들어 보는 메모리를 살펴보도록 하자. CCM 메모리는 기본적으로 SRAM과 많은 부분의 기능들을 공유하고 있는 것으로 보여진다. 하지만 CCM(Core Coupled Memory)이라는 이름에서 보듯이 stm32f405rg의 핵심 부분인 arm cortex-m4와 직접적으로 연결되어 있는 것으로 보인다. 이와 같은 사항은 데이터 시트에서 확인 가능하다.

stm32f405rg의 내부 블럭 다이어 그램
 다른 메모리들(SRAM 112KB, SRAM 16KB, 그리고 Flash)과 다르게 AHB라는 버스 제어 블럭을 거치지 않기 때문에 아마도 CCM을 연산용 메모리를 사용하면 좀 더 빠르게 처리가 가능할 것으로 여겨진다. 하지만, 그림에서도 보듯이 D-BUS만 연결되어 있기 때문에 코드가 직접 실행되는 것을 불가능하고 데이터를 저장하고 읽는 것만 가능한 것 같다. 그럼 CCM의 특성에 해당하는 "x"는 제거하는 것이 마땅할 것으로 여겨진다. 다음과 같이...

 ccm (rw)  : ORIGIN = 0x10000000, LENGTH = 64K  

 그리고 마지막으로 SRAM은 하드웨어적으로 두 개로 구분되어 있지만 두 SRAM이 연속된 메모리 공간에 위치해 있기때문에 하나의 SRAM으로 간주하여 지정되어 있다.

 하지만, 위의 메모리 구성 그림에는 있으나, 스크립트에서는 제외된 Flash 메모리가 존재한다. 위치는 0x00800000에서 0x008fffff에 해당하는 1024Kbyte용량의 메모리이다. 추정해 보건데 아마도 BOOT 핀들의 구성에 따라 Flash가 재 배치되는 공간인 것 같다. 광고에도 없는 메모리를 보너스를 넣어 줄 만큼 STMicrosystem이 훈훈하지는 않을 것이다. 아무리 선진국 프랑스의 회사라고 해도 말이다.

바이너리 코드의 섹션 배치용 변수 지정

 위와 같이 구성된 메모리에 C언어로 컴파일된 바이너리 코드를 배치하기 위해서 링커스크립트는 다음과 같은 참조용 변수를 지정한다. 이것은 어디 까지나 사용자에 따라 무한히 변경이 가능하기 때문에 용도에 따라서 얼마든지 변경 가능하다.

 __rom_start__     = ORIGIN(flash);  
 __rom_size__     = LENGTH(flash);  
 __ram_start__     = ORIGIN(ram);  
 __ram_size__     = LENGTH(ram);  
 __ram_end__     = __ram_start__ + __ram_size__;  
 __stack_end__     = __ram_end__;          /* Top of RAM */  
 __stack_size__     = 16K;  
 __stack_start__     = __stack_end__ - __stack_size__;  
 __heap_start__     = __bss_end__;          /* Between bss and stack */  
 __heap_end__     = __stack_start__;  
 __ccm_start__     = ORIGIN(ccm);  
 __ccm_size__     = LENGTH(ccm);  

 위의 변수들은 이름에서 보듯이 전통적으로 실행 코드만 위치하게 되는 rom 영역의 시작주소와 크기, 데이터만 들어 가게 되는 ram 영역의 시작주소 및 크기, 그리고 램의 마지막주소에서 16Kbyte영역에 해당하는 stack을 위한 영역 시작 주소와 크기, 그리고 마지막 주소에서 부터 사용하는 stack 의 초기 주소를 heap영역을 bss영역의 마지막 주소에서 stack의 시작주소에 해당하는 영역으로 지정한다. 그리고 마지막으로 특수 영역인 ccm의 시작 주소와 크기를 지정한다. 이와 같은 변수들은 startup 코드인 stm32f405rg.S에서 나중에 참조하여 레지스터를 설정하고 영역 초기화하는데 사용할 것이다. 하지만 위의 변수 중 __bss_end__라는 것은 정의 되지 않고 참조만 하고 있다. 이것은 나중에 다시 나올 것이다. 여담 이지만 이와 같은 코드는 상호 참조가 너무 많아서 어디에서 정의 되는지 아니면 컴파일러에서 만들어 주는 것인지 판단하기가 쉽지 않다. 아무튼 어디엔가 있을 것이다.

 SECTIONS  
 {  
  . = 0;  
  .text : {  
  KEEP(*(.startup))               /* Startup code */  
  *(.text*)                    /* Program code */  
  KEEP(*(.rodata*))               /* Read only data */  
  *(.glue_7)  
  *(.glue_7t)  
  *(.eh_frame)  
  . = ALIGN(4);  
  __ctors_start__ = .;  
  KEEP(*(.init_array));               /* C++ constructors */  
  KEEP(*(.ctors));               /* C++ constructors */  
  __ctors_end__ = .;  
  . = ALIGN(16);  
  __text_end__ = .;  
  } >flash  
  .data : ALIGN(16) {  
  __data_beg__ = .;               /* Used in crt0.S */  
  *(.data)                    /* Initialized data */  
  __data_end__ = .;               /* Used in crt0.S */  
  } >ram AT > flash  
  .bss (NOLOAD) : ALIGN(16) {  
  __bss_beg__ = .;               /* Used in crt0.S */  
  *(.bss)                    /* Uninitialized data */  
  *(COMMON)                    /* Common data */  
  __bss_end__ = .;               /* Used in crt0.S */  
  } >ram  
 /* C++ exception unwinding stuff--needed by some toolchains */  
  .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >flash  
  __exidx_start = .;  
  .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >flash  
  __exidx_end = .;  
 }  


 위의 섹션 지정을 이해 하려면 linker command language를 약간 알아 두어야 한다. 먼저 섹션은 크게 3가지로 재배치 되어 진다. text, data 그리고 bss로 관리되며, 그 이름에서도 알 수 있듯이 각각 프로그램 코드, 변수의 데이터, 그리고 동적할당과 Stack을 위한 메모리 공간으로 이름 붙여 졌음을 알 수 있다. 그리고 그 해당 영역은 flash, ram, ram으로 할당되어 있다. 

 

 다음은 C언어를 컴파일러가 메모리 영역을 관리하는 각 섹션에 대한 설명이다.
- Code 섹션: 순수한 실행 코드만 가지고 있는 섹션, 일반적으로 rom과 같은 매체에 위치하게 된다.
- Data 섹션 : 값이 초기화된 전역변수와 값이 초기화된 static 타입의 함수 내에서 정의된 변수를 위해 할당된 메모리 공간
- Bss 섹션 : 값이 초기화 되지 않은 전역변수와 값이 초기화 되지 않은 static 타입의 함수 내에서 정의된 변수를 위해 할당된 메모리 공간
- Heap 섹션 : 동적 메모리 할당(malloc, realloc 등의 기능)을 위해 확보된 메모리 공간
- Stack 섹션 : 말 그대로 스텍 영역 - 함수 호출등으로 발생하는 변수 넘기기 혹은 각 함수의 지역 변수를 위해 확보되는 메모리 공간

 

 text 섹션을 살펴보면, 우선 첫 번째 문장은 location counter를 0으로 설정하는 부분으로 혹시나 해서 넣어 둔 것 같다. 자동적으로 0이 될 것은 자명하기 때문이다(".=0"). 그리고 다음 줄은 출력 파일 즉, 컴파일 과정에서 수집된 모든 실행 파일의 text section을 채워 넣는 부분으로 위치는 위에서 설정한 flash의 영역이 된다(".text : {"). 이 text section에는 순수하게 프로그램을 수행하기 위한 코드들을 위한 메모리 영역이고 프로그램이 수행되는 기간 동안에 내용이 변경될 경우를 고려하지 않는 영역이다.  첫 번째로 채워질 내용은 "KEEP(*(.startup))"으로  startup section의 그 내용이 다른 곳에서 참조되어 지지않거나 사용되지 않아도 강제적으로 넣어 두도록 KEEP 옵션을 추가해 두었다. 그리고 본래의 목적인 프로그램을 수행하는 내용을 담고 있는 text section 을 추가하고 ("*(.text*)"),  통상 인터럽트 테이블 같은 참조 목적으로만 생성된 데이터를 위한 rodata section을 추가한다("KEEP(*(.rodata*))"). 여기까지가 가장 핵심이 되는 재 배치될 text section의 내용이고, 그 내용은 startup 코드 내용, 본래의 프로그램 코드 내용, 그리고 인터럽트 벡터 테이블 같은 참조용 데이터 들이 차지하고 있다. ". = ALIGN(4);"을 통해서 이후의 내용의 경계를 4바이트 단위로 관리한다. .glue_7과 .glue_7t는 각각 Arm 컴파일러가 생성해 내는 중간 코드를 위한 영역으로 glue_7섹션은 ARM Mode에서 동작할때의 중간 코드, glue_7t는 Thumb mode에서 동작할 때의 중간 코드를 가지고 있을 것이라 추정된다. 그리고 나머지 부분들은 C++코드를 수행하는데 필요한 생성자의 시작(__ctors_start), 끝(__ctors_end__)을 지정하는 환경 변수 지정, 그리고 그 안에 생성자(ctor 섹션), 그리고 init_array 색션을 놓아 두게 된다.

  data 섹션은 모든 바이너리 파일들의 data 섹션을 한데 모아 넣어 두고 그 영역의 시작(__data_beg__), 끝(__data_end__)에 해당하는 환경 변수도 잊지 않고 만들어 준다. 그리고 data 섹션의경계는 16바이트 단위로 관리한다("ALIGN(16)"). 이 내용은 모두 ram에 적재되지만, 그 복사본을 flash에 담아 둔다(">ram AT > flash").  이 부분은 코드 내용과 같이 보아야만 이해 할 수 있다.

 마지막으로 bss 섹션은 모든 바이너리 파일의 초기화 되지 않은 데이터를 위한 bss 섹션과 COMMON 섹션을 담아 두고 그 영역의 시작(__bss_beg__)과 끝(__bss_end__)을 환경 변수로 등록한다. 여기서 NOLOAD는 솔직히 나도 정확히 어떤 역할을 하는지 모르겠다.

그럼 위의 각 섹션이 stm32f405rg의 메모리 구성에 비추어 어떻게 배치되는지 그림을 그려보자.


stm32f405rg.S의 분석

해당 코드의 첫 번째 내용은 다음과 같다.

		.syntax 	unified
		.thumb
		.section	.startup, "x"

위에서 보듯이 Thumb  모드에서 동작하는 코드이며, 차지하게될 영역의 센셕을 startup으로 지정한다. "x"는 실행하는 목적으로 생성되는 영역이라는 지시어 같다.

 그리고 다음은 다른 소스코드 파일에서 참조할 수 있도록 전역 변수를 지정하고 있다.

		.global		_start
		.global		_vectors

그 변수는 _start와 _vectors로 초기화 코드 내용의 시작지점 그리고 인터럽트 벡터의 시작 위치를 지정하고 있다.



------------------------------------------------------------------------------------------------------------
참고 사항: FreeRTOS에서는 자체적인 동적 메모리 할당 메카니즘을 가지고 있다. 메모리를 할당하는 기능은 pvPortMalloc()이 하고, vPortFree()로 할당된 메모리를 해제한다. 그리고 내부적으로 할당하는 기능을 여러가지로 지원하는데 ./FreeRTOS/Source/portable/MemMang/ 밑에 총 네 가지의 동적 메모리 관리 기능을 heap_?.c등의 파일로 지원하고 관리하게 될 heap 영역의 크기는 각 Demo 디렉토리 밑에 두어야 할 FreeRTOSConfig.h에 다음과 같이 지정한다.

 #define configMINIMAL_STACK_SIZE          ( ( unsigned short ) 130 )  
 #define configTOTAL_HEAP_SIZE               ( ( size_t ) ( 75 * 1024 ) )  
------------------------------------------------------------------------------------------------------------



............작업중..........

2013년 11월 8일 금요일

데비안 리눅스에서 관리가 편한 arm cross toolchain인 emdebian 설치하기

리눅스에는 많은 좋은 점이 있지만,

나한테는 무엇보다도 휼용한 gcc cross 컴파일러를 사용할 수 있다는 것이 너무나도 좋다.

뭐 기본적인 컴파일러는 많은 곳에서 다운로드하여 사용할 수 있다.

그런데 뭔가 좀 하려다 보면 특정 라이브러리

예를 들면 freetype같은 폰트 라이브러리 같은 것을 쓰려다 보면

해당 소스코드를 다운로드하고 내가 가지고 있는 컴파일러에 맞게

configure와 Makefile 수정을 하고 컴파일하고

컴파일이 완료된 Library와 include 파일들을 복사하는 과정을 거쳐야 한다.

이것이 끝이 아니라 버그 수정이나 버전 상승이 발생하면 위의 모든 과정을 다시 거쳐야한다.

하지만, 여러분의 시스템이 데비안 시스템 혹은 데비안 호완 시스템이면

xapt라는 프로그램을 사용해서 이미 cross 컴파일된 패키지를 자동으로 관리해 준다.

이와 같은 것을 구현하려면 emdebian에서 제공하는

armel의 cross compiler와 라이브러리를 설치해야한다.

emdebian의 패키지를 받아 볼 수 있는 저장소는

아마도 여러분의 apt 소스 리스트에 없을 것이다.

 - /etc/apt/source.list.d/emdebian.list  
 deb http://www.emdebian.org/debian/ testing main  

그리고 하나 참고할 사항은 지금 작업하고 설정이 이루어지는 시스템은 jessie debian 임을 밝혀둔다.

그럼 emdebian의 인증키를 다운받아 설치하자.

 # apt-get install emdebian-archive-keyring  
 # apt-get update  

사전 설정은 어느정도 마무리 되었다.

그럼 현 시점에서 제공되고 있는 arm cross toolchain 패키지를 살펴보자.

 # apt-cache search armel  
 asterisk-prompt-fr-armelle - French voice prompts for Asterisk by Armelle Desjardins  
 debian-installer-7.0-netboot-armel - Debian-installer network boot images for armel  
 installation-guide-armel - Debian installation guide for armel  
 icedtea-6-jre-cacao - Alternative JVM for OpenJDK, using Cacao  
 icedtea-6-jre-jamvm - Alternative JVM for OpenJDK, using JamVM  
 icedtea-7-jre-jamvm - Alternative JVM for OpenJDK, using JamVM  
 cpp-4.3-arm-linux-gnueabi - The GNU C preprocessor  
 cpp-4.4-arm-linux-gnueabi - GNU C preprocessor  
 cpp-4.5-arm-linux-gnueabi - The GNU C preprocessor  
 cpp-4.6-arm-linux-gnueabi - GNU C preprocessor  
 cpp-4.7-arm-linux-gnueabi - GNU C preprocessor  
 g++-4.3-arm-linux-gnueabi - The GNU C++ compiler  
 g++-4.4-arm-linux-gnueabi - GNU C++ compiler  
 g++-4.5-arm-linux-gnueabi - The GNU C++ compiler  
 g++-4.6-arm-linux-gnueabi - GNU C++ compiler  
 g++-4.7-arm-linux-gnueabi - GNU C++ compiler  
 gcc-4.3-arm-linux-gnueabi - The GNU C compiler  
 gcc-4.4-arm-linux-gnueabi - GNU C compiler  
 gcc-4.4-base-armel-cross - The GNU Compiler Collection (base package) (for cross-compiling)  
 gcc-4.5-arm-linux-gnueabi - The GNU C compiler  
 gcc-4.6-arm-linux-gnueabi - GNU C compiler  
 gcc-4.7-arm-linux-gnueabi - GNU C compiler  
 libc-bin-armel-cross - Embedded GNU C Library: Binaries (for cross-compiling)  
 libc-dev-bin-armel-cross - Embedded GNU C Library: Development binaries (for cross-compiling)  
 libc6-armel-cross - Embedded GNU C Library: Shared libraries (for cross-compiling)  
 libc6-dev-armel-cross - Embedded GNU C Library: Development Libraries and Header Files (for cross-compiling)  
 libgcc1-dbg-armel-cross - GCC support library (debug symbols)  
 libgfortran3-armel-cross - Runtime library for GNU Fortran applications  
 libgfortran3-dbg-armel-cross - Runtime library for GNU Fortran applications (debug symbols)  
 libgmp-dev-armel-cross - Multiprecision arithmetic library developers tools (for cross-compiling)  
 libgmp10-armel-cross - Multiprecision arithmetic library (for cross-compiling)  
 libgmp3-dev-armel-cross - Multiprecision arithmetic library developers tools (for cross-compiling)  
 libgmp3c2-armel-cross - Multiprecision arithmetic library (for cross-compiling)  
 libgmpxx4ldbl-armel-cross - Multiprecision arithmetic library (C++ bindings) (for cross-compiling)  
 libgo0-armel-cross - Runtime library for GNU Go applications  
 libgo0-dbg-armel-cross - Runtime library for GNU Go applications (debug symbols)  
 libgomp1-armel-cross - GCC OpenMP (GOMP) support library (for cross-compiling)  
 libgomp1-dbg-armel-cross - GCC OpenMP (GOMP) support library (debug symbols)  
 libmpfr-dev-armel-cross - multiple precision floating-point computation developers tools (for cross-compiling)  
 libmpfr1ldbl-armel-cross - multiple precision floating-point computation (for cross-compiling)  
 libmpfr4-armel-cross - multiple precision floating-point computation (for cross-compiling)  
 libmudflap0-4.4-dev-armel-cross - GCC mudflap support libraries (development files)  
 libmudflap0-4.5-dev-armel-cross - GCC mudflap support libraries (development files)  
 libmudflap0-4.6-dev-armel-cross - GCC mudflap support libraries (development files)  
 libmudflap0-4.7-dev-armel-cross - GCC mudflap support libraries (development files)  
 libmudflap0-armel-cross - GCC mudflap shared support libraries  
 libmudflap0-dbg-armel-cross - GCC mudflap shared support libraries (debug symbols)  
 libobjc2-armel-cross - Runtime library for GNU Objective-C applications  
 libobjc2-dbg-armel-cross - Runtime library for GNU Objective-C applications (debug symbols)  
 libobjc3-armel-cross - Runtime library for GNU Objective-C applications  
 libobjc3-dbg-armel-cross - Runtime library for GNU Objective-C applications (debug symbols)  
 libobjc4-armel-cross - Runtime library for GNU Objective-C applications  
 libobjc4-dbg-armel-cross - Runtime library for GNU Objective-C applications (debug symbols)  
 libstdc++6-4.3-dbg-armel-cross - The GNU Standard C++ Library v3 (debugging files)  
 libstdc++6-4.3-dev-armel-cross - The GNU Standard C++ Library v3 (development files)  
 libstdc++6-4.3-pic-armel-cross - The GNU Standard C++ Library v3 (shared library subset kit)  
 libstdc++6-4.4-dbg-armel-cross - GNU Standard C++ Library v3 (debugging files)  
 libstdc++6-4.4-dev-armel-cross - GNU Standard C++ Library v3 (development files)  
 libstdc++6-4.4-pic-armel-cross - GNU Standard C++ Library v3 (shared library subset kit)  
 libstdc++6-4.5-dbg-armel-cross - The GNU Standard C++ Library v3 (debugging files)  
 libstdc++6-4.5-dev-armel-cross - The GNU Standard C++ Library v3 (development files)  
 libstdc++6-4.5-pic-armel-cross - The GNU Standard C++ Library v3 (shared library subset kit)  
 libstdc++6-4.6-dbg-armel-cross - GNU Standard C++ Library v3 (debugging files)  
 libstdc++6-4.6-dev-armel-cross - GNU Standard C++ Library v3 (development files)  
 libstdc++6-4.6-pic-armel-cross - GNU Standard C++ Library v3 (shared library subset kit)  
 libstdc++6-4.7-dbg-armel-cross - GNU Standard C++ Library v3 (debugging files)  
 libstdc++6-4.7-dev-armel-cross - GNU Standard C++ Library v3 (development files)  
 libstdc++6-4.7-pic-armel-cross - GNU Standard C++ Library v3 (shared library subset kit)  
 libstdc++6-armel-cross - GNU Standard C++ Library v3 (for cross-compiling)  
 linux-libc-dev-armel-cross - Linux support headers for userspace development (for cross-compiling)  
 tzdata-armel-cross - time zone and daylight-saving time data (for cross-compiling)  
 zlib1g-armel-cross - compression library - runtime (for cross-compiling)  
 zlib1g-dev-armel-cross - compression library - development (for cross-compiling)  
 gcc-4.8-base-armel-cross - GCC, the GNU Compiler Collection (base package) (for cross-compiling)  
 libgcc1-armel-cross - GCC support library (for cross-compiling)  
 multiarch-support-armel-cross - Transitional package to ensure multiarch compatibility (for cross-compiling)  
 libpng12-0-armel-cross - PNG library - runtime (for cross-compiling)  

위의 리스트에서 필요한 것들은

 linux-libc-dev-armel-cross,  
 libc6-armel-cross libc6-dev-armel-cross,  
 binutils-arm-linux-gnueabi,  
 gcc-4.7-arm-linux-gnueabi,  
 g++-4.7-arm-linux-gnueabi  

등이다. 하지만, 다음과 같이 뭔가 버전 문제가 발생한다.

 # apt-get install libc6-dev-armel-cross  
 패키지 목록을 읽는 중입니다... 완료  
 의존성 트리를 만드는 중입니다      
 상태 정보를 읽는 중입니다... 완료  
 몇몇 패키지를 설치할 수 없습니다. 요청한 상황이 불가능할 수도 있고,  
 불안정 배포판을 사용해서 일부 필요한 패키지를 아직 만들지 않았거나,  
 아직 Incoming에서 나오지 않은 경우일 수도 있습니다.  
 이 상황을 해결하는데 다음 정보가 도움이 될 수도 있습니다:  
 다음 패키지의 의존성이 맞지 않습니다:  
  libc6-dev-armel-cross : 의존: libc6-armel-cross (= 2.13-37) 하지만 2.17-93 패키지를 설치할 것입니다  
              의존: libc-dev-bin-armel-cross (= 2.13-37) 하지만 %s 패키지를 설치하지 않을 것입니다  
 E: 문제를 바로잡을 수 없습니다. 망가진 고정 패키지가 있습니다.  

필요로 하는 libc6-dev-armel-cross가

설치된 버전 혹은 현재의 소스 리스트의 추천 버전과 맞지 않음을 이야기 하는 것 같다.

그래서 현재 설정된 패키지 환경하에서 어떤 버전이 추천되어 있거나 설치되어 있는지 살펴 보았다.

 # apt-cache show libc6-armel-cross  
 Package: libc6-armel-cross  
 Status: install ok installed  
 Priority: extra  
 Section: libs  
 Maintainer: GNU Libc Maintainers <debian-glibc@lists.debian.org>  
 Architecture: all  
 Source: eglibc  
 Version: 2.17-93  
 Provides: glibc-2.17-1-armel-cross, libc6-armel-dcv1  
 Depends: libgcc1-armel-cross  
 Conflicts: prelink-armel-cross (<= 0.0.20090311-1), tzdata-armel-cross (<< 2007k-1), tzdata-etch-armel-cross  
 Description: Embedded GNU C Library: Shared libraries (for cross-compiling)  
  This package was generated by dpkg-cross for cross compiling.  
  .  
  Contains the standard libraries that are used by nearly all programs on  
  the system. This package includes shared versions of the standard C library  
  and the standard math library, as well as many others.  
 Description-md5: 24a92b169d87e4acb423e610210802be  
 Package: libc6-armel-cross  
 Version: 2.13-37  
 Architecture: all  
 Maintainer: GNU Libc Maintainers <debian-glibc@lists.debian.org>  
 Source: eglibc  
 Provides: glibc-2.13-1-armel-cross, libc6-armel-dcv1  
 Depends: libc-bin-armel-cross (= 2.13-37), libgcc1-armel-cross  
 Conflicts: prelink-armel-cross (<= 0.0.20090311-1), tzdata-armel-cross (<< 2007k-1), tzdata-etch-armel-cross  
 Priority: extra  
 Section: libs  
 Filename: pool/main/e/eglibc/libc6-armel-cross_2.13-37_all.deb  
 Size: 1313090  
 SHA256: 8607015bf3d53b0b7cc79e0ce7208609c4feec58be1f3d8e8e02039bb0551044  
 SHA1: c241df537bfd49221c4d37fbd020582ee6ae0044  
 MD5sum: 54b58aa8641f7ada31e9199ed0405d69  
 Description: Embedded GNU C Library: Shared libraries (for cross-compiling)  
  This package was generated by dpkg-cross for cross compiling.  
  .  
  Contains the standard libraries that are used by nearly all programs on  
  the system. This package includes shared versions of the standard C library  
  and the standard math library, as well as many others.  
 Description-md5: 24a92b169d87e4acb423e610210802be  

보아하니 설치된 것은 2.17-39이고 2.13-37도 제공하고 있는 것으로 추정된다.

정확히 무슨 말인지는 모르겠다.

그래서 해당 배포판의 해당 패키지의 정책에 대해서 살펴 보았다.

 # apt-cache policy libc6-armel-cross  
 libc6-armel-cross:  
  설치: 2.17-93  
  후보: 2.17-93  
  버전 테이블:  
  *** 2.17-93 0  
     100 /var/lib/dpkg/status  
    2.13-37 0  
     500 http://ftp.uk.debian.org/emdebian/toolchains/ testing/main amd64 Packages  

뭐 같은 이야기 인것 같다.

그럼 libc6-dev-armel-cross를 설치하는데 의존성을 가지고 있는 2.13-37 버전을 수동으로 설치하자.

 # apt-get install libc6-armel-cross=2.13-37  
 패키지 목록을 읽는 중입니다... 완료  
 의존성 트리를 만드는 중입니다      
 상태 정보를 읽는 중입니다... 완료  
 다음 패키지를 더 설치할 것입니다:  
  libc-bin-armel-cross  
 다음 새 패키지를 설치할 것입니다:  
  libc-bin-armel-cross  
 다음 패키지를 다운그레이드할 것입니다:  
  libc6-armel-cross  
 0개 업그레이드, 1개 새로 설치, 1개 업그레이드, 0개 제거 및 0개 업그레이드 안 함.  
 1,314 k바이트 아카이브를 받아야 합니다.  
 이 작업 후 0 바이트의 디스크 공간을 더 사용하게 됩니다.  
 계속 하시겠습니까? [Y/n]   

자 그럼 중단된 설치를 마무리 하자.

 # apt-get install linux-libc-dev-armel-cross libc6-armel-cross libc6-dev-armel-cross binutils-arm-linux-gnueabi gcc-4.7-arm-linux-gnueabi g++-4.7-arm-linux-gnueabi  

cross toolchain의 설치는 마무리 된 것 같다. 그럼 gcc가 잘 설치 되었는지 살펴보자.

 # arm-linux-gnueabi-gcc-4.7 -v  
 Using built-in specs.  
 COLLECT_GCC=arm-linux-gnueabi-gcc-4.7  
 COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabi/4.7/lto-wrapper  
 Target: arm-linux-gnueabi  
 Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-4' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/arm-linux-gnueabi/include/c++/4.7.2 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --enable-plugin --enable-objc-gc --disable-sjlj-exceptions --with-arch=armv4t --with-float=soft --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabi --program-prefix=arm-linux-gnueabi- --includedir=/usr/arm-linux-gnueabi/include --with-headers=/usr/arm-linux-gnueabi/include --with-libs=/usr/arm-linux-gnueabi/lib  
 Thread model: posix  
 gcc version 4.7.2 (Debian 4.7.2-4)   

그럼 마지막으로 cross 컴파일된 각종 라이브러리를 자동으로 관리 해줄 xapt를 설치하자.

 # apt-get install pdebuild-cross dpkg-cross xapt  

xapt는 설치할 아키텍쳐와 설치할 패키지를 다음과 같이 지정하여 실행할 수 있다.

 # xapt update  
 # xapt -a armel -m libpng12-0  

위의 과정은 libpng12-0의 armel 아키텍쳐로 cross 컴파일된 버전을 설치하는 명령어이다.

2013년 11월 7일 목요일

amd64의 데비안 리눅스 시스템에서 i386 바이너리 실행하기

시스템은 졸지에 amd64로 변경하는 바람에

이전에 아무런 문제없이 사용하던 arm-none-eabi-gcc이 실행 되지 않는다.

좀 친절하게 아키텍쳐가 달라서 실행할 수 없다라는 메시지를 던져 주면 좋았으려만,

분명히 그 경로에 이 파일이 있는데 arm-none-eabi-gcc를 찾을 수 없다라는 말만해서

바이러스에 결린 건가 하는 생각만 했었다.

뭐 arm-none-eabi-gcc(https://launchpad.net/gcc-arm-embedded)의 관리자가 amd64 시스템에서 한번 더 컴파일해서

올려 주면 만사 해결이지만 아직은 그렇지 못하다.

그래서 어쩔 수 없이 amd64로 깔린 시스템에 다중 아키텍쳐를 설정하고

중복해서 i386 라이브러리를 설치해야 한다.

이 일련의 과정은 amd64의 jessie 데비안 시스템에서 이루어 졌다.

시스템에 부가적으로 i386 아키텍쳐 추가하기

 # dpkg --add-architecture i386  

그리고 패키지 저장소 정보를 업데이트 하자

 # apt-get update  

자 그럼 이제 arm-none-eabi-gcc를 실행하는데 필요한 라이브러리를 설치하자. 물론 i386 기반의 바이너리이어야 한다.

 # apt-get install libc6:i386 libstdc++6:i386 libncurses5:i386 zlib1g:i386  

마지막으로 실행되는지 확인해 보도록 하자.

 # arm-none-eabi-gcc -v  

 Using built-in specs.  
 COLLECT_GCC=arm-none-eabi-gcc  
 COLLECT_LTO_WRAPPER=/home/daysleep/workspace/arm_projects/gcc-arm-none-eabi-4_7-2013q2/bin/../lib/gcc/arm-none-eabi/4.7.4/lto-wrapper  
 Target: arm-none-eabi  
 Configured with: /home/build/work/GCC-4-7-build/src/gcc/configure --target=arm-none-eabi --prefix=/home/build/work/GCC-4-7-build/install-native --libexecdir=/home/build/work/GCC-4-7-build/install-native/lib --infodir=/home/build/work/GCC-4-7-build/install-native/share/doc/gcc-arm-none-eabi/info --mandir=/home/build/work/GCC-4-7-build/install-native/share/doc/gcc-arm-none-eabi/man --htmldir=/home/build/work/GCC-4-7-build/install-native/share/doc/gcc-arm-none-eabi/html --pdfdir=/home/build/work/GCC-4-7-build/install-native/share/doc/gcc-arm-none-eabi/pdf --enable-languages=c,c++ --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-nls --disable-shared --disable-threads --disable-tls --with-gnu-as --with-gnu-ld --with-newlib --with-headers=yes --with-python-dir=share/gcc-arm-none-eabi --with-sysroot=/home/build/work/GCC-4-7-build/install-native/arm-none-eabi --build=i686-linux-gnu --host=i686-linux-gnu --with-gmp=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-mpfr=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-mpc=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-ppl=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-cloog=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-libelf=/home/build/work/GCC-4-7-build/build-native/host-libs/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-pkgversion='GNU Tools for ARM Embedded Processors' --with-multilib-list=armv6-m,armv7-m,armv7e-m,armv7-r  
 Thread model: single  
 gcc version 4.7.4 20130613 (release) [ARM/embedded-4_7-branch revision 200083] (GNU Tools for ARM Embedded Processors)