C 컴파일시, 모든 로컬 함수들이 PLT/GOT를 통해 call되도록 강제하는 방법이 있을까요?
글쓴이: ihjkoh / 작성시간: 일, 2016/11/27 - 6:26오후
C 컴파일시, 모든 로컬 함수들이 PLT/GOT 안에 저장되도록 강제하는 방법이 있을까요?
바이너리 구동할 때, 도중에 메모리상에 있는 바이너리의 전체 코드섹션의 base 주소를 옮겨야 하는 일이 있어요.
그런데 코드섹션을 옮기면 코드 안에 정의된 함수들의 주소값들이 당연히 바뀌고,
그러면 코드가 구동하는 동안 스택, heap 안에 저장되었던 함수포인터 값들은 그대로이기 때문에 더이상 그전에 포인트하던 함수들을 call할 수 없잖아요.
하지만, 만일 모든 로컬 함수들이 다이나믹 라이브러리의 함수들같이 GOT/PLT를 거쳐서 접근되도록 강제할 수 있다면,
나중에 코드가 옮겨지더라도 GOT, PLT 테이블에 저장된 함수값들만 업데이트해주면 되기 때문에
위의 스택, heap에 저장된 함수포인터 문제들을 해결할 수 있어요.
그래서 C 컴파일시, 모든 로컬 함수들이 PLT/GOT를 통해 call되도록 강제하는 방법을 찾고 있습니다.
Forums:
방법을 찾았습니다
오브젝트 파일로 컴파일 시 "-fPIC" 옵션을 주어서 Position Independent Code로 오브젝트 파일을 생성하고,
오브젝트파일들을 모아서 최종 바이너리를 만들 때 "-shared" 옵션을 넣으면 binary가 동적 라이브러리로써 생성됩니다.
그러므로 바이너리 안에 있는 모든 라이브러리들은 PLT/GOT를 통하여 call되도록 프로그램이 생성됩니다.
해결이 안되네요
하지만 shared library는 실행하면 segmentation fault가 뜨네요...
원래 .so는 직접 실행이 안되는거 같습니다.
http://unix.stackexchange.com
http://unix.stackexchange.com/questions/223385/why-and-how-are-some-shared-libraries-runnable-as-though-they-are-executables
설령 PLT/GOT를 거치게 만든다고 해도 완전히
설령 PLT/GOT를 거치게 만든다고 해도 완전히 해결되는 문제는 아닌 것 같습니다만.
함수 호출 주소는 매번 PLT/GOT를 거쳐서 호출하게 만든다고 해도, 함수 호출 시 Call stack에 들어가는 반환 주소(return address)는 원래 코드 영역의 주소를 가리키고 있을 테니까요.
런타임에 코드 섹션을 통째로 옮긴다면 모든 스레드의 Call stack을 다 헤집어서 반환 주소를 다 찾아 바꿔 놓아야 할 겁니다.
뭐 불가능하진 않을 거에요. 근데 손이 좀 많이 가고 제대로 만들기 까다롭겠죠. 저로서는 왜 그런 걸 시도하려 하시는지 의문이 듭니다만 그거까지 여쭤보는 건 좀 과한 참견이네요.
사실... 불가능하진 않을거라는 것도 스택의 고정
사실... 불가능하진 않을거라는 것도 스택의 고정 위치에 (caller 가 묵시적으로) 리턴 주소를 보관하는 CPU 한정이죠. 예를 들면 x86 이라던가 아니면 x86 이라던가, 혹은 x86 이라던가.
확실히 그렇군요. MIPS처럼 반환 주소가 레지스터에
확실히 그렇군요. MIPS처럼 반환 주소가 레지스터에 저장된다던가 하는 아키텍처라면... 음;
보통은 소위 말하는 Leaf function이 아닌 함수들의 경우엔 어떻게든 자기 반환 주소를 스택에 백업해둬야 하므로, 그 메커니즘에 규칙이 있는 컴파일러라면 어떻게든 스택을 파내서 찾아낼 수 있을 가능성이 없지는 않을겁니다. 물론 없지만 않은 정도이고, 이쯤 되면 진짜 불가능하다고 봐야죠.
댓글 달기