2016-04-06 9 views
1

Ich lese die IR von Nginx von Clang generiert. In der Funktion ngx_event_expire_timers gibt es einige getelementptr Anweisungen mit i64 -1 als ersten Indexoperanden. Beispiel:getelelementptr hat -1 als den ersten Indexoperanden

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

Ich weiß, dass der erste Indexoperand als Offset zum ersten Operanden verwendet wird. Aber was bedeutet ein negativer Offset?

Antwort

1

Der GEP-Befehl ist perfekt mit negativen Indizes. In diesem Fall haben Sie so etwas wie:

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

GEP mit negativen Indizes nur die an den Basiszeiger in die andere Richtung versetzt berechnen. Es ist nichts falsch daran.

+0

Das stimmt. Aber der Zweck, diesen negativen Wert zu verwenden, ist interessant. Ich habe es in einer anderen Antwort erklärt. – xywang

0

Betrachtet man, was im nginx-Quellcode vor sich geht, ist die Semantik der geelementptr-Anweisung interessant. Es ist das Ergebnis von zwei Zeilen Code C-Quelle:

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

node ist vom Typ ngx_rbtree_node_t, die ngx_event_t Mitglied ev ‚s-Typ ist. Das ist wie:

struct ngx_event_t { 
    .... 
    struct ngx_rbtree_node_t time; 
    .... 
}; 

struct ngx_event_t *ev; 
struct ngx_rbtree_node_t *node; 

timer ist der Name der Struktur ngx_event_t Mitglied in dem node zeigen sollte.

    |<- ngx_rbtree_node_t ->| 
|<-    ngx_event_t      ->| 
------------------------------------------------------ 
| (some data) | "time"    | (some data) 
------------------------------------------------------ 
^    ^
ev    node 

Die obige Grafik zeigt das Layout einer Instanz ngx_event_t. Das Ergebnis von offsetof(ngx_event_t, time) ist 40. Das bedeutet, dass some data vor time 40 Byte ist. Und die Größe von ngx_rbtree_node_t ist auch 40 Bytes, durch Zufall. So i64 -1 in der ersten Index oprand des Getementptr Befehl berechnet die Basisadresse des ngx_event_t enthält node, die 40 Bytes vor node ist.

handler ist ein weiteres Mitglied von ngx_event_t, die 16 Bytes hinter der Basis von ngx_event_t ist. Durch eine (weitere) Koinzidenz liegt das dritte Glied von ngx_rbtree_node_t ebenfalls 16 Bytes hinter der Basisadresse von ngx_rbtree_node_t. So wird die i32 2 in geteilelementptr Anweisung 16 Bytes zu ev hinzufügen, um die Adresse handler zu erhalten.

Beachten Sie, dass die 16 Bytes aus dem Layout ngx_rbtree_node_t, aber nicht ngx_event_t berechnet werden. Clang muss einige Berechnungen durchgeführt haben, um die Korrektheit der geteileptr Anweisung sicherzustellen. Bevor der Wert %handler verwendet wird, gibt es eine Bitcast-Anweisung, die %handler auf einen Funktionszeigertyp umsetzt.

Was Clang getan hat, bricht den im C-Quellcode definierten Typentransformationsprozess. Aber das Ergebnis ist genau das Gleiche.