Hi.

I have been using a mix of a library compiled by TCC and
an executable compiled by GCC on a linux/x86-64 platform,
this worked great until I ran into an ABI mismatch.

When returning bool, char or short GCC does not clear the
upper bits of the eax register. But TCC assumes these bits
are cleared.

I have attached a small bash script which illustrates this
difference, and two patches.

The bash script creates a shared library compiled using GCC
and two executables one compiled by TCC and another by GCC
that use the library. They call some test functions from
the library and print the results.

The first patch expands bool/char/short return values to int
for the x86-64 target. This is essentially a duplicate of the
code that was already present for the PE target [1].

The second patch adds an extra case to handle this expansion
for bools for the PE target. I have not tested this, but
noticed it was missing.

Regards,
Mart Gerrits

1. http://repo.or.cz/tinycc.git/blob/d348a9a5:/x86_64-gen.c#l930

Attachment: test.sh
Description: application/shellscript

>From f97535755751db471232360f403d6aed185b9e9d Mon Sep 17 00:00:00 2001
From: Mart Gerrits <address@hidden>
Date: Sun, 15 Apr 2018 19:50:17 +0200
Subject: [PATCH 1/2] x86-64: expand bool/char/short return values to int

---
 x86_64-gen.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/x86_64-gen.c b/x86_64-gen.c
index e33a38a..199a74f 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -1237,7 +1237,7 @@ void gfunc_call(int nb_args)
 {
     X86_64_Mode mode;
     CType type;
-    int size, align, r, args_size, stack_adjust, i, reg_count;
+    int size, align, r, args_size, stack_adjust, i, reg_count, bt;
     int nb_reg_args = 0;
     int nb_sse_args = 0;
     int sse_reg, gen_reg;
@@ -1420,6 +1420,20 @@ void gfunc_call(int nb_args)
     gcall_or_jmp(0);
     if (args_size)
         gadd_sp(args_size);
+
+    /* other compilers don't clear the upper bits when returning bool/char/short  */
+    bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
+    if (bt == (VT_BYTE | VT_UNSIGNED))
+        o(0xc0b60f);  /* movzbl %al, %eax */
+    else if(bt == VT_BOOL)
+        o(0xc0b60f);  /* movzbl %al, %eax */
+    else if (bt == VT_BYTE)
+        o(0xc0be0f); /* movsbl %al, %eax */
+    else if (bt == VT_SHORT)
+        o(0x98); /* cwtl */
+    else if (bt == (VT_SHORT | VT_UNSIGNED))
+        o(0xc0b70f);  /* movzbl %al, %eax */
+
     vtop--;
 }
 
-- 
2.16.3

>From 62c5b02b46c7c7b23a54d6aa1c1316c620d6b370 Mon Sep 17 00:00:00 2001
From: Mart Gerrits <address@hidden>
Date: Sun, 15 Apr 2018 19:20:32 +0200
Subject: [PATCH 2/2] x86-64: expand bool return values to int for PE target

---
 x86_64-gen.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/x86_64-gen.c b/x86_64-gen.c
index 199a74f..44cb70c 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -927,10 +927,12 @@ void gfunc_call(int nb_args)
         o(0x0548), gen_le32(func_alloca), func_alloca = ind - 4;
     }
 
-    /* other compilers don't clear the upper bits when returning char/short */
+    /* other compilers don't clear the upper bits when returning bool/char/short */
     bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
     if (bt == (VT_BYTE | VT_UNSIGNED))
         o(0xc0b60f);  /* movzbl %al, %eax */
+    else if(bt == VT_BOOL)
+        o(0xc0b60f);  /* movzbl %al, %eax */
     else if (bt == VT_BYTE)
         o(0xc0be0f); /* movsbl %al, %eax */
     else if (bt == VT_SHORT)
-- 
2.16.3

_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to