const DYLD_CHAINED_IMPORT: u32 = 1;
const DYLD_CHAINED_PTR_64: u16 = 2;
const CHAIN_STRIDE: u64 = 4;
const CHAIN_PAGE_SIZE: u16 = 0x4000;
pub struct ChainedFixups {
pub blob: Vec<u8>,
pub got_page_start: u16,
}
pub fn build(
imports: &[String],
got_fileoff: usize,
data_fileoff: usize,
n_data_sections: usize, ) -> ChainedFixups {
let n = imports.len();
const STARTS_IMAGE_BASE: usize = 4 + 4 * 4;
const STARTS_SEG_SIZE: usize = 24;
let imports_offset: u32 = (32 + STARTS_IMAGE_BASE + STARTS_SEG_SIZE) as u32;
let symbols_offset: u32 = imports_offset + n as u32 * 4;
let mut names: Vec<u8> = Vec::new();
let mut name_offsets: Vec<u32> = Vec::new();
for import in imports {
name_offsets.push(names.len() as u32);
if !import.starts_with('_') {
names.push(b'_');
}
names.extend_from_slice(import.as_bytes());
names.push(0);
}
while names.len() % 4 != 0 { names.push(0); }
let total = 32 + STARTS_IMAGE_BASE + STARTS_SEG_SIZE + n * 4 + names.len();
let mut blob = vec![0u8; total];
let mut w = Writer::new(&mut blob);
w.u32(0); w.u32(32); w.u32(imports_offset); w.u32(symbols_offset); w.u32(n as u32); w.u32(DYLD_CHAINED_IMPORT); w.u32(0); w.u32(0);
debug_assert_eq!(w.pos, 32);
w.u32(4);
w.u32(0); w.u32(0); w.u32(STARTS_IMAGE_BASE as u32); w.u32(0);
debug_assert_eq!(w.pos, 32 + STARTS_IMAGE_BASE);
let got_page_start = (got_fileoff - data_fileoff) as u16; w.u32(STARTS_SEG_SIZE as u32); w.u16(CHAIN_PAGE_SIZE); w.u16(DYLD_CHAINED_PTR_64); w.u64(data_fileoff as u64); w.u32(0); w.u16(if n > 0 { 1 } else { 0 }); if n > 0 {
w.u16(got_page_start);
} else {
w.u16(0xFFFF); }
debug_assert_eq!(w.pos, 32 + STARTS_IMAGE_BASE + STARTS_SEG_SIZE);
for (i, _name) in imports.iter().enumerate() {
let name_off = name_offsets[i];
let entry: u32 = 1 | (name_off << 9);
w.u32(entry);
}
w.bytes(&names);
debug_assert_eq!(w.pos, total);
ChainedFixups { blob, got_page_start }
}
pub fn got_bind_entry(ordinal: usize, is_last: bool) -> u64 {
let next: u64 = if is_last { 0 } else { 2 }; (1u64 << 63) | (next << 51) | (ordinal as u64 & 0x00FF_FFFF)
}
struct Writer<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl<'a> Writer<'a> {
fn new(buf: &'a mut [u8]) -> Self { Self { buf, pos: 0 } }
fn u32(&mut self, v: u32) { self.buf[self.pos..self.pos+4].copy_from_slice(&v.to_le_bytes()); self.pos += 4; }
fn u64(&mut self, v: u64) { self.buf[self.pos..self.pos+8].copy_from_slice(&v.to_le_bytes()); self.pos += 8; }
fn u16(&mut self, v: u16) { self.buf[self.pos..self.pos+2].copy_from_slice(&v.to_le_bytes()); self.pos += 2; }
fn bytes(&mut self, v: &[u8]) { self.buf[self.pos..self.pos+v.len()].copy_from_slice(v); self.pos += v.len(); }
}