링크 에러 메세지에서 주로 보게되는 심볼(Symbol)이 문득 정확히 어떻게 사용되는지, 정확히 무엇을 의미하는지가 궁금해져 정리를 하게 되었습니다. 겉핥기로 알고 있던 심볼에 대해 더 공부하고 정리해보겠습니다.
심볼은 컴파일러·링커가 프로그램 내부 엔티티를 식별하기 위해 생성하는 이름 정보입니다. 즉, 우리가 작성한 C++ 코드를 기계어가 이해할 수 있도록 내부적으로 사용하는 식별자입니다.
C++에서 심볼이 만들어지는 대상은 다음과 같습니다.
심볼은 실제 바이너리 내부에 기록되며, 링커가 여러 개의 obj 파일을 연결할 때 이 정보를 사용합니다.
C++ 함수는 오버로딩, 네임스페이스, 클래스 등 구조가 복잡해서 컴파일하면 내부적으로 이름이 변형됩니다. 이를 네임 맹글링(Name Mangling) 이라고 합니다.
예를 들어:
int Add(int a, int b);이 함수는 컴파일 후 다음과 같은 이름으로 변환될 수 있습니다.
?Add@@YAHHH@Z
이런 형태의 이름이 바로 심볼(Symbol) 입니다.
심볼에는 "어디까지 보이는가?" 를 나타내는 링키지(Linkage) 개념이 붙습니다.
다른 파일에서도 접근 가능한 심볼
(기본적인 전역 함수/전역 변수)
int gValue;
void Foo();
파일 내부에서만 보이는 심볼
static 키워드로 생성됩니다.
static int localGlobal = 10;
지역 변수처럼 링커가 관여하지 않는 경우, 심볼 테이블에 올라가지 않음
C++ 컴파일 시 선언만 있고 정의가 없는 심볼은 링커가 처리해야 합니다.
예:
extern int Value;
Value의 정의가 없다면 링크 단계에서 오류가 발생합니다.undefined reference to `Value`
즉, 심볼은 선언 → 참조 → 정의가 일치해야 linking이 성공합니다.
컴파일러와 링커는 심볼 정보를 다음과 같이 테이블로 관리합니다
.obj 파일을 열면 심볼 테이블을 확인할 수 있습니다.
실제 심볼 테이블을 확인해보기 위해 DUMPBIN을 사용해보겠습니다.

VS2022의 터미널에서 실행했습니다.

obj 파일에서 심볼 테이블을 확인할 수 있었습니다.
심볼은 다음 문제들의 핵심 원인/해결책이 됩니다.
즉, C++ 빌드 과정에서 발생하는 대부분의 문제는 결국 심볼에 대한 이해로 해결됩니다.