Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit 6306e4f

Browse files
author
Pat Hickey
authored
Merge pull request #422 from froydnj/faerie-output-consolidation
faerie output consolidation
2 parents 7b27c68 + 9b635f0 commit 6306e4f

6 files changed

Lines changed: 215 additions & 206 deletions

File tree

lucetc/src/function_manifest.rs

Lines changed: 0 additions & 69 deletions
This file was deleted.

lucetc/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ mod compiler;
44
mod decls;
55
mod error;
66
mod function;
7-
mod function_manifest;
87
mod heap;
98
mod load;
109
mod module;

lucetc/src/output.rs

Lines changed: 188 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
use crate::error::Error;
2-
use crate::function_manifest::{write_function_manifest, FUNCTION_MANIFEST_SYM};
32
use crate::name::Name;
43
use crate::stack_probe;
5-
use crate::table::{link_tables, TABLE_SYM};
6-
use crate::traps::write_trap_tables;
4+
use crate::table::{TABLE_REF_SIZE, TABLE_SYM};
5+
use crate::traps::{translate_trapcode, trap_sym_for_func};
76
use byteorder::{LittleEndian, WriteBytesExt};
8-
use cranelift_codegen::{ir, isa};
7+
use cranelift_codegen::{binemit::TrapSink, ir, isa};
8+
use cranelift_faerie::traps::{FaerieTrapManifest, FaerieTrapSink};
99
use cranelift_faerie::FaerieProduct;
1010
use faerie::{Artifact, Decl, Link};
1111
use lucet_module::{
12-
FunctionSpec, SerializedModule, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM,
12+
FunctionSpec, SerializedModule, TrapSite, VersionInfo, LUCET_MODULE_SYM, MODULE_DATA_SYM,
1313
};
1414
use std::collections::HashMap;
1515
use std::fs::File;
1616
use std::io::{Cursor, Write};
17+
use std::mem::size_of;
1718
use std::path::Path;
1819
use target_lexicon::BinaryFormat;
1920

21+
pub(crate) const FUNCTION_MANIFEST_SYM: &str = "lucet_function_manifest";
22+
2023
pub struct CraneliftFuncs {
2124
funcs: HashMap<Name, ir::Function>,
2225
isa: Box<dyn isa::TargetIsa>,
@@ -48,39 +51,21 @@ pub struct ObjectFile {
4851
}
4952
impl ObjectFile {
5053
pub fn new(
51-
mut product: FaerieProduct,
54+
product: FaerieProduct,
5255
module_data_len: usize,
5356
mut function_manifest: Vec<(String, FunctionSpec)>,
5457
table_manifest: Vec<Name>,
5558
) -> Result<Self, Error> {
56-
stack_probe::declare_and_define(&mut product)?;
57-
58-
// stack_probe::declare_and_define never exists as clif, and as a result never exists a
59-
// cranelift-compiled function. As a result, the declared length of the stack probe's
60-
// "code" is 0. This is incorrect, and must be fixed up before writing out the function
61-
// manifest.
62-
63-
// because the stack probe is the last declared function...
64-
let last_idx = function_manifest.len() - 1;
65-
let stack_probe_entry = function_manifest
66-
.get_mut(last_idx)
67-
.expect("function manifest has entries");
68-
debug_assert!(stack_probe_entry.0 == stack_probe::STACK_PROBE_SYM);
69-
debug_assert!(stack_probe_entry.1.code_len() == 0);
70-
std::mem::swap(
71-
&mut stack_probe_entry.1,
72-
&mut FunctionSpec::new(
73-
0, // there is no real address for the function until written to an object file
74-
stack_probe::STACK_PROBE_BINARY.len() as u32,
75-
0,
76-
0, // fix up this FunctionSpec with trap info like any other
77-
),
78-
);
59+
let mut obj = Self {
60+
artifact: product.artifact,
61+
};
7962

80-
let trap_manifest = &product
63+
let mut trap_manifest: FaerieTrapManifest = product
8164
.trap_manifest
8265
.expect("trap manifest will be present");
8366

67+
obj.write_stack_probe(&mut trap_manifest, &mut function_manifest)?;
68+
8469
// Now that we have trap information, we can fix up FunctionSpec entries to have
8570
// correct `trap_length` values
8671
let mut function_map: HashMap<String, u32> = HashMap::new();
@@ -103,21 +88,187 @@ impl ObjectFile {
10388
}
10489
}
10590

106-
write_trap_tables(trap_manifest, &mut product.artifact)?;
107-
write_function_manifest(function_manifest.as_slice(), &mut product.artifact)?;
108-
link_tables(table_manifest.as_slice(), &mut product.artifact)?;
91+
obj.write_trap_tables(&trap_manifest)?;
92+
obj.write_function_manifest(function_manifest.as_slice())?;
93+
obj.link_tables(table_manifest.as_slice())?;
10994

11095
// And now write out the actual structure tying together all the data in this module.
11196
write_module(
11297
module_data_len,
11398
table_manifest.len(),
11499
function_manifest.len(),
115-
&mut product.artifact,
100+
&mut obj.artifact,
116101
)?;
117102

118-
Ok(Self {
119-
artifact: product.artifact,
120-
})
103+
Ok(obj)
104+
}
105+
106+
fn write_stack_probe(
107+
&mut self,
108+
traps: &mut FaerieTrapManifest,
109+
function_manifest: &mut Vec<(String, FunctionSpec)>,
110+
) -> Result<(), Error> {
111+
self.artifact
112+
.declare_with(
113+
stack_probe::STACK_PROBE_SYM,
114+
Decl::function(),
115+
stack_probe::STACK_PROBE_BINARY.to_vec(),
116+
)
117+
.map_err(|source| {
118+
let message = format!("Error declaring {}", stack_probe::STACK_PROBE_SYM);
119+
Error::Failure(source, message)
120+
})?;
121+
122+
{
123+
let mut stack_probe_trap_sink = FaerieTrapSink::new(
124+
stack_probe::STACK_PROBE_SYM,
125+
stack_probe::STACK_PROBE_BINARY.len() as u32,
126+
);
127+
stack_probe::trap_sites()
128+
.iter()
129+
.for_each(|t| stack_probe_trap_sink.trap(t.offset, t.srcloc, t.code));
130+
traps.add_sink(stack_probe_trap_sink);
131+
}
132+
133+
// The stack probe never exists as clif, and as a result never exists a
134+
// cranelift-compiled function. As a result, the declared length of the stack probe's
135+
// "code" is 0. This is incorrect, and must be fixed up before writing out the function
136+
// manifest.
137+
138+
// because the stack probe is the last declared function...
139+
let last_idx = function_manifest.len() - 1;
140+
let stack_probe_entry = function_manifest
141+
.get_mut(last_idx)
142+
.expect("function manifest has entries");
143+
debug_assert!(stack_probe_entry.0 == stack_probe::STACK_PROBE_SYM);
144+
debug_assert!(stack_probe_entry.1.code_len() == 0);
145+
std::mem::swap(
146+
&mut stack_probe_entry.1,
147+
&mut FunctionSpec::new(
148+
0, // there is no real address for the function until written to an object file
149+
stack_probe::STACK_PROBE_BINARY.len() as u32,
150+
0,
151+
0, // fix up this FunctionSpec with trap info like any other
152+
),
153+
);
154+
155+
Ok(())
156+
}
157+
158+
///
159+
/// Writes a manifest of functions, with relocations, to the artifact.
160+
///
161+
fn write_function_manifest(
162+
&mut self,
163+
functions: &[(String, FunctionSpec)],
164+
) -> Result<(), Error> {
165+
self.artifact
166+
.declare(FUNCTION_MANIFEST_SYM, Decl::data())
167+
.map_err(|source| {
168+
let message = format!("Manifest error declaring {}", FUNCTION_MANIFEST_SYM);
169+
Error::ArtifactError(source, message)
170+
})?;
171+
172+
let mut manifest_buf: Cursor<Vec<u8>> = Cursor::new(Vec::with_capacity(
173+
functions.len() * size_of::<FunctionSpec>(),
174+
));
175+
176+
for (fn_name, fn_spec) in functions.iter() {
177+
/*
178+
* This has implicit knowledge of the layout of `FunctionSpec`!
179+
*
180+
* Each iteraction writes out bytes with relocations that will
181+
* result in data forming a valid FunctionSpec when this is loaded.
182+
*
183+
* Because the addresses don't exist until relocations are applied
184+
* when the artifact is loaded, we can't just populate the fields
185+
* and transmute, unfortunately.
186+
*/
187+
// Writes a (ptr, len) pair with relocation for code
188+
write_relocated_slice(
189+
&mut self.artifact,
190+
&mut manifest_buf,
191+
FUNCTION_MANIFEST_SYM,
192+
Some(fn_name),
193+
fn_spec.code_len() as u64,
194+
)?;
195+
// Writes a (ptr, len) pair with relocation for this function's trap table
196+
let trap_sym = trap_sym_for_func(fn_name);
197+
write_relocated_slice(
198+
&mut self.artifact,
199+
&mut manifest_buf,
200+
FUNCTION_MANIFEST_SYM,
201+
if fn_spec.traps_len() > 0 {
202+
Some(&trap_sym)
203+
} else {
204+
None
205+
},
206+
fn_spec.traps_len() as u64,
207+
)?;
208+
}
209+
210+
self.artifact
211+
.define(FUNCTION_MANIFEST_SYM, manifest_buf.into_inner())
212+
.map_err(|source| {
213+
let message = format!("Manifest error declaring {}", FUNCTION_MANIFEST_SYM);
214+
Error::ArtifactError(source, message)
215+
})?;
216+
217+
Ok(())
218+
}
219+
220+
fn write_trap_tables(&mut self, manifest: &FaerieTrapManifest) -> Result<(), Error> {
221+
for sink in manifest.sinks.iter() {
222+
let func_sym = &sink.name;
223+
let trap_sym = trap_sym_for_func(func_sym);
224+
225+
self.artifact
226+
.declare(&trap_sym, Decl::data())
227+
.map_err(|source| {
228+
let message = format!("Trap table error declaring {}", trap_sym);
229+
Error::ArtifactError(source, message)
230+
})?;
231+
232+
// write the actual function-level trap table
233+
let traps: Vec<TrapSite> = sink
234+
.sites
235+
.iter()
236+
.map(|site| TrapSite {
237+
offset: site.offset,
238+
code: translate_trapcode(site.code),
239+
})
240+
.collect();
241+
242+
let trap_site_bytes = unsafe {
243+
std::slice::from_raw_parts(
244+
traps.as_ptr() as *const u8,
245+
traps.len() * std::mem::size_of::<TrapSite>(),
246+
)
247+
};
248+
249+
// and write the function trap table into the object
250+
self.artifact
251+
.define(&trap_sym, trap_site_bytes.to_vec())
252+
.map_err(|source| {
253+
let message = format!("Trap table error defining {}", trap_sym);
254+
Error::ArtifactError(source, message)
255+
})?;
256+
}
257+
258+
Ok(())
259+
}
260+
261+
fn link_tables(&mut self, tables: &[Name]) -> Result<(), Error> {
262+
for (idx, table) in tables.iter().enumerate() {
263+
self.artifact
264+
.link(Link {
265+
from: TABLE_SYM,
266+
to: table.symbol(),
267+
at: (TABLE_REF_SIZE * idx) as u64,
268+
})
269+
.map_err(|source| Error::Failure(source, "Table error".to_owned()))?;
270+
}
271+
Ok(())
121272
}
122273

123274
pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {

0 commit comments

Comments
 (0)