Drop here!
예제 코드: test.c
#include <stdio.h>
#include "mylib.h"
char extern test;
int main(void)
{
int result = 0;
result = add(5,6);
printf("%d\n",result);
result = 0;
result = sub(10,4);
printf("%d\n",result);
test3();
test = test + 1;
printf("%d\n", test);
return 0;
}
예제코드: mylib.h
int add(int,int);
int add(int,int);
void test3(void);
char extern_char = 'a';
컴파일만 수행하여 test.o 오브젝트 파일 생성
nitraqu@ubuntu:~/Documents/static_test2$ gcc -c test.c
해당 오브젝트 파일을 보면...
Drop here!
objdump -d test.o : 오브젝트의 디스어셈블(disassemble) 코드를 출력objdump -r test.o : 오브젝트의 재배치영역(relocatable) 정보를 출력디스어셈블 된 코드를 보면예를 들어1d: e8 00 00 00 00 callq 22 <main+0x22>에 "00 00 00 00"은 "add"의 함수주소이다.하지만 컴파일 단계에서 해당 정보를 알 수 없기 때문에, 00 00 00 00 으로 채워둔다.다음 -r 명령어로 오브젝트 파일의 재배치 정보를 확인하였을 때000000000000001e R_X86_64_PLT32 add-0x00000000000000041e 위치의 "00 00 00 00"이 add 함수의 실제 주소로 변경되어야 함이 명시되어 있다.이러한 부분을 링커(Linker)가 링킹(Linking) 작업에서 실제 주소로 변경해 준다.
nitraqu@ubuntu:~/Documents/static_test2$ objdump -d test.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 83 ec 10 sub $0x10,%rsp
c: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
13: be 06 00 00 00 mov $0x6,%esi
18: bf 05 00 00 00 mov $0x5,%edi
1d: e8 00 00 00 00 callq 22 <main+0x22>
22: 89 45 fc mov %eax,-0x4(%rbp)
25: 8b 45 fc mov -0x4(%rbp),%eax
28: 89 c6 mov %eax,%esi
2a: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 31 <main+0x31>
31: b8 00 00 00 00 mov $0x0,%eax
36: e8 00 00 00 00 callq 3b <main+0x3b>
3b: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
42: be 04 00 00 00 mov $0x4,%esi
47: bf 0a 00 00 00 mov $0xa,%edi
4c: b8 00 00 00 00 mov $0x0,%eax
51: e8 00 00 00 00 callq 56 <main+0x56>
56: 89 45 fc mov %eax,-0x4(%rbp)
59: 8b 45 fc mov -0x4(%rbp),%eax
5c: 89 c6 mov %eax,%esi
5e: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 65 <main+0x65>
65: b8 00 00 00 00 mov $0x0,%eax
6a: e8 00 00 00 00 callq 6f <main+0x6f>
6f: e8 00 00 00 00 callq 74 <main+0x74>
74: 0f b6 05 00 00 00 00 movzbl 0x0(%rip),%eax # 7b <main+0x7b>
7b: 83 c0 01 add $0x1,%eax
7e: 88 05 00 00 00 00 mov %al,0x0(%rip) # 84 <main+0x84>
84: 0f b6 05 00 00 00 00 movzbl 0x0(%rip),%eax # 8b <main+0x8b>
8b: 0f be c0 movsbl %al,%eax
8e: 89 c6 mov %eax,%esi
90: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 97 <main+0x97>
97: b8 00 00 00 00 mov $0x0,%eax
9c: e8 00 00 00 00 callq a1 <main+0xa1>
a1: b8 00 00 00 00 mov $0x0,%eax
a6: c9 leaveq
a7: c3 retq
nitraqu@ubuntu:~/Documents/static_test2$ objdump -r test.o
test.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
000000000000001e R_X86_64_PLT32 add-0x0000000000000004
000000000000002d R_X86_64_PC32 .rodata-0x0000000000000004
0000000000000037 R_X86_64_PLT32 printf-0x0000000000000004
0000000000000052 R_X86_64_PLT32 sub-0x0000000000000004
0000000000000061 R_X86_64_PC32 .rodata-0x0000000000000004
000000000000006b R_X86_64_PLT32 printf-0x0000000000000004
0000000000000070 R_X86_64_PLT32 test3-0x0000000000000004
0000000000000077 R_X86_64_PC32 extern_char-0x0000000000000004
0000000000000080 R_X86_64_PC32 extern_char-0x0000000000000004
0000000000000087 R_X86_64_PC32 extern_char-0x0000000000000004
0000000000000093 R_X86_64_PC32 .rodata-0x0000000000000004
000000000000009d R_X86_64_PLT32 printf-0x0000000000000004
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
0000000000000020 R_X86_64_PC32 .text
추가로 링킹이 끝난, 실행파일 (test)의
objdump -d test 의 main 부분이다.
- 오브젝트 파일과 달리 링킹과정에서 사용자가 입력하지 않은 코드들 (_init, _start 등이 들어가게 된다.)
- 실제로 호출하지 않는 코드들도 static으로 컴파일하게 되면 모두 들어간다.
1186: e8 86 00 00 00 callq 1211 <add>
와 같이 "e8 00 00 00 00"이 "e8 86 00 00 00"으로 바뀐 것을 볼 수 있다.
코드 위치가 0x1186이고 상대주소 + 0x86을 더하면
- 0x1186 + 0x86 = 0x120C
- 0x120C + 0x5 = 0x1211 (5바이트는 0x1186 의 명령어 길이)
0000000000001169 <main>:
1169: f3 0f 1e fa endbr64
116d: 55 push %rbp
116e: 48 89 e5 mov %rsp,%rbp
1171: 48 83 ec 10 sub $0x10,%rsp
1175: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
117c: be 06 00 00 00 mov $0x6,%esi
1181: bf 05 00 00 00 mov $0x5,%edi
1186: e8 86 00 00 00 callq 1211 <add>
118b: 89 45 fc mov %eax,-0x4(%rbp)
118e: 8b 45 fc mov -0x4(%rbp),%eax
1191: 89 c6 mov %eax,%esi
1193: 48 8d 3d 6a 0e 00 00 lea 0xe6a(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
119a: b8 00 00 00 00 mov $0x0,%eax
119f: e8 cc fe ff ff callq 1070 <printf@plt>
11a4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
11ab: be 04 00 00 00 mov $0x4,%esi
11b0: bf 0a 00 00 00 mov $0xa,%edi
11b5: b8 00 00 00 00 mov $0x0,%eax
11ba: e8 8e 00 00 00 callq 124d <sub>
11bf: 89 45 fc mov %eax,-0x4(%rbp)
11c2: 8b 45 fc mov -0x4(%rbp),%eax
11c5: 89 c6 mov %eax,%esi
11c7: 48 8d 3d 36 0e 00 00 lea 0xe36(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
11ce: b8 00 00 00 00 mov $0x0,%eax
11d3: e8 98 fe ff ff callq 1070 <printf@plt>
11d8: e8 4f 01 00 00 callq 132c <test3>
11dd: 0f b6 05 2c 2e 00 00 movzbl 0x2e2c(%rip),%eax # 4010 <extern_char>
11e4: 83 c0 01 add $0x1,%eax
11e7: 88 05 23 2e 00 00 mov %al,0x2e23(%rip) # 4010 <extern_char>
11ed: 0f b6 05 1c 2e 00 00 movzbl 0x2e1c(%rip),%eax # 4010 <extern_char>
11f4: 0f be c0 movsbl %al,%eax
11f7: 89 c6 mov %eax,%esi
11f9: 48 8d 3d 04 0e 00 00 lea 0xe04(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
1200: b8 00 00 00 00 mov $0x0,%eax
1205: e8 66 fe ff ff callq 1070 <printf@plt>
120a: b8 00 00 00 00 mov $0x0,%eax
120f: c9 leaveq
1210: c3 retq
add의 주소는 0x1211 이다.
참고로 해당 주소조차도, 로더(Loader)에 의해 메모리에 적재될 때
변경된다는 것을 기억하자.
0000000000001211 <add>:
1211: f3 0f 1e fa endbr64
1215: 55 push %rbp
1216: 48 89 e5 mov %rsp,%rbp
1219: 48 83 ec 20 sub $0x20,%rsp
121d: 89 7d ec mov %edi,-0x14(%rbp)
1220: 89 75 e8 mov %esi,-0x18(%rbp)
1223: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
122a: 8b 55 e8 mov -0x18(%rbp),%edx
122d: 8b 45 ec mov -0x14(%rbp),%eax
1230: 89 c6 mov %eax,%esi
1232: 48 8d 3d cf 0d 00 00 lea 0xdcf(%rip),%rdi # 2008 <_IO_stdin_used+0x8>
1239: b8 00 00 00 00 mov $0x0,%eax
123e: e8 2d fe ff ff callq 1070 <printf@plt>
1243: 8b 55 ec mov -0x14(%rbp),%edx
1246: 8b 45 e8 mov -0x18(%rbp),%eax
1249: 01 d0 add %edx,%eax
124b: c9 leaveq
124c: c3 retq



덧글