Najpierw dwie sprawy organizacyjne:
- Po co uczysz się assemblera x86? Jeśli na studia to rozumiem (tylko szkoda, że mamuty was uczą), jeśli nie, lepiej naucz się x64, bo to jest współczesny assembler na PC.
- Używaj debuggera, w każdym debuggerze możesz sobie podejrzeć stan rejestrów i pamięci, i jechać instrukcja po instrukcji. Poza stanem CFLAGS raczej nie powinno tam być czegoś czego nie wywnioskowałbyś ze zmian, które widzisz.
Teraz tak, myślę, że traktujesz ten kod zbyt niskopoziomowo. Generalnie masz stos. To po prostu wydzielony kawałek pamięci, rejestr ESP wskazuje na wierzchni element stosu, nie wiadomo natomiast gdzie się stos zaczyna (przynajmniej architektura nic o tym nie mówi, są sposoby, żeby to ogarnąć). Każdy koljny element jest wrzucany na stos o jedną komórkę (tutaj 4 bajty, choć to też zależy od rozmiaru argumentu) wcześniej. Tak więc push eax
znaczy właściwie tyle co
mov [esp], eax
sub esp, 4
Tyle tylko, że to co tu jest robione używa stosu wedle konwencji wywołania funkcji. Świadczy o tym pierwsza linia mov ebp, esp
, jest to kod idiomatyczny (choć zwykle zaraz potem jest push esp
). Robi się ze względu na ramkę stosu. W momencie wywołania funkcji, na wierzchu stosu (adres esp
) masz adres powrotu, który został tam umieszczony automatycznie przez instrukcję call
. Pod nim masz argumenty funkcji (esp+4 pierwszy parametr, esp+8 to drugi itd. Jest to pewne uproszczenie, ale na tą chwilę wystarczy).
Tyle tylko, że bardzo byłoby to uciążliwe gdybyś chciał używać stosu w funkcji, bo musiałbyś w każdym momencie programu wiedzieć ile masz elementów na stosie, dlatego jest konwencja z rejestrem ebp, zgodnie z którą środek ramki stosu trzymamy w ebp i używamy stosu jak chcemy. Wspomniana instrukcja push ebp
jest konieczna żeby utrzymywać tę konwencję przy kolejnych wywołaniach funkcji wewnątrz funkcji. Nie wiem jak to dokładnie jest na x86, ale na x64 jest to opcjonalne (ale kompilatory i tak to robią, jeśli nie masz włączonych optymalizacji), a ebp jest takim samym rejestrem jak inne.
W drugiej linijce zmniejszasz esp
o 8, co znów jest konwencjonalne i prawdopodobnie oznacza, że alokujesz miejsce na zmienne lokalne. Skoro masz wywołać scanf
to jest to zapewne bufor, co potwierdza linijka następna, wrzucasz adres ebp-4
czyli 4 bajty na bufor (pierwszy int) i 4 bajty na drugiego inta – to będzie ebp-8. Dalej idą parametry, ebp-12=&(ebp-4), ebp-16=&(ebp-8), ebp-20=&("%i %i\0"). Potem wywoływane jest call i wrzuca pod ebp-24 adres powrotu.
jak byś chciał się tego porządnie nauczyć to polecam się. :)