hexagon-unknown-none-elf

层级: 3

用于裸机 Hexagon DSP 的 Rust。

目标描述
hexagon-unknown-none-elfHexagon 32 位 (独立, 硬浮点)

目标维护者

要求

此目标是交叉编译的。不支持 std 库。没有默认分配器,但可以通过提供分配器来使用 alloc 库。

默认情况下,使用此目标生成的代码应在 Hexagon DSP 硬件上运行。

  • -Ctarget-cpu=hexagonv73 增加了对 Hexagon V73 定义的指令的支持。

标记为 extern "C" 的函数使用 Hexagon 架构调用约定

此目标生成 PIC ELF 二进制文件。

构建目标

您可以通过将其添加到 config.toml 中的 target 列表来构建支持此目标的 Rust

[build]
build-stage = 1
host = ["<target for your host>"]
target = ["<target for your host>", "hexagon-unknown-none-elf"]

[target.hexagon-unknown-none-elf]

cc = "hexagon-unknown-none-elf-clang"
cxx = "hexagon-unknown-none-elf-clang++"
linker = "hexagon-unknown-none-elf-clang"
ranlib = "hexagon-unknown-none-elf-ranlib"
ar = "hexagon-unknown-none-elf-ar"
llvm-libunwind = 'in-tree'

<target for your host> 替换为 x86_64-unknown-linux-gnu 或适合您主机系统的其他任何内容。

构建 Rust 程序

Rust 尚未为此目标发布预编译的工件。要为此目标编译,您需要构建启用此目标的 Rust(请参阅上面的“构建目标”),或者使用 build-std 或类似工具构建您自己的 core 副本。

测试

由于 hexagon-unknown-none-elf 支持各种不同的环境且不支持 std,因此此目标不支持运行 Rust 测试套件。

交叉编译工具链和 C 代码

此目标已使用 qemu-system-hexagon 进行测试。

hexagon-unknown-none-elf 的常见用例是构建链接到 C 代码的库,这些库可以在模拟或带有 Hexagon DSP 的设备上使用。

Hexagon SDK 具有在设备上运行时有用的链接库。

独立操作系统

下面的脚本将构建一个针对 “hexagon 独立操作系统” 的可执行文件,该文件适用于模拟或裸机设备测试。

首先,运行 cargo new --bin demo1_hexagon,然后将下面的源代码添加为 src/main.rs。此程序演示了通过半主机模式的控制台输出。

#![no_std]
#![no_main]

extern "C" {
    fn putchar(ch: i32);
    fn _exit(code: i32) -> !;
}

#[no_mangle]
extern "C" fn main() -> i32 {
    let message = "Hello, this is Rust!";
    for b in message.bytes() {
        unsafe {
            putchar(b as i32);
        }
    }
    0
}

#[panic_handler]
fn panic(_panic: &core::panic::PanicInfo) -> ! {
    unsafe {
        _exit(1);
    }
}

接下来,将下面的脚本另存为 build.sh 并根据您的环境进行编辑。

  • 下面的 hex_toolchain 指的是专门使用公共开源仓库的 hexagon 工具链。
  • 下面的 cc 指的是 clang。您可以使用发行版中的 clang,只要它至少是 clang-17。或者您可以使用来自 hexagon 开源工具链版本之一的 hexagon-unknown-none-elf-clang
# Hexagon SDK, required for target libraries:
hex_sdk_root=/local/mnt/workspace/Qualcomm/Hexagon_SDK/5.3.0.0
hex_sdk_toolchain=${hex_sdk_root}/tools/HEXAGON_Tools/8.6.06

sdk_libs=${hex_sdk_toolchain}/Tools/target/hexagon/lib
q6_arch=v65
g0_lib_path=${sdk_libs}/${q6_arch}/G0
pic_lib_path=${sdk_libs}/${q6_arch}/G0/pic

build_cfg=release
cargo build --target=hexagon-unknown-none-elf -Zbuild-std --release

# Builds an executable against "hexagon standalone OS" suitable for emulation:
${cc} --target=hexagon-unknown-none-elf -o testit \
    -fuse-ld=lld \
    -m${q6_arch} \
    -nodefaultlibs \
    -nostartfiles \
    ${g0_lib_path}/crt0_standalone.o \
    ${g0_lib_path}/crt0.o \
    ${g0_lib_path}/init.o \
    -L${sdk_libs}/${q6_arch}/ \
    -L${sdk_libs}/ \
    wrap.c \
    target/hexagon-unknown-none-elf/${build_cfg}/libdemo1_hexagon.rlib \
    target/hexagon-unknown-none-elf/${build_cfg}/deps/libcore-*.rlib \
    target/hexagon-unknown-none-elf/${build_cfg}/deps/libcompiler_builtins-*.rlib \
    -Wl,--start-group \
    -Wl,--defsym,_SDA_BASE_=0,--defsym,__sbss_start=0,--defsym,__sbss_end=0 \
    ${g0_lib_path}/libstandalone.a \
    ${g0_lib_path}/libc.a \
    -lgcc \
    -lc_eh \
    -Wl,--end-group \
    ${g0_lib_path}/fini.o \

${hex_toolchain}/x86_64-linux-gnu/bin/qemu-system-hexagon -monitor none -display none -kernel ./testit

QuRT 操作系统

首先,运行 cargo new --lib demo2_hexagon,然后将下面的源代码添加为 src/lib.rs。此程序演示了内联汇编和通过半主机模式的控制台输出。

#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(asm_experimental_arch)]

use core::arch::asm;

extern "C" {
    fn putchar(ch: i32);
    fn _exit(code: i32) -> !;
}

fn hexagon_specific() {
    let mut buffer = [0_u8; 128];

    unsafe {
        let mut x = &buffer;
        asm!(
                "{{\n\t",
                "  v0=vmem({addr}+#0)\n\t",
                "  {tmp} = and({tmp}, #1)\n\t",
                "}}\n\t",
                addr = in(reg) x,
                tmp = out(reg) _,
            );
    }
}

#[no_mangle]
extern "C" fn hello() -> i32 {
    let message = "Hello, this is Rust!\n";
    for b in message.bytes() {
        unsafe {
            putchar(b as i32);
        }
    }
    hexagon_specific();
    0
}

#[panic_handler]
fn panic(_panic: &core::panic::PanicInfo) -> ! {
    unsafe {
        _exit(1);
    }
}

#[lang = "eh_personality"]
fn rust_eh_personality() {}

接下来,创建一个 C 程序作为入口点,将以下内容另存为 wrap.c

int hello();

int main() {
    hello();
}

然后,将下面的脚本另存为 build.sh 并根据您的环境进行编辑。下面的脚本将构建一个针对 QuRT RTOS 的共享对象,该对象适用于通过 fastrpc-shell 加载时进行模拟或设备上测试。

# Hexagon SDK, required for target libraries:
hex_sdk_root=/local/mnt/workspace/Qualcomm/Hexagon_SDK/5.3.0.0
hex_sdk_toolchain=${hex_sdk_root}/tools/HEXAGON_Tools/8.6.06

sdk_libs=${hex_sdk_toolchain}/Tools/target/hexagon/lib
q6_arch=v65
g0_lib_path=${sdk_libs}/${q6_arch}/G0
pic_lib_path=${sdk_libs}/${q6_arch}/G0/pic
runelf=${hex_sdk_root}/rtos/qurt/computev65/sdksim_bin/runelf.pbn
rmohs=${hex_sdk_root}/libs/run_main_on_hexagon/ship/hexagon_toolv86_${q6_arch}/run_main_on_hexagon_sim

# Builds a library suitable for loading into "run_main_on_hexagon_sim" for
# emulation or frpc shell on real target:
${cc} --target=hexagon-unknown-none-elf -o testit.so \
    -fuse-ld=lld \
    -fPIC -shared \
    -nostdlib \
    -Wl,-Bsymbolic \
      -Wl,--wrap=malloc \
      -Wl,--wrap=calloc \
      -Wl,--wrap=free \
      -Wl,--wrap=realloc \
      -Wl,--wrap=memalign \
    -m${q6_arch} \
    wrap.c \
    target/hexagon-unknown-none-elf/${build_cfg}/libdemo2_hexagon.rlib \
    target/hexagon-unknown-none-elf/${build_cfg}/deps/libcore-*.rlib \
    target/hexagon-unknown-none-elf/${build_cfg}/deps/libcompiler_builtins-*.rlib \
    -Wl,-soname=testit \
    ${pic_lib_path}/libc.so

# -Bsymbolic above for memory alloc funcs is necessary to access the heap on
# target, but otherwise not required.

# multi-stage loader: runelf => run_main_on_hexagon_sim => testit.so{`main`}
${hex_toolchain}/x86_64-linux-gnu/bin/qemu-system-hexagon \
    -monitor none \
    -display none \
    -kernel ${runelf} \
    -append "${rmohs} -- ./testit.so"