2016-04-06 4 views
1

私はClangによって生成されたnginxのIRを読んでいます。関数ngx_event_expire_timersでは、getelementptr命令の中には、最初のインデックスオペランドとしてi64 -1があります。たとえば、getelementptrは最初のインデックスオペランドとして-1を持っています

%handler = getelementptr inbounds %struct.ngx_rbtree_node_s, %struct.ngx_rbtree_node_s* %node.addr.0.i, i64 -1, i32 2 

私は最初のインデックスオペランドが最初のオペランドのオフセットとして使用されることを知っています。しかし、負のオフセットはどういう意味ですか?

答えて

1

GEP命令は、負のインデックスで完全に正常です。ただ、他の方向にベースポインタにオフセットを計算負のインデックスと

node arr[100]; 
node* ptr = arr[50]; 
if ((ptr-1)->value == ptr->value) 
    // then ... 

GEP:あなたが何かを持っている。この場合 。それには何も問題はありません。

+0

これは本当です。しかし、この負の値を使う目的は面白いです。私は別の答えでそれを説明しました。 – xywang

0

nginxのソースコード内で何をしているのかを考えると、getelementptr命令のセマンティクスは面白いです。

ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); 
ev->handler(ev); 

nodeevのタイプ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; 

timernodeがポイントすべき構造体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のベースアドレスを計算します。

handlerngx_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ソースコードで定義されている型変換プロセスを壊してしまったことです。しかし結果はまったく同じです。

関連する問題