Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[x86-64] Problem z liczbami zmiennoprzecinkowymmi

Ostatnio zmodyfikowano 2016-01-03 21:31
Autor Wiadomość
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:
C/C++
extern void fun( unsigned char * a, unsigned char * b, float c );

C/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.

P-142606
j23
» 2015-12-31 11:40:03
A debuggera używasz?

Staraj się usuwać niepotrzebne wartości ze stosu FPU:
...
fmulp
fstp QWORD[ rdi ]
P-142625
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?
P-142659
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.
P-142667
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ę:
C/C++
typedef struct
{
    unsigned char blue;
    unsigned char green;
    unsigned char red;
} Rgb;

I mam taki kod:
C/C++
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ę.
C/C++
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 :)
P-142674
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ś?
P-142682
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.
C/C++
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:
C/C++
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ą.
P-142684
j23
» 2016-01-02 18:37:20
Też działa prawidłowo...
Może i działa, ale masz tu błąd, a dokładniej wyciek pamięci ;)
C/C++
char * pix1 =( char * ) malloc( sizeof( char ) * 7 );
char * pix2 =( char * ) malloc( sizeof( char ) * 7 );
pix1 = tab; // to nie jest równoznaczne z kopiowaniem danych z tab do pix1, tu przypisujesz wskaźnik ;)
pix2 = tba; // jw.
P-142716
« 1 » 2
  Strona 1 z 2 Następna strona