링크 과정 오류: weak symbol의 중복

edward·2025년 10월 17일

두 개의 weak 심볼이 있을 때

/* foo4.c */
#include <stdio.h>
void f(void);

int x;  // weak

int main()
{
    x = 15213;
    f();
    printf("x = %d\n", x);
    return 0;
}

/* bar4.c */
int x;  // weak

void f()
{
    x = 15212;
}

이 경우 링커는 (규칙 3에 따라)
두 weak 심볼 중 하나를 임의로 선택한다.
→ 결과는 예측 불가능할 수 있으며, 버그를 유발할 수 있다.


타입 불일치에 의한 메모리 덮어쓰기

/* foo5.c */
#include <stdio.h>
void f(void);

int y = 15212;
int x = 15213;

int main()
{
    f();
    printf("x = 0x%x y = 0x%x\n", x, y);
    return 0;
}

/* bar5.c */
double x;

void f()
{
    x = -0.0;
}

세부 동작 (타입 불일치에 의한 메모리 덮어쓰기)

x86-64 리눅스에서:

  • double은 8바이트
  • int는 4바이트

주소 배치:

x = 0x601020
y = 0x601024

x = -0.0은 double 값이므로
그 8바이트가 x와 y의 메모리 공간을 모두 덮어쓴다.

결과:

linux> gcc -Wall -Og -o foobar5 foo5.c bar5.c
/usr/bin/ld: Warning: alignment 4 of symbol ‘x’ ... is smaller than 8
linux> ./foobar5
x = 0x0 y = 0x80000000

→ x는 0으로, y는 double 음수 0의 하위 비트가 덮여 0x80000000이 됨.


⚠️ 이런 버그의 위험성

이런 오류는 링커가 오류가 아닌 경고만 출력하기 때문에
발견이 어렵고, 나중에 프로그램 실행 중 전혀 엉뚱한 시점에 나타날 수 있다.

대규모 시스템에서는 이런 종류의 버그를 찾기가 매우 어렵다.
대부분의 프로그래머는 링커 동작에 익숙하지 않아
경고를 무시하기 때문이다.

💡 팁:
GCC 옵션 -fno-common을 사용하면
중복 전역 심볼 정의 시 오류를 발생시킨다.
또는 -Werror 옵션으로 모든 경고를 오류로 취급할 수도 있다.

profile
there ain't no shortcuts

0개의 댓글