🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.asm
Article #993

x86 - błąd przy ładowaniu liczby zmiennoprzecinkowej

#993
From: Lech Lorens
Date: Wed, 14 Feb 2007 01:18
140 lines
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-mail

Show 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