How do I obtain the address of a function? - rust

How do I obtain a function address in Rust? What does '&somefunction' exactly mean?
What addresses do I get doing
std::mem::transmute::<_, u32>(function)
or
std::mem::transmute::<_, u32>(&function)
(on 32-bit system, of course)?
What does
&function as *const _ as *const c_void
give?

If I just wanted to know the address of a function, I'd probably just print it out:
fn moo() {}
fn main() {
println!("{:p}", moo as *const ());
}
However, I can't think of a useful reason to want to do this. Usually, there's something you want to do with the function. In those cases, you might as well just pass the function directly, no need to deal with the address:
fn moo() {}
fn do_moo(f: fn()) {
f()
}
fn main() {
do_moo(moo);
}
I'm less sure about this, but I think that std::mem::transmute::<_, u32>(&function) would just create a local variable that points to function and then gets the reference to that variable. This would match how this code works:
fn main() {
let a = &42;
}
I need not to work with them in Rust, I need an address because I have some FFI that takes an address of the symbol in the current process
You can still just pass the function as-is to the extern functions that will use the callback:
extern {
fn a_thing_that_does_a_callback(callback: extern fn(u8) -> bool);
}
extern fn zero(a: u8) -> bool { a == 0 }
fn main() {
unsafe { a_thing_that_does_a_callback(zero); }
}

The answer by #Shepmaster gives answer to this question (though giving also other not relevant but may be useful for somebody information). I summarize it here.
Obtaining address is easy, just
funct as *const ()
Reference to a function seems to create a local variable just like with
let a = &42;

Related

How to call function from Rust naked function?

just started learning Rust. How do you manage a function call from a Rust naked function? Normally,
pub extern "C" fn bar() {
hprintln!("Function Call!");
}
pub extern "C" fn foo() {
unsafe {
asm!(
"blx {}",
...
in(reg) bar as u32,
);
}
}
But foo() being a naked call, I cannot use a register to pass values. There aren't much documentation on this feature and only thing I figured is that I can use constant and symbol, but I'm not sure how they are used. Any useful documentation on this feature or usage guideline would be greatly appreciated! Thanks.
Figured out a quick fix: function parameters are stored in registers (r0-r3).
pub extern "C" fn bar() {
hprintln!("Function Call!");
}
#[naked]
pub extern "C" fn foo(ft: u32) {
unsafe {
asm!(
"blx r0", // ft is stored in r0
);
}
}
// somewhere
foo(bar as u32);
I believe there are different ways to solve this using constant and symbol though. Would appreciate any input.

How do I declare a static variable as a reference to a hard-coded memory address?

I am working on embedded Rust code for LPC82X series controllers from NXP - the exact toolchain does not matter for the question.
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.
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.
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();
}
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) }
}
This creates a &'static RomI2cApi and allows you to access the functions everywhere directly by calling api_table().master_transmit_poll()

Are raw pointers to temporaries ok in Rust?

I have a function like this:
extern {
fn foo(layout: *const RawLayout) -> libc::uint8_t;
}
fn bar(layout: Layout) -> bool {
unsafe {
foo(&layout.into() as *const _) != 0
}
}
Where Layout is a copyable type that can be converted .into() a RawLayout.
I want to make sure I understand what is happening as it is unsafe. As I understand it, layout.into() creates a temporary RawLayout, then & takes a reference to it, and as *const _ converts it to a raw pointer (*const RawLayout). Then the foo() function is called and returns, and finally the temporary RawLayout is dropped.
Is that correct? Or is there some tricky reason why I shouldn't do this?
You are right. In this case, foo is called first and RawLayout is dropped afterwards. This is explained in The Rust Reference (follow the link to see concrete examples of how this works out in practice):
The lifetime of temporary values is typically the innermost enclosing
statement
However, I would rather follow Shepmaster's advice. Explicitly introducing a local variable would help the reader of the code concentrate in more important things, like ensuring that the unsafe code is correct (instead of having to figure out the exact semantics of temporary variables).
How to check this
You can use the code below to check this behavior:
struct Layout;
struct RawLayout;
impl Into<RawLayout> for Layout {
fn into(self) -> RawLayout {
RawLayout
}
}
impl Drop for RawLayout {
fn drop(&mut self) {
println!("Dropping RawLayout");
}
}
unsafe fn foo(layout: *const RawLayout) -> u8 {
println!("foo called");
1
}
fn bar(layout: Layout) -> bool {
unsafe {
foo(&layout.into() as *const _) != 0
}
}
fn main() {
bar(Layout);
}
The output is:
foo called
Dropping RawLayout

How to wrap a call to a FFI function that uses VarArgs in Rust?

mexPrintf, just like printf, accepts a varargs list of arguments, but I don't know what the best way to wrap this is in Rust. There is a RFC for variadic generics, but what can we do today?
In this example, I want to print of the number of inputs and outputs, but the wrapped function just prints garbage. Any idea how to fix this?
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
use std::os::raw::c_void;
type VarArgs = *mut c_void;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(fmt: &str, args: VarArgs) {
let cs = CString::new(fmt).unwrap();
unsafe {
mex_sys::mexPrintf(cs.as_ptr(), args);
}
}
#[no_mangle]
pub extern "system" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
let hw = CString::new("hello world\n").unwrap();
unsafe {
mex_sys::mexPrintf(hw.as_ptr());
}
let inout = CString::new("%d inputs and %d outputs\n").unwrap();
unsafe {
mex_sys::mexPrintf(inout.as_ptr(), nrhs, nlhs);
}
mexPrintf("hello world wrapped\n", std::ptr::null_mut());
let n = Box::new(nrhs);
let p = Box::into_raw(n);
mexPrintf("inputs %d\n", p as VarArgs);
let mut v = vec![3];
mexPrintf("vec %d\n", v.as_mut_ptr() as VarArgs);
}
Contrary to popular belief, it is possible to call variadic / vararg functions that were defined in C. That doesn't mean that doing so is very easy, and it's definitely even easier to do something bad because there are even fewer types for the compiler to check your work with.
Here's an example of calling printf. I've hard-coded just about everything:
extern crate libc;
fn my_thing() {
unsafe {
libc::printf(b"Hello, %s (%d)\0".as_ptr() as *const i8, b"world\0".as_ptr(), 42i32);
}
}
fn main() {
my_thing()
}
Note that I have to very explicitly make sure my format string and arguments are all the right types and the strings are NUL-terminated.
Normally, you'll use tools like CString:
extern crate libc;
use std::ffi::CString;
fn my_thing(name: &str, number: i32) {
let fmt = CString::new("Hello, %s (%d)").expect("Invalid format string");
let name = CString::new(name).expect("Invalid name");
unsafe {
libc::printf(fmt.as_ptr(), name.as_ptr(), number);
}
}
fn main() {
my_thing("world", 42)
}
The Rust compiler test suite also has an example of calling a variadic function.
A word of warning specifically for printf-like functions: C compiler-writers realized that people screw up this particular type of variadic function call all the time. To help combat that, they've encoded special logic that parses the format string and attempts to check the argument types against the types the format string expect. The Rust compiler will not check your C-style format strings for you!
I had confused a "variable list of arguments" with a va_list. I'm going to avoid both if I can and in this situation, I'm just going to do the string formatting in Rust before passing it to interop. Here is what worked for me in this case:
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(text: &str) {
let cs = CString::new(text).expect("Invalid text");
unsafe {
mex_sys::mexPrintf(cs.as_ptr());
}
}
#[no_mangle]
pub extern "C" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
mexPrintf(&format!("{} inputs and {} outputs\n", nrhs, nlhs));
}

How would you go about creating a pointer to a specific memory address in Rust?

For example, let's say I want to access whatever value is stored at 0x0900. I found the function std::ptr::read in the Rust standard library, but the documentation isn't super clear on how to use it and I'm not sure if it's the right way.
This is what I've tried:
use std::ptr;
fn main() {
let n = ptr::read("0x0900");
println!("{}", n);
}
but it gives me error E0277
If you want to read a value of type u32 from memory location 0x0900, you could do it as follows:
use std::ptr;
fn main() {
let p = 0x0900 as *const u32;
let n = unsafe { ptr::read(p) };
println!("{}", n);
}
Note that you need to decide what type of pointer you want when casting the address to a pointer.

Resources