1 / 41

64bit 프로그래밍

정성태 (kevin13@chol.net) *** 이 문서는 PPT Template 만을 .NETXPERT 를 썼을 뿐 , 회사의 공식 문서가 아닙니다. 64bit 프로그래밍. MSDN Magazine 2006-05 x64 Primer – Everything You Need to Know To Start Programming 64-bit Windows Systems. 2006.06.10. Win64.

lee-dickson
Download Presentation

64bit 프로그래밍

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 정성태(kevin13@chol.net) *** 이 문서는 PPT Template 만을 .NETXPERT 를 썼을 뿐, 회사의 공식 문서가 아닙니다. 64bit 프로그래밍 MSDN Magazine 2006-05x64 Primer – Everything You Need to Know To Start Programming 64-bit Windows Systems 2006.06.10

  2. Win64 IA64 와는 달리 x64 는 기존 x86 시스템과의 호환성을 유지. Win64 시스템은 x64 - AMD x64, Intel x64 모두 에서 동작하며, 이로 인해 응용 프로그램은 단일한 Win64 시스템을 목표로 제작하면 됨. 이 PPT 에서는 기존 Win32 응용 프로그램을 x64 로 변환하기 위해 필요한 Win64 기반 지식을 다룹니다.

  3. 목차 • OS 세부 구현 • x64 CPU 구조 • VC++ 로 x64 프로그램 개발 • .NET 으로 x64 프로그램 개발

  4. OS 세부 구현 1-1. 주소 공간 – 물리 메모리 한계 이론상 가능한 주소 공간 : 2의 64승 – 16 exabytes Windows x64 운영 체제 : 2의 44승 – 16 terabytes 차이가 나는 이유? • 현재의 x64 CPU 자체의 한계 : 2의 40승 까지만 지원 – 1 terabytes • 아키텍쳐 차원에서 확보된 한계 : 2의 52승 까지 가능 – 4 petabytes • 늘어난 메모리 만큼 관리되어져야 할 페이지 테이블도 따라서 증가 표 [1] 참조

  5. OS 세부 구현 • 표 1 Physical Memory and CPU Limits

  6. OS 세부 구현 1-2. 주소 공간 – Windows 시스템

  7. OS 세부 구현 1-3. 주소 공간 – Win64 프로세스 공간 Win32 와 마찬가지로, 가상 주소 공간은 커널과 유저 영역으로 분리 • 0 ~ 8 TB : User mode • 8 ~ 16 TB : Kernel mode • Page size : 4KB • 최초 64KB 영역은 매핑이 안됨. 따라서 실제 유효한 주소 는 0x10000 이상 • System DLL 들은 4GB 이상의 영역에 위치. (보통 0x7FF00000000)

  8. OS 세부 구현 1-4. 주소 공간 – Win32 주소공간 예시 x86 – Windows 2003 기준 : Internet Explorer 실행

  9. OS 세부 구현 1-5. 주소 공간 – Win64 주소공간 예시 x64 – Windows 2003 기준 : Internet Explorer 실행

  10. OS 세부 구현 2. DEP ( Data Execution Protection ) 최근의 x64 프로세서들은 CPU No Execute bit 가 지원되어, Win64 윈도우즈는 하드웨어적으로 구현된 DEP 기능을 사용. • 버퍼 오버런으로 인한 데이터 영역에서의 코드 실행을 금지 • 버퍼 오버런을 야기 시켰던 바이러스 및 프로그램 자체의 오류에 대한 보호 기능 향상 • 시스템 안정화

  11. OS 세부 구현 3. 타입 (Types) int, long, DWORD : Win64 에서도 여전히 32bit 포인터, HANDLE, size_t : Win64 – 64bit 로 변경

  12. OS 세부 구현 4. 파일 포맷 : PE32+ 기존 Win32 PE 파일과 비슷한 구조 유지. 필요 없는 필드의 삭제 및 32bit 크기의 필드들에 대한 64bit 의 확장 변경 • IMAGE_LOAD_CONFIG, IMAGE_THUNK_DATA 같은 경우 역시 32bit 필드들이 64bit 로 확장 • 새롭게 PDATA 섹션이 추가 – Exception Handling 을 위한 함수 테이블 표 [3] 참조

  13. 표 3 Changes to PE File FIelds

  14. OS 세부 구현 5-1. 예외 처리 : Win32 – 스택 기반 예외가 발생하면 OS 는 FS:[0] 을 시작으로 스택 상에 Linked List 로 연결되어 있는 예외 처리기를 실행. EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, struct _CONTEXT *ContextRecord, void * DispatcherContext ){ return ExceptionContinueExecution; }{ DWORD handler = (DWORD)_except_handler; __asm { push handler // Address of handler function push FS:[0] // Address of previous handler mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION} __asm { mov eax,0 // Zero out EAX mov [eax], 1 // Write to EAX to deliberately cause a fault} __asm { mov eax,[ESP] // Get pointer to previous record mov FS:[0], EAX // Install previous record add esp, 8 // Clean our EXECEPTION_REGISTRATION off stack}

  15. OS 세부 구현 5-2. 예외 처리 : Win64 – 테이블 기반 테이블 기반의 예외 처리. Win64 실행 모듈 자체에 runtime function table 을 포함. 함수 테이블에 있는 각각의 entry 는 해당 함수의 시작/끝 주소와 함께 부가 정보에 대한 위치를 포함. • Win64 SDK WinNT.h 파일에 정의된 IMAGE_RUNTIME_FUNCTION_ENTRY 를 참조 • 동적 생성된 코드를 위해서 런타임 시에 추가 entry 를 넣고 싶다면, RtlAddFunctionTable API 를 사용 • 단점 : 스택 기반의 예외 처리에 비해서, 함수 테이블을 모두 검색해야 하기 때문에 상대적으로 느리다. • 장점 : 함수가 실행될 때마다 try 데이터 블록을 설정해야 하는 오버헤드가 없다.

  16. OS 세부 구현 5-3. 예외 처리 : Win64 – 예외 처리 없는 코드 int _tmain(int argc, _TCHAR* argv[]) { 0000000000402DF0 mov qword ptr [rsp+10h],rdx 0000000000402DF5 mov dword ptr [rsp+8],ecx 0000000000402DF9 push rdi 0000000000402DFA sub rsp,10h 0000000000402DFE mov rdi,rsp 0000000000402E01 mov rcx,4 0000000000402E0B mov eax,0CCCCCCCCh 0000000000402E10 rep stos dword ptr [rdi] 0000000000402E12 mov ecx,dword ptr [rsp+20h]  int boundary = 0; 0000000000402E16 mov dword ptr [rsp],0  boundary ++; 0000000000402E1D mov eax,dword ptr [rsp] 0000000000402E20 add eax,1 0000000000402E23 mov dword ptr [rsp],eax { int check = 0; 0000000000402E26 mov dword ptr [check],0 } return 0; 0000000000402E2E xor eax,eax } 0000000000402E30 add rsp,10h 0000000000402E34 pop rdi 0000000000402E35 ret

  17. OS 세부 구현 5-4. 예외 처리 : Win64 – 예외 처리 있는 코드 int _tmain(int argc, _TCHAR* argv[]) { 0000000000402DF0 mov qword ptr [rsp+10h],rdx 0000000000402DF5 mov dword ptr [rsp+8],ecx 0000000000402DF9 push rdi 0000000000402DFA sub rsp,10h 0000000000402DFE mov rdi,rsp 0000000000402E01 mov rcx,4 0000000000402E0B mov eax,0CCCCCCCCh 0000000000402E10 rep stos dword ptr [rdi] 0000000000402E12 mov ecx,dword ptr [rsp+20h] 0000000000402E16 mov qword ptr [rsp+8],0FFFFFFFFFFFFFFFEh int boundary = 0; 0000000000402E1F mov dword ptr [rsp],0  boundary ++; 0000000000402E26 mov eax,dword ptr [rsp] 0000000000402E29 add eax,1 0000000000402E2C mov dword ptr [rsp],eax try { int check = 0; 0000000000402E2F mov dword ptr [check],0 } catch ( ... ) { } return 0; 0000000000402E37 xor eax,eax } 0000000000402E39 add rsp,10h 0000000000402E3D pop rdi 0000000000402E3E ret

  18. OS 세부 구현 5-5. 예외 처리 : 참고 자료 x86 예외 처리A Crash Course on the Depths of Win32™ Structured Exception Handlinghttp://www.microsoft.com/msj/0197/Exception/Exception.aspxx64 예외 처리 X64 Unwind Information http://blogs.msdn.com/509372.aspx

  19. OS 세부 구현 6. 새로 추가된 API IA64 버전과는 달리 x64 버전의 Windows 에서는 그다지 특기할 만한 새로운 API 가 없음. • IsWow64Process – 현재 Win64 시스템에서 구동되고 있는지 검사. • GetNativeSystemInfo – Win64 시스템의 환경 정보 • 그 외의 API 들은 [표 4]에 나열

  20. 표 4 New 64-Bit APIs

  21. OS 세부 구현 7-1. WOW64 Subsystem Win32 코드를 Win64 환경에서 실행시켜 주는 서브시스템 환경. WOW64 에서 실행되고 있는 프로세스는 작업관리자에서 “*32” 로 확인 가능. - 16 bit 코드는 지원 종료

  22. OS 세부 구현 7-2. WOW64 Subsystem - 제한 32bit 프로세스는 커널 모드로 진입시, 중간의 WOW64 코드가 해당 호출을 가로채서 처리. • 32bit 프로세스 – 32bit DLL 만 로딩 가능 • 64bit 프로세스 – 64bit DLL 만 로딩 가능 • 프로세스 간 통신은 여전히 유효하며, 기존의 공유 메모리(shared memory), 명명 파이프(named pipe), 동기화 개체(named synchronization object)들은 그대로 사용 가능 * 이로 인해, Internet Explorer 의 경우 32bit 용이 제공됨. 또한 IIS 웹 애플리케이션의 경우, 64bit 로 변환될 수 없는 32bit COM DLL 로 인해 WOW64 모드로 동작하는 상황도 발생됨.

  23. OS 세부 구현 7-2. WOW64 Subsystem – 시스템 디렉토리 관리 Kernel32.dll 과 같은 DLL 들이 동일한 디렉토리에서 동일한 이름으로 32bit 모듈과 64 모듈을 가지고 있을 수 없으므로, 이를 위해 WOW64 는 32bit 프로세스에 대해 시스템 디렉토리를 “SysWow64” 폴더로 우회 만약, 64bit 프로세스에서 명시적으로 “SysWow64” 폴더 경로를 구하고 싶다면, GetSystemWow64Directory API 를 사용. • 32bit DLL : “C:\Windows\SysWow64” • 64bit DLL : “C:\Windows\System32”

  24. OS 세부 구현 7-3. WOW64 Subsystem – 레지스트리 관리 32bit 와 64bit 로 제공되는 COM 개체가 등록될 때, 또는 32/64bit 프로세스가 해당 COM 개체를 생성할 때의 레지스트리 참조 문제를 해결하기 위해 별도 관리 명시적으로, 다른 환경의 레지스트를 구하기 위해서는 RegOpenKey API 등의 flag 값으로 다음과 같은 값들이 추가됨 KEY_WOW64_64KEY – 명시적으로 64 bit 레지스트리 경로를 반환 KEY_WOW64_32KEY – 명시적으로 32 bit 레지스트리 경로를 반환 • 64bit 프로세스 : HKEY_CLASSES_ROOT\CLSID • 32bit 프로세스 : HKEY_CLASSES_ROOT\Wow6432Node\CLSID

  25. OS 세부 구현 8. 기타 - 쓰레드 환경 블록을 나타내는 FS 레지스터는 Win64 에서는 GS 레지스터가 담당. - PatchGuard 적용 : syscall 테이블이나 IDT (interrupt dispatch table)같은 중요한 커널 데이터를 사용자 모드의 프로그램이나 드라이버가 명시적으로 지원되지 않는 방법으로 변경하는 것을 봉쇄.중요한 커널 메모리 영역에 대한 변화를 별도의 커널 모드 쓰레드를 이용하여 감시.

  26. x64 CPU 구조 1. 레지스터 • IA64 와는 달리, 기존 x86 과의 호환성을 위해서 유사한 구조로 확장됨. • 범용 레지스터의 이름이 64bit 로 확장되면서 새롭게 “R”로 시작. 이전의 EAX, AX, AL, AH 등의 접근 방식도 그대로 지원 • R8 ~ R15 까지의 새로운 64bit 범용 레지스터 추가 • 16개의 128-bit 의 SSE2 레지스터 – XMM0 ~ XMM15 자세한 x64 레지스터 셋은 WinNT.h 파일의 #if defined(_AMD64_)안에 있는 _CONTEXT 구조체를 참고.

  27. x64 CPU 구조 2. 64bit 주소 지정 아래와 같은 기존 32bit 명령어의 경우 5-byte 명령어 크기를 가짐CALL DWORD PTR [XXXXXXXX] 64bit 에서도 64bit 주소 공간을 사용함에도 불구하고 위의 명령어는 그대로 5-byte 를 유지. 64-bit 모드에서는 32-bit 크기의 오퍼랜드 값은 현재 명령어를 기준으로 상대적인 위치를 나타내는 offset 값으로 동작. 즉, 실제로 다음과 같은 명령어는, 00401000: CALL DWORD PTR [00020000h] 00421000h 영역에 저장된 64-bit 포인터 값이 호출 주소가 됨. 이로 인해, 64-bit 포인터 값을 담고 있는 영역이 코드 실행 주소로부터 2GB 내에 위치하고 있어야 하는 제한이 생김. 따라서 개발자가 동적으로 코드를 생성하거나, 기존 코드를 변경하는 경우에는 이것에 주의해야 함.* 2006-08-12 추가 : Call Dword ptr 명령어 다음 주소부터 계산해서 변위값을 더하기 때문에 엄밀히 421000h 값은 아님.

  28. x64 CPU 구조 3-1. 파라미터 전달 방식(calling convention) - 단 하나의 calling convention 만을 지원. __cdecl 같은 지시자들은 컴파일러에 의해 무시됨. x64 호출 방식은 굳이 비교하자면, x86 fastcall 방식과 유사. - 처음 4개의 정수 값들은(우측에서 좌측 순으로) 64bit 레지스터들에 전달.RCX: 첫번재 인자RDX: 두번재 인자R8: 세번째 인자R9: 네번째 인자 - 처음 4개의 부동 소수 값들은 XMM0 ~ XMM3 레지스터에 전달.- 각각 4개의 값들을 초과하는 인수에 대해서는 스택을 통해서 전달.

  29. x64 CPU 구조 3-2. 파라미터 전달 방식(calling convention) - 예제 int test( int k, int j, int t, int o, int p, double dd ) { return 0; } { test( 0, 1, 2, 3, 4, 0.06 ); } 0000000000402E52 movsd xmm0,mmword ptr [__real@3faeb851eb851eb8 (405B88h)] 0000000000402E5A movsd mmword ptr [rsp+28h],xmm0 // XMM0 == 0.06 0000000000402E60 mov dword ptr [rsp+20h],4 // 스택 == 4 0000000000402E68 mov r9d,3 // R9 == 3 0000000000402E6E mov r8d,2 // R8 == 2 0000000000402E74 mov edx,1 // RDX == 1 0000000000402E79 xor ecx,ecx // RCX == 0 0000000000402E7B call test

  30. x64 CPU 구조 3-3. 파라미터 전달 방식(calling convention) – 스택 관리(1) • 인자를 레지스터에 전달하는 것과 상관없이 스택 영역도 확보. 레지스터를 사용해야 할 경우가 생기면, 그 값을 해당하는 스택에 보관. • 인자가 없더라도 최소 4개 영역 만큼은 확보. 이로 인해, 스택 위치로 복사하는 offset 값이 동일하게 유지됨. 인자가 5개 이상일 때부터 추가 스택 영역 확보. - 스택 정리 작업도 “호출자(caller)” 가 담당.

  31. x64 CPU 구조 3-3. 파라미터 전달 방식(calling convention) – 스택 관리(2) • 함수의 진입(prologue)/탈출(epilogue) 코드 부분을 제외하고 RSP 값이 바뀌는 경우가 거의 발생하지 않음. • x64 컴파일러는 함수 내에서 가장 큰 파라미터 수를 가진 호출 함수를 기준으로 충분한 스택 공간을 미리 예약. 그렇게 잡아둔 공간으로 이후의 함수 호출들에 대해서 스택 공간을 재사용. • 함수 호출 시마다 발생했던 ESP 레지스터에 대한 작업이 사라짐 자세한 x64 호출 방식에 대해서는 다음의 토픽을 참조. The history of calling conventions, part 5: amd64 ; http://blogs.msdn.com/oldnewthing/archive/2004/01/14/58579.aspx

  32. x64 CPU 구조 3-4. 파라미터 전달 방식(calling convention) – 반환 값 • 정수인 경우, RAX 로 전달. 부동 소수 값인 경우 XMM0 으로 전달 • 함수 호출 간에 보존되어야 할 레지스터; RBX, RBP, RDI, RSI, R12, R13, R14, R15 • 휘발성이고 값이 변경될 수 있는 레지스터; RAX, RCX, RDX, R8, R9, R10, R11

  33. x64 CPU 구조 4. 기타 • Integer parameters that are less than 64-bits are sign extended, then still passed via the appropriate register, if among the first four integer parameters. • At no point should any parameter be in a stack location that's not a multiple of 8 bytes, thus preserving 64-bit alignment. Any argument that's not 1, 2, 4, or 8 bytes (including structs) is passed by reference. • Structs and unions of 8, 16, 32, or 64-bits are passed as if they were integers of the same size.

  34. VC++ 로 x64 프로그램 개발 1. 컴파일 환경 구성 – VS.NET 2005 “Build” / “Configuration Manager” 에서 “Active solution platform” / “<New...>” 를 선택. “x64” 환경을 위한 빌드 유형을 생성.

  35. VC++ 로 x64 프로그램 개발 2. 권고 사항 – 소스 변환(1) • 포인터 변환 연산을 int, long, DWORD 값 등에 저장해서 한 것이 가장 큰 문제. 포인터는 x64 에서 8byte 로 바뀌어 4GB 이상의 영역을 지정할 수 있는 데 연산을 수행했던 int/long/DWORD 값은 여전히 4byte 로 심각한 문제 발생 • 포인터 연산을 수행한 int/long/DWORD 의 경우, DWORD_PTR, INT_PTR 등으로 변환하고, 크기를 명시해야 할 필요가 있는 경우에는 basetsd.h 에 정의된 INT32, INT64, INT16, UINT32, DWORD64 등을 사용 • printf/sprintf 등의 포맷팅에서 문제 발생. 보통 포인터 값에 대한 출력으로 %X, %08X 를 사용했던 것들을 %p 로 수정. 크기 종속적인 출력인 경우 “I” 접두사를 사용. 예를 들어, UINT_PTR 변수에는 “%lu”, 플랫폼에 무관한 64bit 부호 있는 정수에 대해서는 “%l64d”를 사용

  36. VC++ 로 x64 프로그램 개발 2. 권고 사항 – 소스 변환(2) • 포인터 문제를 명시적으로 끌어내기 위해 DLL/EXE 의 base address 를 4GB 이상의 영역으로 지정 • Win32 와 Win64 에서의 컴파일 시 소스 코드를 지정하기 위해 다음의 매크로 상수를 사용._M_IX86 : x86 프로세서_M_AMD64 : AMD 64 프로세서_WIN64 : IX86 과 AMD64 를 포함한 64bit 환경 #ifdef _M_AMD64// My x64 code here#elif defined (_M_IX86)// My x86 code here#else#error !!! Need to write code for this architecture#endif #ifdef _M_AMD64// My x64 code here#else// My x86 code here#endif

  37. VC++ 로 x64 프로그램 개발 2. 권고 사항 – 소스 변환(3) - 인라인 어셈블리 : x64 빌드에서는 인라인 어셈블리 코드가 지원되지 않음. __asm 예약어 자체를 사용할 수 없음. 64bit MASM (ML64exe)를 사용해서 별도 컴파일.

  38. .NET 으로 x64 프로그램 개발 1. 컴파일 환경 구성 – VS.NET 2005 - .NET 은 기본적으로 “Any CPU” 로 설정되어 있음. 원한다면, 특정 CPU 에서만 동작하도록 “x86”, “x64”, “Itanium”으로 설정 가능.

  39. .NET 으로 x64 프로그램 개발 2. 권고 사항 – 소스 변환 - P/Invoke 관련 코드가 있는 경우, 반드시 검증.

More Related