🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.asm
8 messages
8 total messages Started by Doleś Fri, 11 Apr 2008 01:48
Transpozycja tablicy w C & Asembler
#1785
Author: Doleś
Date: Fri, 11 Apr 2008 01:48
31 lines
2907 bytes
Witam,
mam pewien problem z transpozycją tablicy w Asemblerze. Napisałem 
wszystko oprócz samej transpozycji w C. Ten sam program pod Windowsem 
napisany w Visual Studio działa, ale pod Linuksem już nie chce. 
Naturalnie nie próbuję składni MASMa przerzucić na Linuksa :) 
Przepisałem sobie program na wg składni NASMa i oczywiście po kompilacji 
i asemblacji oraz linkowaniu mam legendarny, kochany błąd "Segmentation 
Fault". Próbowałem poradzić sobie samemu w związku z czym zrobiłem 
przyspieszony kurs obsługi GDB (którego jeszcze do dzisiaj nie 
potrafiłem obsługiwać) i debugowałem program. Zrobiłem "jump transponuj" 
i dawałem na przemian "stepi", "print /d $rejestr" oraz "x /10i <adres>" 
i starałem się kontrolować po kawałku jak się wykonuje program. O dziwo 
sam algorytm wydawał się poprawny, śledziłem zmienne no i nie było 
naruszenia ochrony pamięci w pętlach kodu. Problem powstał dopiero po 
instrukcji RET gdy kod programu poszedł sobie hen, hen daleko poza 
wstawkę w Asemblerze. Jedyne moje skojarzenie było takie, że gdzieś jest 
nadpisane EIP, ale analizowałem kod i nie mam pojęcia gdzie. Poza tym, 
czy gdyby nie było naruszenia stosu to nie wywaliłby komunikat "Smashing 
stack detectet" ? Bo kiedyś takie coś miałem jak próbowałem techniki 
przepełnienia bufora na własnym programie.Podejrzewam, że pewnie coś 
sknociłem przy przepisywaniu ze składni MASMa. Oto i kody źródowe wraz z 
Makefile.
Kod w C: http://paste.org/index.php?id=2580
Kod w Asemblerze: http://paste.org/index.php?id=2581
Makefile: http://paste.org/index.php?id=2582
PS: Wybaczcie mi, że kod w Asemblerze jest taki "prostacki". Chciałem 
użyć adresowania do tablicy dwuwymiarowej wg schematu Tablica[x][y] = 
[Tablica + (x*dlugosc wiersza + y * rozmiar] ale nie mam takiej wprawy 
przy wielowymiarowych tablicach i brakowalo mi po prostu rejestrów na 
zrealizowanie takiego pomysłu a nie miałem żadnej idei kiedy okładać 
sobie coś na stos i z niego zdejmować.
Re: Transpozycja tablicy w C & Asembler
#1786
Author: Bogdan (bogdro)
Date: Fri, 11 Apr 2008 15:41
41 lines
2842 bytes
Doleś pisze:
> Witam,
> mam pewien problem z transpozycją tablicy w Asemblerze. Napisałem 
> wszystko oprócz samej transpozycji w C. Ten sam program pod Windowsem 
> napisany w Visual Studio działa, ale pod Linuksem już nie chce. 
> Naturalnie nie próbuję składni MASMa przerzucić na Linuksa :) 
> Przepisałem sobie program na wg składni NASMa i oczywiście po kompilacji 
> i asemblacji oraz linkowaniu mam legendarny, kochany błąd "Segmentation 
> Fault". Próbowałem poradzić sobie samemu w związku z czym zrobiłem 
> przyspieszony kurs obsługi GDB (którego jeszcze do dzisiaj nie 
> potrafiłem obsługiwać) i debugowałem program. Zrobiłem "jump transponuj" 
> i dawałem na przemian "stepi", "print /d $rejestr" oraz "x /10i <adres>" 
> i starałem się kontrolować po kawałku jak się wykonuje program. O dziwo 
> sam algorytm wydawał się poprawny, śledziłem zmienne no i nie było 
> naruszenia ochrony pamięci w pętlach kodu. Problem powstał dopiero po 
> instrukcji RET gdy kod programu poszedł sobie hen, hen daleko poza 
> wstawkę w Asemblerze. Jedyne moje skojarzenie było takie, że gdzieś jest 
> nadpisane EIP, ale analizowałem kod i nie mam pojęcia gdzie. Poza tym, 
> czy gdyby nie było naruszenia stosu to nie wywaliłby komunikat "Smashing 
> stack detectet" ? Bo kiedyś takie coś miałem jak próbowałem techniki 
> przepełnienia bufora na własnym programie.

  To mówi o tym, że adres powrotny jest nieprawidłowy. Nie musi być od 
razu zamazany. Pomyśl przez chwilę nad ostatnimi liniami kodu:

	pop ebp
	mov esp, ebp
	ret

i w przyszłości używaj

	leave
	ret

:) Ponoć szybsze, a i trudniej się pomylić.

-- 
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: Transpozycja tablicy w C & Asembler
#1787
Author: Bernard
Date: Sat, 12 Apr 2008 12:35
14 lines
1655 bytes
Doleś wrote:
> Witam,
> mam pewien problem z transpozycją tablicy w Asemblerze. Napisałem 
> wszystko oprócz samej transpozycji w C. Ten sam program pod Windowsem 
> napisany w Visual Studio działa, ale pod Linuksem już nie chce. 
> Naturalnie nie próbuję składni MASMa przerzucić na Linuksa :) 
> Przepisałem sobie program na wg składni NASMa i oczywiście po kompilacji 
> i asemblacji oraz linkowaniu mam legendarny, kochany błąd "Segmentation 
> Fault". Próbowałem poradzić sobie samemu w związku z czym zrobiłem 

Zacznij od poprawienia błędu w epilogu - kolejność 2. i 3. instrukcji od 
końca. Ponadto prawdopodobnie kręcisz coś ze wskaźnikami - nietrudno o 
to przy tak zagmatwanym zapisie ich wyliczania i modyfikacji. Wyrzuć 
pushad i popad i wstaw to, co trzeba zgodnie z konwencją wołania.
Re: Transpozycja tablicy w C & Asembler
#1788
Author: doles2
Date: Sat, 12 Apr 2008 17:09
53 lines
3613 bytes
Bernard wrote:
>Zacznij od poprawienia błędu w epilogu - kolejność 2. i 3. instrukcji od
>końca. Ponadto prawdopodobnie kręcisz coś ze wskaźnikami - nietrudno o
>to przy tak zagmatwanym zapisie ich wyliczania i modyfikacji. Wyrzuć
>pushad i popad i wstaw to, co trzeba zgodnie z konwencją wołania.
Dzięki za pomoc. Faktycznie miałem skopane te rozkazy usuwające ramkę
stosu. Jednak to tylko wyeliminowało segmentation fault. Co gorsza
myślałem, że to koniec moich problemów ale oczywiście nie. Problem
polega na tym, że kombinowałem jak koń pod górkę aby napisać w
Asemblerze funkcję która robiłaby to samo co taki zapis w C:
for(i=0; i<A; i++)
    for(j=0; j<B; j++)
        transponowana[j][i] = macierz[i][j];

Czyli po prostu takie przepisanie wartości aby indeksy były
pozamieniane miejscami. Jak napisałem wcześniej chciałem użyć tego
schematu adresowania tablic dwuwymiarowych. Miałem pomysł aby
przypisać ESI np licznik "i", zaś dla EDI zmienną "j", jednak pomysł
spalił na panewce bo wg moich (zapewne błędnych) wyliczeń zabrakło po
prostu rejestrów ogólnego przeznaczenia. Potrzebuję dwóch rejestrów do
zachowania początków tablic, dwóch rejestrów na licznik pętli i kolumn
oraz jednego na bufor. Czyli aż chciało by się zapisać coś takiego:
	mov esi, [ebp+ 8]    ;adres macierzy źródłowej
	mov edi, [ebp+12]    ;adres macierzy docelowej
	mov eax, [ebp+16]    ;załaduj ECX na wartość liczby A
	mov ebx, [ebp+20]    ;załaduj EDX na wartość liczby B

	imull eax,ebx
	mov   ecx,eax
	petla:
		mov edx, [esi + (eax*ebx + edi)*4]
		mov [edi + (edi + (ebx*eax + esi)*4]
		inc esi
		inc edi
		loop petla
	;tutaj coś dalej sam nie wiem co
No ale takiego nienormalnego adresowania nie ma jak zapisałem a nawet
gdyby było, to w ten sposób dostałbym się tylko do elementów [0][0],
[1][1], [2][2] ... a co np z [0][1] ? Nie mam pojęcia. Użyłem takiego
głupiego kodu bo tylko tak pisząc to na kartce i robiąc próby
wychodziło mi teoretycznie dobranie się do wszystkich elementów obu
tablic. Jednak po uruchmieniu mam taki wynik:
0 1 2
3 4 5


------------------------------

196608 262144
327680 0
-1076123404 -1210122082
Wiem tylko tyle, że im bardziej się w to zagłębiam tym staję się
głupszy :(
Re: Transpozycja tablicy w C & Asembler
#1789
Author: Bogdan (bogdro)
Date: Sun, 13 Apr 2008 09:40
72 lines
3467 bytes
doles2@gmail.com pisze:
>  Problem
> polega na tym, że kombinowałem jak koń pod górkę aby napisać w
> Asemblerze funkcję która robiłaby to samo co taki zapis w C:
> for(i=0; i<A; i++)
>     for(j=0; j<B; j++)
>         transponowana[j][i] = macierz[i][j];
> 
> Czyli po prostu takie przepisanie wartości aby indeksy były
> pozamieniane miejscami. Jak napisałem wcześniej chciałem użyć tego
> schematu adresowania tablic dwuwymiarowych. Miałem pomysł aby
> przypisać ESI np licznik "i", zaś dla EDI zmienną "j", jednak pomysł
> spalił na panewce bo wg moich (zapewne błędnych) wyliczeń zabrakło po
> prostu rejestrów ogólnego przeznaczenia. Potrzebuję dwóch rejestrów do
> zachowania początków tablic, dwóch rejestrów na licznik pętli i kolumn
> oraz jednego na bufor. Czyli aż chciało by się zapisać coś takiego:
> 	mov esi, [ebp+ 8]    ;adres macierzy źródłowej
> 	mov edi, [ebp+12]    ;adres macierzy docelowej
> 	mov eax, [ebp+16]    ;załaduj ECX na wartość liczby A
> 	mov ebx, [ebp+20]    ;załaduj EDX na wartość liczby B
> 
> 	imull eax,ebx
> 	mov   ecx,eax
> 	petla:
> 		mov edx, [esi + (eax*ebx + edi)*4]
> 		mov [edi + (edi + (ebx*eax + esi)*4]
> 		inc esi
> 		inc edi
> 		loop petla
> 	;tutaj coś dalej sam nie wiem co
> No ale takiego nienormalnego adresowania nie ma jak zapisałem a nawet
> gdyby było, to w ten sposób dostałbym się tylko do elementów [0][0],
> [1][1], [2][2] ... a co np z [0][1] ? Nie mam pojęcia.

  Niech
	int tab1[a][b];
	int tab2[b][a];

  Wtedy
	tab1[i][j] = tab1[i*b+j] = [tab1+i*b+j];
	tab2[j][i] = tab2[j*a+i] = [tab2+j*a+i];

  W kodzie:
	tab1 = esi
	tab2 = edi
	a = ecx
	b = edx

	for ( eax=0; eax < ecx; eax++ )
	{
		for ( ebx=0; ebx < edx; ebx++ )
		{
			push dword [esi+eax*edx+ebx];
			pop dword [edi+ebx*ecx+eax];
		}
	}

  Jak słusznie zauważyłeś, takie tryby adresowania nie istnieją, 
trzeba więc te adresy poskładać:
	EDX:EAX:=EAX*EDX
	EAX:=EAX+EBX	// EDX odrzucamy
	push [esi+eax]

  Podobnie drugi.
  Jeszcze tylko pozostaje dopowiedzieć w razie czego, że warunek w 
pętli for sprawdzany jest u góry i już masz gotowy algorytm.

-- 
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: Transpozycja tablicy w C & Asembler
#1790
Author: doles2
Date: Sun, 13 Apr 2008 20:01
87 lines
4629 bytes
On 13 Kwi, 11:40, "Bogdan (bogdro)" <bog...@poczta.gazeta.pl> wrote:
>
>   Niech
>         int tab1[a][b];
>         int tab2[b][a];
>
>   Wtedy
>         tab1[i][j] = tab1[i*b+j] = [tab1+i*b+j];
>         tab2[j][i] = tab2[j*a+i] = [tab2+j*a+i];
>
>   W kodzie:
>         tab1 = esi
>         tab2 = edi
>         a = ecx
>         b = edx
>
>         for ( eax=0; eax < ecx; eax++ )
>         {
>                 for ( ebx=0; ebx < edx; ebx++ )
>                 {
>                         push dword [esi+eax*edx+ebx];
>                         pop dword [edi+ebx*ecx+eax];
>                 }
>         }
Główkowałem się nieco nad tym i napisałem coś takiego:
global transponuj
section .text

transponuj:
           push ebp
           mov  ebp, esp

           mov  esi, [ebp+8]
           mov  edi, [ebp+12]
           mov  ecx, [ebp+16]
           mov  edx, [ebp+20]
           xor  eax, eax

petla_wiersze:
	      cmp ecx, eax
              je  koniec
              xor ebx,ebx
              petla_kolumny:
			    cmp  edx, ebx
                            je   koniec_kolumn
                            mul  edx
                            add  eax, ebx
                            push [esi + eax]
                            imul ebx,ecx
                            add  ebx,eax
                            pop  [edi + ebx]
                            inc  ebx
                            jmp  petla_kolumny
koniec_kolumn:

              inc eax
              jmp petla_wiersze
koniec:
              leave
              ret
>   Jak słusznie zauważyłeś, takie tryby adresowania nie istnieją,
> trzeba więc te adresy poskładać:
>         EDX:EAX:=EAX*EDX
>         EAX:=EAX+EBX    // EDX odrzucamy
>         push [esi+eax]
>
>   Podobnie drugi.
Tutaj miałem niebotyczny problem, bo takie przeliczenie trzeba wykonać
przed "push dword [esi+eax*edx+ebx];" i przed "pop dword [edi+ebx*ecx
+eax];". Przed pierwszą operacją pobrania elementu z tablicy źródłowej
to tam pikuś, ale gorzej z drugą gdzie potrzebuję starych wartości EAX
i EBX z pętli a nie po obliczeniach. W związku z tym ja już sam
pisałem mało wiele podobny kod ale nie potrafiłem sobie poradzić
właśnie z przechowaniem wartości tych liczników :/ Nie wiem gdzie mam
zrobić PUSH i POP aby je jakoś zachować albo jest jeszcze inny sposób.
Liczyłem sobie na kartce to jeśli nie popełniłem błędu albo nie znam
jakiegoś triku, to niestety nie da się użyć policzonego EAX (tego dla
elementu macierzy źródłowej) w pobraniu elementu dla macierzy
docelowej. Co operację to trzeba liczyć od nowa :(
>   Jeszcze tylko pozostaje dopowiedzieć w razie czego, że warunek w
> pętli for sprawdzany jest u góry i już masz gotowy algorytm.
Na początku nie wiedziałem o co Ci chodzi, ale potem załapałem. Trzeba
sprawdzać warunek u góry pętli bo jeśli np EAX dawno jest równe ECX to
wykona się cała pętla, kod dawno coś naknoci z macierzami a warunek
sprawdzę dopiero na końcu :)
Pewnie pisząc tę wiadomość już dość mocno nadużywam Twojej
cierpliwości i dobrych chęci, zatem z góry przepraszam :)
Re: Transpozycja tablicy w C & Asembler
#1792
Author: Jacek Wawrzaszek
Date: Sun, 13 Apr 2008 22:30
29 lines
2090 bytes
> myślałem, że to koniec moich problemów ale oczywiście nie. Problem
> polega na tym, że kombinowałem jak koń pod górkę aby napisać w
> Asemblerze funkcję która robiłaby to samo co taki zapis w C:
> for(i=0; i<A; i++)
>    for(j=0; j<B; j++)
>        transponowana[j][i] = macierz[i][j];


Powyższy algorytm można zapisać następująco (nota bene w ten właśnie
sposób powinien go zoptymalizować kompilator języka C):

int *pM = &macierz[0][0];
for(int i=0; i<A; i++)
{
    int *pT = &transponowana[0][i];
    for(int j=0; j<B; j++)
    {
        *pT = *(pM++);
        pT += A;
    }
}

Postać ta jest wygodniejsza do przekształcenia na assembler, a na dodatek
działa bardzo szybko, bo nie potrzebuje ani jednej operacji mnożenia.
"Na oko" wydaje mi się, że powyższy algorytm da się zaimplementować
przy użyciu 7 rejestrów, bez konieczności przechowywania czegokolwiek
na stosie (oczywiście poza parametrami wywołania funkcji).

J.
Re: Transpozycja tablicy w C & Asembler
#1791
Author: Bogdan (bogdro)
Date: Mon, 14 Apr 2008 15:42
68 lines
3980 bytes
doles2@gmail.com pisze:
> Główkowałem się nieco nad tym i napisałem coś takiego:
> global transponuj
> section .text

[...]
  No, nawet ładnie to wyszło. Nie wygląda, aby nie działało, ale 
spytam: działa? :)

>>   Jak słusznie zauważyłeś, takie tryby adresowania nie istnieją,
>> trzeba więc te adresy poskładać:
>>         EDX:EAX:=EAX*EDX
>>         EAX:=EAX+EBX    // EDX odrzucamy
>>         push [esi+eax]
>>
>>   Podobnie drugi.
> Tutaj miałem niebotyczny problem, bo takie przeliczenie trzeba wykonać
> przed "push dword [esi+eax*edx+ebx];" i przed "pop dword [edi+ebx*ecx
> +eax];". Przed pierwszą operacją pobrania elementu z tablicy źródłowej
> to tam pikuś, ale gorzej z drugą gdzie potrzebuję starych wartości EAX
> i EBX z pętli a nie po obliczeniach. W związku z tym ja już sam
> pisałem mało wiele podobny kod ale nie potrafiłem sobie poradzić
> właśnie z przechowaniem wartości tych liczników :/ Nie wiem gdzie mam
> zrobić PUSH i POP aby je jakoś zachować albo jest jeszcze inny sposób.

  Można wyliczone wartości dodać do ESI/EDI, zwalniając rejestry:

	mul  edx
	add  eax, ebx
	add esi, eax	; tu EAX już wolny
	push dword [esi]
	imul ebx,ecx
	add  ebx,eax
	add edi, ebx	; tu EBX wolny
	pop  dword [edi]

  Można włożyć na stos, można zachować do zmiennej. "Dword"-y 
dorobiłem w razie czego.

> Liczyłem sobie na kartce to jeśli nie popełniłem błędu albo nie znam
> jakiegoś triku, to niestety nie da się użyć policzonego EAX (tego dla
> elementu macierzy źródłowej) w pobraniu elementu dla macierzy
> docelowej. Co operację to trzeba liczyć od nowa :(

  Trudno. Prosty algorytm nie musi oznaczać wydajny algorytm. Kolega 
Jacek podał ciekawy algorytm (ale także działający tylko dla tablic 
dwuwymiarowych, nie dla tablic wskaźników na wiersze).

>>   Jeszcze tylko pozostaje dopowiedzieć w razie czego, że warunek w
>> pętli for sprawdzany jest u góry i już masz gotowy algorytm.
> Na początku nie wiedziałem o co Ci chodzi, ale potem załapałem. Trzeba
> sprawdzać warunek u góry pętli bo jeśli np EAX dawno jest równe ECX to
> wykona się cała pętla, kod dawno coś naknoci z macierzami a warunek
> sprawdzę dopiero na końcu :)

  Tak, właśnie o to chodziło :)

> Pewnie pisząc tę wiadomość już dość mocno nadużywam Twojej
> cierpliwości i dobrych chęci, zatem z góry przepraszam :)

  E, nie ma za co :) Grunt aby działało i abyś się nauczył czegoś 
nowego. Inni czytający też - ja też musiałem chwilkę pogłówkować :)

-- 
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