diff mbox series

[RFC,v4,06/11] tcg: Add tcg opcodes and helpers for native library calls

Message ID 20230808141739.3110740-7-fufuyqqqqqq@gmail.com
State New
Headers show
Series Native Library Calls | expand

Commit Message

Yeqi Fu Aug. 8, 2023, 2:17 p.m. UTC
This commit implements tcg opcodes and helpers for extracting and
invoke native functions.

Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
---
 accel/tcg/tcg-runtime.h     |  22 ++++++
 include/tcg/tcg-op-common.h |  11 +++
 include/tcg/tcg.h           |   9 +++
 tcg/tcg-op.c                | 140 ++++++++++++++++++++++++++++++++++++
 4 files changed, 182 insertions(+)

Comments

Alex Bennée Aug. 9, 2023, 4:41 p.m. UTC | #1
Yeqi Fu <fufuyqqqqqq@gmail.com> writes:

> This commit implements tcg opcodes and helpers for extracting and
> invoke native functions.
>
> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
> ---
>  accel/tcg/tcg-runtime.h     |  22 ++++++
>  include/tcg/tcg-op-common.h |  11 +++
>  include/tcg/tcg.h           |   9 +++
>  tcg/tcg-op.c                | 140 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 182 insertions(+)
>
> diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
> index 39e68007f9..bda78b4489 100644
> --- a/accel/tcg/tcg-runtime.h
> +++ b/accel/tcg/tcg-runtime.h
> @@ -37,6 +37,28 @@ DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
>   */
>  #define helper_memset memset
>  DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
> +
> +#define helper_memcpy memcpy
> +DEF_HELPER_FLAGS_3(memcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
> +
> +#define helper_strncpy strncpy
> +DEF_HELPER_FLAGS_3(strncpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
> +
> +#define helper_memcmp memcmp
> +DEF_HELPER_FLAGS_3(memcmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
> +
> +#define helper_strncmp strncmp
> +DEF_HELPER_FLAGS_3(strncmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
> +
> +#define helper_strcpy strcpy
> +DEF_HELPER_FLAGS_2(strcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr)
> +
> +#define helper_strcat strcat
> +DEF_HELPER_FLAGS_2(strcat, TCG_CALL_NO_RWG, ptr, ptr, ptr)
> +
> +#define helper_strcmp strcmp
> +DEF_HELPER_FLAGS_2(strcmp, TCG_CALL_NO_RWG, int, ptr, ptr)
> +
>  #endif /* IN_HELPER_PROTO */
>  
>  DEF_HELPER_FLAGS_3(ld_i128, TCG_CALL_NO_WG, i128, env, i64, i32)
> diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
> index be382bbf77..2e712f1573 100644
> --- a/include/tcg/tcg-op-common.h
> +++ b/include/tcg/tcg-op-common.h
> @@ -903,6 +903,12 @@ void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
>  void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
>  void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
>  
> +/* Host <-> guest conversions */
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg);
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg);
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg);
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg);
> +
>  /* Host pointer ops */
>  
>  #if UINTPTR_MAX == UINT32_MAX
> @@ -938,6 +944,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
>      glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b);
>  }
>  
> +static inline void tcg_gen_subi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
> +{
> +    glue(tcg_gen_subi_, PTR)((NAT)r, (NAT)a, b);
> +}
> +
>  static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s)
>  {
>      glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s);
> diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
> index 0875971719..7c7fafb1cd 100644
> --- a/include/tcg/tcg.h
> +++ b/include/tcg/tcg.h
> @@ -35,6 +35,9 @@
>  #include "tcg-target.h"
>  #include "tcg/tcg-cond.h"
>  #include "tcg/debug-assert.h"
> +#ifdef CONFIG_USER_ONLY
> +#include "exec/user/guest-base.h"
> +#endif
>  
>  /* XXX: make safe guess about sizes */
>  #define MAX_OP_PER_INSTR 266
> @@ -1148,4 +1151,10 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
>  
>  bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
>  
> +/* native call */
> +void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
> +                         TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3);
> +void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
> +                         TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3);
> +
>  #endif /* TCG_H */
> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
> index 7aadb37756..83e3a5682c 100644
> --- a/tcg/tcg-op.c
> +++ b/tcg/tcg-op.c
> @@ -2852,3 +2852,143 @@ void tcg_gen_lookup_and_goto_ptr(void)
>      tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr));
>      tcg_temp_free_ptr(ptr);
>  }
> +
> +#ifdef CONFIG_USER_ONLY
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
> +{
> +    TCGv_ptr temp = tcg_temp_new_ptr();
> +    tcg_gen_ext_i32_ptr(temp, arg);
> +    tcg_gen_addi_ptr(ret, temp, guest_base);
> +    tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
> +{
> +    TCGv_ptr temp = tcg_temp_new_ptr();
> +    tcg_gen_trunc_i64_ptr(temp, arg); /* Not sure */
> +    tcg_gen_addi_ptr(ret, temp, guest_base);
> +    tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
> +{
> +    TCGv_ptr temp = tcg_temp_new_ptr();
> +    tcg_gen_subi_ptr(temp, arg, guest_base);
> +    tcg_gen_trunc_ptr_i32(ret, temp);
> +    tcg_temp_free_ptr(temp);
> +}
> +
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
> +{
> +    TCGv_ptr temp = tcg_temp_new_ptr();
> +    tcg_gen_subi_ptr(temp, arg, guest_base);
> +    tcg_gen_extu_ptr_i64(ret, temp);
> +    tcg_temp_free_ptr(temp);
> +}
> +
> +#else
> +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
> +{

It would be worth adding g_assert_not_reached() to these stubs so any
accidental call gets flagged straight away.

> +}
> +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
> +{
> +}
> +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
> +{
> +}
> +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
> +{
> +}
> +#endif
> +
> +/* p: iptr ; i: i32 ; a: ptr(address) */
> +void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
> +                         TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3)
> +{
> +    TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr ret_ptr = tcg_temp_new_ptr();
> +    tcg_gen_g2h_i32(arg1_ptr, arg1);
> +    if (strcmp(fun_name, "memset") == 0) {/* a aip */
> +        tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
> +        gen_helper_memset(ret_ptr, arg1_ptr, arg2, arg3_ptr);
> +        goto ret_ptr;
> +    }
> +    tcg_gen_g2h_i32(arg2_ptr, arg2);
> +    if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
> +        gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
> +        gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
> +        gen_helper_strcmp(ret, arg1_ptr, arg2_ptr);
> +    }
> +    tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
> +    if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
> +        gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
> +        gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
> +        gen_helper_memcmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
> +    } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
> +        gen_helper_strncmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
> +    }
> +    return;
> +ret_ptr:
> +    tcg_gen_h2g_i32(ret, ret_ptr);
> +    return;

This is a bit of a messy function considering that most of it is data
driven. I think we could have a table with something like:

   {
     { .func = "memset", .helper = gen_helper_memset,
       .g2h_arg1 = true },
     ...
   }

and then remove the duplication between the two gen_native_calls as
simply having different signatures for their g2h and h2h conversions. If
we ever get to embedding the signatures in the library that would make
things simpler to replace as well I think.


> +}
> +
> +void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
> +                         TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3)
> +{
> +    TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
> +    TCGv_ptr ret_ptr = tcg_temp_new_ptr();
> +    TCGv_i32 arg2_i32, ret_i32 = tcg_temp_new_i32();
> +    tcg_gen_g2h_i64(arg1_ptr, arg1);
> +    if (strcmp(fun_name, "memset") == 0) { /* a aip */
> +        arg2_i32 = tcg_temp_new_i32();
> +        tcg_gen_extrl_i64_i32(arg2_i32, arg2);
> +        tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
> +        gen_helper_memset(ret_ptr, arg1_ptr, arg2_i32, arg3_ptr);
> +        goto ret_ptr;
> +    }
> +    tcg_gen_g2h_i64(arg2_ptr, arg2);
> +    if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
> +        gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
> +        gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
> +        gen_helper_strcmp(ret_i32, arg1_ptr, arg2_ptr);
> +        goto ret_i32;
> +    }
> +    tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
> +    if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
> +        gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
> +        gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_ptr;
> +    } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
> +        gen_helper_memcmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_i32;
> +    } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
> +        gen_helper_strncmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
> +        goto ret_i32;
> +    }
> +    return;
> +ret_ptr:
> +    tcg_gen_h2g_i64(ret, ret_ptr);
> +    return;
> +ret_i32:
> +    tcg_gen_extu_i32_i64(ret, ret_i32);
> +    return;
> +}
diff mbox series

Patch

diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
index 39e68007f9..bda78b4489 100644
--- a/accel/tcg/tcg-runtime.h
+++ b/accel/tcg/tcg-runtime.h
@@ -37,6 +37,28 @@  DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
  */
 #define helper_memset memset
 DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
+
+#define helper_memcpy memcpy
+DEF_HELPER_FLAGS_3(memcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
+
+#define helper_strncpy strncpy
+DEF_HELPER_FLAGS_3(strncpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr)
+
+#define helper_memcmp memcmp
+DEF_HELPER_FLAGS_3(memcmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
+
+#define helper_strncmp strncmp
+DEF_HELPER_FLAGS_3(strncmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr)
+
+#define helper_strcpy strcpy
+DEF_HELPER_FLAGS_2(strcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr)
+
+#define helper_strcat strcat
+DEF_HELPER_FLAGS_2(strcat, TCG_CALL_NO_RWG, ptr, ptr, ptr)
+
+#define helper_strcmp strcmp
+DEF_HELPER_FLAGS_2(strcmp, TCG_CALL_NO_RWG, int, ptr, ptr)
+
 #endif /* IN_HELPER_PROTO */
 
 DEF_HELPER_FLAGS_3(ld_i128, TCG_CALL_NO_WG, i128, env, i64, i32)
diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index be382bbf77..2e712f1573 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -903,6 +903,12 @@  void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
 void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset);
 void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
 
+/* Host <-> guest conversions */
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg);
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg);
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg);
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg);
+
 /* Host pointer ops */
 
 #if UINTPTR_MAX == UINT32_MAX
@@ -938,6 +944,11 @@  static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
     glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b);
 }
 
+static inline void tcg_gen_subi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
+{
+    glue(tcg_gen_subi_, PTR)((NAT)r, (NAT)a, b);
+}
+
 static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s)
 {
     glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s);
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 0875971719..7c7fafb1cd 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -35,6 +35,9 @@ 
 #include "tcg-target.h"
 #include "tcg/tcg-cond.h"
 #include "tcg/debug-assert.h"
+#ifdef CONFIG_USER_ONLY
+#include "exec/user/guest-base.h"
+#endif
 
 /* XXX: make safe guess about sizes */
 #define MAX_OP_PER_INSTR 266
@@ -1148,4 +1151,10 @@  static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
 
 bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
 
+/* native call */
+void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
+                         TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3);
+void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
+                         TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3);
+
 #endif /* TCG_H */
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 7aadb37756..83e3a5682c 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2852,3 +2852,143 @@  void tcg_gen_lookup_and_goto_ptr(void)
     tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr));
     tcg_temp_free_ptr(ptr);
 }
+
+#ifdef CONFIG_USER_ONLY
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
+{
+    TCGv_ptr temp = tcg_temp_new_ptr();
+    tcg_gen_ext_i32_ptr(temp, arg);
+    tcg_gen_addi_ptr(ret, temp, guest_base);
+    tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
+{
+    TCGv_ptr temp = tcg_temp_new_ptr();
+    tcg_gen_trunc_i64_ptr(temp, arg); /* Not sure */
+    tcg_gen_addi_ptr(ret, temp, guest_base);
+    tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
+{
+    TCGv_ptr temp = tcg_temp_new_ptr();
+    tcg_gen_subi_ptr(temp, arg, guest_base);
+    tcg_gen_trunc_ptr_i32(ret, temp);
+    tcg_temp_free_ptr(temp);
+}
+
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
+{
+    TCGv_ptr temp = tcg_temp_new_ptr();
+    tcg_gen_subi_ptr(temp, arg, guest_base);
+    tcg_gen_extu_ptr_i64(ret, temp);
+    tcg_temp_free_ptr(temp);
+}
+
+#else
+void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg)
+{
+}
+void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg)
+{
+}
+void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg)
+{
+}
+void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg)
+{
+}
+#endif
+
+/* p: iptr ; i: i32 ; a: ptr(address) */
+void gen_native_call_i32(const char *fun_name, TCGv_i32 ret,
+                         TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3)
+{
+    TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
+    TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
+    TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
+    TCGv_ptr ret_ptr = tcg_temp_new_ptr();
+    tcg_gen_g2h_i32(arg1_ptr, arg1);
+    if (strcmp(fun_name, "memset") == 0) {/* a aip */
+        tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
+        gen_helper_memset(ret_ptr, arg1_ptr, arg2, arg3_ptr);
+        goto ret_ptr;
+    }
+    tcg_gen_g2h_i32(arg2_ptr, arg2);
+    if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
+        gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
+        gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
+        gen_helper_strcmp(ret, arg1_ptr, arg2_ptr);
+    }
+    tcg_gen_ext_i32_ptr(arg3_ptr, arg3);
+    if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
+        gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
+        gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
+        gen_helper_memcmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
+    } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
+        gen_helper_strncmp(ret, arg1_ptr, arg2_ptr, arg3_ptr);
+    }
+    return;
+ret_ptr:
+    tcg_gen_h2g_i32(ret, ret_ptr);
+    return;
+}
+
+void gen_native_call_i64(const char *fun_name, TCGv_i64 ret,
+                         TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3)
+{
+    TCGv_ptr arg1_ptr = tcg_temp_new_ptr();
+    TCGv_ptr arg2_ptr = tcg_temp_new_ptr();
+    TCGv_ptr arg3_ptr = tcg_temp_new_ptr();
+    TCGv_ptr ret_ptr = tcg_temp_new_ptr();
+    TCGv_i32 arg2_i32, ret_i32 = tcg_temp_new_i32();
+    tcg_gen_g2h_i64(arg1_ptr, arg1);
+    if (strcmp(fun_name, "memset") == 0) { /* a aip */
+        arg2_i32 = tcg_temp_new_i32();
+        tcg_gen_extrl_i64_i32(arg2_i32, arg2);
+        tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
+        gen_helper_memset(ret_ptr, arg1_ptr, arg2_i32, arg3_ptr);
+        goto ret_ptr;
+    }
+    tcg_gen_g2h_i64(arg2_ptr, arg2);
+    if (strcmp(fun_name, "strcpy") == 0) { /* a aa */
+        gen_helper_strcpy(ret_ptr, arg1_ptr, arg2_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strcat") == 0) { /* a aa */
+        gen_helper_strcat(ret_ptr, arg1_ptr, arg2_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strcmp") == 0) { /* i aa */
+        gen_helper_strcmp(ret_i32, arg1_ptr, arg2_ptr);
+        goto ret_i32;
+    }
+    tcg_gen_trunc_i64_ptr(arg3_ptr, arg3);
+    if (strcmp(fun_name, "memcpy") == 0) { /* a aap */
+        gen_helper_memcpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "strncpy") == 0) { /* a aap */
+        gen_helper_strncpy(ret_ptr, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_ptr;
+    } else if (strcmp(fun_name, "memcmp") == 0) { /* i aap */
+        gen_helper_memcmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_i32;
+    } else if (strcmp(fun_name, "strncmp") == 0) { /* i aap */
+        gen_helper_strncmp(ret_i32, arg1_ptr, arg2_ptr, arg3_ptr);
+        goto ret_i32;
+    }
+    return;
+ret_ptr:
+    tcg_gen_h2g_i64(ret, ret_ptr);
+    return;
+ret_i32:
+    tcg_gen_extu_i32_i64(ret, ret_i32);
+    return;
+}