Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
  • Groups
    • Arm Research
    • DesignStart
    • Education Hub
    • Innovation
    • Open Source Software and Platforms
  • Forums
    • AI and ML forum
    • Architectures and Processors forum
    • Arm Development Platforms forum
    • Arm Development Studio forum
    • Arm Virtual Hardware forum
    • Automotive forum
    • Compilers and Libraries forum
    • Graphics, Gaming, and VR forum
    • High Performance Computing (HPC) forum
    • Infrastructure Solutions forum
    • Internet of Things (IoT) forum
    • Keil forum
    • Morello Forum
    • Operating Systems forum
    • SoC Design and Simulation forum
    • 中文社区论区
  • Blogs
    • AI and ML blog
    • Announcements
    • Architectures and Processors blog
    • Automotive blog
    • Graphics, Gaming, and VR blog
    • High Performance Computing (HPC) blog
    • Infrastructure Solutions blog
    • Innovation blog
    • Internet of Things (IoT) blog
    • Mobile blog
    • Operating Systems blog
    • Research Articles
    • SoC Design and Simulation blog
    • Smart Homes
    • Tools, Software and IDEs blog
    • Works on Arm blog
    • 中文社区博客
  • Support
    • Open a support case
    • Documentation
    • Downloads
    • Training
    • Arm Approved program
    • Arm Design Reviews
  • Community Help
  • More
  • Cancel
Arm Community blogs
Arm Community blogs
Tools, Software and IDEs blog Migrate to Arm Compiler 6 from gcc
  • Blogs
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
More blogs in Arm Community blogs
  • AI and ML blog

  • Announcements

  • Architectures and Processors blog

  • Automotive blog

  • Embedded blog

  • Graphics, Gaming, and VR blog

  • High Performance Computing (HPC) blog

  • Infrastructure Solutions blog

  • Internet of Things (IoT) blog

  • Operating Systems blog

  • SoC Design and Simulation blog

  • Tools, Software and IDEs blog

Tags
  • Arm Compiler 6
  • Cortex-A9
  • DS-5 Development Studio
  • GNU
  • Tutorial
  • GNU Arm Eclipse
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

Migrate to Arm Compiler 6 from gcc

Ronan Synnott
Ronan Synnott
March 12, 2018

In a previous article I wrote about migration from armasm (the legacy Arm assembler) to Arm Compiler 6 (AC6). This was useful for users who were already using the Arm toolchains for their builds. But what of gcc users?

Previously there was a reasonably high barrier to change, but Arm tools can now readily consume GNU assembler and C constructs, allowing you to more easily use the highly optimizing Arm Compiler in your existing projects.

Setting up your environment

To illustrate the steps necessary, I am using the DS-5 fireworks examples, which are conveniently supplied in AC6 and GCC flavors. I will use Eclipse based projects as they are easier to manage, but I will highlight necessary changes to makefiles as needed.

Though you do not actually need to have GCC installed, if you wish to, I recommend the latest Linaro toolchain, downloaded from here. There is also the GNU Arm embedded toolchain, for Cortex-R and Cortex-M processors, available from here (The fireworks examples are however written for Cortex-A9).

For information on adding gcc toolchains to your DS-5 installation, see my previous article here

Importing the example

We must first import the fireworks projects to the DS-5 Eclipse IDE.

Navigate the menu system to File → Import… → DS-5 → Examples & Programming Libraries, then locate the fireworks_A9x1-FVP_AC6 and fireworks_A9x1-FVP_GCC projects (the filter text box can simplify this step).

Import examples and Programming Libraries in the DS-5 Development Studio

Select both, and click the finish button. We shall in this tutorial migrate the GCC project to AC6 (you can use the AC6 project as a reference). I recommend making a copy of the project, say, fireworks_A9x1-FVP_GCC2AC6, so that we keep the original file intact.

Navigate to the project Properties → C/C++ Build → Tool Chain Editor view, and select your latest available Arm Compiler 6 from the pull down (you will need to deselect “Display compatible toolchains only“).

Tool Chain Editor view to select the latest Arm Compiler 6

Click on Apply. This will remove all the previous settings, and so we will need to restore these appropriately. Go to the Settings tab, and select Cortex-A9 in All Tools Settings → Target. This is necessary as the project contains code that is CPU specific.

Setting view to restore required settings

Note for makefile users. Most of the standard command options are common for both gcc and AC6 (armclang). AC6 however supports many Arm architectures in a single executable, and so you will need update your compiler flags to specify which mode the compiler is running in.

For example, for an Armv7 CPU, such as Cortex-A9, you should use

armclang --target=arm-arm-none-eabi -mcpu=cortex-a9 …

For an Armv8 CPU, such as Cortex-A53, you should use

armclang --target=aarch64-arm-none-eabi -mcpu=cortex-a53 …

These settings are done automatically for Eclipse projects.

Did it build?

You will complete the compilation and assembler stages of the build, but it will fail at link time, with some undefined symbol errors. This is expected, as we have not specified any ld script, or the necessary equivalent… a scatter description file.

Within the fireworks_A9x1_GCC project you will find gcc.ld, a linker script for the GNU linker (ld). Within the fireworks_A9x1_AC6 project you will find scatter.scat, an equivalent scatter file for the Arm linker.

Comparing the two files shows a lot of similarities. They each define a number of code and data sections, defined within {} style braces, though the notation contained within is slightly different.

The gcc.ld script that we provide is in fact overly detailed for the needs of this example, explicitly defining regions which can be grouped into other catch-all regions. For convenience, here is a reduced version containing just those features used by this project.

ENTRY(Vectors)

SECTIONS
{
    .vectors 0x80000000:
    {
        __code_start = .;
        KEEP(*(StartUp))
        *(.text*)
        *(.rodata .rodata.* .gnu.linkonce.r.*)
        *(.data .data.* .gnu.linkonce.d.*)
        *(.bss*)
    }
    .heap (NOLOAD):
    {
        . = ALIGN(64);
        __end__ = .;
        PROVIDE(end = .);
        . = . + 0xA0000;
    }
    .stack (NOLOAD):
    {
        . = ALIGN(64);
        . = . + 4 * 0x4000;
        __stack = .;
    }
    .irq_stacks (NOLOAD):
    {
        . = ALIGN(64);
        . = . + 4 * 256;
        __irq_stack = .;
    }
    .pagetable 0x80500000 (NOLOAD):
    {
        __pagetable_start = .;
        . = . + 0x00100000;
    }
    .framebuffer 0x80600000 (NOLOAD):
    {
        __framebuffer_start = .;
        . = . + 0x00100000;
    }
}

Note that I have grouped together the contents of the .text, .rodata, .data, and .bss sections with the startup code (in the .vectors section).

.vectors 0x80000000:
{
    __code_start = .;
    KEEP(*(StartUp))
    *(.text*)
    *(.rodata .rodata.* .gnu.linkonce.r.*)
    *(.data .data.* .gnu.linkonce.d.*)
    *(.bss*)
}

Other regions remain, as the code will make use of these explicitly.

In the ld script, the ordering that elements are listed within a section defines the ordering in which they will be placed within this section. Here we ensure that StartUp is at the beginning of the .vectors section, and hence is the first code to be executed after reset.

Scatter loading does not have this restriction, but instead uses +FIRST notation (also +LAST) to force the startup code to be located at the beginning of this section:

VECTORS +0
{
    startup.o (StartUp, +FIRST)
    * (+RO, +RW,+ZI)
}

Further sections

In the ld script, sections have an optional start address specified. If no address is specified, then that section immediately follows after the previous one. The scatter file equivalent is to specify the base address as a zero offset, +0. Other commands, such as ALIGN, NOLOAD, etc, are specified as region attributes in scatter loading. For example, the .pagetable region in the ld script:

.pagetable 0x80500000 (NOLOAD):
{
    __pagetable_start = .;
    . = . + 0x00100000;
}

can be specified in scatter loading as:

PAGETABLE 0x80500000 EMPTY 0x0010000 {}

Linker generated symbol names, such as __pagetable_start above, must be manually defined in an ld script file. With scatter loading, a selection of symbol names are implicitly defined, and can be used in the same manner. You can then use #define constructs to map the ld defined symbol to the implicit symbol.

#define __pagetable_start   Image$$PAGETABLE$$ZI$$Base
//  ...
    LDR     r0, =__pagetable_start  // no change to code using the symbol

You can use a special naming for (User mode) stack and heap regions and let the C library initialization code set these up for you automatically (you can remove any other code setting these stacks ).

ARM_LIB_HEAP  +0 ALIGN 64 EMPTY 0xA0000 {}
ARM_LIB_STACK +0 ALIGN 64 EMPTY 0x10000 {}

If, as in this example, you have separate stack and heap regions, you must at some point in your source code import the __use_two_region_memory symbol:

.global __use_two_region_memory

The final scatter file to match the above ld script looks like:

LOAD 0x80000000  0x00100000
{
    VECTORS +0
    {
        startup.o (StartUp, +FIRST)
        * (+RO,+RW,+ZI)
    }
    ARM_LIB_HEAP	+0          ALIGN 64	EMPTY    0xA0000    {}
    ARM_LIB_STACK	+0          ALIGN 64	EMPTY    0x10000    {}
    IRQ_STACK		+0          ALIGN 64	EMPTY     0x1000    {}
    PAGETABLE		0x80500000		        EMPTY   0x100000    {}
    FRAMEBUFFER     0x80600000	        	EMPTY   0x100000    {}
}

Linker command line options

We will need to specify the scatter loading file to the linker. Furthermore, the remaining ld commands map to armlink command line options. We specify these via the project properties pane for the linker:

Project Properties pane

If editing a makefile, to specify the scatterloading file itself, use

--scatter name_of_scatter_file

 To specify the entry point of the code, use

--entry symbol_name

 and to forcibly keep a section, use

--keep object_or_section_name

Sections containing the entry point do not need to be explicitly kept, and so there is no need to keep the StartUp section in this example.

Call the C library initialization code

The entry point of the GNU C library is labeled as _start. With the Arm C library, it is labeled __main. You must update the branch instruction appropriately, either explicitly, or via #define

#define _start  __main
// ...
    B       _start

Advanced users may also wish to edit the inline assembler contained within C source code to use compiler intrinsic functions instead. This will make the code more portable to other Arm processors. For example, in the main function, you could make the following edit:

#include <arm_compat.h>
// ...
    //  asm("CPSIE i");   // Enable IRQ
    __enable_irq();

For a more thorough discussion of the source code features and command line options supported by Arm Compiler 6, I would recommend consulting the Compiler Reference Guide.

You should now have a project that builds and executes successfully. With these few simple steps the code is now built with a highly optimizing compiler, with a significantly reduced code footprint (from approximately 21KB of code with GCC, to under 9KB with Arm Compiler 6, version 6.9, both compiled at -O2 optimization level.

To learn more about DS-5, which contains the latest Arm Compiler, as well as the examples described in this article, please click on the link below. A free, fully featured, 30-day evaluation license is available.

Get started with the DS-5 Development Studio

Anonymous
Tools, Software and IDEs blog
  • New performance features and improvements in GCC 12

    Tamar Christina
    Tamar Christina
    Read about the new architecture and performance feature in GCC 12 for the Arm CPUs. From vectorization to instructions to optimize memory operations.
    • May 10, 2022
  • DPDK Optimization on Arm

    Joyce Kong
    Joyce Kong
    This blog summarizes Data Plane Development Kit (DPDK)'s techniques and the optimization experiences on Arm.
    • May 3, 2022
  • Product update: Arm Development Studio 2022.0 now available with support for Cortex-M85

    Ronan Synnott
    Ronan Synnott
    Arm Development Studio 2022.0 is now available, the first release to support Cortex-M85.
    • April 27, 2022