디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

[CS:APP 13-1] Linking 1.어떻게 링킹 에러를 피할까

츄럴(119.198) 2017.01.09 16:35:10
조회 3072 추천 11 댓글 10

이전화 바로가기

-------------------------------------------------------------------------

[CS:APP 10] C/C++에서 아주 간단한 최적화...

https://gall.dcinside.com/board/view/?id=programming&no=668663&page=2&exception_mode=recommend

[CS:APP 11] The Memory Hierarchy

https://gall.dcinside.com/board/view/?id=programming&no=669079&page=2&exception_mode=recommend

[CS:APP 12] Cache Memories

https://gall.dcinside.com/board/view/?id=programming&no=670217&page=1&exception_mode=recommend

[CS:APP 12] 캐시메모리 추가내용

https://gall.dcinside.com/board/view/?id=programming&no=670219&page=1&exception_mode=recommend

-------------------------------------------------------------------------



이번 화부터는 우리가 만들어대는 프로그램이

시스템 소프트웨어와 어떻게 협력하여 돌아가는지에 대해 배우기 시작한다.


즉 운영체제와 관련되는 부분이다...

책에서는 part 2에 해댕한다. (7장~) part 1은 컴퓨터 구조와 관련이 많다.


----


그런데 왜 링커를 배워야 할까?

이것은 C나 C++을 하다가

SDL이나 기타 다른 라이브러리를 붙여서 사용하려 할 때 (특히 윈도우에서) 

아주 엿같은 경험을 하게되면 자연스럽게 링커에 대해 궁금해지게 된다.


세상에서 가장 무서운 에러 중 하나가... 링킹 에러




viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11b952a5e9d7363338720a3a16b965c861080449d3cd0e



링킹 에러를 만나 본 사람들은 하나같이 그 엿같음에 혀를 내두르지만

그러지 않은 뉴비들을 위해 설명하자면...


느낌은 컴파일 에러같이 프로그램 빌드를 거부하는데

소스코드에 표시가 안 됨 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ


viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11f70ef685df36343e776c2342db1b9b6d3b1b6e014a2e31c95474



게다가 에러코드도 존나 이상해

시발 이게 도대체 무슨소리일까?

내가 뭘 잘못했는데 ㅡㅡ???


진짜 문제는 ​너​가 잘못한 게 아닐 수도 있다는 거야

실제로 내가 SDL을 설치할 때, SDL의 코드를 일정부분 바꿔서 재컴파일하고 나서야 설치할 수 있었는데

그것도 다 링킹 에러 때문이었음....


하지만 링킹 에러도 결국은 버그. 

버그는  생기는지 알면 잡을 수 있다!

최소한 피해갈 수는 있다...

링킹 에러가 왜 생기는지 알아보기 위해 링킹에 대해서 알아 보고 어떻게 C코드를 짜야 하는지 알아봅시다!


그리고, 왜 어떤 라이브러리는 DLL이 필요한데 

어떤 라이브러리는 lib가 필요할까?

lib와 dll의 차이. 즉 static linking과 dynamic linking의 차이와 특성에 대해 알아봅시다!


C/C++로 콘솔 게임, 콘솔 어플리케이션을 벗어나서

진정한 프로그래밍에 입문했을 때, 정말로 실용적인 프로그램을 만들기 시작할 때,

즉 외부 라이브러리를 붙여야하는 순간부터

숙명적으로 프로그래머들은 링커를 사용하게 된다.

수-퍼 후로그래머가 되기 위해서는 링킹에 대해서 알아야 하는 것이다!



그런데 Linking이 뭐지? 

링킹은 여러 코드와 데이터들을 모아서 하나의 실행파일로 만드는 것이다.

리눅스에서는... relocatable object파일(.o파일) 여러개를 묶어서 하나의 실행파일로 만드는 행위다.


다음과 같은 코드가 있다고 하자.


main.c

1
2
3
4
5
6
7
8
int sum(int a[], int n);  // sum.c에서 가져올 sum 함수
 
int array[2= {12};   // 전역 변수(배열)
 
int main(){
    int val = sum(array, 2);  //sum.c에서 가져온 함수 사용
    return val;
}
cs


sum.c

1
2
3
4
5
6
7
8
int sum(int a[], int n)
{
    int i, sum = 0;
    for(i = 0; i < n; i++){
        sum += a[i];
    }
    return sum;
}
cs


이걸로 어떻게 실행파일을 만들어낼까?


뭐? Ctrl+F5면 그냥 만들어진다고?

비주얼 스튜디오 꺼라....


리눅스에서는 다음과 같은 터미널 명령으로 prog라는 executable file(실행파일)을 만들어낸다.

$gcc -Og -o prog main.c sum.c


gcc는 gcc라는 컴파일러를 쓰겠다는 거고

-o prog는 실행파일의 이름을 prog로 하겠다는 거고

-Og는 최적화를 하지 않겠다(는 건데 이건 알필요 없음)


그러면 리눅스에서는(비주얼 스튜디오도 사용자에게 숨길 뿐이지만) compiler driver라는 시스템이

실행파일을 만드는데 필요한 각종 프로그램들

preprocessor(전처리기), 컴파일러, 어셈블러, 링커등을 불러서 북치고 장구치고 해준다


그게 어떻게 되는 건지 궁금하다면 리눅스에서는 다음과 같은 명령어로 컴파일 해보면 알 수 있다.

Visual Studio에서는 어떻게 보냐고? 그런 건 없어...(나는 모르겠네요 혹시 아시면 댓글좀...)

$gcc -v -Og -o prog main.c sum.c

-v는 verbose 옵션으로, 어떠한 과정으로 실행파일이 만들어지는지 사용자에게 알려준다.


근데 실제로 해봤는데 솔직히 잘 모르겠고.. ㅎ 다음 그림이나 봅시다


viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11f70ef685df36343e776c2342db1b94663c17355b412831c95474


(괄호 안에 든 건 리눅스에서의 프로그램 이름임)

즉 relocatable object file들을 적절히 조각 내어 붙여서 실행파일로 만드는게 링킹이다.

참고로 relocatable object file은 바이너리지만 실행이 불가능하다. 그 이유는 나중에 설명하겠읍니다만...

왜 실행을 못할까? 한번 생각은 해보자.




그나저나 링킹은 왜 하는걸까?

1. 모듈화

하나의 거대한(만 라인..) 파일보다는 작은 소스파일 여러개가 관리하기 쉽다

맨날 쓰이는 함수들은 라이브러리로 만들어서 두고두고 우려먹을 수 있다(Math 라이브러리 등..)

2. 효율

시간적 효율: 위 그림에서 알 수 있지만, main은 그대로이고 sum이 바뀌었을 때, main.o는 그대로 두고

sum.c만 다시 빌드해서 sum.o를 만들어 붙이면 새로운 프로그램을 만들 수 있다.

만일 main.c과 sum.c가 하나의 파일이라면 모두 재컴파일해야 할 것이다.

위 소스는 작아서 체감이 안 가지만 크롬(웹브라우저)은 아마 천만라인이 넘는다고 들었다.

그런데 ui약간 변경한다고 천만라인의 코드를 죄다 재컴파일할 수는 읎지..


공간적 효율: 자주쓰이는 라이브러리 함수들은 함수 하나당 하나의 파일로 쪼개져 있는 경우가 많다.

라이브러리에서 필요한 함수가 들어 있는 xxx.o 파일을 링킹해서 실행파일을 만들면 실행파일 크기를 줄일 수 있다.


그러합니다. 솔직히 다 아는 내용일 듯


하지만 링커가 뭘 하는지는 다들 잘 모르지? (난 몰랐어...)


링커가 하는 일은 크게 두가지가 있다.

1. symbol resolution

2. relocation


일단 symbol resolution에 대해 알아보자.


잠깐... resolution? resolve?


viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11f70ef685df36343e776c2342db1b9b6d3b1b6e014a2e31c95474


그렇다. 엿같은 링킹 에러를 유발하는 발암물질 덩어리다...!

어떠한 방식으로 이것이 일어나는지 안다면 우리가 만드는 C 코드의 링킹에러를 없앨 수 있겠다!


symbol resolution을 알아보기 위해

먼저 symbol에 대해서 알아보자.


symbol은 프로그램이 생성하는 것들인데... 다음 3가지 부류로 나눌 수 있다

globa symbol:        특정 모듈m에 ​정의​되어 있고 다른 모듈에 의해 참조될 수 있는 심볼.

ex) static이 붙지 않은 C 함수, static이 아닌 전역변수.


external symbol:    모듈 m에의해 참조되는 global symbol이지만 다른 모듈에 정의되어 있음 


local symbol:        모듈 m에서 정의되어 있고 오로지 모듈 m 내부에서만 참조할 수 있는 심볼

                                모듈 외부에서는 참조가 불가능하다.

ex) static C 함수, static 전역변수


주의- C의 지역변수와 local symbol 다르다! 

(static이 아닌 지역변수는 symbol이 아니다)



viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11f70ef685df36343e776c2342db1b94633f163a0a4a2a31c95474

 

주의할 점은 지역변수는 static의 여부에 따라 symbol이 되기도 하고 그렇지 않기도 하다는 것이다.

static이 선언된 지역변수는 local symbol이 되어 링커의 관리 대상이 되고

symbol table에 들어간다(자세한 건 나중에 설명)


1
2
3
4
5
6
7
8
9
int f(){    
    static int x = 0;  // x.1
    return x;
}
 
int g(){
    static int x = 1;  // x.2
    return x;
}
cs

만일 static 지역변수가 이름이 동일하다면, symbol table에는 각각에게 유일한 이름(x.1, x.2)을 부여해서 들어간다.


static이 선언되지 않은 지역변수는 애초에 symbol이 아니라서 

symbol만 아는 바보 링커는 그런게 있는지도 모른다...

1
2
3
4
5
6
7
8
9
int f(){    
    int x = 0
    return x;
}
 
int g(){
    int x = 1
    return x;
}
cs


지역변수는 실행시 스택에 할당되고, 전역변수는 실행파일의 .data 영역에 존재하기 때문인데..

이것은 이후에 설명하겠다. 여튼 


static이 아닌 지역변수는 symbol이 아니다!

static 지역변수는 local symbol이다!


그건 그렇고



symbol resolution은 

이 symbol들의 reference참조들(예- 함수 호출, 지역변수 사용)을 각각 

단 하나의 symbol definition정의​(예- 함수 정의, 지역변수 정의)와 연관시키는 행위이다.


그런데 symbol의 이름이 겹친다면 링커는 심볼 참조와 정의를 어떻게 연관시켜야 할까?


링커는 symbol의 이름이 겹치는 문제를 해결하기 위해 symbol들을 다시 두 부류로 구분한다.

strong symbol함수(procedure)들과 초기화된 전역 변수

weak symbol​:  초기화되지 않은 전역변수


그리고 다음의 규칙대로 symbol의 reference와 definition을 연관시킨다.

    1. 중복되는 strong symbol은 허용되지 않는다: LINK ERROR!

    2. strong symbol은 ​하나만 존재하고, 동일한 이름의 weak symbol들이 있다면, 

      링커는 strong symbol을 선택한다: 이 이름의 symbol에 대한 reference들은 strong symbol로 연관된다. 

    3. 만약 이름이 중복되는 ​weak symbol 여러개 있다면... 링커는 아무거나 골라서 연관시킨다.


특히 2, 3번이 사람을 환장하게 만드는 링킹에 의한 버그의 근원이다

다음 사례들을 보자. 

one.c와 two.c를 컴파일하고 링킹한다고 생각해보자.


---------------------

(one.c)

int x;
p1() {} //strong!
---------------------

(two.c)

p1() {} //strong!
---------------------
이 경우 2개의 strong symbol의 이름이 겹치므로 Link time error가 뜬다. (1.) 

이런 경우 간단히 코드를 고치면 된다.



---------------------

(one.c)

int x;  //weak
p1() { x = 0; } 
---------------------

(two.c)

int x;  //weak
p2() { x = 9; } 
---------------------
이 경우 p1이나 p2에서 전역변수 x를 쓰게 된다면,
one이나 two의 변수 중 하나를 선택해서 쓰게 된다. (.3)
링크에러는 발생하지 않는다.
p1에서 x를 썼다고 one.c의 x를 쓰고
p2에서 x를 썼다고 two.c의 x를 쓰는게 ​아니다!  
​판단은 링커가 한다.... 

viewimage.php?id=3dafdf21f7d335ab67b1d1&no=29bcc427b28677a16fb3dab004c86b6fae7cfdc6a7b48ad935a3d6c73a38b39e2d84d4388d11b952a5e9d7363338720a6212bd33cb615d0d49c9d30e

그래도 여기까지는 괜찮다(?). 문제는 다음이다.



---------------------

(one.c)

int x;     //weak
int y;     //weak
p1() {} 
---------------------

(two.c)

double x;  //weak
p2() {x = 800.0} 
---------------------

컴파일러는 오직 하나의 소스파일만을 알기 때문에 

one.c에서 x의 크기는 4이고

two.c에서 x의 크기는 8이다.

 

만약에 p2에서 x에 데이터를 썼는데, 

링커가 p2의 reference x를 one.c의 symbol x와 연관시켰다면 (.3)

8바이트를 수정하기 때문에, p1의 x뿐만이 아닌 y까지 이 변하게 된다.


이런 일이 일어나는 이유는 

컴파일러가 two.c로 만든 오브젝트 파일two.o에서는 

x가 있는 곳의 메모리를 8바이트 수정하기 때문이다.

이 또한 3번째 resolution 규칙인 임의의 연결 문제 때문이다.

그러나 링크에러는 발생하지 않는다.


그래도 이것또한 운이 억세게 좋다면 발생하지 않을 수도 있다... 


그러나 다음은 반드시 발생한다.



---------------------

짤려서... 보충 게시물에서 봐 주세요



추천 비추천

11

고정닉 4

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 며느리, 사위되면 시댁, 처가에 잘할 것 같은 스타 운영자 25/10/13 - -
AD iPad Pro 사전예약!! 운영자 25/10/17 - -
공지 프로그래밍 갤러리 이용 안내 [96] 운영자 20.09.28 48061 65
2897249 주말이 벌써끝이라고? 개멍청한유라갤로그로 이동합니다. 16:24 1 0
2897248 공지] 냥덩짤 무단사용 ㄴㄴ [2] ♥덩냥이♥갤로그로 이동합니다. 16:23 3 0
2897247 왜 가난의 이미지를 측은함, 부끄러움으로만 만드는걸까... ㅇㅇ(223.39) 16:16 6 0
2897246 존재하지도 않는 것을 동경하고 절망한다 [2] 공기역학갤로그로 이동합니다. 16:14 14 0
2897245 데이터 분석 과제 하고 있는데 미치겠다. 프갤러(218.152) 16:10 15 1
2897244 개발자 할려면 노트북 필수임? [1] ㅇㅇ갤로그로 이동합니다. 16:08 10 0
2897243 졸린데 지금자면 넘빠름.. ♥덩냥이♥갤로그로 이동합니다. 16:08 6 0
2897242 김창욱 김제동 오은영 같은 프갤러(211.210) 16:01 11 0
2897241 서울가스라이팅 당해서 서울이런 모습인줄알았음 ㅇㅇ(175.197) 16:00 14 0
2897240 나같은 인간이 살아가도 되는걸까 ㅠㅠㅠㅠ [10] 공기역학갤로그로 이동합니다. 15:57 25 0
2897239 아동성애가 최고임 류류(118.235) 15:23 22 0
2897238 냥덩아 발명도둑잡기(39.7) 15:13 26 0
2897237 그래도 이번 정권이 집값은 잡을 의지가 있어보이긴 해 [4] chironpractor갤로그로 이동합니다. 15:10 35 0
2897236 zfs source code opened 나르시갤로그로 이동합니다. 14:50 14 0
2897234 부산에 국제수로기구 인프라센터 생기네 ㅇㅇ(175.197) 14:21 17 0
2897233 전찐연 ㄱㄱ 슈퍼너드_리보갤로그로 이동합니다. 14:20 25 0
2897232 스타벅스 선불금 6년간 2.6조…고객돈으로 투자 수익 등 400억원 발명도둑잡기(118.235) 14:18 18 0
2897231 zfs도 라이센스에 소스 강제공개가 없어서 백도어 가능 발명도둑잡기(118.216) 14:05 15 0
2897230 미국 마이크론부터 때리는 중국, 지켜보는 한국 발명도둑잡기(118.216) 14:00 16 0
2897229 zfs 파일 시스템에서도 mount 명령을 사용하면 되는가? 나르시갤로그로 이동합니다. 13:45 14 0
2897228 캄보디아 중국인 범죄조직 한국인신매매도 결국 이재명 때문이엇넹 [2] ♥덩냥이♥갤로그로 이동합니다. 13:40 32 0
2897227 코스프레가 대중화되야 출산률이 올라간당 By 나님 ♥덩냥이♥갤로그로 이동합니다. 13:37 26 0
2897226 구윤철 “미국처럼 재산세 1% 때리면 고가주택 보유하겠나” [1] 발명도둑잡기(39.7) 13:36 23 0
2897225 저장용 ♥덩냥이♥갤로그로 이동합니다. 13:25 23 0
2897224 제국주의 체제 부역자는 대체로 이기적이고 근시안적인 입장이고 [1] 발명도둑잡기(118.235) 13:23 26 0
2897223 괜찮다는건 무지에 대한 책임감의 부재 아닐까?? [1] ㅇㅇ(223.39) 13:21 32 0
2897222 한반도의 절대반지는 단연코 국가보안법이다 발명도둑잡기(118.235) 13:12 18 0
2897220 예뿐귀염냥들도 풍파좀맞으면 미모떨엊지는듯 [2] ♥덩냥이♥갤로그로 이동합니다. 13:05 40 0
2897219 ‘노 킹스!’ 미국 전역 들썩인 반 트럼프 시위…“역사상 최대 규모” [2] 발명도둑잡기(118.235) 13:02 22 0
2897218 Ada 프로그래밍: 4.1.1 타입의 정의와 중요성 나르시갤로그로 이동합니다. 12:56 21 0
2897217 애널은 버티다 일직자야갯다 ♥덩냥이♥갤로그로 이동합니다. 12:47 21 0
2897216 컨디션 좋을때 효율이 안좋을때 수백수천배임 ♥덩냥이♥갤로그로 이동합니다. 12:47 20 0
2897215 체딸의 갖장 큰 단점은 중요성 판단능력이 떠러진다는거 ♥덩냥이♥갤로그로 이동합니다. 12:45 24 0
2897214 4시간 잤다 발명도둑잡기(118.216) 12:41 24 0
2897213 생후2개월까지만 귀엽고 그이후는 귀여운애들만 귀여운듯 ♥덩냥이♥갤로그로 이동합니다. 12:40 26 0
2897212 새끼길냥이들 좀만크면 안귀여워지네 ♥덩냥이♥갤로그로 이동합니다. 12:39 27 0
2897211 뛰뛰조졋더이 글이 언읽힌당.. [2] ♥덩냥이♥갤로그로 이동합니다. 12:33 32 0
2897210 바이럴이라는게 상당히 중요한게 얼마전에 바이브 코딩 게임 [1] ㅆㅇㅆ(124.216) 12:25 48 0
2897209 [대한민국] 헌재 윤 국무회의 CCTV 고의적으로 증거 은닉 프갤러(121.172) 12:08 20 0
2897207 아 내 서비스를 빨리 완성해야되겠구나 [2] ㅆㅇㅆ(124.216) 12:04 49 0
2897206 프로그래머 너네는 행복한줄 알아. [2] 프갤러(59.16) 12:00 55 0
2897205 우리나라는 진짜 좌파가 없음 . 진짜 좌파는 이런거임 [18] ㅇㅇ(175.197) 11:58 95 0
2897204 [대한민국] 캄보디아 사건을 토대로 알아보는 좌파의 인식과 사회구조 [3] 프갤러(121.172) 11:51 30 0
2897203 삶이 의미 없다 동안구청 건설과 직원들은 11시 40분에 점심먹으러 가고 넥도리아(220.74) 11:31 20 0
2897202 어후 글이어지러 [2] CreeJee(유동근)갤로그로 이동합니다. 11:26 46 0
2897201 양산형 만들 시간에 다른 개발.자 개발자 자체가 적페아닌가 이재명도사장이 넥도리아(119.195) 11:23 19 0
2897200 님들은 게임 개발 왜함. 목적이 뭐임 돈 머니 아니면 코인 아니면 취업사 넥도리아(119.195) 11:21 22 0
2897199 어제 박가네 보는데 오사카는 오사카 짱짱맨이라며 ㅇㅇ(175.197) 11:20 21 0
2897198 문화에 힘을 왜 쓰냐 다 구란데 [8] 프갤러(211.210) 11:19 37 2
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2