2

If I have a struct, for example:

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct SomeData {
    a: u16,
    b: u64,
    c: u32,
    d: u16,
}

How do I copy it to a specific location in memory, e.g. to a point 0x1000 in memory efficiently? Would something like this work?

let dst_addr: u64 = 0x1000;
let src = SomeData {a: 1, b: 2, c: 3, d: 4};
unsafe {
    let tmp: &[u8; 10] = transmute(src);
    copy(dst_addr as *mut _, tmp);
}

Please note that the repr(C, packed) part is actually needed here.

The software is running on bare x86_64, ring 0, without operating system or other limitations. Also, I'm programming without the standard library, so this should be achievable with only the core library.

This is, of course, unsafe, but it is not a problem.

Edit: Just clarifying: I'm copying to uninitialized memory.

Hannes Karppila
  • 969
  • 2
  • 13
  • 31
  • 1
    There are a handful of great tutorials about writing your own kernel including [*Writing an OS in Rust in tiny steps* by Julia Evans](http://jvns.ca/blog/2014/03/12/the-rust-os-story/) and [*Writing an OS in Rust* by Philipp Oppermann](http://os.phil-opp.com/) and at least two larger projects: [Intermezzos](https://intermezzos.github.io/book/) and [Redox](https://github.com/redox-os/redox). – Shepmaster Jul 15 '16 at 17:22
  • @Shepmaster Yep, I have read both. I was just wondering what is the "proper" way to do this, as tutorials don't always get it right, and if there was some great "tricks" I wasn't aware of. – Hannes Karppila Jul 15 '16 at 17:25
  • I think those tutorials get read over thoroughly by the community when they are posted to the subreddit or user's forum, or even Hacker News. I'd expect them to be pretty well reviewed. – Shepmaster Jul 15 '16 at 17:36
  • As a pedantic point, I think `usize` might be slightly better than u64 if it's to hold a pointer. On the other hand it looks like you're doing something very specific to one system! – Chris Emerson Jul 16 '16 at 08:15
  • @ChrisEmerson Yep, it's actually converted from usize, just because the pointer is actually used after this for things where it must be exactly 64bits. – Hannes Karppila Jul 16 '16 at 10:24

1 Answers1

7

You will want to have a look at the core::ptr module.

Its write function does exactly what you wish:

pub unsafe fn write<T>(dst: *mut T, src: T)
core::ptr::write(dst_addr as *mut_, src);

As noted, it does not drop the value current at dst_addr (you can use read to do so).

I advise against using intrinsics::copy_nonoverlapping as intrinsics will never be stabilized.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • It worked => accepted! Had to use `ptr::write(dst_addr as *mut SomeData, *self);` because I was doing this inside a `SomeData`s method. – Hannes Karppila Jul 16 '16 at 14:37