166 lines
4.4 KiB
Rust
166 lines
4.4 KiB
Rust
//! This module contains the definitions for a Symbol.
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use uuid::Uuid;
|
|
|
|
use crate::{model::module::ModuleId, symtab::SymbolTable};
|
|
|
|
/// Tuple struct for type safety. Has methods for fetching symbols by ID.
|
|
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
|
pub struct SymbolId(Uuid);
|
|
|
|
impl From<Symbol> for SymbolId {
|
|
fn from(sym: Symbol) -> Self {
|
|
sym.id
|
|
}
|
|
}
|
|
|
|
impl Default for SymbolId {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl SymbolId {
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self(Uuid::new_v4())
|
|
}
|
|
|
|
/// Convenience method to get the [`Module`] from a [`ModuleId`].
|
|
#[must_use]
|
|
pub fn to_module<'s>(&self, registry: &'s SymbolTable) -> Option<&'s Symbol> {
|
|
registry.get(self)
|
|
}
|
|
|
|
/// Convenience method to get the [`Module`] name from a [`ModuleId`].
|
|
#[must_use]
|
|
pub fn to_module_name(self, registry: &SymbolTable) -> Option<&str> {
|
|
self.to_module(registry).map(|module| module.name.as_str())
|
|
}
|
|
}
|
|
|
|
/// A symbol is a named reference that may be resolved later to an address by a linker.
|
|
#[derive(Debug)]
|
|
pub struct Symbol {
|
|
/// Stored cheaply instead of the name. Shall be stored in the symbol table under
|
|
/// this key.
|
|
pub id: SymbolId,
|
|
|
|
/// The human-readable name for the symbol.
|
|
pub name: String,
|
|
|
|
pub visibility: Visibility,
|
|
|
|
pub symbol_type: SymbolType,
|
|
|
|
/// The id of the module the symbol is defined in. This will be different for symbols
|
|
/// in different objects.
|
|
pub module_id: ModuleId,
|
|
|
|
/// Whether or not the symbol requires relocating.
|
|
pub needs_relocation: bool,
|
|
|
|
/// A list of the symbol's dependencies.
|
|
///
|
|
/// e.g.
|
|
///
|
|
/// ```dsa
|
|
/// main:
|
|
/// call another_func
|
|
///
|
|
/// another_func:
|
|
/// // Code goes here
|
|
/// ret
|
|
/// ```
|
|
///
|
|
/// Where `main` depends on `another_func`.
|
|
pub dependencies: HashSet<SymbolId>,
|
|
|
|
/// The address of the symbol.
|
|
pub address: Option<u32>,
|
|
/// The section the symbol is in.
|
|
/// TODO: Perhaps make this a proper type?
|
|
pub section: Option<String>,
|
|
pub size: Option<u32>,
|
|
}
|
|
|
|
impl Symbol {
|
|
#[must_use]
|
|
pub fn new(
|
|
name: String,
|
|
module_id: ModuleId,
|
|
visibility: Visibility,
|
|
symbol_type: SymbolType,
|
|
) -> Self {
|
|
Self {
|
|
id: SymbolId::new(),
|
|
name,
|
|
module_id,
|
|
address: None,
|
|
section: None,
|
|
size: None,
|
|
visibility,
|
|
symbol_type,
|
|
needs_relocation: false,
|
|
dependencies: HashSet::new(),
|
|
}
|
|
}
|
|
|
|
/// Adds a dependency on another [`Symbol`].
|
|
pub fn add_dependency(&mut self, dep: SymbolId) {
|
|
if self.id == dep {
|
|
return;
|
|
}
|
|
|
|
// We can resolve a lot of addresses at assembly time, but not really foreign
|
|
// ones, since we aren't certain of their position.
|
|
//
|
|
/* TODO: Handle this for flat binary case i.e. no linker required. This may be
|
|
* done using a similar method to before, such as just concatenating all
|
|
* of the files together and handling jumps and halts.
|
|
*
|
|
* > Ask Harry or read the initial code.
|
|
*/
|
|
if self.dependencies.insert(dep) {
|
|
self.needs_relocation = true;
|
|
}
|
|
}
|
|
|
|
/// Returns whether a [`Symbol`] depends on `symbol_id`.
|
|
#[must_use]
|
|
pub fn depends_on(&self, symbol_id: &SymbolId) -> bool {
|
|
self.dependencies.contains(symbol_id)
|
|
}
|
|
|
|
/// Removes a [`Symbol`] from the dependency set.
|
|
pub fn remove_dependency(&mut self, symbol_id: &SymbolId) {
|
|
self.dependencies.remove(symbol_id);
|
|
|
|
if self.dependencies.is_empty() {
|
|
self.needs_relocation = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
/// The visibility of the symbol in different object files.
|
|
pub enum Visibility {
|
|
/// `STB_PUBLIC` under the ELF spec. Visible in all other object files. Shall be used
|
|
/// for labels. Remember labels are namespaced in different files so they won't clash
|
|
/// with one another.
|
|
Public,
|
|
/// Only visible within this object file. `STB_LOCAL` under ELF spec. Shall be used
|
|
/// for data definitions unless they are marked public.
|
|
Local,
|
|
/// `STB_WEAK` under the ELF spec. Potentially unused.
|
|
Weak,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum SymbolType {
|
|
LabelOrFunction,
|
|
Variable,
|
|
}
|