공유라이브러리 함수주소 결정
글쓴이: declspec / 작성시간: 수, 2011/12/07 - 3:09오전
1. 리눅스에서 많은 프로그램들이 libc 의 printf 와같은
공유 라이브러리 함수를 사용하는데(정적 컴파일 할수도 있지만)
이때 컴파일러 입장에서는 printf 의 진입점 주소(가상메모리주소)를 알 수 없을텐데
어떻게 처리하나요? PLT, GOT 섹션등이 사용되는거로 아는데 설명을 봐도
잘 모르겠어서... 예제를 통해 쉽게 설명해주시면 감사하겠습니다
2. 바이너리 파일을 실행시키면 로더는 파일시스템상의 바이너리를 읽어서
프로그램 헤더등의 정보에 따라 각각의 섹션들을 메모리에 로딩시키는데요
우리가 일반적으로 malloc 등으로 메모리에 데이터를 올리는것과 이것에
어떤 차이가 있을까요? 또한 로더는 정해진 가상메모리주소에 데이터를 올릴
수 있어야 하는데 이것은 어떻게 가능한가요? 예로 malloc 같은 함수를 써서
자신이 원하는 0x08010203 번지에 100바이트의 데이터를 올릴수는 없으니까요...
3. 공유 라이브러리는 모든 프로세스가 공유할 수 있어야 하는데
모든 프로세스는 서로 다른 가상주소공간(32비트 머신에서는 4G)을 가지잖아요.
그렇다면 이것을 공유하기 위해서는 서로다른 가상주소(또는 동일한)가 동일한 물리 메모리 페이지에
매핑이 되야할텐데 이것은 누가 언제 처리해주는건가요? 로더가 알아서 하는건가요?
Forums:
윈도우는
filemap쓰면 되는데... 리눅스는 모르겠네요 ㅇ_ㅇ'''
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
Hello World 실행 과정
책 홍보하는건 아니고 제가 책보면서 자세히 설명하려니 너무 장문이 되겠네요.
아래 내용은 아오키 미네로우 씨가 쓴 "컴파일러 구조와 원리" 책의 4부 링크와 로드의 일부분입니다.
1번 질문은 아래 과정 중 4번에서 해결됩니다.
2번 질문은 아래 과정 중 3번에서 mmap을 사용하는데 mmap에서 지원합니다.
3번 질문은 아래 과정 중 3번에서 mmap을 사용하는데
mmap은 MAP_PRIVATE 플래그를 사용해서 로드하면 맵된 페이지(물리 메모리)가 변경되지 않는 이상 모든 프로세스에서
페이지가 공유됩니다.
추가적으로 글로벌 변수나 static이 아닌 함수를 사용하면 재배치가 발생하고 재배치가 발생한다는건
맵된 페이지가 변경된다는 것이고 그 순간 페이지가 복사되서 복사된 페이지를 맵하게 됩니다.
그래서 공유 라이브러리는 위와 같은 재배치를 막기 위해서 위치 독립코드(PIC)여야 합니다.
PIC를 위해서 사용되는 것들이 .got와 .plt입니다.(우리가 직접 사용하지는 않습니다. 우린 그냥 컴파일 옵션만 추가)
간단한 Hello World의 실행 과정을 추적하고 설명해주는 부분을 책의 내용을
간략하게 옮긴겁니다.
1. 프로그램 로드
hello실행 -> execve 시스템 콜 -> 커널이 PHDR 세그먼트를 메모리에 맵 ->
커널이 INTERP 세그먼트 메모리에 맵 -> INTERP(/lib/ld-linux.so.2)의 엔트리 포인트는 주소에 ld.so 존재
$ readelf -l hello
$ readelf -h /lib/ld-linux.so.2
2. ld.so의 실행
커널이 argc, argv, envp, auxv를 정보를 esp 레지스터에 저장하고 ld.so로 제어권을 넘김
3. 공유 라이브러리 read
ld.so는 hello의 DYNAIC 세그먼트를 조사해서 타입이 NEEDED 엔트리로 지정된 라이브러리를 메모리에 맵
$ readelf -d hello
4. 심볼의 해결과 재배치
5. 초기화의 실행
ld.so가 ELF파일의 .init 섹션과 init_array 섹션 실행
6. 프로그램 엔트리 포인트로 점프
ld.so가 제어권을 엔트리 포인트(_start)로 넘김
$ readelf -h hello
$ objdump -d hello | grep "엔트리 포인트 주소"
7. 종료 처리의 실행
main 펑션 종료 후 ld.so가 .fini 섹션과 .fini_array 섹션을 처리
없음
감사합니다
컴파일러 관련 책을 좀더 참고해봐야겟네요
감사합니다~
자기실력이 좋다고 느껴지는건 공부를 안하고 있다는 신호.
댓글 달기