如何声明一个静态变量作为对硬编码内存地址的引用? [英] How do I declare a static variable as a reference to a hard-coded memory address?

查看:77
本文介绍了如何声明一个静态变量作为对硬编码内存地址的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为NXP的LPC82X系列控制器开发嵌入式Rust代码-确切的工具链与问题无关。

I am working on embedded Rust code for LPC82X series controllers from NXP - the exact toolchain does not matter for the question.

这些控制器在ROM中包含外围设备驱动程序。我想使用这些驱动程序,这意味着我需要使用不安全的Rust和FFI而不链接实际代码。

These controllers contain peripheral drivers in ROM. I want to use these drivers, which means I need to use unsafe Rust and FFI without linking actual code.

ROM API公开了在特定地址打包到C结构中的函数指针位置。如果有人需要此API的详细信息,请参阅 LPC82X手册的第29章描述了相关的API。

The ROM APIs expose function pointers packed into C structs at specific address locations. If somebody wants the details of this API, chapter 29 of the LPC82X manual describes the API in question.

我的Rust游乐场虚拟草图看起来像这样,可以通过尚未编写的I2C抽象库隐藏在应用程序代码中。

My Rust playground dummy sketch looks like this, that would be hidden from application code, by a yet unwritten I2C abstraction lib. This compiles.

#![feature(naked_functions)]

const I2C_ROM_API_ADDRESS: usize = 0x1fff_200c;
static mut ROM_I2C_API: Option<&RomI2cApi> = None;

#[repr(C)]
struct RomI2cApi {
    // Dummy functions, real ones take arguments, and have different return
    // These won't be called directly, only through the struct's implemented methods
    // value
    master_transmit_poll: extern "C" fn() -> bool,
    master_receive_poll: extern "C" fn() -> bool,
}

impl RomI2cApi {
    fn api_table() -> &'static RomI2cApi {
        unsafe {
            match ROM_I2C_API {
                None => RomI2cApi::new(),
                Some(table) => table,
            }
        }
    }

    unsafe fn new() -> &'static RomI2cApi {
        ROM_I2C_API = Some(&*(I2C_ROM_API_ADDRESS as *const RomI2cApi));
        ROM_I2C_API.unwrap()
    }

    #[inline]
    fn master_transmit_poll(&self) -> bool {
        (self.master_transmit_poll)()
    }

    #[inline]
    fn master_receive_poll(&self) -> bool {
        (self.master_receive_poll)()
    }
}

impl From<usize> for &'static RomI2cApi {
    fn from(address: usize) -> &'static RomI2cApi {
        unsafe { &*(address as *const RomI2cApi) }
    }
}

fn main() {
    let rom_api = unsafe { RomI2cApi::api_table() };
    println!("ROM I2C API address is: {:p}", rom_api);
    // Should be commented out when trying !
    rom_api.master_transmit_poll();
}

我无法将函数指针结构声明为非可变静态,因为静态有很多限制,包括不取消分配中的指针。是否有比 Option 更好的解决方法?将 Option api_table 函数一起使用至少可以保证初始化的发生。

I cannot declare the function pointer structs as non-mutable static as statics have many restrictions, including not dereferencing pointers in the assignment. Is there a better workaround than Option? Using Option with the api_table function at least guarantees that initialization happens.

推荐答案

您完全可以拥有一个静态变量:

You can get around having a static at all:

const ROM_I2C_API: &RomI2cApi = &*(0x1fff_200c as *const RomI2cApi);

尚未运行,但计划在将来运行。暂时使用

Not yet working, but is planned to work in the future. For now use

const ROM_I2C_API: *const RomI2cApi = 0x1fff_200c as *const RomI2cApi;

fn api_table() -> &'static RomI2cApi {
    unsafe { &*(ROM_I2C_API) }
}

这将创建一个&'静态RomI2cApi ,并允许您通过调用 api_table()。master_transmit_poll()直接访问所有函数。

This creates a &'static RomI2cApi and allows you to access the functions everywhere directly by calling api_table().master_transmit_poll()

这篇关于如何声明一个静态变量作为对硬编码内存地址的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆