이름 망글링

Name mangling

컴파일러 구조에서 이름 망글링(이름 장식이라고도 함)은 많은 현대 프로그래밍 언어에서 프로그래밍 엔티티에 대한 고유한 이름을 해결해야 하는 필요성으로 인해 발생하는 다양한 문제를 해결하기 위해 사용되는 기술입니다.

컴파일러에서 링커로 더 많은 의미 정보를 전달하기 위해 함수, 구조, 클래스 또는 다른 데이터 유형의 이름으로 추가 정보를 인코딩하는 방법을 제공합니다.

이름 망글링의 필요성은 언어에서 서로 다른 네임스페이스(일반적으로 모듈, 클래스 또는 명시적인 네임스페이스 디렉티브에 의해 정의됨)를 점유하거나 서로 다른 시그니처를 가지고 있는 한 서로 다른 엔티티를 동일한 식별자로 명명할 수 있는 경우에 발생합니다(함수 오버로드 등).이러한 사용 예에서는 시그니처마다 머신 코드에 다른 특수한 호출 규칙이 필요할 수 있기 때문에 필요합니다.

컴파일러에 의해 생성되는 오브젝트 코드는 보통 링커라고 불리는 유형의 프로그램에 의해 (같은 컴파일러 또는 다른 컴파일러에 의해) 다른 오브젝트 코드와 링크됩니다.링커에는 각 프로그램 엔티티에 대한 많은 정보가 필요합니다.예를 들어 함수를 올바르게 연결하려면 함수의 이름, 인수 수 및 유형 등이 필요합니다.

C와 같은 1970년대의 단순한 프로그래밍 언어들은 이름만으로 서브루틴을 구분하고 파라미터와 리턴 타입을 포함한 다른 정보는 무시했다.C++같은 이후의 프로그래밍 언어들은 파라미터 유형, 반환 유형, 함수의 호출 규칙과 같은 루틴이 "동일"하다고 간주되는 더 엄격한 요건을 정의했다.이러한 요건에 의해, 메서드의 오버로드와 버그 검출이 가능하게 됩니다(예를 들면, 다른 소스 파일을 컴파일 할 때에, 다른 함수의 정의를 사용하는 등).기존의 툴과 표기법을 사용하기 위해서는 이러한 엄격한 요건이 필요했습니다.따라서 기존의 링커에는 심볼에 대한 유일한 정보였기 때문에 추가 요건이 심볼 이름으로 인코딩되었습니다.

이름 망글링의 또 다른 용도는 시그니처와 관련되지 않은 추가 변경(함수 순도 등)을 검출하거나 예외를 발생시키거나 가비지 수집을 트리거할 수 있는지 여부를 검출하는 것입니다.이를 실행하는 언어의 로는 [1][2]D가 있습니다.이것들은 단순한 에러 체크에 가깝습니다.예를 들어 기능int f();그리고.int g(int) pure;하나의 오브젝트 파일로 컴파일 할 수 있었지만, 그 시그니처는float f(); int g(int);다른 소스를 호출하는 데 사용됩니다.링크 시 링커는 기능이 없음을 감지합니다.f(int)에러를 반환합니다.마찬가지로 링커는 다음 유형의 반환을 검출할 수 없습니다.f다르므로 오류를 반환합니다.그렇지 않으면 호환되지 않는 호출 규칙이 사용되며 잘못된 결과가 발생하거나 프로그램이 크래시될 수 있습니다.망글링은 보통 호출 프로세스의 모든 세부 사항을 캡처하지 않습니다.예를 들어 구조 또는 클래스의 데이터 멤버 변경과 같은 오류를 완전히 방지하지는 않습니다.예를들면,struct S {}; void f(S) {}1개의 오브젝트 파일로 컴파일 할 수 있습니다.그 후, 그 정의는S로 바뀌었다struct S { int x; };에의 콜의 편집에 사용됩니다.f(S())이러한 경우 컴파일러는 보통 다른 호출 규칙을 사용합니다만, 두 경우 모두f링커는 이 문제를 검출하지 않고 실행 시 크래시 또는 데이터 또는 메모리 파손이 발생합니다.

C

일반적으로 이름 망글링은 C나 클래식 파스칼과 같이 함수 오버로드를 지원하지 않는 언어에서는 필요하지 않지만 경우에 따라 함수에 대한 추가 정보를 제공하기 위해 사용합니다.예를 들어 Microsoft Windows 플랫폼을 대상으로 하는 컴파일러는 서브루틴에 파라미터를 송신하고 결과를 반환하는 방법을 결정하는 다양한 호출 규칙을 지원합니다.다른 호출 규약은 서로 호환되지 않기 때문에 컴파일러는 특정 루틴을 호출하기 위해 사용해야 하는 규칙을 상술한 코드와 함께 기호를 망글합니다.

망글링 스킴은 Microsoft에 의해 확립되어 Windows 플랫폼용 코드를 컴파일 할 때 Digital Mars, Borland, GNU GCC 등의 컴파일러가 비공식적으로 행해지고 있습니다.이 스킴은 Pascal, D, Delphi, Fortran 및 C#과 같은 다른 언어에도 적용됩니다.이를 통해 이러한 언어로 작성된 서브루틴은 기본값과 다른 호출 규칙을 사용하여 기존 Windows 라이브러리를 호출하거나 호출할 수 있습니다.

다음 C의 예를 컴파일 할 때:

인트 _cdecl    f (인트 x) { 돌아가다 0; } 인트 _stdcall  g (인트 y) { 돌아가다 0; } 인트 _Fastcall h (인트 z) { 돌아가다 0; } 

32비트 컴파일러는 각각 다음과 같이 출력합니다.

_f _g@4 @h@4

에서stdcall그리고.fastcallmangling scheme, 함수는 다음과 같이 부호화됩니다._name@X그리고.@name@X각각, 여기서X는 파라미터 목록 내의 인수(10진수)의 바이트 수(패스트콜의 경우 레지스터로 전달된 인수 포함)입니다.의 경우cdecl함수 이름 앞에 밑줄만 붙입니다.

Windows(Microsoft C)의 64비트 표기법에는 선행 언더스코어가 없습니다.이 차이로 인해 이러한 코드를 64비트로 포팅할 때 해결되지 않는 외부 현상이 발생할 수 있습니다.예를 들어 Fortran 코드는 다음과 같이 'alias'를 사용하여 이름으로 C 메서드에 연결할 수 있습니다.

서브루틴f() !DEC$ Attributes C, ALIAS:'_f' :: f 엔드 서브루틴 

32비트 미만으로 컴파일 및 링크가 정상적으로 이루어지지만 해결되지 않은 외부 데이터가 생성됩니다._f64비트 이하이를 위한 회피책 중 하나는 '에일리어스'를 전혀 사용하지 않는 것입니다(일반적으로 메서드 이름은 C 및 Fortran으로 대문자로 입력해야 합니다).다른 하나는 BIND 옵션을 사용하는 것입니다.

서브루틴f() 바인드(C,이름.="f") 엔드 서브루틴 

C에서는 대부분의 컴파일러가 스태틱한 함수와 변수(및 C++ 함수 및 변수에서는 스태틱으로 선언되거나 익명 네임스페이스에 삽입됨)를 비 스태틱버전과 같은 머글링 규칙을 사용하여 변환 단위로 머글링합니다.같은 이름의 함수(및 C++의 파라미터)도 다른 변환 단위로 정의되어 사용되고 있는 경우, 같은 이름으로 뭉쳐져 충돌이 발생할 가능성이 있습니다.단, 각각의 번역 단위로 호출되는 경우에는 동등하지 않습니다.컴파일러는 보통 이러한 함수에 대해 임의의 망글링을 자유롭게 실행할 수 있습니다.다른 변환 유닛에서 직접 액세스 하는 것은 불법이기 때문에 다른 오브젝트 코드간의 링크(링크 불필요)는 불필요하기 때문입니다.링크 충돌을 방지하기 위해 컴파일러는 표준 망글링을 사용하지만 이른바 '로컬' 기호를 사용합니다.이러한 많은 변환 유닛을 링크하는 경우 같은 이름의 함수에 대한 정의가 여러 개 있을 수 있지만 결과 코드는 그 변환 유닛의 종류에 따라1 개 또는 다른 것만을 호출합니다.이것은 보통 재배치 메커니즘을 사용하여 수행됩니다.

C++

C++ 컴파일러는 이름 망글을 가장 많이 사용하는 사용자입니다.첫 번째 C++ 컴파일러는 C 소스 코드에 대한 변환기로 구현되었으며, C 컴파일러는 C 소스 코드를 오브젝트하기 위해 컴파일러에 의해 컴파일되었습니다.이 때문에 심볼명은 C 식별자 규칙을 따라야 했습니다.나중에 기계 코드나 어셈블리를 직접 생성하는 컴파일러가 등장하면서, 시스템의 링커는 일반적으로 C++ 기호를 지원하지 않았고, 머글링은 여전히 필요했습니다.

C++ 언어에는 표준적인 장식 방식이 정의되어 있지 않기 때문에 각 컴파일러는 독자적인 것을 사용합니다.C++에는 클래스, 템플릿, 네임스페이스, 연산자 오버로드컨텍스트 또는 사용에 따라 특정 기호의 의미를 변경하는 복잡한 언어 기능도 있습니다.이러한 기능에 대한 메타 데이터는 기호 이름을 망글링(장식)하여 모호성을 제거할 수 있습니다.이러한 기능의 이름 관리 시스템은 컴파일러 간에 표준화되어 있지 않기 때문에 다른 컴파일러에 의해 생성된 오브젝트 코드를 링크할 수 있는 링커는 거의 없습니다.

간단한 예

1개의 C++ 변환 유닛은, 다음의 2개의 함수를 정의할 수 있습니다.f():

인트  f () { 돌아가다 1; } 인트  f (인트)  { 돌아가다 0; } 무효 g () { 인트 i = f(), j = f(0); } 

이들은 이름 이외에는 서로 관련이 없는 별개의 함수입니다.따라서 C++ 컴파일러는 기호명으로 타입 정보를 부호화하며, 그 결과는 다음과 같습니다.

인트  __f_v () { 돌아가다 1; } 인트  __f_i (인트)  { 돌아가다 0; }  무효 __g_v () { 인트 i = __f_v(), j = __f_i(0); } 

이름은 독특하지만g()이름 망글링은 모든 C++ 기호(C++ 기호 이외의 기호)에 적용됩니다.extern "C"{}블록)을 클릭합니다.

복잡한 예

IA-64(Itanium) ABI에 따르면 이 예에서 각 식별자 이름 아래의 코멘트 중 망가지기호는 GNU GCC 3.x 컴파일러에 의해 생성된 것입니다.

네임스페이스 위키백과  {    학급 기사     {    일반의:       표준::스트링 포맷 ();  // = _ZN9wikipedia7article6formatEv        부울 print_to (표준::스트림&);  // = _ZN9wikipedia7article8print_TOERSO        학급 링크        {       일반의:          링크 (표준::스트링 컨스턴트& 이름.);  // = _ZN9wikipedia7article8wikilinkC1ERKS       };    }; } 

모든 찌그러진 기호는 다음 문자로 시작합니다._Z(밑줄로 시작하는 ID와 대문자로 시작하는 ID는 C에서 예약된 ID이므로 사용자 ID와의 경합을 피할 수 있습니다).네스트된 이름(네임스페이스와 클래스 모두 포함)의 경우, 그 뒤에 이어지는 것은 다음과 같습니다.N그 후 일련의 <length, id> 쌍(길이는 다음 식별자의 길이)을 나타냅니다.E.예를들면,wikipedia::article::format다음과 같이 됩니다.

_ZN9wikipedia7article6formatE

기능의 경우, 그 다음에 유형 정보가 이어집니다.format()는 입니다.void기능, 이것은 단순합니다.v; 따라서:

_ZN9wikipedia7article6formatEv

위해서print_to, 표준형std::ostream(이것은에 대해 typedef.std::basic_ostream<char, std::char_traits<char> >)가 사용되고 있습니다.이것은 특별한 에일리어스를 가집니다.So; 이 유형에 대한 참조는 다음과 같습니다.RSo함수의 전체 이름은 다음과 같습니다.

_ZN9wikipedia7article8print_TOERSO

다른 컴파일러가 같은 기능을 망치는 방법

사소한 C++ 식별자조차 뒤죽박죽이 되는 표준화된 스킴은 없습니다.따라서 다른 컴파일러(또는 같은 컴파일러의 다른 버전 또는 다른 플랫폼 상의 같은 컴파일러)는 완전히 다른(따라서 완전히 호환되지 않는) 방법으로 퍼블릭 심볼을 뒤죽박죽으로 만듭니다.다른 C++ 컴파일러가 같은 함수를 어떻게 망칠지 생각해 보십시오.

컴파일러 void h(int) void h(int, char) void h(void)
인텔 C++ 8.0 Linux 버전 _Z1hi _Z1hic _Z1hv
HP aC++ A.05.55 IA-64
IAR EWARM C++
GCC 3.x 이후
Clang 1.x 이후[3]
GCC 2.9.x h__Fi h__Fic h__Fv
HP aC++ A.03.45 PA-RISC
Microsoft Visual C++ v6-v10 (망글링 상세) ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
디지털 Mars C++
볼랜드 C++ v31 @h$qi @h$qizc @h$qv
OpenVMS C++ v6.5(ARM 모드) H__XI H__XIC H__XV
OpenVMS C++ v6.5(ANSI 모드) CXX$__7H__FIC26CDH77 CXX$__7H__FV2CB06E8
OpenVMS C++ X7.1 IA-64 CXX$_Z1HI2DSQ26A CXX$_Z1HIC2NP3LI4 CXX$_Z1HV0BCA19V
SunPro CC __1cBh6Fi_v_ __1cBh6Fic_v_ __1cBh6F_v_
Tru64 C++ v6.5 (ARM 모드) h__Xi h__Xic h__Xv
Tru64 C++ v6.5 (ANSI 모드) __7h__Fi __7h__Fic __7h__Fv
Watcom C++ 10.6 W?h$n(i)v W?h$n(ia)v W?h$n()v

주의:

  • OpenVMS VAX 및 Alpha(IA-64는 제외) 및 Tru64의 Compaq C++ 컴파일러에는 두 가지 이름 망글링 방식이 있습니다.원래의 선행 표준 스킴은 ARM 모델이라고 불리며 C++ 주석 참조 매뉴얼(ARM)에 기재되어 있는 이름 망글링에 근거하고 있습니다.표준 C++에 새로운 기능, 특히 템플릿이 등장함에 따라 ARM 스킴은 특정 함수 타입을 부호화할 수 없거나 동일한 망글링을 생성할 수 없게 되었습니다.다른 기능의 이름.따라서 모든 ANSI 템플릿 기능을 지원하지만 하위 호환성은 없는 새로운 "ANSI" 모델로 대체되었습니다.
  • IA-64 에서는 표준 어플리케이션바이너리 인터페이스(ABI)가 존재하며(외부 링크 참조), 표준 이름 관리 방식을 정의하고 모든 IA-64 컴파일러에서 사용됩니다.또한 GNU GCC 3.x는 인텔 이외의 다른 플랫폼에서 사용하기 위해 이 표준에 정의된 이름 망글링 스킴을 채택했습니다.
  • Visual Studio 및 Windows SDK에는 이 프로그램이 포함되어 있습니다.undnameC-스타일 함수 프로토타입을 출력합니다.
  • Microsoft Windows 에서는, 인텔[4]·컴파일러와 Clang[5] 는, 호환성을 위해서 Visual C++ 의 이름 망글링을 사용합니다.

C++에서 링크할 때 C 기호 처리

일반적인 C++ 관용구의 작업:

#ifdef __cplusplus 외부 'C' { #엔디프     /* ... */ #ifdef __cplusplus } #엔디프 

C 컴파일러와 마찬가지로 이름이 장식되지 않은 바이너리 파일을 내보내는 것입니다.C 언어 정의가 엉켜 있지 않기 때문에 C++ 컴파일러는 이러한 식별자에 대한 참조가 엉켜지지 않도록 해야 합니다.

예를 들어 표준 문자열 라이브러리,<string.h>에는 보통 다음과 같은 것이 포함되어 있습니다.

#ifdef __cplusplus 외부 'C' { #엔디프  무효 *메모리 세트 (무효 *, 인트, size_t);  *스트랫 ( *, 컨스턴트  *); 인트   스트램프 (컨스턴트  *, 컨스턴트  *);  *스트럭시 ( *, 컨스턴트  *);  #ifdef __cplusplus } #엔디프 

따라서 다음과 같은 코드가 있습니다.

한다면 (스트램프(argv[1], -x) == 0)      스트럭시(a, argv[2]); 또 다른      메모리 세트 (a, 0, 크기(a)); 

올바른, 얽히지 않는 사용strcmp그리고.memset. 만약extern "C"(SunPro) C++ 컴파일러는 다음 코드와 동등한 코드를 생성합니다.

한다면 (__1cGstrcmp6Fpkc1_i_(argv[1], -x) == 0)      __1cGstrcpy6Fpcpkc_0_(a, argv[2]); 또 다른      __1cGmeset6FpviI_0_ (a, 0, 크기(a)); 

이러한 기호는 C 런타임 라이브러리(를 들어 libc)에 존재하지 않기 때문에 링크 오류가 발생합니다.


C++로 표준화된 이름 망글링

C++ 언어로 표준화된 이름을 뭉개면 컴파일러 구현 간의 상호 운용성이 향상될 것으로 보입니다.그러나 이러한 표준화만으로는 C++ 컴파일러의 상호 운용성을 보증하기에 충분하지 않으며, 그렇지 않을 경우 상호 운용성이 가능하고 안전하다는 잘못된 인상을 줄 수도 있습니다.이름 망글링은 C++ 구현에서 결정 및 감시해야 하는 Application Binary Interface(ABI; 응용 프로그램바이너리 인터페이스) 세부사항 중 하나에 불과합니다.예외 처리, 가상 테이블 레이아웃, 구조 및 스택프레임 패딩 다른 ABI 측면도 다른 C++ 구현의 호환성을 야기합니다.또한 특정 형태의 망글링을 요구하면 구현 한계(예: 기호 길이)가 특정 망글링 체계를 지시하는 시스템에 문제가 발생할 수 있다.또한 이름 망글링에 대한 표준화된 요건은 망글링이 전혀 필요하지 않은 구현(예를 들어 C++ 언어를 인식하는 링커)을 방지할 수 있습니다.

따라서 C++ 규격은 이름 망글링을 표준화하려고 하지 않습니다.반대로 주석 C++ 참조 설명서(ARM이라고도 함)는 ISBN0-201-51459-1, 섹션 7.2.1c)는 ABI의 다른 측면이 호환되지 않을 때 링크를 방지하기 위해 다양한 머글링 방식의 사용을 적극 권장하고 있습니다.

단, 위의 항에서 상술한 바와 같이 일부 플랫폼에서는 이름[6] 망글링을 포함한 완전한 C++ ABI가 표준화되어 있습니다.

C++ 이름 망글링의 실제 효과

C++ 심볼은 DLL 및 공유 객체 파일에서 정기적으로 내보내지기 때문에 망글링 스킴이라는 이름은 컴파일러 내부만의 문제가 아닙니다.다른 컴파일러(또는 같은 컴파일러의 다른 버전, 많은 경우)는 다른 이름 장식 방식으로 이러한 바이너리를 생성합니다.즉, 라이브러리를 작성하기 위해 사용되는 컴파일러와 이를 사용하는 프로그램이 다른 스킴을 사용하는 경우 심볼은 종종 해결되지 않습니다.예를 들어 여러 개의 C++ 컴파일러가 설치되어 있는 시스템(GNU GCC 및 OS 벤더의 컴파일러 등)에서 Boost C++ 라이브러리를 설치하려면 여러 번 컴파일해야 합니다(GCC 및 벤더 컴파일러용).

호환성이 없는 오브젝트 코드(예를 들어 클래스 및 예외에 관한 다른 ABI에 기초한 코드)를 생성하는 컴파일러는 다른 이름 망글링 방식을 사용하는 것이 안전상의 목적으로 좋다.이것에 의해, 이러한 비호환성이 소프트웨어의 실행이 아닌 링크 국면에서 검출되는 것이 보증됩니다(불명한 버그나 심각한 안정성의 문제가 발생할 가능성이 있습니다).

따라서 이름 장식은 C++ 관련 ABI에서 중요한 측면입니다.

c++필트를 통한 디멘글링

$ c++filt - n _ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16 디폴트Allocator E3에는ERKS0_ <StringName, 참조 <GDScript>, 비교기 <StringName>, 기본값Allocator > : : has ( StringName const & ) const

내장 GCC ABI를 통한 디멘글링

#실패하다 <stdio.h> #실패하다 <stdlib.h> #실패하다 <cxabi.h>  인트 주된() {  컨스턴트  *magraged_name = "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16 디폴트Allocator E3에는ERKS0_";  인트 상황 = -1;   *해제_이름 = abi::__cxa_demangle(magraged_name, 특수한 순서, 특수한 순서, &상황);  인쇄물("해제: %s\n", 해제_이름);  공짜(해제_이름);  돌아가다 0; } 

출력:

Demangled: Map<StringName, Ref<GDScript>, Comparator<StringName>, DefaultAllocator>::has(StringName const&) const 

자바

Java에서 메서드 또는 클래스의 시그니처는 해당 이름과 메서드 인수 및 반환 값의 유형을 포함합니다(해당하는 경우).시그니처의 형식은 언어, 컴파일러 및 .class 파일 형식이 모두 함께 설계되었기 때문에 문서화되어 있습니다(개체 지향성과 범용 상호 운용성을 처음부터 염두에 두고 있습니다).

내부 및 익명 클래스에 대한 고유한 이름 만들기

어나니머스 클래스의 범위는 부모 클래스로 한정되므로 컴파일러는 같은 이름(내부 또는 비내부)의 다른 클래스가 같은 네임스페이스에 존재하는 경우 충돌을 피하기 위해 내부 클래스의 "수식" 공용 이름을 생성해야 합니다.마찬가지로 익명 클래스에는 생성된 "가짜" 공용 이름이 있어야 합니다(익명 클래스 개념은 실행 시간이 아닌 컴파일러에만 존재하기 때문입니다).그래서 다음과 같은 자바 프로그램을 컴파일 합니다.

일반의 학급 후우 {     학급 막대기 {         일반의 인트 x;     }      일반의 무효 자크 () {         물건 f = 신규 물건 () {             일반의 스트링 문자열() {                 돌아가다 "안녕하세요";             }         };     } } 

그럼 3개의 .class 파일이 생성됩니다.

  • foo.class(메인(메인) 클래스 foo 포함)
  • foo$bar.class. 이름 있는 내부 클래스 foo.bar를 포함합니다.
  • foo$1.class. 어나니머스 내부 클래스(메서드 foo.zark의 로컬)를 포함합니다.

이러한 클래스 이름은 모두 유효하며(JVM 사양에서 $ 심볼이 허용되므로), Java 언어 정의에서는 일반 Java 클래스 정의에서 $ 심볼을 사용하지 않도록 권장하고 있으므로 컴파일러가 생성하기에 "안전"합니다.

Java에서의 이름 해결은 실행 시 더욱 복잡합니다. 완전 수식 클래스 이름은 특정 클래스 로더 인스턴스 내에서만 고유하기 때문입니다.클래스로더는 계층적으로 정렬되며 JVM의 각 스레드에는 이른바 컨텍스트클래스 로더가 있습니다.따라서 2개의 다른 클래스로더 인스턴스가 같은 이름의 클래스를 포함하는 경우 시스템은 먼저 루트(또는 시스템) 클래스로더를 사용하여 클래스를 로드한 후 컨텍스트클래스 로더로 계층을 내려갑니다.

Java 네이티브 인터페이스

Java의 네이티브 메서드 지원을 통해 Java 언어 프로그램은 다른 언어로 작성된 프로그램(일반적으로 C 또는 C++)을 호출할 수 있습니다.이름 해결에는 두 가지 문제가 있지만, 둘 다 특별히 표준적인 방법으로 구현되지 않습니다.

  • JVM에서 네이티브 이름으로 변환 - Oracle이 스킴을 [7]공개하기 때문에 더 안정적인 것 같습니다.
  • 일반 C++ 이름 망글링 - 위 참조.

파이썬

Python에서는 mangling은 하위 클래스가 두 개 이상의 선행 밑줄과 후행 밑줄을 가진 이름을 지정함으로써 사용하지[8] 않는 클래스 속성에 사용됩니다.예를들면,__thing파괴될 것이다.___thing그리고.__thing_,그렇지만__thing__그리고.__thing___하지 않을 것이다.Python의 런타임은 이러한 속성에 대한 액세스를 제한하지 않습니다. Mangling은 파생 클래스가 동일한 이름의 속성을 정의하는 경우에만 이름 충돌을 방지합니다.

이름이 망가진 속성이 발견되면 Python은 다음과 같이 단일 밑줄과 둘러싸인 클래스의 이름을 추가하여 이러한 이름을 변환합니다.

>>>학급 시험: ...    방어하다 __sublicled_name(자신): ...        통과하다 ...    방어하다 normal_name(자신): ...        통과하다 >>>t = 시험() >>>[특성 위해서 특성  디르(t) 한다면 "이름  특성] ['_Test__mangled_name', 'normal_name'] 

파스칼

볼랜드의 터보 파스칼 / 델파이 레인지

Pascal에서 이름 뭉치를 방지하려면 다음을 사용합니다.

수출.   마이 펑크 이름. '마이펑크',   myProc 이름. 'myProc'; 

프리 파스칼

Free Pascal은 함수 및 연산자 오버로드를 지원하므로 이러한 기능을 지원하기 위해 이름 망글링도 사용합니다.반면 프리 파스칼은 다른 언어로 작성된 외부 모듈에 정의된 기호를 호출하고 다른 언어로 호출할 수 있도록 자체 기호를 내보낼 수 있다.자세한 내용은 Free Pascal Programmer's Guide 6.2장7.1장참조하십시오.

포트란

원래 언어가 대소문자를 구분하지 않기 때문에 Fortran 컴파일러에서도 이름 망글링이 필요합니다.Fortran 90 표준에 모듈 및 기타 기능이 추가되었기 때문에 언어의 진화 과정에서 추가적인 망글링 요구 조건이 부과되었습니다.특히 케이스 망글링은 LAPACK 등의 Fortran 라이브러리를 C 의 다른 언어에서 호출하기 위해 대처해야 하는 일반적인 문제입니다.

대소문자를 구분하지 않기 때문에 서브루틴 또는 함수의 이름FOO는 컴파일러에 의해 표준화된 케이스와 형식으로 변환되어 대소문자를 불문하고 동일한 방식으로 링크되어야 합니다.다양한 컴파일러가 이를 다양한 방법으로 구현하고 있으며 표준화는 이루어지지 않았습니다.AIX 및 HP-UX Fortran 컴파일러는 모든 식별자를 소문자로 변환합니다.foo단, Cray Unicos Fortran 컴파일러는 식별자를 모두 대문자로 변환합니다.FOO GNUg77 컴파일러는 식별자를 소문자와 밑줄로 변환합니다.foo_(이미 밑줄이 포함되어 있는 식별자 제외)FOO_BAR밑줄이 두 개 붙어 있다foo_bar__f2c에 의해 확립된 규약에 따릅니다.SGIIRIX 컴파일러, GNU Fortran, 인텔의 Fortran 컴파일러(Microsoft Windows 제외)를 포함한 많은 다른 컴파일러는 모든 식별자를 소문자와 밑줄로 변환합니다.foo_그리고.foo_bar_(각각).Microsoft Windows 에서는, 인텔 Fortran 컴파일러는 디폴트로 밑줄 [9]없이 대문자로 되어 있습니다.

Fortran 90 모듈의 식별자는 서로 다른 모듈에서 동일한 절차 이름이 발생할 수 있으므로 더 많이 혼합해야 합니다.Fortran 2003 표준에서는 모듈 프로시저 이름이 다른 외부 [10]기호와 충돌하지 않도록 요구하기 때문에 컴파일러는 모듈 이름과 프로시저 이름을 구분하여 사용하는 경향이 있습니다.예를 들어 다음과 같습니다.

모듈m  포함하다    정수기능.다섯개()       다섯개 = 5    엔드 함수다섯개 엔드 모듈m 

이 모듈에서는 함수의 이름이 다음과 같이 뭉개집니다.__m_MOD_five(예: GNU Fortran),m_MP_five_(예: 인텔의 ifort),m.five_(예를 들어 Oracle의 Sun95) 등Fortran은 프로시저의 이름을 오버로드 할 수 없지만 범용 인터페이스 블록과 범용 타입 바운드프로시저를 대신 사용하기 때문에 망가지어 있는 이름에는 인수에 대한 단서를 포함할 필요가 없습니다.

Fortran 2003 BIND 옵션은 위와 같이 컴파일러에 의해 수행된 이름 망글을 덮어씁니다.

함수 이름은 기본적으로 Rust에서 뭉개집니다.다만, 이것은, 에 의해서 디세블로 할 수 있습니다.#[no_mangle]함수 아트리뷰트.이 속성을 사용하여 함수를 C, C++ 또는 Objective-C로 [11]내보낼 수 있습니다.또한,#[start]기능 속성 또는#[no_main]crate 속성. 사용자가 프로그램의 [12]C 스타일 진입점을 정의할 수 있습니다.

Rust는 컴파일 시 선택할 수 있는 많은 버전의 심볼 머글링 스킴을 사용해 왔습니다.-Z symbol-mangling-version선택.다음 망글러가 정의되어 있습니다.

  • legacyItanium IA-64 C++ ABI를 기반으로 한 C++ 스타일 머글링.기호는 로 시작합니다._ZN및 파일 이름 해시는 명확화를 위해 사용됩니다.Rust 1.[13]9 이후 사용.
  • v0기존 스킴의 개량된 버전으로, Rust에 대한 변경사항이 있습니다.기호는 로 시작합니다._R다형성을 부호화할 수 있습니다.함수에 인코딩된 반환 유형이 없습니다(Rust에는 오버로드가 없습니다).Unicode 이름에는 수정된 Punycode가 사용됩니다.압축(백레퍼런스)은 바이트 기반 주소 지정을 사용합니다.Rust 1.37 [14]이후 사용.

예는 "Rust" (녹)에 기재되어 있습니다.symbol-names테스트를 [15]실시합니다.

목표-C

기본적으로 Objective-C에는 클래스("static") 메서드인스턴스 메서드의 두 가지 형식이 있습니다.Objective-C의 메서드 선언은 다음과 같은 형식입니다.

+ (return-type) 이름0: 파라미터01 이름: 파라미터1 ...– (return-type) 이름0: 파라미터01 이름: 파라미터1... 

클래스 메서드는 +, 인스턴스 메서드는 -로 나타냅니다.일반 클래스 메서드 선언은 다음과 같습니다.

+ (아이디) initWithX: (인트) 번호 그리고 Y: (인트) 번호; + (아이디) 신규; 

인스턴스 메서드는 다음과 같습니다.

- (아이디) 가치; - (아이디) set Value: (아이디) new_value; 

이러한 메서드 선언은 각각 특정 내부 표현을 가지고 있습니다.컴파일 시 클래스 메서드의 다음 스킴에 따라 각 메서드의 이름이 지정됩니다.

_c_Class_name_name_01... 

인스턴스 메서드의 경우 다음과 같습니다.

_i_Class_name_name_01... 

Objective-C 구문의 콜론은 밑줄로 변환됩니다.그래서 Objective-C 클래스 메서드는+ (id) initWithX: (int) number andY: (int) number;(에 속해 있는 경우Point클래스는 로 번역됩니다._c_Point_initWithX_andY_및 인스턴스 메서드(같은 클래스에 추가)- (id) value;로 번역될 것이다._i_Point_value.

클래스의 각 메서드는 이러한 방식으로 레이블이 지정됩니다.그러나 모든 메서드가 이러한 방식으로 표현되어 있다면 클래스가 응답할 수 있는 메서드를 찾는 것은 지루할 것입니다.각 메서드에는 고유한 기호(예: 정수)가 할당됩니다.이러한 기호를 선택기라고 합니다.Objective-C에서는 셀렉터를 직접 관리할 수 있습니다.실렉터는 Objective-C에 특정 유형이 있습니다.SEL.

컴파일 중에 다음과 같은 텍스트 표현을 매핑하는 테이블이 작성됩니다._i_Point_value셀렉터(타입이 지정됨)로 이동합니다.SEL). 셀렉터를 관리하는 것이 메서드의 텍스트 표현을 조작하는 것보다 효율적입니다.셀렉터는 메서드 이름에만 일치하며 소속 클래스는 일치하지 않습니다.클래스에 따라 같은 이름의 메서드 구현이 다를 수 있습니다.이것 때문에, 메서드의 구현은 또한 특정 식별자를 부여받으며, 이들은 구현 포인터라고 알려져 있으며, 유형도 부여된다.IMP.

송신되는 메시지는 컴파일러에 의해 콜로서 부호화됩니다.id objc_msgSend (id receiver, SEL selector, ...)기능, 또는 그 사촌 중 하나, 여기서receiver메시지의 수신자이며,SEL에, 콜의 방식을 지정합니다.각 클래스에는 실장에 실렉터를 매핑하는 자체 테이블이 있습니다.실장 포인터는 메서드의 실제 실장이 메모리 내에 존재하는 위치를 지정합니다.클래스 메서드와 인스턴스 메서드에는 별도의 테이블이 있습니다.에 저장되는 것 외에SEL로.IMP검색 테이블, 함수는 기본적으로 익명입니다.

SEL셀렉터의 값은 클래스 간에 변경되지 않습니다.이것에 의해, 다형성이 유효하게 됩니다.

Objective-C 런타임에는 인수 및 메서드 반환 유형에 대한 정보가 유지됩니다.그러나 이 정보는 메서드 이름의 일부가 아니며 클래스에 따라 다를 수 있습니다.

Objective-C는 네임스페이스를 지원하지 않으므로 클래스 이름(생성된 이진에서 기호로 표시됨)을 망글할 필요가 없습니다.

재빠르다

Swift는 함수(및 기타)에 대한 메타데이터를 해당 함수를 참조하는 찌그러진 기호로 보관합니다.이 메타데이터에는 함수 이름, 속성, 모듈 이름, 매개 변수 유형, 반환 유형 등이 포함됩니다.예를 들어 다음과 같습니다.

메서드의 뭉개진 이름func calculate(x: int) -> intMyClass모듈 내 클래스test_TFC4test7MyClass9calculatefS0_FT1xSi_Si, 2014 Swift.컴포넌트와 [16]그 의미는 다음과 같습니다.

  • _T: 모든 Swift 기호의 접두사.모든 것은 이 일에서 시작될 것이다.
  • F: 건조되지 않은 함수.
  • C: 클래스의 함수, 즉 메서드
  • 4test: 모듈 이름. 그 길이가 프리픽스 붙습니다.
  • 7MyClass: 함수가 속한 클래스의 이름으로, 그 길이가 앞에 붙습니다.
  • 9calculate: 함수 이름. 그 길이가 앞에 붙습니다.
  • f: 함수 속성.이 경우 'f'는 정상적인 기능을 의미합니다.
  • S0: 첫 번째 파라미터(클래스 인스턴스)의 유형을 유형 스택의 첫 번째 파라미터(여기서는 클래스 인스턴스)로 지정합니다.MyClass는 네스트되지 않기 때문에 인덱스 0)이 됩니다.
  • _FT: 함수의 파라미터 태플 타입 리스트가 시작됩니다.
  • 1x: 함수의 첫 번째 파라미터 외부명.
  • Si: Swift 타입의 빌트인을 나타냅니다.첫 번째 파라미터의 Int.
  • _Si: 반환 유형: 다시 스위프트.내부.

Swift 4.0 이후 버전의 망글링은 공식적으로 문서화되어 있습니다.Itanium과 [17]비슷한 점이 있습니다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ "Application Binary Interface - D Programming Language". dlang.org. Retrieved 2020-05-19.
  2. ^ Rainer, Schuetze (20 December 2017). "D's Newfangled Name Mangling". The D Blog. Retrieved 2020-05-19.
  3. ^ Clang - Features and Goals: GCC Compatibility, 15 April 2013
  4. ^ JBIntel_deleted_06032015. "OBJ differences between Intel Compiler and VC Compiler". software.intel.com.
  5. ^ "MSVC compatibility". Retrieved 13 May 2016.
  6. ^ "Itanium C++ ABI, Section 5.1 External Names (a.k.a. Mangling)". Retrieved 16 May 2016.
  7. ^ "Design Overview". docs.oracle.com.
  8. ^ "PEP 8 -- Style Guide for Python Code".
  9. ^ "Summary of Mixed-Language Issues". User and Reference Guide for the Intel Fortran Compiler 15.0. Intel Corporation. Retrieved 17 November 2014.
  10. ^ "Documentation Library".
  11. ^ "Foreign Function Interface # Calling Rust code from C". Rust Manual. rust-lang.org. Retrieved 13 May 2016.
  12. ^ "No stdlib". Rust Manual. rust-lang.org. Retrieved 13 May 2016.
  13. ^ "rust/src/librustc_codegen_utils/symbol_names/legacy.r.rs at 57e1da59cd0761330b4ea8d47b16340a78eeafa9 · rust-lang/rust · GitHub". GitHub. 3 November 2021.
  14. ^ "Rust Symbol Mangling". The Rust RFC Book.
  15. ^ "Rust 1.42.0: src/test/ui/symbol-names". Github. Retrieved 20 March 2020.
  16. ^ "mikeash.com: Friday Q&A 2014-08-15: Swift Name Mangling". mikeash.com.
  17. ^ "apple/swift: mangling.rst". GitHub. 3 November 2021.

외부 링크