gdb - info function
GDB
를 사용하여 binary file
을 분해하여 정의된 함수 목록을 확인
int main(int, char **);
int F2(int);
int F1(int);
- 총 세 개의 함수가 정의되어 있음
disassemble
disassemble
을 수행하여 특정 함수의 assmebly code
를 확인하고, 코드를 한 줄씩 확인하면서 함수의 동작을 파악함
1) disassemble main function
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000001196 <+0>: push %rbx
0x0000000000001197 <+1>: mov $0xa,%edi
0x000000000000119c <+6>: callq 0x114a <F1>
0x00000000000011a1 <+11>: mov %eax,%ebx
0x00000000000011a3 <+13>: mov $0xa,%edi
0x00000000000011a8 <+18>: callq 0x117c <F2>
0x00000000000011ad <+23>: add %ebx,%eax
0x00000000000011af <+25>: pop %rbx
0x00000000000011b0 <+26>: retq
End of assembler dump.
- stack에 %rbx 저장
- local variable에 10을 넣어주고, 함수 F1 호출
- F1 함수 호출로 반환된 결과를 %ebx에 옮겨놓음
- Local variable에 다시 10을 넣고, F2 함수 호출
- F2 함수 호출의 결과가 저장되어 있는 %eax와 F1의 결과가 저장되어 있는 %ebx를 더함
- Stack에 %rbx 해제한 후 %eax에 저장되어 있는 Return value 값을 return
int main(int argc, char** argv) {
int a, result = 0;
a = 10;
result = F1(a);
return result + F2(a);
}
2) disassemble F1 function
(gdb) disassemble F1
Dump of assembler code for function F1:
0x000000000000114a <+0>: push %rbp
0x000000000000114b <+1>: push %rbx
0x000000000000114c <+2>: sub $0x8,%rsp
0x0000000000001150 <+6>: mov %edi,%ebx
0x0000000000001152 <+8>: test %edi,%edi
0x0000000000001154 <+10>: je 0x115b <F1+17>
0x0000000000001156 <+12>: cmp $0x1,%edi
0x0000000000001159 <+15>: jne 0x1164 <F1+26>
0x000000000000115b <+17>: mov %ebx,%eax
0x000000000000115d <+19>: add $0x8,%rsp
0x0000000000001161 <+23>: pop %rbx
0x0000000000001162 <+24>: pop %rbp
0x0000000000001163 <+25>: retq
0x0000000000001164 <+26>: lea -0x1(%rdi),%edi
0x0000000000001167 <+29>: callq 0x114a <F1>
0x000000000000116c <+34>: mov %eax,%ebp
0x000000000000116e <+36>: lea -0x2(%rbx),%edi
0x0000000000001171 <+39>: callq 0x114a <F1>
0x0000000000001176 <+44>: lea 0x0(%rbp,%rax,1),%ebx
0x000000000000117a <+48>: jmp 0x115b <F1+17>
End of assembler dump.
- Stack에 %rbp, %rbx 저장하고 Stack에 8만큼 공간 확보
- ZF : equal/zero -> 0이면 <F1+17> 위치로 jump
- 1과 같지 않은 경우 <F1 + 26> 위치로 jump
- 1과 같은 경우 return 1
- 0이여서 <F1 + 17>로 jump한 경우 바로 return 0
- Stack에 확보한 공간 해제, %rbp와 %rbx 해제 후 return
- <F1 + 26> 위치로 jump한 경우 F1 호출 시 %rdi – 0x1을 %edi 주소 값으로 줌
- 호출 후 결과 값을 %ebp에 저장한 후 %rbx – 0x2 주소 값으로 다시 F1 호출
- %rbp + %rax * 1 + 0x0 -> 첫 번째 호출 값과 두번째 호출 결과 값을 더해서 %ebx 저장
- 조건 체크 없이 바로 <F1 + 17>로 jump한 후 %eax에 %ebx을 넣어서 반환
int F1(int a){
if(a == 0){
return 0;
}
if(a != 1){
return F1(a - 1) + F1(a - 2);
}
return 1;
}
3) disassemble F2 function
(gdb) disassemble F2
Dump of assembler code for function F2:
0x000000000000117c <+0>: test %edi,%edi
0x000000000000117e <+2>: jne 0x1186 <F2+10>
0x0000000000001180 <+4>: mov $0x1,%eax
0x0000000000001185 <+9>: retq
0x0000000000001186 <+10>: push %rbx
0x0000000000001187 <+11>: mov %edi,%ebx
0x0000000000001189 <+13>: lea -0x1(%rdi),%edi
0x000000000000118c <+16>: callq 0x117c <F2>
0x0000000000001191 <+21>: imul %ebx,%eax
0x0000000000001194 <+24>: pop %rbx
0x0000000000001195 <+25>: retq
End of assembler dump.
- ~ZF : not zero/not equal : 0이 아니면 <F2 + 10>으로 jump
- 만약, 0이면 %eax에 1을 넣고 바로 return 1
- Stack에 %rbx 저장
- %rdi – 0x1 주소값으로 F2 호출
- F2 호출 결과가 저장된 %eax와 %ebx를 곱해서 %eax에 저장
- Stack에 %rbx 해제
int F2(int a){
if(a){
return a * F2(a - 1);
}
return 1;
}
전체 C code
#include <stdio.h>
int F1(int a){
if(a == 0){
return 0;
}
if(a != 1){
return F1(a - 1) + F1(a - 2);
}
return 1;
}
int F2(int a){
if(a){
return a * F2(a - 1);
}
return 1;
}
int main(int argc, char** argv) {
int a, result = 0;
a = 10;
result = F1(a);
return result + F2(a);
}