Assembler Module mit CMake
« | 19 Dec 2021 | »So wie es in Star Trek heißt
Space, the final frontier.
so heißt es dann auch gerne in der Software-Entwicklung:
Assembler, the final frontier.
Bleibt nur die Frage offen, wie man diese letzte Grenze dann auch in CMake überwindet.
Das GATE Projekt soll eigentlich frei von Hardware-Spezialitäten sein,
lediglich die “notwendigen” OS
APIs der wichtigsten Hersteller sollen gesammelt und abstrahiert werden.
Assembler Codes haben da keinen Platz und sind auch in anderen Libs wie
OpenSSL / libreSSL
usw. bewusst abgeschaltet.
Eine kleine Ausnahme gibt es, wenn es um die CPU-ID geht, die man mit Inline-Assembler auslesen kann … aber schon da gibt es das typische MSVC X64 Problem, dass dort nämlich kein Inline-Assembler unterstützt wird.
Mit der EFI
Plattform gibt es nun aber einen Sonderfall, wo es um den Nachbau von
C-APIs geht,
namentlich setjmp()
und longjmp()
.
Diese Funktionen lassen sich nicht mit reinem C nachbauen. Doch diese sind
in der gnuefi
Bibliothek als .s
Assembler Dateien beigelegt.
Blöd ist nur, dass ich primär unter Windows mit dem MSVC
arbeite,
wo mir erstens die .s
Dateien nichts bringen und zweitens CMake
diese Dateien nicht automatisch mitbaut.
GNU Assembler Support für CMake
Im Netz findet man schnell die Info, dass man ASM
als Sprache im CMake
Projekt angeben soll, also z.B.
project(my_project C ASM)
Dann werden noch *.s
Dateien hinzugefügt und man erhält:
CMake generiert dann Make-Files, die die .s
Assembler Dateien kompilieren
und zur Zielbibliothek (oder Executable) hinzufügen.
MSVC Assembler Support für CMake
In Visual Studio kann man manuell den MASM
Support aktivieren, in dem man das Projekt auswählt, und dann unter
Project
- Build Customizations
klickt und dort die masm
Zeile anhakt.
Ab dann werden alle .asm
Dateien an den Assembler Compiler weitergereicht.
Für CMake
gibt es beim MSVC einen eigenen MASM Token, der da lautet:
ASM_MASM
.
Somit muss man nur noch die unter DOS
und Windows üblichen .asm
Dateien in CMakeLists.txt
aufnehmen:
MASM Funktionen für C schreiben
Nun beginnt für mich der harte Kampf die AT&T Assemblercodes nach MASM zu
portieren. Denn da der AT&T Syntax bei GNU und GCC vorherrscht und auch die
setjmp()
und longjmp()
Codes der gnu-efi
Bibliothek so geschrieben sind,
müssen fast alle Codezeilen “umgedreht” werden, damit sie MASM-tauglich werden.
Warum MASM ein Operator Ziel, Quell
Schema verfolgt und
AT&T umgekehrt Operator Quelle, Ziel
nutzt und es da keinen Standard gibt, stört mich damals wie heute.
So sehen jedenfalls meine vorläufigen Bemühungen aus:
1.CODE 2 3PUBLIC _setjmp 4 5_setjmp PROC 6 ; RCX hold pointer to jmp_buf 7 pop rdx ; RET address 8 push rdx 9 mov rax, 0 10 mov [rcx + 00h], rsp ; Frame 11 mov [rcx + 08h], rbx 12 mov [rcx + 10h], rsp 13 mov [rcx + 18h], rbp 14 mov [rcx + 20h], rsi 15 mov [rcx + 28h], rdi 16 mov [rcx + 30h], r12 17 mov [rcx + 38h], r13 18 mov [rcx + 40h], r14 19 mov [rcx + 48h], r15 20 mov [rcx + 50h], rdx ; RIP 21 ; currently, skip following fields in jmp_buf 22 ret 23_setjmp ENDP 24 25PUBLIC longjmp 26 27longjmp PROC 28 mov rbx, [rcx + 08h] 29 mov rsp, [rcx + 10h] 30 mov rbp, [rcx + 18h] 31 mov rsi, [rcx + 20h] 32 mov rdi, [rcx + 28h] 33 mov r12, [rcx + 30h] 34 mov r13, [rcx + 38h] 35 mov r14, [rcx + 40h] 36 mov r15, [rcx + 48h] 37 38 mov r8, [rcx + 50h] ; RIP 39 40 mov eax, edx 41 and rax, 0ffffffffh 42 cmp eax, 0 43 jne longjmp_exit 44 mov eax, 1 45longjmp_exit: 46 jmp r8 47longjmp ENDP
Fazit
Der erste Schritt ist also getan.
Die in Assembler implementierten setjmp()
und longjmp()
Symbole erlauben mir
nun weitere Bibliotheken wie LUA oder
libjpeg auch für native EFI-Apps zu
nutzen.
Das Potential ist aber weit größer.
Denn mit Assembler-Fragmenten kann ich nun auch zu anderen Stacks springen
und z.B. Koroutinen ohne
OS-Support implementieren.
Aber … bis das lauffähig sein wird, vergeht vermutlich noch einige Zeit.