EVM SIGNEXTEND Opcode-Erklärung

Ich versuche, mein eigenes kleines EVM zu entwickeln. Das ist eine gute Möglichkeit für mich, mehr über die Byteebene zu erfahren. Ich hatte mit den meisten Anleitungen keine Probleme, aber es gibt ein paar, die ich einfach nicht verstehe. SIGNEXTEND ist einer davon...

So beschreibt das gelbe Papier den Opcode:Geben Sie hier die Bildbeschreibung ein

Ich versuche zu verstehen und herauszufinden, was hier passiert und wie dieser Opcode funktioniert. Ich kann weder ein geeignetes Beispiel noch einen Fall finden, in dem ich diesen Opcode benötigen könnte.

Hat jemand von euch ein Beispiel oder eine Erklärung für diesen Opcode?

Danke im Voraus.

Vielleicht finden Sie dieses Papier interessant arxiv.org/pdf/1802.08660.pdf . Es beschreibt eine formale Semantik in kleinen Schritten für die Ethereum Virtual Machine. (Hinweis: Es ist nicht aktuell, zB fehlt STATICCALL).
Danke für die Verlinkung des Papers. Einige Opcodes sind etwas anders geschrieben, was es klarer macht. Trotzdem verstehe ich ihr SIGNEXTEND nicht ...

Antworten (2)

Großartig! Das ist eine großartige Möglichkeit, etwas über die EVM zu lernen. Die Antwort kann ausführlich sein, aber sie wird vollständig sein.


Zweierkomplement

Das Zweierkomplement ist eine Möglichkeit, ganze Zahlen binär darzustellen. Es ermöglicht uns, ganz einfach vorzeichenbehaftete Ganzzahlen auszudrücken (der Einfachheit halber eingefügt; siehe Quelle für weitere Details):

Angenommen, wir arbeiten mit 8-Bit-Mengen (der Einfachheit halber) und nehmen an, wir wollen herausfinden, wie -28 in der Zweierkomplementnotation ausgedrückt würde. Zuerst schreiben wir 28 in binärer Form aus.

00011100

Dann invertieren wir die Ziffern. Aus 0 wird 1, aus 1 wird 0.

11100011

Dann addieren wir 1.

11100100

So würde man -28 in 8-Bit-Binär schreiben.

Erweitern der Länge einer vorzeichenbehafteten Ganzzahl

Das Konzept, die Länge einer vorzeichenlosen Ganzzahl zu verlängern, ist ziemlich trivial, zum Beispiel:

Nehmen Sie zum Beispiel die Nummer 01010101 . Es ist 1 Byte lang.

Angenommen, wir möchten es als 2 Bytes darstellen. Alles, was wir tun müssen, ist, acht Nullen zu unserer Nummer hinzuzufügen: 00000000 01010101 . Jetzt sind es 2 Bytes.

Das am weitesten links stehende Bit einer vorzeichenbehafteten Ganzzahl ist jedoch das Vorzeichenbit. Wir müssen darauf achten, das Vorzeichenbit einzubeziehen, wenn wir eine vorzeichenbehaftete Ganzzahl erweitern, oder wir ändern seinen ursprünglichen Wert. Nehmen wir an, ich wollte die Zahl, die wir über -28 in Binär 11100100 verwendet haben , auf die gleiche Weise erweitern, wie wir die Ganzzahl ohne Vorzeichen erweitert haben, wie folgt:

00000000 11100100

Jetzt ist unsere vorzeichenbehaftete Ganzzahl nicht mehr -28, sondern 228. Daher brauchen wir einen Mechanismus zum Erweitern der vorzeichenbehafteten Ganzzahl unter Beibehaltung des Vorzeichenbits. Es ist nicht so, dass wir nur acht der Vorzeichenbits anhängen müssen, anstatt acht Nullen anzuhängen. In diesem Fall ist das Vorzeichenbit 1. Also hängen wir acht Einsen wie folgt an:

11111111 11100100

Jetzt haben wir den Wert -28, ausgedrückt in zwei Bytes statt 1.

Siehe Quelle für weitere Details.

Warum also??

Warum gibt es dafür einen speziellen Opcode? Dies könnte sehr schnell ein niedriges Niveau erreichen, aber der Prozess des Erweiterns des Vorzeichens einer vorzeichenbehafteten Ganzzahl würde mehrere Opcodes erfordern. Ich erkläre kurz , wie ich es ohne den SIGNEXTEND-Opcode machen würde:

  1. Bitmaske, um das am weitesten links stehende Bit zu erhalten
  2. Überprüfen Sie den Wert des Bits ganz links
  3. Hängen Sie den Wert des Bits ganz links an

Aus diesem Grund und weil es häufig genug verwendet wird, müssen die Entwickler es für notwendig gehalten haben, einen speziellen Opcode dafür zu erstellen.

Und warum sollten wir es verwenden? Dies ist eine fundierte Vermutung, aber man könnte sie verwenden, um Daten zwischen Registern unterschiedlicher Größe zu verschieben, wie dieser Artikel vorschlagen würde.

Lassen Sie mich wissen, ob Sie dies hilfreich fanden! 😃

Danke für deine Antwort. Obwohl es eine nette Erklärung für das Zweierkomplement ist, habe ich immer noch keine Ahnung, wie der Opcode funktioniert :) Glauben Sie, Sie könnten mir sagen, welche Art von Werten in Bezug auf Ihr Beispiel von -28 auf den Stack geschoben werden?
@foba: aber was bedeutet dann das Größenargument SIGNEXTEND?
@ user2284570 Ich glaube, es ist die Anzahl der Bytes, um die es erweitert werden soll. Hier ist das Golang für diese Operation, die in go-ethereum verwendet wird .

Nachdem ich mit einigen Leuten von gitter/yellowpaper gesprochen habe, bin ich jetzt in der Lage, die SIGNEXTENDOperation zu erklären.

Mein Fehler war zu glauben, dass das LSB bei μ_s[1] die Position 0 hat. Das MSB hat die Position 0 und das LSB die Position 255.

Außerdem erweitert der evm alles immer auf Wortgröße, egal welche Größe die Werte selbst haben.

Nur ein Beispiel, um diese Operation klarer zu machen:

Nehmen wir an, wir haben -2, was 1111 1110binär ist. Da im evm alles Wortgröße hat, befindet sich das 0im binären String an Position 255. Um das Vorzeichenbit zu erhalten, hat μ_s[0] den Wert 0. Das bedeutet für t:

t = 256 - 8(0 + 1) = 256 - 8 = 248

Damit erweitert es das 1111 1110auf 1111 1111 ... 1111 1110, wo das 1111 111131 weitere Male vorkommt :)

Ich hoffe es hilft.

Welche Gegenstände befinden sich in Ihrem Beispiel auf dem Stapel?
Ich habe endlich ein Beispiel gefunden, bei dem signextend neben der Eingabe auch etwas zurückgibt. signextend(0xff, 0) -> (-1). Ich hatte eine Off-by-One-Annahme - zum Beispiel dachte ich, signextend(x, 1) würde x als eine 1-Byte-Zahl mit Vorzeichen behandeln, aber signextend(x, 0) tut dies tatsächlich.