GCC の __atribute__ キーワード

書籍「C/C++セキュアコーディング」を読んでたら書いてあったので, テスト.
GCC依存(だよね?).
詳細は, GCCのinfoを読むしかないのかな.



関数は, before, main, afterの順で実行されるハズ.

#include<stdio.h>

void before( void ) __attribute__ ((constructor));
void after( void  ) __attribute__ ((destructor));


int main( int argc, char *argv[] )
{
  puts( "main" );

  return 0;
}


void before( void ){
  puts( "before" );
}

void after( void ){
  puts( "after" );
}

このプログラムを, コンパイル, そして, 実行

[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute1
before
main
after

ちゃんと予定通りの動作をしました.


GCCでは, 関数に属性を指定することができる.
やり方は, __attribute__キーワードにつづいて, 二重の丸括弧で囲んで属性名を指定する.
今回指定したものは, constructor と destructor.
constructorは, mainの実行前に.
descructorは, mainの処理後, もしくは, exit が呼ばれた後に実行される.



constructor や destructor を指定した関数が複数あるとどうなるか実験.

#include<stdio.h>

void before1( void ) __attribute__ ((constructor));
void before2( void ) __attribute__ ((constructor));
void after1( void  ) __attribute__ ((destructor));
void after2( void  ) __attribute__ ((destructor));


int main( int argc, char *argv[] )
{
  puts( "main" );

  return 0;
}


void before1( void ){
  puts( "before1" );
}

void before2( void ){
  puts( "before2" );
}

void after1( void ){
  puts( "after1" );
}

void after2( void ){
  puts( "after2" );
}

こんなつまんない例を作ってみた.
以下, コンパイルと実行.

[khiker@khlin001 ~/<1>c/gcc]$ gcc test_attribute2.c -o test_attribute2 -Wall
[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute2
before2
before1
main
after1
after2
[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute2
before2
before1
main
after1
after2
[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute2
before2
before1
main
after1
after2

何度やっても同じ順序で実行されるということは, 何かルールがあるのかな.


日本語版のinfoを簡単に(ホント簡単に)読んでみたけど, 特に書いてないようだから, さらに実験.
宣言の順番を変えてみる.
これを,

void before1( void ) __attribute__ ((constructor));
void before2( void ) __attribute__ ((constructor));
void after1( void  ) __attribute__ ((destructor));
void after2( void  ) __attribute__ ((destructor));

こうする.

void before2( void ) __attribute__ ((constructor));
void before1( void ) __attribute__ ((constructor));
void after2( void  ) __attribute__ ((destructor));
void after1( void  ) __attribute__ ((destructor));

結果.

[khiker@khlin001 ~/<1>c/gcc]$ gcc test_attribute2.c -o test_attribute2 -Wall
[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute2
before2
before1
main
after1
after2

変化なし.



じゃあ, 関数実装部分の順番を変えてみようかな.
これを,

void before1( void ){
  puts( "before1" );
}

void before2( void ){
  puts( "before2" );
}

void after1( void ){
  puts( "after1" );
}

void after2( void ){
  puts( "after2" );
}

こうする.

void before2( void ){
  puts( "before2" );
}

void before1( void ){
  puts( "before1" );
}

void after2( void ){
  puts( "after2" );
}

void after1( void ){
  puts( "after1" );
}

結果.

[khiker@khlin001 ~/<1>c/gcc]$ gcc test_attribute2.c -o test_attribute2 -Wall
[khiker@khlin001 ~/<1>c/gcc]$ ./test_attribute2
before1
before2
main
after2
after1

見事に変化.
constructorは, 上から順番にスタックに積んでその順に実行してるってことなのかな.
before2, before1と積む. before2が下. よって, before1から.
んで, destructorは, キューってこと?
よく分からん. 3個以上は, 実験してないからどうなるか分かんないし.
まあ, 通常は, 2つ以上 constructor や destructor 属性を宣言すべきじゃないよね.
混乱するし.


これは, 終了時にメッセージだしたりとか,
結構色々と使えそうな気がする.
良さそう.
他のキーワードもまた調べてみるか.