Name Mangling
name mangling 又稱為 name decoration, 是程式語言中常使用的技術, 用來需要獨一無二名稱的問題。 藉由此種方式 compiler 可以提供更多的資訊給 linker。 這種需求隨著語言允許在不同 namespace 有相同名稱的東西或是不同 signatures (function overloading) 而提高。
C++
測試範例:
// mangling.cpp
#include <cstdio>
namespace mangled
{
class test
{
public:
void func1()
{
printf("test\n");
}
};
}
class test
{
public:
void func1()
{
printf("test\n");
}
};
int main() {
mangled::test foo;
test bar;
foo.func1();
bar.func1();
return 0;
}
編譯:
$ g++ -c mangling.cpp -o mangling.o
$ objdump -Sr mangling.o # without demangling
$ objdump -CSr mangling.o # with demangling
$ g++ -S mangling.cpp -o mangling.s
$ cat mangling.s
可以觀察到 mangled::test::func
變成了 _ZN7mangled4test5func1Ev
,
demangling 也可以利用 binutils 裡的 c++filt 來做,
例如:
$ c++filt -n _ZN7mangled4test5func1Ev
mangled::test::func1()
$ c++filt -n _ZN4test5func1Ev
test::func1()
GCC 對 C++ 做 name mangling 的一些規則:
所有 mangled 符號都由 “_Z” 開頭
巢狀名稱的話在 “_Z” 後面加上 “N” 作為開頭
接著為一連串 字串長度 + 名稱
最後面加上 “E” 作為結尾
- 最後加上 return type
int -> i
float -> f
void -> v
Python
在 Python 中,用雙底線開頭、零個或一個底線結尾的 class member 會做 name mangling,
可以達到某種程度 private 的效果,在用 dir
看 attribute 的時候,
可以發現符合這 pattern 的 class member 會被轉成 “_ClassName” + member name,
而在 instance 單純使用原本的 member name 來存取會發現拿不到原本 member 的值 (因為名字不同了)。
class Test1(object):
__mangled_var = ":P"
normal_var = ":("
def __mangled_name(self):
print("I'm mangled : ", self.__mangled_var)
def normal_name(self):
print("I'm not mangled : ", self.normal_var)
def name(self):
self.__mangled_name()
self.normal_name()
class Test2(Test1):
__mangled_var = ":O"
normal_var = ":|"
########################################
print("=" * 10)
t1 = Test1()
print(dir(t1))
t1.name()
t1.normal_var = ":(("
t1.__mangled_var = ":PP"
t1.name()
print("=" * 10)
t2 = Test2()
print(dir(t2))
t2.name()
t2.normal_var = ":(("
t2.__mangled_var = ":PP"
t2.name()
print("=" * 10)
########################################
''' Output
==========
['_Test1__mangled_name', '_Test1__mangled_var', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'normal_name', 'normal_var']
I'm mangled : :P
I'm not mangled : :(
I'm mangled : :P
I'm not mangled : :((
==========
['_Test1__mangled_name', '_Test1__mangled_var', '_Test2__mangled_var', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'normal_name', 'normal_var']
I'm mangled : :P
I'm not mangled : :|
I'm mangled : :P
I'm not mangled : :((
==========
'''
注意的點:
Test1 的 class member “__mangled_name” 變成 “_Test1__mangled_name”
Test1 的 class member “__mangled_var” 變成 “_Test1__mangled_var”
instance 用 .__mangled_var 無法改到原本的 member,要用 ._Test1__manbled_var 才可以 access 到
Test2 繼承 Test1 後,用 __mangled_var 宣告新的 member 會跟原本的隔開,不會蓋到、影響到原本 access 的 function