From: Aleksey Kliger (λgeek) Date: Fri, 10 Jul 2020 00:37:36 +0000 (-0400) Subject: [mono] Add support for UnmanagedCallersOnlyAttribute (#38728) X-Git-Tag: submit/tizen/20210909.063632~6828 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1e3c959b087bc7cc7d10e360211150b3db050454;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [mono] Add support for UnmanagedCallersOnlyAttribute (#38728) * [marshal] Add mono_method_has_unmanaged_callers_only_attribute * [marshal] Allow calls to mono_marshal_get_managed_wrapped without a delegate class In that case, create a wrapper based on the signature of the method itself. * [aot] Allow decode_method_ref to decode NATIVE_TO_MANAGED wrappers without a delegate class Bump the AOT file format * [interp] ldftn will return a native-to-managed wrapper to UnmanagedCallersOnly methods * aot: emit byte when we don't expect a class * jit: create wrapper creation for ldftn in method-to-ir Do it at IR generation of the caller, not every time the ldftn is executed * jit: don't create a jump trampoline for ldftn of a native-to-managed wrapper The wrapper might be called from a thread that's not attached to the runtime, and the jump trampoline will look at TLS vars that are not initialized * interp: transform LDFTN into LDC of a create_method_pointer for UnmanagedCallersOnly method * marshal: throw invalid program exception for instance and generic methods * Emit IPE throw instead of aborting JIT or interp compilation for bad UnmanagedCallersOnly methods Instead of throwing while JITing (or transforming), throw when the LDFTN is executed. * disallow delegate constructor calls on UnmanagedCallersOnly methods * throw IPE if UnmanagedCallersOnly method has non-blittable args * disallow DllImport and UnmanagedCallersOnly together throw NotSupportedException Co-authored-by: Ryan Lucia --- diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 3c271b2..49f5460 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -1553,6 +1553,9 @@ mono_method_is_constructor (MonoMethod *method); gboolean mono_class_has_default_constructor (MonoClass *klass, gboolean public_only); +gboolean +mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method); + // There are many ways to do on-demand initialization. // Some allow multiple concurrent initializations. Some do not. // Some allow multiple concurrent writes to the global. Some do not. diff --git a/src/mono/mono/metadata/jit-icall-reg.h b/src/mono/mono/metadata/jit-icall-reg.h index 5b07e4c..3abbdf4 100644 --- a/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/mono/mono/metadata/jit-icall-reg.h @@ -308,6 +308,8 @@ MONO_JIT_ICALL (mono_threads_state_poll) \ MONO_JIT_ICALL (mono_throw_exception) \ MONO_JIT_ICALL (mono_throw_method_access) \ MONO_JIT_ICALL (mono_throw_bad_image) \ +MONO_JIT_ICALL (mono_throw_not_supported) \ +MONO_JIT_ICALL (mono_throw_invalid_program) \ MONO_JIT_ICALL (mono_trace_enter_method) \ MONO_JIT_ICALL (mono_trace_leave_method) \ MONO_JIT_ICALL (mono_trace_tail_method) \ diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index bec2c30..fe74f17 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -113,6 +113,7 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, #ifdef ENABLE_NETCORE static GENERATE_TRY_GET_CLASS_WITH_CACHE (suppress_gc_transition_attribute, "System.Runtime.InteropServices", "SuppressGCTransitionAttribute") +static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_callers_only_attribute, "System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute") #endif static MonoImage* @@ -3661,6 +3662,23 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, mb->method->save_lmf = 1; + if (G_UNLIKELY (pinvoke && mono_method_has_unmanaged_callers_only_attribute (method))) { + /* emit a wrapper that throws a NotSupportedException */ + get_marshal_cb ()->mb_emit_exception (mb, "System", "NotSupportedException", "Method canot be marked with both DllImportAttribute and UnmanagedCallersOnlyAttribute"); + + info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE); + info->d.managed_to_native.method = method; + + csig = mono_metadata_signature_dup_full (get_method_image (method), sig); + csig->pinvoke = 0; + res = mono_mb_create_and_cache_full (cache, method, mb, csig, + csig->param_count + 16, info, NULL); + mono_mb_free (mb); + + return res; + } + + /* * In AOT mode and embedding scenarios, it is possible that the icall is not * registered in the runtime doing the AOT compilation. @@ -3940,10 +3958,54 @@ emit_managed_wrapper_noilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke } #endif +static gboolean +type_is_blittable (MonoType *type) +{ + if (type->byref) + return FALSE; + type = mono_type_get_underlying_type (type); + switch (type->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: + return TRUE; + default: + return m_class_is_blittable (mono_class_from_mono_type_internal (type)); + } +} + +static gboolean +method_signature_is_blittable (MonoMethodSignature *sig) +{ + if (!type_is_blittable (sig->ret)) + return FALSE; + + for (int i = 0; i < sig->param_count; ++i) { + MonoType *type = sig->params [i]; + if (!type_is_blittable (type)) + return FALSE; + } + return TRUE; +} + /** * mono_marshal_get_managed_wrapper: * Generates IL code to call managed methods from unmanaged code * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure. + * + * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with + * UnamangedCallersOnlyAttribute. */ MonoMethod * mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error) @@ -3975,11 +4037,33 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, if (!target_handle && (res = mono_marshal_find_in_cache (cache, method))) return res; - invoke = mono_get_delegate_invoke_internal (delegate_klass); - invoke_sig = mono_method_signature_internal (invoke); - - mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature_internal (invoke)->param_count + 1); - mono_method_get_marshal_info (invoke, mspecs); + if (G_UNLIKELY (!delegate_klass)) { + /* creating a wrapper for a function pointer with UnmanagedCallersOnlyAttribute */ + if (mono_method_has_marshal_info (method)) { + mono_error_set_invalid_program (error, "method %s with UnmanadedCallersOnlyAttribute has marshal specs", mono_method_full_name (method, TRUE)); + return NULL; + } + invoke = NULL; + invoke_sig = mono_method_signature_internal (method); + if (invoke_sig->hasthis) { + mono_error_set_invalid_program (error, "method %s with UnamanagedCallersOnlyAttribute is an instance method", mono_method_full_name (method, TRUE)); + return NULL; + } + if (method->is_generic || method->is_inflated || mono_class_is_ginst (method->klass)) { + mono_error_set_invalid_program (error, "method %s with UnamangedCallersOnlyAttribute is generic", mono_method_full_name (method, TRUE)); + return NULL; + } + if (!method_signature_is_blittable (invoke_sig)) { + mono_error_set_invalid_program (error, "method %s with UnmanagedCallersOnlyAttribute has non-blittable parameters or return type", mono_method_full_name (method, TRUE)); + return NULL; + } + mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); + } else { + invoke = mono_get_delegate_invoke_internal (delegate_klass); + invoke_sig = mono_method_signature_internal (invoke); + mspecs = g_new0 (MonoMarshalSpec*, invoke_sig->param_count + 1); + mono_method_get_marshal_info (invoke, mspecs); + } sig = mono_method_signature_internal (method); @@ -4005,10 +4089,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, m.csig = csig; m.image = get_method_image (method); - mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE); + if (invoke) + mono_marshal_set_callconv_from_modopt (invoke, csig, TRUE); /* The attribute is only available in Net 2.0 */ - if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) { + if (delegate_klass && mono_class_try_get_unmanaged_function_pointer_attribute_class ()) { MonoCustomAttrInfo *cinfo; MonoCustomAttrEntry *attr; @@ -4097,7 +4182,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, } mono_mb_free (mb); - for (i = mono_method_signature_internal (invoke)->param_count; i >= 0; i--) + for (i = invoke_sig->param_count; i >= 0; i--) if (mspecs [i]) mono_metadata_free_marshal_spec (mspecs [i]); g_free (mspecs); @@ -6755,3 +6840,33 @@ get_marshal_cb (void) } return &marshal_cb; } + +/** + * mono_method_has_unmanaged_callers_only_attribute: + * + * Returns \c TRUE if \p method has the \c UnmanagedCallersOnlyAttribute + */ +gboolean +mono_method_has_unmanaged_callers_only_attribute (MonoMethod *method) +{ +#ifndef ENABLE_NETCORE + return FALSE; +#else + ERROR_DECL (attr_error); + MonoClass *attr_klass = NULL; + attr_klass = mono_class_try_get_unmanaged_callers_only_attribute_class (); + if (!attr_klass) + return FALSE; + MonoCustomAttrInfo *cinfo; + cinfo = mono_custom_attrs_from_method_checked (method, attr_error); + if (!is_ok (attr_error) || !cinfo) { + mono_error_cleanup (attr_error); + return FALSE; + } + gboolean result; + result = mono_custom_attrs_has_attr (cinfo, attr_klass); + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + return result; +#endif +} diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index adb9cab..7c76e4c 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -3761,7 +3761,13 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 case MONO_WRAPPER_NATIVE_TO_MANAGED: { g_assert (info); encode_method_ref (acfg, info->d.native_to_managed.method, p, &p); - encode_klass_ref (acfg, info->d.native_to_managed.klass, p, &p); + MonoClass *klass = info->d.native_to_managed.klass; + if (!klass) { + encode_value (0, p, &p); + } else { + encode_value (1, p, &p); + encode_klass_ref (acfg, klass, p, &p); + } break; } default: diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 209279d..b42c76e 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -1312,9 +1312,13 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod m = decode_resolve_method_ref (module, p, &p, error); if (!m) return FALSE; - klass = decode_klass_ref (module, p, &p, error); - if (!klass) - return FALSE; + gboolean has_class = decode_value (p, &p); + if (has_class) { + klass = decode_klass_ref (module, p, &p, error); + if (!klass) + return FALSE; + } else + klass = NULL; ref->method = mono_marshal_get_managed_wrapper (m, klass, 0, error); if (!is_ok (error)) return FALSE; diff --git a/src/mono/mono/mini/aot-runtime.h b/src/mono/mono/mini/aot-runtime.h index c4171fa..79b9b6d 100644 --- a/src/mono/mono/mini/aot-runtime.h +++ b/src/mono/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 178 +#define MONO_AOT_FILE_VERSION 179 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index ad2e654..351812f 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -841,6 +841,32 @@ interp_generate_bie_throw (TransformData *td) td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); } +static void +interp_generate_not_supported_throw (TransformData *td) +{ + MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_not_supported; + + interp_add_ins (td, MINT_ICALL_V_V); + td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); +} + +static void +interp_generate_ipe_throw_with_msg (TransformData *td, MonoError *error_msg) +{ + MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_invalid_program; + + char *msg = mono_mempool_strdup (td->rtm->domain->mp, mono_error_get_message (error_msg)); + + interp_add_ins (td, MINT_MONO_LDPTR); + td->last_ins->data [0] = get_data_item_index (td, msg); + PUSH_SIMPLE_TYPE (td, STACK_TYPE_I); + + interp_add_ins (td, MINT_ICALL_P_V); + td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); + + td->sp -= 1; +} + /* * These are additional locals that can be allocated as we transform the code. * They are allocated past the method locals so they are accessed in the same @@ -6203,6 +6229,61 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (method->wrapper_type == MONO_WRAPPER_NONE && m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) m = mono_marshal_get_synchronized_wrapper (m); + if (G_UNLIKELY (*td->ip == CEE_LDFTN && + m->wrapper_type == MONO_WRAPPER_NONE && + mono_method_has_unmanaged_callers_only_attribute (m))) { + + if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + interp_generate_not_supported_throw (td); + interp_add_ins (td, MINT_LDNULL); + td->ip += 5; + PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP); + break; + } + + MonoMethod *ctor_method; + + const unsigned char *next_ip = td->ip + 5; + /* check for + * ldftn method_sig + * newobj Delegate::.ctor + */ + if (next_ip < end && + *next_ip == CEE_NEWOBJ && + ((ctor_method = interp_get_method (method, read32 (next_ip + 1), image, generic_context, error))) && + is_ok (error) && + m_class_get_parent (ctor_method->klass) == mono_defaults.multicastdelegate_class && + !strcmp (ctor_method->name, ".ctor")) { + mono_error_set_not_supported (error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute"); + goto exit; + } + + MonoClass *delegate_klass = NULL; + MonoGCHandle target_handle = 0; + ERROR_DECL (wrapper_error); + m = mono_marshal_get_managed_wrapper (m, delegate_klass, target_handle, wrapper_error); + if (!is_ok (wrapper_error)) { + /* Generate a call that will throw an exception if the + * UnmanagedCallersOnly attribute is used incorrectly */ + interp_generate_ipe_throw_with_msg (td, wrapper_error); + mono_error_cleanup (wrapper_error); + interp_add_ins (td, MINT_LDNULL); + } else { + /* push a pointer to a trampoline that calls m */ + gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (m, TRUE, error); +#if SIZEOF_VOID_P == 8 + interp_add_ins (td, MINT_LDC_I8); + WRITE64_INS (td->last_ins, 0, &entry); +#else + interp_add_ins (td, MINT_LDC_I4); + WRITE32_INS (td->last_ins, 0, &entry); +#endif + } + td->ip += 5; + PUSH_SIMPLE_TYPE (td, STACK_TYPE_MP); + break; + } + interp_add_ins (td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN); td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); goto_if_nok (error, exit); diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 0cdc7a5..d4116aa 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -54,7 +54,12 @@ mono_ldftn (MonoMethod *method) return addr; } - addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error); + /* if we need the address of a native-to-managed wrapper, just compile it now, trampoline needs thread local + * variables that won't be there if we run on a thread that's not attached yet. */ + if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) + addr = mono_compile_method_checked (method, error); + else + addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error); if (!is_ok (error)) { mono_error_set_pending_exception (error); return NULL; @@ -1591,6 +1596,22 @@ mono_throw_bad_image () } void +mono_throw_not_supported () +{ + ERROR_DECL (error); + mono_error_set_generic_error (error, "System", "NotSupportedException", ""); + mono_error_set_pending_exception (error); +} + +void +mono_throw_invalid_program (const char *msg) +{ + ERROR_DECL (error); + mono_error_set_invalid_program (error, "Invalid IL due to: %s", msg); + mono_error_set_pending_exception (error); +} + +void mono_dummy_jit_icall (void) { } diff --git a/src/mono/mono/mini/jit-icalls.h b/src/mono/mono/mini/jit-icalls.h index 41ebae8..7de1133 100644 --- a/src/mono/mono/mini/jit-icalls.h +++ b/src/mono/mono/mini/jit-icalls.h @@ -223,6 +223,10 @@ ICALL_EXTERN_C void mono_throw_method_access (MonoMethod *caller, MonoMethod *ca ICALL_EXTERN_C void mono_throw_bad_image (void); +ICALL_EXTERN_C void mono_throw_not_supported (void); + +ICALL_EXTERN_C void mono_throw_invalid_program (const char *msg); + ICALL_EXTERN_C void mono_dummy_jit_icall (void); #endif /* __MONO_JIT_ICALLS_H__ */ diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 032d519..efcecb8 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -2307,6 +2307,25 @@ emit_bad_image_failure (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee mono_emit_jit_icall (cfg, mono_throw_bad_image, NULL); } +static void +emit_not_supported_failure (MonoCompile *cfg) +{ + mono_emit_jit_icall (cfg, mono_throw_not_supported, NULL); +} + +static void +emit_invalid_program_with_msg (MonoCompile *cfg, MonoError *error_msg, MonoMethod *caller, MonoMethod *callee) +{ + g_assert (!is_ok (error_msg)); + char *str = mono_mempool_strdup (cfg->domain->mp, mono_error_get_message (error_msg)); + MonoInst *iargs[1]; + if (cfg->compile_aot) + EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str); + else + EMIT_NEW_PCONST (cfg, iargs [0], str); + mono_emit_jit_icall (cfg, mono_throw_invalid_program, iargs); +} + // FIXME Consolidate the multiple functions named get_method_nofail. static MonoMethod* get_method_nofail (MonoClass *klass, const char *method_name, int num_params, int flags) @@ -11059,6 +11078,10 @@ mono_ldptr: if (mono_security_core_clr_enabled ()) ensure_method_is_allowed_to_call_method (cfg, method, cmethod); + const gboolean has_unmanaged_callers_only = + cmethod->wrapper_type == MONO_WRAPPER_NONE && + mono_method_has_unmanaged_callers_only_attribute (cmethod); + /* * Optimize the common case of ldftn+delegate creation */ @@ -11069,6 +11092,11 @@ mono_ldptr: MonoMethod *invoke; int invoke_context_used; + if (G_UNLIKELY (has_unmanaged_callers_only)) { + mono_error_set_not_supported (cfg->error, "Cannot create delegate from method with UnmanagedCallersOnlyAttribute"); + CHECK_CFG_ERROR; + } + invoke = mono_get_delegate_invoke_internal (ctor_method->klass); if (!invoke || !mono_method_signature_internal (invoke)) LOAD_ERROR; @@ -11106,6 +11134,38 @@ mono_ldptr: } } + /* UnmanagedCallersOnlyAttribute means ldftn should return a method callable from native */ + if (G_UNLIKELY (has_unmanaged_callers_only)) { + if (G_UNLIKELY (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { + // Follow CoreCLR, disallow [UnmanagedCallersOnly] and [DllImport] to be used + // together + emit_not_supported_failure (cfg); + EMIT_NEW_PCONST (cfg, ins, NULL); + *sp++ = ins; + inline_costs += CALL_COST * MIN(10, num_calls++); + break; + } + MonoClass *delegate_klass = NULL; + MonoGCHandle target_handle = 0; + ERROR_DECL (wrapper_error); + MonoMethod *wrapped_cmethod; + wrapped_cmethod = mono_marshal_get_managed_wrapper (cmethod, delegate_klass, target_handle, wrapper_error); + if (!is_ok (wrapper_error)) { + /* if we couldn't create a wrapper because cmethod isn't supposed to have an + UnmanagedCallersOnly attribute, follow CoreCLR behavior and throw when the + method with the ldftn is executing, not when it is being compiled. */ + emit_invalid_program_with_msg (cfg, wrapper_error, method, cmethod); + mono_error_cleanup (wrapper_error); + EMIT_NEW_PCONST (cfg, ins, NULL); + *sp++ = ins; + + inline_costs += CALL_COST * MIN(10, num_calls++); + break; + } else { + cmethod = wrapped_cmethod; + } + } + argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst); *sp++ = ins; diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 9d0adce..a1e1187 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -4887,6 +4887,8 @@ register_icalls (void) register_icall (mono_get_method_object, mono_icall_sig_object_ptr, TRUE); register_icall (mono_throw_method_access, mono_icall_sig_void_ptr_ptr, FALSE); register_icall (mono_throw_bad_image, mono_icall_sig_void, FALSE); + register_icall (mono_throw_not_supported, mono_icall_sig_void, FALSE); + register_icall (mono_throw_invalid_program, mono_icall_sig_void_ptr, FALSE); register_icall_no_wrapper (mono_dummy_jit_icall, mono_icall_sig_void); register_icall_with_wrapper (mono_monitor_enter_internal, mono_icall_sig_int32_obj);