디시인사이드 갤러리

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

갤러리 본문 영역

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

츄럴(119.198) 2017.01.09 16:35:10
조회 3074 추천 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/20 - -
공지 프로그래밍 갤러리 이용 안내 [97] 운영자 20.09.28 48128 65
2897668 돈없어서 카드이벤트 참여하는 [2] 개멍청한유라갤로그로 이동합니다. 00:27 2 0
2897667 홈플러스 키친아트처럼 노동자협동조합이 인수하면 안되나요? 발명도둑잡기(39.7) 00:24 0 0
2897666 다들 잘 지내는거야 [6] 개멍청한유라갤로그로 이동합니다. 00:18 14 0
2897665 현실 멘스티어 발명도둑잡기(39.7) 00:15 7 0
2897664 ㅂ졸어하고 싸피가야디 ㅇㅇ(118.139) 00:13 6 0
2897663 지잡 1학년인데 아는 척 해봄 ㅋㅋ ㅇㅇ(118.139) 00:04 11 0
2897661 자전거 배우는 것도 암기인가 발명도둑잡기(39.7) 10.21 11 0
2897660 현실에서 2찍 처음 만나봄 [1] 저스트두잇이여(211.108) 10.21 27 0
2897659 스칼라 하다가 자바 다시 해보는데 진짜... 저스트두잇이여(211.108) 10.21 18 0
2897658 대기업 계약직 vs 싸피 2학기 [2] 프갤러(121.144) 10.21 20 0
2897657 곽튜브 부인 예쁘네... 프갤러(175.197) 10.21 20 0
2897656 ❤✨☀⭐⚡☘⛩나님 시작합니당⛩☘⚡⭐☀✨❤ ♥벼락부자냥덩♥갤로그로 이동합니다. 10.21 20 0
2897655 1DCNN으로 부하 추론하는 리눅스 가버너 쪄왓어용 [3] 파란빤스갤로그로 이동합니다. 10.21 28 0
2897653 어셈블리 분석하는 데 팁 있나요?? [19] 프갤러(211.176) 10.21 76 1
2897650 좌좀에게 살아남기 ㄷㅅㄷ ♥냥덩이♥갤로그로 이동합니다. 10.21 17 0
2897649 책임은 윗대가리가 지는거다 ㅇㅇ(211.196) 10.21 16 0
2897648 한화 야구 존나 재밋게하넹 ♥냥덩이♥갤로그로 이동합니다. 10.21 18 0
2897647 혹시 술집에서 복분자주 시켜먹으려면 연봉 얼마 벌어야함?? ㅇㅇ(223.39) 10.21 13 0
2897646 애널안으로 하이라이트 올라오려낭? ♥냥덩이♥갤로그로 이동합니다. 10.21 15 0
2897645 러스트 사용하면 누가 돈 주나? 나르시갤로그로 이동합니다. 10.21 16 0
2897644 Ada 프로그래밍: 4장 데이터 타입 나르시갤로그로 이동합니다. 10.21 9 0
2897642 사이드 프로젝트는 집이 아니라 회사에서 하는 것이니라 [1] 프갤러(110.8) 10.21 23 0
2897641 김현지가 누구야? 짜근엄마 얘 알아? [2] ♥냥덩이♥갤로그로 이동합니다. 10.21 24 0
2897639 GPU 고유번호 변조 구현했다 [6] 루도그담당(58.239) 10.21 54 0
2897638 알렉산더 이새끼 낭만뿐이 없는 상남자네 ㅋㅋ [1] ㅇㅇ(223.39) 10.21 22 0
2897637 애널 회식하면서 야구보느라 밤잠 조졋넹;; ♥냥덩이♥갤로그로 이동합니다. 10.21 16 0
2897635 노시환문동주가 다 했넹 ♥냥덩이♥갤로그로 이동합니다. 10.21 17 0
2897634 문동주 미쳤당 ㄷㅅㄷ 다 씹어먹넹 ♥냥덩이♥갤로그로 이동합니다. 10.21 22 0
2897631 ai 시대오고 프론트가 더 어려워진것같다 [1] ㅇㅇ(59.6) 10.21 30 0
2897630 한국 대통령, 의원이라면 미제 상납 대신 한국 일자리에 투자를 발명도둑잡기(39.7) 10.21 17 0
2897628 사이드 프로젝트는 코드가 개떡같을수밖에 없어 [2] ㅇㅇ(118.222) 10.21 34 0
2897626 나님 배뷰륩니댱❤+ [2] ♥냥덩이♥갤로그로 이동합니다. 10.21 33 0
2897624 내일 모레 납품할 것은 GNN논문 재현인데 이거 논문이 코드 공개되있어서 ㅆㅇㅆ(124.216) 10.21 25 0
2897622 미국 선 넘었다, 지금 우리에게 필요한 것은 고도의 냉정함 발명도둑잡기(39.7) 10.21 17 0
2897621 이미친세상에어디에잇더라도행복해야해 [3] 노력갤로그로 이동합니다. 10.21 35 0
2897619 방금 EBS <극한직업> 노르웨이 고등어, 연어 공장편 봤다 [1] 발명도둑잡기(211.246) 10.21 27 0
2897618 비효율적 기술이 표준을 잠식해 락인된 경우 [2] 발명도둑잡기(211.246) 10.21 30 0
2897617 생각해보면 최초의 성공은 오래 가진 않는듯 [4] ㅆㅇㅆ(124.216) 10.21 51 1
2897616 레딧 보면서 느끼는게 사이드 프로젝트들 보면 선구자는 다 실패하지 않냐? ㅆㅇㅆ(124.216) 10.21 36 0
2897615 해외도 서비스 존나게 베끼는구나 [3] 노력갤로그로 이동합니다. 10.21 47 0
2897614 영국, 프랑스, 이탈리아 가려는데 얘네 팁문화 있나요?? ㅇㅇ(223.39) 10.21 13 0
2897613 코딩이라는게 개나소나 다 할 수 있다. 자판질하니 그리 보이지. [1] 프갤러(59.16) 10.21 54 1
2897612 유럽이 1년일해 모은 돈을 박을만큼 가치있나요?? [1] ㅇㅇ(223.39) 10.21 35 0
2897611 멜로디도 그렇지만 나는 이 곡 제목이 진짜 소름인거 같아 chironpractor갤로그로 이동합니다. 10.21 21 0
2897610 KIOXIA 3108 이네 3111이 아니라 넥도리아2025(220.74) 10.21 11 0
2897609 오랜만이노 게이들아 이기 [6] 슈퍼막코더(126.166) 10.21 47 0
2897608 개발자로서 꿀은 2017~2020 해외 이민 이였다. 이미 기회는 떠남 [3] Kyle(124.171) 10.21 68 1
2897607 선생님들 데이터베이스 설계 관련 책 알아보고 있는데 책 괜찮아 보이나요? [1] ㅇㅇㅇㅇㅇ갤로그로 이동합니다. 10.21 27 0
2897606 나는 학교때 공부못했음 [3] 배구공(119.202) 10.21 45 0
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2