Arm Compiler 6.12: Bringing in security and improved performance

Written by ARM

abril 16, 2019

Outstanding performance

As always, Arm is constantly investing to improve our optimizations and overall performance across all workloads.

Arm Compiler 6.12 delivers the highest-ever CoreMark score of 4.02 CoreMarks/MHz on a Cortex-M33. It also delivers significant improvement for range of specific workloads such as the CMSIS-DSP and CMSIS-NN software libraries.

 Performance of Cortex-M33 graph

 

CMSIS-DSP Performance Improvement graph Arm Compiler 6.12 over Arm Compiler 6.9 for Cortex-M33

Arm Compiler 6.12 new features

In this release, Arm Compiler 6.12 adds full support to two new features:

1. Stack protection

Arm Compiler 6.12 now provides full support for stack protection, a security feature to protect against attacks that try to exploit memory access errors, thereby improving the overall resilience and integrity of the system.

The way this is done is by inserting a guard variable onto the stack frame for each vulnerable function or for all functions. The prologue of a function stores a guard variable onto the stack frame. Before returning from the function, the function epilogue checks the guard variable to make sure that it has not been overwritten. A guard variable that is overwritten indicates a buffer overflow, and the checking code alerts the run-time Environment.

Stack protection can be enabled by using the compiler options -fstack-protector, -fstack-protector-all, -fstack-protector-strong.

The initial value of its guard variable is taken from a global variable:

void *__stack_chk_guard;

A suitable value must be provided in this variable. For example, a suitable implementation might set this variable to a random value when the program is loaded, and before the first protected function is entered. The value must remain unchanged during the life of the program.

When the checking code detects that the guard variable on the stack has been modified, it notifies the run-time environment by calling the function:

void __stack_chk_fail(void);

Optimizations can affect stack protection. The following are simple examples of when this can happen:

  • Inlining can affect whether a function is protected.
  • Removal of an unused variable can prevent a function from being protected

2. Global named register variables

Arm Compiler 6.12 supports the use of global named register variables to enable faster access to these variables than if they were stored in memory, thereby giving a slight performance gain. This feature is only available for aarch32 state.

Using register and _asm keywords allows direct manipulation of a core register as if it were a ‘C’ variable.

register Type VariableName __asm("Reg")

where,

Type = datatype of the variable – can be char or any 8-bit, 16-bit, or 32-bit integer type, or their respective pointer types.

VariableName = Name of the variable

Reg = Core register to use to store the variable – Can be R5-R11

 Arm recommends that the following registers are not used as global named register variables because the Arm ABI reserves them for use as a frame pointer if needed.

  • R7 in T32 state
  • R11 in A32 state.

For example, to use register R5 as a global named register for an integer foo, you must use:

register int foo __asm("R5")

In the above example, you must compile with -ffixed-r5 (see -ffixed-rN) as the Arm standard library has not been built with any -ffixed-rN option.

If you want to link application code containing global named register variables with the Arm standard library, then:

  • To ensure correct run-time behaviour, ensure that the library code does not call code that uses the global named register variables in your application code.
  • The library code might push and pop the register to stack, even if your application code uses this register as a global named register variable.

Although giving a performance gain, the use of global named register variables can result in increase in code size since the core register is no longer available to the compiler for other operations. If too many global named register variables are declared, then code size increases significantly. In some cases, the program might not compile, simply because there are insufficient registers available to compute a particular expression.

Installation and useful resources

If you are new to Arm Compiler, then you can evaluate it in Arm Development Studio or Keil MDK. For existing Arm Compiler users, refer to Accessing Arm Compiler from Arm Development Studio or Accessing Arm Compiler from Keil MDK in their respective user guides.

For the list of changes and supported features, refer to the Arm Compiler 6.12 Release note. Further resources can be found in the Arm Compiler 6.12 Documentation.

If you are using Arm Compiler 5.x and are planning to migrate to Arm Compiler 6, the Migration and Compatibility Guide provides lots of helpful information and advice.