Pi Pico Embedded Rust Always elf2uf2-r Always Produces Error: "Unrecognized ABI"
12:07 02 Mar 2026

I've been trying unsuccessfully to get a simple embedded Rust program to build and run on a Pi Pico.

Here is my project:

.cargo/config.toml:

[build]
target = "thumbv6m-none-eabi"

[target.thumbv6m-none-eabi]
rustflags = [
    "-C", "link-arg=-Tlink.x",
    "-C", "link-arg=--nmagic",
    # This line is the magic bullet:
    "-C", "link-arg=-z", "-C", "link-arg=keep-section=.boot2",
]

src/main.rs:

#![no_std]
#![no_main]

// FORCE the bootloader into the binary
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;

use panic_halt as _;

// Use the entry macro from the HAL, not cortex_m_rt
// This ensures the bootloader is linked correctly
use rp_pico::entry; 
use core::fmt::Write;
use embedded_hal::digital::OutputPin;

use rp_pico::hal::{
    clocks::{init_clocks_and_plls, Clock},
    fugit::RateExtU32,
    pac,
    sio::Sio,
    uart::{DataBits, StopBits, UartConfig, UartPeripheral},
    watchdog::Watchdog,
};

const XTAL_FREQ_HZ: u32 = 12_000_000;

#[entry]
fn main() -> ! {
    let mut pac = pac::Peripherals::take().unwrap();
    let core = pac::CorePeripherals::take().unwrap();

    let mut watchdog = Watchdog::new(pac.WATCHDOG);
    let sio = Sio::new(pac.SIO);

    let clocks = init_clocks_and_plls(
        XTAL_FREQ_HZ,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let pins = rp_pico::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    let uart_pins = (
        pins.gpio0.into_function(),
        pins.gpio1.into_function(),
    );

    let mut uart = UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
        .enable(
            UartConfig::new(
                115200.Hz(),
                DataBits::Eight,
                None,
                StopBits::One,
            ),
            clocks.peripheral_clock.freq(),
        )
        .unwrap();

    let mut buzzer = pins.gpio4.into_push_pull_output();

    let mut delay = cortex_m::delay::Delay::new(
        core.SYST,
        clocks.system_clock.freq().to_Hz(),
    );

    let _ = writeln!(uart, "cricket chirper starting");

    let mut seed: u32 = 12345;

    loop {
        seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
        let seconds = (seed % 60) + 1;

        let _ = writeln!(uart, "waiting {} seconds", seconds);

        delay.delay_ms(seconds * 1000);

        let _ = writeln!(uart, "buzzing");

        for _ in 0..500 {
            let _ = buzzer.set_high();
            delay.delay_us(500);
            let _ = buzzer.set_low();
            delay.delay_us(500);
        }

        delay.delay_ms(500);
    }
}

build.rs:

fn main() {
    println!("cargo:rerun-if-changed=memory.x");
}

Cargo.toml:

[package]
name = "pico-buzzer"
version = "0.1.0"
edition = "2021"

[dependencies]
# Standard ARM crates
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "0.2"

# Hardware abstraction
embedded-hal = "1.0"
embedded-io = "0.6"

# The Pico HAL - 'rt' feature provides the linker script automatically
rp-pico = { version = "0.9", features = ["rt"] }
rp2040-boot2 = "0.3"

[profile.release]
panic = "abort"
opt-level = 3
lto = true
codegen-units = 1
debug = true

memory.x:

MEMORY
{
    /* The 2nd stage bootloader is 256 bytes at the start of flash */
    FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
    RAM   : ORIGIN = 0x20000000, LENGTH = 264K
}

Then I run these commands:

cargo clean
cargo build --release

They both finish fine.

Then I run:

elf2uf2-rs target/thumbv6m-none-eabi/release/pico-buzzer

and always get the same error output:

Error: "Unrecognized ABI"

How can I overcome this?

rust embedded cortex-m pi raspberry-pi-pico