Asembler - błąd przy kopiowaniu tablic

Witam :slight_smile: Mam problem z programem w asemblerze. Jednym z zadań programu jest kopiowanie elementów z jednej tablicy do drugiej (tablice z integerami), gdzie druga jest przekazywana jako wskaźnik. Mam problem z kodem, gdyż aktualnie zwracane jest ok 30% danych (przykładowo na 10 liczb tylko 3 pierwsze są prawidłowo skopiowane, reszta liczb to wartości przed kopiowaniem). Wyczytałem, że mój problem może być związany ze złymi wartościami (8 bitów zamiast 32) lecz nie potrafię znaleźć co, jak i w jakim miejscu poprawić. 

 

Kopiuj proc uses ebx ecx edx esi edi tablica:DWORD, nowa_tablica:DWORD, ilosc:DWORD, liczbaWatkow:DWORD, indexWatku:DWORD


local liczbaWatkowZmienna:DWORD ;lokalna zmienna przechowywująca "iloscWatkow"
local iloscElem:DWORD   ;lokalna zmienna przechowywująca ilość elementów
local licznik:DWORD             ;licznik z informacją o aktualnym indeksie tablicy


local adrNowaTab:DWORD


mov eax, ilosc          ;wpisanie do rejestru eax "ilość" z parametrów
mov iloscElem, eax      ;wpisanie do zmiennej lokalnej
mov eax, liczbaWatkow           ;wpisanie do rejestru eax liczby wątków
mov liczbaWatkowZmienna, eax    ;wpisanie do zmiennej lokalnej wartości z eax




xor eax, eax            ;wyzerowanie rejestru eax


mov ecx, indexWatku             ;wpisanie do ecx indeksu aktualnie przerabianego wątku
mov ebx, tablica        ;przekazanie adresu tablicy do ebx
mov edx, nowa_tablica   ;przekazanie adresu nowej_tablicy do edx
mov adrNowaTab, edx
 xor esi, esi


add ebx, ecx                ;zwiększenie indeksu tablicy o numer wątku
add edx, ecx                 ;zwiększenie indeksu nowej tablicy o numer wątku
add esi, ecx                    ; zwiększenie licznika o numer wątku




petla:
mov eax, [ebx]           ;przeniesienie do rejestru eax pierwszego elementu z tablicy ebx
mov [edx], eax           ;wpisanie do pierwszego elementu nowa_tablica wartości spod eax


add ebx, liczbaWatkowZmienna ;zwiększenie indeksu tablicy o ilość wątków
add edx, liczbaWatkowZmienna ;zwiększenie indeksu nowej tablicy o ilość wątków
add esi, liczbaWatkowZmienna ;zwiekszenie eax o ilość wątków




cmp esi, iloscElem  ;porównanie ilości wątków z licznikiem
jbe petla                               ;skok do pętla jeżeli mniejsze lub równe






mov eax, adrNowaTab
ret


Kopiuj endp


end

 

Poglądowa funkcja w c++

 

for (int i=indexWatku; i<=ilosc; i+=liczbaWatkow){


nowa_tablica[i]  = tablica[i];


}

 

Będę niezmiernie wdzięczny za pomoc, gdyż cały dzień spędziłem próbując to naprawić :slight_smile:

Z Twojego opisu nie jest jasne co tak naprawdę próbujesz zrobić. Dane w tablicy są 8-bitowe i chcesz (N=indeksWatku, K=ilosc, Q=liczbaWatkow) od Ntego do Ktego bajtu skopiować co Qty, tak? Operacja wydaje się dziwaczna, a nazwy zmiennych dobrane są tak, że nie ma mowy, żeby zgadnąć co chciałeś uzyskać. Jedyne co można z tego, co pokazałeś, podpowiedzieć, to że kopiujesz po 4 bajty (mov eax, [ebx]), a jeśli liczbaWatkowSmienna ma wartość większą niż 4, to masz w kopiowanych danych przerwy; jeśli mniejszą, to kopiujesz po kilka razy to samo (i robisz to powolnie, bo czytasz z adresów niewyrównanych do DWORDa).

Ten kod jest przygotowany pod obsługę wielu wątków (jedno z wymagań projektu)

 

Przykład

jeżeli mamy 4 wątki, 10 liczb w tabeli to:

1 wątek skopiuje 1 5 9 element

2 wątek 2 6 10 element

3 wątek 3 7

4 wątek 4 8

 

Do tego założenie jest, że ilość wątków (lista rozwijana wyboru) nie może być większa niż ilość liczb w tabeli.

Funkcja jest puszczona w pętli i wykonuje się dla każdego wątku, ale dla testów i tak wykonuje ją ilości wątków =1.

W c++ kod działa mi poprawnie. W asemblerze nie. Oczekuje, że po zakończeniu kodu otrzymam zapełnioną tablicę, w obecnej chwili otrzymuję tylko cześć elementów.

Wciąż nie wiem jak zdefiniowane są nowa_tablica oraz tablica. A pytałem o to, bo bez tego nie da się odpowiedzieć co chcesz uzyskać (choć domyślam się bardziej, niż dotychczas).

No i mam nadzieję, że autor wymagań jest świadom ich bzdurności. W ten sposób wielowątkowego kodu się nie pisze, więc ktoś kto stworzył wymagania nie miał bladego pojęcia na temat tego jak działa komputer. Tak napisany kod będzie działał wolniej na wielu wątkach, niż działałby na jednym dla prawie każdego rozmiaru danych (jeśli nie dla absolutnie każdego).

Zamiast używać xor eax,eax lepiejm użyć edq - wyzeruje eax i edx(i będzie szybszy)

Przy kopiowaniu też chyba jest, bo tablica jest prawdopodobnie bajtowa, a kopiuje zawsze DWORDa. :wink:

 

 

To dynamiczne tablice integerów, które indeksuje od 1, bo w [0] mam inne jeszcze informacje zachowane

 

int *tablica=new int[MojeFunkcje::PobierzLiczebnosc()];

int *nowa_tablica;

nowa_tablica = new int[ilosc+1];

Czyli to jednak nie tablica bajtów, a intów. Nic dziwnego, że kopiujesz tylko część. :slight_smile: Przy kopiowaniu mówisz “weź 4 bajty spod adresu X i skopiuj pod adres Y”. Następnie inkrementujesz X i Y o liczbę wątków i powtarzasz ten proces. Załóżmy, że liczba wątków jest równa 1 - dodajesz do adresów po jeden i powtarzasz kopiowanie. W efekcie kopiujesz 3 bajty, które już skopiowałeś i jeden dodatkowy. Musisz się przesuwać o 4*liczbaWatkow, a nie o liczbaWatkow. Asm generalnie nie wie, że ebx i edx używasz jako indeksy w tablicy intów (każdy ma 4 bajty), więc nie zadziała tak, jak oczekujesz. Ale to nie jest jedyny problem z tym kodem. ;-]

Reguła, jak zawsze: debuguj. Asm x86 się dużo łatwiej czyta, niż pisze, więc stosunkowo nietrudno Ci będzie znaleźć problem w kodzie o tej złożoności, jeśli poobserwujesz go w działaniu.

 

 

Zmieniłem dodawanie tablicy z add ebx, ecx na add ebc, [adresB+ecx*4] gdzie adresB to adres początku. Gdzie pod ecx najpierw przechowuje index wątku a potem wrzucam liczbę wątków Analogicznie dla add edx, ecx. Teraz przy debuggowaniu wyrzuca mnie na mov eax, [ebx] mov [edx], eax. . Jak zmieniłem na [adresB+ecx*4] i analogicznie dla edx, to tablica zwraca same 0, czyli to co było przed wywołaniem funkcji Już nie mam pomysłów na to.

Co to znaczy “wyrzuca mnie na mov…”? Co wyrzuca, jak wyrzuca, gdzie wyrzuca?

Nie wiem w czym debugujesz, ale powinieneś po przypisaniu rejestrom funkcji sprawdzić (przykładowo dla oryginalnego kodu przy debugowaniu w ntsd/windbg: dd ebx), czy pod adresami źródła i celu masz to, co oczekujesz mieć (jeśli wołasz to z C - a zakładam, że tak jest - to umieść także w tablicy docelowej przewidywalny wzorzec danych, żebyś wiedział, czy widzisz obszar pamięci, który Cię interesuje). Jeśli adresy się zgadzają, to sprawdź jaki jest pattern odczytu/zapisu w poszczególnych krokach pętli w celu ustalenia gdzie masz problem w logice funkcji.

A ponad wszystko: jeśli chcesz pomocy na forum to umieszczaj na pastebin aktualny kod i linkuj. I komentuj swój kod w sposób sensowny (hint: pisanie co robi każda linijka jest bezużyteczne; robiącego audyt interesuje algorytm i intencja).