Sarth Temat założony przez niniejszego użytkownika |
[x86-64] Problem z liczbami zmiennoprzecinkowymmi » 2015-12-30 21:31:17 Mam program w C i w nim wywołuję funkcję napisaną w x86-64 (NASM). Prototyp funkcji to: extern void fun( unsigned char * a, unsigned char * b, float c );
finit
fld QWORD[ rdi ] fld QWORD[ rdx ] fmul st0, st1 fst QWORD[ rdi ]
I chcę pomnożyć a * c , ale niestety wynikiem tej operacji jest 0. Nie wiem co robię nie tak. Pytanie zapewne proste, ale ja dopiero zaczynam się uczyć x86. Mniej więcej ogarniam już operacje na liczbach całkowitych, ale FPU/SSE itp. to dla mnie na razie czarna magia. |
|
j23 |
» 2015-12-31 11:40:03 A debuggera używasz? Staraj się usuwać niepotrzebne wartości ze stosu FPU: ... fmulp fstp QWORD[ rdi ] |
|
Sarth Temat założony przez niniejszego użytkownika |
» 2016-01-01 15:50:04 Niestety nie używałem, bo nie za bardzo potrafię się posługiwać gdb, ale chyba czas najwyższy się nauczyć. A wracając do tematu to zdeasemblowałem sobie funkcje, które napisełem w C i widzę, że floaty trafiają do rejestrów xmm0, ..., xmm15, a nie rdi, rsi, rdx itd.
Edit: Czy FPU się jeszcze używa? Czy nie warto tego się uczyć i może warto od razu zacząć MMX/SSE1-5/AVX? |
|
j23 |
» 2016-01-01 20:40:44 Z tego co wyczytałem w internetach, w aplikacjach 64-bitowych obliczenia wykonuje się z wykorzystaniem instrukcji SSE. Nie wiem, czy to wymóg, czy po prostu korzystanie z wygodniejszego rozwiązania. Na 32-bitowych procesorach też możesz używać SSE do obliczeń FP, tyle tylko że nie każdy procesor 32-bitowy ma SSE. |
|
Sarth Temat założony przez niniejszego użytkownika |
» 2016-01-02 00:33:10 OK, SSE już zaczynam powoli ogarniać. Napisałem kilka wmiarę prostych funkcji i działają. Jednak mam teraz problem z C. Mam strukturę: typedef struct { unsigned char blue; unsigned char green; unsigned char red; } Rgb;
I mam taki kod: unsigned char fa = 'a', fb = 'b'; float fc = 0.5; printf( "%d %d %f\n", fa, fb, fc );
unsigned char * f1 = & fa, * f2 = & fb;
fun( f1, f2, fc ); printf( "%d %d %f\n", fa, fb, fc ); printf( "%d %d %f\n", * f1, * f2, fc );
Funkcja fun napisana w x86 działa, robi to co chciałem. Ale niestety dalej mam kawałek kodu, który nie działa tak jak chcę. Rgb * pixel1 =( Rgb * ) malloc( sizeof( Rgb ) ); Rgb * pixel2 =( Rgb * ) malloc( sizeof( Rgb ) );
fun( & pixel1->blue, & pixel2->blue, 0.5 ); fun( & pixel1->green, & pixel2->green, 0.5 ); fun( & pixel1->red, & pixel2->red, 0.5 );
Argumenty są tego samego typu zarówno przy pierwzym wywołaniu funkcji, jak i przy kolejnych, ale tylko w pierwszym przypadku funkcja wypisuje to czego oczekiwałem. Podaję złe argumenty, czy coś innego robię źle? Kod w x86 raczej musi być dobry, bo przy pierwszym wywołaniu wszysytko działa prawidłowo. Nie mogę zlokalizować błędu, chyba już zmęczony jestem :) |
|
j23 |
» 2016-01-02 10:22:44 W pierwszym kodzie argumenty mają przypisane wartości (fa i fb), w drugim jedynie tworzysz dwie struktury. Więc czego oczekiwałeś? |
|
Sarth Temat założony przez niniejszego użytkownika |
» 2016-01-02 11:22:31 Przepraszam, zapomniałem dodać wszysstkie ważne części kodu. if( fread( pixel1, 1, sizeof( Rgb ), inFile1 ) != sizeof( Rgb ) ) return - 1;
if( j < info2.height && i < info2.width && fread( pixel2, 1, sizeof( Rgb ), inFile2 ) != sizeof( Rgb ) ) return - 1;
W tym samym pliku mam funkcje w C, które operują na bitmapach, a więc raczej operacje wczytywania i zapisywania pikseli są dobrze zrealizowane. Później postaram się przerobić program na wczytywanie nie poszczególnych pikseli, ale od razu całych obrazków - tak jest chyba efektywniej? Edit: Dopisałem jeszcze taki test: char tab[] = "zzzzzz"; char tba[] = "xxxxxx"; char * pix1 =( char * ) malloc( sizeof( char ) * 7 ); char * pix2 =( char * ) malloc( sizeof( char ) * 7 ); pix1 = tab; pix2 = tba; int v; for( v = 0; v < 6; v++, pix1++, pix2++ ) { fun( pix1, pix2, 0.5 ); printf( "%s\n%s\n\n", tab, tba ); }
Też działa prawidłowo... Edit2: Przejrzałem przed chwilą mój kod i już wiem dlaczgo przetwarzanie ciągów znaków skłądających się z liczb i liter alfabetu mi działa. Bo wszystie są kodowane w ASCII liczbą mniejszą niż 128. Ponadto składowe pikseli mniejsze niż 128 też są dobrze przetwarzane w moich asemblerowych funkcjach. Tylko nie za bardzo wiem dlaczego jest problem z tym najstarszym bitem? Jako argumenty podaję unsigned char , więc bitu znaku nie ma. Edit3: Temat do zamknięcia. Znalazlem rozwiązanie problemu: w dwóch miejscach używałem instrukcji movsx , zamiast movzx . Eh... cięzkie są początki nauki programowania w x86, szczególnie, gdy ostatnio miało się styczność głównie z Javą. |
|
j23 |
» 2016-01-02 18:37:20 Może i działa, ale masz tu błąd, a dokładniej wyciek pamięci ;) char * pix1 =( char * ) malloc( sizeof( char ) * 7 ); char * pix2 =( char * ) malloc( sizeof( char ) * 7 ); pix1 = tab; pix2 = tba;
|
|
|
« 1 » 2 |