コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2022年4月15日 >>> 2022年4月2日
link もっと後

2022年4月15日

glibcのスレッドローカルストレージ - 変数宣言編

目次: C言語とlibc

スレッドごとに独立したデータを保持する空間をTLS(Thread Local Storage)といいます。日本語だと「スレッド局所記憶」というそうです。TLSへのアクセス方法、TLSの初期化方法などはアーキテクチャ依存ですので、今回はglibcのRISC-V版の実装を観察します。

スレッドローカル変数の宣言

変数宣言は __libc_tsd_define() マクロを使います。例として文字処理に使われるctype関連の変数を見ます。

ctype関連のスレッドローカル変数宣言

// glibc/ctype/ctype-info.c

__libc_tsd_define (, const uint16_t *, CTYPE_B)
__libc_tsd_define (, const int32_t *, CTYPE_TOLOWER)
__libc_tsd_define (, const int32_t *, CTYPE_TOUPPER)


// glibc/sysdeps/generic/libc-tsd.h

#define __libc_tsd_define(CLASS, TYPE, KEY)	\
  CLASS __thread TYPE __libc_tsd_##KEY attribute_tls_model_ie;


// glibc/include/libc-symbols.h

#define attribute_tls_model_ie __attribute__ ((tls_model ("initial-exec")))

マクロは下記のように展開されます。

スレッドローカル変数宣言マクロの展開例

// glibc/ctype/ctype-info.c

__libc_tsd_define (, const uint16_t *, CTYPE_B)
↓
__thread const uint16_t * __libc_tsd_CTYPE_B __attribute__ ((tls_model ("initial-exec")));


// glibc/include/ctype.h

__libc_tsd_define (extern, const uint16_t *, CTYPE_B)
↓
extern __thread const uint16_t * __libc_tsd_CTYPE_B __attribute__ ((tls_model ("initial-exec")));

ごちゃごちゃして見えますが、普通の変数宣言との違いは__thread指定子とtls_model("initial-exec") 属性の2つです。

スレッドローカル変数の宣言、詳細

これだけだと「そうですか」で終わってしまうので、もう少し詳しく調べます。

  • __thread: スレッドローカル変数であることを示します。
  • tls_model("initial-exec"): スレッドローカル変数のモデル、実行可能ファイルから参照可能な変数とします。

スレッドローカル変数のモデルは、Common Variable Attributes - Using the GNU Compiler Collection (GCC) を見る限り4種類あるようです。

  • global-dynamic
  • local-dynamic
  • initial-exec
  • local-exec

それぞれの意味は悲しいことにGCCのマニュアルに書いていないのです。どうして……。参考になるマニュアルとしては、-ftls-model (-qtls) - XL C/C++ for Linux - IBM Documentation もしくは スレッド固有ストレージのアクセスモデル - Oracle Solaris 11.1リンカーとライブラリガイドがわかりやすいです。

global-dynamic
すべてのスレッドローカル変数を参照できます。
local-dynamic
共有ライブラリのスレッドローカル変数を参照できますが、モジュール外からの参照は不可能です。global-dynamicより速いとのこと。
initial-exec
実行可能ファイルから共有ライブラリのスレッドローカル変数を参照できますが、実行可能ファイルと同時にロードされている必要があります(dlopenでロードしたライブラリは不可)。local-dynamicより速いとのこと。
local-exec
実行可能ファイル内のスレッドローカル変数のみ参照できます。initial-execより速いとのこと。

Solarisのリンカーのモデル名はGCCと少し違いますが、一見して対応がわかる程度の差でしょう。

次回は変数のアドレス取得について見たいと思います。

編集者:すずき(2022/04/22 03:01)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月13日

C言語とlibc - まとめリンク

目次: C言語とlibc

C言語について。

Cライブラリ(libc)について。

編集者:すずき(2024/01/13 17:22)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月10日

glibcとAuxiliary Vector

目次: C言語とlibc

Linuxはプロセスの起動時に、引数や環境変数に加えてAuxiliary Vector(補助ベクタ−)というデータを渡します。ダンプするにはLD_SHOW_AUXVを定義してから起動すると良いです。

Auxiliary Vectorのダンプ
$ LD_SHOW_AUXV=1 /bin/echo

AT_SYSINFO_EHDR:      0x7ffec8bcc000
AT_??? (0x33): 0x6f0
AT_HWCAP:             178bfbff
AT_PAGESZ:            4096
AT_CLKTCK:            100
AT_PHDR:              0x5650e2ab4040
AT_PHENT:             56
AT_PHNUM:             11
AT_BASE:              0x7f5d30b65000
AT_FLAGS:             0x0
AT_ENTRY:             0x5650e2ab6980
AT_UID:               1000
AT_EUID:              1000
AT_GID:               1000
AT_EGID:              1000
AT_SECURE:            0
AT_RANDOM:            0x7ffec8bb3499
AT_HWCAP2:            0x2
AT_EXECFN:            /bin/echo
AT_PLATFORM:          x86_64

補助ベクターは基本的には存在するかしないか定かではなく任意です。が、どうもglibcはいくつかの補助ベクターの存在を前提としていて、存在しない場合は起動すらしないようです。

補助ベクターを調べる

補助ベクターを変更するスマートな方法がありそうですが、わかりませんでした。仕方ないのでデバッガを使って力尽くで書き換えます。まずはテストプログラムを書きます。mainに到達する前のことを扱うためプログラムの中身は何でも良いです。

テストプログラム

// a.c

#include <stdio.h>

int main(int argc, char *argv[], char *envp[])
{
	printf("hello\n");
	return 0;
}

実行してmainでブレークし、環境変数の配列envpをダンプします。envpの終端はNULLポインタですが、実はその先に補助ベクターが置かれています。

ビルド、envをダンプして補助ベクターの位置を調べる
$ gcc -Wall -g -O0 -static a.c

$ gdb a.out

...

(gdb) b main

Breakpoint 1 at 0x4017d8: file a.c, line 5.

(gdb) r

Starting program: /home/katsuhiro/share/a/a.out 

Breakpoint 1, main (argc=1, argv=0x7fffffffdcf8, env=0x7fffffffdd08) at a.c:5
5               printf("hello\n");

(gdb) x/32x envp

0x7fffffffdd08: 0xffffe039      0x00007fff      0xffffe049      0x00007fff
0x7fffffffdd18: 0xffffe05c      0x00007fff      0xffffe070      0x00007fff
0x7fffffffdd28: 0xffffe089      0x00007fff      0xffffe09f      0x00007fff
0x7fffffffdd38: 0xffffe0b3      0x00007fff      0xffffe495      0x00007fff
0x7fffffffdd48: 0xffffe4a9      0x00007fff      0xffffe4d8      0x00007fff
0x7fffffffdd58: 0xffffe503      0x00007fff      0xffffe50c      0x00007fff
0x7fffffffdd68: 0xffffe534      0x00007fff      0xffffe549      0x00007fff
0x7fffffffdd78: 0xffffe55e      0x00007fff      0xffffe571      0x00007fff

(...略...)

0x7fffffffde88: 0xffffefb1      0x00007fff      0x00000000      0x00000000    ★★envpの終端★★
0x7fffffffde98: 0x00000021      0x00000000      0xf7ffd000      0x00007fff    ★★補助ベクターの始まり★★

...

補助ベクターは下記のような構造です。

補助ベクターのデータ構造

typedef struct
{
  long int a_type;              /* Entry type */
  union
    {
      long int a_val;           /* Integer value */
      void *a_ptr;              /* Pointer value */
      void (*a_fcn) (void);     /* Function pointer value */
    } a_un;
} auxv_t;

簡単に言えばx86_64の場合8バイトのtypeと、8バイトのunionが並んでいるだけです。最初のデータ(アドレス0x7fffffffde98)を例に取るとtype = 0x21, data = 0x7fff_f7ff_d000です。わかりやすいですね。

補助ベクターを書き換える

デバッガから起動する場合はargv, envp, 補助ベクターのアドレスは常に同じです。そのため、

  • mainでブレーク
  • envpの後ろの補助ベクターのアドレスを調べる
  • 同じ実行ファイルを再実行
  • プロセス開始直後に実行される関数(_start)でブレーク
  • アドレスがわかっている補助ベクターをデバッガで書き換え

このような手順を取ってglibcが補助ベクターを見る前に補助ベクターの値を好きに変更できます。試しにglibcが起動時に参照していてNULLにすることが許されないAT_RANDOMを書き換えます。AT_RANDOMはtype = 0x19です。

AT_RANDOMを書き換える
(gdb) b _start

Breakpoint 2 at 0x4016a0

(gdb) r

The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/katsuhiro/share/a/a.out 

Breakpoint 2, 0x00000000004016a0 in _start ()

(gdb) x/32x 0x7fffffffde98

0x7fffffffde98: 0x00000021      0x00000000      0xf7ffd000      0x00007fff
0x7fffffffdea8: 0x00000033      0x00000000      0x000006f0      0x00000000

(...略...)

0x7fffffffdf98: 0x00000019      0x00000000      0xffffdfe9      0x00007fff    ★★書き換え対象AT_RANDOM★★
0x7fffffffdfa8: 0x0000001a      0x00000000      0x00000002      0x00000000
0x7fffffffdfb8: 0x0000001f      0x00000000      0xffffefce      0x00007fff
0x7fffffffdfc8: 0x0000000f      0x00000000      0xffffdff9      0x00007fff
0x7fffffffdfd8: 0x00000000      0x00000000      0x00000000      0x00000000    ★★補助ベクターの終端type = 0★★
0x7fffffffdfe8: 0xf8e1f900      0x056adb4e      0xb6df71ae      0x67d4fca2

...

(gdb) set *0x7fffffffdfa0=0
(gdb) set *0x7fffffffdfa4=0

(gdb) x/32x 0x7fffffffdf98

0x7fffffffdf98: 0x00000019      0x00000000      0x00000000      0x00000000    ★★NULLポインタに書き換えた★★
0x7fffffffdfa8: 0x0000001a      0x00000000      0x00000002      0x00000000
0x7fffffffdfb8: 0x0000001f      0x00000000      0xffffefce      0x00007fff

...

(gdb) c

Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00000000004032fd in __libc_start_main ()

実行を継続するとmainに到達することなくSEGVでクラッシュします。glibcは起動時にAT_RANDOMの指す配列を参照していて、アドレスをNULLポインタに書き換えたからです。glibcはLinux専用のlibcですから、AT_RANDOMが存在しない場合を考慮する必要はないとはいえ、なんか微妙な動作ですね……うーん。

編集者:すずき(2022/04/22 03:00)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月9日

glibcと最適化

目次: C言語とlibc

たまに最適化を無効にするとビルドできなくなるソフトウェアがあります。大抵はバグです。しかし何か目的があって、あえてやっている場合もあります。C言語標準ライブラリの実装で有名なglibcもその一つです。

最適化をわざと無効にしてglibcをビルドするとエラーが発生します。コードはglibc-2.35を使いました。

O2とO0でglibcをビルドした場合
$ cd glibc
$ mkdir _build
$ cd _build

$ ../configure CPPFLAGS="-O2 -g" --disable-sanity-checks
$ make

(成功する、ログは省略)

$ cd ../
$ rm -rf _build
$ mkdir _build
$ cd _build

$ ../configure CPPFLAGS="-O0 -g" --disable-sanity-checks
$ make

In file included from <command-line>:
./../include/libc-symbols.h:75:3: error: #error "glibc cannot be compiled without optimization"
   75 | # error "glibc cannot be compiled without optimization"
      |   ^~~~~

最適化を無効にするなと怒られました。コードを見ると__OPTIMIZE__ マクロの定義/未定義を見て検出していました。へえー。

最適化の有無を検出している場所

// glibc/include/libc-symbols.h

/* Some files must be compiled with optimization on.  */
#if !defined __ASSEMBLER__ && !defined __OPTIMIZE__
# error "glibc cannot be compiled without optimization"
#endif

このチェックをごまかして、最適化を有効にしつつも特定の最適化だけ無効にするとどうなるでしょう?

O2でインライン展開のみ無効にした場合
$ cd glibc
$ mkdir __build
$ cd __build

$ ../configure CPPFLAGS="-O2 -g -fno-inline" --disable-sanity-checks --disable-werror
$ make

(...略...)

gcc   -nostdlib -nostartfiles -r -o glibc/__build/elf/librtld.os '-Wl,-(' glibc/__build/elf/dl-allobjs.os glibc/__build/elf/rtld-libc.a -lgcc '-Wl,-)' \
          -Wl,-Map,glibc/__build/elf/librtld.os.map
gcc   -nostdlib -nostartfiles -shared -o glibc/__build/elf/ld.so.new         \
          -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both -Wl,-z,defs      \
          glibc/__build/elf/librtld.os -Wl,--version-script=glibc/__build/ld.map         \
          -Wl,-soname=ld-linux-x86-64.so.2                      \
          -Wl,-defsym=_begin=0
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `_dl_close_worker':
glibc/elf/dl-close.c:383: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/dl-close.c:689: undefined reference to `free'
/usr/bin/ld: glibc/elf/dl-close.c:691: undefined reference to `free'
/usr/bin/ld: glibc/elf/dl-close.c:693: undefined reference to `free'
/usr/bin/ld: glibc/elf/dl-close.c:701: undefined reference to `free'
/usr/bin/ld: glibc/elf/dl-close.c:710: undefined reference to `free'
/usr/bin/ld: glibc/__build/elf/librtld.os:glibc/elf/dl-close.c:715: more undefined references to `free' follow
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `_dl_map_object_deps':
glibc/elf/dl-deps.c:438: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/dl-deps.c:479: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/dl-deps.c:571: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/dl-deps.c:543: undefined reference to `malloc'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `_dl_error_free':
glibc/elf/dl-exception.c:41: undefined reference to `free'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `__GI__dl_exception_create':
glibc/elf/dl-exception.c:89: undefined reference to `malloc'

(...略...)

/usr/bin/ld: glibc/elf/../sysdeps/posix/getcwd.c:249: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/../sysdeps/posix/getcwd.c:493: undefined reference to `free'
/usr/bin/ld: glibc/elf/../sysdeps/posix/getcwd.c:469: undefined reference to `realloc'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `__alloc_dir':
glibc/elf/../sysdeps/unix/sysv/linux/opendir.c:115: undefined reference to `malloc'
/usr/bin/ld: glibc/elf/../sysdeps/unix/sysv/linux/opendir.c:115: undefined reference to `malloc'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `__closedir':
glibc/dirent/../sysdeps/unix/sysv/linux/closedir.c:50: undefined reference to `free'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `scratch_buffer_free':
glibc/malloc/../include/scratch_buffer.h:86: undefined reference to `free'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `__libc_scratch_buffer_set_array_size':
glibc/malloc/scratch_buffer_set_array_size.c:51: undefined reference to `malloc'
/usr/bin/ld: glibc/__build/elf/librtld.os: in function `__strdup':
glibc/string/strdup.c:42: undefined reference to `malloc'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:1234: glibc/__build/elf/ld.so] エラー1
make[2]: ディレクトリ 'glibc/elf' から出ます
make[1]: *** [Makefile:483: elf/subdir_lib] エラー2
make[1]: ディレクトリ 'glibc' から出ます
make: *** [Makefile:9: all] エラー2

リンク時に激しく怒られてしまいダメでした。小細工は効きませんね。

O2以外の最適化レベル

デバッグ時に見やすくするためにOgやO1といった最適化レベルを使うことは珍しくないと思いますが、glibcはOgやO1だとおかしなビルドエラーが発生します。

Ogでビルドするとエラー
$ ../configure CPPFLAGS="-Og -g" --disable-sanity-checks

(...略...)

canonicalize.c: In function ‘realpath_stk’:
canonicalize.c:424:50: error: ‘dest’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
  424 |   return scratch_buffer_dupfree (rname_buf, dest - rname);
      |                                             ~~~~~^~~~~~~
cc1: all warnings being treated as errors

警告がエラー扱いされただけなので、configureに --disable-werrorを渡して警告をエラーと見なさないようにするとビルドは成功します(実は前節でもしれっと使っていました)。

しかし良く考えるとO2では無警告なのにOgでは警告が出るとは?なかなか興味深い現象です。警告が出ているrealpath_stk() のコードを見ます。

realpath_stk() のコード

// glibc/stdlib/canonicalize.c

static char *
realpath_stk (const char *name, char *resolved,
              struct scratch_buffer *rname_buf)
{
  char *dest;
  char const *start;
  char const *end;
  int num_links = 0;

  //...

  struct scratch_buffer extra_buffer, link_buffer;
  scratch_buffer_init (&extra_buffer);
  scratch_buffer_init (&link_buffer);
  scratch_buffer_init (rname_buf);
  char *rname_on_stack = rname_buf->data;
  char *rname = rname_on_stack;
  bool end_in_extra_buffer = false;
  bool failed = true;

  /* This is always zero for Posix hosts, but can be 2 for MS-Windows
     and MS-DOS X:/foo/bar file names.  */
  idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);

  if (!IS_ABSOLUTE_FILE_NAME (name))    //★★この条件が成立、かつ★★
    {
      while (!__getcwd (rname, rname_buf->length))    //★★この条件が成立、かつ★★
        {
          if (errno != ERANGE)    //★★この条件が不成立、かつ★★
            {
              dest = rname;
              goto error;
            }
          if (!scratch_buffer_grow (rname_buf))    //★★この条件が成立した場合を考えると★★
            goto error_nomem;    //★★destが未定義のまま、このgotoに到達する★★
          rname = rname_buf->data;
        }
      dest = __rawmemchr (rname, '\0');
      start = name;
      prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
    }

  //...

error_nomem:
  scratch_buffer_free (&extra_buffer);
  scratch_buffer_free (&link_buffer);

  if (failed || rname == resolved)    //★★しかし、前半のfailed = trueの条件が必ず成立していて、未定義変数の使用は発生しない★★
    {
      scratch_buffer_free (rname_buf);
      return failed ? NULL : resolved;
    }

  return scratch_buffer_dupfree (rname_buf, dest - rname);    //★★ここで未定義変数の使用の警告が出る★★
}

コード上はdestが未定義のまま使われる可能性があるように見えますし、Ogの警告はもっともに思えます。しかしコードを良く見るとdestが未定義のままerror_nomemに来る場合、failed = trueが必ず成立して警告が出る行には到達しません。他にもgoto error_nomemする箇所はありますが、同様に必ずfailed = trueが成立します。

O2だとif文は必ず成立する場合(異常パス)と、しない場合(正常パス)でコードが複製されるようです。if文が成立する側のコードでは、if文の後は不要 = 未使用コードを消去 = dest - rnameというコードそのものがなかったことになる、というメカニズムが働いて警告が出ないのでしょう。たぶん。

GCCの警告は大体合っていますが、これはコンパイラが誤警告を出してしまうちょっと珍しい例でした。個人的には紛らわしいコードを書くんじゃねえ!と思いますが、歴史あるコードですし……何か理由があってこうなっているんでしょう。

編集者:すずき(2022/04/22 03:00)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月5日

Timberborn

遊ばずに放置していたTimberbornをしばらくやっていました。まだ発展途上のEarly Access版でもありますし、私の遊び方が良くないのもありそうですが、ゲームの前半は非常に面白いのですが、後半がダレ気味です。

前半はいかに効率よく水を確保してビーバー達を救うかがキモです。水源開発(ダムなど)を優先しすぎると容易に木材、食料、住宅不足に陥って街の開発が詰んでしまいます。かといって街の開発を優先しすぎると、水が足りなくなってビーバー達が干からびて死んでしまいます。

この辺りのバランスの取り方が難しくも面白いです。干ばつまでの時間と戦いつつ街もダムも拡張させる、ギリギリの街作りを進める楽しさがあります。

しかし一度でも最長期間の干ばつ(Normal難易度なら9日間)に耐えられる街ができると、非常に安定してしまい、人口を極端に変えない限りはやることがなくなります。特にダイナマイト量産に成功した後は「山崩しゲーム」と化します。

  • 山へ階段作る
  • 山を一段爆破
  • 階段を一段解体
  • 山を一段爆破
  • 階段を一段解体
  • ...

これが延々と続きます。広いマップの巨大な山を切り崩すのは辛いんで、とりあえず一番狭いDiorama(50x50)マップを使い、山を2つ(右の山と、左の手前の小さい山)ほど潰して更地にしてみました。こんな小さい山を潰すだけでもかなり時間が掛かります。ひたすらダルいです。


オリジナルの状態


山を2つ潰した後

最後の山も残っていますが……もういいや……。

メモ: 技術系?の話はFacebookから転記しておくことにした。加筆。

編集者:すずき(2022/04/06 12:13)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月4日

SUPER HOTELのタブレット端末

奥さんと銀座のSUPER HOTELに来ました。現在SUPER HOTELと進撃の巨人がコラボしていて、泊まるとノベルティが1人1つ貰えるそうです。ノベルティは全部で2種類あり、両方欲しいので2人で泊まりたかったんですって。へー。

部屋にはタブレットとテレビがありました。タブレットはONKYO TA2C-74Z8Aという古い業務用のタブレットでした。Atom機でx86 Androidです。バージョンはAndroid 5.1とかなり古いですね。


ONKYO TA2C-74Z8A

戻るボタン、ホームボタンは画面に出せますが、ホームアプリが差し替えられているため基本的には他のアプリは起動しません。


ホーム画面

さらにPerfect AppLockなるロックアプリが入っています。通知バーから設定アプリを起動しようとするなど、ホテル業務と関係ないアプリを起動しようとすると妨害されるようです。デフォルトのホームアプリ(Launcher3)はなぜか起動妨害対象に入っておらず、ロックアプリのアイコンが拝めます。


Perfect AppLock(右下の錠前のアイコン)

これ以上は何も弄れませんでしたと言いたいところですが、このロックアプリはバグってるみたいで、画面遷移の瞬間に連打するとロックの設定を削除できてしまいました。名前に反して全然パーフェクトじゃないんだが……??設定アプリも拝めましたし、開発者モードもONにできました。ここまで到達できるならadbを繋ぎたかったですね。パソコンを持ってこなかったのが惜しまれます。


開発者モード

タブレットはこれくらいにして、テレビを見ると普通のブラビア(SONY KJ-49X8000E)でした。


サイドの木箱にSTBが隠してありました、業務用のSTB + 普通のテレビというホテルではありがちな構成ですね。残念なことにリモコンはSTB用のリモコンしかなく、ブラビアのリモコンは見あたりませんでした。


STBのリモコン

おかげでブラビアのメニュー画面が出せなくて特に何も弄れませんでした。つまんないですね……。

メモ: 技術系の話はFacebookから転記しておくことにした。加筆、写真追加。

編集者:すずき(2022/04/06 12:00)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年4月2日

射的3回目

目次: 射的

秋葉原のトリガーハッピーでシューティングレンジに3回目のチャレンジ。7mくらい先の的9個を撃つゲームです。

前回はアベレージ15秒、ベスト12秒くらい、今回はアベレージ13〜14秒、ベスト10秒くらいでした。一度だけマグレで8秒台が出ましたが、その後は二度と10秒を切ることはありませんでした。

前回はダブルアクションで1発目がブレがちなベレッタ92だったので、今回はグロック19で挑みました。グロック系はセーフティー操作が不要(トリガーセーフティーのみ)で扱いが楽ですね。

構え方の問題なのか、狙いを上下に移動させたときに外しやすいようです。サイトは同じように狙っているつもりなんですが、ズレてる?難しいなー。

ルールは適当!

スチールチャレンジやアンリミテッドシューティングチャレンジであれば、下記のようなルールのためセーフティー操作とタイムはダイレクトに影響するはずです。

  • コッキング(弾を送る)
  • セーフティー設定(ダブルアクションならデコッキングも可)
  • ホールドアップ(両手を顔の高さに)
  • 合図が鳴ったら……ホルスターから銃を抜く
  • 的を狙う(このとき銃口が自分の手や体に向くと失格らしい)
  • セーフティー解除
  • 的を撃つ

シューティングバーでやるような射的はノールールです。ホルスターなんて持って行きませんし、セーフティー解除してから撃ち始めますからセーフティー操作とタイムもほとんど関係ありません。超適当です。当たる、楽しい!で良いのだ!

趣味としては息が長そう

エアガンを使った趣味として代表的なモノはサバゲー(サバイバルゲーム)です。サバゲーはやったことありませんが、みなさんでワイワイやるのは楽しそうです。難点は何だろうな?フィールドで移動する最低限の体力が必要ですね。あとは相手に撃たれたら痛いくらい……?

シューティングはほぼ動きませんし撃たれません。シューティング大会に出るなどのガチ系の人は別として、他人の動向を気にする必要はなくて気楽です。難点は何だろうな。

  • 場所: 音がうるさい&一定の直線距離が必要(都会の集合住宅には向いてない)
  • コスト: 弾代は安いが、フロンガス代はやや高い(電動ガンなら不要)
  • 人数: 基本一人、気楽でもあり寂しくもあり

ランニングコストに関してはバカスカ撃たなければ常識の範囲内だと思いますし、もし多人数で交流したいなら練習会に行くのも良いでしょう。

私にとっては一生モノの気楽に遊べる趣味にできそうです。

編集者:すずき(2022/04/04 05:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2022年4月15日 >>> 2022年4月2日
link もっと後

管理用メニュー

link 記事を新規作成

<2022>
<<<04>>>
-----12
3456789
10111213141516
17181920212223
24252627282930

最近のコメント20件

  • link 21年9月20日
    すずきさん (11/19 01:04)
    「It was my pleasure.」
  • link 21年9月20日
    whtさん (11/17 23:41)
    「This blog solves my ...」
  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」
  • link 14年6月13日
    2048playerさん (09/26 01:00)
    「今のところ最も簡略化した式です。\n--...」
  • link 14年6月13日
    2048playerさん (09/16 01:00)
    「返信ありがとうございます。\nコメントが...」
  • link 14年6月13日
    すずきさん (09/12 21:19)
    「コメントありがとうございます。同じ結果に...」
  • link 14年6月13日
    2048playerさん (09/08 17:30)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048さん (09/08 17:16)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048playerさん (09/08 16:10)
    「私も2048の最高スコアを求めたのですが...」
  • link 02年8月4日
    lxbfYeaaさん (07/12 10:11)
    「555」
  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」
  • link 24年5月17日
    すずきさん (05/20 13:16)
    「そうですねえ、普通はStandardなの...」
  • link 24年5月17日
    hdkさん (05/19 07:45)
    「なるほど、そういうことなんですね。Exc...」

最近の記事3件

  • link 24年11月18日
    すずき (12/04 02:08)
    「[nvJPEGとNVJPGとJetson APIその1 - nvJPEG decoupled API] 目次: Linux半年...」
  • link 23年4月10日
    すずき (12/04 01:40)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年11月28日
    すずき (12/01 00:53)
    「[BIOS/UEFI画面に入る方法] PCは起動時にあるキーを押すとBIOS/UEFIの設定画面に遷移します。良く見るパターン...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 12/04 02:08