]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Add the beginnings of a C++ name mangler, to help with extracting
authorRhys Weatherley <rweather@southern-storm.com.au>
Mon, 3 May 2004 06:32:22 +0000 (06:32 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Mon, 3 May 2004 06:32:22 +0000 (06:32 +0000)
C++ symbols from dynamic shared libraries.

ChangeLog
jit/Makefile.am
jit/jit-mangle.c [new file with mode: 0644]

index decc427e3171761611c2485ba5e312b04b560d93..05a2a0d7b2777f9bdfbe5d7b5df5ec027fae3b85 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        types so that they can be distinguished from the fixed-sized types
        when it is necessary to do so.
 
+       * jit/Makefile.am, jit/jit-mangle.c: add the beginnings of a C++
+       name mangler, to help with extracting C++ symbols from dynamic
+       shared libraries.
+
 2004-05-01  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * jit/jit-apply-x86.c, jit/jit-rules-x86.c, tools/gen-apply.c:
index 100213404c85dcd833cb5a3276d4f03d6cc47f9d..f11f9d68a2e7ef0397ba6ff1e4c4e2ee75deb012 100644 (file)
@@ -28,6 +28,7 @@ libjit_a_SOURCES = \
                jit-interp.cpp \
                jit-intrinsic.c \
                jit-live.c \
+               jit-mangle.c \
                jit-memory.c \
                jit-memory.h \
                jit-meta.c \
diff --git a/jit/jit-mangle.c b/jit/jit-mangle.c
new file mode 100644 (file)
index 0000000..ad19bcc
--- /dev/null
@@ -0,0 +1,1082 @@
+/*
+ * jit-mangle.c - Perform C++ name mangling.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "jit-internal.h"
+#include <config.h>
+#include <stdio.h>
+
+/*@
+
+@cindex jit-mangle.h
+
+Sometimes you want to retrieve a C++ method from a dynamic library
+using @code{jit_dynlib_get_symbol}.  Unfortunately, C++ name mangling
+rules differ from one system to another, making this process very
+error-prone.
+
+The functions that follow try to help.  They aren't necessarily fool-proof,
+but they should work in the most common cases.  The only alternative is
+to wrap your C++ library with C functions, so that the names are predictable.
+
+The basic idea is that you supply a description of the C++ method that
+you wish to access, and these functions return a number of candidate forms
+that you can try with @code{jit_dynlib_get_symbol}.  If one form fails,
+you move on and try the next form, until either symbol lookup succeeds
+or until all forms have been exhausted.
+
+@noindent
+The following code demonstrates how to resolve a global function:
+
+@example
+jit_dynlib_handle_t handle;
+jit_type_t signature;
+int form = 0;
+void *address = 0;
+char *mangled;
+
+while((mangled = jit_mangle_global_function
+             ("foo", signature, form)) != 0)
+@{
+    address = jit_dynlib_get_symbol(handle, mangled);
+    if(address != 0)
+    @{
+        break;
+    @}
+    jit_free(mangled);
+    ++form;
+@}
+
+if(address)
+@{
+    printf("%s = 0x%lx\n", mangled, (long)address);
+@}
+else
+@{
+    printf("could not resolve foo\n");
+@}
+@end example
+
+This mechanism typically cannot be used to obtain the entry points for
+@code{inline} methods.  You will need to make other arrangements to
+simulate the behaviour of inline methods, or recompile your dynamic C++
+library in a mode that explicitly exports inlines.
+
+C++ method names are very picky about types.  On 32-bit systems,
+@code{int} and @code{long} are the same size, but they are mangled
+to different characters.  To ensure that the correct function is
+picked, you should use @code{jit_type_sys_int}, @code{jit_type_sys_long}, etc
+instead of the platform independent types.  If you do use a platform
+independent type like @code{jit_type_int}, this library will try to
+guess which system type you mean, but the guess will most likely be wrong.
+
+@*/
+
+/*
+ * Useful encoding characters.
+ */
+static char const hexchars[16] = "0123456789ABCDEF";
+
+/*
+ * Name mangling output context.
+ */
+typedef struct jit_mangler *jit_mangler_t;
+struct jit_mangler
+{
+       char               *buf;
+       unsigned int    buf_len;
+       unsigned int    buf_max;
+       int                             out_of_memory;
+};
+
+/*
+ * Initialize a mangling context.
+ */
+static void init_mangler(jit_mangler_t mangler)
+{
+       mangler->buf = 0;
+       mangler->buf_len = 0;
+       mangler->buf_max = 0;
+       mangler->out_of_memory = 0;
+}
+
+/*
+ * End a mangling operation, and return the final string.
+ */
+static char *end_mangler(jit_mangler_t mangler)
+{
+       if(!(mangler->buf) || mangler->out_of_memory)
+       {
+               jit_free(mangler->buf);
+               return 0;
+       }
+       return mangler->buf;
+}
+
+/*
+ * Add a character to a mangling buffer.
+ */
+static void add_ch(jit_mangler_t mangler, int ch)
+{
+       char *new_buf;
+       if(mangler->buf_len >= mangler->buf_max)
+       {
+               if(mangler->out_of_memory)
+               {
+                       return;
+               }
+               new_buf = (char *)jit_realloc
+                       (mangler->buf, mangler->buf_len + 32);
+               if(!new_buf)
+               {
+                       mangler->out_of_memory = 1;
+                       return;
+               }
+               mangler->buf = new_buf;
+               mangler->buf_max += 32;
+       }
+       mangler->buf[(mangler->buf_len)++] = (char)ch;
+}
+
+/*
+ * Add a string to a mangling buffer.
+ */
+static void add_string(jit_mangler_t mangler, const char *str)
+{
+       while(*str != '\0')
+       {
+               add_ch(mangler, *str++);
+       }
+}
+
+/*
+ * Add a length-prefixed string to a mangling buffer.
+ */
+static void add_len_string(jit_mangler_t mangler, const char *str)
+{
+       char buf[32];
+       sprintf(buf, "%u", jit_strlen(str));
+       add_string(mangler, buf);
+       add_string(mangler, str);
+}
+
+/*
+ * Get a system integer type of a particular size.
+ */
+static jit_type_t get_system_type(jit_type_t type, int size, int is_signed)
+{
+       if(size == sizeof(int))
+       {
+               if(is_signed)
+                       return jit_type_sys_int;
+               else
+                       return jit_type_sys_uint;
+       }
+       else if(size == sizeof(long))
+       {
+               if(is_signed)
+                       return jit_type_sys_long;
+               else
+                       return jit_type_sys_ulong;
+       }
+       else if(size == sizeof(jit_long))
+       {
+               if(is_signed)
+                       return jit_type_sys_longlong;
+               else
+                       return jit_type_sys_ulonglong;
+       }
+       else if(size == sizeof(short))
+       {
+               if(is_signed)
+                       return jit_type_sys_short;
+               else
+                       return jit_type_sys_ushort;
+       }
+       else if(size == sizeof(char))
+       {
+       #ifdef __CHAR_UNSIGNED__
+               if(is_signed)
+                       return jit_type_sys_schar;
+               else
+                       return jit_type_sys_char;
+       #else
+               if(is_signed)
+                       return jit_type_sys_char;
+               else
+                       return jit_type_sys_uchar;
+       #endif
+       }
+       else
+       {
+               return type;
+       }
+}
+
+/*
+ * Convert a fixed-sized integer type into a system-specific type.
+ */
+static jit_type_t fix_system_types(jit_type_t type)
+{
+       if(!type)
+       {
+               return 0;
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_SBYTE:
+                       return get_system_type(type, sizeof(jit_sbyte), 1);
+               case JIT_TYPE_UBYTE:
+                       return get_system_type(type, sizeof(jit_ubyte), 0);
+               case JIT_TYPE_SHORT:
+                       return get_system_type(type, sizeof(jit_short), 1);
+               case JIT_TYPE_USHORT:
+                       return get_system_type(type, sizeof(jit_ushort), 0);
+               case JIT_TYPE_INT:
+                       return get_system_type(type, sizeof(jit_int), 1);
+               case JIT_TYPE_UINT:
+                       return get_system_type(type, sizeof(jit_uint), 0);
+               case JIT_TYPE_NINT:
+                       return get_system_type(type, sizeof(jit_nint), 1);
+               case JIT_TYPE_NUINT:
+                       return get_system_type(type, sizeof(jit_nuint), 0);
+               case JIT_TYPE_LONG:
+                       return get_system_type(type, sizeof(jit_long), 1);
+               case JIT_TYPE_ULONG:
+                       return get_system_type(type, sizeof(jit_long), 0);
+       }
+       return type;
+}
+
+/*
+ * Determine if a type is an unsigned integer value.
+ */
+static int is_unsigned(jit_type_t type)
+{
+       type = jit_type_remove_tags(type);
+       if(type)
+       {
+               if(type->kind == JIT_TYPE_UBYTE ||
+                  type->kind == JIT_TYPE_USHORT ||
+                  type->kind == JIT_TYPE_UINT ||
+                  type->kind == JIT_TYPE_NUINT ||
+                  type->kind == JIT_TYPE_ULONG)
+               {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Forward declarations.
+ */
+static void mangle_type_gcc2(jit_mangler_t mangler, jit_type_t type);
+static void mangle_type_gcc3(jit_mangler_t mangler, jit_type_t type);
+
+/*
+ * Mangle a function signature, using gcc 2.x rules.
+ */
+static void mangle_signature_gcc2(jit_mangler_t mangler, jit_type_t type)
+{
+       unsigned int num_params;
+       unsigned int param;
+       num_params = jit_type_num_params(type);
+       if(num_params == 0 && jit_type_get_abi(type) != jit_abi_vararg)
+       {
+               add_ch(mangler, 'v');
+       }
+       for(param = 0; param < num_params; ++param)
+       {
+               mangle_type_gcc2(mangler, jit_type_get_param(type, param));
+       }
+       if(jit_type_get_abi(type) == jit_abi_vararg)
+       {
+               add_ch(mangler, 'e');
+       }
+}
+
+/*
+ * Mangle a type, using gcc 2.x rules.
+ */
+static void mangle_type_gcc2(jit_mangler_t mangler, jit_type_t type)
+{
+       int kind;
+
+       /* Bail out if the type is invalid */
+       if(!type)
+       {
+               return;
+       }
+
+       /* Handle "const", "unsigned", "volatile", and "restrict" prefixes */
+       if(jit_type_has_tag(type, JIT_TYPETAG_CONST))
+       {
+               add_ch(mangler, 'C');
+       }
+       if(is_unsigned(type) && !jit_type_has_tag(type, JIT_TYPETAG_SYS_CHAR))
+       {
+               add_ch(mangler, 'U');
+       }
+       if(jit_type_has_tag(type, JIT_TYPETAG_VOLATILE))
+       {
+               add_ch(mangler, 'V');
+       }
+       if(jit_type_has_tag(type, JIT_TYPETAG_RESTRICT))
+       {
+               add_ch(mangler, 'u');
+       }
+
+       /* Strip the prefixes that we just output, together with tag kinds
+          that we don't handle specially ourselves */
+       while(jit_type_is_tagged(type))
+       {
+               kind = jit_type_get_tagged_kind(type);
+               if(kind == JIT_TYPETAG_CONST ||
+                  kind == JIT_TYPETAG_VOLATILE ||
+                  kind == JIT_TYPETAG_RESTRICT)
+               {
+                       type = jit_type_get_tagged_type(type);
+               }
+               else if(kind < JIT_TYPETAG_NAME ||
+                               kind > JIT_TYPETAG_SYS_LONGDOUBLE)
+               {
+                       type = jit_type_get_tagged_type(type);
+               }
+               else
+               {
+                       break;
+               }
+       }
+
+       /* Handle the inner-most part of the type */
+       if(type->kind >= JIT_TYPE_SBYTE && type->kind <= JIT_TYPE_ULONG)
+       {
+               type = fix_system_types(type);
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_VOID:                     add_ch(mangler, 'v'); break;
+
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       /* Will only happen if the primitive numeric type
+                          does not correspond to one of the system types */
+                       jit_nuint size = jit_type_get_size(type);
+                       add_ch(mangler, 'I');
+                       add_ch(mangler, hexchars[(size >> 4) & 0x0F]);
+                       add_ch(mangler, hexchars[size & 0x0F]);
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:          add_ch(mangler, 'f'); break;
+               case JIT_TYPE_FLOAT64:          add_ch(mangler, 'd'); break;
+       #ifdef JIT_NFLOAT_IS_DOUBLE
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'd'); break;
+       #else
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'r'); break;
+       #endif
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       /* These should have been tagged with a name */
+                       add_ch(mangler, '?');
+               }
+               break;
+
+               case JIT_TYPE_SIGNATURE:
+               {
+                       add_ch(mangler, 'F');
+                       mangle_signature_gcc2(mangler, type);
+                       add_ch(mangler, '_');
+                       mangle_type_gcc2(mangler, jit_type_get_return(type));
+               }
+               break;
+
+               case JIT_TYPE_PTR:
+               {
+                       add_ch(mangler, 'P');
+                       mangle_type_gcc2(mangler, jit_type_get_ref(type));
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_NAME:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_STRUCT_NAME:
+               {
+                       /* Output the qualified name of the type */
+                       /* TODO */
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_REFERENCE:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_OUTPUT:
+               {
+                       add_ch(mangler, 'R');
+                       mangle_type_gcc2
+                               (mangler, jit_type_get_ref(jit_type_remove_tags(type)));
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_BOOL:
+                       add_ch(mangler, 'b'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_CHAR:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UCHAR:
+                       add_ch(mangler, 'c'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SCHAR:
+                       add_ch(mangler, 'S');
+                       add_ch(mangler, 'c'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SHORT:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_USHORT:
+                       add_ch(mangler, 's'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_INT:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UINT:
+                       add_ch(mangler, 'i'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONG:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONG:
+                       add_ch(mangler, 'l'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGLONG:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONGLONG:
+                       add_ch(mangler, 'x'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_FLOAT:
+                       add_ch(mangler, 'f'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_DOUBLE:
+                       add_ch(mangler, 'd'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGDOUBLE:
+                       add_ch(mangler, 'r'); break;
+
+               default: break;
+       }
+}
+
+/*
+ * Mangle a function signature, using gcc 3.x rules.
+ */
+static void mangle_signature_gcc3(jit_mangler_t mangler, jit_type_t type)
+{
+       unsigned int num_params;
+       unsigned int param;
+       num_params = jit_type_num_params(type);
+       if(num_params == 0 && jit_type_get_abi(type) != jit_abi_vararg)
+       {
+               add_ch(mangler, 'v');
+       }
+       for(param = 0; param < num_params; ++param)
+       {
+               mangle_type_gcc3(mangler, jit_type_get_param(type, param));
+       }
+       if(jit_type_get_abi(type) == jit_abi_vararg)
+       {
+               add_ch(mangler, 'z');
+       }
+}
+
+/*
+ * Mangle a type, using gcc 3.x rules.
+ */
+static void mangle_type_gcc3(jit_mangler_t mangler, jit_type_t type)
+{
+       int kind;
+
+       /* Bail out if the type is invalid */
+       if(!type)
+       {
+               return;
+       }
+
+       /* Handle "const", "volatile", and "restrict" prefixes */
+       if(jit_type_has_tag(type, JIT_TYPETAG_RESTRICT))
+       {
+               add_ch(mangler, 'r');
+       }
+       if(jit_type_has_tag(type, JIT_TYPETAG_VOLATILE))
+       {
+               add_ch(mangler, 'V');
+       }
+       if(jit_type_has_tag(type, JIT_TYPETAG_CONST))
+       {
+               add_ch(mangler, 'K');
+       }
+
+       /* Strip the prefixes that we just output, together with tag kinds
+          that we don't handle specially ourselves */
+       while(jit_type_is_tagged(type))
+       {
+               kind = jit_type_get_tagged_kind(type);
+               if(kind == JIT_TYPETAG_CONST ||
+                  kind == JIT_TYPETAG_VOLATILE ||
+                  kind == JIT_TYPETAG_RESTRICT)
+               {
+                       type = jit_type_get_tagged_type(type);
+               }
+               else if(kind < JIT_TYPETAG_NAME ||
+                               kind > JIT_TYPETAG_SYS_LONGDOUBLE)
+               {
+                       type = jit_type_get_tagged_type(type);
+               }
+               else
+               {
+                       break;
+               }
+       }
+
+       /* Handle the inner-most part of the type */
+       if(type->kind >= JIT_TYPE_SBYTE && type->kind <= JIT_TYPE_ULONG)
+       {
+               type = fix_system_types(type);
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_VOID:                     add_ch(mangler, 'v'); break;
+
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       /* Will only happen if the primitive numeric type
+                          does not correspond to one of the system types */
+                       jit_nuint size = jit_type_get_size(type);
+                       if(is_unsigned)
+                               add_string(mangler, "uU");
+                       else
+                               add_string(mangler, "uI");
+                       add_ch(mangler, hexchars[(size >> 4) & 0x0F]);
+                       add_ch(mangler, hexchars[size & 0x0F]);
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:          add_ch(mangler, 'f'); break;
+               case JIT_TYPE_FLOAT64:          add_ch(mangler, 'd'); break;
+       #ifdef JIT_NFLOAT_IS_DOUBLE
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'd'); break;
+       #else
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'e'); break;
+       #endif
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       /* These should have been tagged with a name */
+                       add_ch(mangler, '?');
+               }
+               break;
+
+               case JIT_TYPE_SIGNATURE:
+               {
+                       add_ch(mangler, 'F');
+                       mangle_type_gcc3(mangler, jit_type_get_return(type));
+                       mangle_signature_gcc3(mangler, type);
+                       add_ch(mangler, 'E');
+               }
+               break;
+
+               case JIT_TYPE_PTR:
+               {
+                       add_ch(mangler, 'P');
+                       mangle_type_gcc3(mangler, jit_type_get_ref(type));
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_NAME:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_STRUCT_NAME:
+               {
+                       /* Output the qualified name of the type */
+                       /* TODO */
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_REFERENCE:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_OUTPUT:
+               {
+                       add_ch(mangler, 'R');
+                       mangle_type_gcc3
+                               (mangler, jit_type_get_ref(jit_type_remove_tags(type)));
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_BOOL:
+                       add_ch(mangler, 'b'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_CHAR:
+                       add_ch(mangler, 'c'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SCHAR:
+                       add_ch(mangler, 'a'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UCHAR:
+                       add_ch(mangler, 'h'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SHORT:
+                       add_ch(mangler, 's'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_USHORT:
+                       add_ch(mangler, 't'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_INT:
+                       add_ch(mangler, 'i'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UINT:
+                       add_ch(mangler, 'j'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONG:
+                       add_ch(mangler, 'l'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONG:
+                       add_ch(mangler, 'm'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGLONG:
+                       add_ch(mangler, 'x'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONGLONG:
+                       add_ch(mangler, 'y'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_FLOAT:
+                       add_ch(mangler, 'f'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_DOUBLE:
+                       add_ch(mangler, 'd'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGDOUBLE:
+                       add_ch(mangler, 'e'); break;
+
+               default: break;
+       }
+}
+
+#if defined(JIT_WIN32_PLATFORM)
+
+/*
+ * Forward declaration.
+ */
+static void mangle_type_msvc6(jit_mangler_t mangler, jit_type_t type);
+
+/*
+ * Mangle a function signature, using MSVC 6.0 rules.
+ */
+static void mangle_signature_msvc6(jit_mangler_t mangler, jit_type_t type,
+                                                                  int output_return, int is_this_call,
+                                                                  int has_explicit_this)
+{
+       unsigned int num_params;
+       unsigned int param;
+       jit_abi_t abi = jit_type_get_abi(type);
+       if(is_this_call)
+       {
+               add_ch(mangler, 'E');
+       }
+       else if(abi == jit_abi_stdcall)
+       {
+               add_ch(mangler, 'G');
+       }
+       else if(abi == jit_abi_fastcall)
+       {
+               add_ch(mangler, 'I');
+       }
+       else
+       {
+               add_ch(mangler, 'A');
+       }
+       if(output_return)
+       {
+               /* Ordinary function with an explicit return type */
+               mangle_type_msvc6(mangler, jit_type_get_return(type));
+       }
+       else
+       {
+               /* Constructor or destructor, with no explicit return type */
+               add_ch(mangler, '@');
+       }
+       num_params = jit_type_num_params(type);
+       if(num_params == 0 && abi != jit_abi_vararg)
+       {
+               add_ch(mangler, 'X');
+               add_ch(mangler, 'Z');
+               return;
+       }
+       for(param = (has_explicit_this ? 1 : 0); param < num_params; ++param)
+       {
+               mangle_type_msvc6(mangler, jit_type_get_param(type, param));
+       }
+       if(abi == jit_abi_vararg)
+       {
+               add_ch(mangler, 'Z');
+               add_ch(mangler, 'Z');
+       }
+       else
+       {
+               add_ch(mangler, '@');
+               add_ch(mangler, 'Z');
+       }
+}
+
+/*
+ * Mangle a type, using MSVC 6.0 rules.
+ */
+static void mangle_type_msvc6(jit_mangler_t mangler, jit_type_t type)
+{
+       int kind;
+       jit_type_t sub_type;
+
+       /* Bail out if the type is invalid */
+       if(!type)
+       {
+               return;
+       }
+
+       /* Strip tag kinds that we don't handle specially ourselves */
+       while(jit_type_is_tagged(type))
+       {
+               kind = jit_type_get_tagged_kind(type);
+               if(kind < JIT_TYPETAG_NAME ||
+                  kind > JIT_TYPETAG_SYS_LONGDOUBLE)
+               {
+                       type = jit_type_get_tagged_type(type);
+               }
+               else
+               {
+                       break;
+               }
+       }
+
+       /* Handle the inner-most part of the type */
+       if(type->kind >= JIT_TYPE_SBYTE && type->kind <= JIT_TYPE_ULONG)
+       {
+               type = fix_system_types(type);
+       }
+       switch(type->kind)
+       {
+               case JIT_TYPE_VOID:                     add_ch(mangler, 'X'); break;
+
+               case JIT_TYPE_SBYTE:
+               case JIT_TYPE_UBYTE:
+               case JIT_TYPE_SHORT:
+               case JIT_TYPE_USHORT:
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_LONG:
+               case JIT_TYPE_ULONG:
+               {
+                       /* Shouldn't happen, as "fix_system_types" resolved them above */
+               }
+               break;
+
+               case JIT_TYPE_FLOAT32:          add_ch(mangler, 'M'); break;
+               case JIT_TYPE_FLOAT64:          add_ch(mangler, 'N'); break;
+       #ifdef JIT_NFLOAT_IS_DOUBLE
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'N'); break;
+       #else
+               case JIT_TYPE_NFLOAT:           add_ch(mangler, 'O'); break;
+       #endif
+
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       /* These should have been tagged with a name */
+                       add_ch(mangler, '?');
+               }
+               break;
+
+               case JIT_TYPE_SIGNATURE:
+               {
+                       add_string(mangler, "P6");
+                       mangle_signature_msvc6(mangler, type, 1, 0, 0);
+               }
+               break;
+
+               case JIT_TYPE_PTR:
+               {
+                       add_ch(mangler, 'P');
+                       sub_type = jit_type_get_ref(type);
+                       if(jit_type_has_tag(sub_type, JIT_TYPETAG_CONST))
+                       {
+                               if(jit_type_has_tag(sub_type, JIT_TYPETAG_VOLATILE))
+                               {
+                                       add_ch(mangler, 'D');
+                               }
+                               else
+                               {
+                                       add_ch(mangler, 'B');
+                               }
+                       }
+                       else if(jit_type_has_tag(sub_type, JIT_TYPETAG_VOLATILE))
+                       {
+                               add_ch(mangler, 'C');
+                       }
+                       else
+                       {
+                               add_ch(mangler, 'A');
+                       }
+                       mangle_type_msvc6(mangler, sub_type);
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_NAME:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_STRUCT_NAME:
+               {
+                       /* Output the qualified name of the type */
+                       /* TODO */
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_REFERENCE:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_OUTPUT:
+               {
+                       add_ch(mangler, 'A');
+                       sub_type = jit_type_get_ref(jit_type_remove_tags(type));
+                       if(jit_type_has_tag(sub_type, JIT_TYPETAG_CONST))
+                       {
+                               if(jit_type_has_tag(sub_type, JIT_TYPETAG_VOLATILE))
+                               {
+                                       add_ch(mangler, 'D');
+                               }
+                               else
+                               {
+                                       add_ch(mangler, 'B');
+                               }
+                       }
+                       else if(jit_type_has_tag(sub_type, JIT_TYPETAG_VOLATILE))
+                       {
+                               add_ch(mangler, 'C');
+                       }
+                       else
+                       {
+                               add_ch(mangler, 'A');
+                       }
+                       mangle_type_msvc6(mangler, sub_type);
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_CONST:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_VOLATILE:
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_RESTRICT:
+               {
+                       /* These are handled in the pointer and reference cases */
+                       mangle_type_msvc6(mangler, jit_type_get_tagged_type(type));
+               }
+               break;
+
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_BOOL:
+                       add_ch(mangler, 'D'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_CHAR:
+                       add_ch(mangler, 'D'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SCHAR:
+                       add_ch(mangler, 'C'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UCHAR:
+                       add_ch(mangler, 'E'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_SHORT:
+                       add_ch(mangler, 'F'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_USHORT:
+                       add_ch(mangler, 'G'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_INT:
+                       add_ch(mangler, 'H'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_UINT:
+                       add_ch(mangler, 'I'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONG:
+                       add_ch(mangler, 'J'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONG:
+                       add_ch(mangler, 'K'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGLONG:
+                       add_string(mangler, "_J"); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_ULONGLONG:
+                       add_string(mangler, "_K"); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_FLOAT:
+                       add_ch(mangler, 'M'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_DOUBLE:
+                       add_ch(mangler, 'N'); break;
+               case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_SYS_LONGDOUBLE:
+                       add_ch(mangler, 'O'); break;
+
+               default: break;
+       }
+}
+
+#endif /* JIT_WIN32_PLATFORM */
+
+/*
+ * Name mangling forms, in the order in which they should be tried.
+ * We try to arrange for the most likely to be tried first.
+ */
+#if defined(JIT_WIN32_PLATFORM)
+       #define MANGLING_FORM_MSVC_6            0
+       #if defined(__GNUC__) && (__GNUC__ >= 3)
+               #define MANGLING_FORM_GCC_3             1
+               #define MANGLING_FORM_GCC_2             2
+       #else
+               #define MANGLING_FORM_GCC_2             1
+               #define MANGLING_FORM_GCC_3             2
+       #endif
+#elif defined(__GNUC__) && (__GNUC__ >= 3)
+       #define MANGLING_FORM_GCC_3                     0
+       #define MANGLING_FORM_GCC_2                     1
+#else
+       #define MANGLING_FORM_GCC_2                     0
+       #define MANGLING_FORM_GCC_3                     1
+#endif
+
+/*@
+ * @deftypefun {char *} jit_mangle_global_function ({const char *} name, jit_type_t signature, int form)
+ * Mangle the name of a global C++ function using the specified @code{form}.
+ * Returns NULL if out of memory, or if the form is not supported.
+ * @end deftypefun
+@*/
+char *jit_mangle_global_function
+       (const char *name, jit_type_t signature, int form)
+{
+       struct jit_mangler mangler;
+       init_mangler(&mangler);
+       switch(form)
+       {
+       #ifdef MANGLING_FORM_GCC_2
+               case MANGLING_FORM_GCC_2:
+               {
+                       add_string(&mangler, name);
+                       add_string(&mangler, "__F");
+                       mangle_signature_gcc2(&mangler, signature);
+               }
+               break;
+       #endif
+
+       #ifdef MANGLING_FORM_GCC_3
+               case MANGLING_FORM_GCC_3:
+               {
+                       add_string(&mangler, "_Z");
+                       add_len_string(&mangler, name);
+                       mangle_signature_gcc3(&mangler, signature);
+               }
+               break;
+       #endif
+
+       #ifdef MANGLING_FORM_MSVC_6
+               case MANGLING_FORM_MSVC_6:
+               {
+                       add_ch(&mangler, '?');
+                       add_string(&mangler, name);
+                       add_string(&mangler, "@@Y");
+                       mangle_signature_msvc6(&mangler, signature, 1, 0, 0);
+               }
+               break;
+       #endif
+       }
+       return end_mangler(&mangler);
+}
+
+#define        JIT_MANGLE_PUBLIC                       0x0001
+#define        JIT_MANGLE_PROTECTED            0x0002
+#define        JIT_MANGLE_PRIVATE                      0x0003
+#define        JIT_MANGLE_STATIC                       0x0000
+#define        JIT_MANGLE_INSTANCE                     0x0008
+#define        JIT_MANGLE_VIRTUAL                      0x0010
+#define        JIT_MANGLE_CONST                        0x0020
+#define        JIT_MANGLE_EXPLICIT_THIS        0x0040
+#define        JIT_MANGLE_IS_CTOR                      0x0080
+#define        JIT_MANGLE_IS_DTOR                      0x0100
+
+/*@
+ * @deftypefun {char *} jit_mangle_member_function ({const char *} class_name, {const char *} name, jit_type_t signature, int form, int flags)
+ * Mangle the name of a C++ member function using the specified @code{form}.
+ * Returns NULL if out of memory, or if the form is not supported.
+ * The following flags may be specified to modify the mangling rules:
+ *
+ * @table @code
+ * @vindex JIT_MANGLE_PUBLIC
+ * @item JIT_MANGLE_PUBLIC
+ * The method has @code{public} access within its containing class.
+ *
+ * @vindex JIT_MANGLE_PROTECTED
+ * @item JIT_MANGLE_PROTECTED
+ * The method has @code{protected} access within its containing class.
+ *
+ * @vindex JIT_MANGLE_PRIVATE
+ * @item JIT_MANGLE_PRIVATE
+ * The method has @code{private} access within its containing class.
+ *
+ * @vindex JIT_MANGLE_STATIC
+ * @item JIT_MANGLE_STATIC
+ * The method is @code{static}.
+ *
+ * @vindex JIT_MANGLE_INSTANCE
+ * @item JIT_MANGLE_INSTANCE
+ * The method is a non-virtual instance method.
+ *
+ * @vindex JIT_MANGLE_VIRTUAL
+ * @item JIT_MANGLE_VIRTUAL
+ * The method is a virtual instance method.
+ *
+ * @vindex JIT_MANGLE_CONST
+ * @item JIT_MANGLE_CONST
+ * The method is an instance method with the @code{const} qualifier.
+ *
+ * @vindex JIT_MANGLE_EXPLICIT_THIS
+ * @item JIT_MANGLE_EXPLICIT_THIS
+ * The @code{signature} includes an extra pointer parameter at the start
+ * that indicates the type of the @code{this} pointer.  This parameter won't
+ * be included in the final mangled name.
+ *
+ * @vindex JIT_MANGLE_IS_CTOR
+ * @item JIT_MANGLE_IS_CTOR
+ * The method is a constructor.  The @code{name} parameter will be ignored.
+ *
+ * @vindex JIT_MANGLE_IS_DTOR
+ * @item JIT_MANGLE_IS_DTOR
+ * The method is a destructor.  The @code{name} parameter will be ignored.
+ * @end table
+ *
+ * The @code{class_name} may include namespace and nested parent qualifiers
+ * by separating them with @code{::} or @code{.}.  Class names that involve
+ * template parameters are not supported yet.
+ * @end deftypefun
+@*/
+char *jit_mangle_member_function
+       (const char *class_name, const char *name,
+        jit_type_t signature, int form, int flags)
+{
+       struct jit_mangler mangler;
+       init_mangler(&mangler);
+       switch(form)
+       {
+       #ifdef MANGLING_FORM_GCC_2
+               case MANGLING_FORM_GCC_2:
+               {
+                       /* TODO */
+               }
+               break;
+       #endif
+
+       #ifdef MANGLING_FORM_GCC_3
+               case MANGLING_FORM_GCC_3:
+               {
+                       /* TODO */
+               }
+               break;
+       #endif
+
+       #ifdef MANGLING_FORM_MSVC_6
+               case MANGLING_FORM_MSVC_6:
+               {
+                       /* TODO */
+               }
+               break;
+       #endif
+       }
+       return end_mangler(&mangler);
+}