( ricpet | 2024. 03. 12., k – 12:09 )

Szerkesztve: 2024. 03. 12., k – 12:49

Hogy ne csak a levegőbe beszéljek, és tényleg korrekt összehasonlítás legyen, megcsináltam C nyelven és Rust-ban is. A Merge Request-et már ott a repo-ban.

Hogy izgalmas legyen, a C/C++ megoldás Visual Studio-val készült, PE formáutmú .exe az output-ja.

A háttérről: assembly-ben kb. 25 éve, még gyerekként programoztam értelmezhető mennyiséget, akkor kb. néhány száz óra nagyságrendű volt az idő, amit ebbe beletoltam. Meg volt egy könyvem, ami a 32 bites védett módú oprendszerekről szólt, ez hasznos volt annak kapcsán, hogy mi az az Interrupt Descriptor Table (ami egyébként koncepciójában nem sokat változott 64 bitre átállásnál). Ez most nagyon jól jött, hogy értsem miről is van szó, mit csinál az assembly nyelvű példa megoldás.

C nyelvvel már többet foglalkoztam, de igazán olyan sokat nem használtam, főleg az utóbbi 10 évben.

Rust-ot még soha nem használtam. Igazából erős kezdés volt így, hogy egyből egy rendszerprogramozási feladat :) Ez látszik is, hogy a nyelvet nem ismertem, sokkal inkább C jellegű a megoldás, kevésbé jól használja a Rust-os feature-öket. Ez jól látszik a már korábban elkészült Rust-os megoldáshoz hasonlítva. A legtöbb idő itt egyébként arra ment el, hogyan lehet bare metal bináris output-ot gyártani, hogyan lehet az outputhoz base address-t beállítani stb.

Amit mindkét megoldásban megcsináltam, hogy ne busy loop legyen a belépési pont végén a ciklus, hanem a HLT utasítást hajtja végre.

Összesen kb. tíz órát toltam bele. Napi szinten egyébként magasabb szintű nyelvekkel foglalkozok, C#, Java, JavaScript, Kubernetes, Cloud, DevOps témák.

Megjegyzés a peremfeltételekhez: az iretq hívást így kezelni, hogy a saját interrupt handlerből kell meghívni függvényként azt, ami majd valahogy kiléptet az egész interrupt handler-ből, ez szerintem szívás. Csak fragile megoldásokat találtam rá, de ahogy látom, mások is. A probléma gyökere, hogy egy magas szintű nyelvben, lényegében bármi ami nem assembly, nem igazán tudod megtippelni, hogy mekkora lesz a stack frame, amit el kell pusztítani, hogy az IRETQ gépi kódú utasítás a megfelelő stack pointernél fusson le. Itt kb. jósolni kell, hogy mi az a szám, amivel nem fagy le az egész gép. És ez lehet, hogy egy másik compiler verziónál már más lesz. Hogy itt tegyek javaslatot is, ezt szépen úgy lehet szoftver architektúra szempontból megcsinálni, hogy az interrupt handler egy rövid stub assembly-ben, akár a bootloader részeként, ami CALL utasítással meghívja a tényleges függvényt, ami a megoldás része, és a visszatérés után ez a stub lép ki IRETQ-val. Persze ekkor az eredeti megoldandó feladatnak egy jó része már kiesik, hiszen az IDT-t nem a megoldásban kell kitölteni, hanem a bootloader tölti ki, és a bootloader hív tovább a stub-ból a már normál módon megírt interrupt kezelő függvénybe.