mirror of https://github.com/m-labs/artiq.git
firmware: rewrite the dynamic linker in Rust.
This commit is contained in:
parent
907589fb58
commit
04ad267055
|
@ -62,6 +62,10 @@ dependencies = [
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyld"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fringe"
|
name = "fringe"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -93,6 +97,7 @@ dependencies = [
|
||||||
"build_artiq 0.0.0",
|
"build_artiq 0.0.0",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dyld 0.0.0",
|
||||||
"std_artiq 0.0.0",
|
"std_artiq 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -136,6 +141,7 @@ dependencies = [
|
||||||
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"drtioaux 0.0.0",
|
"drtioaux 0.0.0",
|
||||||
|
"dyld 0.0.0",
|
||||||
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"logger_artiq 0.0.0",
|
"logger_artiq 0.0.0",
|
||||||
|
|
|
@ -16,5 +16,6 @@ build_artiq = { path = "../libbuild_artiq" }
|
||||||
alloc_none = { path = "../liballoc_none" }
|
alloc_none = { path = "../liballoc_none" }
|
||||||
std_artiq = { path = "../libstd_artiq" }
|
std_artiq = { path = "../libstd_artiq" }
|
||||||
board = { path = "../libboard" }
|
board = { path = "../libboard" }
|
||||||
|
dyld = { path = "../libdyld" }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
cslice = { version = "0.3" }
|
cslice = { version = "0.3" }
|
||||||
|
|
|
@ -11,8 +11,7 @@ LDFLAGS += --eh-frame-hdr \
|
||||||
-L../libcompiler-rt \
|
-L../libcompiler-rt \
|
||||||
-L../libbase \
|
-L../libbase \
|
||||||
-L../libm \
|
-L../libm \
|
||||||
-L../libunwind \
|
-L../libunwind
|
||||||
-L../libdyld
|
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=unwind
|
RUSTFLAGS += -Cpanic=unwind
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ $(RUSTOUT)/libksupport.a:
|
||||||
|
|
||||||
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
||||||
$(LD) $(LDFLAGS) -T $(KSUPPORT_DIRECTORY)/ksupport.ld -o $@ $^ \
|
$(LD) $(LDFLAGS) -T $(KSUPPORT_DIRECTORY)/ksupport.ld -o $@ $^ \
|
||||||
-lbase -lm -lcompiler-rt -ldyld -lunwind
|
-lbase -lm -lcompiler-rt -lunwind
|
||||||
@chmod -x $@
|
@chmod -x $@
|
||||||
|
|
||||||
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
||||||
|
|
|
@ -12,12 +12,11 @@ macro_rules! api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(required: &str) -> usize {
|
pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||||
unsafe {
|
unsafe {
|
||||||
API.iter()
|
API.iter()
|
||||||
.find(|&&(exported, _)| exported == required)
|
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||||
.map(|&(_, ptr)| ptr as usize)
|
.map(|&(_, ptr)| ptr as u32)
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
use core::{ptr, slice, str};
|
|
||||||
use libc::{c_void, c_char, c_int, size_t};
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Default)]
|
|
||||||
struct dyld_info {
|
|
||||||
__opaque: [usize; 7]
|
|
||||||
}
|
|
||||||
|
|
||||||
extern {
|
|
||||||
fn dyld_load(shlib: *const c_void, base: usize,
|
|
||||||
resolve: extern fn(*mut c_void, *const c_char) -> usize,
|
|
||||||
resolve_data: *mut c_void,
|
|
||||||
info: *mut dyld_info, error_out: *mut *const c_char) -> c_int;
|
|
||||||
fn dyld_lookup(symbol: *const c_char, info: *const dyld_info) -> *const c_void;
|
|
||||||
|
|
||||||
fn strlen(ptr: *const c_char) -> size_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Library {
|
|
||||||
lower: dyld_info
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Library {
|
|
||||||
pub unsafe fn load<F>(shlib: &[u8], base: usize, mut resolve: F)
|
|
||||||
-> Result<Library, &'static str>
|
|
||||||
where F: Fn(&str) -> usize {
|
|
||||||
extern fn wrapper<F>(data: *mut c_void, name: *const c_char) -> usize
|
|
||||||
where F: Fn(&str) -> usize {
|
|
||||||
unsafe {
|
|
||||||
let f = data as *mut F;
|
|
||||||
let name = slice::from_raw_parts(name as *const u8, strlen(name));
|
|
||||||
(*f)(str::from_utf8_unchecked(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut library = Library { lower: dyld_info::default() };
|
|
||||||
let mut error: *const c_char = ptr::null();
|
|
||||||
if dyld_load(shlib.as_ptr() as *const _, base,
|
|
||||||
wrapper::<F>, &mut resolve as *mut _ as *mut _,
|
|
||||||
&mut library.lower, &mut error) == 0 {
|
|
||||||
let error = slice::from_raw_parts(error as *const u8, strlen(error));
|
|
||||||
Err(str::from_utf8_unchecked(error))
|
|
||||||
} else {
|
|
||||||
Ok(library)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn lookup(&self, symbol: &str) -> usize {
|
|
||||||
assert!(symbol.len() < 32);
|
|
||||||
let mut buf = [0u8; 32];
|
|
||||||
buf[0..symbol.as_bytes().len()].copy_from_slice(symbol.as_bytes());
|
|
||||||
dyld_lookup(&buf as *const _ as *const c_char, &self.lower) as usize
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,6 +9,7 @@ extern crate libc;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate board;
|
extern crate board;
|
||||||
extern crate cslice;
|
extern crate cslice;
|
||||||
|
extern crate dyld;
|
||||||
|
|
||||||
#[path = "../runtime/mailbox.rs"]
|
#[path = "../runtime/mailbox.rs"]
|
||||||
mod mailbox;
|
mod mailbox;
|
||||||
|
@ -20,10 +21,9 @@ mod kernel_proto;
|
||||||
#[path = "../runtime/rpc_proto.rs"]
|
#[path = "../runtime/rpc_proto.rs"]
|
||||||
mod rpc_proto;
|
mod rpc_proto;
|
||||||
|
|
||||||
mod dyld;
|
|
||||||
mod api;
|
mod api;
|
||||||
|
|
||||||
use core::{mem, ptr, str};
|
use core::{mem, ptr, slice, str};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use cslice::{CSlice, AsCSlice};
|
use cslice::{CSlice, AsCSlice};
|
||||||
use kernel_proto::*;
|
use kernel_proto::*;
|
||||||
|
@ -294,8 +294,12 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn main() {
|
pub unsafe fn main() {
|
||||||
|
let image = slice::from_raw_parts_mut(kernel_proto::KERNELCPU_PAYLOAD_ADDRESS as *mut u8,
|
||||||
|
kernel_proto::KERNELCPU_LAST_ADDRESS -
|
||||||
|
kernel_proto::KERNELCPU_PAYLOAD_ADDRESS);
|
||||||
|
|
||||||
let library = recv!(&LoadRequest(library) => {
|
let library = recv!(&LoadRequest(library) => {
|
||||||
match Library::load(library, kernel_proto::KERNELCPU_PAYLOAD_ADDRESS, api::resolve) {
|
match Library::load(library, image, &api::resolve) {
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
send(&LoadReply(Err(error)));
|
send(&LoadReply(Err(error)));
|
||||||
loop {}
|
loop {}
|
||||||
|
@ -307,16 +311,16 @@ pub unsafe fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let __bss_start = library.lookup("__bss_start");
|
let __bss_start = library.lookup(b"__bss_start").unwrap();
|
||||||
let _end = library.lookup("_end");
|
let _end = library.lookup(b"_end").unwrap();
|
||||||
ptr::write_bytes(__bss_start as *mut u8, 0, _end - __bss_start);
|
ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize);
|
||||||
|
|
||||||
send(&NowInitRequest);
|
send(&NowInitRequest);
|
||||||
recv!(&NowInitReply(now) => NOW = now);
|
recv!(&NowInitReply(now) => NOW = now);
|
||||||
(mem::transmute::<usize, fn()>(library.lookup("__modinit__")))();
|
(mem::transmute::<u32, fn()>(library.lookup(b"__modinit__").unwrap()))();
|
||||||
send(&NowSave(NOW));
|
send(&NowSave(NOW));
|
||||||
|
|
||||||
attribute_writeback(library.lookup("typeinfo") as *const ());
|
attribute_writeback(library.lookup(b"typeinfo").unwrap_or(0) as *const ());
|
||||||
|
|
||||||
send(&RunFinished);
|
send(&RunFinished);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
name = "dyld"
|
||||||
|
version = "0.0.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "dyld"
|
||||||
|
path = "lib.rs"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,313 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(untagged_unions, ptr_unaligned)]
|
||||||
|
|
||||||
|
use core::{mem, ptr, fmt, slice, str, convert};
|
||||||
|
use elf::*;
|
||||||
|
|
||||||
|
pub mod elf;
|
||||||
|
|
||||||
|
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Result<T, ()> {
|
||||||
|
if data.len() < offset + mem::size_of::<T>() {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
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)]
|
||||||
|
pub enum Error<'a> {
|
||||||
|
Parsing(&'static str),
|
||||||
|
Lookup(&'a [u8])
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> convert::From<&'static str> for Error<'a> {
|
||||||
|
fn from(desc: &'static str) -> Error<'a> {
|
||||||
|
Error::Parsing(desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for Error<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&Error::Parsing(desc) =>
|
||||||
|
write!(f, "parse error: {}", desc),
|
||||||
|
&Error::Lookup(sym) =>
|
||||||
|
match str::from_utf8(sym) {
|
||||||
|
Ok(sym) => write!(f, "symbol lookup error: {}", sym),
|
||||||
|
Err(_) => write!(f, "symbol lookup error: {:?}", sym)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Library<'a> {
|
||||||
|
image_off: Elf32_Addr,
|
||||||
|
image_sz: usize,
|
||||||
|
strtab: &'a [u8],
|
||||||
|
symtab: &'a [Elf32_Sym],
|
||||||
|
hash_bucket: &'a [Elf32_Word],
|
||||||
|
hash_chain: &'a [Elf32_Word],
|
||||||
|
}
|
||||||
|
|
||||||
|
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 fixup_rela(&self, rela: &Elf32_Rela, resolve: &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 =>
|
||||||
|
return Ok(()),
|
||||||
|
|
||||||
|
R_OR1K_RELATIVE =>
|
||||||
|
value = self.image_off + rela.r_addend as Elf32_Word,
|
||||||
|
|
||||||
|
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => {
|
||||||
|
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
||||||
|
|
||||||
|
let sym_name_off = sym.st_name as usize;
|
||||||
|
let sym_name_end =
|
||||||
|
self.strtab.iter().skip(sym_name_off).position(|&x| x == 0)
|
||||||
|
.ok_or("symbol in symbol table not null-terminated")?;
|
||||||
|
let sym_name =
|
||||||
|
self.strtab.get(sym_name_off..sym_name_off + sym_name_end)
|
||||||
|
.ok_or("cannot read symbol name")?;
|
||||||
|
|
||||||
|
// 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")?
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
unsafe { *ptr = value }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &Fn(&[u8]) -> Option<Elf32_Word>)
|
||||||
|
-> Result<Library<'a>, Error<'a>> {
|
||||||
|
let ehdr = read_unaligned::<Elf32_Ehdr>(data, 0)
|
||||||
|
.map_err(|()| "cannot read ELF header")?;
|
||||||
|
|
||||||
|
const IDENT: [u8; EI_NIDENT] = [
|
||||||
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
|
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
|
];
|
||||||
|
|
||||||
|
#[cfg(target_arch = "or1k")]
|
||||||
|
const ARCH: u16 = EM_OPENRISC;
|
||||||
|
#[cfg(not(target_arch = "or1k"))]
|
||||||
|
const ARCH: u16 = EM_NONE;
|
||||||
|
|
||||||
|
if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH {
|
||||||
|
return Err("not a shared library for current architecture")?
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dyn_off = None;
|
||||||
|
for i in 0..ehdr.e_phnum {
|
||||||
|
let phdr_off = ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
||||||
|
let phdr = read_unaligned::<Elf32_Phdr>(data, phdr_off)
|
||||||
|
.map_err(|()| "cannot read program header")?;
|
||||||
|
|
||||||
|
match phdr.p_type {
|
||||||
|
PT_LOAD => {
|
||||||
|
if (phdr.p_vaddr + phdr.p_filesz) as usize > image.len() ||
|
||||||
|
(phdr.p_offset + phdr.p_filesz) as usize > data.len() {
|
||||||
|
return Err("program header requests an out of bounds load")?
|
||||||
|
}
|
||||||
|
let dst = image.get_mut(phdr.p_vaddr as usize..
|
||||||
|
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||||
|
.ok_or("cannot write to program header destination")?;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
PT_DYNAMIC =>
|
||||||
|
dyn_off = Some(phdr.p_vaddr),
|
||||||
|
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
||||||
|
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 != 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,
|
||||||
|
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.fixup_rela(r, resolve)? }
|
||||||
|
for r in pltrel { library.fixup_rela(r, resolve)? }
|
||||||
|
|
||||||
|
Ok(library)
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ logger_artiq = { path = "../liblogger_artiq" }
|
||||||
cslice = { version = "0.3" }
|
cslice = { version = "0.3" }
|
||||||
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
|
||||||
board = { path = "../libboard", features = ["uart_console"] }
|
board = { path = "../libboard", features = ["uart_console"] }
|
||||||
|
dyld = { path = "../libdyld" }
|
||||||
drtioaux = { path = "../libdrtioaux" }
|
drtioaux = { path = "../libdrtioaux" }
|
||||||
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use dyld;
|
||||||
|
|
||||||
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
|
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
|
||||||
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000;
|
pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000;
|
||||||
|
@ -22,7 +23,7 @@ pub struct Exception<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Message<'a> {
|
pub enum Message<'a> {
|
||||||
LoadRequest(&'a [u8]),
|
LoadRequest(&'a [u8]),
|
||||||
LoadReply(Result<(), &'a str>),
|
LoadReply(Result<(), dyld::Error<'a>>),
|
||||||
|
|
||||||
NowInitRequest,
|
NowInitRequest,
|
||||||
NowInitReply(u64),
|
NowInitReply(u64),
|
||||||
|
|
|
@ -16,6 +16,7 @@ extern crate smoltcp;
|
||||||
extern crate board;
|
extern crate board;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
extern crate drtioaux;
|
extern crate drtioaux;
|
||||||
|
extern crate dyld;
|
||||||
|
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use smoltcp::wire::{EthernetAddress, IpAddress};
|
use smoltcp::wire::{EthernetAddress, IpAddress};
|
||||||
|
|
|
@ -179,7 +179,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul
|
||||||
session.kernel_state = KernelState::Loaded;
|
session.kernel_state = KernelState::Loaded;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
&kern::LoadReply(Err(error)) => {
|
&kern::LoadReply(Err(ref error)) => {
|
||||||
kernel::stop();
|
kernel::stop();
|
||||||
Err(io::Error::new(io::ErrorKind::Other,
|
Err(io::Error::new(io::ErrorKind::Other,
|
||||||
format!("cannot load kernel: {}", error)))
|
format!("cannot load kernel: {}", error)))
|
||||||
|
|
Loading…
Reference in New Issue