Skip to content

Instantly share code, notes, and snippets.

@Itay2805
Last active August 18, 2023 10:28
Show Gist options
  • Save Itay2805/817f3118431cb9658a166e91f7d17eaf to your computer and use it in GitHub Desktop.
Save Itay2805/817f3118431cb9658a166e91f7d17eaf to your computer and use it in GitHub Desktop.
Visual C++ name manglerfor fun and profit
from curses.ascii import isalnum
class CppNameMangler:
KNOWN_TYPES = {
# Basic types
'signed char': 'A',
'char': 'D',
'unsigned char': 'E',
'short': 'F',
'unsigned short': 'G',
'int': 'H',
'unsigned int': 'I',
'long': 'J',
'unsigned long': 'K',
'float': 'M',
'double': 'N',
'long double': 'O',
'bool': '_N',
'__int8': '_D',
'unsigned __int8': '_E',
'__int16': '_F',
'unsigned __int16': '_G',
'__int32': '_H',
'unsigned __int32': '_I',
'__int64': '_J',
'unsigned __int64': '_K',
'__int128': '_L',
'unsigned __int128': '_M',
'char8_t': '_Q',
'char16_t': '_S',
'char32_t': '_U',
# Complex types
'union': 'T',
'struct': 'U',
'class': 'V',
'void': 'X',
}
def __init__(self, name: str) -> None:
self._name = name
self._index = 0
def _get(self) -> str:
c = self._name[self._index]
self._index += 1
return c
def _consume(self, value):
if self._peek() == value:
self._index += 1
return True
return False
def _peek(self) -> str:
if self._index == len(self._name):
return ''
c = self._get()
self._unget()
return c
def _expect(self, c):
cc = self._get()
assert cc == c, f'wanted {c} got {cc} (left `{self._name[self._index:]}`)'
def _unget(self):
self._index -= 1
def _get_basic_name(self) -> str:
ident = ''
while True:
c = self._peek()
if c == '':
break
c = self._get()
if len(ident) == 0:
assert c.isalpha(), c
ident += c
elif c.isalnum():
ident += c
else:
self._unget()
break
return ident
def _mangle_type_name(self):
mname = ''
while True:
name = self._get_basic_name()
if name in ['unsigned', 'signed', 'long']:
if self._consume(' '):
name += ' ' + self._get_basic_name()
if name in self.KNOWN_TYPES:
mname += self.KNOWN_TYPES[name]
if name in ['union', 'struct', 'class']:
self._expect(' ')
mname += self._mangle_name() + '@'
break
else:
# TODO: const/volatile/whatever
assert False, name + f' -- left: {self._name[self._index:]}'
while True:
if self._consume('*'):
mname = 'PA' + mname
elif self._consume('&'):
if self._consume('&'):
mname = '$$QA' + mname
else:
mname = 'AA' + mname
else:
break
return mname
def _mangle_qualification(self):
basic_name = self._get_basic_name() + '@'
assert basic_name != ''
if self._consume('<'):
basic_name = '?$' + basic_name
while True:
basic_name += self._mangle_type_name()
if not self._consume(','):
self._expect('>')
break
basic_name += '@'
return basic_name
def _mangle_name(self):
final = self._mangle_qualification()
while self._peek() == ':':
self._expect(':')
self._expect(':')
final = self._mangle_qualification() + final
return final
def mangle_function(self):
ret_type = self._mangle_type_name()
self._expect(' ')
# TODO: access
access = 'Y'
name = self._mangle_name()
# None, not exported
# TODO: this
calling_convention = 'K'
# arguments
args = ''
self._expect('(')
while self._peek() != ')':
args += self._mangle_type_name()
if self._peek() == ')':
break
self._expect(',')
self._expect(')')
# terminate it
if args == '':
args = 'X'
else:
args += '@'
# TODO: throw attribute
throw_attribute = 'Z'
return '?' + name + '@' + access + calling_convention + ret_type + args + throw_attribute
print(CppNameMangler("void abc<class def<int>,void*>::xyz()").mangle_function())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment