Assembler-Unwissender: "Rahmen" einer naked-Funktion
-
Ich hab die Frage zwar schon einigemale gestellt (mit anderem Titel), aber hier einfach mal der dritte Versuch, vielleicht weiß jetzt jemand was ich meine.
Schonmal vorweg die Frage: Welchen "Rahmen" muss die folgende naked-Funktion haben (bzw. wie muss ich sie benutzen), damit sie nicht abstürzt? Beispiele, wie ichs schon probiert habe, folgen danach:
__m128 __declspec(naked) __stdcall am_sin_ss(__m128 x) { __asm { movss [esp - 4], xmm0 movss xmm1, _ps_am_inv_sign_mask mov eax, [esp - 4] mulss xmm0, _ps_am_2_o_pi andps xmm0, xmm1 and eax, 0x80000000 cvttss2si ecx, xmm0 movss xmm1, _ps_am_1 mov edx, ecx shl edx, (31 - 1) cvtsi2ss xmm2, ecx and ecx, 0x1 and edx, 0x80000000 subss xmm0, xmm2 movss xmm6, _sincos_masks[ecx * 4] minss xmm0, xmm1 movss xmm5, _ps_sincos_p3 subss xmm1, xmm0 andps xmm1, xmm6 andnps xmm6, xmm0 orps xmm1, xmm6 movss xmm4, _ps_sincos_p2 movss xmm0, xmm1 mulss xmm1, xmm1 movss xmm7, _ps_sincos_p1 xor eax, edx movss xmm2, xmm1 mulss xmm1, xmm5 movss xmm5, _ps_sincos_p0 mov [esp - 4], eax addss xmm1, xmm4 mulss xmm1, xmm2 movss xmm3, [esp - 4] addss xmm1, xmm7 mulss xmm1, xmm2 orps xmm0, xmm3 addss xmm1, xmm5 mulss xmm0, xmm1 ret 16 } }
Wenn ich darum ne Funktion bau, die float als Parameter nimmt und zurückgibt, stürzt das Programm mit Speicherfehler ab, der Code:
float FSIN(float x) { __m128 a, b; a.m128_f32[0] = x; a.m128_f32[1] = 0; a.m128_f32[2] = 0; a.m128_f32[3] = 0; b.m128_f32[0] = 0; b.m128_f32[1] = 0; b.m128_f32[2] = 0; b.m128_f32[3] = 0; b = am_sin_ss(a); return b.m128_f32[0]; }
Bau ich keine Funktion drumrum (bzw. eben nur main) und benutze nur das Innenleben dieser Funktion, wird der Sinus sogar korrekt berechnet, nur wenn ich einen Geschwindigkeitstest machen will, stürzt das Programm ab, wenn ich den Sinus so in einer Schleife ab größer 10 Durchläufe berechne.
Was muss ich um ne naked-Funktion herumbauen, zumal in der Funktion am_sin_ss doch schon ret vorhanden ist und sie außerdem Parameter hat, muss ich etwa in der Funktion selbst etwas ändern??
-
wieso ret 16 ? soweit ich erkennen kann, werden __m128 typen in xmm0 übergeben und zurückgegeben
ich bezweifle sowieso, dass sich der aufwand zeitlich lohnt im vergleich zu inline fsin mit 24bit genauigkeit. das wäre nat. sicher der fall, wenn tatsächlich der sinus eines ganzen vektors gesucht ist.
-
Ret 16 ??? Keine Ahnung.
Der Code ist aus ner library, die ziemlich gut sein soll (AM library).
Er wird bestimmt auch schneller sein, auch wenn man nur einen statt vier sinusse berechnet, was man mit der Funktion ja eigentlich machen könnte.
Aber der Geschwindigkeitstest funktioniert ja nicht und keiner kann mir sagen, was am obigen Code falsch ist, schade eigentlich.
-
die genaue behandlung von xmm typen dürfte compiler abhängig sein, ich würde auf jedenfall das ret 16 durch einfaches ret zu ersetzen.
-
Tatsächlich, es hat gefruchtet!!! Zumindest stürzt das Testprogramm jetzt nicht mehr ab, danke.
Ich melde mich nochmal, wenn ich geprüft hab, wie schnell (und damit sinnvoll) das Ganze eigentlich ist.
Was hat es mit dem ret 16 auf sich (near Rücksprung ???)?
-
ret 16 dient dazu, den stack aufzuräumen, an sich ist __m128 ja eine 16byte struktur; offenbar hat sich aber in den neueren vc++ versionen die behandlung von xmm intrinsics geändert, da der parameter nun in xmm0 übergeben wird, darf man dann natürlich nicht mehr am stack herumbasteln.
anders gesagt: der code, so wie er ist, ist unlogisch - entweder wird alles über den stack abgewickelt (direkt oder per referenz), also auch der rückgabewert, oder beides geht über xmm register - ich habe das gefühl, diese funktion wurde nie getestet, jedenfalls nicht mit dem compiler, den du benutzt.