#pragma omp section
#pragma omp parallel...
을 이용하여 멀티 프로세서를 사용함으로써 효율을 높일 수 있다.
출처 및 예제: http://deadwi.jaram.org/wiki/wikka.php?wakka=OpenMPSections/show&time=2008-09-08+17:55:15
장현준
2008/10/23 09:50
2008/10/23 09:50
이 글에는 아직 트랙백이 없고, 아직 댓글이 없고, OpenMP,
듀얼코어,
성능올리기,
프로그래밍 태그가 달려있으며, 2008/10/23 09:50에 작성되었습니다.
와 같은 루틴을 찾아서 if문을 patch하는 방식을 주로 이용하는데요..
이것을 직접 구현하는 방법을 알아보도록 하겠습니다.
Windows에서는 Thread Environment Block라는 블록이 있습니다.
말 그대로 Thread에 관련된 환경값이 있는데요, 이 중 Thread가 속한 Process Environment Block를 구할 수 있는 field가 있습니다.
TEB는 FS:[0x18]로 구하고, PEB는 아래에 나오는 구조체의 필드로부터 메모리 주소값을 얻어와서 구합니다.
왜 FS:[0x18]이냐... ring3에서는 fs레지스터가 teb를 가리키고 있게 구성 되어 있다고 합니다.
그렇다면 우선 Winternl.h에 선언되어 있는 PEB와 TEB의 구조를 보겠습니다. (VS 2003입니다)
재미있는건 PEB를 IsDebuggerPresent(), CheckRemoteDebuggerPresent() 대신 BeingDebugged 필드를 이용하여도 된다고 하네요.
//
// Instead of using the BeingDebugged field, use the Win32 APIs
// IsDebuggerPresent, CheckRemoteDebuggerPresent
// Instead of using the SessionId field, use the Win32 APIs
// GetCurrentProcessId and ProcessIdToSessionId
// Sample x86 assembly code that gets the SessionId (subject to change
// between Windows releases, use the Win32 APIs to make your application
// resilient to changes)
// mov eax,fs:[00000018]
// mov eax,[eax+0x30]
// mov eax,[eax+0x1d4]
//
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[229];
PVOID Reserved3[59];
ULONG SessionId;
} PEB, *PPEB;
//
// Instead of using the Tls fields, use the Win32 TLS APIs
// TlsAlloc, TlsGetValue, TlsSetValue, TlsFree
//
// Instead of using the ReservedForOle field, use the COM API
// CoGetContextToken
//
typedef struct _TEB {
BYTE Reserved1[1952];
PVOID Reserved2[412];
PVOID TlsSlots[64];
BYTE Reserved3[8];
PVOID Reserved4[26];
PVOID ReservedForOle; // Windows 2000 only
PVOID Reserved5[4];
PVOID TlsExpansionSlots;
} TEB;
typedef TEB *PTEB;
역시 MS......... PEB와 TEB의 구조를 다 Reserved로 바꿔놓았네요.
아래는 reserved를 없애고 실제 데이터가 의미하는 바를 나타낸 구조체 입니다.
필드들이 참 많죠; 이 중 Winternl.h에 등록되어 있는 것도 있다고 합니다만, platform sdk를 업그레이드 안해서인지 VS 2003에는 구조체들이 없더라구요.
어쨌건간에.. FS:[0x18]에 가보면 진짜로(?) TEB가 저장되어 있습니다. VC에서 TEB를 구하기 위해서는 다음과 같이 작성합니다
MFC로 코딩하다.. KillFocus 부분에서 OnCancel() 나 OnOK()를 호출하였는데, 이게 왠일! 오류가 나는게 아닌가? 그것도 내가 짠 코드가 아닌 wincore.cpp 에서..
// wincore.cpp 4530 line
// acquire and dispatch messages until the modal state is done for (;;)
{
ASSERT(ContinueModal()); // 여기서 오류가!
// phase1: check to see if we can do idle work
while (bIdle && !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal()); // show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
...
위에 주석으로 표시된 부분에서 ASSERT 오류가 났다. 왜? 왜? 왜? 그렇다면 ContinueModal()로 들어가보자.
결과적으로 WF_CONTINUEMODAL flag가 켜져 있지 않으면 오류가 난다 이거다. 이것도 문제가 생길때가 있고 안생길때가 있어서 사람을 미치게 만드는데.. 그럼 뭐가 문제일까? 결론부터 말하자면 dialog가 없어졌는데 (= 핸들이 해제되었는데) 메시지를 보내서 문제가 되는것이며, 이는 WM_KILLFOCUS같은 메시지가 처리되면서 dialog가 해제되어 발생하는 문제로 파악되어 진다. (SendMessage는 메시지를 바로 처리하는 함수이기 때문에) 해결책은? WM_KILLFOCUS안에서 PostMessage로 Dialog를 종료한다. 그러면 WM_KILLFOCUS가 모두 호출 된 뒤 message queue에서 종료메시지를 받게 된다. 즉,
void CYourDlg::OnKillfocus()
{
// OnClose나 OnOK 대신 PostMessage(WM_CLOSE);
}
VC에서 만든 DLL을 VB에서 사용할 때 애먹고 있으신 분들을 위해.. 참고로, 굳이 프로젝트 세팅에서 __stdcall 방식으로 바꿀 필요는 없다. 이렇게 하면 c 코드를 작성하는 모든 부분의 데이터를 이상하게 처리해야될지 모르므로 -ㅅ-;; 각 함수마다 __stdcall을 이용하면되는데..
예를 들면
int __stdcall a() {}
와 같이 함수 선언부에 __stdcall를 붙이면 이 함수만 __stdcall 규약을 따르게 될 수 있다.
P.S. 보통 Windows API들이 __stdcall을 따른다. 그 이유는, Windows에서 제공하는 API들은 VC, VB, Delphi 등등의 프로그램에서 사용되어야 하므로 표준 규약인 __stdcall을 지키는것이며, 그래서 VC에서 Windows API들이 선언된 것을 보면 WINAPI 라고 된 것을 볼 수 있다. 이 WINAPI는 PASCAL 형이며, PASCAL은 _pascal 의 별칭이다. (wtypes.h에 define 되어 있으며, pascal과 stdcall방식은 서로 같다. pascal방식은 caller가 stack을 삭제하는 것이다.) 이렇게 함으로써, 우리는 쥐도새도모르게(?) Windows에서 제공하는 API를 __stdcall이라는 키워드 없이 이용할 수 있는것이다.
Title Use VC++ to create a DLL file and use its functions in Visual Basic 6 Description
This example shows how to use VC++ to create a DLL file and use its functions in Visual Basic 6. Keywords VC++, VCC, DLL, C++ Categories Software Engineering
I have found 2 methods to do this. The first makes the VC++ easier and the Visual Basic messier. The second makes the VC++ harder and the Visual Basic easier.
Method 1: Easy VC++, Hard VB
VC++: Invoke New\Projects\Win32 Dynamic-Link Library. Enter the directory where you want the VC++ project and the project name (MyFuncsProject in the example).
VC++: Invoke New\Files\C++ Source File. Check the Add To Project box. Enter the file name (MyFuncs.cpp in the example).
VC++: Enter the function's source code. Use __declspec (note the two underscores) to export the function's symbol. Use 'extern "C"' to minimize name mangling by VC++.
// Define DllExport to declare exported symbols.
#define DllExport __declspec( dllexport )
// Prototype the function.
// Use 'extern "C"' to minimize name mangling.
extern "C" DllExport long MyCFunc(long x);
// Define the function.
extern "C" DllExport long MyCFunc(long x)
{
return x * x;
}
VC++: Set project options using Project\Settings. On the C/C++ tab, select the Code Generation category. Then change Calling Convention to __stdcall.
VC++: Select Build\Set Active Configuration. Select the Release configuration. Repeat step 4 to make the options apply to the release configuration in addition to the debug configuration. Use Build\Set Active Configuration to reselect the debug configuration if desired.
VC++: Build the project (press F7 or use the Build menu). This creates the DLL file.
VB: In your Visual Basic program, declare the DLL function using the DLL file's full path name. The function's name in the DLL file has been slightly mangled by VC++. The name is an underscore, followed by the name you gave it, followed by "@", followed by the number of bytes in the function's argument list. In this example the name is _MyCFunc@4 because the function takes one 4 byte argument (a long integer).
Private Declare Function MyCFunc Lib "C:\VBHelper\VcDll\Method1\Release\MyFuncsProject.dll" Alias "_MyCFunc@4" (ByVal x As Long) As Long
Private Sub Command1_Click()
Dim x As Long
Dim y As Long
x = CInt(Text1.Text)
y = MyCFunc(x)
Label1.Caption = Str$(y)
End Sub
*** HINT: To quickly determine the mangled name of the function, find the DLL file in Windows Explorer. Right click on the file and select the "Quick View" command. This presents an editor showing information about the DLL. Page down 2 or 3 pages and you will find a list of exported symbols available in the DLL. One of these will be the mangled function name.
Method 2, Hard VC++, Easy VB Steps 1 through 5 are the same as in Method 1.
VC++: New\Text File. Check the Add To Project box. Enter the file name. Give it a .DEF extension (MyFuncs.def in the example).
VC++: Enter definition file information that tells VC++ to export the function with the mangled name using the name you want it to have. The following code makes the exported name MyCFunc equivalent to _MyCFunc@4.
EXPORTS
MyCFunc=_MyCFunc@4
VC++: Build the project (press F7 or use the Build menu). This creates the DLL file. *** HINT: Use Quick View to verify the exported names. Find the DLL file in Windows Explorer. Right click on the file and select the "Quick View" command. Page down 2 or 3 pages and you will find a list of exported symbols available in the DLL. This includes both the mangled name and the name you specified in the .DEF file.
VB: In your Visual Basic program, declare the DLL function using the DLL file's full path name. Use the name you placed in the .DEF file not the mangled name.
Private Declare Function MyCFunc Lib "C:\VBHelper\VcDll\Method2\Release\MyFuncsProject.dll" (ByVal x As Long) As Long
Private Sub Command1_Click()
Dim x As Long
Dim y As Long
x = CInt(Text1.Text)
y = MyCFunc(x)
Label1.Caption = Str$(y)
End Sub
일반적으로 우리가 사용하는 assert()는 runtime에서 사용할 수 있다. UPX 소스를 분석하던 중 독특한 define이 눈에 들어왔는데 그것은..
COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 248)
와 같은 구문이었다.
딱 봤을때 신기하다는 생각이 들지 않는가? compile하는 시점에서 assertion을 수행한다는 것 자체가 신기할 따름이었다. 그래서 그 define부분을 보고 분석 한 결과..
#define COMPILE_ASSERT(x) switch(0) case 1: case !(x): break;
#define COMPILE_ASSERT2(x) typedef int __acc_cta_t[1-!(x)];
와 같은 define문을 간추려 내었다. (UPX에서는 각 컴파일러의 버전에 맞게 되어 있지만 여기서는 생략한다) 즉, x를 조건식으로 본 뒤 switch에서 동일한 값의 case가 있을때 오류나는 원리를 이용하여 조건을 검사하는 것이다.
두번째는, 배열의 첨자는 0이 될 수 없다는 오류 메시지를 출력하는 컴파일러를 위해 있는 구문이며, 배열의 크기가 1-!(x), 즉 참일 경우에는 1-0 이 되지만 거짓일 경우에는 1-1이 되서, 결국 배열의 첨자가 0이라는 오류를 출력하게 하는 구문이다. 참고로 typedef는 여러번 겹쳐도 되기 때문에 문제가 되질 않는다.
장현준
2007/06/19 21:24
2007/06/19 21:24
이 글에는 아직 트랙백이 없고, 아직 댓글이 없고, c,
컴파일러,
테크닉,
프로그래밍 태그가 달려있으며, 2007/06/19 21:24에 작성되었습니다.
c와 php에서 포인터는 비슷하다. 하지만 가끔 헷갈리는 경우가 있는데.. 조심해야되는 경우가 있다. c처럼 생각하고 포인터를 썼다가는 큰일이 날지도 모른다는 생각에 정리해둔다. (고수들은 이미 다 알고 있는 사실일지도 모르지만 -ㅅ- 나같이 삽질하는 초보들을 위해 정리한다)
int *p;
int a;
a = 10;
p = &a;
*p = 5;
을 php코드로 짜면 다음과 같이 될 것이다.
$a = 10;
$p = &$a;
$p = 5;
하지만 다음은 어떨까?
int *p;
int *p2;
int a;
a = 10;
p = &a;
p2 = p;
*p2 = 5;
c에서는 a가 5로 바뀐다.
php에서는..
$a = 10;
$p = &$a;
$p2 = $p;
$p2 = 5;
라고 하면? c로 따지면 $p는 int*이지만, $p2는 int가 된다. 즉, $p2 = $p 하는 순간 p2 = *p; 와같은 식이 되어버리고 만다는것. 이걸을 방지하기 위해 $p2가 포인터 변수라는것을 알려주기 위해 다음과 같이 바꾼다.
$a = 10;
$p = &$a;
$p2 = &$p;
$p2 = 5;
$p앞에 &를 붙이면 $p2가 포인터 변수라는것을 알려주기 때문에 원하는 결과를 얻을 수 있다.
함수의 경우, 인자를 보내는쪽(?)이나 받는쪽에서 &를 붙이게 되면 자연스럽게 둘중 하나가 포인터 같이 사용될 수 있다. 예를들어
$a = 2;
myf(&$a);
function myf($b)
{
$b = 10;
}
와 같은 코드가 있다면 $a의 값이 10으로 바뀐다. 반대로
$a = 2;
myf($a);
function myf(&$b)
{
$b = 10;
}
라고 해도 마찬가지의 결과를 얻을 수 있다. 물론 둘다 &라고 해도 정상적으로 된다.
장현준
2007/06/09 11:53
2007/06/09 11:53
이 글에는 아직 트랙백이 없고, 아직 댓글이 없고, php,
pointer,
프로그래밍 태그가 달려있으며, 2007/06/09 11:53에 작성되었습니다.