# Bauen und inspizieren

> Build-Profile, auf eine einzige Semantik festgelegt, das ELF, das ein Build erzeugt, das ProgramImage, das der Loader daraus macht, sein Bericht und die Programmidentität, die ein Verifier registriert.

## Bauen

Aus dem Verzeichnis des Gastprogramms (Guest), ohne weiteres Flag außer dem Target:

```sh
cd guests/my-app
cargo build --release --target riscv32imac-unknown-none-elf     # .../release/my-app
cargo build --target riscv32imac-unknown-none-elf               # .../debug/my-app
```

Das ELF landet im einzigen Target-Verzeichnis des Gastprogramm-Workspace, `guests/target/riscv32imac-unknown-none-elf/`. `guests/.cargo/config.toml` fügt zwei Linker-Argumente hinzu, die Sie nie eintippen:

- **`-T crates/guest-sdk/link.ld`**, die Speicherkarte, die auch die Symbole definiert, die der Startup-Code und der Allokator verwenden.
- **`--no-relax`**. Linker-Relaxation schreibt Befehlsfolgen um und verschiebt jede spätere Adresse, und die Programmidentität bindet diese Adressen.

Es gibt keinen `runner`: Nichts außerhalb von Apogee bildet die Speicherbereiche eines Gastprogramms ab; `cargo run` hat also nichts, womit es das Gastprogramm ausführen könnte. Sie führen ein Gastprogramm über den Emulator aus ([Ausführen und profilieren](https://apogee.gweb3networks.com/docs/launch/run)).

## Profile

`guests/Cargo.toml` legt beide Profile auf eine einzige Semantik fest. Sie unterscheiden sich nur in der Optimierung und in den Debug-Assertions der Abhängigkeiten:

| | dev | release |
| --- | --- | --- |
| `opt-level` | 0 | 3 |
| `overflow-checks` | an | **an** |
| `debug-assertions` | an | an im Crate des Gastprogramms, aus in seinen Abhängigkeiten |
| `panic`, `codegen-units`, `debug`, `incremental` | `abort`, 1, aus, aus | identisch |

Das Standard-Release-Profil von Cargo schaltet Überlaufprüfungen ab, und in einem Gastprogramm ist das keine Performance-Einstellung. Es ändert die Aussage: `u32::MAX + 1` würde `00000000` festschreiben und mit Exit 0 enden, wo der Dev-Build einen Panic auslöst und mit Exit 101 endet. Deshalb lässt der Workspace die Prüfungen in beiden Profilen aktiv. Die Debug-Assertion einer Abhängigkeit prüft eine Invariante dieses Crates selbst, und eine korrekte Abhängigkeit berechnet ohne sie dasselbe; das Release-Profil schaltet sie deshalb ab und spart die Zyklen: 6,8 % des Laufs des zustandslosen Ethereum-Gastprogramms.

**Beweisen Sie den Release-Build.** Jeder ausgeführte Befehl ist eine bewiesene Zeile, `opt-level = 3` entfernt ein Viertel bis über die Hälfte des Images eines Gastprogramms, und der Code jeder Familie muss in ihre dekodierte Tabelle passen: Das Debug-Image des Ethereum-Gastprogramms braucht Tabellen mit `2^22` Zeilen, sein Release-Image `2^20`. Die Identität, die Sie veröffentlichen, ist die des Release-Images.

## Reproduzierbarkeit

Zwei saubere Builds auf einer Maschine erzeugen identische ELFs. Builds auf zwei Maschinen im Allgemeinen nicht: Das ELF bettet in Strings für Panic-Locations absolute Pfade ein, zu den `core`-Quellen der Toolchain, zu `crates/guest-sdk` und zur Cargo-Registry, während die eigenen Dateien des Gastprogramms relativ zu `guests/` erscheinen. Ein Build an anderer Stelle ist ein anderes Image mit einer anderen Identität.

Was Sie registrieren und weitergeben, ist also **das ELF eines Builds, kein Rezept**. Bewahren Sie das ELF auf, das Sie bewiesen haben, und lassen Sie jeden, der die Identität prüfen will, sie aus diesem ELF, den Parametern und der Zeremoniedatei neu berechnen.

## Das Image exportieren

```sh
cargo run -p artifact-dump -- guests/target/riscv32imac-unknown-none-elf/release/my-app --out artifacts
```

Das schreibt `artifacts/my-app.img`, das geladene `ProgramImage` in seinem Serialisierungsformat (`postcard`, ohne Header), und `artifacts/my-app.img.txt`, einen Bericht, der aus dem über den validierenden Reader zurückgelesenen Image erzeugt wird. Ausgegeben werden der Einsprungpunkt, die Zahl der Segmente und Befehle sowie Größe und SHA-256 des Artefakts. Weicht das Zurückgelesene ab oder weist der Loader das ELF zurück, wird nichts geschrieben.

Die `.img`-Datei ist die statische Beschreibung des Programms, zum Aufbewahren und Vergleichen; nichts Nachgelagertes braucht sie, denn das Setup und die Werkzeuge nehmen das ELF entgegen. Ihr SHA-256 legt Bytes fest. Er ist **nicht** die Programmidentität.

## Den Bericht lesen

| Abschnitt | Zeigt |
| --- | --- |
| `entry and memory` | den Einsprung, `_start` bei `0x00010000`; das RAM-Fenster; `slot_base` und die Slot-Spanne |
| `segments` | Adresse, Ende, `mem_len`, Dateibytes, Nullauffüllung und Befehlszahl jedes Segments: `.text`, `.rodata`, falls vorhanden, und ein beschreibbares Segment bis `0x80000000` für `.data`, `.bss`, Heap und Stack |
| `instruction stream` | Vier- und Zwei-Byte-Befehle, Slots mitten in einem Befehl und `not code`-Slots, die sich zur Slot-Zahl summieren |
| `symbols` | Namen nach Adresse aus der Symboltabelle des ELF, die das Artefakt nicht mitführt |
| `listing` | pro Befehl: Adresse, Länge, die Bytes im Speicher, das expandierte 32-Bit-Wort, das Symbol |

Ein komprimierter Befehl behält seine Adresse und seine zwei Bytes; allein `len` gibt an, ob der nächste pc `pc + 2` oder `pc + 4` ist. Für Mnemonics verwenden Sie die Ansicht `tables` unten oder den festgelegten Disassembler:

```sh
"$(rustc --print sysroot)"/lib/rustlib/*/bin/llvm-objdump \
    --disassemble --no-print-imm-hex -M no-aliases <elf>
```

### Die `not code`-Halbwörter

Ein Bericht kann eine Zeile wie `---- not code: 0x00010f9a .. 0x00010f9c, 1 halfword ----` enthalten. Das ist gewöhnliche Compiler-Ausgabe. LLVM hat den Default-Zweig eines `match` als unerreichbar bewiesen, rustc hat den unerreichbaren Block zu `unimp` übersetzt, und mit der C-Erweiterung ist das `c.unimp`, das Halbwort aus lauter Nullen, die definiert illegale Kodierung von RVC. Der Loader verzeichnet es als Nicht-Befehl und macht weiter. Kein pc erreicht es; einer, der es täte, würde den Lauf mit `NotAnInstruction` anhalten.

## Was die VM beweisen wird

```sh
cargo run --release -p artifact-dump -- tables <elf> --ptau assets/ptau/ppot_0080_24.ptau
```

Das gibt bei den Standardparametern die `VmConfig` aus, die aus dem Image abgeleitet wird: die Höhe jeder Familie, ihre belegten Zeilen und dekodierten Spalten. Danach folgen für jeden Befehl pc, `next_pc`, Familie, Mnemonic und Felder. Mit `--ptau` und der Zeremoniedatei gibt es außerdem die **Programmidentität** aus, den Wert, den ein Verifier registriert. Der [Schnellstart](https://apogee.gweb3networks.com/docs/launch/quickstart#inspect) zeigt eine echte.

Die Identität ist ein einziges Körperelement. Sie bindet jeden Befehl mit seinem pc, seiner Länge, seinen Operanden und seiner Art, jedes in der Datei enthaltene Byte des Images (`.text`, `.rodata`, `.data`), den Einsprungpunkt, die Menge der Familien, jede Höhe, die Obergrenze der Codegröße und die Codeversion. Sie bindet nicht die Symboltabelle, nicht `.bss` und nichts, was eine Ausführung wählt. Ein ELF mit zwei Einstellungen der Höhen hat zwei Identitäten.

Die Ableitung weist das Programm zurück und nennt dabei den pc oder die Größe:

| Zurückweisung | Ursache |
| --- | --- |
| `Not all opcodes supported: pc=…` | ein Wort außerhalb von RV32IMA irgendwo im ausführbaren Code, etwa ein CSR-Zugriff in Assembly |
| `TableTooShort` | Code jenseits der Reichweite einer Familie, `pc ≤ 2h − 4`: 1,9375 MiB Code bei `2^20` und 7,9375 MiB bei `2^22` |
| `ProgramTooLarge` | das Image überschreitet `bytecode_size_words`, standardmäßig 4 MiB |
| `ImageOutsideWindow` | ein in der Datei enthaltenes Byte liegt bei der gewählten Fensterhöhe jenseits von RAM-Fenster 0 |
| `UnknownDelegation` | das Image deklariert eine Delegationsnummer, auf die keine Familie antwortet |

## Einen Build prüfen

Bauen Sie in ein frisches Target-Verzeichnis, exportieren Sie erneut und vergleichen Sie:

```sh
cd guests/my-app
CARGO_TARGET_DIR=/tmp/fresh cargo build --release --target riscv32imac-unknown-none-elf
cd ../..
cargo run -p artifact-dump -- /tmp/fresh/riscv32imac-unknown-none-elf/release/my-app --out /tmp/again
cmp artifacts/my-app.img /tmp/again/my-app.img
diff artifacts/my-app.img.txt /tmp/again/my-app.img.txt     # differs only in the `source ELF` line
```
