Aby zdefiniować tablicę w segmencie danych inicjalizowanych .data używamy dyrektyw db, dw itd. Możemy wykorzystać dyrektywę TIMES by nie pisać wielokrotnie tego samego.
Aby zdefiniować tablicę w segmencie danych nieinicjalizowanych .bss używamy dyrektyw resb, resw itd., pamiętając o operandzie określającym ilość rezerwowanych jednostek pamięci.
segment .data
a1 dd 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; tablica 10 podwójnych słów zainicjalizowana na 1,2,..,10
a2 dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; tablica 10 słów zainicjalizowana na 0
a3 times 10 dw 0 ; j.w. z wykorzystaniem TIMES
a4 times 200 db 0 ; tablica bajtów zawierająca 200 zer i potem 100 jedynek
times 100 db 1
segment .bss
a5 resd 10 ; tablica 10 podwójnych słów
a6 resw 100 ; tablica 100 słów
Warto pamiętać, że kompilator nie będzie w żaden sposób sprawdzał poprawności typów i ich właściwego użycia.
Poniższe zapisy definiują dokładnie takie same tablice (100 bajtów wypełnionych zerami).
tab1 times 100 db 0
tab2 times 50 dw 0
tab3 times 25 dd 0
Podany rozmiar jest głównie informacją dla assemblera jak ma traktować podaną stałą. Dlatego poniższe tablice nie są równoważne
tab1 times 100 db 1 ; kolejne bajty to 1,1,1,1,1,1,1,1,...
tab2 times 50 dw 1 ; 1,0,1,0,1,0,1,0,...
W asemblerze nie ma operatora [ ] z C, pozwalającego na dostęp do elementów tablicy. Aby uzyskać dostęp do elementu tablicy, należy obliczyć jego adres. Rozważmy definicje dwóch tablic:
array1 db 5, 4, 3, 2, 1 ; tablica bajtów
array2 dw 5, 4, 3, 2, 1 ; tablica słów
Przykłady operacji na tablicach:
mov al, [array1] ; al = array1[0]
mov al, [array1 + 1] ; al = array1[1]
mov [array1 + 3], al ; array1[3] = al
mov ax, [array2] ; ax = array2[0]
mov ax, [array2 + 2] ; ax = array2[1] (nie array2[2]!)
mov [array2 + 6], ax ; array2[3] = ax
mov [array2 + 3 * 2], ax ; można też tak
mov ax, [array2 + 1] ; w ax wartość 0x0400 (młodszy bajt z 5 i starszy z 4)
Na Listingu 1 przedstawiono przykład wykorzystania tablicy w procedurze sumującej liczby, wpisane w elementach tablicy:
Listing 1
mov rbx, array1 ; rbx = adres tablicy bajtów array1
mov rdx, 0 ; dx będzie zawierać sumę
mov rax, 0 ; zerujemy rax, bo w sumowaniu uczestniczy rejestr ax
mov rcx, 5 ; wielkość tablicy array1
lp:
mov al, [rbx] ; al = *ebx
add dx, ax ; dx += ax (nie al!)
inc rbx ; rbx++ (przesuwamy wskaźnik)
loop lp
Adresowanie skalowane ModR/M
Przy iteracyjnym dostępie do tablic korzysta się z adresowania skalowanego (ModR/M). Najbardziej ogólna forma takiego adresowania wygląda następująco:
[ base_reg + factor *index_reg + constant ]
gdzie
base_reg jest jednym z rejestrów ogólnego przeznaczenia np. RAX, RBX, RDI, R9 itd
factor jest równy 1, 2, 4 lub 8 w zależności od typu danych w indeksowanej tablicy t.j. bajt, słowo, podwójne słowo, poczwórne słowo (jeśli 1 to nie używamy),
index_reg jest jednym ogólnego przeznaczenia np. RAX, RBX, RDI, R9 itd
constant jest stałą (może np. służyć do wskazywania na dane pole wewnątrz większej struktury).
Listing 2
array2 dw 5, 4, 3, 2, 1 ; tablica słów
...
mov rbx, array2 ; rbx = adres tablicy array2
mov rcx, 5 ; liczba elementów tablicy
xor rdx, rdx ; zerujemy dx
sumowanie:
add dx, [rbx + 2*rcx - 2] ; dodajemy elementy od ostatniego
loop sumowanie
Jeżeli chcemy obliczyć adres elementu tablicy (np. w celu przekazania go do fukcji) możemy użyć instrukcji lea
lea rdx, [rbx + 2*rcx - 2] ; jeżeli rcx=2 to rdx będzie zawierał
; adres drugiego elementu tablicy (a nie jego wartość)
W poniższych zadaniach można korzystać z biblioteki asm64_io
Proszę napisać program wczytujący zadaną ilość liczb całkowitych do tablicy oraz obliczający ich iloczyn. Można wykorzystać kod przedstawiony na Listingu 1 lub 2.
Uwaga: Najpierw należy uzupełnić tablicę a dopiero potem w oddzielnej pętli obliczyć iloczyn.
Dla łańcucha tekstowego w stylu C (zakończonego zerem) oraz danej litery, wypisać jego długość i oraz indeks ostatniego wystąpienia danej litery (indeksujemy od 0).
Jeżeli litera nie występuje wypisujemy -1.
Uwaga: Łańcuch tekstowy i litera mogą być na "sztywno" wpisane w program.
Napisać funkcję przekształcającą dany łańcuch tekstowy (zakończony zerem) na liczbę całkowitą oraz drugą funkcję przekształcającą liczbę całkowitą (ze znakiem) na tekst.
Program powinien prezentować możliwości tych funkcji.
Dane są dwa ciągi znaków s1 i s2 (poniższe są przykładowe):
s1="abcdefghijklmnopqrstuvwxyz"
s2="zyxwvutsrqponmlkjihgfedcba"
Napisz program, który dla każdej litery ciągu wejściowego znalezionej na pozycji n w ciągu s1 wypisze odpowiadającą jej literę z ciągu s2 na pozycji n, natomiast nie znalezione znaki wypisuje bez zmian.
Przykład:
Podaj ciąg znaków...
ala ma kota
zoz nz plgz
Podaj ciąg znaków...
123 zoz nz plgz.
123 ala ma kota.