티스토리 뷰
32bit와 64bit의 차이
- CPU 레지스터(Registers)
- Calling Conventions(함수 호출 규약)
1. CPU Registers
CPU의 레지스터란 처리의 지연 시간을 줄이기 위해 사용하고 있는 CPU 내부의 임시 기억장치이다. 컴퓨터가 데이터를 처리할 때 중앙처리장치인 CPU를 통해 처리를 하는데 매 번 메모리에서 처리를 할 때 마다 데이터를 가져오게 되면 시간 낭비가 생기게 되어 지연이 생기게 된다. 그래서 CPU 내부에 임시 기억장치인 레지스터를 두어 메모리에서 데이터를 가져와 저장하고 필요할 때 마다 불러와서 처리를 한다.
임시 기억장치이기 때문에 이 레지스터 또한 용량을 가지고 있는데 이 용량을 기준으로 CPU를 n bit 레지스터로 나누게 된다. 따라서 32bit 레지스터와 64bit 레지스터로 32bit와 64bit로 나뉘게 된다. 그리고 물론 레지스터의 용량이 클 수록 메모리에서 더 많은 데이터를 가져와 저장할 수 있기 때문에 처리 속도도 더 빨라진다.
64bit는 레지스터의 크기가 4byte(32bit)에서 8byte(64bit)로 변경되면서 메모리 주소를 저장하는 레지스터에 맞춰 메모리 주소 또한 4byte에서 8byte로 커지게 된다. 그리고 여기에 맞춰 매핑되는 메모리의 영역의 주소도 변경되었다.
32bit 매핑 tribal@tribal-virtual-machine:~$ cat /proc/self/maps 08048000-08053000 r-xp 00000000 08:01 131098 /bin/cat 08053000-08054000 r--p 0000a000 08:01 131098 /bin/cat 08054000-08055000 rw-p 0000b000 08:01 131098 /bin/cat 08055000-08076000 rw-p 00000000 00:00 0 [heap] b7ae3000-b7c15000 r--p 00858000 08:01 141654 /usr/lib/locale/locale-archive b7c15000-b7e15000 r--p 00000000 08:01 141654 /usr/lib/locale/locale-archive b7e15000-b7e16000 rw-p 00000000 00:00 0 b7e16000-b7fbe000 r-xp 00000000 08:01 1131 /lib/i386-linux-gnu/libc-2.19.so b7fbe000-b7fc0000 r--p 001a8000 08:01 1131 /lib/i386-linux-gnu/libc-2.19.so b7fc0000-b7fc1000 rw-p 001aa000 08:01 1131 /lib/i386-linux-gnu/libc-2.19.so b7fc1000-b7fc4000 rw-p 00000000 00:00 0 b7fd8000-b7fda000 rw-p 00000000 00:00 0 b7fda000-b7fdc000 r--p 00000000 00:00 0 [vvar] b7fdc000-b7fde000 r-xp 00000000 00:00 0 [vdso] b7fde000-b7ffe000 r-xp 00000000 08:01 1107 /lib/i386-linux-gnu/ld-2.19.so b7ffe000-b7fff000 r--p 0001f000 08:01 1107 /lib/i386-linux-gnu/ld-2.19.so b7fff000-b8000000 rw-p 00020000 08:01 1107 /lib/i386-linux-gnu/ld-2.19.so bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
64bit 매핑 tribal@tribal-virtual-machine:~/debug/test$ cat /proc/self/maps 00400000-0040b000 r-xp 00000000 08:06 259101 /bin/cat 0060a000-0060b000 r--p 0000a000 08:06 259101 /bin/cat 0060b000-0060c000 rw-p 0000b000 08:06 259101 /bin/cat 0060c000-0062d000 rw-p 00000000 00:00 0 [heap] 7ffff7201000-7ffff7a14000 r--p 00000000 08:06 140279 /usr/lib/locale/locale-archive 7ffff7a14000-7ffff7bcf000 r-xp 00000000 08:06 264702 /lib/x86_64-linux-gnu/libc-2.19.so 7ffff7bcf000-7ffff7dcf000 ---p 001bb000 08:06 264702 /lib/x86_64-linux-gnu/libc-2.19.so 7ffff7dcf000-7ffff7dd3000 r--p 001bb000 08:06 264702 /lib/x86_64-linux-gnu/libc-2.19.so 7ffff7dd3000-7ffff7dd5000 rw-p 001bf000 08:06 264702 /lib/x86_64-linux-gnu/libc-2.19.so 7ffff7dd5000-7ffff7dda000 rw-p 00000000 00:00 0 7ffff7dda000-7ffff7dfd000 r-xp 00000000 08:06 264678 /lib/x86_64-linux-gnu/ld-2.19.so 7ffff7fde000-7ffff7fe1000 rw-p 00000000 00:00 0 7ffff7ff6000-7ffff7ff8000 rw-p 00000000 00:00 0 7ffff7ff8000-7ffff7ffa000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffa000-7ffff7ffc000 r--p 00000000 00:00 0 [vvar] 7ffff7ffc000-7ffff7ffd000 r--p 00022000 08:06 264678 /lib/x86_64-linux-gnu/ld-2.19.so 7ffff7ffd000-7ffff7ffe000 rw-p 00023000 08:06 264678 /lib/x86_64-linux-gnu/ld-2.19.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] |
추가로, 1byte(=8bit)가 표현할 수 있는 수의 범위는 2^8인 것 처럼 32bit는 2^32 만큼 64bit는 2^64 만큼 표현이 가능하여 이것에 맞춰 RAM의 크기 또한 달라지게 된다. 32bit는 2^32만큼으로 최대 RAM의 크기 4GB, 64bit는 2^64이므로 최대 RAM의 크기가 8GB가 된다. 그래서 32bit는 RAM을 4GB에서 더 추가하더라도 의미가 없는 것이다.
2. Calling Conventions
32bit와 64bit의 중요한 차이점 2번째는 함수 호출 규약이다.
32bit Calling Conventions |
||
Calling Conventions |
인자 전달 방법 |
인자 정리 시점 |
__cdecl |
스택 |
함수 반환 후 인자 정리 |
__sedcall |
스택 |
함수 반환 전 인자 정리 |
__fastcall |
레지스터 EDX, ECX |
함수 반환 전 인자 정리 |
32bit는 위와 같이 3가지 함수 호출 규약 방식을 사용하고 있다. 하지만 64bit는 32bit와 달리 fastcall 함수 호출 규약을 한층 더 강화하여 오로지 하나의 함수 호출 규약 방식을 사용하고 있다.
64bit Calling Conventions |
||
Calling Conventions |
인자 전달 방법 |
인자 정리 시점 |
__fastcall 변형 |
레지스터로 전달 정수 : EDI, ESI, EDX, ECX, R8, R9 이 이후의 인자는 스택 |
함수 반환 전 인자 정리 |
__fastcall 변형 |
레지스터로 전달 정수 : ECX, EDX, R8, R9 이 이후의 인자는 스택 |
함수 반환 전 인자 정리 |
64bit ELF 프로그램 내부의 함수를 예로 들어서 설명하자면 add(int a, int b, float c, int d, float e)라는 함수가 있다. 이 경우 먼저 인자 a는 정수형 int이기 때문에 EDI 레지스터로 들어간다. 다음 b 역시 정수형 int이므로 ESI 레지스터로 들어가고 인자 c는 실수형 float이므로 XMM0 레지스터로 들어가게 된다. 다음은 순서대로 d가 EDX 레지스터, e가 XMM1 레지스터로 향하게 된다.
정리하자면 아래와 같이 된다. 32bit와 동일하게 인자가 뒤에서 부터 들어간다.
add(int a, int b, float c, int d, float e)
float e -> XMM1
int d -> EDX
float c -> XMM0
int b -> ESI
int a -> EDI
'System > Linux' 카테고리의 다른 글
SROP 정리 (0) | 2016.01.11 |
---|---|
ropgadget find (0) | 2016.01.06 |
포장 함수 gets, fgets의 임시 버퍼 (0) | 2015.12.28 |
쉘 스크립트 (0) | 2015.11.30 |
gcc 컴파일러 (0) | 2015.11.28 |