missing symbol filling

This commit is contained in:
2024-10-12 18:24:15 -04:00
parent cf9f3469ae
commit 77735953a5
6 changed files with 171 additions and 124 deletions

View File

@@ -1,3 +1,5 @@
use super::program::Addr;
#[repr(C)] #[repr(C)]
pub struct ELF64Header { pub struct ELF64Header {
magic: u32, magic: u32,
@@ -49,7 +51,7 @@ pub struct SectionHeader {
} }
// this is currently specialized for riscv64; obviously add params later // this is currently specialized for riscv64; obviously add params later
pub fn create(program: Vec<u8>, start_offset: u64) -> Vec<u8> { pub fn create(program: Vec<u8>, start_offset: Addr) -> Vec<u8> {
let addr_start = 0x1000; let addr_start = 0x1000;
let page_size = 0x1000; let page_size = 0x1000;
let progam_size = std::mem::size_of_val(&program[..]) as u64; let progam_size = std::mem::size_of_val(&program[..]) as u64;
@@ -76,7 +78,7 @@ pub fn create(program: Vec<u8>, start_offset: u64) -> Vec<u8> {
ty: 0x2, // executable ty: 0x2, // executable
machine: 0xf3, // risc-v machine: 0xf3, // risc-v
e_version: 0x1, e_version: 0x1,
entry: addr_start + program_pos + start_offset, entry: addr_start + program_pos + start_offset.val(),
program_header_offset: size_of::<ELF64Header>() as u64, program_header_offset: size_of::<ELF64Header>() as u64,
section_header_offset: 0x0, section_header_offset: 0x0,
// C ABI (16 bit instruction align) + double precision floats // C ABI (16 bit instruction align) + double precision floats

View File

@@ -10,6 +10,8 @@ mod program;
mod riscv64; mod riscv64;
mod target; mod target;
use program::*;
pub fn main() { pub fn main() {
use std::io::prelude::*; use std::io::prelude::*;
let dir = Path::new("./build"); let dir = Path::new("./build");
@@ -62,7 +64,3 @@ pub fn main() {
} }
} }
// qemu-riscv64 -g 1234 test &
// riscv64-linux-gnu-gdb -q \
// -ex "target remote :1234" \
// test

View File

@@ -1,35 +1,118 @@
use std::collections::HashMap; use std::{collections::HashMap, ops::Deref};
pub fn create_program<I: Instr>( pub fn create_program<I: Instr>(map: SymMap<I>, start: Symbol) -> (Vec<u8>, Option<Addr>) {
ro_data: HashMap<String, Vec<u8>>,
functions: Vec<Function<I>>,
) -> (Vec<u8>, Option<u64>) {
let mut data = Vec::new(); let mut data = Vec::new();
let mut sym_map = HashMap::new(); let mut sym_table = SymTable::new(map.len());
for (key, val) in ro_data { let mut missing = HashMap::<Symbol, Vec<(Addr, I)>>::new();
sym_map.insert(key, data.len() as u64); for (val, id) in map.ro_data {
sym_table.insert(id, Addr(data.len() as u64));
data.extend(val); data.extend(val);
} }
let mut start = None; for (fun, id) in map.functions {
for fun in functions { sym_table.insert(id, Addr(data.len() as u64));
if fun.label == "_start" { for i in fun {
start = Some(data.len() as u64); let i_pos = Addr(data.len() as u64);
} if let Some(sym) = i.push(&mut data, &sym_table, i_pos, false) {
sym_map.insert(fun.label, data.len() as u64); if let Some(vec) = missing.get_mut(&sym) {
for i in fun.instructions { vec.push((i_pos, i));
let pos = data.len() as u64; } else {
i.push(&mut data, &sym_map, pos); missing.insert(sym, vec![(i_pos, i)]);
} }
} }
(data, start) }
} if let Some(vec) = missing.remove(&id) {
for (addr, i) in vec {
pub struct Function<I: Instr> { let mut replace = Vec::new();
pub label: String, i.push(&mut replace, &sym_table, addr, true);
pub instructions: Vec<I>, let pos = addr.val() as usize;
data[pos..pos + replace.len()].copy_from_slice(&replace);
}
}
}
assert!(missing.is_empty());
(data, sym_table.get(start))
} }
pub trait Instr { pub trait Instr {
fn push(&self, data: &mut Vec<u8>, ro_map: &HashMap<String, u64>, pos: u64) -> Option<String>; fn push(&self, data: &mut Vec<u8>, syms: &SymTable, pos: Addr, missing: bool) -> Option<Symbol>;
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Addr(u64);
impl Addr {
const NONE: Self = Self(!0);
pub fn val(&self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Symbol(usize);
/// intentionally does not have copy or clone;
/// this should only be consumed once
pub struct WritableSymbol(Symbol);
impl Deref for WritableSymbol {
type Target = Symbol;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct SymMap<I: Instr> {
i: usize,
ro_data: Vec<(Vec<u8>, Symbol)>,
functions: Vec<(Vec<I>, Symbol)>,
}
impl<I: Instr> SymMap<I> {
pub fn new() -> Self {
Self {
i: 0,
ro_data: Vec::new(),
functions: Vec::new(),
}
}
pub fn push_ro_data(&mut self, data: impl Into<Vec<u8>>) -> (Symbol, usize) {
let sym = self.reserve();
self.write_ro_data(sym, data)
}
pub fn push_fn(&mut self, instructions: Vec<I>) -> Symbol {
let sym = self.reserve();
self.write_fn(sym, instructions)
}
pub fn write_ro_data(&mut self, sym: WritableSymbol, data: impl Into<Vec<u8>>) -> (Symbol, usize) {
let data = data.into();
let len = data.len();
self.ro_data.push((data, *sym));
(*sym, len)
}
pub fn write_fn(&mut self, sym: WritableSymbol, instructions: Vec<I>) -> Symbol {
self.functions.push((instructions, *sym));
*sym
}
pub fn reserve(&mut self) -> WritableSymbol {
let val = self.i;
self.i += 1;
WritableSymbol(Symbol(val))
}
pub fn len(&self) -> usize {
self.functions.len() + self.ro_data.len()
}
}
pub struct SymTable(Vec<Addr>);
impl SymTable {
pub fn new(len: usize) -> Self {
Self(vec![Addr::NONE; len])
}
pub fn insert(&mut self, sym: Symbol, addr: Addr) {
self.0[sym.0] = addr;
}
pub fn get(&self, sym: Symbol) -> Option<Addr> {
match self.0[sym.0] {
Addr::NONE => None,
addr => Some(addr),
}
}
}

View File

@@ -1,57 +1,56 @@
use crate::compiler::program::Instr; use crate::compiler::program::{Addr, Instr, SymTable, Symbol};
use super::*; use super::*;
pub enum AsmInstruction { pub enum AsmInstruction {
Addi(Reg, Reg, i32), Addi(Reg, Reg, i32),
La(Reg, String), La(Reg, Symbol),
Jal(Reg, i32), Jal(Reg, i32),
Jala(String), Call(Symbol),
Ja(String), J(Symbol),
Ret, Ret,
Ecall, Ecall,
Li(Reg, i32),
} }
impl Instr for AsmInstruction { impl Instr for AsmInstruction {
fn push( fn push(&self, data: &mut Vec<u8>, sym_map: &SymTable, pos: Addr, missing: bool) -> Option<Symbol> {
&self, let last = match self {
data: &mut Vec<u8>, Self::Addi(dest, src, imm) => addi(*dest, *src, BitsI32::new(*imm)),
sym_map: &std::collections::HashMap<String, u64>,
pos: u64,
) -> Option<String> {
match self {
Self::Addi(dest, src, imm) => {
data.extend(addi(*dest, *src, BitsI32::new(*imm)).to_le_bytes());
}
Self::La(dest, sym) => { Self::La(dest, sym) => {
if let Some(addr) = sym_map.get(sym) { if let Some(addr) = sym_map.get(*sym) {
let offset = *addr as i32 - pos as i32; let offset = addr.val() as i32 - pos.val() as i32;
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes()); data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
data.extend(addi(*dest, *dest, BitsI32::new(offset)).to_le_bytes()); addi(*dest, *dest, BitsI32::new(offset))
} else { } else {
return Some(sym.to_string()); data.extend_from_slice(&[0; 2 * 4]);
return Some(*sym);
} }
} }
Self::Jal(dest, offset) => data.extend(jal(*dest, BitsI32::new(*offset)).to_le_bytes()), Self::Jal(dest, offset) => jal(*dest, BitsI32::new(*offset)),
Self::Ja(sym) => { Self::J(sym) => {
if let Some(addr) = sym_map.get(sym) { if let Some(addr) = sym_map.get(*sym) {
let offset = *addr as i32 - pos as i32; let offset = addr.val() as i32 - pos.val() as i32;
data.extend(j(BitsI32::new(offset)).to_le_bytes()); j(BitsI32::new(offset))
} else { } else {
return Some(sym.to_string()); data.extend_from_slice(&[0; 4]);
return Some(*sym);
} }
} }
Self::Jala(sym) => { Self::Call(sym) => {
if let Some(addr) = sym_map.get(sym) { if let Some(addr) = sym_map.get(*sym) {
let offset = *addr as i32 - pos as i32; let offset = addr.val() as i32 - pos.val() as i32;
data.extend(jal(ra, BitsI32::new(offset)).to_le_bytes()); jal(ra, BitsI32::new(offset))
} else { } else {
return Some(sym.to_string()); data.extend_from_slice(&[0; 4]);
return Some(*sym);
} }
} }
Self::Ret => data.extend(ret().to_le_bytes()), Self::Ret => ret(),
Self::Ecall => data.extend(ecall().to_le_bytes()), Self::Ecall => ecall(),
} Self::Li(reg, val) => addi(*reg, zero, BitsI32::new(*val)),
};
data.extend(last.to_le_bytes());
None None
} }
} }

View File

@@ -5,9 +5,7 @@ mod opcode;
mod reg; mod reg;
mod single; mod single;
use std::collections::HashMap; use super::{create_program, elf, SymMap};
use super::{elf, program::{create_program, Function}};
use crate::util::BitsI32; use crate::util::BitsI32;
use base::*; use base::*;
use funct::{op::*, width}; use funct::{op::*, width};
@@ -18,64 +16,33 @@ use single::*;
pub fn gen() -> Vec<u8> { pub fn gen() -> Vec<u8> {
use asm::AsmInstruction as I; use asm::AsmInstruction as I;
// let mut program = Vec::new(); let mut table = SymMap::new();
// let msg = b"Hello world!\n"; let (msg, len) = table.push_ro_data(b"Hello world!\n");
// program.extend(msg); let (msg2, len2) = table.push_ro_data(b"IT WORKS!!!!\n");
// program.resize(((program.len() - 1) / 4 + 1) * 4, 0); let print_stuff = table.reserve();
// let start = program.len() as u64; let start = table.push_fn(vec![
// let instructions = [ I::Call(*print_stuff),
// auipc(t0, BitsI32::new(0)), I::Li(a0, 0),
// addi(t0, t0, BitsI32::new(-(start as i32))), I::Li(a7, 93),
// addi(a0, zero, BitsI32::new(1)),
// mv(a1, t0),
// addi(a2, zero, BitsI32::new(msg.len() as i32)),
// addi(a7, zero, BitsI32::new(64)),
// addi(t0, zero, const { BitsI32::new(-10) }),
// ecall(),
// // exit
// addi(a0, zero, BitsI32::new(0)),
// addi(a7, zero, BitsI32::new(93)),
// ecall(),
// j(BitsI32::new(0)),
// ];
// for i in instructions {
// program.extend(i.to_le_bytes());
// }
let msg = b"Hello world!\n";
let msg2 = b"IT WORKS!!!!\n";
let ro_data = HashMap::from([
("msg".to_string(), msg.to_vec()),
("msg2".to_string(), msg2.to_vec()),
]);
let functions = vec![
Function {
label: "print_stuff".to_string(),
instructions: vec![
I::Addi(a0, zero, 1),
I::La(a1, "msg".to_string()),
I::Addi(a2, zero, msg.len() as i32),
I::Addi(a7, zero, 64),
I::Ecall,
I::Addi(a0, zero, 1),
I::La(a1, "msg2".to_string()),
I::Addi(a2, zero, msg2.len() as i32),
I::Addi(a7, zero, 64),
I::Ecall,
I::Ret,
]
},
Function {
label: "_start".to_string(),
instructions: vec![
I::Jala("print_stuff".to_string()),
I::Ecall,
I::Addi(a0, zero, 0),
I::Addi(a7, zero, 93),
I::Ecall, I::Ecall,
I::Jal(zero, 0), I::Jal(zero, 0),
] ]);
}, table.write_fn(
]; print_stuff,
let (program, start) = create_program(ro_data, functions); vec![
I::Li(a0, 1),
I::La(a1, msg),
I::Li(a2, len as i32),
I::Li(a7, 64),
I::Ecall,
I::Li(a0, 1),
I::La(a1, msg2),
I::Li(a2, len2 as i32),
I::Li(a7, 64),
I::Ecall,
I::Ret,
],
);
let (program, start) = create_program(table, start);
elf::create(program, start.expect("no start!")) elf::create(program, start.expect("no start!"))
} }

View File

@@ -1,6 +1,4 @@
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(const_unbounded_shifts)]
#![feature(unbounded_shifts)]
mod util; mod util;
mod compiler; mod compiler;