'빌트인'에 해당되는 글 1건

  1. 2011.07.05 [Hack #22] GCC 확장기능 (빌트인, 애트리뷰트, 레이블)
2011. 7. 5. 17:57

[ 빌트인 함수 ]

♧ gcc에는 표준 라이브러리에 있을 듯한 몇몇 함수가 빌트인 함수로 마련되어 있음.

최적화 방법에 따라 소스에 쓰인 것과 다른 코드를 생성할 경우 있다.

   

▷ 예를 들면 printf(3) 함수의 경우 다음과 같이 문자열을 출력하는 코드에서는 실행할 때

pirntf(3)의 형식 문자열을 해석할 수 없으므로 다음과 같이 puts(3)를 호출하는 코드를 생성.

▷ 기본적으로는 같은 동작을 하고 더 빠르게 실행될 듯한 코드가 생성되어 문제는 없으나,

LD_PRELOAD 등으로 오버라이드(override)해서 동작을 변경하고자 할 경우에는 주의 할

필요가 있다. 최적화를 통해 어떤 코드가 생성되는지 gcc/builtins.c에 프로그램 되어 있다.

   

void *__builtin_return_address (unsigned int LEVEL)

→ 함수의 리턴 주소, 즉 함수를 호출한 지점의 주소를 반환.

매개변수 LEVEL은 호출 지점을 몇 번 거슬러 올라갈지를 정수로 지정하는데

통상 0(현재 함수)을 지정. 일반적으로 x86인 경우 %ebp + 4에 해당하는 포인터 값이 됨

   

void *__builtin_frame_address (unsigned int LEVEL)

→ 함수의 프레임 포인터(지역 변수나 레지스터 저장영역을 가리키는 포인터)를 반환.

매개변수 LEVEL은 호출 지점을 몇 번 거술러 올라갈지를 정수로 지정하는데

통상 0(현재 함수)을 지정. 일반적으로 X86인 경우 %ebp 가 된다.

   

int __builtin_types_compatible_p (TYPE1, TYPE2)

→ 매개변수 TYPE1과 TYPE2가 서로 호환성이 있는지를 검사.

일반적으로 매크로를 이용해 타입에 맞는 적당한 함수로 dispatch할 때 사용.

   

TYPE __builtin_choose_expr (CONST _EXP, EXP1, EXP2)

→ 이 함수는 CONST_EXT? EXT1 : EXT2와 동일한 기능을 하지만, 컴파일할 때 결정.

__builtin_types_compatible_p를 매개변수 CONST _EXP로 사용해서 적당한 함수호출을

선택하는 형태의 매크로를 작성할 때 사용.

   

int __builtin_constant_p (EXP)

→ 매개변수 EXP가 정수인지를 판정.

인수가 정수임을 알았을 때 최적화된 코드를 선택하는 편이 더 좋을 경우에 사용.

   

long __builtin_expect (long EXP, long C)

→ 매개변수 EXP의 값이 매개변수 C값이 될 경우가 많을 것이라는 판단의 근거로,

분기를 최적화하고자 할 경우에 사용.

   

long __builtin_prefetch (const void *ADDR, int RW, int LOCALITY)

→ 매개변수 ADDR에 있는 데이터를 캐시에 prefetch하고자 할 경우 사용한다.

매개변수 RW가 1일 경우는 가까운 곳에 기록할 내용이 있음을,

0일 경우는 가까운 곳에 읽어야 할 내용이 있음을 나타낸다.

매개변수 LOCALITY는 0~3사이 값으로 0은 사용하면 바로 불필요한 데이터,

3은 사용하기 시작하면 당분간 계속 사용할 데이터임을 나타냄.

  

   

[ 애트리뷰트 (__attribute__) ]

♧ 함수에 애트리뷰트를 덧붙여 선언하면

함수에 특별한 의미를 부여하거나 함수호출을 최적화 할 수 있다.

   

▶ 애트리뷰트 선언 2가지 방법

① int foo(int n) __attribute__((애트리뷰트));

int foo(int n) { … }

   

② __attribute__((애트리뷰트)) int foo(int n) { … }

   

▶ 함수에 관한 애트리뷰트에는 다음과 같은 것들이 있다.

attribute

설명

constructor

main 함수가 호출되기 전이나 공유 오브젝트가 로드 되었을 때

실행해야 하는 함수에 사용.

destructor

exit하기 전이나 공유 오브젝트가 언로드 되기 직전에

실행해야 하는 함수에 사용.

cleanup

auto 변수가 주어진 영역에서 벗어나 없어질 때 호출되는 함수를 지정.

section

특정 섹션에 코드를 배치.

used

어디에서도 호출하지 않는 경우에도 코드를 반드시 생성.

어셈블러 코드에서 호출되는 경우에 사용.

weak

weak 심볼인 코드를 생성

alias

다른 심볼의 별칭(앨리어스)을 지정. 통상 weak와 함께 사용

visibility

심볼의 가시성을 제어하기 위해 사용.

'default', 'hidden' (공유 객체 밖에서는 볼 수 없음),

'protected'(공유 객체 내에서 호출할 때는 LD_PRELOAD로도

오버라이드 되지 않음) , 'initernal' (함수 포인터 등을 포함한 객체

외부에서의 호출을 수행하지 않음) 등...

stdcall

x86 호출 규약 중 하나.

매개변수에 사용한 스택을 호출된 쪽에서 pop하는 경우 사용.

sdecl

x86 호출 규약 중 하나.

매개변수에 사용한 스택을 호출한 쪽에서 pop하는 경우 사용.

fastcall

x86 호출 규약 중 하나. 처음 두 매개변수를 %ecx, %edx를 이용해 호출

regparm

레지스터에 전달할 매개변수의 개수를 제어.

vector_size

변수의 벡터 크기를 지정.

dllimport

MS 윈도우의 dllimport.

dllexport

MS 윈도우의 dllexport

pure

전역 변수와 매개변수에 따라서만 반환 값이 결정되고 부작용이 없는 경우에

사용된다. 경우에 따라서는 불필요한 호출을 생략할 경우가 있다.

const

매개변수만으로 반환 값이 결정되고 부작용이 없는 경우에 사용.

malloc

NULL 외의 반환 값이 다른 포인터와 공유되지 않은 경우에 사용.

noreturn

exit(2)와 같이 반환되지 않는 함수에 사용.

noinline

인라인 전개되기를 원하지 않는 경우에 사용.

always_inline

최적화 레벨이 낮아도 인라인 전개한다.

nothrow

예외를 throw 하지 않는 경우 사용.

format

형식 문자열이 printf, scanf, strftime, strfmon 중

어떤 스타일과 같은지를 가리키는 것으로,

형식 문자열과 가변 매개변수 간 대응을 검사하게 된다.

format_arg

어떤 매개변수가 형식 문자열인지를 가리킨다.

nonnull

NULL이 될 수 없는 포인터 매개변수를 가리킨다.

unused

사용하지 않을 경우에도 경고를 출력하지 않는다.

deprecated

사용될 경우에 경고를 출력.

warn_unused_result

반환 값을 검사하지 않을 때 경고를 출력.

no_instrument_function

-finstrument-functions인 경우에도

프로파일 함수를 호출하지 않도록 한다.

데이터에 관한 애트리뷰트 

aligned

변수 영역의 정렬을 제어.

packed

구조체 내부에 정렬에 의한 채우기(padding)를 최소화 한다.

common

변수를 common 영역에 배치.

nocommon

변수를 common 영역에 배치하지 않는다.

shared

DLL을 사용한 프로세스 전체로 공유된 매개변수에 사용.

  

   

   

[ 레이블(label) 참조 ]

♧ C에서는 그다지 사용되지 않지만 goto로 점프할 위치를 지정할 때 레이블을 사용.

goto error

……

error:

/* 에러 처리 */

   

▷ GCC에서 레이블은 &&로 참조하고 void *형 함수에 대입할 수 있다.

void * label;

label = &&error;

……

goto *label;

……

error:

이와 같이 레이블을 변수에 대입할 수 있기 때문에 변수 값에 따라 점프할 위치를 변경하도록

하는 코드는 레이블로의 참조를 요소로 갖는 배열로도 구현할 수 있다.

레이블을 &&로 참조한 값은 void *에 대입할 수 있는 포인터형이므로 뺄셈으로 오프셋을

얻을 수 있다. 따라서 다음과 같은 코드를 작성할 수 있다.

static int labals[] = { &&labal0 - &&label0, &&label1 - &&label0, ...};

goto * (&&labal0 + labels[ i]);


label0:

label1:

  

   

[ 정리 ]

GCC는 C99표준에 준거하도록 노력하는 한편, 소스코드를 기술하기 쉽도록 하기 위한

확장 기능을 제공하고 있다. GCC의 확장기능임을 이해한 후 이 기능을 사용하면 편리한

경우가 있다. 예를 들면 리눅스 커널에는 GCC확장 기능을 이용한 코드를 볼 수 있다.

이러한 코드를 파악하려 할 경우에는 GCC 확장기능에 대한 이해가 필수적이다.

Posted by devanix