Article View: pl.comp.lang.asm
Article #993x86 - błąd przy ładowaniu liczby zmiennoprzecinkowej
From: 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
Technical Details
Message-ID:
<slrnet4ocd.7io.lech_lorens@neo.zion>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mailShow Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail From: Lech Lorens <lech_lorens@spam.is.not.wel.com> Newsgroups: pl.comp.lang.asm Subject: x86 - błąd przy ładowaniu liczby zmiennoprzecinkowej Date: Wed, 14 Feb 2007 01:18:37 +0000 (UTC) Organization: "Portal Gazeta.pl -> http://www.gazeta.pl" Lines: 140 Message-ID: <slrnet4ocd.7io.lech_lorens@neo.zion> NNTP-Posting-Host: dts110.neoplus.adsl.tpnet.pl Mime-Version: 1.0 X-Trace: inews.gazeta.pl 1171415917 13380 83.22.0.110 (14 Feb 2007 01:18:37 GMT) X-Complaints-To: usenet@agora.pl NNTP-Posting-Date: Wed, 14 Feb 2007 01:18:37 +0000 (UTC) X-User: llorens User-Agent: slrn/0.9.8.1pl1 (Debian) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit