cranelift-object: move relocation processing to finish

This removes the need to call `finalize_definitions` for cranelift-object.
`finalize_definitions` is only intended for backends that produce
finalized functions and data objects, which cranelift-object does not.
This commit is contained in:
Philip Craig
2020-01-24 14:09:32 +10:00
committed by Benjamin Bouvier
parent 376654bdfc
commit 3c15f8f129
5 changed files with 72 additions and 87 deletions

View File

@@ -311,7 +311,7 @@ impl Backend for FaerieBackend {
// Nothing to do. // Nothing to do.
} }
fn finish(self) -> FaerieProduct { fn finish(self, _namespace: &ModuleNamespace<Self>) -> FaerieProduct {
FaerieProduct { FaerieProduct {
artifact: self.artifact, artifact: self.artifact,
trap_manifest: self.trap_manifest, trap_manifest: self.trap_manifest,

View File

@@ -146,7 +146,7 @@ where
/// Consume this `Backend` and return a result. Some implementations may /// Consume this `Backend` and return a result. Some implementations may
/// provide additional functionality through this result. /// provide additional functionality through this result.
fn finish(self) -> Self::Product; fn finish(self, namespace: &ModuleNamespace<Self>) -> Self::Product;
} }
/// Default names for `ir::LibCall`s. A function by this name is imported into the object as /// Default names for `ir::LibCall`s. A function by this name is imported into the object as

View File

@@ -714,8 +714,9 @@ where
/// Consume the module and return the resulting `Product`. Some `Backend` /// Consume the module and return the resulting `Product`. Some `Backend`
/// implementations may provide additional functionality available after /// implementations may provide additional functionality available after
/// a `Module` is complete. /// a `Module` is complete.
pub fn finish(mut self) -> B::Product { pub fn finish(self) -> B::Product {
self.finalize_definitions(); self.backend.finish(&ModuleNamespace::<B> {
self.backend.finish() contents: &self.contents,
})
} }
} }

View File

@@ -16,6 +16,7 @@ use object::write::{
}; };
use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope}; use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope};
use std::collections::HashMap; use std::collections::HashMap;
use std::mem;
use target_lexicon::PointerWidth; use target_lexicon::PointerWidth;
#[derive(Debug)] #[derive(Debug)]
@@ -79,6 +80,7 @@ pub struct ObjectBackend {
functions: SecondaryMap<FuncId, Option<SymbolId>>, functions: SecondaryMap<FuncId, Option<SymbolId>>,
data_objects: SecondaryMap<DataId, Option<SymbolId>>, data_objects: SecondaryMap<DataId, Option<SymbolId>>,
traps: SecondaryMap<FuncId, Vec<ObjectTrapSite>>, traps: SecondaryMap<FuncId, Vec<ObjectTrapSite>>,
relocs: Vec<SymbolRelocs>,
libcalls: HashMap<ir::LibCall, SymbolId>, libcalls: HashMap<ir::LibCall, SymbolId>,
libcall_names: Box<dyn Fn(ir::LibCall) -> String>, libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
collect_traps: ObjectTrapCollection, collect_traps: ObjectTrapCollection,
@@ -109,6 +111,7 @@ impl Backend for ObjectBackend {
functions: SecondaryMap::new(), functions: SecondaryMap::new(),
data_objects: SecondaryMap::new(), data_objects: SecondaryMap::new(),
traps: SecondaryMap::new(), traps: SecondaryMap::new(),
relocs: Vec::new(),
libcalls: HashMap::new(), libcalls: HashMap::new(),
libcall_names: builder.libcall_names, libcall_names: builder.libcall_names,
collect_traps: builder.collect_traps, collect_traps: builder.collect_traps,
@@ -212,13 +215,15 @@ impl Backend for ObjectBackend {
let offset = self let offset = self
.object .object
.add_symbol_data(symbol, section, &code, self.function_alignment); .add_symbol_data(symbol, section, &code, self.function_alignment);
if !reloc_sink.relocs.is_empty() {
self.relocs.push(SymbolRelocs {
section,
offset,
relocs: reloc_sink.relocs,
});
}
self.traps[func_id] = trap_sink.sites; self.traps[func_id] = trap_sink.sites;
Ok(ObjectCompiledFunction { Ok(ObjectCompiledFunction)
offset,
size: code_size,
section,
relocs: reloc_sink.relocs,
})
} }
fn define_data( fn define_data(
@@ -290,11 +295,14 @@ impl Backend for ObjectBackend {
let offset = let offset =
self.object self.object
.add_symbol_data(symbol, section, &data, u64::from(align.unwrap_or(1))); .add_symbol_data(symbol, section, &data, u64::from(align.unwrap_or(1)));
Ok(ObjectCompiledData { if !relocs.is_empty() {
offset, self.relocs.push(SymbolRelocs {
section, section,
relocs, offset,
}) relocs,
});
}
Ok(ObjectCompiledData)
} }
fn write_data_funcaddr( fn write_data_funcaddr(
@@ -319,34 +327,10 @@ impl Backend for ObjectBackend {
fn finalize_function( fn finalize_function(
&mut self, &mut self,
_id: FuncId, _id: FuncId,
func: &ObjectCompiledFunction, _func: &ObjectCompiledFunction,
namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
) { ) {
for &RelocRecord { // Nothing to do.
offset,
ref name,
kind,
encoding,
size,
addend,
} in &func.relocs
{
let offset = func.offset + u64::from(offset);
let symbol = self.get_symbol(namespace, name);
self.object
.add_relocation(
func.section,
Relocation {
offset,
size,
kind,
encoding,
symbol,
addend,
},
)
.unwrap();
}
} }
fn get_finalized_function(&self, _func: &ObjectCompiledFunction) { fn get_finalized_function(&self, _func: &ObjectCompiledFunction) {
@@ -356,34 +340,10 @@ impl Backend for ObjectBackend {
fn finalize_data( fn finalize_data(
&mut self, &mut self,
_id: DataId, _id: DataId,
data: &ObjectCompiledData, _data: &ObjectCompiledData,
namespace: &ModuleNamespace<Self>, _namespace: &ModuleNamespace<Self>,
) { ) {
for &RelocRecord { // Nothing to do.
offset,
ref name,
kind,
encoding,
size,
addend,
} in &data.relocs
{
let offset = data.offset + u64::from(offset);
let symbol = self.get_symbol(namespace, name);
self.object
.add_relocation(
data.section,
Relocation {
offset,
size,
kind,
encoding,
symbol,
addend,
},
)
.unwrap();
}
} }
fn get_finalized_data(&self, _data: &ObjectCompiledData) { fn get_finalized_data(&self, _data: &ObjectCompiledData) {
@@ -394,7 +354,36 @@ impl Backend for ObjectBackend {
// Nothing to do. // Nothing to do.
} }
fn finish(self) -> ObjectProduct { fn finish(mut self, namespace: &ModuleNamespace<Self>) -> ObjectProduct {
let mut symbol_relocs = Vec::new();
mem::swap(&mut symbol_relocs, &mut self.relocs);
for symbol in symbol_relocs {
for &RelocRecord {
offset,
ref name,
kind,
encoding,
size,
addend,
} in &symbol.relocs
{
let target_symbol = self.get_symbol(namespace, name);
self.object
.add_relocation(
symbol.section,
Relocation {
offset: symbol.offset + u64::from(offset),
size,
kind,
encoding,
symbol: target_symbol,
addend,
},
)
.unwrap();
}
}
ObjectProduct { ObjectProduct {
object: self.object, object: self.object,
functions: self.functions, functions: self.functions,
@@ -405,7 +394,7 @@ impl Backend for ObjectBackend {
} }
impl ObjectBackend { impl ObjectBackend {
// This should only be called during finalization because it creates // This should only be called during finish because it creates
// symbols for missing libcalls. // symbols for missing libcalls.
fn get_symbol( fn get_symbol(
&mut self, &mut self,
@@ -459,20 +448,8 @@ fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) {
(scope, weak) (scope, weak)
} }
#[derive(Clone)] pub struct ObjectCompiledFunction;
pub struct ObjectCompiledFunction { pub struct ObjectCompiledData;
offset: u64,
size: u32,
section: SectionId,
relocs: Vec<RelocRecord>,
}
#[derive(Clone)]
pub struct ObjectCompiledData {
offset: u64,
section: SectionId,
relocs: Vec<RelocRecord>,
}
/// This is the output of `Module`'s /// This is the output of `Module`'s
/// [`finish`](../cranelift_module/struct.Module.html#method.finish) function. /// [`finish`](../cranelift_module/struct.Module.html#method.finish) function.
@@ -509,6 +486,13 @@ impl ObjectProduct {
} }
} }
#[derive(Clone)]
struct SymbolRelocs {
section: SectionId,
offset: u64,
relocs: Vec<RelocRecord>,
}
#[derive(Clone)] #[derive(Clone)]
struct RelocRecord { struct RelocRecord {
offset: CodeOffset, offset: CodeOffset,

View File

@@ -507,7 +507,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
/// ///
/// This method does not need to be called when access to the memory /// This method does not need to be called when access to the memory
/// handle is not required. /// handle is not required.
fn finish(self) -> Self::Product { fn finish(self, _namespace: &ModuleNamespace<Self>) -> Self::Product {
self.memory self.memory
} }
} }