Chinaunix首页 | 论坛 | 博客
  • 博客访问: 234845
  • 博文数量: 27
  • 博客积分: 358
  • 博客等级: 一等列兵
  • 技术积分: 291
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 17:35
文章分类

全部博文(27)

文章存档

2015年(1)

2014年(4)

2013年(6)

2012年(4)

2011年(12)

分类: 嵌入式

2011-04-22 17:35:50

转自:http://blog.csdn.net/ebrother/archive/2009/04/27/4127171.aspx

前段时间一直在用IAR开发一款基于Luminary LM3S系列芯片的产品,可是在加入TCP/IP协议栈的时候遇到了32K的代码限制,在google上搜索了好几天都没有找到破解版本(想省点银子),结果大失所望,要么就是4.10的keygen,5.10的keygen竟然不好用。

    天无绝人之路,本还没打算这么早投入gcc怀抱,看来只能提前了。在写这篇文章的时候,已经能够用OpenOCD下载由arm-elf-gcc编译的firmware,并且能够设置断点。后续文章将做介绍,现在就把编译gcc的过程贴出来,老外写的E文,我就不翻译了,有些做了点修改。

[操作系统] UBUNTU 8.04 / 8.10。比较推荐用这个系统,好用。

This tutorial explains how you can create a GCC+Newlib toolchain that can be used to compile programs for the Cortex (Thumb2) architecture, thus making it possible to use GCC to compile programs for the increasingly number of Cortex CPUs out there (, ST, with new Cortex CPUs being announced by Atmel and other companies). I am writing this tutorial because I needed to work on a Cortex CPU for the eLua project and I couldn't find anywhere a complete set of instructions for building GCC for this architecture. You'll need such a toolchain if you want to compile eLua for Cortex-M3 CPUs.

DISCLAIMER: I'm by no means a specialist in the GCC/newlib/binutils compilation process. I'm sure that there are better ways to accomplish what I'm describing here, however I just wanted a quick and dirty way to build a toolchain, I have no intention in becoming too intimate with the build process. If you think that what I did is wrong, innacurate, or simply outrageously ugly, feel free to  and I'll make the necessary corrections. And of course, this tutorial comes without any guarantees whatsoever.

Prerequisites

To build your toolchain you'll need:

  • a computer running Linux: I use Ubuntu 8.04, but any Linux will do as long as you know how to find the equivalent of "apt-get" for your distribution. I won't be going into details about this, google it and you'll sure find what you need. It is also assumed that the Linux system already has a "basic" native toolchain installed (gcc/make and related). This is true for Ubuntu after installation. Again, you might need to check your specific distribution.
  • GNU binutils: get it from . At the moment of writing this, the latest versions is 2.18, which for some weird reason refuses to compile on my system, so I'm using 2.17 instead. UPDATE: you MUST use the new binutils 2.19 distribution for the Cortex toolchain, since it fixes some assembler issues. You won't be able to compile eLua 0.5 or higher if you don't use binutils 2.19.
  • GCC: since support for Cortex (Thumb2) was only introduced staring with version 4.3.0, you'll need to download version 4.3.0 or newer. As I'm writing this, the latest GCC version is 4.3.1, which I'll be using for this tutorial. Download it from  after choosing a suitable mirror.
  • Newlib: as I'm writing this, the latest official Newlib version is 1.16.0. However, the CVS version contains some fixes for the Thumb2 architecture, some of them in very important functions (like setjmp/longjmp), so you'll need to fetch the sources from CVS (this will most likely change when a new official Newlib version is released). So go to  and follow the instructions there in order to get the latest sources from CVS.
  • Also, the tutorial assumes that you're using bash as your shell. If you use something else, you might need to adjust some shell-specific commands.

Also, you need some support programs/libraries in order to compile the toolchain. To install them:

$ sudo apt-get install flex bison libgmp3-dev libmpfr-dev autoconf texinfo build-essential

Next, decide where you want to install your toolchain. They generally go in /usr/local/, so I'm going to assume /usr/local/cross-cortex for this tutorial. To save yourself some typing, set this path into a shell variable:

$ mkdir /opt/cross-cortex                                                                                                    

$ export TOOLPATH=/opt/cross-cortex                                                                               

Step 1: binutils

This is the easiest step: unpack, configure, build.

$ tar -xvjf binutils-2.19.tar.bz2
$ cd binutils-2.19
$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls
$ make all
$ sudo make install
$ export PATH=${TOOLPATH}/bin:$PATH

Now you have your ARM "binutils" (assembler, linker, disassembler ...) in your PATH. They are fully capable of handling Thumb2.

Step 2: basic GCC

In this step we build a "basic" GCC (that is, a GCC without any support libs, which we'll use in order to build all the libraries for our target). But first we need to make a slight modification in the configuration files. Out of the box, the GCC 4.3.1/newlib combo won't compile properly, giving a very weird "Link tests are not allowed after GCC_NO_EXECUTABLES" error. After a bit of googling, I found the solution for this:

$ tar -xvjf gcc-4.4.0.tar.bz2
$ cd gcc-4.4.0/libstdc++-v3
$ gedit configure.ac

Now find the line which says "AC_LIBTOOL_DLOPEN" and comment it out by adding a "#" before it:[注:这里用最新的4.4.0,而没有用原文的4.3.1,编译是一样的]

# AC_LIBTOOL_DLOPEN
[注:我遇到的是,在产生configure文件时,会产生包含这个的三句脚本,需要全注释掉]
Save the modified file and exit the text editor
$ autoconf
$ cd ..

Great, now we know it will compile, so let's do it:

$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --enable-multilib --enable-languages="c,c++" --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld
$ make all-gcc
$ sudo make install-gcc
# export PATH=/opt/cross-cortex/bin:$PATH
# make install-gcc
# exit

Step 3: Newlib

Again, some modifications are in order before we start compiling. Because the CVS version of Newlib doesn't seem to have all the required support for Thumb2 yet, we need to tell Newlib to skip some of its libraries when compiling:

$ cd [directory where the newlib CVS is located]
$ gedit configure.ac

Find this fragment of code:

arm-*-elf* | strongarm-*-elf* | xscale-*-elf* | arm*-*-eabi* )
noconfigdirs="$noconfigdirs target-libffi target-qthreads"
libgloss_dir=arm
;;

And add "target-libgloss" to the "noconfigdirs" variable:

arm-*-elf* | strongarm-*-elf* | xscale-*-elf* | arm*-*-eabi* )
noconfigdirs="$noconfigdirs target-libffi target-qthreads target-libgloss"
libgloss_dir=arm
;;


Save the modified file and exit the text editor


$ autoconf

On one of the systems I ran the above sequence, it terminated with errors, complaining that autoconf 2.59 was not found. I don't know why that happens. 2.59 seems to be quite ancient, and the build ran equally well with 2.61 (the version of autoconf on the system that gave the error). If this happens to you, first execute autoconf --version to find the actual version of your autoconf, then do this:

$ joe config/override.m4

Look for this line:

[m4_define([_GCC_AUTOCONF_VERSION], [2.59])])

And replace [2.59] with your actual version ([2.61] in my case).
$ autoconf

[注:ubuntu 8.04,8.10的autoconf的版本都是2.61,所以必须更改,记得编译gcc也有类似问题,一定注意]

Once again, now we're ready to actually compile Newlib. But we need to tell it to compile for Thumb2. As already specified, I'm not a specialist when it comes to Newlib's build system, so I chosed the quick, dirty and not so elegant solution of providing the compilation flags directly from the command line. Also, as I wanted my library to be as small as possible (as opposed to as fast as possible) and I only wanted to keep what's needed from it in the final executable, I added the "-ffunction-sections -fdata-sections" flags to allow the linker to perform dead code stripping:

 

$ mkdir build
$ cd build
$ ../configure --target=arm-elf --prefix=$TOOLPATH --enable-interwork --disable-newlib-supplied-syscalls --with-gnu-ld --with-gnu-as --disable-shared
$ make CFLAGS_FOR_TARGET="-ffunction-sections -fdata-sections -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__ -Os -fomit-frame-pointer -mcpu=cortex-m3 -mthumb -D__thumb2__ -D__BUFSIZ__=256" CCASFLAGS="-mcpu=cortex-m3 -mthumb -D__thumb2__"
$ sudo make install

 

Some notes about the flags used in the above sequence:

  • --disable-newlib-supplied-syscalls: this deserves a page of its own, but I won't cover it here. For an explanation, see for example .
  • -DPREFER_SIZE_OVER_SPEED -D__OPTIMIZE_SIZE__: compile Newlib for size, not for speed (these are Newlib specific).
  • -mcpu=cortex-m3 -mthumb: this tells GCC that you want to compile for Cortex. Note that you need both flags.
  • -D__thumb2__: again, this is Newlib specific, and seems to be required when compiling Newlib for Cortex.
  • -Os -fomit-frame-pointer: tell GCC to optimize for size, not for speed.
  • -D__BUFSIZ__=256: again Newlib specific, this is the buffer size allocated by default for files opened via fopen(). The default is 1024, which I find too much for an eLua, so I'm using 256 here. Of course, you can change this value
Step 4: full GCC

Finally, in the last step of our tutorial, we complete the GCC build. In this stage, a number of compiler support libraries are built (most notably libgcc.a). Fortunately this is simpler that the Newlib compilation step, as long as you remember that we want to build our compiler support libraries for the Cortex architecture:

$ cd gcc-4.3.1/build
$ make CFLAGS="-mcpu=cortex-m3 -mthumb" CXXFLAGS="-mcpu=cortex-m3 -mthumb" LIBCXXFLAGS="-mcpu=cortex-m3 -mthumb" all
$ sudo make install

 

参考: http://eluaproject.dreamhosters.com/en/Building_GCC_for_Cortex

 

附录:

arm-elf-gcc已经可以使用了,下面就利用这个工具来编译代码,

 

startup.c

  1. //*****************************************************************************  
  2. //  
  3. // startup.c - Boot code for Stellaris.  
  4. //  
  5. // Copyright (c) 2005-2007 Luminary Micro, Inc.  All rights reserved.  
  6. //   
  7. // Software License Agreement  
  8. //   
  9. // Luminary Micro, Inc. (LMI) is supplying this software for use solely and  
  10. // exclusively on LMI's microcontroller products.  
  11. //   
  12. // The software is owned by LMI and/or its suppliers, and is protected under  
  13. // applicable copyright laws.  All rights are reserved.  You may not combine  
  14. // this software with "viral" open-source software in order to form a larger  
  15. // program.  Any use in violation of the foregoing restrictions may subject  
  16. // the user to criminal sanctions under applicable laws, as well as to civil  
  17. // liability for the breach of the terms and conditions of this license.  
  18. //   
  19. // THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED  
  20. // OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF  
  21. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.  
  22. // LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR  
  23. // CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.  
  24. //   
  25. // This is part of revision 1928 of the Stellaris Peripheral Driver Library.  
  26. //  
  27. //*****************************************************************************  
  28.   
  29. //*****************************************************************************  
  30. //  
  31. // Forward declaration of the default fault handlers.  
  32. //  
  33. //*****************************************************************************  
  34. void ResetISR(void);  
  35. static void NmiSR(void);  
  36. static void FaultISR(void);  
  37. static void IntDefaultHandler(void);  
  38.   
  39. //*****************************************************************************  
  40. //  
  41. // The entry point for the application.  
  42. //  
  43. //*****************************************************************************  
  44.   
  45.   
  46. //*****************************************************************************  
  47. //  
  48. // Reserve space for the system stack.  
  49. //  
  50. //*****************************************************************************  
  51. #ifndef STACK_SIZE  
  52. #define STACK_SIZE                              64  
  53. #endif  
  54. static unsigned long pulStack[STACK_SIZE];  
  55.   
  56. //*****************************************************************************  
  57. //  
  58. // The minimal vector table for a Cortex M3.  Note that the proper constructs  
  59. // must be placed on this to ensure that it ends up at physical address  
  60. // 0x0000.0000.  
  61. //  
  62. //*****************************************************************************  
  63. __attribute__ ((section(".isr_vector")))  
  64. void (* const g_pfnVectors[])(void) =  
  65. {  
  66.     (void (*)(void))((unsigned long)pulStack + sizeof(pulStack)),  
  67.                                             // The initial stack pointer  
  68.     ResetISR,                               // The reset handler  
  69.     NmiSR,                                  // The NMI handler  
  70.     FaultISR,                               // The hard fault handler  
  71.     IntDefaultHandler,                      // The MPU fault handler  
  72.     IntDefaultHandler,                      // The bus fault handler  
  73.     IntDefaultHandler,                      // The usage fault handler  
  74.     0,                                      // Reserved  
  75.     0,                                      // Reserved  
  76.     0,                                      // Reserved  
  77.     0,                                      // Reserved  
  78.     IntDefaultHandler,                      // SVCall handler  
  79.     IntDefaultHandler,                      // Debug monitor handler  
  80.     0,                                      // Reserved  
  81.     IntDefaultHandler,                      // The PendSV handler  
  82.     IntDefaultHandler,                      // The SysTick handler  
  83.     IntDefaultHandler,                      // GPIO Port A  
  84.     IntDefaultHandler,                      // GPIO Port B  
  85.     IntDefaultHandler,                      // GPIO Port C  
  86.     IntDefaultHandler,                      // GPIO Port D  
  87.     IntDefaultHandler,                      // GPIO Port E  
  88.     IntDefaultHandler,                      // UART0 Rx and Tx  
  89.     IntDefaultHandler,                      // UART1 Rx and Tx  
  90.     IntDefaultHandler,                      // SSI Rx and Tx  
  91.     IntDefaultHandler,                      // I2C Master and Slave  
  92.     IntDefaultHandler,                      // PWM Fault  
  93.     IntDefaultHandler,                      // PWM Generator 0  
  94.     IntDefaultHandler,                      // PWM Generator 1  
  95.     IntDefaultHandler,                      // PWM Generator 2  
  96.     IntDefaultHandler,                      // Quadrature Encoder  
  97.     IntDefaultHandler,                      // ADC Sequence 0  
  98.     IntDefaultHandler,                      // ADC Sequence 1  
  99.     IntDefaultHandler,                      // ADC Sequence 2  
  100.     IntDefaultHandler,                      // ADC Sequence 3  
  101.     IntDefaultHandler,                      // Watchdog timer  
  102.     IntDefaultHandler,                      // Timer 0 subtimer A  
  103.     IntDefaultHandler,                      // Timer 0 subtimer B  
  104.     IntDefaultHandler,                      // Timer 1 subtimer A  
  105.     IntDefaultHandler,                      // Timer 1 subtimer B  
  106.     IntDefaultHandler,                      // Timer 2 subtimer A  
  107.     IntDefaultHandler,                      // Timer 2 subtimer B  
  108.     IntDefaultHandler,                      // Analog Comparator 0  
  109.     IntDefaultHandler,                      // Analog Comparator 1  
  110.     IntDefaultHandler,                      // Analog Comparator 2  
  111.     IntDefaultHandler,                      // System Control (PLL, OSC, BO)  
  112.     IntDefaultHandler,                      // FLASH Control  
  113.     IntDefaultHandler,                      // GPIO Port F  
  114.     IntDefaultHandler,                      // GPIO Port G  
  115.     IntDefaultHandler,                      // GPIO Port H  
  116.     IntDefaultHandler,                      // UART2 Rx and Tx  
  117.     IntDefaultHandler,                      // SSI1 Rx and Tx  
  118.     IntDefaultHandler,                      // Timer 3 subtimer A  
  119.     IntDefaultHandler,                      // Timer 3 subtimer B  
  120.     IntDefaultHandler,                      // I2C1 Master and Slave  
  121.     IntDefaultHandler,                      // Quadrature Encoder 1  
  122.     IntDefaultHandler,                      // CAN0  
  123.     IntDefaultHandler,                      // CAN1  
  124.     IntDefaultHandler,                      // CAN2  
  125.     IntDefaultHandler,                      // Ethernet  
  126.     IntDefaultHandler                       // Hibernate  
  127. };  
  128.   
  129. //*****************************************************************************  
  130. //  
  131. // The following are constructs created by the linker, indicating where the  
  132. // the "data" and "bss" segments reside in memory.  The initializers for the  
  133. // for the "data" segment resides immediately following the "text" segment.  
  134. //  
  135. //*****************************************************************************  
  136. extern unsigned long _etext;  
  137. extern unsigned long _data;  
  138. extern unsigned long _edata;  
  139. extern unsigned long _bss;  
  140. extern unsigned long _ebss;  
  141.   
  142.   
  143. void start_kernel(void)  
  144. {  
  145.     /* Do anything here */  
  146.     while(1);  
  147. }  
  148.   
  149. //*****************************************************************************  
  150. //  
  151. // This is the code that gets called when the processor first starts execution  
  152. // following a reset event.  Only the absolutely necessary set is performed,  
  153. // after which the application supplied main() routine is called.  Any fancy  
  154. // actions (such as making decisions based on the reset cause register, and  
  155. // resetting the bits in that register) are left solely in the hands of the  
  156. // application.  
  157. //  
  158. //*****************************************************************************  
  159. void  
  160. ResetISR(void)  
  161. {  
  162.     unsigned long *pulSrc, *pulDest;  
  163.   
  164.     start_kernel();  
  165.     //  
  166.     // Copy the data segment initializers from flash to SRAM.  
  167.     //  
  168.     pulSrc = &_etext;  
  169.     for(pulDest = &_data; pulDest < &_edata; )  
  170.     {  
  171.         *pulDest++ = *pulSrc++;  
  172.     }  
  173.   
  174.     //  
  175.     // Zero fill the bss segment.  This is done with inline assembly since this  
  176.     // will clear the value of pulDest if it is not kept in a register.  
  177.     //  
  178.     __asm("    ldr     r0, =_bss\n"  
  179.           "    ldr     r1, =_ebss\n"  
  180.           "    mov     r2, #0\n"  
  181.           "    .thumb_func\n"  
  182.           "zero_loop:\n"  
  183.           "        cmp     r0, r1\n"  
  184.           "        it      lt\n"  
  185.           "        strlt   r2, [r0], #4\n"  
  186.           "        blt     zero_loop");  
  187.   
  188.     start_kernel();  
  189. }  
  190.   
  191. //*****************************************************************************  
  192. //  
  193. // This is the code that gets called when the processor receives a NMI.  This  
  194. // simply enters an infinite loop, preserving the system state for examination  
  195. // by a debugger.  
  196. //  
  197. //*****************************************************************************  
  198. static void  
  199. NmiSR(void)  
  200. {  
  201.     //  
  202.     // Enter an infinite loop.  
  203.     //  
  204.     while(1)  
  205.     {  
  206.     }  
  207. }  
  208.   
  209. //*****************************************************************************  
  210. //  
  211. // This is the code that gets called when the processor receives a fault  
  212. // interrupt.  This simply enters an infinite loop, preserving the system state  
  213. // for examination by a debugger.  
  214. //  
  215. //*****************************************************************************  
  216. static void  
  217. FaultISR(void)  
  218. {  
  219.     //  
  220.     // Enter an infinite loop.  
  221.     //  
  222.     while(1)  
  223.     {  
  224.     }  
  225. }  
  226.   
  227. //*****************************************************************************  
  228. //  
  229. // This is the code that gets called when the processor receives an unexpected  
  230. // interrupt.  This simply enters an infinite loop, preserving the system state  
  231. // for examination by a debugger.  
  232. //  
  233. //*****************************************************************************  
  234. static void  
  235. IntDefaultHandler(void)  
  236. {  
  237.     //  
  238.     // Go into an infinite loop.  
  239.     //  
  240.     while(1)  
  241.     {  
  242.     }  
  243. }  

  1. /****************************************************************************** 
  2.  * 
  3.  * standalone.ld - Linker script for applications using startup.c and 
  4.  *                 DriverLib. 
  5.  * 
  6.  * Copyright (c) 2005-2007 Luminary Micro, Inc.  All rights reserved. 
  7.  *  
  8.  * Software License Agreement 
  9.  *  
  10.  * Luminary Micro, Inc. (LMI) is supplying this software for use solely and 
  11.  * exclusively on LMI's microcontroller products. 
  12.  *  
  13.  * The software is owned by LMI and/or its suppliers, and is protected under 
  14.  * applicable copyright laws.  All rights are reserved.  You may not combine 
  15.  * this software with "viral" open-source software in order to form a larger 
  16.  * program.  Any use in violation of the foregoing restrictions may subject 
  17.  * the user to criminal sanctions under applicable laws, as well as to civil 
  18.  * liability for the breach of the terms and conditions of this license. 
  19.  *  
  20.  * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED 
  21.  * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF 
  22.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. 
  23.  * LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR 
  24.  * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. 
  25.  *  
  26.  * This is part of revision 1928 of the Stellaris Peripheral Driver Library. 
  27.  * 
  28.  *****************************************************************************/  
  29.   
  30. MEMORY  
  31. {  
  32.     FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K  
  33.     SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K  
  34. }  
  35.   
  36. SECTIONS  
  37. {  
  38.     .text :  
  39.     {  
  40.         KEEP(*(.isr_vector))  
  41.         *(.text*)  
  42.         *(.rodata*)  
  43.         _etext = .;  
  44.     } > FLASH  
  45.   
  46.     .data : AT (ADDR(.text) + SIZEOF(.text))  
  47.     {  
  48.         _data = .;  
  49.         *(vtable)  
  50.         *(.data*)  
  51.         _edata = .;  
  52.     } > SRAM  
  53.   
  54.     .bss :  
  55.     {  
  56.         _bss = .;  
  57.         *(.bss*)  
  58.         *(COMMON)  
  59.         _ebss = .;  
  60.     } > SRAM  
  61. }  


# arm-elf-gcc -g -mcpu=cortex-m3 -mthumb startup.c -nostartfiles -T standalone.ld -c -o startup.o
# arm-elf-ld  -T standalone.ld startup.o -o startup
# arm-elf-objcopy -O binary -S -R .note -R .comment startup startup.bin

这里的startup.bin就是可以烧写到flash的二进制文件,startup就是可以用gdb进行调试的,后续文章将继续介绍。

阅读(3967) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~