2013-07-17 3 views
5

링커는 x86-64 ELF 형식 실행 파일에서 main 함수를 어떻게 찾습니까?링커가 주 기능을 어떻게 찾습니까?

+0

는 HTTP ([(.so를가) 링커에 의해 처리되는 방법 공유 객체 내부) (주요 기능] 참조 .com/questions/9807194/how-main-function-inside-a-shared-object-so-taken-take-by-linker) –

+1

[어떻게 C++ 링크가 실제로 작동합니까?] http://stackoverflow.com/a/12122534/309483)? 어느 부분을 이해하지 못합니까? –

+0

main 함수의 메모리 주소를 어떻게 결정할 수 있는지 이해할 수 없습니다. – RouteMapper

답변

2

매우 일반적인 개요 인 링커는 기호 main으로 식별되는 코드 블록에 주소를 할당합니다. 오브젝트 파일에있는 모든 심볼에 적용됩니다.

사실 실제 주소를 지정하지는 않지만 프로그램 실행시 로더가 실제 주소로 변환 할 일부 기본 주소를 할당합니다.

실제 진입 점은 main이 아니지만 main을 호출하는 crt의 일부 기호입니다. LD는 something different을 지정하지 않는 한 기본적으로 기호 start을 찾습니다.

링크 된 코드는 실행 파일의 .text 부분에서 끝이 같은 (매우 간단) 볼 수 있었다 :

Address | Code 
1000  someFunction 
... 
2000  start 
2001  call 3000 
... 
3000  main 
... 

링커가 주소 2000의 엔트리 포인트를 지정합니다 ELF 헤더를 기록

objdump과 같은 실행 파일의 내용을 덤프하여 main의 상대 주소를 가져올 수 있습니다. 런타임시 실제 주소를 얻으려면 기호 funcptr ptr = main;을 읽고 main의 서명이있는 함수에 대한 포인터로 funcptr이 정의됩니다. 링커 제 상대 주소 심볼 main를 해결할 보낸 심벌 제거되었는지

typedef int (*funcptr)(int argc, char* argv[]); 

int main(int argc, char* argv[]) 
{ 
    funcptr ptr = main; 
    printf("%p\n", ptr); 
    return 0; 
} 

메인의 어드레스에 관계없이 정확하게 해결한다.

은 다음과 같이 objdump를 사용 : 나는 윈도우 그렇게 결과가 약간 다를 수 Cygwin에서 사용 오전

$ objdump -D funcptr.exe | grep main 
    40102c:  e8 af 01 00 00   call 4011e0 <_cygwin_premain0> 
    401048:  e8 a3 01 00 00   call 4011f0 <_cygwin_premain1> 
    401064:  e8 97 01 00 00   call 401200 <_cygwin_premain2> 
    401080:  e8 8b 01 00 00   call 401210 <_cygwin_premain3> 
00401170 <_main>: 
    401179:  e8 a2 00 00 00   call 401220 <___main> 
004011e0 <_cygwin_premain0>: 
004011f0 <_cygwin_premain1>: 
00401200 <_cygwin_premain2>: 
00401210 <_cygwin_premain3>: 
00401220 <___main>: 

참고 :

$ objdump -f funcptr.exe 

funcptr.exe:  file format pei-i386 
architecture: i386, flags 0x0000013a: 
EXEC_P, HAS_DEBUG, HAS_SYMS, HAS_LOCALS, D_PAGED 
start address 0x00401000 

특별히 main을 찾고, 내 컴퓨터에서 나는이 얻을. 나를 위해 00401170에 사는 main 모양입니다.

+0

따라서 런타임 전에 '메인'의 주소가 무엇인지 판단 할 방법이 없습니까? – RouteMapper

+0

지금 내가 수정 한 소식을 보았습니다. 나는'start'의 주소가 ELF 헤더에 있다는 것을 알고 있습니다. 하지만'main'의 주소를 정적으로 계산할 방법이 있습니까? main의 주소가 동적으로 재배치되는 경우가 있습니다. – RouteMapper

+0

@RouteMapper 정적 분석을하고 있습니다. 맞습니까? 재배치가 존재하지 않습니다. 재배치하는 것은 로더의 직업이며, 당신은 로더 *입니다. 단지 재배치하지 않기로 결정했습니다. – harold

0

는 Binutils의에, 하나에 의해 결정됩니다

  • -e CLI 옵션
  • 당신은 당신의 링커 스크립트를 볼 수 있습니다

링커 스크립트 :

ld --verbose 

가 내 포함 :

ENTRY(_start) 

은 다음 링크시의 _start 기호를 포함 crt1.o 같은 glibc에 제공하는 오브젝트 파일은 main.o와 함께 링커에 전달됩니다.

이러한 개체 파일은 argv과 같은 설정을 한 다음 main 기능을 호출합니다.

gcc -v으로 몰래 들어간 여분의 오브젝트 파일을 볼 수 있습니다. 엔트리 포인트를 호출하는 프로그램 실행 https://sourceware.org/binutils/docs/ld/Entry-Point.html#Entry-Point

제 조작법 :

은이 설명된다. ENTRY 링커 스크립트 명령을 사용하여 진입 점을 설정할 수 있습니다.

ENTRY(symbol) 

가 엔트리 포인트를 설정하는 방법은 여러 가지가 있습니다 인수는 심볼 이름입니다. 그 중 하나가 성공하면 링커는 순서대로 다음 각각의 방법을 시도하고 중지하여 진입 점을 설정합니다 :

  • 은`-e '항목 명령 줄 옵션을;
  • 링커 스크립트의 ENTRY (symbol) 명령.
  • 타겟 특정 기호의 값 (정의 된 경우). 많은 타겟에서 이것은 시작이지만 PE와 BeOS 기반 시스템은 발견 된 첫 번째 심볼과 일치하는 가능한 엔트리 심볼 목록을 확인합니다.
  • `.text '섹션의 첫 번째 바이트 주소 (있는 경우).
  • 주소도 0

참조 : // 유래 : is there a GCC compiler/linker option to change the name of main?

관련 문제