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??


  • Mod

    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.


  • Mod

    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 ???)?


  • Mod

    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.


Anmelden zum Antworten