네임 맹글링
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
네임 맹글링은 컴파일러가 함수 오버로딩, 네임스페이스, 템플릿과 같은 기능을 지원하기 위해 사용하는 기술로, 심볼(함수, 변수 등)의 이름을 변경하여 고유성을 확보한다. C++은 표준화된 맹글링 규칙이 없어 컴파일러에 따라 규칙이 다르며, 윈도우 플랫폼에서는 호출 규약을 명시하기 위해 맹글링 체계를 사용한다. 자바는 내부 클래스 및 익명 클래스에 대한 고유한 이름 생성과 JNI를 통한 네이티브 코드 연동 시 맹글링과 유사한 변환이 발생한다. 파이썬, 파스칼, 포트란, Rust, Objective-C, Swift 등 다양한 프로그래밍 언어에서도 맹글링을 활용하며, 각 언어의 특성에 맞게 맹글링 규칙이 정의되어 있다.
더 읽어볼만한 페이지
- 자바 (프로그래밍 언어) - 자바 애플릿
자바 애플릿은 웹 페이지에서 실행되는 자바 기반 프로그램으로, 웹 상호작용성을 높였으나 기술적 문제와 웹 표준 기술 발전에 따라 쇠퇴하여 사용이 중단되었다. - 자바 (프로그래밍 언어) - 자바FX
JavaFX는 자바 기반의 UI 구축 플랫폼으로, 다양한 플랫폼을 지원하며 풍부한 UI 기능들을 제공하고, Java 8부터 JDK에 포함되었다가 JDK 11부터 분리되어 관리된다. - 컴파일러 구성 - 구문 분석
구문 분석은 입력 데이터를 구조화된 형태로 변환하는 과정으로, 컴퓨터 언어에서는 소스 코드를 분석하여 추상 구문 트리를 생성하고, 자연어 처리에서는 텍스트의 문장 구조와 의미를 분석한다. - 컴파일러 구성 - 바이너리 재컴파일러
- 라이브러리 - 바이너리 재컴파일러
- 라이브러리 - 동적 링크 라이브러리
동적 링크 라이브러리(DLL)는 윈도우 운영체제에서 프로그램 실행 시 필요한 코드와 데이터를 제공하며, 여러 프로그램에서 공유되어 메모리 효율성을 높이고 모듈성을 향상시키는 라이브러리 형식이다.
네임 맹글링 | |
---|---|
이름 | |
한국어 | 네임 맹글링 |
영어 | Name mangling |
일본어 | 名前修飾 (나마에 슈우쇼쿠) |
개요 | |
정의 | 컴파일러가 프로그래밍 언어에서 사용하는 이름의 원래 형태를 변경하는 과정이다. |
목적 | 링커와 로더가 프로그램의 여러 부분을 올바르게 연결할 수 있도록 돕는다. |
다른 이름 | 이름 장식(name decoration)이라고도 한다. |
동작 방식 | |
함수 이름 변경 | 함수 이름에 추가 정보를 추가한다. 추가 정보 예시: 매개변수 타입, 반환 타입, 클래스 이름 등 |
이유 | 동일한 이름의 함수를 여러 개 정의할 수 있도록 지원 (함수 오버로딩) 링커가 올바른 함수를 호출할 수 있도록 보장 |
사용 언어 | |
사용 언어 예시 | C++ 델파이 포트란 |
설명 | 각 언어는 고유한 이름 맹글링 규칙을 사용한다. |
예시 (C++) | |
원래 함수 이름 | void foo(int i) |
맹글링된 이름 (컴파일러에 따라 다름) | _Z3fooi |
장점 | |
장점 | 함수 오버로딩 지원 타입 안정성 향상 네임스페이스 지원 |
단점 | |
단점 | 맹글링된 이름은 사람이 읽기 어렵다. 다른 언어로 작성된 라이브러리와의 호환성이 떨어질 수 있다. |
활용 | |
활용 | 동적 라이브러리 정적 라이브러리 컴파일러 링커 |
2. C/C++ 이름 맹글링
C++ 컴파일러는 함수 오버로딩, 네임스페이스, 클래스, 템플릿 등의 기능을 지원하기 위해 이름 맹글링을 사용한다. C++는 표준화된 맹글링 규칙이 없어 컴파일러마다 다른 규칙을 사용하므로, 서로 다른 컴파일러에서 생성된 오브젝트 파일 간의 링크가 실패할 수 있다.[4]
최초의 C++ 컴파일러는 C 소스 코드로 변환하는 방식으로 구현되었으며, C 컴파일러가 이를 객체 코드로 컴파일했다. 이 때문에 심볼 이름은 C 식별자 규칙을 따라야 했다. 이후 기계어 또는 어셈블리를 직접 생성하는 컴파일러가 등장했지만, 시스템의 링커는 일반적으로 C++ 심볼을 지원하지 않았고, 여전히 맹글링이 필요했다.
C++는 표준 데코레이션 방식을 정의하지 않으므로, 각 컴파일러는 자체적인 방식을 사용한다. C++는 연산자 오버로딩과 같은 복잡한 언어 기능을 가지고 있으며, 이는 특정 심볼의 의미를 문맥이나 사용법에 따라 변경한다. 이러한 기능에 대한 메타데이터는 심볼의 이름을 맹글링(데코레이션)하여 구별한다.
일반적인 C는 함수의 다중 정의를 지원하지 않아 이름 수식이 필요하지 않지만, 경우에 따라 이름 수식을 통해 함수에 대한 정보를 추가할 수 있다. 예를 들어, Microsoft Windows 상의 컴파일러는 여러 호출 규약을 지원하며, 호출 규약 간에는 호환성이 없으므로 컴파일러는 이름 수식을 통해 호출 규약을 상세히 기술한다. 마이크로소프트에 의해 확립된 이름 수식 체계는 디지털 마스, C++ 빌더 (보르랜드 C), gcc 등 다른 컴파일러도 비공식적으로 따른다.
2. 1. 컴파일러별 맹글링 규칙 (C/C++)
C++는 표준화된 맹글링 방식을 가지고 있지 않기 때문에, 컴파일러마다(혹은 같은 컴파일러라도 버전이나 플랫폼에 따라) 서로 다른 맹글링 규칙을 적용한다. 이는 링커 단계에서 심볼을 찾지 못하는 문제를 야기할 수 있다.다음 표는 다양한 C/C++ 컴파일러들이 `void h(int)`, `void h(int, char)`, `void h(void)` 함수에 대해 어떻게 다른 맹글링 이름을 생성하는지 보여준다.
컴파일러 | |||
---|---|---|---|
인텔 C++ 8.0 for Linux | _Z1hi | _Z1hic | _Z1hv |
HP aC++ A.05.55 IA-64 | |||
IAR EWARM C++ | |||
GCC 3.x 이상 | |||
Clang 1.x 이상[19] | |||
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 |
Digital Mars C++ | |||
Borland C++ v3.1 | @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 |
몇 가지 특이사항은 다음과 같다.
- Compaq C++ 컴파일러(OpenVMS VAX, DEC Alpha(IA-64 제외), Tru64 UNIX)는 ARM 모델과 ANSI 모델, 두 가지 맹글링 체계를 사용한다. ARM 모델은 표준화 이전 방식이며, ANSI 모델은 템플릿을 지원하지만 이전 버전과 호환되지 않는다.
- IA-64는 표준 응용 프로그램 이진 인터페이스(ABI)가 존재하며, 모든 IA-64 컴파일러는 표준 이름 맹글링 체계를 따른다. GCC 3.x 버전부터는 이 표준을 채택하여 다른 플랫폼에서도 사용한다.
- 마이크로소프트 윈도우에서 인텔 컴파일러[2]와 Clang[3]은 Visual C++ 이름 맹글링을 사용하여 호환성을 유지한다.
2. 1. 1. C 맹글링 (Windows)
C영어 컴파일러는 다양한 호출 규약을 지원하며, 이는 매개변수가 서브루틴으로 전달되고 결과가 반환되는 방식을 결정한다. 서로 다른 호출 규약은 서로 호환되지 않기 때문에 컴파일러는 특정 루틴을 호출하는 데 사용해야 하는 규약을 자세히 설명하는 코드로 기호를 맹글링한다.[1]윈도우용 맹글링 체계는 마이크로소프트에 의해 확립되었으며, Digital Mars, 보르랜드, GNU 컴파일러 모음(GCC)을 포함한 다른 컴파일러가 윈도우 플랫폼용 코드를 컴파일할 때 비공식적으로 따랐다.[1] 이 체계는 Pascal, D, Delphi, 포트란, C#과 같은 다른 언어에도 적용된다.[1] 이를 통해 해당 언어로 작성된 서브루틴은 기본값과 다른 호출 규약을 사용하여 기존 윈도우 라이브러리를 호출하거나 호출될 수 있다.[1]
다음 C영어 예제를 컴파일할 때:[1]
```c
int _cdecl f (int x) { return 0; }
int _stdcall g (int y) { return 0; }
int _fastcall h (int z) { return 0; }
```
32비트 컴파일러는 각각 다음을 출력한다:[1]
```text
_f
_g@4
@h@4
```
`stdcall` 및 `fastcall` 맹글링 체계에서 함수는 각각 `_이름@X` 및 `@이름@X`로 인코딩되며, 여기서 X는 매개변수 목록의 인수의 바이트 수(10진수)이다(fastcall의 경우 레지스터로 전달된 인수를 포함).[1] `cdecl`의 경우 함수 이름은 밑줄로 접두어가 붙는다.[1]
윈도우의 64비트 규약(마이크로소프트 C)에는 선행 밑줄이 없다. 이러한 차이점은 드물게 이러한 코드를 64비트로 포팅할 때 해결되지 않은 externals로 이어질 수 있다.[1] 예를 들어, 포트란 코드는 다음과 같이 'alias'를 사용하여 C 메서드를 이름으로 연결할 수 있다.[1]
```fortran
SUBROUTINE f()
!DEC$ ATTRIBUTES C, ALIAS:'_f' :: f
END SUBROUTINE
```
이것은 32비트에서는 제대로 컴파일 및 연결되지만 64비트에서는 해결되지 않은 외부 `_f`를 생성한다. 이에 대한 해결 방법 중 하나는 'alias'를 전혀 사용하지 않는 것이다(이 경우 메서드 이름은 일반적으로 C 및 포트란에서 대문자로 표시되어야 함). 다른 방법은 BIND 옵션을 사용하는 것이다.[1]
```fortran
SUBROUTINE f() BIND(C,NAME="f")
END SUBROUTINE
2. 1. 2. C++ 맹글링 예시
cppnamespace wikipedia {
class article {
public:
std::string format (void);
/* = _ZN9wikipedia7article6formatEv */
bool print_to (std::ostream&);
/* = _ZN9wikipedia7article8print_toERSo */
class wikilink {
public:
wikilink (std::string const& name);
/* = _ZN9wikipedia7article8wikilinkC1ERKSs */
};
};
}
```
GNU GCC 3.x 컴파일러의 맹글링 방식은 다음과 같다. 맹글링된 이름은 모두 `_Z`로 시작하는데, 이는 밑줄과 대문자로 시작하는 식별자가 C와 C++에서 시스템용으로 예약되어 사용자 식별자와 충돌하지 않도록 하기 위함이다.[16][17] 중첩된 이름(네임스페이스, 클래스)은 `N`으로 시작하고, `<길이, 식별자>` 쌍(여기서 '길이'는 해당 식별자의 길이)이 이어지며, 마지막은 `E`이다. 예를 들어 `wikipedia::article::format`은 다음과 같이 맹글링된다.
```
_ZN9wikipedia7article6formatE
```
함수는 형식 정보가 추가된다. `format()`은 `void` 함수이므로 `v`가 붙어 다음과 같이 된다.
```
_ZN9wikipedia7article6formatEv
```
`print_to`는 표준 형식 `std::ostream`(`std::basic_ostream
```
_ZN9wikipedia7article8print_toERSo
```
C++에는 표준 맹글링 방식이 없어 컴파일러 제조사, 버전, 플랫폼에 따라 호환되지 않는 방식을 쓸 수 있다. 다음은 여러 컴파일러가 같은 함수에 대해 생성하는 맹글링 이름 예시다.
컴파일러 | void h(int) | void h(int, char) | void h(void) |
---|---|---|---|
clang 1.x | _Z1hi | _Z1hic | _Z1hv |
GNU GCC 3.x | _Z1hi | _Z1hic | _Z1hv |
GNU GCC 2.9x | h__Fi | h__Fic | h__Fv |
Intel C++ 8.0 for Linux | _Z1hi | _Z1hic | _Z1hv |
마이크로소프트 비주얼 C++ v6/v7 | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
Borland C++ v3.1 | @h$qi | @h$qizc | @h$qv |
OpenVMS C++ V6.5 (ARM 모드) | H__XI | H__XIC | H__XV |
OpenVMS C++ V6.5 (ANSI 모드) | CXX$__7H__FI0ARG51T | CXX$__7H__FIC26CDH77 | CXX$__7H__FV2CB06E8 |
OpenVMS C++ X7.1 IA-64 | CXX$_Z1HI2DSQ26A | CXX$_Z1HIC2NP3LI4 | CXX$_Z1HV0BCA19V |
Digital Mars C++ | ?h@@YAXH@Z | ?h@@YAXHD@Z | ?h@@YAXXZ |
SunPro CC | __1cBh6Fi_v_ | __1cBh6Fic_v_ | __1cBh6F_v_ |
HP aC++ A.05.55 IA-64 | _Z1hi | _Z1hic | _Z1hv |
HP aC++ A.03.45 PA-RISC | h__Fi | h__Fic | h__Fv |
Tru64 C++ V6.5 (ARM 모드) | h__Xi | h__Xic | h__Xv |
Tru64 C++ V6.5 (ANSI 모드) | __7h__Fi | __7h__Fic | __7h__Fv |
참고:
- OpenVMS VAX, DEC Alpha(IA-64 제외) 및 Tru64 UNIX의 Compaq C++ 컴파일러는 두 가지 맹글링 방식을 쓴다. ARM 모델은 표준화 이전 방식으로, 『The Annotated C++ Reference Manual (ARM)』(번역본 『주해 C++ 레퍼런스 매뉴얼』)에 기술되었다. ANSI 모델은 표준 C++ 템플릿을 지원하나 이전 버전과 호환되지 않는다.
- IA-64는 애플리케이션 바이너리 인터페이스(ABI) 표준 이름 맹글링 규칙(Itanium C++ ABI mangling)이 있어 모든 IA-64 컴파일러가 쓴다. GNU GCC 3.x도 이 표준을 따르며 인텔 환경 외에서도 쓸 수 있다.
2. 2. C++에서 C 심볼 처리
C++ 코드에서 C 함수를 호출할 때 맹글링 문제가 발생할 수 있다. C++ 컴파일러는 함수 이름을 맹글링하여 고유한 이름을 생성하지만, C 컴파일러는 맹글링을 하지 않기 때문이다. 이 문제를 해결하기 위해 `extern "C"`를 사용한다.`extern "C"` 블록 안에 C 함수 선언을 넣으면, C++ 컴파일러는 해당 함수 이름을 맹글링하지 않고 C 스타일로 처리한다. 이렇게 하면 C++ 코드에서 C 함수를 문제없이 호출할 수 있다.
예를 들어, 표준 C 라이브러리 헤더 파일 `
```cpp
#ifdef __cplusplus
extern "C" {
#endif
void *memset (void *, int, size_t);
char *strcat (char *, const char *);
int strcmp (const char *, const char *);
char *strcpy (char *, const char *);
#ifdef __cplusplus
}
#endif
```
이렇게 하면 C++ 코드에서 `strcmp`, `strcpy`, `memset` 등의 C 함수를 사용할 때 링커 오류가 발생하는 것을 방지할 수 있다. `extern "C"`를 사용하지 않으면 C++ 컴파일러는 맹글링된 이름을 생성하여 C 런타임 라이브러리에 존재하지 않는 심볼을 참조하게 되기 때문이다.
일반적인 C와 파스칼 등의 언어는 함수의 다중 정의를 지원하지 않아 이름 수식이 필요하지 않지만, 경우에 따라 이름 수식을 통해 함수에 대한 정보를 추가할 수 있다.
예를 들어, Microsoft Windows 상의 컴파일러는 여러 호출 규약 (서브루틴과 데이터를 주고받는 방법)을 지원한다. 호출 규약 간에는 호환성이 없으므로 컴파일러는 이름 수식을 통해 호출 규약을 상세히 기술한다.
마이크로소프트에 의해 확립된 이름 수식 체계가 있으며, 비공식적으로 다른 컴파일러도 이를 따른다. 예를 들어, 디지털 마스, C++ 빌더(보르랜드 C), gcc가 있다. 이 체계는 다른 언어, 예를 들어 파스칼, D 언어, 델파이, FORTRAN, C#에도 적용된다. 이처럼 해당 처리 시스템의 기본 호출 규약이 다른 경우에도 해당 처리 시스템에서 생성된 서브루틴이 기존의 Windows 라이브러리를 호출하거나, 거기에서 호출될 수 있다.
다음 C 코드를 컴파일한다고 하자:
```c
int _cdecl f(int x) { return 0; }
int _stdcall g(int y) { return 0; }
int _fastcall h(int z) { return 0; }
```
`_cdecl`은 C의 표준 호출 규약을 사용할 것을 명시하는 수식어이다.
32비트 컴파일러는 각각 다음을 출력한다.
```text
_f
_g@4
@h@4
```
`stdcall`과 `fastcall`에서는 함수 이름이 `_'''이름'''@'''X'''` 및 ` @'''이름'''@'''X'''`와 같이 인코딩된다. `X`에는 콜 스택 (이하 단순히 스택)에 쌓이는 인수의 바이트 수가 들어간다.
다른 일반적인 수식 방법으로는 ( `__f`와 같이) 여러 개의 밑줄로 접두사를 추가하는 방법이 있다.
2. 3. C++ 맹글링 표준화의 어려움
C++(C++) 언어는 표준화된 맹글링 방식을 정의하지 않으므로, 컴파일러마다 각기 다른 방식을 사용한다. 이는 응용 프로그램 바이너리 인터페이스(ABI) 호환성 문제를 일으키는 주요 원인 중 하나이다.C++는 클래스, 템플릿, 네임스페이스, 연산자 오버로딩과 같은 복잡한 기능을 지원하는데, 이러한 기능들은 심볼의 의미를 문맥에 따라 다르게 해석해야 한다. 따라서 컴파일러는 이러한 메타데이터를 심볼 이름에 맹글링(데코레이션)하여 구별한다. 그러나 이 맹글링 방식이 컴파일러 간에 표준화되어 있지 않아, 서로 다른 컴파일러에서 생성된 객체 코드를 링커가 제대로 연결하지 못하는 문제가 발생한다.[4]
표준화된 네임 맹글링은 컴파일러 구현 간의 상호 운용성을 높일 수 있지만, 이것만으로는 C++ 컴파일러의 완전한 상호 운용성을 보장할 수 없다. 예외 처리, 가상 함수 테이블 레이아웃, 구조체 및 스택 프레임 패딩 등 다른 ABI 요소들도 구현 간 비호환성을 유발하기 때문이다.
또한, 특정 형태의 맹글링을 강제하면 심볼 길이 제한과 같은 구현상의 제약이 있는 시스템에서 문제가 발생할 수 있다. 표준화된 맹글링 ''요구 사항''은 C++ 언어를 이해하는 링커와 같이 맹글링이 불필요한 구현을 방해할 수도 있다.
이러한 이유로 C++ 표준은 네임 맹글링을 표준화하지 않는다. 오히려 ''주석이 달린 C++ 참조 매뉴얼''(''ARM'', 7.2.1c절)은 ABI의 다른 측면이 호환되지 않을 때 링크를 방지하기 위해 서로 다른 맹글링 체계를 사용할 것을 권장한다.
특히 크고 복잡한 코드 베이스에서는 링커 오류 메시지에 나타나는 맹글링된 이름을 소스 코드의 해당 토큰/변수 이름으로 다시 매핑하는 것이 어렵거나 비현실적일 수 있다. 이 문제는 단일 컴파일러 및 링커를 사용하더라도 빌드 또는 테스트 엔지니어가 관련 소스 파일을 식별하는 것을 매우 어렵게 만들 수 있다. 디맹글러(링커 오류 보고 메커니즘 내 포함)가 때때로 도움이 되지만, 맹글링 메커니즘 자체가 중요한 식별 정보를 제거할 수 있다.
3. Java 이름 맹글링
자바는 언어, 컴파일러, `.class` 파일 형식이 함께 설계되어, 자바 런타임 환경(JRE) 수준에서는 이름 맹글링 문제가 발생하지 않는다. 하지만 내부 클래스, 무명(익명) 클래스 등에 고유한 이름을 부여하기 위해 이름 변환이 필요하다.
내부 클래스는 부모 클래스로 범위가 제한되므로 컴파일러는 "수식된" 공개 이름을 부여해야 한다. 무명(익명) 클래스는 컴파일러에서만 존재하는 개념이므로 "가짜" 공개 이름을 생성한다. 이러한 이름들은 Java 가상 머신(JVM)에서 유효하며, 컴파일러는 Java 언어 사양에 따라 `$` 기호를 안전하게 사용한다.
자바 네이티브 인터페이스(JNI)는 자바와 네이티브 코드 간의 상호 운용을 위한 표준이다. JNI를 사용하면 자바 프로그램에서 다른 언어(주로 C, C++)로 작성된 코드를 호출할 수 있다. 이때 JVM에서 네이티브 이름으로 변환하는 과정과 C++ 이름 맹글링 문제가 발생할 수 있지만, 표준적인 방식으로 구현되지는 않는다. 오라클은 JVM에서 네이티브 이름으로 변환하는 스키마를 공개했다.[18]
3. 1. 내부 클래스 및 익명 클래스 이름 생성
자바에서 내부 클래스 및 익명 클래스는 부모 클래스의 범위로 제한된다. 따라서 컴파일러는 이러한 클래스에 대해 "정규화된" 공개 이름을 생성하여 동일한 네임스페이스 내 다른 클래스와의 충돌을 방지해야 한다. 익명 클래스의 경우, 컴파일 시에만 존재하고 런타임에는 존재하지 않으므로 "가짜" 공개 이름을 생성한다.예를 들어 다음과 같은 Java 코드를 컴파일하면:
```java
public class Foo {
// 내부 클래스
class bar {
public int x;
}
public void zark() {
// 무명 클래스 인스턴스화
Object f = new Object() {
public String toString() {
return "hello";
}
};
}
}
```
다음과 같은 세 개의 `.class` 파일이 생성된다.
- `Foo.class`: 주 클래스(바깥쪽 클래스) `Foo`를 포함한다.
- `Foo$bar.class`: `Foo.bar`라는 명명된 내부 클래스를 포함한다.
- `Foo$1.class`: 메서드 `Foo.zark`에 대한 지역 무명 내부 클래스를 포함한다.
이러한 클래스 이름들은 모두 Java 가상 머신(JVM) 사양에서 `$` 기호가 허용되므로 유효하다. Java 언어 정의에서는 일반적인 Java 클래스 정의에서 `$` 기호 사용을 권장하지 않으므로, 컴파일러는 이러한 이름을 안전하게 생성할 수 있다.[1]
3. 2. Java Native Interface (JNI)
자바 네이티브 인터페이스(JNI)는 자바와 네이티브 코드를 양방향으로 상호 운용하기 위한 표준 사양이다. 자바의 네이티브 메서드 지원을 통해 자바로 작성된 프로그램에서 다른 언어(일반적으로 C 또는 C++)로 작성된 프로그램을 호출할 수 있다. 여기에는 두 가지 이름 맹글링에 대한 우려가 있는데, 둘 다 특히 표준적인 방식으로 구현되지는 않는다.[18]- JVM에서 네이티브 이름으로의 변환: 오라클이 스키마를 공개했다.[18]
- 일반적인 C++ 이름 맹글링: 앞서 언급한 내용을 참조.
이와는 별도로, 자바 네이티브 액세스(JNA)는 자바 프로그램에서 네이티브 공유 라이브러리에 접근하는 방법을 라이브러리 레벨에서 제공한다.
4. 기타 언어의 이름 맹글링
파이썬, Free Pascal, 포트란, Rust, Objective-C, Swift 등 다양한 프로그래밍 언어에서 네임 맹글링이 사용된다. 각 언어는 고유한 규칙에 따라 네임 맹글링을 수행한다.
- 포트란: 대소문자를 구분하지 않기 때문에 컴파일러는 서브루틴이나 함수 이름을 표준화된 대소문자와 형식으로 변환한다.[7] 모듈 등이 추가되면서 맹글링 규칙이 더 복잡해졌다.[7]
- Rust: 기본적으로 함수 이름이 맹글링되지만, `#[no_mangle]` 속성을 사용하여 비활성화할 수 있다.[9]
- Objective-C: 클래스 메서드와 인스턴스 메서드에 대해 서로 다른 맹글링 규칙이 적용되며, 메서드 이름의 콜론(:)은 밑줄(_)로 변환된다.
- Swift: 함수 이름, 속성, 모듈 이름, 매개변수 유형, 반환 유형 등 함수의 메타데이터를 포함하여 맹글링된 심볼을 생성한다.[14]
4. 1. Python
파이썬에서 맹글링은 하위 클래스가 사용하지 않도록 하려는 클래스 속성에 사용된다.[6] 이는 두 개 이상의 밑줄로 시작하고 하나의 밑줄로 끝나지 않는 이름을 지정하여 표시된다. 예를 들어, `__thing`은 맹글링되고, `___thing`과 `__thing_`도 마찬가지지만, `__thing__`과 `__thing___`은 맹글링되지 않는다. 파이썬 런타임은 이러한 속성에 대한 접근을 제한하지 않으며, 맹글링은 파생 클래스가 동일한 이름의 속성을 정의하는 경우 이름 충돌을 방지할 뿐이다.이름이 맹글링된 속성을 만나면 파이썬은 단일 밑줄과 둘러싸는 클래스의 이름을 앞에 붙여 이러한 이름을 변환한다. 예를 들면 다음과 같다.
```python
class Test:
def __privateSymbol(self):
pass
def normalSymbol(self):
pass
print(dir(Test))
```
위 코드의 실행 결과는 다음과 같다.
```
['_Test__privateSymbol', '__doc__', '__module__', 'normalSymbol']
```
파이썬 프로그래머는 식별자의 처음 두 글자를 밑줄로 시작하여 해당 식별자가 "비공개 이름"(스코프가 클래스로 제한됨)임을 명시적으로 나타낼 수 있다. 파이썬 컴파일러는 이러한 이름을 만나면 밑줄 하나와 식별자를 포함하는 클래스 이름을 앞에 추가하여 비공개 이름을 전역 심볼로 변환한다.
4. 2. Pascal
Free Pascal은 함수와 연산자 오버로딩을 지원하므로 이러한 기능을 지원하기 위해 네임 맹글링을 사용한다. 반면에 Free Pascal은 다른 언어로 생성된 외부 모듈에서 정의된 심볼을 호출하고, 다른 언어에서 호출할 수 있도록 자체 심볼을 내보낼 수 있다. 자세한 내용은 [http://www.freepascal.org/docs-html/prog/progse21.html 6.2장] 및 [http://www.freepascal.org/docs-html/prog/progse27.html 7.1장]을 참고할 수 있다.이러한 파스칼 처리 시스템에서는 다음과 같은 방법으로 이름 맹글링을 억제한다.
```pascal
exports
myFunc name 'myFunc', myProc name 'myProc';
4. 3. Fortran
이름 맹글링은 원래 언어가 대소문자를 구분하지 않기 때문에 포트란 컴파일러에서도 필요하다.[7] 포트란 90 표준에 모듈 및 기타 기능이 추가되면서 언어의 발전에 따라 더 많은 맹글링 요구 사항이 부과되었다.[7] 특히 대소문자 맹글링은 LAPACK과 같은 포트란 라이브러리를 C 언어와 같은 다른 언어에서 호출하기 위해 처리해야 하는 일반적인 문제이다.[7]대소문자를 구분하지 않기 때문에 서브루틴 또는 함수 FOO|FOO영어의 이름은 컴파일러에 의해 표준화된 대소문자 및 형식으로 변환되어야 대소문자와 관계없이 동일한 방식으로 연결된다. 다른 컴파일러는 이를 다양한 방식으로 구현했으며 표준화는 이루어지지 않았다. AIX 및 HP-UX 포트란 컴파일러는 모든 식별자를 소문자 foo|foo영어로 변환하는 반면, Cray 및 Unicos 포트란 컴파일러는 식별자를 모두 대문자 FOO|FOO영어로 변환했다. GNU g77 컴파일러는 식별자를 소문자 더하기 밑줄 foo_|foo_영어로 변환하지만, 밑줄 FOO_BAR|FOO_BAR영어를 이미 포함하는 식별자는 f2c에 의해 설정된 규칙에 따라 밑줄 두 개 foo_bar__|foo_bar__영어가 추가된다. 실리콘 그래픽스(SGI)의 IRIX 컴파일러, GNU Fortran, 인텔의 포트란 컴파일러 (Microsoft Windows 제외)를 포함한 많은 다른 컴파일러는 모든 식별자를 소문자 더하기 밑줄 (각각 foo_|foo_영어 및 foo_bar_|foo_bar_영어)로 변환한다. Microsoft Windows에서 인텔 포트란 컴파일러는 밑줄 없이 기본적으로 대문자를 사용한다.[7]
포트란 90 모듈의 식별자는 동일한 프로시저 이름이 다른 모듈에 나타날 수 있으므로 추가로 맹글링되어야 한다. 포트란 2003 표준은 모듈 프로시저 이름이 다른 외부 심볼과 충돌하지 않도록 요구하기 때문에[8] 컴파일러는 모듈 이름과 프로시저 이름 사이에 뚜렷한 마커를 사용하여 사용한다. 예를 들어 다음과 같다.
```fortran
module m
contains
integer function five()
five = 5
end function five
end module m
```
이 모듈에서 함수의 이름은 __m_MOD_five|__m_MOD_five영어 (예: GNU Fortran), m_MP_five_|m_MP_five_영어 (예: Intel의 ifort), m.five_|m.five_영어 (예: Oracle의 sun95) 등으로 맹글링된다. 포트란은 프로시저 이름의 오버로딩을 허용하지 않지만 일반 인터페이스 블록과 일반 타입-바운드 프로시저를 대신 사용하므로 맹글링된 이름은 인수에 대한 단서를 통합할 필요가 없다.
포트란 2003 BIND 옵션은 컴파일러에서 수행한 모든 이름 맹글링을 재정의한다.
4. 4. Rust
Rust에서는 기본적으로 함수 이름이 맹글링된다. 하지만, `#[no_mangle]` 함수 속성을 사용하여 이 기능을 비활성화할 수 있다. 이 속성은 C, C++, 또는 Objective-C로 함수를 내보낼 때 사용할 수 있다.[9] 또한, `#[start]` 함수 속성 또는 `#[no_main]` 크레이트 속성과 함께 사용하면 사용자가 프로그램의 C 스타일 진입점을 정의할 수 있다.[10]Rust는 `-Z symbol-mangling-version` 옵션을 사용하여 컴파일 시 선택할 수 있는 여러 버전의 심볼 맹글링 스키마를 사용해 왔다. 다음 맹글러가 정의되어 있다.
- `legacy`: Itanium IA-64 C++ ABI를 기반으로 하는 C++ 스타일 맹글링. 심볼은 `_ZN`으로 시작하며, 파일 이름 해시가 모호성을 제거하는 데 사용된다. Rust 1.9부터 사용되었다.[11]
- `v0`: Rust에 맞춰 변경된 레거시 스키마의 개선된 버전. 심볼은 `_R`로 시작한다. 다형성을 인코딩할 수 있다. 함수는 반환 유형을 인코딩하지 않는다(Rust는 오버로딩을 지원하지 않는다). 유니코드 이름은 수정된 Punycode를 사용한다. 압축(역참조)은 바이트 기반 주소를 사용한다. Rust 1.37부터 사용되었다.[12]
예시는 Rust `symbol-names` 테스트에 제공된다.[13]
4. 5. Objective-C
Objective-C에는 클래스 메서드와 인스턴스 메서드 두 가지 종류가 있다. 클래스 메서드는 '+'로 표시하고, 인스턴스 메서드는 '-'로 표시한다. 메서드 선언은 다음과 같은 형태를 가진다.- 클래스 메서드: `+ (반환 타입) 이름0:매개변수0 이름1:매개변수1 ...`
- 인스턴스 메서드: `- (반환 타입) 이름0:매개변수0 이름1:매개변수1 ...`
예를 들어, `Point` 클래스의 클래스 메서드 `+ (id) initWithX: (int) number andY: (int) number;`는 `_c_Point_initWithX_andY_`로, 인스턴스 메서드 `- (id) value;`는 `_i_Point_value`로 맹글링된다. 여기서 콜론(:)은 밑줄(_)로 변환된다.
컴파일 시 각 메서드에는 고유한 심볼인 "셀렉터(selector)" (SEL)가 할당된다. 예를 들어, `_i_Point_value`와 같은 텍스트 표현은 셀렉터에 매핑된다. 셀렉터는 메서드의 이름만 일치시키며, 메서드가 속한 클래스는 일치시키지 않는다. 서로 다른 클래스가 동일한 이름의 메서드를 서로 다르게 구현할 수 있다.
메서드의 구현에는 구현 포인터(implementation pointer) (IMP)라는 식별자가 부여된다. 메시지 전송은 컴파일러에 의해 `id objc_msgSend (id receiver, SEL selector, ...)` 함수 호출로 인코딩된다. 여기서 `receiver`는 메시지 수신자, `SEL`은 호출할 메서드를 결정한다. 각 클래스는 셀렉터를 해당 구현에 매핑하는 자체 테이블을 가지고 있다.
셀렉터에 대한 값은 클래스에 따라 변하지 않으므로, 다형성이 가능하다. Objective-C 런타임은 메서드의 인수와 반환 타입에 대한 정보를 유지하지만, 이 정보는 메서드 이름의 일부가 아니며 클래스마다 다를 수 있다. Objective-C는 네임스페이스를 지원하지 않으므로 클래스 이름 맹글링은 필요하지 않다.
4. 6. Swift
Swift는 함수(및 기타)에 대한 메타데이터를 함수를 지칭하는 네임 맹글링된 심볼에 저장한다. 이 메타데이터에는 함수의 이름, 속성, 모듈 이름, 매개변수 유형, 반환 유형 등이 포함된다.[14]예를 들어, 2014년 Swift에서 모듈 `test`의 `MyClass` 클래스에 있는 `func calculate(x: int) -> int` 메서드의 맹글링된 이름은 `_TFC4test7MyClass9calculatefS0_FT1xSi_Si`이다. 구성 요소와 그 의미는 다음과 같다:[14]
- `_T`: 모든 Swift 심볼의 접두사이다. 모든 것은 이것으로 시작한다.
- `F`: 커리되지 않은 함수이다.
- `C`: 클래스의 함수, 즉 메서드이다.
- `4test`: 모듈 이름이며, 길이를 접두사로 사용한다.
- `7MyClass`: 함수가 속한 클래스의 이름이며, 길이를 접두사로 사용한다.
- `9calculate`: 함수 이름이며, 길이를 접두사로 사용한다.
- `f`: 함수 속성이다. 이 경우 'f'는 일반 함수를 의미한다.
- `S0`: 첫 번째 매개변수(즉, 클래스 인스턴스)의 유형을 유형 스택의 첫 번째 항목으로 지정한다(여기서 `MyClass`는 중첩되지 않으므로 인덱스 0을 갖는다).
- `_FT`: 함수의 매개변수 튜플에 대한 유형 목록을 시작한다.
- `1x`: 함수의 첫 번째 매개변수의 외부 이름이다.
- `Si`: 첫 번째 매개변수에 대한 내장 Swift 유형 Swift.Int를 나타낸다.
- `_Si`: 반환 유형이다. 다시 Swift.Int이다.
Swift 4.0 이후 버전의 맹글링은 공식적으로 문서화되어 있다. Itanium과 약간의 유사성을 유지한다.[15]
참조
[1]
웹사이트
Clang - Features and Goals: GCC Compatibility
http://clang.llvm.or[...]
2013-04-15
[2]
웹사이트
OBJ differences between Intel Compiler and VC Compiler
https://software.int[...]
[3]
웹사이트
MSVC compatibility
http://clang.llvm.or[...]
2016-05-13
[4]
웹사이트
Itanium C++ ABI, Section 5.1 External Names (a.k.a. Mangling)
https://itanium-cxx-[...]
2016-05-16
[5]
웹사이트
Design Overview
https://docs.oracle.[...]
[6]
웹사이트
PEP 8 -- Style Guide for Python Code
https://www.python.o[...]
[7]
웹사이트
Summary of Mixed-Language Issues
https://software.int[...]
Intel Corporation
2014-11-17
[8]
웹사이트
Documentation Library
https://software.int[...]
[9]
웹사이트
Foreign Function Interface # Calling Rust code from C
https://doc.rust-lan[...]
rust-lang.org
2016-05-13
[10]
웹사이트
No stdlib
https://doc.rust-lan[...]
rust-lang.org
2016-05-13
[11]
웹사이트
rust/src/librustc_codegen_utils/symbol_names/legacy.r.rs at 57e1da59cd0761330b4ea8d47b16340a78eeafa9 · rust-lang/rust · GitHub
https://github.com/r[...]
2021-11-03
[12]
웹사이트
Rust Symbol Mangling
https://rust-lang.gi[...]
[13]
웹사이트
Rust 1.42.0: src/test/ui/symbol-names
https://github.com/r[...]
2020-03-20
[14]
웹사이트
mikeash.com: Friday Q&A 2014-08-15: Swift Name Mangling
https://mikeash.com/[...]
[15]
웹사이트
apple/swift: mangling.rst
https://github.com/a[...]
2021-11-03
[16]
문서
Identifier (C) - cppreference.com
https://en.cpprefere[...]
[17]
문서
Identifiers (C++) - cppreference.com
https://en.cpprefere[...]
[18]
문서
Design Overview | Java SE 7 Documentation | Oracle
https://docs.oracle.[...]
[19]
간행물
Clang - Features and Goals: GCC Compatibility
http://clang.llvm.or[...]
2013-04-15
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com