|
|
|
@ -25,7 +25,7 @@ use super::ElfObject;
|
|
|
|
|
pub struct ElfOutput<'data> {
|
|
|
|
|
destination: PathBuf,
|
|
|
|
|
file: ELF64,
|
|
|
|
|
segment_data: SegmentData<'data>,
|
|
|
|
|
input_data: InputData<'data>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'data> ElfOutput<'data> {
|
|
|
|
@ -44,7 +44,7 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
Self {
|
|
|
|
|
destination,
|
|
|
|
|
file: elf,
|
|
|
|
|
segment_data: SegmentData::new(),
|
|
|
|
|
input_data: InputData::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -54,34 +54,32 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
Self {
|
|
|
|
|
destination,
|
|
|
|
|
file: elf_bin_from_object(other),
|
|
|
|
|
segment_data: SegmentData::new(),
|
|
|
|
|
input_data: InputData::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn populate_sections(&mut self) -> Result<u64, Error> {
|
|
|
|
|
fn populate_sections(&mut self) -> Result<(), Error> {
|
|
|
|
|
let mut names = Vec::new();
|
|
|
|
|
let mut name_idx = 0usize;
|
|
|
|
|
let mut result = 0u64;
|
|
|
|
|
|
|
|
|
|
for (name, sections) in self.segment_data.sections_mut() {
|
|
|
|
|
let mut data = Vec::new();
|
|
|
|
|
for (name, sections) in self.input_data.sections_mut() {
|
|
|
|
|
let mut data_size = 0;
|
|
|
|
|
|
|
|
|
|
for t in sections.iter_mut() {
|
|
|
|
|
if let Some(iter) = &mut t.data {
|
|
|
|
|
data.extend(iter.as_mut());
|
|
|
|
|
for t in sections.iter() {
|
|
|
|
|
if let Some(bytes) = t.data {
|
|
|
|
|
data_size += bytes.len();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if data.is_empty() {
|
|
|
|
|
if data_size == 0{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result += data.len() as u64;
|
|
|
|
|
names.push(name);
|
|
|
|
|
let section = Section64 {
|
|
|
|
|
name: name.into(),
|
|
|
|
|
header: make_section_header(name_idx, ShType::ProgBits, data.len()),
|
|
|
|
|
contents: Contents64::Raw(data),
|
|
|
|
|
header: make_section_header(name_idx, ShType::ProgBits, data_size),
|
|
|
|
|
contents: Contents64::Raw(Vec::new()), // placeholder only
|
|
|
|
|
};
|
|
|
|
|
name_idx += name.len() + 1;
|
|
|
|
|
self.file.add_section(section);
|
|
|
|
@ -90,7 +88,6 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
let name = ".shstrtab";
|
|
|
|
|
names.push(name);
|
|
|
|
|
let string_table = build_string_table(names, true);
|
|
|
|
|
result += string_table.len() as u64;
|
|
|
|
|
let section = Section64 {
|
|
|
|
|
name: name.into(),
|
|
|
|
|
header: make_section_header(name_idx, ShType::StrTab, string_table.len()),
|
|
|
|
@ -98,7 +95,7 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
};
|
|
|
|
|
self.file.add_section(section);
|
|
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn populate_segment(&mut self, offset: &mut u64, size: u64, which: SegmentType) {
|
|
|
|
@ -114,12 +111,15 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
segment.header.p_memsz = size;
|
|
|
|
|
segment.header.p_offset = *offset;
|
|
|
|
|
|
|
|
|
|
let mut page_size = next_page(size);
|
|
|
|
|
|
|
|
|
|
match which {
|
|
|
|
|
SegmentType::Text => segment.header.p_flags = PF_R | PF_X,
|
|
|
|
|
SegmentType::Data => segment.header.p_flags = PF_R | PF_W,
|
|
|
|
|
SegmentType::Bss => {
|
|
|
|
|
segment.header.p_flags = PF_R;
|
|
|
|
|
segment.header.p_memsz = 0;
|
|
|
|
|
page_size = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -127,7 +127,7 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
self.file.ehdr.e_phnum += 1;
|
|
|
|
|
self.file.ehdr.e_phentsize = size_of::<Phdr64>() as u16;
|
|
|
|
|
|
|
|
|
|
*offset += next_page(size);
|
|
|
|
|
*offset += page_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn populate_segments(&mut self) -> Result<u64, Error> {
|
|
|
|
@ -136,29 +136,25 @@ impl<'data> ElfOutput<'data> {
|
|
|
|
|
// contains .text + .rodata as one segment
|
|
|
|
|
self.populate_segment(
|
|
|
|
|
&mut offset,
|
|
|
|
|
self.segment_data.program_size(),
|
|
|
|
|
self.input_data.program_size(),
|
|
|
|
|
SegmentType::Text,
|
|
|
|
|
);
|
|
|
|
|
// contains .data as one segment
|
|
|
|
|
self.populate_segment(
|
|
|
|
|
&mut offset,
|
|
|
|
|
self.segment_data.data_size(),
|
|
|
|
|
self.input_data.data_size(),
|
|
|
|
|
SegmentType::Data,
|
|
|
|
|
);
|
|
|
|
|
// contains .bss as one segment
|
|
|
|
|
self.populate_segment(&mut offset, self.segment_data.bss_size(), SegmentType::Bss);
|
|
|
|
|
self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss);
|
|
|
|
|
|
|
|
|
|
Ok(offset)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'data> Output<'data> for ElfOutput<'data> {
|
|
|
|
|
fn allocate(&mut self, size: u64) -> Result<u64, Error> {
|
|
|
|
|
Ok(size)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> {
|
|
|
|
|
self.segment_data.append_section(section)
|
|
|
|
|
self.input_data.append_section(section)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn finalize(mut self) -> Result<PathBuf, Error> {
|
|
|
|
@ -169,20 +165,19 @@ impl<'data> Output<'data> for ElfOutput<'data> {
|
|
|
|
|
self.populate_sections()?;
|
|
|
|
|
let page_size = self.populate_segments()?;
|
|
|
|
|
|
|
|
|
|
self.file.ehdr.e_shnum = self.file.sections.len() as u16;
|
|
|
|
|
self.file.ehdr.e_entry = 4096; // TODO
|
|
|
|
|
self.file.ehdr.e_phentsize = PHS;
|
|
|
|
|
self.file.ehdr.e_shentsize = SHS;
|
|
|
|
|
self.file.ehdr.e_phoff = EHS; // TODO: align
|
|
|
|
|
self.file.ehdr.e_shoff = self.file.ehdr.e_phoff
|
|
|
|
|
+ u64::from(self.file.ehdr.e_phnum * self.file.ehdr.e_phentsize)
|
|
|
|
|
+ page_size;
|
|
|
|
|
self.file.ehdr.e_shnum = self.file.sections.len() as u16;
|
|
|
|
|
self.file.ehdr.e_entry = 0x100; // TODO
|
|
|
|
|
self.file.ehdr.e_phoff = EHS;
|
|
|
|
|
self.file.ehdr.e_shoff = self.file.ehdr.e_phoff + (usize::from(self.file.ehdr.e_phentsize) * self.file.segments.len()) as u64;
|
|
|
|
|
|
|
|
|
|
let str_path = expand_path(&self.destination)?;
|
|
|
|
|
|
|
|
|
|
let mut writer = file_writer(str_path, 0o755)?;
|
|
|
|
|
let mut offset = 0;
|
|
|
|
|
|
|
|
|
|
// write ELF header
|
|
|
|
|
offset += writer.write(&self.file.ehdr.to_le_bytes())?;
|
|
|
|
|
|
|
|
|
|
// write program header table
|
|
|
|
@ -191,17 +186,32 @@ impl<'data> Output<'data> for ElfOutput<'data> {
|
|
|
|
|
offset += writer.write(&seg.header.to_le_bytes())?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write section/segment data
|
|
|
|
|
eprintln!("SH start: {}", offset);
|
|
|
|
|
// write section header table
|
|
|
|
|
for sec in self.file.sections.iter_mut() {
|
|
|
|
|
sec.header.sh_offset = offset as u64;
|
|
|
|
|
offset += write_padded(&mut writer, offset, &sec.to_le_bytes())?;
|
|
|
|
|
if sec.header.get_type() == ShType::StrTab {
|
|
|
|
|
sec.header.sh_offset = offset as u64 + u64::from(SHS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eprintln!("SHT: {}", offset);
|
|
|
|
|
// write section header table
|
|
|
|
|
for sec in self.file.sections.iter() {
|
|
|
|
|
offset += writer.write(&sec.header.to_le_bytes())?;
|
|
|
|
|
if sec.header.get_type() == ShType::StrTab {
|
|
|
|
|
offset += writer.write(&sec.to_le_bytes())?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// program data (segments)
|
|
|
|
|
offset += pad_to_next_page(&mut writer, offset)?;
|
|
|
|
|
eprintln!("Prog start: {}", offset);
|
|
|
|
|
// write section/segment data
|
|
|
|
|
for bytes in self.input_data.program_bytes() {
|
|
|
|
|
offset += writer.write(bytes)?;
|
|
|
|
|
}
|
|
|
|
|
offset += pad_to_next_page(&mut writer, offset)?;
|
|
|
|
|
|
|
|
|
|
eprintln!("Data start: {}", offset);
|
|
|
|
|
for bytes in self.input_data.data_bytes() {
|
|
|
|
|
offset += writer.write(bytes)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writer.flush()?;
|
|
|
|
|
|
|
|
|
|
Ok(self.destination)
|
|
|
|
@ -213,7 +223,7 @@ fn file_writer(output_filename: &str, permission: u32) -> Result<BufWriter<File>
|
|
|
|
|
|
|
|
|
|
let file = std::fs::OpenOptions::new()
|
|
|
|
|
.create(true)
|
|
|
|
|
.read(true)
|
|
|
|
|
.truncate(true)
|
|
|
|
|
.write(true)
|
|
|
|
|
.mode(permission)
|
|
|
|
|
.open(output_filename)?;
|
|
|
|
@ -271,14 +281,13 @@ fn next_page(size: u64) -> u64 {
|
|
|
|
|
page_size * pages_needed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn write_padded(writer: &mut BufWriter<File>, offset: usize, data: &[u8]) -> Result<usize, Error> {
|
|
|
|
|
fn pad_to_next_page(writer: &mut BufWriter<File>, offset: usize) -> Result<usize, Error> {
|
|
|
|
|
let page_size = page_size::get();
|
|
|
|
|
let mut written = 0usize;
|
|
|
|
|
|
|
|
|
|
written += writer.write(data)?;
|
|
|
|
|
let padding = page_size - (page_size % offset);
|
|
|
|
|
let padding = page_size - (offset % page_size);
|
|
|
|
|
|
|
|
|
|
written += writer.get_mut().seek(SeekFrom::Current(padding as i64))? as usize;
|
|
|
|
|
eprintln!("Padding from: {} with: {}", offset, padding);
|
|
|
|
|
writer.seek(SeekFrom::Current(padding.try_into()?))?;
|
|
|
|
|
|
|
|
|
|
Ok(written)
|
|
|
|
|
Ok(padding)
|
|
|
|
|
}
|
|
|
|
|