Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/prototype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ fn run (args: Args) -> Result<(), Error> {
("str.1", Decl::cstring().into()),
("DEADBEEF", Decl::data_import().into()),
("STATIC", Decl::data().global().writable().into()),
("STATIC_REF", Decl::data().global().writable().into()),
("STATIC_REF", Decl::data().global().writable().with_align(Some(64)).into()),
("printf", Decl::function_import().into()),
];
obj.declarations(declarations.into_iter())?;
Expand Down
26 changes: 19 additions & 7 deletions src/artifact/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,19 @@ macro_rules! align_methods {
() => {
/// Build alignment. Size is in bytes. If None, a default is chosen
/// in the backend.
pub fn with_align(mut self, align: Option<usize>) -> Self {
self.align = align;
pub fn with_align(mut self, align: Option<u64>) -> Self {
self.set_align(align);
self
}
/// Set alignment
pub fn set_align(&mut self, align: Option<usize>) {
pub fn set_align(&mut self, align: Option<u64>) {
if let Some(align) = align {
debug_assert_eq!(align.checked_next_power_of_two(), Some(align));
}
self.align = align;
}
/// Get alignment
pub fn get_align(&self) -> Option<usize> {
pub fn get_align(&self) -> Option<u64> {
self.align
}
}
Expand Down Expand Up @@ -215,6 +218,15 @@ impl DefinedDecl {
DefinedDecl::Section(a) => a.is_writable(),
}
}

/// Accessor to determine the minimal alignment
pub fn get_align(&self) -> Option<u64> {
match self {
DefinedDecl::Data(a) => a.get_align(),
DefinedDecl::Function(a) => a.get_align(),
DefinedDecl::Section(a) => a.get_align(),
}
}
}

impl Decl {
Expand Down Expand Up @@ -387,7 +399,7 @@ impl Into<Decl> for DataImportDecl {
pub struct FunctionDecl {
scope: Scope,
visibility: Visibility,
align: Option<usize>,
align: Option<u64>,
}

impl Default for FunctionDecl {
Expand Down Expand Up @@ -419,7 +431,7 @@ pub struct DataDecl {
visibility: Visibility,
writable: bool,
datatype: DataType,
align: Option<usize>,
align: Option<u64>,
}

impl Default for DataDecl {
Expand Down Expand Up @@ -487,7 +499,7 @@ pub enum SectionKind {
pub struct SectionDecl {
kind: SectionKind,
datatype: DataType,
align: Option<usize>,
align: Option<u64>,
}

impl SectionDecl {
Expand Down
4 changes: 2 additions & 2 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ struct SectionBuilder {
alloc: bool,
size: u64,
name_offset: usize,
align: Option<usize>,
align: Option<u64>,
}

impl SectionBuilder {
Expand Down Expand Up @@ -234,7 +234,7 @@ impl SectionBuilder {
self
}
/// Specify section alignment
pub fn align(mut self, align: Option<usize>) -> Self {
pub fn align(mut self, align: Option<u64>) -> Self {
self.align = align;
self
}
Expand Down
89 changes: 81 additions & 8 deletions src/mach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use failure::Error;
use indexmap::IndexMap;
use scroll::ctx::SizeWith;
use scroll::{IOwrite, Pwrite};
use std::collections::HashMap;
use std::io::SeekFrom::*;
use std::io::{BufWriter, Cursor, Seek, Write};
use string_interner::DefaultStringInterner;
Expand Down Expand Up @@ -45,6 +46,16 @@ impl From<Architecture> for CpuType {
}
}

fn align_to_align_exp(align: u64) -> u64 {
assert!(align != 0);
assert!(align.is_power_of_two());
let mut align_exp = 0;
while 1 << align_exp != align {
align_exp += 1;
}
align_exp
}

type SectionIndex = usize;
type StrtableOffset = u64;

Expand Down Expand Up @@ -105,7 +116,6 @@ impl SymbolBuilder {
self
}
/// Finalize and create the symbol
/// The n_value (offset into section) is still unset, and needs to be generated by the client
pub fn create(self) -> Nlist {
use goblin::mach::symbols::{NO_SECT, N_EXT, N_SECT, N_UNDF};
let n_strx = self.name;
Expand Down Expand Up @@ -395,6 +405,7 @@ struct SegmentBuilder {
/// A stupid offset value I need to refactor out
pub offset: u64,
size: u64,
align_pad_map: HashMap<String, u64>,
}

impl SegmentBuilder {
Expand Down Expand Up @@ -422,27 +433,53 @@ impl SegmentBuilder {
symbol_offset: &mut u64,
section: SectionIndex,
definitions: &[Definition],
alignment_exponent: u64,
min_alignment_exponent: u64,
flags: Option<u32>,
align_pad_map: &mut HashMap<String, u64>,
) {
let mut local_size = 0;
let mut segment_relative_offset = 0;
for def in definitions {
let mut section_relative_offset = 0;
let mut alignment_exponent = min_alignment_exponent;
let mut def_iter = definitions.iter().peekable();
while let Some(def) = def_iter.next() {
if let DefinedDecl::Section { .. } = def.decl {
unreachable!();
}
local_size += def.data.len() as u64;

symtab.insert(
def.name,
SymbolType::Defined {
section,
segment_relative_offset,
segment_relative_offset: section_relative_offset,
absolute_offset: *symbol_offset,
global: def.decl.is_global(),
},
);
*symbol_offset += def.data.len() as u64;
segment_relative_offset += def.data.len() as u64;
section_relative_offset += def.data.len() as u64;
local_size += def.data.len() as u64;

let next_def_alignment_exponent = std::cmp::max(
min_alignment_exponent,
def_iter
.peek()
.map(|def| align_to_align_exp(def.decl.get_align().unwrap_or(1)))
.unwrap_or(0),
);
alignment_exponent = std::cmp::max(alignment_exponent, next_def_alignment_exponent);

let align_pad = (1 << next_def_alignment_exponent)
- (section_relative_offset % (1 << next_def_alignment_exponent));
let align_pad = if align_pad == (1 << next_def_alignment_exponent) {
0
} else {
align_pad
};
align_pad_map.insert(def.name.to_string(), align_pad);

*symbol_offset += align_pad;
section_relative_offset += align_pad;
local_size += align_pad;
}
let mut section = SectionBuilder::new(sectname.to_string(), segname, local_size)
.offset(*offset)
Expand Down Expand Up @@ -504,7 +541,7 @@ impl SegmentBuilder {
let section = SectionBuilder::new(sectname, segment_name, local_size)
.offset(*offset)
.addr(*addr)
.align(1)
.align(align_to_align_exp(s.get_align().unwrap_or(1)))
.flags(flags);
*offset += local_size;
*addr += local_size;
Expand All @@ -525,6 +562,7 @@ impl SegmentBuilder {
let mut size = 0;
let mut symbol_offset = 0;
let mut sections = IndexMap::new();
let mut align_pad_map = HashMap::new();
Self::build_section(
symtab,
"__text",
Expand All @@ -537,6 +575,7 @@ impl SegmentBuilder {
&code,
4,
Some(S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS),
&mut align_pad_map,
);
Self::build_section(
symtab,
Expand All @@ -550,6 +589,7 @@ impl SegmentBuilder {
&data,
3,
None,
&mut align_pad_map,
);
Self::build_section(
symtab,
Expand All @@ -563,6 +603,7 @@ impl SegmentBuilder {
&cstrings,
0,
Some(S_CSTRING_LITERALS),
&mut align_pad_map,
);
for (idx, def) in custom_sections.iter().enumerate() {
Self::build_custom_section(
Expand All @@ -588,6 +629,7 @@ impl SegmentBuilder {
size,
sections,
offset,
align_pad_map,
}
}
}
Expand Down Expand Up @@ -742,6 +784,14 @@ impl<'a> Mach<'a> {
//////////////////////////////
for code in self.code {
file.write_all(code.data)?;

if let Some(&align_pad) = self.segment.align_pad_map.get(code.name) {
for _ in 0..align_pad {
// `0xcc` generates a debug interrupt on x86. When there is no debugger attached
// this will abort the program.
file.write_all(&[0xcc])?;
}
}
}
debug!("SEEK: after code: {}", file.seek(Current(0))?);

Expand All @@ -750,6 +800,15 @@ impl<'a> Mach<'a> {
//////////////////////////////
for data in self.data {
file.write_all(data.data)?;

if let Some(&align_pad) = self.segment.align_pad_map.get(data.name) {
for _ in 0..align_pad {
// Exact padding value doesn't matter. Not using zero to prevent confusion
// with a zero pointer when the final executable accidentially reads past
// the end of a data object.
file.write_all(&[0xaa])?;
}
}
}
debug!("SEEK: after data: {}", file.seek(Current(0))?);

Expand All @@ -758,6 +817,13 @@ impl<'a> Mach<'a> {
//////////////////////////////
for cstring in self.cstrings {
file.write_all(cstring.data)?;

if let Some(&align_pad) = self.segment.align_pad_map.get(cstring.name) {
for _ in 0..align_pad {
// See comment above for explanation of 0xaa
file.write_all(&[0xaa])?;
}
}
}
debug!("SEEK: after cstrings: {}", file.seek(Current(0))?);

Expand All @@ -766,6 +832,13 @@ impl<'a> Mach<'a> {
//////////////////////////////
for section in self.sections {
file.write_all(section.data)?;

if let Some(&align_pad) = self.segment.align_pad_map.get(section.name) {
for _ in 0..align_pad {
// See comment above for explanation of 0xaa
file.write_all(&[0xaa])?;
}
}
}
debug!("SEEK: after custom sections: {}", file.seek(Current(0))?);

Expand Down