Obsuga FPU - pobranie wartości ze stosu

Obsuga FPU - pobranie wartości ze stosu
N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

Mam problem z pobraniem wartości ze stosu FPU. Program działa jako wywołanie funkcji "dodawanie" w pliku .c
Potrzebuję wynik operacji pobrany ze stosu zapisać do eax, ale mam problem z naruszeniem ochrony pamięci.
Składnia AT&T, Linux x86

Kopiuj
.section .data
liczba1: .int 1

liczba2: .int 1

liczba3: .double 1

.section .text

.global dodawanie

dodawanie:

push %rbp
mov %rsp, %rbp

mov %rdi, (liczba1)
mov %rsi, (liczba2)

finit
fild (liczba1)
fild (liczba2)

faddp %st, %st(1)

fstp (%eax)

leaveq
retq

Próbowałam zapisać do liczba3 i potem do eax, ale wtedy z kolei wyrzuca losową wartość.

Kopiuj
fstp (liczba3)
mov $liczba3, %eax

Wynik dodawania na stosie jest poprawny, problem jest z pobraniem wartości.
Będę bardzo wdzięczna za pomoc.

edytowany 1x, ostatnio: nitka91
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 9 godzin
0

liczba typu double jest 64-bitowa i nie zmieści się w 32-bitowym rejestrze eax.
Po co w ogóle chcesz to robić?

edytowany 1x, ostatnio: Azarien
OA
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 10 lat
  • Postów:95
0

Przecież nie można napisać fstp (zwykły rejestr), bo nawet nie ma takiej instrukcji. Możesz spokojnie zwrócić wartość przez st0.

N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

Jestem bardzo początkująca i nie wiedziałam, że można przekazywać wartość przez inny rejestr.
Musze poszukać jak to zrobić, dziękuje za odpowiedzi, może już sobie poradzę:)

OA
Tylko, że dalej nie wiadomo co tak naprawdę chcesz zrobić. Jeżeli chodzi tylko o zwrócenie wartości z funkcji, to wykorzystaj st0 (tak się robi m.in. w języku C).
N9
Mam plik main.c gdzie mam wywołanie funkcji suma=dodawanie(liczba1, liczba2) i chodzi mi tylko właśnie a zwrócenie wartości tej sumy.
Bartosz Wójcik
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 4 lata
  • Postów:439
1

Zobacz sobie tutorial na http://www.website.masmforum.com/tutorials/fptute/index.html sam z niego często korzystałem, fajnie i prosto wyjaśnione korzystanie z FPU.

OA
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 10 lat
  • Postów:95
0

Przykładowy test pod win32:

Kopiuj
/* main.c */

#include <stdio.h>

extern double fpu_test();

int main(void) {
    printf("wynik = %lf\n", fpu_test());
    return 0;
}
Kopiuj
; fpu_test.asm

global _fpu_test

section .text

_fpu_test:
    fld1
    ret
Kopiuj
> nasm -f win32 fpu_test.asm
> gcc main.c fpu_test.obj
> a.exe
wynik = 1.000000
edytowany 2x, ostatnio: flowCRANE
N9
Czyli po załadowaniu na stos 1 to powinien zwrócić ją jako wartość funkcji?
OA
Tak. Dodałem wynik wykonania do postu.
N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

To ja już nie rozumiem... Przerobiłam pliki tylko żeby przetestować:

Kopiuj
 #include <stdio.h>
extern double dodawanie();
int main()
{
	printf("Wynik to %lf\n",dodawanie());
	return 0;
}
Kopiuj
.global dodawanie
.section .text
dodawanie:
finit
fld1
ret

I wyrzuca mi wynik 0. A gdy jeszcze miałam wczytywanie liczb (bez przekazywania ich do "dodawanie") to wyrzucał drugą wczytaną liczbę.

Kopiuj
	.file	"zad2.c"
	.section	.rodata
.LC0:
	.string	"Wynik to %lf\n"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	movq	%rsp, %rbp
	.cfi_offset 6, -16
	.cfi_def_cfa_register 6
	movl	$0, %eax
	call	dodawanie
	movl	$.LC0, %eax
	movq	%rax, %rdi
	movl	$1, %eax
	call	printf
	movl	$0, %eax
	leave
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
	.section	.note.GNU-stack,"",@progbits
edytowany 1x, ostatnio: nitka91
OA
Wklej wynik działania gcc -c -S main.c (pojawi się plik main.s). Zobaczymy czego oczekuje kompilator.
OA
Kompilujesz main.c na x86-64. Nic dziwnego, że nie działa. Musisz skompilować na architekturę 32-bitową. Spróbuj dodać opcję -m32 do gcc. Ewentualnie można zmienić kod assembly na 64-bitowy.
N9
Zupełnie o tym zapomniałam, żeby zmienić kompilację. Ale nie wpadłabym na to, że to jest problemem. Bardzo dziękuję:) Przykład z fld1 już działa, moja wersja z fild (liczba1) jeszcze nie (nadal wyrzuca 0), ale to pewnie jakiś nowy problem (może przepisanie z %esi), zaraz będę sprawdzać rejestry. EDIT. %esi i %edi wchodzą puste do funkcji.
Azarien
w x86-64 wartość typu double jest zwracana w rejestrze xmm0, więc nic dziwnego że nie działało.
OA
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 10 lat
  • Postów:95
1

Pamiętaj o tym, że argumenty przekazywane są przez stos. Dodawanie można zaimplementować tak:

Kopiuj
; double dodawanie(double x, double y);
; [RET]  [x]  [y]
;        ^4   ^12
_dodawanie:
    fld  qword [esp+4]
    fadd qword [esp+12]
    ret
edytowany 1x, ostatnio: Oak
N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

Działa :) Bardzo, bardzo dziękuję:)
(jedyna różnica to adres esp+8, zamiast esp+12 działa w moim przypadku)

Kopiuj
.section .text

.global dodawanie

dodawanie:

finit
fild 8(%esp)
fild 4(%esp)
faddp %st, %st(1)

ret

Po zamianie na:

Kopiuj
finit
fldl 12(%esp)
fldl 4(%esp)
halo:

Break przy halo
st0 6.3659873738839482370166397329427641e-314 (raw 0x3beec000000080000000)
st1 4.8535791833262006676910555829069706e-270 (raw 0x3c80a41a87fffede4000)

Przed finit
st0 0 (raw 0x00000000000000000000)
st1 0 (raw 0x00000000000000000000)

Kopiuj
 #include <stdio.h>
extern double dodawanie(int liczba1, int liczba2);
extern double odejmowanie(int liczba1, int liczba2);
extern double mnozenie(int liczba1, int liczba2);
extern double dzielenie(int liczba1, int liczba2);

int main()
{
	double a,b,c;
	char znak;
	printf ("Podaj znak operacji\n");
	scanf("%c",&znak);
	printf ("Podaj liczbe\n");
	scanf("%lf",&a);
	printf ("Podaj liczbe\n");
	scanf("%lf",&b);
	switch(znak)
	{
		case '+':c=dodawanie(a,b);break;
	}
	printf("Wynik to %lf\n",c);
	return 0;

}
edytowany 2x, ostatnio: nitka91
Zobacz pozostały 1 komentarz
N9
Coś nie do końca dobrze mam;/ Ale faktycznie fild nie łapie ułamkowych, więc musiałabym coś zmienić. W poście wartości z st(0) i st(1).
OA
A stos przed finit? Jeszcze wklej plik .c.
N9
Dodałam. Dla fild działa dobrze (pomijając obcięcie ułamka)
OA
Twoje funkcje w C przyjmują inty. :D
N9
Moje nieogarnięcie czasami sprawia, że umieram ze wstydu... :(
N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

Mam jeszcze problem z inną wersją tego programu, użyciem scanf w pliku .s
O ile printf działa dobrze, to nie potrafię pobrać scanf wartości wpisywanej liczby. Docelowo próbowałam zapisać ją do liczba1 i liczba2, do rejestrów, ale coś chyba robię źle. We wrzuconej wersji wyrzuca wyniki liczbowe, ale zupełnie bez sensu.

Kopiuj
SYSREAD=3
SYSWRITE=4
STDOUT=1
STDIN=0

.section .rodata

.liczba:
.string "Wynik to %f\n"

.pytanie1:
.string "Podaj liczbe\n"

.odczyt:
.string "%f"

.section .data

msg_pytanie3: .ascii "Podaj znak\n "
msg_pytanie3_len= . - msg_pytanie3

msg_znak: .ascii "+"
msg_znak_len= . - msg_znak

liczba1: .int 25

liczba2: .int 8

.text
.global main
main:

mov $SYSWRITE, %eax
mov $STDOUT, %ebx
mov $msg_pytanie3, %ecx
mov $msg_pytanie3_len, %edx

int $0x80

mov $SYSREAD, %eax
mov $STDIN, %ebx
mov $msg_znak, %ecx
mov $msg_znak_len, %edx

int $0x80

finit

subl $0x24, %esp

movl $.pytanie1, (%esp)

call printf 

pushl $liczba1         ;chodzi o ten moment
pushl $.odczyt

call scanf

popl %edx
popl (liczba1)

movl $.pytanie1, (%esp)

call printf 

pushl $liczba2
pushl $.odczyt

call scanf

popl %edx
popl (liczba2)

fild (liczba2)
fild (liczba1)

addl $0x24, %esp

mov $1, %ecx

mov $msg_znak, %ebx
movb -1(%ebx,%ecx, 1), %al

cmp $0x2B, %al
je dodawanie

dodawanie:
	faddp %st, %st(1)
	jmp koniec

koniec:
	subl $0x12, %esp
	fstpl 0x04(%esp)

movl $.liczba, (%esp)

call  printf

addl $0x12, %esp

xorl  %eax,%eax
ret

Make file jak coś (ale nie sądzę, żeby to był problem):

Kopiuj
 zad1: zad1.o
	gcc -m32 -o zad1 zad1.o
zad1.o:
	as -32 -o zad1.o zad1.s
edytowany 1x, ostatnio: nitka91
Bartosz Wójcik
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 4 lata
  • Postów:439
1

Nie trawię składni AT&T, ale scanf ma taki prototyp http://www.cplusplus.com/reference/cstdio/scanf/, więc wywołując scanf powinnaś zapisać na stosie offsety do zmiennych gdzie znajdą się wartości ze zdefiniowanego string-a formatującego, więc samo "pop liczba1" nie zwróci Ci tam żadnej wartości, bo ona już powinna tam być pod tą zmienną, te pop tylko zniszczy tą wartość, bo scanf to funkcja w konwencji cdecl i te 2x pop jedynie skorygują stos i sprawią, że nadpiszesz wartość pod zmienną liczba1

Reasumując - parametry dla scanf powinny zawierać offset do ciągu formatującego i offset do zmiennej liczba1, a po wywołaniu scanf daj tylko add esp,4*2 (rozmiar parametrów na stosie) i powinno być ok.

PS. Ciąg formatujący "%f" odpowiada za typ float, a ty pod liczba1 masz zdefiniowaną wartość typu int. Wprawdzie oba mają rozmiar 32 bitów, jednak to inny typ danych.

edytowany 3x, ostatnio: Bartosz Wójcik
N9
Dziękuję, wszystko działa:)
N9
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:7
0

Mam nadzieję, że to już ostatnie moje pytanie w tym temacie.
Chcę ustawić bity RC w słowie kontrolnym (11 i 10) dla wyboru rodzaju zaokrąglania. I po dodaniu danego fragmentu kodu pojawia mi się problem z naruszeniem ochrony pamięci.

Kopiuj
finit

subl $0x12, %esp

fnstcw (%esp)

movl %esp, %eax      

or $3072, %eax

movl %eax, %esp      
          
fldcw (%esp) 

addl $0x12, %esp 

Dokładnie rzecz biorąc problematyczna jest środkowa linijka:

Kopiuj
movl %eax, %esp  

bez niej wszystko jest w porządku (jeśli chodzi o naruszenie ochrony pamięci).
Próbowałam wersji z:

Kopiuj
pushl %eax
addl $0x04, (%esp)

ale tu z kolei po pushl i sprawdzeniu rejestru esp, nie ma tam przepisanej wartości z eax.
Będę wdzięczna za pomoc.

Bartosz Wójcik
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 4 lata
  • Postów:439
0

cofasz stos o 18 bajtów, być może chodzi o ochronę pamięci i pisanie po adresie niewyrównanym do 4-ki, spróbuj cofnąć o wartość, która jest wielokrotnością 4-ki, czyli w tym wypadku 16, w przeciwnym wypadku zostaje debugger, z którym trzeba się zaprzyjaźnić pisząc w assemblerze

N9
Poprawiłam na 16 i przy okazji znalazłam, że dalej w programie miałam jakieś nierówne subl i addl, ogólnie już ok:) EDIT: Jednak nie, szukam dalej;/
N9
Już cała obsługa tego przestała działać, bo wyrzuca naruszenia nawet przy tylko fnstcw i fldcw. Coś namieszałam.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)