forked from M-Labs/artiq-zynq
Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
Astro | 7abcd3dd95 | |
Astro | 9aca1a780b | |
Astro | 355b746715 | |
Astro | 027fc49809 | |
Astro | 00550fda86 | |
Astro | c4ce42f7a4 | |
Astro | 8e99c5eb7a | |
Astro | d9c58da1e9 | |
Astro | 91085ca8d6 | |
Astro | 35b9627371 |
|
@ -46,15 +46,27 @@ checksum = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
||||||
name = "dyld"
|
name = "dyld"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libboard_zynq",
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
||||||
|
dependencies = [
|
||||||
|
"nb",
|
||||||
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#f8782f3f699ba0e749a639534553c9dc2599523e"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
"nb",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
]
|
]
|
||||||
|
@ -62,19 +74,22 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#f8782f3f699ba0e749a639534553c9dc2599523e"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
"nb",
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
|
"void",
|
||||||
"volatile-register",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#f8782f3f699ba0e749a639534553c9dc2599523e"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
@ -83,7 +98,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#f8782f3f699ba0e749a639534553c9dc2599523e"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -93,7 +108,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#f8782f3f699ba0e749a639534553c9dc2599523e"
|
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#aa9379463207a02ee7ca4e597054a447b9a90232"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
@ -125,6 +140,12 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
checksum = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -147,9 +168,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
version = "0.1.0-alpha.4"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
|
@ -185,6 +206,7 @@ dependencies = [
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
"libsupport_zynq",
|
"libsupport_zynq",
|
||||||
|
"log",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
@ -202,9 +224,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -223,6 +245,12 @@ version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
|
checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "volatile-register"
|
name = "volatile-register"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["runtime"]
|
members = [
|
||||||
|
"libdyld",
|
||||||
|
"runtime"
|
||||||
|
]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -5,3 +5,6 @@ version = "0.1.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "dyld"
|
name = "dyld"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4"
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
use core::{mem, ptr, fmt, slice, str, convert, ops::{Deref, Range}};
|
||||||
|
use super::{
|
||||||
|
Arch,
|
||||||
|
elf::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
|
||||||
|
if data.len() < offset + mem::size_of::<T>() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||||
|
Some(unsafe { ptr::read_unaligned(ptr) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ELF file
|
||||||
|
pub struct File<'a> {
|
||||||
|
pub ehdr: Elf32_Ehdr,
|
||||||
|
data: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> File<'a> {
|
||||||
|
pub fn new(data: &'a [u8]) -> Option<Self> {
|
||||||
|
let ehdr = read_unaligned(data, 0)?;
|
||||||
|
Some(File { ehdr, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_unaligned<T: Copy>(&self, offset: usize) -> Option<T> {
|
||||||
|
read_unaligned(self.data, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arch(&self) -> Option<Arch> {
|
||||||
|
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
||||||
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
|
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
|
];
|
||||||
|
const IDENT_ARM: [u8; EI_NIDENT] = [
|
||||||
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
|
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
|
];
|
||||||
|
|
||||||
|
match (self.ehdr.e_ident, self.ehdr.e_machine) {
|
||||||
|
(IDENT_ARM, EM_ARM) => Some(Arch::Arm),
|
||||||
|
(IDENT_OPENRISC, EM_OPENRISC) => Some(Arch::OpenRisc),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b
|
||||||
|
{
|
||||||
|
(0..self.ehdr.e_phnum).map(move |i| {
|
||||||
|
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
||||||
|
self.read_unaligned::<Elf32_Phdr>(phdr_off)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dynamic_header_vaddr(&self) -> Option<Range<usize>> {
|
||||||
|
self.program_headers()
|
||||||
|
.filter_map(|phdr| phdr)
|
||||||
|
.find(|phdr| phdr.p_type == PT_DYNAMIC)
|
||||||
|
.map(|phdr| phdr.p_vaddr as usize..(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for File<'_> {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
use core::{
|
||||||
|
ops::{Deref, DerefMut, Range},
|
||||||
|
mem,
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutErr};
|
||||||
|
use super::{
|
||||||
|
elf::*,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn elf_hash(name: &[u8]) -> u32 {
|
||||||
|
let mut h: u32 = 0;
|
||||||
|
for c in name {
|
||||||
|
h = (h << 4) + *c as u32;
|
||||||
|
let g = h & 0xf0000000;
|
||||||
|
if g != 0 {
|
||||||
|
h ^= g >> 24;
|
||||||
|
h &= !g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DynamicSection<'a> {
|
||||||
|
pub strtab: &'a [u8],
|
||||||
|
pub symtab: &'a [Elf32_Sym],
|
||||||
|
pub hash_bucket: &'a [Elf32_Word],
|
||||||
|
pub hash_chain: &'a [Elf32_Word],
|
||||||
|
pub rel: &'a [Elf32_Rel],
|
||||||
|
pub rela: &'a [Elf32_Rela],
|
||||||
|
pub pltrel: &'a [Elf32_Rel],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DynamicSection<'a> {
|
||||||
|
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
|
||||||
|
let hash = elf_hash(name);
|
||||||
|
let mut index = self.hash_bucket[hash as usize % self.hash_bucket.len()] as usize;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if index == STN_UNDEF { return None }
|
||||||
|
|
||||||
|
let sym = &self.symtab[index];
|
||||||
|
let sym_name_off = sym.st_name as usize;
|
||||||
|
match self.strtab.get(sym_name_off..sym_name_off + name.len()) {
|
||||||
|
Some(sym_name) if sym_name == name => {
|
||||||
|
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
match sym.st_shndx {
|
||||||
|
SHN_UNDEF => return None,
|
||||||
|
SHN_ABS => return Some(sym.st_value),
|
||||||
|
_ => return Some(sym.st_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
index = self.hash_chain[index] as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_starting_at(&self, offset: usize) -> Result<&'a [u8], Error> {
|
||||||
|
let size = self.strtab.iter().skip(offset).position(|&x| x == 0)
|
||||||
|
.ok_or("symbol in symbol table not null-terminated")?;
|
||||||
|
Ok(self.strtab.get(offset..offset + size)
|
||||||
|
.ok_or("cannot read symbol name")?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// target memory image
|
||||||
|
pub struct Image {
|
||||||
|
layout: Layout,
|
||||||
|
data: &'static mut [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn new(size: usize, align: usize) -> Result<Self, LayoutErr> {
|
||||||
|
let layout = Layout::from_size_align(size, align)?;
|
||||||
|
let data = unsafe {
|
||||||
|
let ptr = alloc_zeroed(layout);
|
||||||
|
slice::from_raw_parts_mut(ptr, size)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Image {
|
||||||
|
layout,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// assumes that self.data is properly aligned
|
||||||
|
pub fn get_ref<T>(&self, offset: usize) -> Option<&T>
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
if self.data.len() < offset + mem::size_of::<T>() {
|
||||||
|
None
|
||||||
|
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||||
|
Some(unsafe { &*ptr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ref_slice<T: Copy>(&self, offset: usize, len: usize) -> Option<&[T]> {
|
||||||
|
if self.data.len() < offset + mem::size_of::<T>() * len {
|
||||||
|
None
|
||||||
|
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
||||||
|
Some(unsafe { slice::from_raw_parts(ptr, len) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dynamic_headers<'a>(&'a self, range: Range<usize>) ->
|
||||||
|
impl Iterator<Item = &'a Elf32_Dyn> + 'a
|
||||||
|
{
|
||||||
|
range
|
||||||
|
.step_by(mem::size_of::<Elf32_Dyn>())
|
||||||
|
.filter_map(move |offset| {
|
||||||
|
self.get_ref::<Elf32_Dyn>(offset)
|
||||||
|
})
|
||||||
|
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dynamic_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
|
||||||
|
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
||||||
|
let (mut symtab_off, mut symtab_sz) = (0, 0);
|
||||||
|
let (mut rel_off, mut rel_sz) = (0, 0);
|
||||||
|
let (mut rela_off, mut rela_sz) = (0, 0);
|
||||||
|
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
||||||
|
let (mut hash_off, mut hash_sz) = (0, 0);
|
||||||
|
let mut sym_ent = 0;
|
||||||
|
let mut rel_ent = 0;
|
||||||
|
let mut rela_ent = 0;
|
||||||
|
let mut nbucket = 0;
|
||||||
|
let mut nchain = 0;
|
||||||
|
|
||||||
|
for dyn_header in self.dynamic_headers(range) {
|
||||||
|
let val = unsafe { dyn_header.d_un.d_val } as usize;
|
||||||
|
match dyn_header.d_tag {
|
||||||
|
DT_NULL => break,
|
||||||
|
DT_STRTAB => strtab_off = val,
|
||||||
|
DT_STRSZ => strtab_sz = val,
|
||||||
|
DT_SYMTAB => symtab_off = val,
|
||||||
|
DT_SYMENT => sym_ent = val,
|
||||||
|
DT_REL => rel_off = val,
|
||||||
|
DT_RELSZ => rel_sz = val / mem::size_of::<Elf32_Rel>(),
|
||||||
|
DT_RELENT => rel_ent = val,
|
||||||
|
DT_RELA => rela_off = val,
|
||||||
|
DT_RELASZ => rela_sz = val / mem::size_of::<Elf32_Rela>(),
|
||||||
|
DT_RELAENT => rela_ent = val,
|
||||||
|
DT_JMPREL => pltrel_off = val,
|
||||||
|
DT_PLTRELSZ => pltrel_sz = val / mem::size_of::<Elf32_Rel>(),
|
||||||
|
DT_HASH => {
|
||||||
|
nbucket = *self.get_ref::<Elf32_Word>(val + 0)
|
||||||
|
.ok_or("cannot read hash bucket count")? as usize;
|
||||||
|
nchain = *self.get_ref::<Elf32_Word>(val + 4)
|
||||||
|
.ok_or("cannot read hash chain count")? as usize;
|
||||||
|
hash_off = val + 8;
|
||||||
|
hash_sz = nbucket + nchain;
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sym_ent != mem::size_of::<Elf32_Sym>() {
|
||||||
|
return Err("incorrect symbol entry size")?
|
||||||
|
}
|
||||||
|
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
|
||||||
|
return Err("incorrect relocation entry size")?
|
||||||
|
}
|
||||||
|
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
|
||||||
|
return Err("incorrect relocation entry size")?
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the same--there are as many chains as buckets, and the chains only contain
|
||||||
|
// the symbols that overflowed the bucket.
|
||||||
|
symtab_sz = nchain;
|
||||||
|
|
||||||
|
let hash = self.get_ref_slice::<Elf32_Word>(hash_off, hash_sz)
|
||||||
|
.ok_or("cannot read hash entries")?;
|
||||||
|
let strtab = self.get_ref_slice(strtab_off, strtab_sz)
|
||||||
|
.ok_or("cannot read string table")?;
|
||||||
|
let symtab = self.get_ref_slice::<Elf32_Sym>(symtab_off, symtab_sz)
|
||||||
|
.ok_or("cannot read symbol table")?;
|
||||||
|
let hash_bucket = &hash[..nbucket];
|
||||||
|
let hash_chain = &hash[nbucket..nbucket + nchain];
|
||||||
|
let rel = self.get_ref_slice::<Elf32_Rel>(rel_off, rel_sz)
|
||||||
|
.ok_or("cannot read rel entries")?;
|
||||||
|
let rela = self.get_ref_slice::<Elf32_Rela>(rela_off, rela_sz)
|
||||||
|
.ok_or("cannot read rela entries")?;
|
||||||
|
let pltrel = self.get_ref_slice::<Elf32_Rel>(pltrel_off, pltrel_sz)
|
||||||
|
.ok_or("cannot read pltrel entries")?;
|
||||||
|
// debug!("ELF: {} rela, {} rel, {} pltrel entries", rela_sz, rel_sz, pltrel_sz);
|
||||||
|
|
||||||
|
Ok(DynamicSection {
|
||||||
|
strtab,
|
||||||
|
symtab,
|
||||||
|
hash_bucket,
|
||||||
|
hash_chain,
|
||||||
|
rel,
|
||||||
|
rela,
|
||||||
|
pltrel,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptr(&self) -> *const u8 {
|
||||||
|
self.data.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
|
||||||
|
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
|
||||||
|
return Err("relocation out of image bounds")?
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;
|
||||||
|
Ok(unsafe { *ptr = value })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Image {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
dealloc(self.data.as_mut_ptr(), self.layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Image {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Image {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,349 +1,114 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
use core::{mem, ptr, fmt, slice, str, convert};
|
use core::{mem, ptr, fmt, slice, str, convert};
|
||||||
|
use alloc::string::String;
|
||||||
|
use log::{info, trace, error};
|
||||||
use elf::*;
|
use elf::*;
|
||||||
|
|
||||||
pub mod elf;
|
pub mod elf;
|
||||||
|
mod file;
|
||||||
|
mod image;
|
||||||
|
mod reloc;
|
||||||
|
|
||||||
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Result<T, ()> {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
if data.len() < offset + mem::size_of::<T>() {
|
pub enum Arch {
|
||||||
Err(())
|
Arm,
|
||||||
} else {
|
OpenRisc,
|
||||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
|
||||||
Ok(unsafe { ptr::read_unaligned(ptr) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ref<T: Copy>(data: &[u8], offset: usize) -> Result<&T, ()> {
|
|
||||||
if data.len() < offset + mem::size_of::<T>() {
|
|
||||||
Err(())
|
|
||||||
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
|
||||||
Err(())
|
|
||||||
} else {
|
|
||||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
|
||||||
Ok(unsafe { &*ptr })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ref_slice<T: Copy>(data: &[u8], offset: usize, len: usize) -> Result<&[T], ()> {
|
|
||||||
if data.len() < offset + mem::size_of::<T>() * len {
|
|
||||||
Err(())
|
|
||||||
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
|
||||||
Err(())
|
|
||||||
} else {
|
|
||||||
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
|
|
||||||
Ok(unsafe { slice::from_raw_parts(ptr, len) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn elf_hash(name: &[u8]) -> u32 {
|
|
||||||
let mut h: u32 = 0;
|
|
||||||
for c in name {
|
|
||||||
h = (h << 4) + *c as u32;
|
|
||||||
let g = h & 0xf0000000;
|
|
||||||
if g != 0 {
|
|
||||||
h ^= g >> 24;
|
|
||||||
h &= !g;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error<'a> {
|
pub enum Error {
|
||||||
Parsing(&'static str),
|
Parsing(&'static str),
|
||||||
Lookup(&'a [u8])
|
Lookup(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> convert::From<&'static str> for Error<'a> {
|
impl convert::From<&'static str> for Error {
|
||||||
fn from(desc: &'static str) -> Error<'a> {
|
fn from(desc: &'static str) -> Error {
|
||||||
Error::Parsing(desc)
|
Error::Parsing(desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for Error<'a> {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
&Error::Parsing(desc) =>
|
&Error::Parsing(desc) =>
|
||||||
write!(f, "parse error: {}", desc),
|
write!(f, "parse error: {}", desc),
|
||||||
&Error::Lookup(sym) =>
|
&Error::Lookup(ref sym) =>
|
||||||
match str::from_utf8(sym) {
|
write!(f, "symbol lookup error: {}", sym),
|
||||||
Ok(sym) => write!(f, "symbol lookup error: {}", sym),
|
|
||||||
Err(_) => write!(f, "symbol lookup error: {:?}", sym)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Library<'a> {
|
pub fn load(
|
||||||
image_off: Elf32_Addr,
|
data: &[u8],
|
||||||
image_sz: usize,
|
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||||
strtab: &'a [u8],
|
) -> Result<image::Image, Error> {
|
||||||
symtab: &'a [Elf32_Sym],
|
// validate ELF file
|
||||||
pltrel: &'a [Elf32_Rela],
|
let file = file::File::new(data)
|
||||||
hash_bucket: &'a [Elf32_Word],
|
.ok_or("cannot read ELF header")?;
|
||||||
hash_chain: &'a [Elf32_Word],
|
if file.ehdr.e_type != ET_DYN {
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Library<'a> {
|
|
||||||
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
|
|
||||||
let hash = elf_hash(name);
|
|
||||||
let mut index = self.hash_bucket[hash as usize % self.hash_bucket.len()] as usize;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if index == STN_UNDEF { return None }
|
|
||||||
|
|
||||||
let sym = &self.symtab[index];
|
|
||||||
let sym_name_off = sym.st_name as usize;
|
|
||||||
match self.strtab.get(sym_name_off..sym_name_off + name.len()) {
|
|
||||||
Some(sym_name) if sym_name == name => {
|
|
||||||
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
match sym.st_shndx {
|
|
||||||
SHN_UNDEF => return None,
|
|
||||||
SHN_ABS => return Some(sym.st_value),
|
|
||||||
_ => return Some(self.image_off + sym.st_value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
index = self.hash_chain[index] as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name_starting_at(&self, offset: usize) -> Result<&'a [u8], Error<'a>> {
|
|
||||||
let size = self.strtab.iter().skip(offset).position(|&x| x == 0)
|
|
||||||
.ok_or("symbol in symbol table not null-terminated")?;
|
|
||||||
Ok(self.strtab.get(offset..offset + size)
|
|
||||||
.ok_or("cannot read symbol name")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_rela(&self, rela: &Elf32_Rela, value: Elf32_Word) -> Result<(), Error<'a>> {
|
|
||||||
if rela.r_offset as usize + mem::size_of::<Elf32_Addr>() > self.image_sz {
|
|
||||||
return Err("relocation out of image bounds")?
|
|
||||||
}
|
|
||||||
|
|
||||||
let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr;
|
|
||||||
Ok(unsafe { *ptr = value })
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is unsafe because it mutates global data (the PLT).
|
|
||||||
pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> {
|
|
||||||
for rela in self.pltrel.iter() {
|
|
||||||
match ELF32_R_TYPE(rela.r_info) {
|
|
||||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT |
|
|
||||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT => {
|
|
||||||
let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
|
||||||
.ok_or("symbol out of bounds of symbol table")?;
|
|
||||||
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
|
||||||
|
|
||||||
if sym_name == name {
|
|
||||||
self.update_rela(rela, addr)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No associated symbols for other relocation types.
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
|
||||||
-> Result<(), Error<'a>> {
|
|
||||||
let sym;
|
|
||||||
if ELF32_R_SYM(rela.r_info) == 0 {
|
|
||||||
sym = None;
|
|
||||||
} else {
|
|
||||||
sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
|
||||||
.ok_or("symbol out of bounds of symbol table")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
let value;
|
|
||||||
match ELF32_R_TYPE(rela.r_info) {
|
|
||||||
R_OR1K_NONE | R_ARM_NONE =>
|
|
||||||
return Ok(()),
|
|
||||||
|
|
||||||
R_OR1K_RELATIVE | R_ARM_RELATIVE =>
|
|
||||||
value = self.image_off + rela.r_addend as Elf32_Word,
|
|
||||||
|
|
||||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT |
|
|
||||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT => {
|
|
||||||
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
|
||||||
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
|
||||||
|
|
||||||
// First, try to resolve against itself.
|
|
||||||
match self.lookup(sym_name) {
|
|
||||||
Some(addr) => value = addr,
|
|
||||||
None => {
|
|
||||||
// Second, call the user-provided function.
|
|
||||||
match resolve(sym_name) {
|
|
||||||
Some(addr) => value = addr,
|
|
||||||
None => {
|
|
||||||
// We couldn't find it anywhere.
|
|
||||||
return Err(Error::Lookup(sym_name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ =>
|
|
||||||
return Err("unsupported relocation type")?,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update_rela(rela, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
|
||||||
-> Result<Library<'a>, Error<'a>> {
|
|
||||||
#![allow(unused_assignments)]
|
|
||||||
|
|
||||||
let ehdr = read_unaligned::<Elf32_Ehdr>(data, 0)
|
|
||||||
.map_err(|()| "cannot read ELF header")?;
|
|
||||||
|
|
||||||
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
|
||||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
|
||||||
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
|
||||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
|
||||||
];
|
|
||||||
const IDENT_ARM: [u8; EI_NIDENT] = [
|
|
||||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
|
||||||
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
|
||||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
|
||||||
];
|
|
||||||
|
|
||||||
if ehdr.e_type != ET_DYN {
|
|
||||||
return Err("not a shared library")?
|
return Err("not a shared library")?
|
||||||
}
|
}
|
||||||
|
let arch = file.arch()
|
||||||
|
.ok_or("not for a supported architecture")?;
|
||||||
|
|
||||||
if !((ehdr.e_ident == IDENT_OPENRISC && ehdr.e_machine == EM_OPENRISC)
|
// prepare target memory
|
||||||
|| ((ehdr.e_ident == IDENT_ARM && ehdr.e_machine == EM_ARM))) {
|
let image_size = file.program_headers()
|
||||||
return Err("not for a supported architecture")?
|
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0) as usize;
|
||||||
|
let image_align = file.program_headers()
|
||||||
|
.filter_map(|phdr| phdr.and_then(|phdr| {
|
||||||
|
if phdr.p_type == PT_LOAD {
|
||||||
|
Some(phdr.p_align)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(4) as usize;
|
||||||
|
// 1 image for all segments
|
||||||
|
let mut image = image::Image::new(image_size, image_align)
|
||||||
|
.map_err(|_| "cannot allocate target image")?;
|
||||||
|
info!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||||
|
|
||||||
let mut dyn_off = None;
|
// LOAD
|
||||||
for i in 0..ehdr.e_phnum {
|
for phdr in file.program_headers() {
|
||||||
let phdr_off = ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
let phdr = phdr.ok_or("cannot read program header")?;
|
||||||
let phdr = read_unaligned::<Elf32_Phdr>(data, phdr_off)
|
if phdr.p_type != PT_LOAD { continue; }
|
||||||
.map_err(|()| "cannot read program header")?;
|
|
||||||
|
|
||||||
match phdr.p_type {
|
trace!("Program header: {:08X}+{:08X} to {:08X}",
|
||||||
PT_LOAD => {
|
phdr.p_offset, phdr.p_filesz,
|
||||||
if (phdr.p_vaddr + phdr.p_filesz) as usize > image.len() {
|
image.ptr() as u32
|
||||||
return Err("program header requests an out of bounds load (in image)")?
|
);
|
||||||
}
|
let src = file.get(phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize)
|
||||||
if (phdr.p_offset + phdr.p_filesz) as usize > data.len() {
|
.ok_or("program header requests an out of bounds load (in file)")?;
|
||||||
return Err("program header requests an out of bounds load (in data)")?
|
|
||||||
}
|
|
||||||
let dst = image.get_mut(phdr.p_vaddr as usize..
|
let dst = image.get_mut(phdr.p_vaddr as usize..
|
||||||
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
.ok_or("cannot write to program header destination")?;
|
.ok_or("program header requests an out of bounds load (in target)")?;
|
||||||
let src = data.get(phdr.p_offset as usize..
|
|
||||||
(phdr.p_offset + phdr.p_filesz) as usize)
|
|
||||||
.ok_or("cannot read from program header source")?;
|
|
||||||
dst.copy_from_slice(src);
|
dst.copy_from_slice(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
PT_DYNAMIC =>
|
// relocate DYNAMIC
|
||||||
dyn_off = Some(phdr.p_vaddr),
|
let dyn_range = file.dynamic_header_vaddr()
|
||||||
|
.ok_or("cannot find a dynamic header")?;
|
||||||
|
let dynamic_section = image.dynamic_section(dyn_range)?;
|
||||||
|
info!("Relocating {} rela, {} rel, {} pltrel",
|
||||||
|
dynamic_section.rela.len(), dynamic_section.rel.len(), dynamic_section.pltrel.len());
|
||||||
|
|
||||||
_ => ()
|
for rela in dynamic_section.rela {
|
||||||
|
reloc::relocate(arch, &image, &dynamic_section, rela, resolve)?;
|
||||||
}
|
}
|
||||||
|
for rel in dynamic_section.rela {
|
||||||
|
reloc::relocate(arch, &image, &dynamic_section, rel, resolve)?;
|
||||||
|
}
|
||||||
|
for pltrel in dynamic_section.pltrel {
|
||||||
|
reloc::relocate(arch, &image, &dynamic_section, pltrel, resolve)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
Ok(image)
|
||||||
let (mut symtab_off, mut symtab_sz) = (0, 0);
|
|
||||||
let (mut rela_off, mut rela_sz) = (0, 0);
|
|
||||||
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
|
||||||
let (mut hash_off, mut hash_sz) = (0, 0);
|
|
||||||
let mut sym_ent = 0;
|
|
||||||
let mut rela_ent = 0;
|
|
||||||
let mut nbucket = 0;
|
|
||||||
let mut nchain = 0;
|
|
||||||
|
|
||||||
let dyn_off = dyn_off.ok_or("cannot find a dynamic header")?;
|
|
||||||
for i in 0.. {
|
|
||||||
let dyn_off = dyn_off as usize + i * mem::size_of::<Elf32_Dyn>();
|
|
||||||
let dyn = get_ref::<Elf32_Dyn>(image, dyn_off)
|
|
||||||
.map_err(|()| "cannot read dynamic header")?;
|
|
||||||
|
|
||||||
let val = unsafe { dyn.d_un.d_val } as usize;
|
|
||||||
match dyn.d_tag {
|
|
||||||
DT_NULL => break,
|
|
||||||
DT_REL => return Err("relocations with implicit addend are not supported")?,
|
|
||||||
DT_STRTAB => strtab_off = val,
|
|
||||||
DT_STRSZ => strtab_sz = val,
|
|
||||||
DT_SYMTAB => symtab_off = val,
|
|
||||||
DT_SYMENT => sym_ent = val,
|
|
||||||
DT_RELA => rela_off = val,
|
|
||||||
DT_RELASZ => rela_sz = val / mem::size_of::<Elf32_Rela>(),
|
|
||||||
DT_RELAENT => rela_ent = val,
|
|
||||||
DT_JMPREL => pltrel_off = val,
|
|
||||||
DT_PLTRELSZ => pltrel_sz = val / mem::size_of::<Elf32_Rela>(),
|
|
||||||
DT_HASH => {
|
|
||||||
nbucket = *get_ref::<Elf32_Word>(image, val + 0)
|
|
||||||
.map_err(|()| "cannot read hash bucket count")? as usize;
|
|
||||||
nchain = *get_ref::<Elf32_Word>(image, val + 4)
|
|
||||||
.map_err(|()| "cannot read hash chain count")? as usize;
|
|
||||||
hash_off = val + 8;
|
|
||||||
hash_sz = nbucket + nchain;
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sym_ent != mem::size_of::<Elf32_Sym>() {
|
|
||||||
return Err("incorrect symbol entry size")?
|
|
||||||
}
|
|
||||||
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
|
|
||||||
return Err("incorrect relocation entry size")?
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are the same--there are as many chains as buckets, and the chains only contain
|
|
||||||
// the symbols that overflowed the bucket.
|
|
||||||
symtab_sz = nchain;
|
|
||||||
|
|
||||||
// Drop the mutability. See also the comment below.
|
|
||||||
let image = &*image;
|
|
||||||
|
|
||||||
let strtab = get_ref_slice::<u8>(image, strtab_off, strtab_sz)
|
|
||||||
.map_err(|()| "cannot read string table")?;
|
|
||||||
let symtab = get_ref_slice::<Elf32_Sym>(image, symtab_off, symtab_sz)
|
|
||||||
.map_err(|()| "cannot read symbol table")?;
|
|
||||||
let rela = get_ref_slice::<Elf32_Rela>(image, rela_off, rela_sz)
|
|
||||||
.map_err(|()| "cannot read rela entries")?;
|
|
||||||
let pltrel = get_ref_slice::<Elf32_Rela>(image, pltrel_off, pltrel_sz)
|
|
||||||
.map_err(|()| "cannot read pltrel entries")?;
|
|
||||||
let hash = get_ref_slice::<Elf32_Word>(image, hash_off, hash_sz)
|
|
||||||
.map_err(|()| "cannot read hash entries")?;
|
|
||||||
|
|
||||||
let library = Library {
|
|
||||||
image_off: image.as_ptr() as Elf32_Word,
|
|
||||||
image_sz: image.len(),
|
|
||||||
strtab: strtab,
|
|
||||||
symtab: symtab,
|
|
||||||
pltrel: pltrel,
|
|
||||||
hash_bucket: &hash[..nbucket],
|
|
||||||
hash_chain: &hash[nbucket..nbucket + nchain],
|
|
||||||
};
|
|
||||||
|
|
||||||
// If a borrow exists anywhere, the borrowed memory cannot be mutated except
|
|
||||||
// through that pointer or it's UB. However, we need to retain pointers
|
|
||||||
// to the symbol tables and relocations, and at the same time mutate the code
|
|
||||||
// to resolve the relocations.
|
|
||||||
//
|
|
||||||
// To avoid invoking UB, we drop the only pointer to the entire area (which is
|
|
||||||
// unique since it's a &mut); we retain pointers to the various tables, but
|
|
||||||
// we never write to the memory they refer to, so it's safe.
|
|
||||||
mem::drop(image);
|
|
||||||
|
|
||||||
for r in rela { library.resolve_rela(r, resolve)? }
|
|
||||||
for r in pltrel { library.resolve_rela(r, resolve)? }
|
|
||||||
|
|
||||||
Ok(library)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
use alloc::string::String;
|
||||||
|
use log::{debug, trace};
|
||||||
|
use super::{
|
||||||
|
Arch,
|
||||||
|
elf::*,
|
||||||
|
Error,
|
||||||
|
image::{DynamicSection, Image},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Relocatable {
|
||||||
|
fn offset(&self) -> usize;
|
||||||
|
fn type_info(&self) -> u8;
|
||||||
|
fn sym_info(&self) -> u32;
|
||||||
|
fn addend(&self, image: &Image) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Relocatable for Elf32_Rel {
|
||||||
|
fn offset(&self) -> usize {
|
||||||
|
self.r_offset as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_info(&self) -> u8 {
|
||||||
|
ELF32_R_TYPE(self.r_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sym_info(&self) -> u32 {
|
||||||
|
ELF32_R_SYM(self.r_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addend(&self, image: &Image) -> i32 {
|
||||||
|
*image.get_ref(self.offset()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Relocatable for Elf32_Rela {
|
||||||
|
fn offset(&self) -> usize {
|
||||||
|
self.r_offset as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_info(&self) -> u8 {
|
||||||
|
ELF32_R_TYPE(self.r_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sym_info(&self) -> u32 {
|
||||||
|
ELF32_R_SYM(self.r_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addend(&self, _: &Image) -> i32 {
|
||||||
|
self.r_addend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum RelType {
|
||||||
|
None,
|
||||||
|
Relative,
|
||||||
|
Lookup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelType {
|
||||||
|
pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
|
||||||
|
match type_info {
|
||||||
|
R_OR1K_NONE if arch == Arch::OpenRisc =>
|
||||||
|
Some(RelType::None),
|
||||||
|
R_ARM_NONE if arch == Arch::Arm =>
|
||||||
|
Some(RelType::None),
|
||||||
|
|
||||||
|
R_OR1K_RELATIVE if arch == Arch::OpenRisc =>
|
||||||
|
Some(RelType::Relative),
|
||||||
|
R_ARM_RELATIVE if arch == Arch::Arm =>
|
||||||
|
Some(RelType::Relative),
|
||||||
|
|
||||||
|
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT
|
||||||
|
if arch == Arch::OpenRisc => Some(RelType::Lookup),
|
||||||
|
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT
|
||||||
|
if arch == Arch::Arm => Some(RelType::Lookup),
|
||||||
|
|
||||||
|
_ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_sym_name(sym_name: &[u8]) -> String {
|
||||||
|
core::str::from_utf8(sym_name)
|
||||||
|
.map(String::from)
|
||||||
|
.unwrap_or(String::from("<invalid symbol name>"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn relocate<'a, R: Relocatable>(
|
||||||
|
arch: Arch, image: &'a Image, dynamic_section: &'a DynamicSection<'a>,
|
||||||
|
rel: &'a R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// debug!("rel r_offset={:08X} r_info={:08X} r_addend={:08X}", rel.offset(), rel.r_info, rela.r_addend);
|
||||||
|
let sym;
|
||||||
|
if rel.sym_info() == 0 {
|
||||||
|
sym = None;
|
||||||
|
} else {
|
||||||
|
sym = Some(dynamic_section.symtab.get(rel.sym_info() as usize)
|
||||||
|
.ok_or("symbol out of bounds of symbol table")?)
|
||||||
|
}
|
||||||
|
|
||||||
|
let rel_type = RelType::new(arch, rel.type_info())
|
||||||
|
.ok_or("unsupported relocation type")?;
|
||||||
|
let value;
|
||||||
|
match rel_type {
|
||||||
|
RelType::None =>
|
||||||
|
return Ok(()),
|
||||||
|
|
||||||
|
RelType::Relative => {
|
||||||
|
let addend = rel.addend(image);
|
||||||
|
value = image.ptr().wrapping_offset(addend as isize) as Elf32_Word;
|
||||||
|
}
|
||||||
|
|
||||||
|
RelType::Lookup => {
|
||||||
|
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
||||||
|
let sym_name = dynamic_section.name_starting_at(sym.st_name as usize)?;
|
||||||
|
|
||||||
|
if let Some(addr) = dynamic_section.lookup(sym_name) {
|
||||||
|
// First, try to resolve against itself.
|
||||||
|
trace!("looked up symbol {} in image", format_sym_name(sym_name));
|
||||||
|
value = image.ptr() as u32 + addr;
|
||||||
|
} else if let Some(addr) = resolve(sym_name) {
|
||||||
|
// Second, call the user-provided function.
|
||||||
|
trace!("resolved symbol {:?}", format_sym_name(sym_name));
|
||||||
|
value = addr;
|
||||||
|
} else {
|
||||||
|
// We couldn't find it anywhere.
|
||||||
|
return Err(Error::Lookup(format_sym_name(sym_name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("rel_type={:?} write at {:08X} value {:08X}", rel_type, rel.offset(), value);
|
||||||
|
image.write(rel.offset(), value)
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ default = ["target_zc706"]
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
cslice = "0.3"
|
cslice = "0.3"
|
||||||
|
log = "0.4"
|
||||||
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" }
|
||||||
|
|
|
@ -16,6 +16,7 @@ use libboard_zynq::{
|
||||||
iface::{NeighborCache, EthernetInterfaceBuilder, Routes},
|
iface::{NeighborCache, EthernetInterfaceBuilder, Routes},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
},
|
},
|
||||||
|
timer::GlobalTimer,
|
||||||
};
|
};
|
||||||
use libsupport_zynq::alloc::{vec, vec::Vec};
|
use libsupport_zynq::alloc::{vec, vec::Vec};
|
||||||
use libasync::{smoltcp::{Sockets, TcpStream}, task};
|
use libasync::{smoltcp::{Sockets, TcpStream}, task};
|
||||||
|
@ -205,7 +206,7 @@ async fn handle_connection(stream: &TcpStream, control: Rc<RefCell<kernel::Contr
|
||||||
const HWADDR: [u8; 6] = [0, 0x23, 0xab, 0xad, 0x1d, 0xea];
|
const HWADDR: [u8; 6] = [0, 0x23, 0xab, 0xad, 0x1d, 0xea];
|
||||||
const IPADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 52]));
|
const IPADDR: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 52]));
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main(timer: GlobalTimer) {
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
const RX_LEN: usize = 8;
|
const RX_LEN: usize = 8;
|
||||||
let mut rx_descs = (0..RX_LEN)
|
let mut rx_descs = (0..RX_LEN)
|
||||||
|
@ -257,9 +258,7 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut time = 0u32;
|
|
||||||
Sockets::run(&mut iface, || {
|
Sockets::run(&mut iface, || {
|
||||||
time += 1;
|
Instant::from_millis(timer.get_time().0 as i32)
|
||||||
Instant::from_millis(time)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,12 +84,15 @@ fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
api!(rtio_input_timestamp = rtio::input_timestamp),
|
api!(rtio_input_timestamp = rtio::input_timestamp),
|
||||||
api!(rtio_input_data = rtio::input_data),
|
api!(rtio_input_data = rtio::input_data),
|
||||||
api!(rtio_input_timestamped_data = rtio::input_timestamped_data),
|
api!(rtio_input_timestamped_data = rtio::input_timestamped_data),
|
||||||
|
api!(__artiq_personality = __artiq_personality),
|
||||||
];
|
];
|
||||||
api.iter()
|
api.iter()
|
||||||
.find(|&&(exported, _)| exported.as_bytes() == required)
|
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||||
.map(|&(_, ptr)| ptr as u32)
|
.map(|&(_, ptr)| ptr as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn __artiq_personality() {
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core1() {
|
pub fn main_core1() {
|
||||||
|
@ -107,12 +110,12 @@ pub fn main_core1() {
|
||||||
}
|
}
|
||||||
let core1_rx = core1_rx.unwrap();
|
let core1_rx = core1_rx.unwrap();
|
||||||
|
|
||||||
let mut image = vec![0; 1024*1024];
|
|
||||||
for message in core1_rx {
|
for message in core1_rx {
|
||||||
match *message {
|
match *message {
|
||||||
Message::LoadRequest(data) => {
|
Message::LoadRequest(data) => {
|
||||||
match dyld::Library::load(&data, &mut image, &resolve) {
|
match dyld::load(&data, &resolve) {
|
||||||
Ok(library) => {
|
Ok(image) => {
|
||||||
|
println!("image loaded");
|
||||||
core1_tx.send(Message::LoadCompleted)
|
core1_tx.send(Message::LoadCompleted)
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|
|
@ -2,14 +2,16 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
|
|
||||||
use libboard_zynq::{
|
use libboard_zynq::{
|
||||||
println,
|
println,
|
||||||
self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll},
|
self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll},
|
||||||
|
timer::GlobalTimer,
|
||||||
};
|
};
|
||||||
use libsupport_zynq::ram;
|
use libsupport_zynq::{logger, ram};
|
||||||
|
|
||||||
mod comms;
|
mod comms;
|
||||||
mod pl;
|
mod pl;
|
||||||
|
@ -33,6 +35,8 @@ fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
println!("ARTIQ runtime starting...");
|
println!("ARTIQ runtime starting...");
|
||||||
|
let _ = logger::init();
|
||||||
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
|
||||||
const CPU_FREQ: u32 = 800_000_000;
|
const CPU_FREQ: u32 = 800_000_000;
|
||||||
|
|
||||||
|
@ -42,8 +46,9 @@ pub fn main_core0() {
|
||||||
libboard_zynq::stdio::drop_uart(); // reinitialize UART after clocking change
|
libboard_zynq::stdio::drop_uart(); // reinitialize UART after clocking change
|
||||||
let mut ddr = zynq::ddr::DdrRam::new();
|
let mut ddr = zynq::ddr::DdrRam::new();
|
||||||
ram::init_alloc(&mut ddr);
|
ram::init_alloc(&mut ddr);
|
||||||
|
let timer = GlobalTimer::start();
|
||||||
|
|
||||||
println!("Detected gateware: {}", identifier_read(&mut [0; 64]));
|
println!("Detected gateware: {}", identifier_read(&mut [0; 64]));
|
||||||
|
|
||||||
comms::main();
|
comms::main(timer);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue