2015-01-28 3 views
2

C 코드에서는 명령 줄 인수를 반복하고 각 인수를 출력합니다. 어셈블리에서 같은 일을하려고했기 때문에 GDB에서 컴파일하여 주요 기능이 어떻게 보이는지 살펴 보았습니다. 결국 내 문제는 내 인쇄 기능이 주요 기능과 동일한 레지스터를 사용하고 있다는 것을 알아 냈습니다. 함수 호출 전에 각각을 스택으로 밀어 넣고 끝내기 만하면됩니다. 왜 내가 이해할 수없는 것은이 코드가 그렇게하지 않는 것, 그리고 왜 내가이 코드와 같은 문제에 빠지지 않는지입니다.보존 레지스터?

0x000000000040052d <+0>:  push %rbp 
    0x000000000040052e <+1>:  mov %rsp,%rbp 
    0x0000000000400531 <+4>:  sub $0x20,%rsp 
    0x0000000000400535 <+8>:  mov %edi,-0x14(%rbp) 
    0x0000000000400538 <+11>: mov %rsi,-0x20(%rbp) 
    0x000000000040053c <+15>: jmp 0x400561 <main+52> 
    0x000000000040053e <+17>: mov -0x4(%rbp),%eax 
    0x0000000000400541 <+20>: cltq 
    0x0000000000400543 <+22>: lea 0x0(,%rax,8),%rdx 
    0x000000000040054b <+30>: mov -0x20(%rbp),%rax 
    0x000000000040054f <+34>: add %rdx,%rax 
    0x0000000000400552 <+37>: mov (%rax),%rax 
    0x0000000000400555 <+40>: mov %rax,%rdi 
    0x0000000000400558 <+43>: callq 0x400410 <[email protected]> 
    0x000000000040055d <+48>: addl $0x1,-0x4(%rbp) 
    0x0000000000400561 <+52>: mov -0x4(%rbp),%eax 
    0x0000000000400564 <+55>: cmp -0x14(%rbp),%eax 
    0x0000000000400567 <+58>: jl  0x40053e <main+17> 
    0x0000000000400569 <+60>: leaveq 
    0x000000000040056a <+61>: retq 

모든 입력이 인식되고, 감사합니다.

(gdb) disass 0x400410 
Dump of assembler code for function [email protected]: 
    0x0000000000400410 <+0>:  jmpq *0x200c02(%rip)  # 0x601018 <[email protected]> 
    0x0000000000400416 <+6>:  pushq $0x0 
    0x000000000040041b <+11>: jmpq 0x400400 
End of assembler dump. 
(gdb) disass 0x601018 
Dump of assembler code for function [email protected]: 
    0x0000000000601018 <+0>:  (bad) 
    0x0000000000601019 <+1>:  add $0x40,%al 
    0x000000000060101b <+3>:  add %al,(%rax) 
    0x000000000060101d <+5>:  add %al,(%rax) 
    0x000000000060101f <+7>:  add %ah,(%rsi) 
End of assembler dump. 

사실 나는 그것이 풋에서 인쇄되는 부분을 찾을 수없는 것 같습니다. 나는 무엇인가 놓치고 있어야한다, 단지 무엇이 있는지에 관해 모른다.

+0

'puts @ plt '이 무엇인지 확인하십시오. 정당한 추측은 처음에 사용할 레지스터를 푸시하는 것입니다. – usr2564301

+0

그 말이 맞을 것입니다.하지만 체크하지는 않았지만, 내가 찾은 것을 보여주기 위해 잠시 후에 내 포스트를 업데이트 할 것입니다. – Jonnycake

답변

4

팟에 대해 표시하는 디스 어셈블리가 올바르지 않습니다. 동적으로로드 된 라이브러리의 라이브러리 심볼은 동적으로 잘 해석됩니다. 컴파일러에서 스텁 (프로 시저 연결 테이블 또는 PLT)에 대한 호출을 생성하면 런타임에 해당 함수를 호출 할 때 두 번째로 주소가 확인되고 더 빠르게 실행됩니다. 두 번째 반복에서이를 분해하면 실제 puts 코드가 실행되는 것을 볼 수 있으며 푸시 된 레지스터가 표시됩니다.

자세한 정보 here.

+0

고맙습니다. 나는 뭔가를 이해하지 못한다는 것을 알았다. – Jonnycake

3

이 명령어 :

jmpq *0x200c02(%rip)  # 0x601018 <[email protected]> 

가 명령 포인터로부터 오프셋이 이동에 의해 지정된 어드레스로부터 쿼드 워드 (8 바이트)를 읽는다. 따라서 이것이 어디로 가고 있는지 확인하려면 disas 0x601018을 사용하고 싶지 않으므로 x /1xg 0x601018을 사용하여 해당 바이트에 무엇이 있는지 확인하고 (포인터를 읽음) disas을 해당 값으로 호출하여 puts

의 실제 코드를 확인합니다.

이 항목은 동적 라이브러리의 함수를 호출하도록 설정된 모든 동적 연결 요소입니다. plt은 "program linkage table"의 약어로, 객체가 다른 동적 라이브러리에서 함수를 호출 할 때마다 링커가 만든 트램폴린 집합입니다. got은 "전역 개체 테이블"의 약자이며 링커에서 작성하고 프로그램이로드 될 때 동적 링커에 의해 채워지는 함수 포인터 테이블입니다.