@@ -415,7 +415,9 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
415415 self . module_cx
416416 . llvm_di_builder
417417 . finalize_function ( & self , di_func) ;
418- ll_fn. verify ( self . module_cx ) ;
418+ // Non-fatal: function verification errors will be caught at module level
419+ // and the module will be skipped.
420+ let _ = ll_fn. verify ( self . module_cx ) ;
419421 }
420422
421423 fn translate_instruction ( & mut self , instr : & sbc:: Bytecode ) {
@@ -1891,11 +1893,15 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
18911893 src : & [ mast:: TempIndex ] ,
18921894 _instr : & sbc:: Bytecode ,
18931895 ) {
1894- // Special-case: object::exists_at<T>(addr) → reuse Exists rtcall
1896+ // Special-case interceptions for native functions that can't go through
1897+ // the normal native call path (ABI mismatches, pure in-memory ops, etc.)
18951898 {
18961899 let global_env = & self . env . module_env . env ;
18971900 let fn_env = global_env. get_function ( fun_id. qualified ( mod_id) ) ;
1898- if fn_env. get_full_name_str ( ) . ends_with ( "::exists_at" ) {
1901+ let full_name = fn_env. get_full_name_str ( ) ;
1902+
1903+ // object::exists_at<T>(addr) → reuse Exists rtcall
1904+ if full_name. ends_with ( "::exists_at" ) {
18991905 let types = mty:: Type :: instantiate_vec ( types. to_vec ( ) , self . type_params ) ;
19001906 assert_eq ! ( types. len( ) , 1 ) ;
19011907 assert_eq ! ( src. len( ) , 1 ) ;
@@ -1904,6 +1910,54 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
19041910 self . emit_rtcall ( RtCall :: Exists ( src0_reg, types[ 0 ] . clone ( ) ) , dst, _instr) ;
19051911 return ;
19061912 }
1913+
1914+ // create_signer(addr: address) -> signer
1915+ // Both are 32 bytes but different LLVM types: address=[32 x i8], signer={[32 x i8]}.
1916+ // RV64 ABI mismatch prevents passing/returning 32-byte aggregates by value.
1917+ // Since signer is a transparent wrapper around address, just load+wrap+store.
1918+ if full_name. ends_with ( "::create_signer" ) {
1919+ assert_eq ! ( src. len( ) , 1 ) ;
1920+ assert_eq ! ( dst. len( ) , 1 ) ;
1921+ let builder = & self . module_cx . llvm_builder ;
1922+ let addr_val =
1923+ builder. load_alloca ( self . locals [ src[ 0 ] ] . llval , self . locals [ src[ 0 ] ] . llty ) ;
1924+ let signer_ty = self . locals [ dst[ 0 ] ] . llty ;
1925+ let agg = llvm:: Constant :: get_const_null ( signer_ty) . as_any_value ( ) ;
1926+ let signer_val = builder. build_insert_value ( agg, addr_val, 0 , "wrap_signer" ) ;
1927+ builder. build_store ( signer_val, self . locals [ dst[ 0 ] ] . llval ) ;
1928+ return ;
1929+ }
1930+
1931+ // transaction_context functions returning address (32 bytes).
1932+ // RV64 ABI mismatch — intercept and call guest export with output pointer.
1933+ if full_name. ends_with ( "::sender_internal" )
1934+ || full_name. ends_with ( "::gas_payer_internal" )
1935+ || full_name. ends_with ( "::generate_unique_address" )
1936+ {
1937+ assert_eq ! ( dst. len( ) , 1 ) ;
1938+ assert_eq ! ( src. len( ) , 0 ) ;
1939+ let builder = & self . module_cx . llvm_builder ;
1940+ let llcx = & self . module_cx . llvm_cx ;
1941+ // Determine the guest export symbol name
1942+ let sym_name = fn_env. llvm_native_fn_symbol_name ( ) ;
1943+ // Declare or get the function with correct ABI: void(ptr)
1944+ let ll_fn = match self . module_cx . llvm_module . get_named_function ( & sym_name) {
1945+ Some ( f) => f,
1946+ None => {
1947+ let fn_ty = llvm:: FunctionType :: new ( llcx. void_type ( ) , & [ llcx. ptr_type ( ) ] ) ;
1948+ self . module_cx . llvm_module . add_function (
1949+ & mut vec ! [ ] ,
1950+ "native" ,
1951+ & sym_name,
1952+ fn_ty,
1953+ false ,
1954+ )
1955+ }
1956+ } ;
1957+ let dst_ptr = self . locals [ dst[ 0 ] ] . llval . as_any_value ( ) ;
1958+ builder. call ( ll_fn, & [ dst_ptr] ) ;
1959+ return ;
1960+ }
19071961 }
19081962
19091963 let types = mty:: Type :: instantiate_vec ( types. to_vec ( ) , self . type_params ) ;
@@ -2561,8 +2615,10 @@ pub fn write_object_file(
25612615 llmod : llvm:: Module ,
25622616 llmachine : & llvm:: TargetMachine ,
25632617 outpath : & str ,
2564- ) -> anyhow:: Result < ( ) > {
2565- llmod. verify ( ) ;
2618+ ) -> anyhow:: Result < bool > {
2619+ if !llmod. verify ( ) {
2620+ return Ok ( false ) ;
2621+ }
25662622 // Dump LLVM IR for debugging
25672623 unsafe {
25682624 let ir_path = format ! ( "{outpath}.ll" ) ;
@@ -2571,5 +2627,5 @@ pub fn write_object_file(
25712627 llvm_sys:: core:: LLVMPrintModuleToFile ( llmod. 0 , ir_path_c. as_ptr ( ) , & mut err) ;
25722628 }
25732629 llmachine. emit_to_obj_file ( & llmod, outpath) ?;
2574- Ok ( ( ) )
2630+ Ok ( true )
25752631}
0 commit comments