Thread View: pl.comp.lang.asm
27 messages
27 total messages
Started by MrokU
Sat, 23 May 2009 18:14
Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sat, 23 May 2009 18:14
Date: Sat, 23 May 2009 18:14
17 lines
1805 bytes
1805 bytes
Witam, zupełnie nie znam asemblera, a muszę napisać bibliotekę dll, służącą do interpolacji algorytmem Goertzel`a. Wymyśliłem sobie, żeby do biblioteki przekazywać listę / tablicę węzłów interpolacji (czyli punktów, w których funkcja wyjściowa i wejściowa muszą się zgadzać) i dla nich wyliczać wartość funkcji interpolującej. Czy ktoś może mi podpowiedzieć od czego w ogóle zacząć, podrzucić jakieś tutoriale do tworzenia bibliotek dll, wymiany danych między C/C+ + i biblioteką dll w asmie? Ewentualnie, czy ktoś, kto się na tym zna byłby skory coś takiego napisać? pozdrawiam
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Sun, 24 May 2009 09:17
Date: Sun, 24 May 2009 09:17
21 lines
1796 bytes
1796 bytes
MrokU pisze: > Witam, > zupełnie nie znam asemblera, a muszę napisać bibliotekę dll, służącą > do interpolacji algorytmem Goertzel`a. > > Wymyśliłem sobie, żeby do biblioteki przekazywać listę / tablicę > węzłów interpolacji (czyli punktów, w których funkcja wyjściowa i > wejściowa muszą się zgadzać) i dla nich wyliczać wartość funkcji > interpolującej. > > Czy ktoś może mi podpowiedzieć od czego w ogóle zacząć, podrzucić > jakieś tutoriale do tworzenia bibliotek dll, wymiany danych między C/C+ > + i biblioteką dll w asmie? Odpowiedziano na forum. -- Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS) Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32 www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sun, 24 May 2009 10:07
Date: Sun, 24 May 2009 10:07
6 lines
1516 bytes
1516 bytes
Wiem, widziałem już. Pozostaje jeszcze pytanie, czy ktoś osobiście (lub znajomi) robi tego typu projekty, że tak powiem odpłatnie? pozdrawiam
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan
Date: Mon, 25 May 2009 01:42
Date: Mon, 25 May 2009 01:42
12 lines
1242 bytes
1242 bytes
Użytkownik "Bogdan (bogdro)" napisał: > Odpowiedziano na forum. Na jakim forum? Można prosić o oświecenie mnie? Do MrokU: Parę DLL-ek pod Windows w asemblerze napisałem. Mogę co nieco podpowiedzieć. Mój e-mail z nagłówka jest fałszywy. To tak na wszelki. Remek
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Mon, 25 May 2009 15:23
Date: Mon, 25 May 2009 15:23
121 lines
4235 bytes
4235 bytes
To może tak:
wkleję tutaj kod, który mi działa, ale zapewne wiele rzeczy jest
nieoptymalnie, niefajnie, etc.
Czy ktoś może rzucić na to okiem i powiedzieć co i jak robić lepiej?
pozdrawiam.
-----------------------------------------------------------------------------------------------------------------
KOD DLL:
.586
.387
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE .\masm32\include\windows.inc;
INCLUDE .\masm32\include\user32.inc
INCLUDE .\masm32\include\kernel32.inc
INCLUDELIB .\masm32\lib\user32.lib
INCLUDELIB .\masm32\lib\kernel32.lib
.DATA
.CODE
DllEntry PROC hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax, TRUE
ret
DllEntry ENDP
;***************************************************************
;****** Procedura testowa ***** dodawanie
sumuj PROC a: DWORD , b: DWORD
pushad
mov eax, a
add b, eax
popad
mov eax, b
ret ;koniec funkcji
sumuj ENDP
;***************************************************************
;****** Procedura testowa ***** odejmowanie
odejmuj PROC a: DWORD , b: DWORD
pushad
mov eax, a
sub b, eax
popad
mov eax, b
ret ;koniec funkcji
odejmuj ENDP
;***************************************************************
;****** Procedura testowa ***** HARDCORE - sinus()
sinus PROC kat:DQ;, wynik:PTR
pushad
finit
fld kat ; wczytanie zmiennej do rejestru st0
fsin
fst kat
popad
mov eax, kat
ret ;koniec funkcji
sinus ENDP
END DllEntry
-----------------------------------------------------------------------------------------------------------------
KOD C++:
#include <windows.h>
#include <stdio.h>
#include <iostream>
#define PI
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
//---------------------------------------------------------------------------
typedef int (__stdcall *MYPROC)(int, int);
typedef float (__stdcall *MYPROC2)(float);
MYPROC ProcAdd, ProcSub;
MYPROC2 ProcSin;
HINSTANCE hinstLib;
int a, b;
float d;
int main(int argc, char* argv[])
{
hinstLib = LoadLibrary ("DLLint.dll"); //ladowanie biblioteki
if (hinstLib == NULL) //sprawdzenie, czy moduł faktycznie
został załadowany
return 1;
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "sumuj");
if (NULL != ProcAdd)
a = (ProcAdd)(9,2);
ProcSub = (MYPROC) GetProcAddress(hinstLib, "odejmuj");
if (NULL != ProcAdd)
b = (ProcSub)(2,9);
ProcSin = (MYPROC2) GetProcAddress(hinstLib, "sinus");
if (NULL != ProcAdd)
d = (ProcSin)(PI / 6); // sinus 30 stopni
FreeLibrary(hinstLib);
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << d << std::endl;
system("PAUSE");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
pozdrawiam.
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Mon, 25 May 2009 15:30
Date: Mon, 25 May 2009 15:30
2 lines
1524 bytes
1524 bytes
No a to forum, to http://profesor.niesfornazyta.pl/viewtopic.php?f=84&t=151&sid=19e22332db7f7e7749ca37199d4d60f2
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Mon, 25 May 2009 15:35
Date: Mon, 25 May 2009 15:35
19 lines
1476 bytes
1476 bytes
Bogdan pisze: > Użytkownik "Bogdan (bogdro)" napisał: > >> Odpowiedziano na forum. > > Na jakim forum? Można prosić o oświecenie mnie? Oczywiście: http://profesor.niesfornazyta.pl/ [...] > Remek Podpisujesz się na raz "Remek" i "Bogdan"? -- Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS) Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32 www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Mon, 25 May 2009 16:05
Date: Mon, 25 May 2009 16:05
110 lines
4415 bytes
4415 bytes
MrokU pisze:
> To może tak:
> wkleję tutaj kod, który mi działa, ale zapewne wiele rzeczy jest
> nieoptymalnie, niefajnie, etc.
> Czy ktoś może rzucić na to okiem i powiedzieć co i jak robić lepiej?
> pozdrawiam.
[...]
> ;****** Procedura testowa ***** dodawanie
>
> sumuj PROC a: DWORD , b: DWORD
> pushad
> mov eax, a
> add b, eax
> popad
> mov eax, b
> ret ;koniec funkcji
> sumuj ENDP
Możesz nie pisać PUSHAD i POPAD, bo używasz tylko rejestru EAX, który
nie tylko można dowolnie zmieniać, ale przy wyjściu zawiera wynik.
Podobnie w kilku innych procedurach.
> ;****** Procedura testowa ***** HARDCORE - sinus()
>
> sinus PROC kat:DQ;, wynik:PTR
> pushad
> finit
> fld kat ; wczytanie zmiennej do rejestru st0
> fsin
> fst kat
> popad
> mov eax, kat
> ret ;koniec funkcji
> sinus ENDP
Oj, tu niedobrze. Pomijając PUSHAD/POPAD, wykonywanie FINIT może być
dość kosztowne czasowo i raczej powinno się to robić tylko raz, przy
starcie programu (chyba że naprawdę potrzebny jest reset). Większy
problem jest w tym, że wkładasz coś na stos i nie zdejmujesz - po 8
uruchomieniach się przepełni (pewnie dlatego robiłeś FINIT). Zamiast
FST użyj FSTP. Nawet jeśli nigdzie indziej nie używasz koprocesora,
rób tak dla zasady.
Swoją drogą, chyba "wynik" jest od tego, by otrzymać wynik, a nie "kat"?
> #include <windows.h>
> #include <stdio.h>
> #include <iostream>
> #define PI
> 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
Czemu nie użyjesz stałych "firmowych" (jeśli są dostępne, oczywiście)?
#include <math.h>
#ifndef M_PI
#define M_PI 3.141592653589793238462643383279502884197 blablabla...
#endif
> //---------------------------------------------------------------------------
>
> typedef int (__stdcall *MYPROC)(int, int);
> typedef float (__stdcall *MYPROC2)(float);
>
> MYPROC ProcAdd, ProcSub;
> MYPROC2 ProcSin;
> HINSTANCE hinstLib;
> int a, b;
> float d;
>
> int main(int argc, char* argv[])
> {
> hinstLib = LoadLibrary ("DLLint.dll"); //ladowanie biblioteki
> if (hinstLib == NULL) //sprawdzenie, czy moduł faktycznie
> został załadowany
> return 1;
>
> ProcAdd = (MYPROC) GetProcAddress(hinstLib, "sumuj");
> if (NULL != ProcAdd)
> a = (ProcAdd)(9,2);
Formalnie to pewnie powinno być
a = (*ProcAdd)(9,2);
jako że "ProcAdd" jest wskaźnikiem. Ale jak działa, to dobrze.
[...]
> d = (ProcSin)(PI / 6); // sinus 30 stopni
W tym błędu nie ma, ale jak będziesz potrzebował szybkiego działania,
używaj stałych, bez obliczeń, np.
#define M_PI_6 0.5235987755982988527 /* M_PI / 6 */
d = (*ProcSin)(M_PI_6);
aby od razu przekazywać parametr do funkcji, bez zbędnych obliczeń na
stałych (a na przykład dzielenie jest akurat kosztowne).
Pewnie mądry kompilator i tak by tu wstawił stałą, ale co jeśli nie?
Tyle ja zauważyłem na pierwszy rzut oka. Może ktoś jeszcze coś dołoży.
--
Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS)
Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro
Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32
www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Mon, 25 May 2009 20:34
Date: Mon, 25 May 2009 20:34
45 lines
3693 bytes
3693 bytes
> Możesz nie pisać PUSHAD i POPAD, bo używasz tylko rejestru EAX, który > nie tylko można dowolnie zmieniać, ale przy wyjściu zawiera wynik. No właśnie muszę używać, bo Visual mi się pluje, że coś robię nie tak z rejestrem ESI. Nie wiem o co chodzi, ale jak te instrukcje dodam, to żadnych błędów mi nie wyrzuca... > Oj, tu niedobrze. Pomijając PUSHAD/POPAD, wykonywanie FINIT może być > dość kosztowne czasowo i raczej powinno się to robić tylko raz, przy > starcie programu (chyba że naprawdę potrzebny jest reset). Większy > problem jest w tym, że wkładasz coś na stos i nie zdejmujesz - po 8 > uruchomieniach się przepełni (pewnie dlatego robiłeś FINIT). Zamiast > FST użyj FSTP. Nawet jeśli nigdzie indziej nie używasz koprocesora, > rób tak dla zasady. > Swoją drogą, chyba "wynik" jest od tego, by otrzymać wynik, a nie "kat"? o FINIT nie wiedziałem. Jak na razie to jedyna funkcja, która używa liczb zmiennoprzecinkowych, ale domyślnie będzie to działało tak, że jedna duża funkcja będzie liczyła interpolację dla danego punktu, w związku z tym FINIT będzie tylko raz (aczkolwiek to na razie plany). Wynik jest do tego, żeby sobie spróbować zwrócić wynik w inny sposób niż przez eax, ale jak na razie tego nie robiłem, bo nie do końca wiem jak :P chociaż pewnie trzeba przekazać wskaźnik i modyfikować adres. Tylko nie zastanawiałem się jeszcze jak to robić. > > #include <windows.h> > > #include <stdio.h> > > #include <iostream> > > #define PI > > 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 > > Czemu nie użyjesz stałych "firmowych" (jeśli są dostępne, oczywiście)? > > #include <math.h> > #ifndef M_PI > #define M_PI 3.141592653589793238462643383279502884197 blablabla... > #endif nie widziałem sensu dołączania całej biblioteki, skoro potrzebuję tylko PI (chociaż jak już mówiłem, to są dopiero próby i przymierzanie się do pisania programu). No a z liczeniem sinusa 30 stopni, to nie ma sensu robić to z #define, bo nie będę liczył stałych wartości kątów. Wszystko leci na wzorach i będzie wyliczane na bieżąco.
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Remek
Date: Mon, 25 May 2009 21:13
Date: Mon, 25 May 2009 21:13
9 lines
1302 bytes
1302 bytes
Użytkownik "Bogdan (bogdro)" napisał: > Podpisujesz się na raz "Remek" i "Bogdan"? Nie do końca. Podpis był mój, ale gościnnie skorzystałem z innego komputera i konta, zapominając o skutkach. Przepraszam za zamieszanie. Nie powinno się powtórzyć. Pozdrawiam Remek
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Tue, 26 May 2009 00:45
Date: Tue, 26 May 2009 00:45
201 lines
8305 bytes
8305 bytes
A czy wiecie może, co może być skutkiem nagłej zmiany w Windowsach i
wysypu błędów?
Bo w pewnym momencie coś się VS odwidziało i kod, który się normalnie
kompilował, nagle wyrzuca coś takiego (dla pewności kompilowany kod):
-----------------------------------------------------------------------------------------------------------------
C++
#include <windows.h>
#include <stdio.h>
#include <iostream>
#define PI 3.1415926535897932
typedef int (__stdcall *MYPROC)(int, int);
typedef float (__stdcall *MYPROC2)(float);
MYPROC ProcAdd, ProcSub;
MYPROC2 ProcSin;
HINSTANCE hinstLib;
int a, b;
float d;
int main(int argc, char* argv[])
{
hinstLib = LoadLibrary ("DLLint.dll");//ladowanie biblioteki
if (hinstLib == NULL)//sprawdzenie, czy moduł faktycznie
został załadowany
return 1;
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "sumuj");
if (NULL != ProcAdd)
a = (ProcAdd)(9,2);
ProcSub = (MYPROC) GetProcAddress(hinstLib, "odejmuj");
if (NULL != ProcAdd)
b = (ProcSub)(2,9);
ProcSin = (MYPROC2) GetProcAddress(hinstLib, "sinus");
if (NULL != ProcAdd)
d = (ProcSin)(PI / 6); // sinus 30 stopni
FreeLibrary(hinstLib);
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << d << std::endl;
system("PAUSE");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
ASM
.586
.387
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE .\masm32\include\windows.inc;
INCLUDE .\masm32\include\user32.inc
INCLUDE .\masm32\include\kernel32.inc
INCLUDELIB .\masm32\lib\user32.lib
INCLUDELIB .\masm32\lib\kernel32.lib
.DATA
.CODE
DllEntry PROC hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax, TRUE
ret
DllEntry ENDP
;***************************************************************
;****** Procedura testowa ***** dodawanie
sumuj PROC a: DWORD , b: DWORD
pushad
mov eax, a
add b, eax
popad
mov eax, b
ret ;koniec funkcji
sumuj ENDP
;***************************************************************
;****** Procedura testowa ***** odejmowanie
odejmuj PROC a: DWORD , b: DWORD
pushad
mov eax, a
sub b, eax
popad
mov eax, b
ret ;koniec funkcji
odejmuj ENDP
;***************************************************************
;****** Procedura testowa ***** HARDCORE - sinus()
sinus PROC kat:DQ
pushad
finit
fld kat ; wczytanie zmiennej do
rejestru st0
fsin
fst kat
popad
mov eax, kat
ret ;koniec funkcji
sinus ENDP
END DllEntry
-----------------------------------------------------------------------------------------------------------------
DEF
LIBRARY DLLint
EXPORTS sumuj
EXPORTS odejmuj
EXPORTS sinus
-----------------------------------------------------------------------------------------------------------------
KOMPILACJA:
1>------ Rebuild All started: Project: interJA, Configuration: Debug
Win32 ------
1>Deleting intermediate and output files for project 'interJA',
configuration 'Debug|Win32'
2>------ Rebuild All started: Project: DLLint, Configuration: Debug
Win32 ------
2>Deleting intermediate and output files for project 'DLLint',
configuration 'Debug|Win32'
2>Assembling...
1>Compiling...
1>main.cpp
2> Assembling: .\DLLint.asm
2>.\DLLint.asm(1) : error A2044: invalid character in file
2>.\DLLint.asm(2) : error A2008: syntax error : .
2>.\DLLint.asm(4) : error A2008: syntax error : .
2>.\DLLint.asm(6) : error A2008: syntax error : P
2>.\DLLint.asm(8) : error A2109: only white space or comment can
follow backslash
2>.\DLLint.asm(10) : error A2109: only white space or comment can
follow backslash
2>.\DLLint.asm(12) : error A2109: only white space or comment can
follow backslash
2>.\DLLint.asm(14) : error A2109: only white space or comment can
follow backslash
2>.\DLLint.asm(16) : error A2109: only white space or comment can
follow backslash
2>.\DLLint.asm(19) : error A2008: syntax error : .
2>.\DLLint.asm(20) : error A2008: syntax error : .
2>.\DLLint.asm(22) : error A2008: syntax error : l
2>.\DLLint.asm(23) : error A2008: syntax error : m
2>.\DLLint.asm(24) : error A2008: syntax error : r
2>.\DLLint.asm(25) : error A2008: syntax error : D
2>.\DLLint.asm(30) : error A2008: syntax error : u
2>.\DLLint.asm(31) : error A2008: syntax error : p
2>.\DLLint.asm(32) : error A2008: syntax error : m
2>.\DLLint.asm(33) : error A2008: syntax error : a
2>.\DLLint.asm(34) : error A2008: syntax error : p
2>.\DLLint.asm(35) : error A2008: syntax error : m
2>.\DLLint.asm(36) : error A2008: syntax error : r
2>.\DLLint.asm(37) : error A2008: syntax error : s
2>.\DLLint.asm(42) : error A2008: syntax error : d
2>.\DLLint.asm(43) : error A2008: syntax error : p
2>.\DLLint.asm(44) : error A2008: syntax error : m
2>.\DLLint.asm(45) : error A2008: syntax error : s
2>.\DLLint.asm(46) : error A2008: syntax error : p
2>.\DLLint.asm(47) : error A2008: syntax error : m
2>.\DLLint.asm(48) : error A2008: syntax error : r
2>.\DLLint.asm(49) : error A2008: syntax error : o
2>.\DLLint.asm(54) : error A2008: syntax error : i
2>.\DLLint.asm(55) : error A2008: syntax error : p
2>.\DLLint.asm(56) : error A2008: syntax error : f
2>.\DLLint.asm(57) : error A2008: syntax error : f
2>.\DLLint.asm(58) : error A2008: syntax error : f
2>.\DLLint.asm(59) : error A2008: syntax error : f
2>.\DLLint.asm(60) : error A2008: syntax error : p
2>.\DLLint.asm(61) : error A2008: syntax error : m
2>.\DLLint.asm(62) : error A2008: syntax error : r
2>.\DLLint.asm(63) : error A2008: syntax error : s
2>.\DLLint.asm(65) : error A2008: syntax error : E
2>.\DLLint.asm(65) : error A2088: END directive required at end of
file
2>Project : error PRJ0019: A tool returned an error code from
"Assembling..."
1>c:\documents and settings\ala\desktop\interja\interja\main.cpp(33) :
warning C4305: 'argument' : truncation from 'double' to 'float'
2>Build log was saved at "file://c:\Documents and Settings\Ala\Desktop
\interJA\DLLint\Debug\BuildLog.htm"
2>DLLint - 44 error(s), 0 warning(s)
1>Compiling manifest to resources...
1>Linking...
1>LINK : C:\Documents and Settings\Ala\Desktop\interJA\Debug
\interJA.exe not found or not built by the last incremental link;
performing full link
1>Embedding manifest...
1>Build log was saved at "file://c:\Documents and Settings\Ala\Desktop
\interJA\InterJA\Debug\BuildLog.htm"
1>interJA - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Michal Schulz
Date: Tue, 26 May 2009 14:28
Date: Tue, 26 May 2009 14:28
9 lines
1037 bytes
1037 bytes
MrokU wrote: > zupełnie nie znam asemblera, a muszę napisać bibliotekę dll, Nie chce sie wtracac, ale co ma pisanie biblioteki dll wspolnego z assemblerem? ;) -- Michal Schulz
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Tue, 26 May 2009 15:11
Date: Tue, 26 May 2009 15:11
7 lines
1516 bytes
1516 bytes
Właściwie to poza tym, że biblioteka ma być napisana w ASMie, to nic :) PS. Spojrzał już ktoś może na te errory/ Bo kurde nie umiem sobie z tym poradzić... pozdr
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Remek
Date: Tue, 26 May 2009 16:01
Date: Tue, 26 May 2009 16:01
38 lines
1909 bytes
1909 bytes
Użytkownik "MrokU" napisał:
> Spojrzał już ktoś może na te errory/ Bo kurde nie
> umiem sobie z tym poradzić...
Nie używam VC, więc wyodrębniłem kod DLL-ki do MrokU.asm :)
Skompilowało się po usunięciu jednego błędu:
sinus PROC kat:DQ
Masm32 akurat nie rozumie tej deklaracji. Musiałem podać:
sinus PROC kat:QWORD
ale wówczas nie zgadza mu się linia:
mov eax, kat
ze względu na niezgodność rozmiarów operandów. Masm nie umie rzutować tak
jak HL-e. Dałem więc:
sinus PROC kat:DWORD
I teraz działa. Można również tak:
sinus PROC kat:QWORD
...
mov eax, dword ptr kat
Zależy co ma być wykorzystane. W tym przypadku do eax zostanie zapisany
"górny" dword. Nie analizoeałem szczegółowo tej procedurki, więc nie wiem
czy to wystarczy. Analizować "w locie" potrafi Bogdan.
Remek
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Tue, 26 May 2009 16:29
Date: Tue, 26 May 2009 16:29
9 lines
1664 bytes
1664 bytes
No MASMem też to kompilowałem i nie miał problemów... Tylko to zasrane VS mi się rzuca nie wiadomo o co... Więc to chyba nie jest kwestia samej składni, tylko środowiska... W czym jeszcze można robić tego typu projekty? W sensie C++ z ASMem, żeby się normalnie debugować dało i kompilować jako jeden projekt? pozdrawiam
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Tue, 26 May 2009 16:52
Date: Tue, 26 May 2009 16:52
50 lines
3550 bytes
3550 bytes
MrokU pisze: >> Możesz nie pisać PUSHAD i POPAD, bo używasz tylko rejestru EAX, który >> nie tylko można dowolnie zmieniać, ale przy wyjściu zawiera wynik. > > No właśnie muszę używać, bo Visual mi się pluje, że coś robię nie tak > z rejestrem ESI. Nie wiem o co chodzi, ale jak te instrukcje dodam, to > żadnych błędów mi nie wyrzuca... Aha. No skoro tak, to nie ruszaj. Bo właśnie EBX, EBP, ESI i EDI nie wolno ruszać (chyba że zachowa się i przywróci poprzednią wartość). >> Swoją drogą, chyba "wynik" jest od tego, by otrzymać wynik, a nie "kat"? > > o FINIT nie wiedziałem. Jak na razie to jedyna funkcja, która używa > liczb zmiennoprzecinkowych, ale domyślnie będzie to działało tak, że > jedna duża funkcja będzie liczyła interpolację dla danego punktu, w > związku z tym FINIT będzie tylko raz (aczkolwiek to na razie plany). > Wynik jest do tego, żeby sobie spróbować zwrócić wynik w inny sposób > niż przez eax, ale jak na razie tego nie robiłem, bo nie do końca wiem > jak :P chociaż pewnie trzeba przekazać wskaźnik i modyfikować adres. > Tylko nie zastanawiałem się jeszcze jak to robić. Jeśli "wynik" to adres zmiennej, to ładujesz go do rejestru, np. EAX, po czym wynik z FPU ładujesz do [EAX]. >> #include <math.h> >> #ifndef M_PI >> #define M_PI 3.141592653589793238462643383279502884197 blablabla... >> #endif > > nie widziałem sensu dołączania całej biblioteki, skoro potrzebuję > tylko PI (chociaż jak już mówiłem, to są dopiero próby i przymierzanie > się do pisania programu). To nie jest dołączanie biblioteki w sensie binarnym (chyba że środowisko/linker jest naprawdę tępy). To jest dołączanie pliku nagłówkowego, a biblioteka fizycznie powinna zostać dołączona do programu tylko jak są wywoływane z niej jakiekolwiek funkcje. > No a z liczeniem sinusa 30 stopni, to nie ma sensu robić to z #define, > bo nie będę liczył stałych wartości kątów. Wszystko leci na wzorach i > będzie wyliczane na bieżąco. OK, to była tylko porada w razie czego. -- Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS) Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32 www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Tue, 26 May 2009 16:52
Date: Tue, 26 May 2009 16:52
57 lines
3503 bytes
3503 bytes
MrokU pisze: > A czy wiecie może, co może być skutkiem nagłej zmiany w Windowsach i > wysypu błędów? > > Bo w pewnym momencie coś się VS odwidziało i kod, który się normalnie > kompilował, nagle wyrzuca coś takiego (dla pewności kompilowany kod): [...] > KOMPILACJA: > 1>------ Rebuild All started: Project: interJA, Configuration: Debug > Win32 ------ > 1>Deleting intermediate and output files for project 'interJA', > configuration 'Debug|Win32' > 2>------ Rebuild All started: Project: DLLint, Configuration: Debug > Win32 ------ > 2>Deleting intermediate and output files for project 'DLLint', > configuration 'Debug|Win32' > 2>Assembling... > 1>Compiling... > 1>main.cpp > 2> Assembling: .\DLLint.asm > 2>.\DLLint.asm(1) : error A2044: invalid character in file > 2>.\DLLint.asm(2) : error A2008: syntax error : . > 2>.\DLLint.asm(4) : error A2008: syntax error : . > 2>.\DLLint.asm(6) : error A2008: syntax error : P > 2>.\DLLint.asm(8) : error A2109: only white space or comment can > follow backslash > 2>.\DLLint.asm(10) : error A2109: only white space or comment can > follow backslash > 2>.\DLLint.asm(12) : error A2109: only white space or comment can > follow backslash > 2>.\DLLint.asm(14) : error A2109: only white space or comment can > follow backslash > 2>.\DLLint.asm(16) : error A2109: only white space or comment can > follow backslash Wygląda, jakby nie tego narzędzia używał, choć niby pisze "assembling". Cokolwiek zmieniłeś w opcjach projektu, cofnij to :) Sprawdź, czy kompiluje tym, co trzeba (nie wiem jak, nie pytaj - może wystarczy gdzieś włączyć opcję pokazującą wykonywane komendy). Sprawdź, czy opcje są dobre. Sprawdź, czy rozszerzenie jest dobre (w niektórych kompilatorach na przykład ".c" a ".C" robi różnicę). Bo wyglądałoby na to, że parsuje ten plik preprocesorem C, czego nie powinien robić. > 2>Build log was saved at "file://c:\Documents and Settings\Ala\Desktop > \interJA\DLLint\Debug\BuildLog.htm" > 2>DLLint - 44 error(s), 0 warning(s) Sprawdź, co napisał w tym pliku. -- Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS) Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32 www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Remek
Date: Tue, 26 May 2009 17:56
Date: Tue, 26 May 2009 17:56
20 lines
1988 bytes
1988 bytes
Użytkownik "MrokU" napisał: > No MASMem też to kompilowałem i nie miał problemów Taki kod jaki podałeś? I nie zgłosił błędów? Próbowałeś uzyc tej DLLki w jakims programie zrobionym w HLu? > W czym jeszcze można robić tego typu projekty? W sensie C++ z ASMem, > żeby się normalnie debugować dało i kompilować jako jeden projekt? Moim zdaniem normalne to jest robienie DLLi jako samodzielnych projektów. Przecież mają służyć wielu innym programom. No i jak asembler, to asembler, a nie HL. Nie jestem mocny w językach wyższego poziomu, ale wydaje mi się, że do kompilacji wstawek asemblerowych używają osobnych narzędzi np. produkty Borlana - Tama, MS - Masma. Niektóre umożliwiają wybór z wielu dostępnych (trzeba je wtedy doinstalować oddzielnie). I co to znaczy "normalnie debugować"? Remek
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Fri, 29 May 2009 17:49
Date: Fri, 29 May 2009 17:49
48 lines
3635 bytes
3635 bytes
W tym logu nie napisał nic ciekawego, to co wkleiłem plus informacje, że linkuje i jakie programy do tego odpala... Ale. Już wszystko działa, nie wiem czemu nagle mu się odwidziało... > Taki kod jaki podałeś? I nie zgłosił błędów? Próbowałeś uzyc tej DLLki w > jakims programie zrobionym w HLu? Nie no zgłosił błędy, ale po poprawieniu składni wszystko się skompilowało. DLLki używam w programie w C++. VS ma na tyle fajną możliwość, że możesz w jednym projekcie mieć 2 podprojekty - jeden z HL i jeden jako DLL w ASMie. > Moim zdaniem normalne to jest robienie DLLi jako samodzielnych projektów. > Przecież mają służyć wielu innym programom. No i jak asembler, to asembler, > a nie HL. Nie jestem mocny w językach wyższego poziomu, ale wydaje mi się, > że do kompilacji wstawek asemblerowych używają osobnych narzędzi np. > produkty Borlana - Tama, MS - Masma. Niektóre umożliwiają wybór z wielu > dostępnych (trzeba je wtedy doinstalować oddzielnie). I co to znaczy > "normalnie debugować"? No właśnie to jest DLLka, którą piszę na projekt na zaliczenie i ona domyślnie służy do tego, żeby nauczyć się robić takie rzeczy i jest dedykowana dla tego jednego programu. Zresztą jak będzie działać z jednym, to z resztą również. I nie chodzi tutaj o żadne wstawki, tylko o normalnego ASMa. Normalnie debugować... Chodziło mi o to, że jestem w stanie w jednym środowisku prześledzić kod w C++, przeskoczyć do DLL, prześledzić rejestry i wrócić z powrotem do głównego programu. No i teraz kolejne pytanie: mam napisać funkcję, która wywoływana jest rekurencyjnie i zwraca wartość double. Na razie zwracałem wartości zmiennoprzecinkowe tylko wpisując wynik pod adres podany jako zmienna wejściowa (tak jak napisał Bogdan). Generalnie wyliczać mam taki wzorek: U(k) = f(x) + 2 * U(k+1) * cos(B) - U(k+2) zresztą mniejsza o to, możecie podpowiedzieć, jak zrobić takie wywołanie rekurencyjne i zwrócenie wartości double przez funkcję? pozdrawiam
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sat, 30 May 2009 10:45
Date: Sat, 30 May 2009 10:45
108 lines
4715 bytes
4715 bytes
Na razie, po pierwszych próbach funkcja (oczywiście nie działa dobrze)
wygląda tak:
;******************************************************************
;****** Procedura obliczajaca pierwsze 2 wyrazy ciagu Un
;****** Wg wzoru:
;****** double U (int k, double beta, Element *tab) //obliczanie
wspólczynnika U - wzór 28
;****** {
;****** if ( k > n )
;****** return (0.0);
;****** else
;****** return (tab[k].f_x + (2.0) * ( U(k+1, beta, tab) * cosf
(beta) ) - U(k+2, beta, tab));
;****** }
;****** definicja elementu tablicy
;****** struct Element
;****** {
;****** double x;
;****** double f_x;
;****** double g_x;
;****** double blad;
;****** };
wspU PROC n:DWORD, k:DWORD, beta:PTR, tab:PTR
LOCAL t1:QWORD, t2:QWORD, t3:QWORD, t4:QWORD, temp:DWORD, tempptr:PTR
pushad
finit
mov eax, k
cmp eax, n ; if (k > n)
ja Zwroc0 ; return 0;
mov ebx, tab ; zaladowanie adresu tablicy
fld QWORD PTR [ebx+8] ; zaladowanie wartosci f(x)
fstp t1 ; zachowanie wartosci do zmiennej lokalnej, zwolnienie
stosu
mov ebx, beta ; zaladowanie adresu zmiennej beta (liczonej przez
funkcje "Beta(j, n)"
fld QWORD PTR [ebx] ; zaladowanie wartosci spod wskaznika beta
fcos ; cosinus (beta)
fadd st(0), st(0) ; 2 * cos (beta)
fstp t2 ; zachowanie powyzszej wartosci do lokalnej zmiennej
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
mov eax, tab ; zachowanie adresu tablicy
mov tempptr, eax
add tempptr, 32 ; przesuniecie sie do nastepnego elementu tablicy
INVOKE wspU, n, temp, beta, tempptr ; wywolanie funkcji wspU (n, k+1,
beta, tab[k+1])
fld QWORD PTR [eax] ; odczytanie wyniku zwroconego przez wspU
fstp t3 ; zapisanie wyniku
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
inc temp ; temp = k+2
mov eax, tab ; zachowanie adresu tablicy
mov tempptr, eax
add tempptr, 64 ; przesuniecie sie w tablicy o 2 elementy
INVOKE wspU, n, temp, beta, tempptr ; wywolanie funkcji wspU (n, k+2,
beta, tab[k+2])
fld QWORD PTR [eax] ; odczytanie wyniku zwroconego przez wspU
fstp t4 ; zapisanie wyniku
fld t4 ; st2 = U(k+2)
fld t3 ; st1 = U(k+1)
fld t2 ; st0 = 2 * cos(beta)
fmul st(0), st(1) ; st0 = 2 * cos(beta) * U(k+1)
fld t1 ; st0 = f(x)
fadd st(0), st(1) ; st0 = f(x) + 2 * cos(beta) * U(k+1)
fsub st(0), st(3) ; st0 = f(x) + 2 * cos(beta) * U(k+1) - U(k+2)
popad
fstp QWORD PTR [eax] ; zapisanie wyniku
jmp Koniec
Zwroc0:
fldz ; ladujemy 0 do st0
popad
fstp QWORD PTR [eax]; zapisanie zera pod adres wynikowy
Koniec:
ret ;koniec funkcji
No i teraz nie wiem dlaczego, ale modyfikowane są wartości tab[].x
czyli te, pod adresami tab + x * 32 (bo tyle zajmują 4 double).
na szczęście błąd ten jest mało ważny. Jednak dla identycznych
parametrów, funkcja w C i w ASMie zwraca zupełnie inne wyniki i tego
już nie kumam... Patrze w te instrukcje i nie widzę gdzie może być
błąd...
wspU ENDP
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Sat, 30 May 2009 14:06
Date: Sat, 30 May 2009 14:06
94 lines
4358 bytes
4358 bytes
MrokU pisze:
[...]
> Generalnie wyliczać mam taki wzorek:
>
> U(k) = f(x) + 2 * U(k+1) * cos(B) - U(k+2)
[...]
> Na razie, po pierwszych próbach funkcja (oczywiście nie działa dobrze)
> wygląda tak:
>
> ;******************************************************************
> ;****** Procedura obliczajaca pierwsze 2 wyrazy ciagu Un
> ;****** Wg wzoru:
> ;****** double U (int k, double beta, Element *tab) //obliczanie
> wspólczynnika U - wzór 28
> ;****** {
> ;****** if ( k > n )
> ;****** return (0.0);
> ;****** else
> ;****** return (tab[k].f_x + (2.0) * ( U(k+1, beta, tab) * cosf
> (beta) ) - U(k+2, beta, tab));
> ;****** }
>
> ;****** definicja elementu tablicy
>
> ;****** struct Element
> ;****** {
> ;****** double x;
> ;****** double f_x;
> ;****** double g_x;
> ;****** double blad;
> ;****** };
>
> wspU PROC n:DWORD, k:DWORD, beta:PTR, tab:PTR
Wiesz, że ten prototyp wygląda inaczej niż ten z C i musisz tę
funkcję (znacznie) inaczej uruchamiać, prawda?
> LOCAL t1:QWORD, t2:QWORD, t3:QWORD, t4:QWORD, temp:DWORD, tempptr:PTR
> pushad
> finit
>
> mov eax, k
> cmp eax, n ; if (k > n)
>
> ja Zwroc0 ; return 0;
Załóżmy najpierw, że w tym punkcie warunek jest spełniony i skok JA
wykonany. W końcu kiedyś będzie się to musiało zdarzyć. Spójrz teraz,
co się dzieje pod "Zwroc0".
[...]
> fmul st(0), st(1) ; st0 = 2 * cos(beta) * U(k+1)
> fld t1 ; st0 = f(x)
> fadd st(0), st(1) ; st0 = f(x) + 2 * cos(beta) * U(k+1)
> fsub st(0), st(3) ; st0 = f(x) + 2 * cos(beta) * U(k+1) - U(k+2)
>
> popad
>
> fstp QWORD PTR [eax] ; zapisanie wyniku
Ta sama uwaga, co poniżej dla zwracania zera.
> jmp Koniec
>
> Zwroc0:
> fldz ; ladujemy 0 do st0
> popad
> fstp QWORD PTR [eax]; zapisanie zera pod adres wynikowy
Wielkie pytanie, co jest w EAX w tym miejscu, gdy "ja Zwroc0"
zostanie wykonane. A z resztą, nawet jak nie będzie wykonane, to co
jest w EAX? Wykonując POPAD, przywracasz wartość z momentu
uruchomienia funkcji, a rejestr EAX jest używany dowolnie, więc jego
wartość jest nieokreślona. Piszesz więc pod nieznany adres (przy
pierwszym uruchomieniu funkcji). Inicjalizuj EAX na tyle, ile trzeba
(czyli pewnie tab+8).
> No i teraz nie wiem dlaczego, ale modyfikowane są wartości tab[].x
> czyli te, pod adresami tab + x * 32 (bo tyle zajmują 4 double).
>
> na szczęście błąd ten jest mało ważny. Jednak dla identycznych
> parametrów, funkcja w C i w ASMie zwraca zupełnie inne wyniki i tego
> już nie kumam... Patrze w te instrukcje i nie widzę gdzie może być
> błąd...
Pewnie wszystko wina niezainicjalizowanych wskaźników. Jeśli nie, to
pokaż kod wywołujący.
--
Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS)
Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro
Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32
www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sat, 30 May 2009 15:01
Date: Sat, 30 May 2009 15:01
138 lines
5701 bytes
5701 bytes
> Wiesz, że ten prototyp wygląda inaczej niż ten z C i musisz tę
> funkcję (znacznie) inaczej uruchamiać, prawda?
Wiem wiem.
Wywołanie z C jest dobre. Robię to poprzez wskaźnik na funkcję i
przekazanie odpowiednich parametrów (zresztą, trochę już pozmieniałem)
Skoki były ok, a pod eax były rzeczywiście wartości inne niż
oczekiwana. Teraz już normalnie zwracam wynik przez wpisanie go pod
adres, który dostaję do funkcji.
wspU PROC n:DWORD, k:DWORD, beta:PTR, tab:PTR, wynik:PTR
LOCAL t1:QWORD, t2:QWORD, t3:QWORD, t4:QWORD, temp:DWORD, tabptr:PTR,
twynik:QWORD
pushad
finit
mov eax, k
cmp eax, n ; if (k > n)
ja Zwroc0 ; return 0;
mov ebx, tab ; zaladowanie adresu tablicy
fld QWORD PTR [ebx+8] ; zaladowanie wartosci f(x)
fstp t1 ; zachowanie wartosci do zmiennej lokalnej, zwolnienie
stosu
mov ebx, beta ; zaladowanie adresu zmiennej beta (liczonej przez
funkcje "Beta(j, n)"
fld QWORD PTR [ebx] ; zaladowanie wartosci spod wskaznika beta
fcos ; cosinus (beta)
fadd st(0), st(0) ; 2 * cos (beta)
fstp t2 ; zachowanie powyzszej wartosci do lokalnej zmiennej
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
mov eax, tab ; zachowanie adresu tablicy
mov tabptr, eax
add tabptr, 32 ; przesuniecie sie do nastepnego elementu tablicy
lea eax, twynik ; wyluskanie adresu zmiennej twynik
INVOKE wspU, n, temp, beta, tabptr, eax ; wywolanie funkcji wspU
(n, k+1, beta, tab[k+1])
lea eax, twynik ; zaladowanie adresu wyniku
fld QWORD PTR [eax] ; odczytanie wyniku zwroconego przez wspU
fstp t3 ; zapisanie wyniku
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
inc temp ; temp = k+2
mov eax, tab ; zachowanie adresu tablicy
mov tabptr, eax
add tabptr, 64 ; przesuniecie sie w tablicy o 2 elementy
lea eax, twynik ; wyluskanie adresu zmiennej twynik
INVOKE wspU, n, temp, beta, tabptr, eax ; wywolanie funkcji wspU
(n, k+2, beta, tab[k+2])
lea eax, twynik ; zaladowanie adresu wyniku
fld QWORD PTR [eax] ; odczytanie wyniku zwroconego przez wspU
fstp t4 ; zapisanie wyniku
fld t4 ; st2 = U(k+2)
fld t3 ; st1 = U(k+1)
fld t2 ; st0 = 2 * cos(beta)
fmul st(0), st(1) ; st0 = 2 * cos(beta) * U(k+1)
mov ebx, tab
fld QWORD PTR [ebx+8] ; st0 = f(x)
fadd st(0), st(1) ; st0 = f(x) + 2 * cos(beta) * U(k+1)
fsub st(0), st(3) ; st0 = f(x) + 2 * cos(beta) * U(k+1) - U(k+2)
mov eax, wynik ; wczytanie adresu zmiennej wynikowej
fstp QWORD PTR [eax] ; zapisanie wyniku
popad
jmp Koniec
Zwroc0:
fldz ; ladujemy 0 do st0
mov eax, wynik ; wczytanie adresu zmiennej wynikowej
fstp QWORD PTR [eax] ; zapisanie zera pod adres wynikowy
popad
Koniec:
ret ;koniec funkcji
wspU ENDP
Przy czym teraz to wszystko bardzo dziwnie działa...
Oba INVOKE wykonują się dobrze i zwracają poprawny wynik (nie
wchodzimy głębiej w rekurencję, bo tam wszystko dobrze się liczy).
Jednak, w momencie, gdy próbuję po nich wczytać jakąś lokalną zmienną,
dostaję błąd...
[...]
fld t4 ; st2 = U(k+2)
fld t3 ; st1 = U(k+1)
fld t2 ; st0 = 2 * cos(beta)
fmul st(0), st(1) ; st0 = 2 * cos(beta) * U(k+1)
mov ebx, tab
fld QWORD PTR [ebx+8] ; st0 = f(x)
[...]
po wykonaniu powyższego, w st0 i st1 mam 1#IND... Najdziwniejsze jest
to, że dzieje się tak tylko na tym najwyższym poziomie rekurencji
(czyli w pierwszej wywołanej funkcji)...
No a wywołanie w C wygląda tak (oczywiście po maksymalnym okrojeniu):
struct Element
{
double x;
double f_x;
double g_x;
double blad;
};
Element *tab;
double *c, *e;
MYPROC4 ProcU;
HINSTANCE hinstLib;
main:
hinstLib = LoadLibrary ("sss.dll");
ProcU = (MYPROC4) GetProcAddress(hinstLib, "wspU");
(ProcU)(3, 1, c, tab, e);
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Remek
Date: Sat, 30 May 2009 15:20
Date: Sat, 30 May 2009 15:20
11 lines
1708 bytes
1708 bytes
Użytkownik "MrokU" napisał: > lea eax, twynik ; wyluskanie adresu zmiennej twynik Dlaczego mordujesz eax do indeksowania zmniennych? :) Do tego celu masz rejestry indeksowe esi i edi. Zużyjesz rejestr i będziesz musiał wymieniać procesor. Pokaż wywołanie funkcji z głównego programu. Remek
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sat, 30 May 2009 15:59
Date: Sat, 30 May 2009 15:59
93 lines
3803 bytes
3803 bytes
cały kod w C++ wygląda tak:
Przy czym jest mało czytelny, bo chodzi tylko o wywołanie funkcji i
sprawdzenie jej działania...
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
#define PI
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
//---------------------------------------------------------------------------
struct Element
{
double x;
double f_x;
double g_x;
double blad;
};
typedef int (__stdcall *MYPROC)(int, int);
typedef double* (__stdcall *MYPROC2)(double*);
typedef void (__stdcall *MYPROC3)(int, int, double*);
typedef void (__stdcall *MYPROC4)(int, int, double*, Element*,
double* );
MYPROC ProcAdd, ProcSub;
MYPROC2 ProcSin;
MYPROC3 ProcBeta;
MYPROC4 ProcU;
HINSTANCE hinstLib;
Element *tab;
double *c, *e, d, f;
double U (int n, int k, double beta, Element *tab) //obliczanie
wspolczynnika U - wzór 28
{
if ( k > n )
return (0.0);
else {
double fx = tab[k-1].f_x;
double cosbet = cos(beta);
double wynik = (fx + (2.0) * ( U(n, k+1, beta, tab) * cosbet ) - U
(n, k+2, beta, tab));
std::cout << "f(x) = " << fx << "\n cos(beta) = " << cosbet << "\n
wynik: " << wynik << std::endl;
return wynik;
}
}
int main(int argc, char* argv[])
{
hinstLib = LoadLibrary ("sss.dll"); //ladowanie biblioteki
if (hinstLib == NULL) //sprawdzenie, czy moduł faktycznie
został załadowany
return 1;
ProcU = (MYPROC4) GetProcAddress(hinstLib, "wspU");
if (NULL != ProcU) {
e = new (double);
tab = new Element [7];
d = PI/2;
c = &d;
tab[0].f_x = 2.0;
tab[1].f_x = 6.0;
tab[2].f_x = 10.0;
tab[3].f_x = 14.0;
tab[4].f_x = 18.0;
tab[5].f_x = 22.0;
tab[6].f_x = 24.0;
f = U (6, 1, d, tab);
(ProcU)(6, 1, c, tab, e);
}
FreeLibrary(hinstLib);
std::cout << *e << std::endl;
std::cout << f << std::endl;
system("PAUSE");
return 0;
}
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Sat, 30 May 2009 18:50
Date: Sat, 30 May 2009 18:50
67 lines
3218 bytes
3218 bytes
No, przepełniał mi się chyba stos FPU ... Funkcja napisana od nowa, działająca, wygląda tak: wspU_2 PROC n:DWORD, k:DWORD, beta:QWORD, tab:PTR, wynik:PTR LOCAL Uk1:QWORD, Uk2:QWORD, tabT:PTR pushad finit mov eax, k cmp eax, n ; if (k > n) ja Zwroc0 ; return 0 mov ebx, k inc ebx ; ebx = k+1 mov ecx, tab add ecx, 32 mov tabT, ecx ; tabT = tab + 32 (przejscie do kolejnego elementu tablicy) INVOKE wspU_2, n, ebx, beta, tabT, wynik mov ebx, wynik fld QWORD PTR [ebx] fstp Uk1 ; zapisanie wyniku do zmiennej lokalnej mov ebx, k add ebx, 2 ; ebx = k+2 mov ecx, tab add ecx, 64 mov tabT, ecx ; tabT = tab + 64 (przejscie o 2 elementy tablicy) INVOKE wspU_2, n, ebx, beta, tabT, wynik mov ebx, wynik fld QWORD PTR [ebx] fstp Uk2 ; zapisanie wyniku do zmiennej lokalnej fld beta fcos ; cosinus (beta) fadd st(0), st(0) ; 2 * cos (beta) fld Uk1 ; zaladowanie wartosci U(k+1) fmulp st(1), st(0) ; 2 * cos (beta) * U(k+1) -> st0 fld Uk2 fsubp st(1), st(0) ; 2 * cos (beta) * U(k+1) - U(k+2) -> st0 mov esi, tab fld QWORD PTR [esi+8] faddp st(1), st(0) ; f(xk) + 2 * cos (beta) * U(k+1) - U(k+2) -> st0 mov esi, wynik fstp QWORD PTR [esi] jmp Koniec Zwroc0: mov esi, wynik fldz fstp QWORD PTR [esi] Koniec: popad ret; wspU_2 ENDP
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: MrokU
Date: Tue, 02 Jun 2009 23:13
Date: Tue, 02 Jun 2009 23:13
518 lines
14947 bytes
14947 bytes
No nic, programik działa, interpoluje (zapewne nieoptymalnie, ale
cóż...). Kod w ASMie wrzucę, tak dla potomności, oraz może ktoś
skomentuje i poprawi moje wypociny :)
.586
.387
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE c:\masm32\include\windows.inc;
.DATA
.CODE
DllEntry PROC ;hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax, TRUE
ret
DllEntry ENDP
;******************************************************************
;****** Procedura obliczajaca wspolczynnik beta dla j-ego elementu
;****** Wg wzoru:
;****** double beta (int j) //obliczanie wspólczynnika beta - wzór 26
;****** {
;****** return ((j* 2 * pi) / (n + 1));
;****** }
Beta PROC n:DWORD, j:DWORD, wynik:PTR
pushad
mov ebx, wynik ; adres wyniku
finit
fldpi ; PI -> st0
fadd st(0), st(0) ; 2*PI -> st0
fild j ; 2*PI -> st1, j -> st0
fmulp st(1), st(0) ; 2*PI*j -> st0
fld1 ; 1 -> st0
fild n ; n -> st0
faddp st(1), st(0) ; n+1 -> st0
fdivp st(1), st(0) ; 2*PI*j / n+1 -> st0
fstp QWORD PTR [ebx]; zapisanie wyniku pod adres przekazanego
wskaznika
popad
ret ;koniec funkcji
Beta ENDP
;******************************************************************
;****** Procedura obliczajaca pierwsze 2 wyrazy ciagu Un
;****** Wg wzoru:
;****** double U (int k, double beta, Element *tab) //obliczanie
wspólczynnika U - wzór 28
;****** {
;****** if ( k > n )
;****** return (0.0);
;****** else
;****** return (tab[k].f_x + (2.0) * ( U(k+1, beta, tab) * cosf
(beta) ) - U(k+2, beta, tab));
;****** }
;****** definicja elementu tablicy
;****** struct Element
;****** {
;****** double x;
;****** double f_x;
;****** double g_x;
;****** double blad;
;****** };
wspU PROC n:DWORD, k:DWORD, beta:PTR, tab:PTR, wynik:PTR
LOCAL t1:QWORD, t2:QWORD, t3:QWORD, t4:QWORD, temp:DWORD, tabptr:PTR,
twynik:QWORD
pushad
finit
mov eax, k
cmp eax, n ; if (k > n)
ja Zwroc0 ; return 0;
mov ebx, tab ; zaladowanie adresu tablicy
fld QWORD PTR [ebx+8] ; zaladowanie wartosci f(x)
fstp t1 ; zachowanie wartosci do zmiennej lokalnej, zwolnienie
stosu
mov ebx, beta ; zaladowanie adresu zmiennej beta (liczonej przez
funkcje "Beta(j, n)"
fld QWORD PTR [ebx] ; zaladowanie wartosci spod wskaznika beta
fcos ; cosinus (beta)
fadd st(0), st(0) ; 2 * cos (beta)
fstp t2 ; zachowanie powyzszej wartosci do lokalnej zmiennej
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
mov esi, tab ; zachowanie adresu tablicy
mov tabptr, esi
add tabptr, 32 ; przesuniecie sie do nastepnego elementu tablicy
lea edi, twynik ; wyluskanie adresu zmiennej twynik
INVOKE wspU, n, temp, beta, tabptr, edi ; wywolanie funkcji wspU
(n, k+1, beta, tab[k+1])
lea edi, twynik ; zaladowanie adresu wyniku
fld QWORD PTR [edi] ; odczytanie wyniku zwroconego przez wspU
fstp t3 ; zapisanie wyniku
mov eax, k ; zachowanie zmiennej k
mov temp, eax
inc temp ; temp = k+1
inc temp ; temp = k+2
mov esi, tab ; zachowanie adresu tablicy
mov tabptr, esi
add tabptr, 64 ; przesuniecie sie w tablicy o 2 elementy
lea edi, twynik ; wyluskanie adresu zmiennej twynik
INVOKE wspU, n, temp, beta, tabptr, edi ; wywolanie funkcji wspU
(n, k+2, beta, tab[k+2])
lea edi, twynik ; zaladowanie adresu wyniku
fld QWORD PTR [edi] ; odczytanie wyniku zwroconego przez wspU
fstp t4 ; zapisanie wyniku
fld t3 ; st1 = U(k+1)
fld t2 ; st0 = 2 * cos(beta)
fmulp st(1), st(0) ; st0 = 2 * cos(beta) * U(k+1)
fld t4 ; st0 = U(k+2)
fsubp st(1), st(0) ; st0 = 2 * cos(beta) * U(k+1) - U(k+1)
mov ebx, tab
fld QWORD PTR [ebx+8] ; st0 = f(x)
faddp st(1), st(0) ; st0 = f(x) + 2 * cos(beta) * U(k+1)
mov esi, wynik ; wczytanie adresu zmiennej wynikowej
fstp QWORD PTR [esi] ; zapisanie wyniku
jmp Koniec
Zwroc0:
fldz ; ladujemy 0 do st0
mov esi, wynik ; wczytanie adresu zmiennej wynikowej
fstp QWORD PTR [esi] ; zapisanie zera pod adres wynikowy
Koniec:
popad
ret ;koniec funkcji
wspU ENDP
;******************************************************************
;****** Procedura obliczajaca pierwsze 2 wyrazy ciagu Un
;****** Wg wzoru:
;****** double U (int k, double beta, Element *tab) //obliczanie
wspólczynnika U - wzór 28
;****** {
;****** if ( k > n )
;****** return (0.0);
;****** else
;****** return (tab[k].f_x + (2.0) * ( U(k+1, beta, tab) * cosf
(beta) ) - U(k+2, beta, tab));
;****** }
;****** definicja elementu tablicy
;****** struct Element
;****** {
;****** double x;
;****** double f_x;
;****** double g_x;
;****** double blad;
;****** };
wspU_2 PROC n:DWORD, k:DWORD, beta:QWORD, tab:PTR, wynik:PTR
LOCAL Uk1:QWORD, Uk2:QWORD, tabT:PTR
pushad
finit
mov eax, k
cmp eax, n ; if (k > n)
ja Zwroc0 ; return 0
mov ebx, k
inc ebx ; ebx = k+1
mov ecx, tab
add ecx, 32
mov tabT, ecx ; tabT = tab + 32 (przejscie do kolejnego elementu
tablicy)
INVOKE wspU_2, n, ebx, beta, tabT, wynik
mov ebx, wynik
fld QWORD PTR [ebx]
fstp Uk1 ; zapisanie wyniku do zmiennej lokalnej
mov ebx, k
add ebx, 2 ; ebx = k+2
mov ecx, tab
add ecx, 64
mov tabT, ecx ; tabT = tab + 64 (przejscie o 2 elementy tablicy)
INVOKE wspU_2, n, ebx, beta, tabT, wynik
mov ebx, wynik
fld QWORD PTR [ebx]
fstp Uk2 ; zapisanie wyniku do zmiennej lokalnej
fld beta
fcos ; cosinus (beta)
fadd st(0), st(0) ; 2 * cos (beta)
fld Uk1 ; zaladowanie wartosci U(k+1)
fmulp st(1), st(0) ; 2 * cos (beta) * U(k+1) -> st0
fld Uk2
fsubp st(1), st(0) ; 2 * cos (beta) * U(k+1) - U(k+2) -> st0
mov esi, tab
fld QWORD PTR [esi+8]
faddp st(1), st(0) ; f(xk) + 2 * cos (beta) * U(k+1) - U(k+2) -> st0
mov esi, wynik
fstp QWORD PTR [esi] ; zapisanie wyniku
jmp Koniec
Zwroc0:
mov esi, wynik
fldz
fstp QWORD PTR [esi] ; zwrocenie zera
Koniec:
popad
ret;
wspU_2 ENDP
;******************************************************************
;****** Procedura liczaca wspolczynnik A
;****** double wspA (int j, Element *tab) //obliczanie wspolczynnika A
- wzór 27
;****** {
;****** double beta_j = beta (j);
;****** return ( (2.0/(n+1)) * (tab[0].f_x + U(1, beta_j, tab) * cosf
(beta_j) - U(2, beta_j, tab)) );
;****** }
wspA PROC n:DWORD, j:DWORD, tab:PTR, wynik:PTR
LOCAL Tbeta:QWORD, U2:QWORD, temp:DWORD
pushad
finit
lea ebx, Tbeta ; wyluskanie adresu zmiennej Tbeta (bedzie w niej
przechowywany wynik funkcji Beta())
INVOKE Beta, n, j, ebx
mov esi, tab
add esi, 64
INVOKE wspU_2, n, 2, Tbeta, esi, wynik
mov esi, wynik
fld QWORD PTR [esi] ; zapamietanie wyniku
fstp U2
mov esi, tab
add esi, 32
INVOKE wspU_2, n, 1, Tbeta, esi, wynik
mov esi, wynik
fld QWORD PTR [esi] ; U(1) -> st0
fld Tbeta
fcos ; cos(beta) -> st0
fmulp st(1), st(0) ; cos(beta) * U1 -> st0
fld U2 ; U(2) -> st0
fsubp st(1), st(0) ; cos(beta) * U1 - U2 -> st0
mov esi, tab
fld QWORD PTR [esi+8] ; f(x0) -> st0
faddp st(1), st(0) ; f(x0) + cos(beta) * U1 - U2 -> st(0)
fadd st(0), st(0) ; 2 * st0
mov ebx, n
inc ebx ; n+1 -> ebx
mov temp, ebx
fild temp ; n+1 -> st0
fdivp st(1), st(0) ; [2 * (x0) + cos(beta) * U1 - U2 -> st(0)] / (n
+1) -> st0
mov esi, wynik
fstp QWORD PTR [esi] ; zwrocenie wyniku
popad
ret
wspA ENDP
;******************************************************************
;****** Procedura liczaca wspolczynnik B
;****** double B (int j, Element* tab) //obliczanie współczynnika B -
wzór 27
;****** {
;****** double beta_j = beta (j);
;****** return (2 * ( U(n, 1, beta_j, tab) * sinf(beta_j) ) ) / (n +
1) ;
;****** }
wspB PROC n:DWORD, j:DWORD, tab:PTR, wynik:PTR
LOCAL Tbeta:QWORD, temp:DWORD
pushad
finit
lea esi, Tbeta ; wyluskanie adresu zmiennej Tbeta (bedzie w niej
przechowywany wynik funkcji Beta())
INVOKE Beta, n, j, esi
mov esi, tab
add esi, 32
INVOKE wspU_2, n, 1, Tbeta, esi, wynik
mov esi, wynik
fld QWORD PTR [esi] ; U(1) -> st0
fld Tbeta
fsin ; sin(beta) -> st0
fmulp st(1), st(0) ; U(1) * sin(beta) -> st0
fadd st(0), st(0) ; 2 * U(1) * sin(beta) -> st0
mov ebx, n
inc ebx ; n+1 -> ebx
mov temp, ebx
fild temp ; n+1 -> st0
fdivp st(1), st(0) ; [2 * sin(beta) * U1] / (n+1) -> st0
mov esi, wynik
fstp QWORD PTR [esi] ; zwrocenie wyniku
popad
ret
wspB ENDP
;******************************************************************
;****** Procedura obliczajaca wartosc funkcji interpolujacej w danym
punkcie.
;****** wg wzoru:
;****** t(x) = A(0)/2 + // lokalnie jako wA02
;****** [ delta * A(m+1) * cos ((m+1)*x) ] / 2 + // lokalnie
jako wA
;****** SUMA (od j=1 do m) [ A(j) * cos (j*x) + B(j) * sin (j*x) ]
;****** gdzie:
;****** dla n parzystych: delta = 0, m = n / 2
;****** dla n nieparzystych: delta = 1, m =(n-1) / 2
;******
;****** funkcja bedzie wywolywana osobno dla kazdego punktu
;****** interpolacji, stad 2 wskazniki na tablice tab[]
;****** jeden wskaznik na poczatek tablicy oraz jeden wskaznik
;****** na aktualnie liczony element
Interpoluj PROC n:DWORD, tab:PTR, AKT_tab:PTR
LOCAL m:DWORD, j:DWORD, wA:QWORD, wA02:QWORD, wAsuma:QWORD,
wBsuma:QWORD, SUMA:QWORD
pushad
finit
mov eax, n ; zaladowanie n
shl eax, 31 ; wyluskanie najmlodszego bitu (1 - nieparzysta)
cmp eax, 0 ; sprawdzenie parzystosci liczby
je Parzysta
Nieparzysta: ; tutaj bedziemy liczyc: [ A(m+1) * cos ((m+1)*x) ] /
2
mov ebx, n
dec ebx ; n - 1
shr ebx, 1 ; (n - 1) / 2
mov m, ebx ; m = (n - 1) / 2
lea esi, wA
mov ebx, m
inc ebx
mov j, ebx ; j = m+1
INVOKE wspA, n, j, tab, esi ; obliczamy A(m+1), wynik -> wA
fld wA ; A(m+1) -> st0
fild j ; m+1 -> st0
fld QWORD PTR AKT_tab ; zaladowanie wartosci x dla aktualnie
liczonego wezla
fmulp st(1), st(0) ; [ A(m+1) * x ] -> st0
fcos ; cos ((m+1)*x) -> st0
fmulp st(1), st(0) ; [ A(m+1) * cos ((m+1)*x) ] -> st0
mov j, 2
fild j ; zaladowanie 2 do st0
fdivp st(1), st(0) ; [ A(m+1) * cos ((m+1)*x) ] / 2 -> st0
fstp wA ; zapisanie powyzszego wyniku do wA
jmp M_obliczone
Parzysta: ; ustawienie odpowiedniego m oraz wA = 0
mov ebx, n
shr ebx, 1 ; n / 2
mov m, ebx ; m = n / 2
fldz
fstp wA
M_obliczone: ; obliczenie A(0) / 2 i petla liczaca sume
lea esi, wA02 ; zaladowanie adresu zmiennej do esi
INVOKE wspA, n, 0, tab, esi ; obliczamy A(0), wynik -> wA02
fld wA02 ; A(0) -> st0
mov j, 2
fild j ; zaladowanie 2 do st0
fdivp st(1), st(0) ; A(0) / 2 -> st0
fstp wA02 ; zaladowanie st0 do zmiennej wA02
;* petla obliczajaca sume
;** SUMA (od j=1 do m) [ A(j) * cos (j*x) + B(j) * sin (j*x) ]
mov ecx, 1 ; for (j = 1...)
fldz
fstp SUMA ; SUMA = 0
Petla:
mov j, ecx
cmp ecx, m
ja Endfor ; for (j = 1; j < m...)
lea esi, wAsuma
INVOKE wspA, n, j, tab, esi ; wAsuma = A(j)
lea esi, wBsuma
INVOKE wspB, n, j, tab, esi ; wBsuma = B(j)
mov esi, AKT_tab
fld QWORD PTR [esi] ; tab[j].x -> st0
fild j ; j -> st0
fmulp st(1), st(0) ; j * x -> st0
fcos ; cos (j * x) -> st0
fld wAsuma
fmulp st(1), st(0) ; A(j) * cos (j * x) -> st0
mov esi, AKT_tab
fld QWORD PTR [esi] ; tab[j].x -> st0
fild j ; j -> st0
fmulp st(1), st(0) ; j * x -> st0
fsin ; sin (j * x) -> st0
fld wBsuma
fmulp st(1), st(0) ; B(j) * cos (j * x) -> st0
faddp st(1), st(0) ; [ A(j) * cos (j*x) + B(j) * sin (j*x) ] ->
st0
fld SUMA
faddp st(1), st(0)
fstp SUMA ; SUMA += [ A(j) * cos (j*x) + B(j) * sin (j*x) ]
inc ecx ; for (j = 1, j < m, j++)
jmp Petla
Endfor:
fld SUMA
fld wA02
fld wA
faddp st(1), st(0)
faddp st(1), st(0) ; SUMA += A(0)/2 + [ delta * A(m+1) * cos ((m
+1)*x) ] / 2
mov esi, AKT_tab ; zaladowanie wskaznika na aktualny element
tablicy
add esi, 16 ; przesuniecie sie na element g_x struktury
fstp QWORD PTR [esi] ; zapisanie wartosci funkcji interpolacyjnej
dla danego elementu
Liczenie_bledu:
mov esi, AKT_tab
fld QWORD PTR [esi+8] ; f(x) -> st0 __zaladowanie wartosci
oryginalnej funkcji
fld QWORD PTR [esi+16] ; g(x) -> st0 __zaladowanie wartosci
funkcji interpolacyjnej
fsubp st(1), st(0) ; f(x) - g(x) -> st(0)
fldz
fcomip st(0), st(1) ; porownanie st0 i st1
jbe bladdodatni
bladujemny:
fldz
fld1
fsubp st(1), st(0) ; -1 -> st0
fmulp st(1), st(0) ; zmiana znaku bledu
bladdodatni:
fstp QWORD PTR [esi+24] ; zapisanie wartosci bledu
Koniec:
popad
ret
Interpoluj ENDP
END DllEntry
Re: Visual Studio 2008 (C++ oraz DLL w asmie) Interpolacja
Author: Bogdan (bogdro)
Date: Wed, 03 Jun 2009 15:59
Date: Wed, 03 Jun 2009 15:59
40 lines
3120 bytes
3120 bytes
MrokU pisze: > No nic, programik działa, interpoluje (zapewne nieoptymalnie, ale > cóż...). Kod w ASMie wrzucę, tak dla potomności, oraz może ktoś > skomentuje i poprawi moje wypociny :) [...] > INCLUDE c:\masm32\include\windows.inc; Średnik zapewne niepotrzebny :) Poza tym, można byłoby pewnie uniknąć ciągłego FINIT i PUSHAD+POPAD. Zamiast dwóch INC można użyć ADD. Do procedury można przekazać adres zmiennej od razu, bez używania rejestru, za pomocą "offset twynik" lub "addr twynik". Można przerobić kod, by nie ładować "t4" na stos FPU 4 instrukcje po zdjęciu tej wartości. Sprawdzenie parzystości liczby: mov eax, n ; zaladowanie n shl eax, 31 ; wyluskanie najmlodszego bitu (1 - nieparzysta) cmp eax, 0 je Parzysta można zastąpić kodem: test n, 1 je Parzysta I mała sztuczka optymalizacyjna: widzę, że ciągle wyliczasz "j*x", a nie widzę, by "x" się zmieniał w tym czasie. Jeśli dobrze widzę, to możesz ustawić sobie jakiś rejestr na "x" (bo zaczynamy od 1) i zwiększać go o "x" za każdą iteracją zamiast ciągle mnożyć. To tyle z moich uwag. Najważniejsze, że program działa i problemy zostały rozwiązane. -- Pozdrawiam/Regards - Bogdan (GNU/Linux & FreeDOS) Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro Grupy dyskusyjne o asm: pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32 www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
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