Skip to content

Technicolor ARM Toolchain (Cortex-A9 + NEON)

This page documents how to prepare and use the Technicolor/OpenWrt-style cross toolchain located at:

~/firmware/technicolor_toolchain/toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_glibc_eabi/

The toolchain provides binaries such as:

  • arm-openwrt-linux-gnueabi-gcc
  • arm-openwrt-linux-gnueabi-g++
  • arm-openwrt-linux-gnueabi-ld
  • arm-openwrt-linux-gnueabi-strip
  • arm-openwrt-linux-gnueabi-objcopy
  • arm-openwrt-linux-gnueabi-objdump
  • arm-openwrt-linux-gnueabi-readelf
  • arm-openwrt-linux-gnueabi-gdb

Goals

  • Ensure the toolchain is callable from any shell
  • Verify it targets ARM EABI (gnueabi)
  • Provide reproducible Makefile / CMake / Autotools patterns
  • Avoid host header/library contamination

Directory Layout

~/firmware/technicolor_toolchain/
└── toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_glibc_eabi/
    ├── bin/
    ├── lib/
    ├── include/
    └── ...

The bin/ directory must be added to PATH.


1) Environment Setup

One-shot (Current Shell)

export TCROOT="~/firmware/technicolor_toolchain/toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_glibc_eabi"
export PATH="$TCROOT/bin:$PATH"

export TARGET="arm-openwrt-linux-gnueabi"
export CROSS_COMPILE="$TARGET-"

export CC="${CROSS_COMPILE}gcc"
export CXX="${CROSS_COMPILE}g++"
export AR="${CROSS_COMPILE}ar"
export AS="${CROSS_COMPILE}as"
export LD="${CROSS_COMPILE}ld"
export RANLIB="${CROSS_COMPILE}ranlib"
export STRIP="${CROSS_COMPILE}strip"
export OBJCOPY="${CROSS_COMPILE}objcopy"
export OBJDUMP="${CROSS_COMPILE}objdump"
export READELF="${CROSS_COMPILE}readelf"

mkdir -p ~/.config/technicolor
nano ~/.config/technicolor/arm-a9-neon.env

Add:

export TCROOT="~/firmware/technicolor_toolchain/toolchain-arm_cortex-a9+neon_gcc-4.8-linaro_glibc_eabi"
export PATH="$TCROOT/bin:$PATH"
export TARGET="arm-openwrt-linux-gnueabi"
export CROSS_COMPILE="$TARGET-"
export CC="${CROSS_COMPILE}gcc"
export CXX="${CROSS_COMPILE}g++"
export AR="${CROSS_COMPILE}ar"
export RANLIB="${CROSS_COMPILE}ranlib"
export STRIP="${CROSS_COMPILE}strip"

Load when needed:

source ~/.config/technicolor/arm-a9-neon.env

2) Sanity Checks

Confirm Toolchain

which arm-openwrt-linux-gnueabi-gcc
arm-openwrt-linux-gnueabi-gcc -v
arm-openwrt-linux-gnueabi-gcc -dumpmachine

Expected output:

arm-openwrt-linux-gnueabi

Compile Test Program

cat > hello.c <<'EOF'
#include <stdio.h>
int main() { puts("hello"); return 0; }
EOF

$CC hello.c -o hello.arm
file hello.arm
$READELF -h hello.arm | sed -n '1,30p'

Expected result:

ELF 32-bit LSB executable, ARM, EABI5 ...

3) Cortex-A9 + NEON Compiler Flags

CFLAGS="-O2 -pipe -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
CXXFLAGS="$CFLAGS"
LDFLAGS=""

Warning

Most gnueabi toolchains use a soft-float ABI.
Do not use -mfloat-abi=hard unless the firmware userland is confirmed hard-float.

Optional (if firmware expects ARM mode instead of Thumb):

-marm

4) Sysroot & Preventing Host Contamination

Check sysroot:

$CC -print-sysroot
$CC -print-search-dirs

If valid:

SYSROOT="$($CC -print-sysroot)"
$CC --sysroot="$SYSROOT" $CFLAGS hello.c -o hello.arm

Best Practices

  • Avoid /usr/include
  • Avoid /usr/lib
  • Use --sysroot
  • Inspect verbose logs during build

5) Build System Recipes


A) Minimal Makefile

TARGET   ?= hello
CC       ?= arm-openwrt-linux-gnueabi-gcc
STRIP    ?= arm-openwrt-linux-gnueabi-strip

CFLAGS   ?= -O2 -pipe -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
LDFLAGS  ?=

all: $(TARGET)

$(TARGET): hello.c
	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
	$(STRIP) -s $@

clean:
	rm -f $(TARGET)

Build:

make CC="$CC" STRIP="$STRIP"

B) Autotools

export CFLAGS="-O2 -pipe -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
export CXXFLAGS="$CFLAGS"

./configure \
  --host=arm-openwrt-linux-gnueabi \
  --build=$(gcc -dumpmachine) \
  CC="$CC" CXX="$CXX" AR="$AR" RANLIB="$RANLIB" \
  --prefix=/usr

make -j"$(nproc)"

C) CMake Toolchain File

Create toolchain-arm-openwrt.cmake:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(TOOLCHAIN_PREFIX arm-openwrt-linux-gnueabi)

set(CMAKE_C_COMPILER   ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_AR           ${TOOLCHAIN_PREFIX}-ar)
set(CMAKE_RANLIB       ${TOOLCHAIN_PREFIX}-ranlib)
set(CMAKE_STRIP        ${TOOLCHAIN_PREFIX}-strip)

set(CMAKE_C_FLAGS   "-O2 -pipe -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp")
set(CMAKE_CXX_FLAGS "-O2 -pipe -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

Build:

cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain-arm-openwrt.cmake
cmake --build build -j"$(nproc)"

6) Debugging & Inspection

Inspect linked libraries:

$READELF -d yourbinary | grep -E 'NEEDED|RPATH|RUNPATH'

Architecture details:

file yourbinary
$READELF -A yourbinary | sed -n '1,120p'

Strip symbols:

$STRIP -s yourbinary

7) Common Failure Modes

Exec Format Error During Build

Cause: A configure script attempted to run an ARM binary on x86_64.

Fix:

--host=arm-openwrt-linux-gnueabi
--build=$(gcc -dumpmachine)

Disable runtime tests or cache results when necessary.


Header/Library Mismatch

Cause: Host /usr/include or /usr/lib contamination.

Fix:

  • Use --sysroot
  • Verify verbose logs
  • Ensure CMake root path modes are ONLY

Soft-Float vs Hard-Float Mismatch

Symptoms:

  • Loader refusal
  • Runtime crashes

Fix:

  • Use -mfloat-abi=softfp
  • Confirm ABI via:
readelf -A binary

Compare against target firmware libc.


Appendix: Environment Dump (Bug Reports)

echo "TCROOT=$TCROOT"
echo "$PATH" | tr ':' '\n' | head -15
$CC -v
$CC -dumpmachine
$CC -print-sysroot