11use crate :: error:: Error ;
2- use crate :: function_manifest:: { write_function_manifest, FUNCTION_MANIFEST_SYM } ;
32use crate :: name:: Name ;
43use 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 } ;
76use byteorder:: { LittleEndian , WriteBytesExt } ;
8- use cranelift_codegen:: { ir, isa} ;
7+ use cranelift_codegen:: { binemit:: TrapSink , ir, isa} ;
8+ use cranelift_faerie:: traps:: { FaerieTrapManifest , FaerieTrapSink } ;
99use cranelift_faerie:: FaerieProduct ;
1010use faerie:: { Artifact , Decl , Link } ;
1111use lucet_module:: {
12- FunctionSpec , SerializedModule , VersionInfo , LUCET_MODULE_SYM , MODULE_DATA_SYM ,
12+ FunctionSpec , SerializedModule , TrapSite , VersionInfo , LUCET_MODULE_SYM , MODULE_DATA_SYM ,
1313} ;
1414use std:: collections:: HashMap ;
1515use std:: fs:: File ;
1616use std:: io:: { Cursor , Write } ;
17+ use std:: mem:: size_of;
1718use std:: path:: Path ;
1819use target_lexicon:: BinaryFormat ;
1920
21+ pub ( crate ) const FUNCTION_MANIFEST_SYM : & str = "lucet_function_manifest" ;
22+
2023pub struct CraneliftFuncs {
2124 funcs : HashMap < Name , ir:: Function > ,
2225 isa : Box < dyn isa:: TargetIsa > ,
@@ -48,39 +51,21 @@ pub struct ObjectFile {
4851}
4952impl 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