nginxのソースコード内で何をしているのかを考えると、getelementptr命令のセマンティクスは面白いです。
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
ev->handler(ev);
node
ev
のタイプngx_event_t
のメンバーである、タイプngx_rbtree_node_t
である:これは、Cのソースコードの2つのラインの結果です。
struct ngx_event_t {
....
struct ngx_rbtree_node_t time;
....
};
struct ngx_event_t *ev;
struct ngx_rbtree_node_t *node;
timer
がnode
がポイントすべき構造体ngx_event_t
メンバーの名前は次のとおりです。のようなものです。
|<- ngx_rbtree_node_t ->|
|<- ngx_event_t ->|
------------------------------------------------------
| (some data) | "time" | (some data)
------------------------------------------------------
^ ^
ev node
上記グラフは、ngx_event_t
のインスタンスのレイアウトを示しています。 offsetof(ngx_event_t, time)
の結果は40です。つまり、の前にsome data
が40バイトであることを意味します。そして、偶然にもngx_rbtree_node_t
のサイズも40バイトです。したがって、getelementptr命令の最初のインデックスoprandのi64 -1
は、node
の40バイト先のnode
を含むngx_event_t
のベースアドレスを計算します。
handler
はngx_event_t
の別のメンバーで、ngx_event_t
の16バイト後になります。 (別の)偶然の一致によって、ngx_rbtree_node_t
の3番目のメンバーは、ngx_rbtree_node_t
のベースアドレスの16バイト後になります。したがって、getelementptr命令のi32 2
は、のアドレスを得るために、ev
に16バイトを追加します。
ngx_event_t
ではなく、ngx_rbtree_node_t
のレイアウトから16バイトが計算されることに注意してください。 Clangはgetelementptr命令の正確さを保証するためにいくつかの計算を行っているに違いありません。 %handler
の値を使用する前に、%handler
を関数ポインタ型にキャストするビットキャスト命令があります。
Cangが行ったことは、Cソースコードで定義されている型変換プロセスを壊してしまったことです。しかし結果はまったく同じです。
これは本当です。しかし、この負の値を使う目的は面白いです。私は別の答えでそれを説明しました。 – xywang