You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1578 lines
36 KiB

/*
* jit-cpp-mangle.c - Perform C++ name mangling.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
*
* This file is part of the libjit library.
*
* The libjit library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 2.1 of
* the License, or (at your option) any later version.
*
* The libjit library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the libjit library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <jit/jit-dynamic.h>
#include <jit/jit.h>
#include <config.h>
#include <stdio.h>
/*@
@cindex Name mangling
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";
static char const b36chars[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/*
* 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;
char **names;
unsigned int num_names;
unsigned int max_names;
};
/*
* 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;
mangler->names = 0;
mangler->num_names = 0;
mangler->max_names = 0;
}
/*
* End a mangling operation, and return the final string.
*/
static char *end_mangler(jit_mangler_t mangler)
{
unsigned int index;
for(index = 0; index < mangler->num_names; ++index)
{
jit_free(mangler->names[index]);
}
jit_free(mangler->names);
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);
}
/*
* Add a name to the name list in "mangler". Returns the index
* of a previous occurrence, or -1 if there was no previous version.
*/
static int add_name(jit_mangler_t mangler, const char *name,
unsigned int name_len)
{
unsigned int index;
unsigned int len;
char **new_names;
for(index = 0; index < mangler->num_names; ++index)
{
len = jit_strlen(mangler->names[index]);
if(len == name_len && !jit_strncmp(name, mangler->names[index], len))
{
return (int)index;
}
}
if(mangler->num_names >= mangler->max_names)
{
if(mangler->out_of_memory)
{
return -1;
}
new_names = (char **)jit_realloc
(mangler->names, (mangler->num_names + 8));
if(!new_names)
{
mangler->out_of_memory = 1;
return -1;
}
mangler->names = new_names;
mangler->max_names += 8;
}
mangler->names[mangler->num_names] = jit_strndup(name, name_len);
if(!(mangler->names[mangler->num_names]))
{
mangler->out_of_memory = 1;
}
else
{
++(mangler->num_names);
}
return -1;
}
/*
* 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(jit_type_get_kind(type))
{
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)
{
int kind = jit_type_get_kind(jit_type_remove_tags(type));
if(kind == JIT_TYPE_UBYTE ||
kind == JIT_TYPE_USHORT ||
kind == JIT_TYPE_UINT ||
kind == JIT_TYPE_NUINT ||
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);
/*
* Special prefixes for gcc 2.x rules.
*/
#define GCC2_CTOR_PREFIX "__"
#define GCC2_DTOR_PREFIX "_._" /* Could be "_$_" on some systems */
/*
* 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 qualified name, using gcc 2.x rules.
*/
static void mangle_name_gcc2(jit_mangler_t mangler, const char *name)
{
unsigned int len;
unsigned int posn;
unsigned int index;
unsigned int count;
char buf[32];
/* Bail out if we don't have a name at all */
if(!name)
{
return;
}
/* Count the number of components */
len = jit_strlen(name);
count = 1;
for(posn = 0; posn < len; ++posn)
{
if(name[posn] == '.')
{
++count;
}
else if(name[posn] == ':')
{
if((posn + 1) < len && name[posn + 1] == ':')
{
++count;
++posn;
}
}
}
/* Output the component count */
if(count > 9)
{
add_ch(mangler, 'Q');
add_ch(mangler, '_');
sprintf(buf, "%u", count);
add_string(mangler, buf);
add_ch(mangler, '_');
}
else if(count > 1)
{
add_ch(mangler, 'Q');
add_ch(mangler, (int)('0' + count));
}
/* Output the components in the name */
posn = 0;
while(posn < len)
{
index = posn;
while(index < len)
{
if(name[index] == '.' || name[index] == ':')
{
break;
}
++index;
}
sprintf(buf, "%u", index - posn);
add_string(mangler, buf);
while(posn < index)
{
add_ch(mangler, name[posn++]);
}
if(posn < len && name[posn] == ':')
{
if((posn + 1) < len && name[posn + 1] == ':')
{
posn += 2;
}
else
{
++posn;
}
}
else if(posn < len && name[posn] == '.')
{
++posn;
}
}
}
/*
* 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 */
kind = jit_type_get_kind(type);
if(kind >= JIT_TYPE_SBYTE && kind <= JIT_TYPE_ULONG)
{
type = fix_system_types(type);
}
switch(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:
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_UNION_NAME:
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_ENUM_NAME:
{
/* Output the qualified name of the type */
mangle_name_gcc2
(mangler, (const char *)jit_type_get_tagged_data(type));
}
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 substitution reference.
*/
static void mangle_substitution_gcc3(jit_mangler_t mangler, int name_index)
{
char buf[32];
unsigned int index;
add_ch(mangler, 'S');
if(name_index > 0)
{
--name_index;
index = sizeof(buf) - 1;
buf[index] = '\0';
while(name_index != 0)
{
buf[--index] = b36chars[name_index % 36];
name_index /= 36;
}
while(index == (sizeof(buf) - 1))
{
buf[--index] = '0';
}
add_string(mangler, buf + index);
}
add_ch(mangler, '_');
}
/*
* Mangle a qualified name, using gcc 3.x rules.
*/
static void mangle_name_gcc3(jit_mangler_t mangler, const char *name,
const char *member_name)
{
unsigned int len;
unsigned int posn;
unsigned int index;
int name_index;
int name_index2;
char buf[32];
int multiple;
if(!name)
{
return;
}
len = jit_strlen(name);
name_index = add_name(mangler, name, len);
if(name_index != -1)
{
/* We have a substitution for the whole name */
mangle_substitution_gcc3(mangler, name_index);
return;
}
multiple = (jit_strchr(name, '.') != 0 || jit_strchr(name, ':') != 0 ||
member_name != 0);
if(multiple)
{
add_ch(mangler, 'N');
}
posn = 0;
name_index = -1;
while(posn < len)
{
/* Extract the next component */
index = posn;
while(index < len)
{
if(name[index] == '.' || name[index] == ':')
{
break;
}
++index;
}
/* Determine if we have a substitution for the current prefix */
name_index2 = add_name(mangler, name, index);
if(name_index2 != -1)
{
name_index = name_index2;
posn = index;
}
else
{
if(name_index != -1)
{
mangle_substitution_gcc3(mangler, name_index);
name_index = -1;
}
sprintf(buf, "%u", index - posn);
add_string(mangler, buf);
while(posn < index)
{
add_ch(mangler, name[posn++]);
}
}
/* Move on to the next component */
if(posn < len && name[posn] == ':')
{
if((posn + 1) < len && name[posn + 1] == ':')
{
posn += 2;
}
else
{
++posn;
}
}
else if(posn < len && name[posn] == '.')
{
++posn;
}
}
if(member_name)
{
add_len_string(mangler, member_name);
}
if(multiple)
{
add_ch(mangler, 'E');
}
}
/*
* 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 */
kind = jit_type_get_kind(type);
if(kind >= JIT_TYPE_SBYTE && kind <= JIT_TYPE_ULONG)
{
type = fix_system_types(type);
}
switch(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(type))
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:
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_UNION_NAME:
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_ENUM_NAME:
{
/* Output the qualified name of the type */
mangle_name_gcc3
(mangler, (const char *)jit_type_get_tagged_data(type), 0);
}
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 qualified name, using MSVC 6.0 rules.
*/
static void mangle_name_msvc6(jit_mangler_t mangler, const char *name)
{
unsigned int len;
unsigned int posn;
unsigned int index;
int name_index;
int output_at;
if(!name)
{
return;
}
len = jit_strlen(name);
while(len > 0)
{
posn = len - 1;
while(posn > 0 && name[posn] != '.' && name[posn] != ':')
{
--posn;
}
++posn;
name_index = add_name(mangler, name + posn, len - posn);
if(name_index == -1 || name_index > 9)
{
for(index = posn; index < len; ++index)
{
add_ch(mangler, name[index]);
}
output_at = 1;
}
else
{
add_ch(mangler, '0' + name_index);
output_at = 0;
}
if(posn > 0 && name[posn - 1] == ':')
{
--posn;
if(posn > 0 && name[posn - 1] == ':')
{
--posn;
}
}
else if(posn > 0 && name[posn - 1] == '.')
{
--posn;
}
len = posn;
if(len > 0 && output_at)
{
add_ch(mangler, '@');
}
}
}
/*
* 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 */
kind = jit_type_get_kind(type);
if(kind >= JIT_TYPE_SBYTE && kind <= JIT_TYPE_ULONG)
{
type = fix_system_types(type);
}
switch(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:
{
add_ch(mangler, 'V');
mangle_name_msvc6
(mangler, (const char *)jit_type_get_tagged_data(type));
add_string(mangler, "@@");
}
break;
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_STRUCT_NAME:
{
add_ch(mangler, 'U');
mangle_name_msvc6
(mangler, (const char *)jit_type_get_tagged_data(type));
add_string(mangler, "@@");
}
break;
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_UNION_NAME:
{
add_ch(mangler, 'T');
mangle_name_msvc6
(mangler, (const char *)jit_type_get_tagged_data(type));
add_string(mangler, "@@");
}
break;
case JIT_TYPE_FIRST_TAGGED + JIT_TYPETAG_ENUM_NAME:
{
add_ch(mangler, 'W');
add_ch(mangler, (int)('0' + jit_type_get_size(type)));
mangle_name_msvc6
(mangler, (const char *)jit_type_get_tagged_data(type));
add_string(mangler, "@@");
}
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 *@var{name}, jit_type_t @var{signature}, int @var{form})
* Mangle the name of a global C++ function using the specified @var{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);
}
/*@
* @deftypefun {char *} jit_mangle_member_function (const char *@var{class_name}, const char *@var{name}, jit_type_t @var{signature}, int @var{form}, int @var{flags})
* Mangle the name of a C++ member function using the specified @var{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_VIRTUAL
* @item JIT_MANGLE_VIRTUAL
* The method is a virtual instance method. If neither
* @code{JIT_MANGLE_STATIC} nor @code{JIT_MANGLE_VIRTUAL} are supplied,
* then the method is assumed to be a non-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 @var{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 @var{name} parameter will be ignored.
*
* @vindex JIT_MANGLE_IS_DTOR
* @item JIT_MANGLE_IS_DTOR
* The method is a destructor. The @var{name} parameter will be ignored.
*
* @vindex JIT_MANGLE_BASE
* @item JIT_MANGLE_BASE
* Fetch the "base" constructor or destructor entry point, rather than
* the "complete" entry point.
* @end table
*
* The @var{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:
{
if((flags & JIT_MANGLE_IS_CTOR) != 0)
{
add_string(&mangler, GCC2_CTOR_PREFIX);
mangle_name_gcc2(&mangler, class_name);
mangle_signature_gcc2(&mangler, signature);
}
else if((flags & JIT_MANGLE_IS_DTOR) != 0)
{
add_string(&mangler, GCC2_DTOR_PREFIX);
mangle_name_gcc2(&mangler, class_name);
}
else
{
add_string(&mangler, name);
add_string(&mangler, "__");
mangle_signature_gcc2(&mangler, signature);
}
}
break;
#endif
#ifdef MANGLING_FORM_GCC_3
case MANGLING_FORM_GCC_3:
{
if((flags & JIT_MANGLE_IS_CTOR) != 0)
{
add_string(&mangler, "_Z");
if((flags & JIT_MANGLE_BASE) != 0)
{
mangle_name_gcc3(&mangler, class_name, "C2");
}
else
{
mangle_name_gcc3(&mangler, class_name, "C1");
}
mangle_signature_gcc3(&mangler, signature);
}
else if((flags & JIT_MANGLE_IS_DTOR) != 0)
{
add_string(&mangler, "_Z");
if((flags & JIT_MANGLE_BASE) != 0)
{
mangle_name_gcc3(&mangler, class_name, "D2");
}
else
{
mangle_name_gcc3(&mangler, class_name, "D1");
}
mangle_signature_gcc3(&mangler, signature);
}
else
{
add_string(&mangler, "_Z");
mangle_name_gcc3(&mangler, class_name, name);
mangle_signature_gcc3(&mangler, signature);
}
}
break;
#endif
#ifdef MANGLING_FORM_MSVC_6
case MANGLING_FORM_MSVC_6:
{
if((flags & JIT_MANGLE_IS_CTOR) != 0)
{
add_string(&mangler, "??0");
mangle_name_msvc6(&mangler, class_name);
}
else if((flags & JIT_MANGLE_IS_DTOR) != 0)
{
add_string(&mangler, "??1");
mangle_name_msvc6(&mangler, class_name);
}
else
{
add_ch(&mangler, '?');
add_string(&mangler, name);
add_ch(&mangler, '@');
mangle_name_msvc6(&mangler, class_name);
}
add_string(&mangler, "@@");
if((flags & 0x07) == JIT_MANGLE_PROTECTED)
{
if((flags & JIT_MANGLE_STATIC) != 0)
{
/* static protected */
add_ch(&mangler, 'K');
}
else if((flags & JIT_MANGLE_VIRTUAL) != 0)
{
/* virtual protected */
add_ch(&mangler, 'M');
}
else
{
/* instance protected */
add_ch(&mangler, 'I');
}
}
else if((flags & 0x07) == JIT_MANGLE_PRIVATE)
{
if((flags & JIT_MANGLE_STATIC) != 0)
{
/* static private */
add_ch(&mangler, 'C');
}
else if((flags & JIT_MANGLE_VIRTUAL) != 0)
{
/* virtual private */
add_ch(&mangler, 'E');
}
else
{
/* instance private */
add_ch(&mangler, 'A');
}
}
else
{
if((flags & JIT_MANGLE_STATIC) != 0)
{
/* static public */
add_ch(&mangler, 'S');
}
else if((flags & JIT_MANGLE_VIRTUAL) != 0)
{
/* virtual public */
add_ch(&mangler, 'U');
}
else
{
/* instance public */
add_ch(&mangler, 'Q');
}
}
if((flags & JIT_MANGLE_STATIC) == 0)
{
if((flags & JIT_MANGLE_CONST) != 0)
{
add_ch(&mangler, 'B');
}
else
{
add_ch(&mangler, 'A');
}
}
mangle_signature_msvc6
(&mangler, signature,
(flags & (JIT_MANGLE_IS_CTOR | JIT_MANGLE_IS_DTOR)) == 0,
(flags & JIT_MANGLE_STATIC) == 0,
(flags & JIT_MANGLE_EXPLICIT_THIS) != 0);
}
break;
#endif
}
return end_mangler(&mangler);
}