【问题标题】:How do I declare a static variable as a reference to a hard-coded memory address?如何将静态变量声明为对硬编码内存地址的引用?
【发布时间】:2018-02-09 08:47:28
【问题描述】:

我正在为 NXP 的 LPC82X 系列控制器开发嵌入式 Rust 代码 - 确切的工具链对于这个问题并不重要。

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

ROM API 在特定地址位置公开封装到 C 结构中的函数指针。如果有人想要此 API 的详细信息,the LPC82X manual 的第 29 章描述了相关 API。

我的 Rust 操场虚拟草图看起来像这样,它会被一个尚未编写的 I2C 抽象库隐藏在应用程序代码中。这样就编译好了。

#![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 更好的解决方法吗?将Optionapi_table 函数一起使用至少可以保证初始化发生。

【问题讨论】:

    标签: rust embedded ffi


    【解决方案1】:

    你完全可以绕过静态:

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

    尚未工作,但计划在未来工作。暂时使用

    const ROM_I2C_API: *const RomI2cApi = 0x1fff_200c as *const RomI2cApi;
    
    fn api_table() -> &'static RomI2cApi {
        unsafe { &*(ROM_I2C_API) }
    }
    

    这将创建一个&amp;'static RomI2cApi 并允许您通过调用api_table().master_transmit_poll() 直接访问任何地方的函数

    【讨论】:

    • 这不能作为 const 初始化工作,与静态初始化具有相同的限制 - 错误 [E0396]:无法在常量中取消引用原始指针但是这可以工作 const ROM_I2C_API2: *const RomI2cApi = 0x1fff_200c as * const RomI2cApi;
    • 哦...抱歉。我已经习惯了它的工作,我忘记了它还没有工作。应该在 3 个月左右进入稳定的 rustc:github.com/rust-lang/rust/pull/46882
    • 谢谢,我想我会解决的。在我的情况下,Naked 很可能不起作用,但我希望编译器会尽最大努力优化调用链。
    • 另外,感谢有关 rust 功能更新的信息,部分原因是我接受了答案!
    猜你喜欢
    • 2012-05-25
    • 2013-05-10
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    相关资源
    最近更新 更多