Closed phil-opp closed 5 years ago
@phil-opp What needs to be changed?
P.S. I think it is reasonable to expect the size of a disk image to be a multiple of the minimum block size.
Yes, it's absolutely reasonable, it's just not what objcopy
does by default. The relevant code is: https://github.com/rust-osdev/bootimage/blob/c2ce530bda246300b0d4ea14b0634dff4f48d4f0/src/builder.rs#L283-L298
To fix this we need to either find some objcopy
argument that performs the alignment or pad the created binary manually after it's created.
There are 2 options for objcopy
which seem to do that: --pad-to
and --gap-fill
Hmm, --gap-fill
seems to be about the value that is used to fill alignment gaps (instead of leaving them undefined. The --pad-to
argument seems fitting, but it expects an address as argument, which is a bit cumbersome to find out (read the ELF file, get the load address and size of the last section, and round it up).
Given that the result is a binary file, it's probably easier to just open it afterwards and using set_len
to pad it to the next 512-byte boundary.
@phil-opp Would something like this work? I can't test it now.
// Pad to nearest block size
{
// BLOCK_SIZE must be a power of 2
const BLOCK_SIZE = 512;
use std::fs::{OpenOptions, File};
let mut file = OpenOptions::new().append(true).open(&output_bin_path).map_err(|err| CreateBootimageError::Io {
message: "failed to open output file",
error: err,
})?;
let file_size = file.metadata().map_err(|err| CreateBootimageError::Io {
message: "failed to get size of output file",
error: err,
})?.len();
file.set_len((file_size + BLOCK_SIZE - 1) & -BLOCK_SIZE).map_err(|err| CreateBootimageError::Io {
message: "failed to pad output file to a multiple of the block size",
error: err,
})?;
}
Yes, I think so.
One nit: I would prefer a different approach for aligning so that it becomes more apparent that we never make the file length smaller. Maybe something like file_size + padding
with let padding: u64 = […]
is possible?
@phil-opp How about this?
let padding = file_size % BLOCK_SIZE;
let padding = if padding > 0 { BLOCK_SIZE - padding } else { 0 };
file.set_len(file_size + padding).map_err(_)?;
Actually, since BLOCK_SIZE
is a power of 2, the first line could be this:
let padding = file_size & -BLOCK_SIZE;
Looks good! Do you mind opening a pull request?
Actually, since BLOCK_SIZE is a power of 2, the first line could be this:
I think the compiler should be able to perform this optimization automatically. I like the first variant more because it is more obvious what happens. (Performance shouldn't be relevant at this place anyway since it's clearly IO-bound.
@phil-opp I created a pull request. Also, I agree with you that the compiler (or rather LLVM) should perform this optimization itself.
For some reason VirtualBox expects that disk images are a multiple of 512 bytes. We had an option to add the required padding in an old version of
bootimage
but we haven't ported that option to the new build system yet.Reported in https://github.com/phil-opp/blog_os/issues/403#issuecomment-480662955