Thread View: pl.comp.lang.asm
1 messages
1 total messages
Started by Lech Lorens
Wed, 14 Feb 2007 01:18
x86 - błąd przy ładowaniu liczby zmiennoprzecinkowej
Author: Lech Lorens
Date: Wed, 14 Feb 2007 01:18
Date: Wed, 14 Feb 2007 01:18
140 lines
3811 bytes
3811 bytes
Mam program w C:
#v+
#include <stdio.h>
unsigned square_roots(double, double, double, double*, double*);
void display_roots(unsigned n, double r1, double r2)
{
switch(n)
{
case 2:
printf("(%lf, %lf)\n", r1, r2);
break;
case 1:
printf("(%lf)\n", r1);
break;
default:
printf("()\n");
break;
}
}
int main(int argc, char **argv)
{
unsigned nroots;
double r1, r2;
r1 = r2 = 0;
nroots = square_roots(4.0, 0.0, -16.0, &r1, &r2);
printf("nroots = %u\n", nroots);
display_roots(nroots, r1, r2);
nroots = square_roots(1.0l, 8.0l, 16.0l, &r1, &r2);
printf("nroots = %u\n", nroots);
display_roots(nroots, r1, r2);
return 0;
}
#v-
Program przy pomocy funkcji square_roots() liczy pierwiastki równania
kwadratowego. Te pierwiastki są zapisywane w zmiennych r1 i r2. Funkcja
square_roots() jest napisana w asemblerze x86 (w osobnym pliku):
#v+
section .data
MinusFour dw -4
section .text
global square_roots
; unsigned square_root(double a, double b, double c, double *r1, double *r2);
; liczy pierwiastki równania kwadratowego a*x^2 + b*x + c = 0
; zwraca liczbę różnych rzeczywistych pierwiastków
%define a qword [ebp + 8]
%define b qword [ebp + 16]
%define c qword [ebp + 24]
square_roots:
push ebp
mov ebp, esp
sub esp, 16
fild word [MinusFour]
fld a
fld c ; c, a, -4
fmulp st1 ; c * a
fmulp st1 ; -4 * a * c
fld b ; b, -4 * a * c
fmul st0
faddp st1 ; b * b - 4 * a * c
ftst
fstsw ax
sahf
ja two_roots
je single_root
jmp no_roots
two_roots:
fsqrt
fst qword [ebp - 8] ; załaduj wyróżnik do ebp - 8
fld1
fld a
fscale
fst qword [ebp - 16]
fld b
fchs
fsub qword [ebp - 8]
fdiv qword [ebp - 16]
mov eax, [ebp + 32] ; adres zmiennej r1 do eax
fst qword [eax]
fld b
fchs
fadd qword [ebp - 8]
fdiv qword [ebp - 16]
mov eax, [ebp + 36] ; adres zmiennej r2 do eax
fst qword [eax]
mov eax, 2
jmp end_square_roots
single_root:
fld1
fld a
fscale
fld b ; PROBLEM - ładuje się NaN
fchs
fdiv st1
mov eax, [ebp + 32] ; adres zmiennej r1 do eax
fst qword [eax]
mov eax, [ebp + 36] ; adres zmiennej r2 do eax
fst qword [eax]
mov eax, 1
jmp end_square_roots
no_roots:
xor eax, eax
end_square_roots:
mov esp, ebp
pop ebp
ret
#v-
Wynik dla pierwszego wywołania square_roots() jest poprawny - zostają
wyliczone dwa pierwiastki: -2.0 i 2.0. Wynik dla drugiego wywołania nie
jest poprawny - do zmiennych r1 i r2 zostaje przypisane NaN. Dzieje się
tak dlatego, że instrukcja fld b z linii oznaczonej komentarzem
"PROBLEM" powoduje załadowanie do rejestru st0 NaN.
Program w C kompiluję przy pomocy gcc 4.1, plik w asemblerze asembluję
przy pomocy NASM-a. Debugowałem program przy pomocy gdb, oczywiście pod
adresem, z którego jest odczytywana liczba znajduje się poprawna wartość
(8.0).
Co robię źle? Z góry dziękuję za pomoc!
--
Pozdrawiam,
Lech Lorens - lp.pw@snerol_hcel
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads