[asembler] kilka pytan i prosty program

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
Hellbike
Sędziwy Jeż
Sędziwy Jeż
Posty: 70
Rejestracja: 03 lut 2007, 09:59
Płeć: Mężczyzna
Wersja Ubuntu: 8.10
Środowisko graficzne: GNOME

[asembler] kilka pytan i prosty program

Post autor: Hellbike »

Rozumiem ze zadeklarowane zmienne zostaja utworzone w pamieci ram, a sam program 'pamieta' ich ardesy.
Rejestry moga przechowywac pewna wartosc - ktora moze byc rownie dobrze adresem, jak i wartoscia przechowywanym adresem (co dla procesora nie ma znaczenia).
jedyna operacja, jaka moge wykonac na pamieci ram, to zapisanie tam okreslonych bajtow - tzn, nie moge w pamieci ram wykonac algorytmu sumy logicznej, czy czegokolwiek innego - jedyne co moge zrobic, to zapisac okreslone juz dane (np. 00010111). do wykonywania operacji logicznych/arytmetycznych musze skopiowac pewne dane do rejestru procesora, i operowac na rejestrach.
w ksiazce przeczytalem, ze odnoszac sie zmiennej w pamieci ram, napisanie jej nazwy w nawiasach kwadratowych powoduje odczytanie jej wartosci, a bez nawiasow - adresu. w innej ksiazce mam nastepujacy przyklad, programu dodajcego dwie liczby:

.data
VARA DW 17
VARB DW 35
.stack 100h
.code
mov ax, @data
mov ds, ax
mov ax, VARA
add ax, VARB
w .code pierwsze dwie linijki sa dla mnie malo zrozumiale(wiem jaki jest cel ich istnienia, ale na przykladach pod linuksa nie musze tego umieszczac, dlaczego?), a pozostale powinno kolejno umieszczac adres VARA w rejestrze ax, a nastepnie zwiekszyc wartosc ax o wartosc adresu VARB. dlaczego nie uzyto tutaj nawiasow klamrowych?

chcialem napisac program dodajacy dwie liczby i wyswietlajacy wynik pod linuksa (idac za przykladem powyzej, bez nawiasow klamrowych).
format ELF executable ; typ pliku
entry _start ; punkt startu programu
segment readable executable ; początek sekcji kodu
_start:
mov eax, number1
add eax, number2
mov ebx, 1
mov ecx, eax
mov edx, 1
mov eax, 4
int 80h
segment readable writeable ; początek sekcji danych.
number1 dw 10
number2 dw 15
exc ma zawaierac adres danych, ktore chce wyswietlic. a co jesli dane te sa w rejestrze? czy mozna w ogole mowic o adresie rejestru? jesli tak, to jak go przekazac do innego rejestru? czy musze najpierw zawartosc adresu przekazac do zmiennej?
i co z wyswietleniem wartosci? chcac wyswietlic wartosc 17, czy musze najpierw napisac program konwertujacy 17 do 17 w postaci ASCII?

oraz dodatkowe pytanie odnosnie zmiennych - czy tworzac zmienna moge dokladnie okreslic jej polozenie w pamieci ram?
jesli tak, to czy pozniej moge zapisywac wartosci do konkretnej komorki, nie odnoszac sie do nazw zmiennych?
jesli tak, to czy moge zmusic procesor do dzialania "nad" systemem operacyjnym? nie wiem do konca jak to dziala, ale zakladam ze program uruchamiany kontrolowany jest przez system operacyjny, ktory moze blokowac dostep do pewnych elementow pamieci. Czy moge sprawic, aby procesor zaczal wykonywac operacje bezposrednio na pamieci ram, bez zadnej komunikacji z systemem operacyjnym?
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: [asembler] kilka pytan i prosty program

Post autor: doles2 »

Postaram się mało wiele zrozumiale (jak na mój ubogi zasób słownictwa) wytłumaczyć to i owo:
1. Program z Twojej książki jest pod DOSa - systemu gdzie wszystko pracuje w trybie rzeczywistym procesora, zatem trzeba ręcznie ustawiać segmenty. Innymi słowy wiesz że w TR (Tryb Rzeczywisty) trzeba pisać segment: offset a domyślnie adres segmentu danych jest czytany z DS (Data Segment - nazwa rejestru nieprzypadkowa ;)), dlatego program ręcznie ustawia tak, że ładuje DS na adres segmentu danych dla programu. Na Linuskie tego się nie robi bo:
a) Linux pracuje w trybie chronionym, nie ma jakiegoś podziału na segmenty, cała pamięć to jeden wielki segment.
b) Nie wolno na Linuksie (i na Windowsie też) tykać rejestrów segmentowych bowiem w nich znajdują się selektory deskryptorów (poczytaj sobie o mechanizmie stronicowania pamięci).

2. Na Linuksie wywołania sytemowe używasz podobnie jak w C. Czyli jeśli tam funkcja write() w C ma taką deklarację:

Kod: Zaznacz cały

ssize_t write(int fd, const void *buf, size_t count);
to w rejestrze EAX dajesz pierwszy parametr funkcji, w EBX drugi, zaś w ECX trzeci i tak dalej. W Twoim przypadku do ECX wrzucasz deskryptor wyjścia, czyli 1 bo to jest na Uniksie STDOUT, w ECX znajduje się adres ciągu znaków (To nie ma być ciąg ! Pamiętaj: ADRES) zaś w EDX liczbę bajtów do zapisania. Natomiast w rejestrze EAX musisz wpisać liczbę która jest identyfikatorem wywołania systemowego (4 to było sys_write()). Nie pamiętam gdzie to sprawdzić, może w pliku unistd.h, sprawdź w necie. Analogicznie podajesz argumenty w rejestrach dla innych wywołań systemowych. Generalnie pod Linuksem programowanie w Asemblerze bardzo przpomina język C (wbre pozorom).

3. Jeśli chcesz wyświetlić liczbę od 0 do 9 musisz tylko orować ją z 20h. Jeśli większa - no cóż - masz rację, potrzebna będzie konwersja do ASCII. Albo użycie pritnf() z glibca, jak najbardziej można to łączyć :)

4. Nie możesz robić nic ponad systemem operacyjnym. Pamiętam używasz języka procesora, ale programujesz system operacyjny, myśl tak jak pisząc w językach wysokiego poziomu, nie możesz sobie ot co użyć rozkazów out/in jak w systemie w trybie rzeczywistym (DOS).
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

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