plt와 got에 관해 질문있습니다.
얼마전 linking과정에 대해 질문했던 사람입니다.
많은 도움으로 어느정도 감은 잡게 되었지만 아직까지 궁금한 점이 남아 다시 포스팅했습니다.
plt와 got에 관련된 건데요
제가 이해한것은
plt는 현제 프로그램이 동작하는데 필요한 외부함수의 심볼을 만들기 위해 외부함수loader와 연결해 주는 역할을 하는 table입니다.
즉 loader 함수에 필요한 인자를 push한 후 got의 첫번째 심볼인 loader를 호출해 필요한 외부함수의 주소를 받아와
got를 완성해주는 것으로 이해했습니다.
허나 아직 궁금한점이 있습니다.(사실은 이전보다 더 생겼습니다.)
int main() { printf("main\n"); return 0; }
위와같은 test용 소스를 작성했습니다.
objdump로 보면
28 080482c0 <__gmon_start__@plt-0x10>:
29 80482c0: ff 35 f8 9f 04 08 pushl 0x8049ff8
30 80482c6: ff 25 fc 9f 04 08 jmp *0x8049ffc
31 80482cc: 00 00 add %al,(%eax)
...
44 080482f0 :
45 80482f0: ff 25 08 a0 04 08 jmp *0x804a008
46 80482f6: 68 10 00 00 00 push $0x10
47 80482fb: e9 c0 ff ff ff jmp 80482c0 <_init+0x30>
이런식으로 되어있습니다.
즉 main은 puts를 호출하고 puts는 printf 호출부이고
push $0x10을 한 후 0x8048c0로 jmp를 합니다.(puts의 첫 명령인 jmp *0x804a008에는 바로 다음줄의 주소가 들어있기 때문에 생략했습니다.)
0x080482c0에서는 0x8049ff8을 push 하는데 이것이 바로 got의 주소입니다.
0x8049ffc(got+4) 에는 외부함수loader 의 주소가 들어있을 것으로 추정됩니다.
결론은 0x10을 push 한 이유는 got base로 부터 puts 함수의 주소가 들어갈 위치의 offset이고
0x8049ff8을 push 한 이유는 loader 함수에게 got의 주소를 알려주기 위함으로 생각됩니다.
이런식으로 동적 라이브러리상 puts의 절대주소를 알아내면 이후에는 jmp *0x804a008로
loader없이 puts의 절대주소로 이동할 수 있을것입니다.
하지만 puts의 함수주소를 알기 위해서는 가장중요한 무슨함수를 찾을것인가에 대한 정보를 알아야 하는데요
소스의 어디를 봐도 loader에게 puts를 찾으라는 단서를 제공하지 않습니다.
어떻게 loader는 puts를 찾을 수 있을까요?
readelf -a에서 리로케이션 테이블들을 보세요.
readelf -a에서 리로케이션 테이블들을 보세요.
아.. 그리고 리로케이션같은 것들 abi에
아.. 그리고 리로케이션같은 것들 abi에 정의되어있는 거고 x86-64 리눅스는 다음 문서를 참조하시면 됩니다.
http://www.x86-64.org/documentation/abi.pdf
tj님께서 잘 설명해 주셨지만..
한마디 덧붙이자면
push한 0x10이라는 인덱스 값은 GOT에서 저장될 위치를 나타내기도 하지만
리로케이션 테이블에서 해당 심볼을 찾기위한 용도로도 사용됩니다.
readelf -r a.out 으로 나온 결과 (rel.plt 혹은 rela.plt 섹션)에서
해당 인덱스를 확인해 보시면 될 것 같습니다.
(objdump -dj .plt 결과와 비교해 보세요..)
답변 감사드립니다. 34 [10]
답변 감사드립니다.
34 [10] .rel.plt REL 08048278 000278 000018 08 A 5 12 4
...
118 Relocation section '.rel.plt' at offset 0x278 contains 3 entries:
119 Offset Info Type Sym.Value Sym. Name
120 0804a000 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
121 0804a004 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main
122 0804a008 00000307 R_386_JUMP_SLOT 00000000 puts
이렇게 relocation table이 있군요. .rel.plt 섹션에 들어있는데 이 섹션의 위치는 0x08048278 가 됩니다.
이곳에는 위에 적어놓은 offset과 info가 순서대로 적혀있습니다.
즉 다음과 같습니다.
0x0804a000
0x00000107
0x0804a004
0x00000207
0x0804a008
0x00000307
여기서 또 info 필드가 궁금해 졌습니다. 이것이 바로 puts를 나타내는 값인가요?
정리하자면 pastime 님께서 말씀하신 0x10을 push 하는 이유가 got 뿐만 아니라 puts를 relocation table에서
찾기위한 용도로 사용된다 하셨는데 찾은 307값이 puts가 되는건가요?
그렇다면 .rel.plt 섹션의 주소는 loader 함수가 어떻게 찾았을까요?
ELF 스펙을 참조하세요..
info 필드는 symbol index + relocation type 입니다.
307이라면 3이 index고 7이 R_386_JUMP_SLOT에 해당합니다.
(그렇다면 PLT 내의 puts 부분에서도 3을 push해야 할 것 같은데 좀 이상해 보입니다..)
dynamic linking에 대한 모든 정보는 .dynamic이라는 이름의 섹션에서 찾을 수 있고
.dynamic 섹션의 위치도 ELF의 program header를 통해 쉽게 찾을 수 있습니다.
댓글 달기