Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#[repr(C)] structs missing Cread/Cwrite implementations #421

Open
PinkNoize opened this issue Aug 25, 2024 · 2 comments
Open

#[repr(C)] structs missing Cread/Cwrite implementations #421

PinkNoize opened this issue Aug 25, 2024 · 2 comments

Comments

@PinkNoize
Copy link

All the #[repr(C)] structs implement Pread/Pwrite but do not implement Cread/Cwrite which is useful in no_std environments.

I'd be happy to implement Cread/Cwrite for the ELF structs (with tests), but wanted to know if this is something that is wanted for the project and if the implementation below is the recommend way to do this.

Here is my implementation for the ELF header:

        use core::mem;
        use scroll::{Cread, Cwrite, Endian};

        impl ctx::FromCtx<Endian> for Header {
            #[inline]
            fn from_ctx(src: &[u8], le: Endian) -> Self {
                assert!(src.len() >= SIZEOF_EHDR);
                let mut elf_header = Header::default();
                for i in 0..SIZEOF_IDENT {
                    elf_header.e_ident[i] = src.cread(i);
                }
                let endianness = match elf_header.e_ident[EI_DATA] {
                    ELFDATA2LSB => scroll::LE,
                    ELFDATA2MSB => scroll::BE,
                    // fallback to provided endian
                    _ => le,
                };
                elf_header.e_type = src.cread_with(SIZEOF_IDENT, endianness);
                elf_header.e_machine = src.cread_with(SIZEOF_IDENT + 2, endianness);
                elf_header.e_version = src.cread_with(SIZEOF_IDENT + 4, endianness);
                elf_header.e_entry = src.cread_with(SIZEOF_IDENT + 8, endianness);
                elf_header.e_phoff =
                    src.cread_with(SIZEOF_IDENT + 8 + mem::size_of::<$size>(), endianness);
                elf_header.e_shoff =
                    src.cread_with(SIZEOF_IDENT + 8 + 2 * mem::size_of::<$size>(), endianness);
               ...
                elf_header.e_shstrndx =
                    src.cread_with(SIZEOF_IDENT + 22 + 3 * mem::size_of::<$size>(), endianness);
                elf_header
            }
        }
        impl ctx::IntoCtx<Endian> for Header {
            fn into_ctx(self, bytes: &mut [u8], le: Endian) {
                assert!(bytes.len() >= SIZEOF_EHDR);
                let endianness = match self.e_ident[EI_DATA] {
                    ELFDATA2LSB => scroll::LE,
                    ELFDATA2MSB => scroll::BE,
                    // fallback to provided endian
                    _ => le,
                };
                for i in 0..self.e_ident.len() {
                    bytes.cwrite(self.e_ident[i], i);
                }
                bytes.cwrite_with(self.e_type, SIZEOF_IDENT, endianness);
                bytes.cwrite_with(self.e_machine, SIZEOF_IDENT + 2, endianness);
                ...
                bytes.cwrite_with(
                    self.e_shstrndx,
                    SIZEOF_IDENT + 22 + 3 * mem::size_of::<$size>(),
                    endianness,
                );
            }
        }
@m4b
Copy link
Owner

m4b commented Aug 26, 2024

Interesting! So I'd like to hear a little bit more about your usecase, if you don't mind; it sounds like you might be using/wanting to use goblin for parsing elf structures in a no_std environment, is that correct? And if so, you why doesn't pread work for you in that environment?

My first worry about adding Cread/Cwrite implementations is that it will be fairly redundant for the various types w.r.t. their Pread implementations (although many of them are also derived), which could be a maintenance burden.

I'm also wondering how useful cread is after e.g., header/program_header, section_header, etc. in general all the remaining stuff is fairly fallible, so I don't think FromCtx impls are a great match there, semantically? Anyway, that doesn't mean no, just curious to solicit more information about your usecases, and etc. :)

@PinkNoize
Copy link
Author

I'm working on making some reference implementations for elf infectors so that would be parsing, modifying and writing elf structures in a no_std and no alloc environment. As its no alloc, pread/pwrite aren't available for these structs.

I'm also wondering how useful cread is after e.g., header/program_header, section_header, etc. in general all the remaining stuff is fairly fallible

Cread/Cwrite isn't really necessary as all these structs are Plain and can be converted to and from bytes with plain functions. I figured I'd ask as the scroll traits seem a bit nicer to use.

// cread
let h: Header = plain::from_mut_bytes(buf[offset..offset + mem::size_of::<Header>()]);
h.ph_num = 5;
// cwrite
let bytes = unsafe { plain::as_bytes(h) };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants