[nasm] Dostęp do elementu tablicy

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
Awatar użytkownika
MarioX
Piegowaty Guziec
Piegowaty Guziec
Posty: 18
Rejestracja: 09 gru 2006, 22:28
Płeć: Mężczyzna
Wersja Ubuntu: 8.10
Środowisko graficzne: GNOME

[nasm] Dostęp do elementu tablicy

Post autor: MarioX »

Witam,
chciałbym uzyskać dostęp do elementu tablicy, jako index elementu podając zmienną.

Żeby dalej nie mieszać podam przykład, o co mi chodzi:

Kod: Zaznacz cały

section .text

global _start

_start:	
	mov byte [string+1], 66					; podmiana liczby

	mov EAX, 4						; wypisywanie na ekran
	mov EBX, 1
	mov ECX, string
	mov EDX, string_l
	int 80h
	
	mov EAX, 1						; wyjście z programu
	int 80h
	
section .data
	string		db 90, 111, 100
	string_l 	equ $ - string
	index		db 1
I to działa bez problemu, ale zamieniając:

Kod: Zaznacz cały

	mov byte [string+1], 66				; podmiana liczby
na:

Kod: Zaznacz cały

	mov byte [string+index], 66			; podmiana liczby
Wywala:

Kod: Zaznacz cały

test.asm:8: error: beroset-p-637-invalid effective address
Więc ponawiam pytanie:
Jak można uzyskać dostęp do elementu tablicy, jako index elementu podając zmienną?
Oprogramowanie jest jak sex, lepsze jeśli nie trzeba za nie płacić :p
Awatar użytkownika
doles2
Sędziwy Jeż
Sędziwy Jeż
Posty: 46
Rejestracja: 24 lip 2006, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.10
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [nasm] Dostęp do elementu tablicy

Post autor: doles2 »

Po pytaniu sądzę, że jesteś raczej początkującym programistą w Asemblerze, choć - tutaj musze Ciebie pochwalić - świetnie sobie radzisz z używaniem znaków "[]". Mam na myśli to, że doskonale orientujesz się w adresowaniu (no może prawie, inaczej przecież byś nie pytał :P). Dobra, przejde do rzeczy.

Nie możesz używać zmiennej do adresowania, w sensie nie jako indeks. Oczywiście zmienna może być "bazą" dla adresowania, ale nie cyferką która będzie "robiła za przesunięcie". Pomyśl w ten sposób. Masz taki oto zapis:

Kod: Zaznacz cały

mov ecx, string
bardzo dobrze wiemy, że to oznacza załadowanie adresu zmiennej "string" do rejestru ECX. A teraz weźmy ten kawałek kodu:

Kod: Zaznacz cały

mov byte [string+1], 66
to spowoduje umieszczenie liczby 66 w komórce pamięci o adresie o 1 bajt większy niż adres zmiennej string, innymi słowy w kolejnej komórce pamięci, albo jak kto woli w kolejnej zmiennej w tablicy :)
Zatem jak NASM zobaczył coś takiego:

Kod: Zaznacz cały

mov byte [string+index], 66	
to nie bardzo wiedział o co chodzi. dla niego ten zapis oznaczałby, że przesunięciem "index" jest adres tej zmiennej nie zaś jej zawartości. A przecież zupełnie bez sensu jest ten (pseudo)kod:

Kod: Zaznacz cały

mov byte [string+ [index] ], 66	
To już jest absurd, jak sam mogłeś zauważyć. Zresztą nie jest to ograniczenie Asemblera, tylko procesora. Żaden z procesorów 80x86 ani 80x86_64 nie potrafi tak adresować pamięci. Tak, czyli indeks nie może być zmienną. Musi to być wartość bezpośrednia jak np "1" albo w rejestrze. I tutaj właśnie pięknie dobrnąłem do zapomianych rejestrów wskaźnikowych: ESI oraz EDI. Tak, właśnie po to one powstały aby odwalać tę brudną robotę. Twój program można tak zmodyfikować:

Kod: Zaznacz cały

section .text
global _start

_start:

        mov esi, 1
        mov byte [string + esi], 66
        mov eax, 4
        mov ebx, 1
        mov ecx, string
        mov edx, string_l
        int 80h

        mov eax, 1
        xor ebx, ebx
        int 80h

section .data
string   db     90, 111, 100, 10
string_l equ    $ - string
index    db     1
To nie jedyna możliwość. Zawsze można pokobinować z rozkazem LEA. Oto i kod:

Kod: Zaznacz cały

section .text
global _start

_start:

        lea eax,[string]     ;pobierz adres zmiennej string i zapisz go w eax
        inc eax                ;tenże adres zwiększ o 1
        mov byte [eax],66 ;[eax] czyli do adresu w eax wpisz 66
        mov eax, 4
        mov ebx, 1
        mov ecx, string
        mov edx, string_l
        int 80h

        mov eax, 1
        xor ebx, ebx
        int 80h

section .data
string   db     90, 111, 100, 10
string_l equ    $ - string
index    db     1

Jeśli to wszystko wiedziałeś i chciałeś tylko zapytać czy możesz użyć zmiennej w pamięci jako indeks to powiedziedź jest ultra krótka: Nie.
Awatar użytkownika
MarioX
Piegowaty Guziec
Piegowaty Guziec
Posty: 18
Rejestracja: 09 gru 2006, 22:28
Płeć: Mężczyzna
Wersja Ubuntu: 8.10
Środowisko graficzne: GNOME

Odp: [nasm] Dostęp do elementu tablicy

Post autor: MarioX »

Dzięki, za odpowiedź

Masz racje, dopiero zaczynam przygodę z asemblerem :)

Kombinowałem z rejestrami wskaźnikowymi, ale zamiast ESI dawałem SI i owszem kompilowało się, ale przy linkerze(tak to się chyba nazywa?), wywalało błąd:

Kod: Zaznacz cały

test.o: In function `_start':

test.asm:(.text+0x7): relocation truncated to fit: R_386_16 against `.data'
Dlaczego tak się dzieje?
Oprogramowanie jest jak sex, lepsze jeśli nie trzeba za nie płacić :p
Awatar użytkownika
doles2
Sędziwy Jeż
Sędziwy Jeż
Posty: 46
Rejestracja: 24 lip 2006, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.10
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: [nasm] Dostęp do elementu tablicy

Post autor: doles2 »

Powiem szczerze, że nie wiem dlaczego linker wywala takie błędy. Asemblerowi "to nie robi", że się tak wyrażę, on sprawdza tylko czy wszystkie bajty opcodów są poprawne oraz czy są poprawne tryby adresowania. Zasemblować zasemblowało jednak pewnie nie tak jakbyśmy sobie tego życzyli. Tutaj linker wywalił błąd wg mnie zupełnie niezwiązany z rejestrami i nawet nie potrafię go wytłumaczyć. Może jakieś dziwne mu wyszło obliczanie adresów dla pamięci gdzie adres bazowy jest 32-bitowy a wskaźnik SI szesnasto bitowy ? Nie wiem, nie mam pojęcia. Krótko mówiąc SI jest rejestrem 16-bitowym i powinieneś używać ZAWSZE rejestru 32-bitowego tak długo jak programujesz na systemie w trybie chronionym. Używaj po prostu ESI i EDI bez wględu na to czy zmienna jest bajtem, słowem, dwusłowem czy czymkolwiek innym.
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości