'CS/Common'에 해당되는 글 8건

  1. 2011.05.25 특권 레벨 (Privilege ring level)
  2. 2010.01.20 Copy propagation
  3. 2010.01.08 Semaphore 이용환 Download 완료 확인
  4. 2010.01.08 식사하는 철학자 동기화
  5. 2010.01.08 Reader / Writer 동기화
  6. 2009.09.11 Google 친구들의 goto 피하기
  7. 2009.09.11 ASCII CODE 표
  8. 2009.04.10 Calling Convention (VS)

특권 레벨 (Privilege ring level)

CS/Common 2011. 5. 25. 14:19
원문 : Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3A

권한 레벨은 세그먼트 디스크립터의 세그먼트 셀렉터가 세그먼트 레지스터로 로드될 때 체크된다.

CPL (Current Privilege Level)
: 현재 실행되고 있는 태스크의 특권 레벨로, CS, SS 세그먼트 레지스터 0, 1 번째 비트.
: 일반적으로 CPL은 명령어가 페치되는 코드 세그먼트의 특권 레벨과 동일하다. 
: 프로세서는 프로그램 컨트롤이 다른 권한 레벨을 가진 코드 세그먼트로 전이될 때 CPL을 변경한다.
: CPL은 conforming 코드 세그먼트에 접근할 때 약간 다르게 취급된다. Confirming 코드 세그먼트는 confirming 코드의 DPL보다 같거나 더 작은 권한(숫자적으로 높은)을 가진 어떤 다른 권한 레벨에서 접근될 수 있다.
: CPL은 프로세서가 CPL과 다른 권한 레벨을 가진 conforming 코드 세그먼트에 접근할 때 변경되지 않는다. 


DPL (Descriptor Privilege Level)
: 세그먼트나 게이트 디스크립터가 포함하고 있는 필드.
: 세그먼트나 게이트의 특권레벨.
: 현재 실행되고 있는 코드가 세그먼트나 게이트에 접근하려고 할 때, 세그먼트나 게이트의 DPL은 CPL과 세그먼트가 게이트의 RPL과 비교된다.
: DPL은 세그먼트나 게이트가 엑세스되고 있는 타입에 따라 다르게 해석된다.
  • Data segment - DPL은 프로그램이나 태스크가 세그먼트에 엑세스를 허용해야만 하는 가장 낮은 권한 레벨(숫자상으로 가장 높은)을 가리킨다. 예를 들어, 만약 데이터 세그먼트의 DPL이 1이라면, 0이나 1의 CPL에서 동작하고 있는 프로그램만이 세그먼트에 엑세스 할 수 있다.
  • Nonconforming code segment (without using call gate) - DPL은 프로그램이나 태스크가 세그먼트에 엑세스하기 위해 가져야 하는 권한 레벨을 가리킨다. 예를 들어 만약 nonconforming 코드 세그먼트의 DPL이 0이라면 CPL 0에서 수행되는 프로그램만이 이 세그먼트에 엑세스 할 수 있다.
  • Call gate - DPL은 현재 수행되고 있는 프로그램이나 태스크가 될 수 있고 여전히 콜 게이트에 접근할 수 있는 가장 낮은 레벨(숫자상으로 가장 높은)을 가리킨다. (data segment와 같은 규칙)
  • Conforming code segment and nonconforming code segment accessed through a call gate - DPL은 프로그램이나 태스크가 세그먼트에 엑세스를 허용해야만 하는 가장 높은 레벨(숫자상으로 가장 낮은)을 가리킨다. 예를 들어, 만약 conforming 코드 세그먼트의 DPL이 2 이고, 프로그램이 0이나 1의 CPL에서 동작하고 있다면 세그먼트에 엑세스 할 수 없다.
  • TSS - DPL은 현재 실행되고 있는 프로그램이나 태스크가 될 수 있거나 여전히 TSS에 접근 할 수 있는 가장 낮은 권한 레벨(숫자상으로 가장 높은)을 가리킨다. (data segment와 같은 규칙)
RPL (Requested Privilege Level)
: 세그먼트 셀렉터의 0, 1 번째 비트.
: 세그먼트 셀렉터에 할당된 override된 권한 레벨이다.
: 프로세서는 세그먼트의 접근이 허용되는지 판단하기 위해 CPL과 함께 RPL을 체크한다. 
: 비록 세그먼트의 접근을 요청하는 프로그램이나 태스크가 세그먼트에 접근하기 위한 충분한 권한을 가지고 있더라도, 만약 RPL이 충분한 권한 레벨을 가지고 있지 않다면, 접근은 거부된다. 즉, 세그먼트 셀렉터의 RPL이 CPL보다 낮은 권한 레벨(숫자상으로 높은)인 경우, RPL은 CPL을 override 한다. (반대도 마찬가지이다.)
: 5.10.4 Checking Caller Access Privileges (ARPL Instruction) 참고
: RPL은 만약 프로그램 자체가 세그먼트에 대한 엑세스 권한을 가지고 있지 않다면 에플리케이션 프로그램 대신에 권한 코드(privileged code)가 세그먼트에 접근하지 않는 것을 보장하기 위해 사용된다.


발번역 주의. 이놈의 영어... ㅜㅜ 







:

Copy propagation

CS/Common 2010. 1. 20. 10:45
원문 : Wiki

In compiler theory, copy propagation is the process of replacing the occurrences of targets of direct assignments with their values. A direct assignment is an instruction of the form y = x, which simply assigns the value of x to y.

From the following code:

y = x
z = 3 + y

Copy propagation would yield:

z = 3 + x

Copy propagation often makes use of reaching definitions, use-def chains and def-use chains when computing which occurrences of the target may be safely replaced. If all upwards exposed uses of the target may be safely modified, the assignment operation may be eliminated.

Copy propagation is a useful "clean up" optimization frequently used after other optimizations have already been run. Some optimizations require that copy propagation be run afterward in order to achieve an increase in efficiency.
:

Semaphore 이용환 Download 완료 확인

CS/Common 2010. 1. 8. 07:10
원문 : Stanford iTunesU Programming Paradigm 17강

int DownloadSingleFile(const char* server, const char* path);
int DownloadAllFiles(const char* server, const char* files[], int n)
{
	int totalBytes = 0;

	Semaphore lock = 1;
	Semaphore childrenDone = 0;

	for (int i=0; i < n; ++i)
	{
		ThreadNew("DownloadSingleFile", DownloadSingleFile, 4, server, files[i], &
		totalBytes, lock, childrenDone);
	}
	for (int i=0; i < n; ++i)
	{
		// wait return.
		SemaphoreWait(childrenDone);
	}

	return totalBytes;
}

void DownloadHelper(const char* server, const char* path, 
	int* returnButes, Semaphore lock, Semaphore parentToSignal)
{
	int bytesDownloaded = DownloadSingleFile(server, path);
	SemaphoreWait(lock);
	*numBytes += bytesDownloaded;
	SemaphoreSignal(lock);
	SemaphoreSignal(parentToSignal);
}
:

식사하는 철학자 동기화

CS/Common 2010. 1. 8. 06:48
원문 : Stanford iTunesU Programming Paradigm 17강

Semaphore forks[5] = {1, 1, 1, 1, 1}
Semaphore numAllowedToEat(4); // 최소한 한명은 Idle. DeadLock 피함.

void Philosopher(int id)
{
	for (int i=0; i < 3; ++i) 
	{
		Think();
		SemaphoreWait( numAllowedToEat );
		SemaphoreWait( forks[ id ] );
		SemaphoreWait( forks[ (i+1)%5 ] );
		Eat();
		SemaphoreSignal( forks[ id ] );
		SemaphoreSignal( forks[ (id+1)%5 ] );
		SemaphoreSignal( numAllowedToEat );
	}
}

학부때 OS 시간에는 뭔가 엄청 복잡하고 어려웠는데... 왜이렇게 간단하지...? ;;;
:

Reader / Writer 동기화

CS/Common 2010. 1. 8. 05:45
원문 : Stanford iTunesU Programming Paradigm 16강

버퍼에서 Read 전에 Write 금지.
Write 되지 않은 버퍼 Read 하지 않기.
char buffer[8];
Semaphore emptyBuffers(8);
Semaphore fullBuffers(0);

int main()
{
	ThreadNew("Writer", Writer, 0);
	ThreadNew("Reader", Reader, 0);
	RunAllThread();
}

void Writer()
{
	for (int i=0; i < 40; ++i)
	{
		char c = PrepareRandomChar();
		SemaphoreWait(emptyBuffers);
		buffer[ i%f ] = c;
		SemaphoreSignal(fullBuffers);
	}
}

void Reader()
{
	for (int i=0; i < 40; ++i)
	{
		SemaphoreWait(fullBuffers);
		char c = buffer[ i%f ];
		ProcessChar(c);
		SemaphoreSignal(emptyBuffers);
	}
}
:

Google 친구들의 goto 피하기

CS/Common 2009. 9. 11. 15:53
Google 친구 아저씨들이 짠 코드를 보면 가끔 이런 형식이 보인다.
do
{
	result = false;

	...

	if ( result = foo() )
		break;
	...

	if ( result = bar() )
		break;
	
	...
} while (0);

if (false == result)
{
	...
}

foo()나 bar()에서 실패시 이후의 코드를 처리하지 않기 위함인데,

결국은 리눅스 커널의 네트워크 관련 코드의 다음과 같은 일을 한다.
if ( result = foo() )
	goto FAILED;

...

if ( result = basr() )	
	goto FAILED;

...

FAILED :
	...

결국 goto를 사용하지 않고, do-while(0) 을 이용하여 break를 사용해서 분기를 제어한 것인데,
나는 커널 코드에 익숙해져 있어서 인지, goto가 더 명시적이고 좋아 보인다.
또한 do-while(0)과 break를 이용한 방법은 그 안에 loop가 없는 경우만 사용할 수 있는 단점도 있다.

하지만,
if (  )
{
	if (  )
	{
		if (  )
		{
			if (  )
			{
				...
			}
		}
	}
}

요렇게 된 코드를
do {
	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}
} while(0);

요렇게 쓸 수 있다는 점에서는 참 매력적인 방법이다.

첨에 이 코드를 봤을때는 그냥 그렇구나 하고 지나갔었다.
그런데 우연히 미팅 시간에 팀원들과 이 코드에 대해서 얘기를 하게 되었는데, 사람들이 좋은 방법이다... 라고 대부분 얘기 하길래 포스팅 까지... 역시 셀로판귀... 팔락팔락... orz
:

ASCII CODE 표

CS/Common 2009. 9. 11. 13:08
은근히 필요할 때가 많네...

:

Calling Convention (VS)

CS/Common 2009. 4. 10. 22:02
. 모든 calling convention에서 모든 Arguments는 함수로 전달될 32비트로 확장되며 리턴 값 또한 32비트로 확장되며, EAX에 리턴된다. 단, 8-byte 구조체에 대해서는 EDX:EAX 레지스터 쌍에 리턴된다.

. 더 큰 구조체는 리턴 구조체를 숨기기 위해서 EAX레지스터에 포인터로서 리턴된다.

. Parameter는 스택에 오른쪽에서 왼쪽으로 push 된다. 
(Structures that are not PODs will not be returned in registers.)

.만약 ESI, EDI, EBX, EBP 레지스터가 함수 내부에서 사용된다면, 컴파일러는 이들을 restore하고 save하기 위해서 prolog와 epilog 코드를 생성한다.



__cdecl 
Stack Cleanup : Caller
인자 전달 : 스택에 Parameters를 reverse order로 Push한다. (RIGHT to LEFT)

C/C++ 에서의 기본 Calling convention이다.
스택이 Caller에 의해서 cleanup 되기 때문에 가변인자 함수를 사용할 수 있다.
각 함수를 호출할 때마다 cleanup 코드를 포함하애 하기 때문에 __stdcall보다 큰 실행 파일을 생성한다.
__cdecl 변경자는 함수 이름이나 variable 전에 위치시킨다.
__cdecl을 강제하기 위해서는 /Gd 컴파일러 옵션을 지정한다.
/Gz(stdcall), /Gr(fastcall) 컴파일러 옵션을 지정했을 경우만 __cdecl을 필요로 한다.

// Example of the __cdecl keyword on function

int __cdecl system(const char *);

 

// Example of the __cdecl keyword on function pointer

typedef BOOL (__cdecl *funcname_ptr)(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  push        2   

004118F9  push        1   

004118FB  call        foo (411118h)

00411900  add         esp,10h

 

 

int __cdecl foo(int a, int b, int c, int d) {

00411840  push        ebp 

00411841  mov         ebp,esp

00411843  sub         esp,0CCh

00411849  push        ebx 

0041184A  push        esi 

0041184B  push        edi 

0041184C  lea         edi,[ebp-0CCh]

00411852  mov         ecx,33h

00411857  mov         eax,0CCCCCCCCh

0041185C  rep stos    dword ptr es:[edi]

    int x = a+b+c+d;

0041185E  mov         eax,dword ptr [a]

00411861  add         eax,dword ptr [b]

00411864  add         eax,dword ptr [c]

00411867  add         eax,dword ptr [d]

0041186A  mov         dword ptr [x],eax

    return x;

0041186D  mov         eax,dword ptr [x]

00411870  pop         edi 

00411871  pop         esi 

00411872  pop         ebx 

00411873  mov         esp,ebp

00411875  pop         ebp 

00411876  ret

}




__stdcall
Stack Cleanup : Callee
인자 전달 : 스택에 Parameters를 reverse order로 Push한다.(RIGHT TO LEFT)

Win32 API를 호출하기 위해 사용된다. 
#define CALLBACK __stdcall #define WINAPI __stdcall #define WINAPIV __cdecl #define APIENTRY WINAPI

__stdcall을 강제하기 위해서는 /Gz 컴파일러 옵션을 지정한다.
__cdecl로 선언된 함수와 같은 방법으로 values를 리턴한다.

// Example of the __stdcall keyword

#define WINAPI __stdcall

 

// Example of the __stdcall keyword on function pointer

typedef BOOL (__stdcall *funcname_ptr)

(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  push        2   

004118F9  push        1   

004118FB  call        foo (411249h)

 

 

int __stdcall foo(int a, int b, int c, int d) {

00411840  push        ebp 

00411841  mov         ebp,esp

00411843  sub         esp,0CCh

00411849  push        ebx 

0041184A  push        esi 

0041184B  push        edi 

0041184C  lea         edi,[ebp-0CCh]

00411852  mov         ecx,33h

00411857  mov         eax,0CCCCCCCCh

0041185C  rep stos    dword ptr es:[edi]

    int x = a+b+c+d;

0041185E  mov         eax,dword ptr [a]

00411861  add         eax,dword ptr [b]

00411864  add         eax,dword ptr [c]

00411867  add         eax,dword ptr [d]

0041186A  mov         dword ptr [x],eax

    return x;

0041186D  mov         eax,dword ptr [x]

00411870  pop         edi 

00411871  pop         esi 

00411872  pop         ebx 

00411873  mov         esp,ebp

00411875  pop         ebp 

00411876  ret         10h

}




__fastcall
Stack Cleanup : Callee
인자 전달 : Stored in registers, then pushed on stack

가능하다면 arguments가 함수에 레지스터를 통하여 전달된다.
이후의 컴파일러는 parameters를 저장하기 위해 다른 register를 사용할 수도 있다.
__fastcall을 강제하기 위해서는 /Gr 컴파일러 옵션을 지정한다.

// Example of the __fastcall keyword

#define FASTCALL    __fastcall

 

void FASTCALL DeleteAggrWrapper(void* pWrapper);

// Example of the __ fastcall keyword on function pointer

typedef BOOL (__fastcall *funcname_ptr)

(void * arg1, const char * arg2, DWORD flags, ...);

foo(1, 2, 3, 4);

004118F3  push        4   

004118F5  push        3   

004118F7  mov         edx,2

004118FC  mov         ecx,1

00411901  call        foo (41124Eh)

 

 

int __fastcall foo(int a, int b, int c, int d) {

004115D0  push        ebp 

004115D1  mov         ebp,esp

004115D3  sub         esp,0E4h

004115D9  push        ebx 

004115DA  push        esi 

004115DB  push        edi 

004115DC  push        ecx 

004115DD  lea         edi,[ebp-0E4h]

004115E3  mov         ecx,39h

004115E8  mov         eax,0CCCCCCCCh

004115ED  rep stos    dword ptr es:[edi]

004115EF  pop         ecx 

004115F0  mov         dword ptr [ebp-14h],edx

004115F3  mov         dword ptr [ebp-8],ecx

    int x = a+b+c+d;

004115F6  mov         eax,dword ptr [a]

004115F9  add         eax,dword ptr [b]

004115FC  add         eax,dword ptr [c]

004115FF  add         eax,dword ptr [d]

00411602  mov         dword ptr [x],eax

    return x;

00411605  mov         eax,dword ptr [x]

00411608  pop         edi 

00411609  pop         esi 

0041160A  pop         ebx 

0041160B  mov         esp,ebp

0041160D  pop         ebp 

0041160E  ret         8

}




__thiscall
Stack Cleanup : Callee
인자 전달 : Pushed on stack; this pointer stored in ECX



__clrcall
Stack Cleanup : n/a
인자 전달 : Parameters를 CLR expression stacke에 order로 Load한다.(left to right).


예전에 사용하던 블로그에 있던 글인데, 정리할 겸 다시 정리했다. 이놈의 calling convention은 왜 자꾸 까먹는건지.. ㅜㅜ

출처 : MSDN, 나의 옛 블로그
: