Embedded Linux CPU Baselines: Diagnose SIGILL After Reusing an Image on a Similar Board

Resolve the faulting instruction to the exact binary, then compare that instruction path’s requirements with the features exposed to userspace on the replacement board. Two processors sharing an architecture name do not necessarily support every instruction emitted by the same build. A successful boot or application startup can leave an incompatible library path untested.

The concrete compiler examples here use GCC 14.2 AArch64 options and Linux v6.12 arm64 capability documentation. Other architectures require their own option and feature-discovery rules. No AArch64 executable was built or run, and no illegal instruction was deliberately triggered.

Establish where SIGILL occurred

Preserve the exact executable and shared libraries, build identifiers, signal context, program counter and available crash evidence. Identify the mapped object containing the fault address and its corresponding file offset before disassembling. Address-space randomization makes a raw runtime address insufficient for an unrelated binary.

Use a matching disassembler and symbols to inspect the instruction and surrounding control flow. Determine whether it belongs to ordinary compiled code, a selected optimized implementation, generated code or an unexpected location. A jump into data or corrupted instruction stream needs a different investigation from a genuine unsupported ISA extension.

Do not assume that every illegal-instruction report is caused by an overly ambitious CPU setting. Compilers and libraries can deliberately trap on invalid states, and corrupted control flow can land on invalid bytes. Tie the interpretation to the actual instruction and source before rebuilding the entire image.

Distinguish ISA selection from performance tuning

The GCC 14.2 AArch64 options distinguish -march, which selects permitted architecture features, from -mtune, which tunes performance. The -mcpu option combines instruction-selection and tuning choices, with explicit -march or -mtune overriding the corresponding part.

Consequently, changing only a tuning option is not the same decision as raising the ISA baseline. Record the complete effective compilation command, including target-specific additions from libraries or build systems. A top-level configuration value may be overridden by a package’s own flags.

Native selection is especially easy to misuse for redistributed artifacts. The documented AArch64 native option chooses based on the compiler host when supported. A binary built on a more capable development machine should not be assumed suitable for every shipped board.

Record a baseline for the complete image

Component Required evidence
Main application Effective architecture/features, compiler version and build identity
Shared libraries and plugins Supplier baseline or reproducible build flags and optimized paths
Static archives Provenance of objects linked into the final executable
Runtime dispatch code Feature test, selected implementation and baseline fallback
Each board variant Actual userspace-exposed capabilities under the deployed kernel

Inspect the final objects as well as the source build recipe. An old prebuilt archive can survive a clean rebuild of the main application. Conversely, an optimized function may be intentionally present but safe because a valid dispatcher never selects it on an unsupported system.

Define the minimum supported feature set from the product’s board matrix. Keep optional acceleration separate from that minimum. A library’s marketing claim of AArch64 support is not enough to establish which optional extensions its particular binary requires.

A faulting instruction is linked to its exact binary build requirement and the capabilities advertised to userspace on the target.
Original CPU-baseline investigation graph; no real SIGILL incident or board result is represented.

Use the kernel’s userspace capability contract

Linux v6.12’s arm64 ELF hwcap documentation exposes relevant features through auxiliary-vector entries such as AT_HWCAP and AT_HWCAP2. When code depends on a documented capability, it should test the corresponding flag before using it.

The same document warns that executing a candidate instruction is not a reliable feature probe. An unavailable feature is not guaranteed to produce a dependable SIGILL result. Do not build production dispatch by trying arbitrary instructions and treating the absence of a crash as proof of support.

Read capability flags in the actual process environment and interpret them using the matching architecture definitions. A board’s CPU label, a copied /proc/cpuinfo line or a feature observed on a different machine cannot replace that contract. Kernel configuration and software support can affect what userspace is allowed to use.

Investigate one optimized path at a time

For a hypothetical atomic-operation failure, GCC 14.2 documents that selecting Armv8.1-A or explicitly enabling LSE can cause direct use of the corresponding atomic instructions. Its outline-atomics mechanism is a separate way to select compatible helpers when building for an appropriate baseline. Do not assume the helper mechanism protects a build that already requires the newer feature directly.

This is a source-grounded example, not a diagnosis of a particular board. First establish whether the faulting instruction is actually from that family and whether the binary’s configuration required it. A speculative compiler flag change can hide the original evidence.

Exercise less common library routes: large versus small buffers, crypto algorithms, compression levels, vectorized loops and dynamically loaded plugins actually used by the product. Startup may select one implementation while a later input reaches another. Keep representative correctness vectors for each required route.

Compare controlled repairs

  1. Rebuild the implicated component for the declared minimum ISA, preserving the earlier artifact.
  2. Verify that all linked dependencies meet the same baseline or use reviewed runtime dispatch.
  3. Run the previously failing input on the least-capable supported target.
  4. Exercise any optional accelerated route on a capable target and compare functional results.
  5. Repeat startup, delayed plugin loading and recovery using the final image.

These target tests remain proposed here. Use a recoverable environment and do not disable application fault handling merely to continue execution past an illegal instruction. If a closed binary has no compatible build, retain that component as an explicit release blocker or narrow the supported hardware scope.

Close the CPU compatibility claim

The acceptance record should connect the original fault address, decoded instruction, originating object, build option and runtime capability. A successful rebuild is stronger evidence when it explains that chain instead of merely producing a different binary.

Qualify the complete image on every declared baseline, not only the main executable on the newest board. Keep the minimum ISA and optional-dispatch policy in the release manifest so a future supplier-library update cannot silently raise the hardware requirement.

Similar Posts