skracając długą historię, która oznacza instrukcje ZRÓB TO, ponieważ instrukcje były wcześniej.
Yuda Prawira
2
@YudaPrawira: powinieneś myśleć o wcześniejszych instrukcjach jako o ustawianiu argumentów w rejestrach i int 0x80jako o specjalnym rodzaju callfunkcji w jądrze (wybieranej przez eax).
Peter Cordes
Dlaczego powiedziałeś „BYŁ używany?” Czy nie jest już używany?
Liga
129
intoznacza przerwanie, a liczba 0x80jest numerem przerwania. Przerwanie przenosi przepływ programu do tego, kto obsługuje to przerwanie, którym 0x80w tym przypadku jest przerwanie . W Linuksie obsługa 0x80przerwań jest jądrem i jest używana do wykonywania wywołań systemowych jądra przez inne programy.
Jądro jest powiadamiane o tym, które wywołanie systemowe chce wykonać program, sprawdzając wartość w rejestrze %eax(składnia AT&T i EAX w składni Intela). Każde wywołanie systemowe ma inne wymagania dotyczące wykorzystania innych rejestrów. Na przykład wartość 1in %eaxoznacza wywołanie systemowe exit(), a wartość in %ebxzawiera wartość kodu statusu dla exit().
Widzisz tutaj, że INTjest to tylko jedna z wielu instrukcji (właściwie reprezentacja języka asemblera (lub powinienem powiedzieć „mnemonik”) tego), które istnieją w zestawie instrukcji x86. Więcej informacji na temat tej instrukcji można również znaleźć w podręczniku firmy Intel, który można znaleźć tutaj .
Podsumowując z pliku PDF:
INT n / INTO / INT 3 - Procedura wywołania przerwania
Instrukcja INT n generuje wywołanie procedury obsługi przerwania lub wyjątku określonej w operandzie przeznaczenia. Operand docelowy określa wektor od 0 do 255, zakodowany jako 8-bitowa wartość pośrednia bez znaku. Instrukcja INT n jest ogólnym mnemonikiem do wykonywania wywołania generowanego programowo do obsługi przerwań.
Jak widać, argumentem docelowym w pytaniu jest 0x80 . W tym momencie procesor wie, że powinien wykonać kod znajdujący się w jądrze, ale jaki kod? Jest to określane przez wektor przerwań w systemie Linux.
Jednym z najbardziej przydatnych przerwań programowych DOS było przerwanie 0x21. Wywołując go z różnymi parametrami w rejestrach (głównie ah i al), można uzyskać dostęp do różnych operacji IO, wyjścia łańcuchowego i innych.
Większość systemów uniksowych i pochodnych nie używa przerwań programowych, z wyjątkiem przerwania 0x80, używanego do wykonywania wywołań systemowych. Odbywa się to poprzez wprowadzenie 32-bitowej wartości odpowiadającej funkcji jądra do rejestru EAX procesora, a następnie wykonanie INT 0x80.
Spójrz na to, gdzie pokazane są inne dostępne wartości w tabelach obsługi przerwań:
Jak widać, tabela wskazuje procesorowi wykonanie wywołania systemowego. Tabelę wywołań systemowych Linuksa znajdziesz tutaj .
Więc przenosząc wartość 0x1 do rejestru EAX i wywołując INT 0x80 w swoim programie, możesz sprawić, że proces zacznie wykonywać kod w jądrze, który zatrzyma (zakończy) aktualnie działający proces (w systemie Linux, procesor Intel x86).
Przerwania sprzętowego nie należy mylić z przerwaniem programowym. Oto bardzo dobra odpowiedź na ten temat.
Link do tabeli wywołań systemu Linux jest uszkodzony = \
Miguel Angelo
1
Większość systemów Unix i pochodnych nie używa przerwań programowych (z wyjątkiem int 0x80) wydaje się dziwnym sposobem ujęcia tego. int 0x80I386 Linux wywołanie systemowe ABI jest bardzo podobna do DOS int 0x21ABI. Umieść numer wywoławczy w rejestrze (AH dla DOS, EAX dla Linuksa) i inne argumenty w innych rejestrach, a następnie uruchom instrukcję przerwania oprogramowania. Główna różnica polega na tym, na co pozwalają wywołania systemowe (dostęp do sprzętu bezpośrednio w DOS, ale nie w Linuksie), a nie w sposobie ich wywoływania.
Peter Cordes,
Oto nieuszkodzony link do tabeli wywołań systemowych. syscalls.kernelgrok.com Po prostu rozwiń go, aby wyświetlić wszystkie wywołania u góry.
ollien
Korzystając z 64-bitowego systemu Linux, można zobaczyć wywołanie systemowe dostępne pod adresem/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton
11
Przykład minimalnego uruchomienia systemu Linux
Linux konfiguruje obsługę przerwań w 0x80taki sposób, że implementuje wywołania systemowe, sposób komunikowania się programów środowiska użytkownika z jądrem.
.data
s:
.ascii "hello world\n"
len = . - s
.text
.global _start
_start:
movl $4, %eax /* write system call number */
movl $1, %ebx /* stdout */
movl $s, %ecx /* the data to print */
movl $len, %edx /* length of the buffer */
int $0x80
movl $1, %eax /* exit system call number */
movl $0, %ebx /* exit status */
int $0x80
Skompiluj i uruchom z:
as -o main.o main.S
ld -o main.out main.o
./main.out
Wynik: program drukuje na stdout:
hello world
i wychodzi czysto.
Nie możesz ustawić własnych programów obsługi przerwań bezpośrednio z przestrzeni użytkownika, ponieważ masz tylko pierścień 3, a Linux ci to uniemożliwia .
Najpierw dowiedz się, jak stworzyć minimalny system operacyjny bootloadera i uruchomić go na QEMU i prawdziwym sprzęcie, jak wyjaśniłem tutaj: https://stackoverflow.com/a/32483545/895245
Teraz możesz działać w 16-bitowym trybie rzeczywistym:
movw $handler0, 0x00
mov %cs, 0x02
movw $handler1, 0x04
mov %cs, 0x06
int $0
int $1
hlt
handler0:
/* Do 0. */
iret
handler1:
/* Do 1. */
iret
Zrobiłoby to w kolejności:
Do 0.
Do 1.
hlt: zatrzymaj wykonywanie
Zwróć uwagę, jak procesor szuka pierwszego programu obsługi pod adresem 0, a drugiego pod adresem 4: to jest tablica programów obsługi nazywana IVT , a każdy wpis ma 4 bajty.
Nowoczesne systemy operacyjne działają w tzw. Trybie chronionym.
Obsługa ma więcej opcji w tym trybie, więc jest bardziej złożona, ale duch jest ten sam.
Kluczowym krokiem jest użycie instrukcji LGDT i LIDT, które wskazują adres struktury danych w pamięci (tablica deskryptorów przerwań), która opisuje procedury obsługi.
Prosta odpowiedź: przerwanie, mówiąc najprościej, jest zdarzeniem, które przerywa procesor i nakazuje mu wykonanie określonego zadania.
Szczegółowa odpowiedź :
Procesor posiada tablicę procedur obsługi przerwań (lub ISR) przechowywanych w pamięci. W Real (16-bit) Tryb ten jest przechowywany jako IVT , albo ja nterrupt V ector T stanie. IVT zwykle znajduje się pod adresem 0x0000:0x0000(adres fizyczny 0x00000) i jest to seria adresów przesuniętych w segmentach, które wskazują na ISR. System operacyjny może zastąpić istniejące wcześniej wpisy IVT swoimi własnymi ISR.
(Uwaga: rozmiar IVT jest ustalony na 1024 (0x400) bajtów.)
W trybie chronionym (32-bitowym) procesor używa IDT. IDT jest strukturą o zmiennej długości, która składa się z deskryptorów (zwanych inaczej bramkami), które informują procesor o obsłudze przerwań. Struktura tych deskryptorów jest znacznie bardziej złożona niż proste wpisy przesunięcia segmentów w IVT; tutaj jest:
bytes 0, 1: Lower 16 bits of the ISR's address.
bytes 2, 3: A code segment selector (in the GDT/LDT)
byte 4: Zero.
byte 5: A type field consisting of several bitfields.
bit 0: P (Present): 0 for unused interrupts, 1 for used interrupts.*
bits 1, 2: DPL (Descriptor Privilege Level): The privilege level the descriptor (bytes 2, 3) must have.
bit 3: S (Storage Segment): Is 0 for interrupt and trap gates. Otherwise, is one.
bits 4, 5, 6, 7: GateType:
0101: 32 bit task gate
0110: 16-bit interrupt gate
0111: 16-bit trap gate
1110: 32-bit interrupt gate
1111: 32-bit trap gate
* IDT może mieć zmienną wielkość, ale musi być sekwencyjny, tj. Jeśli deklarujesz IDT od 0x00 do 0x50, musisz mieć każde przerwanie od 0x00 do 0x50. System operacyjny niekoniecznie używa ich wszystkich, więc obecny bit pozwala procesorowi poprawnie obsłużyć przerwania, których system operacyjny nie zamierza obsłużyć.
Kiedy pojawia się przerwanie (albo przez zewnętrzny wyzwalacz (np. Urządzenie sprzętowe) w IRQ, albo przez intinstrukcję z programu), CPU wypycha EFLAGS, następnie CS, a następnie EIP. (Są one automatycznie przywracane przeziret instrukcję powrotu przerwania). System operacyjny zwykle przechowuje więcej informacji o stanie maszyny, obsługuje przerwanie, przywraca stan maszyny i kontynuuje.
W wielu systemach operacyjnych * NIX (w tym Linux), wywołania systemowe są oparte na przerwaniach. Program umieszcza argumenty wywołania systemowego w rejestrach (EAX, EBX, ECX, EDX, itd.) I wywołuje przerwanie 0x80. Jądro ustawiło już IDT tak, aby zawierał obsługę przerwań na 0x80, która jest wywoływana, gdy otrzyma przerwanie 0x80. Następnie jądro odczytuje argumenty i odpowiednio wywołuje funkcję jądra. Może przechowywać zwrot w EAX / EBX. Wywołania systemowe zostały w dużej mierze zastąpione przez instrukcje sysenteri sysexit(lub syscalli sysretna AMD), które pozwalają na szybsze wejście do pierścienia 0.
To przerwanie może mieć inne znaczenie w innym systemie operacyjnym. Koniecznie sprawdź jego dokumentację.
Ciekawostka: wywołanie systemowe i386 we FreeBSD, ABI, przekazuje argumenty na stos przestrzeni użytkownika. Tylko eaxsłuży do numer funkcji. asm.sourceforge.net/intro/hello.html
Peter Cordes
2
Jak wspomniano, powoduje przeskok sterowania do wektora przerwania 0x80. W praktyce oznacza to (przynajmniej pod Linuksem), że wywoływane jest wywołanie systemowe; dokładne wywołanie systemowe i argumenty są zdefiniowane przez zawartość rejestrów. Na przykład exit () można wywołać, ustawiając% eax na 1, a następnie „int 0x80”.
Mówi procesorowi, aby aktywował wektor przerwań 0x80, który w systemach operacyjnych Linux jest przerwaniem wywołania systemowego, używanym do wywoływania funkcji systemowych, takich jak open()dla plików, i tak dalej.
Ściśle mówiąc, nie informuje jądra ... Mówi procesorowi, który wyszukuje procedurę obsługi w IDT, co kończy się wskazaniem do kodu jądra.
asveikau
Prawdziwe. Przypuszczam, że lepszym sformułowaniem byłoby polecenie CPU, aby aktywował wektor, a wektor (jako część jądra) wywołuje funkcję.
Bursztynowy
co kończy się robieniem tego, co z kolei kończy się robieniem tamtego, co potem robi to, co potem idzie tam zdezorientowane . : / Amber ma odpowiedź, która jest zrozumiała… to wszystko…
Afzaal Ahmad Zeeshan
1
int to nic innego jak przerwanie, tj. procesor wstrzyma bieżące wykonanie.
0x80 to nic innego jak wywołanie systemowe lub wywołanie jądra. tzn. funkcja systemowa zostanie wykonana.
Mówiąc konkretnie, 0x80 reprezentuje rt_sigtimedwait / init_module / restart_sys, różni się w zależności od architektury.
Odpowiedzi:
Przekazuje sterowanie, aby przerwać wektor 0x80
Zobacz http://en.wikipedia.org/wiki/Interrupt_vector
W systemie Linux spójrz na to : był używany do obsługi
system_call
. Oczywiście w innym systemie operacyjnym może to oznaczać coś zupełnie innego.źródło
int 0x80
jako o specjalnym rodzajucall
funkcji w jądrze (wybieranej przezeax
).int
oznacza przerwanie, a liczba0x80
jest numerem przerwania. Przerwanie przenosi przepływ programu do tego, kto obsługuje to przerwanie, którym0x80
w tym przypadku jest przerwanie . W Linuksie obsługa0x80
przerwań jest jądrem i jest używana do wykonywania wywołań systemowych jądra przez inne programy.Jądro jest powiadamiane o tym, które wywołanie systemowe chce wykonać program, sprawdzając wartość w rejestrze
%eax
(składnia AT&T i EAX w składni Intela). Każde wywołanie systemowe ma inne wymagania dotyczące wykorzystania innych rejestrów. Na przykład wartość1
in%eax
oznacza wywołanie systemoweexit()
, a wartość in%ebx
zawiera wartość kodu statusu dlaexit()
.źródło
Pamiętaj, że
0x80
=80h
=128
Widzisz tutaj, że
INT
jest to tylko jedna z wielu instrukcji (właściwie reprezentacja języka asemblera (lub powinienem powiedzieć „mnemonik”) tego), które istnieją w zestawie instrukcji x86. Więcej informacji na temat tej instrukcji można również znaleźć w podręczniku firmy Intel, który można znaleźć tutaj .Podsumowując z pliku PDF:
Jak widać, argumentem docelowym w pytaniu jest 0x80 . W tym momencie procesor wie, że powinien wykonać kod znajdujący się w jądrze, ale jaki kod? Jest to określane przez wektor przerwań w systemie Linux.
Jednym z najbardziej przydatnych przerwań programowych DOS było przerwanie 0x21. Wywołując go z różnymi parametrami w rejestrach (głównie ah i al), można uzyskać dostęp do różnych operacji IO, wyjścia łańcuchowego i innych.
Większość systemów uniksowych i pochodnych nie używa przerwań programowych, z wyjątkiem przerwania 0x80, używanego do wykonywania wywołań systemowych. Odbywa się to poprzez wprowadzenie 32-bitowej wartości odpowiadającej funkcji jądra do rejestru EAX procesora, a następnie wykonanie INT 0x80.
Spójrz na to, gdzie pokazane są inne dostępne wartości w tabelach obsługi przerwań:
Jak widać, tabela wskazuje procesorowi wykonanie wywołania systemowego. Tabelę wywołań systemowych Linuksa znajdziesz tutaj .
Więc przenosząc wartość 0x1 do rejestru EAX i wywołując INT 0x80 w swoim programie, możesz sprawić, że proces zacznie wykonywać kod w jądrze, który zatrzyma (zakończy) aktualnie działający proces (w systemie Linux, procesor Intel x86).
Przerwania sprzętowego nie należy mylić z przerwaniem programowym. Oto bardzo dobra odpowiedź na ten temat.
To też jest dobre źródło.
źródło
int 0x80
I386 Linux wywołanie systemowe ABI jest bardzo podobna do DOSint 0x21
ABI. Umieść numer wywoławczy w rejestrze (AH dla DOS, EAX dla Linuksa) i inne argumenty w innych rejestrach, a następnie uruchom instrukcję przerwania oprogramowania. Główna różnica polega na tym, na co pozwalają wywołania systemowe (dostęp do sprzętu bezpośrednio w DOS, ale nie w Linuksie), a nie w sposobie ich wywoływania./usr/include/x86_64-linux-gnu/asm/unistd_64.h
Przykład minimalnego uruchomienia systemu Linux
Linux konfiguruje obsługę przerwań w
0x80
taki sposób, że implementuje wywołania systemowe, sposób komunikowania się programów środowiska użytkownika z jądrem.Skompiluj i uruchom z:
Wynik: program drukuje na stdout:
i wychodzi czysto.
Nie możesz ustawić własnych programów obsługi przerwań bezpośrednio z przestrzeni użytkownika, ponieważ masz tylko pierścień 3, a Linux ci to uniemożliwia .
GitHub upstream . Testowane na Ubuntu 16.04.
Lepsze alternatywy
int 0x80
zostało zastąpione lepszymi alternatywami wykonywania wywołań systemowych: najpierwsysenter
, a następnie VDSO.x86_64 ma nową
syscall
instrukcję .Zobacz też: Co jest lepsze "int 0x80" lub "syscall"?
Minimalny przykład 16-bitowy
Najpierw dowiedz się, jak stworzyć minimalny system operacyjny bootloadera i uruchomić go na QEMU i prawdziwym sprzęcie, jak wyjaśniłem tutaj: https://stackoverflow.com/a/32483545/895245
Teraz możesz działać w 16-bitowym trybie rzeczywistym:
Zrobiłoby to w kolejności:
Do 0.
Do 1.
hlt
: zatrzymaj wykonywanieZwróć uwagę, jak procesor szuka pierwszego programu obsługi pod adresem
0
, a drugiego pod adresem4
: to jest tablica programów obsługi nazywana IVT , a każdy wpis ma 4 bajty.Minimalny przykład, który wykonuje niektóre operacje we / wy, aby wyświetlić moduły obsługi.
Przykład minimalnego trybu chronionego
Nowoczesne systemy operacyjne działają w tzw. Trybie chronionym.
Obsługa ma więcej opcji w tym trybie, więc jest bardziej złożona, ale duch jest ten sam.
Kluczowym krokiem jest użycie instrukcji LGDT i LIDT, które wskazują adres struktury danych w pamięci (tablica deskryptorów przerwań), która opisuje procedury obsługi.
Minimalny przykład
źródło
http://www.linfo.org/int_0x80.html
źródło
Instrukcja „int” powoduje przerwanie.
Co to jest przerwanie?
Prosta odpowiedź: przerwanie, mówiąc najprościej, jest zdarzeniem, które przerywa procesor i nakazuje mu wykonanie określonego zadania.
Szczegółowa odpowiedź :
Procesor posiada tablicę procedur obsługi przerwań (lub ISR) przechowywanych w pamięci. W Real (16-bit) Tryb ten jest przechowywany jako IVT , albo ja nterrupt V ector T stanie. IVT zwykle znajduje się pod adresem
0x0000:0x0000
(adres fizyczny0x00000
) i jest to seria adresów przesuniętych w segmentach, które wskazują na ISR. System operacyjny może zastąpić istniejące wcześniej wpisy IVT swoimi własnymi ISR.(Uwaga: rozmiar IVT jest ustalony na 1024 (0x400) bajtów.)
W trybie chronionym (32-bitowym) procesor używa IDT. IDT jest strukturą o zmiennej długości, która składa się z deskryptorów (zwanych inaczej bramkami), które informują procesor o obsłudze przerwań. Struktura tych deskryptorów jest znacznie bardziej złożona niż proste wpisy przesunięcia segmentów w IVT; tutaj jest:
* IDT może mieć zmienną wielkość, ale musi być sekwencyjny, tj. Jeśli deklarujesz IDT od 0x00 do 0x50, musisz mieć każde przerwanie od 0x00 do 0x50. System operacyjny niekoniecznie używa ich wszystkich, więc obecny bit pozwala procesorowi poprawnie obsłużyć przerwania, których system operacyjny nie zamierza obsłużyć.
Kiedy pojawia się przerwanie (albo przez zewnętrzny wyzwalacz (np. Urządzenie sprzętowe) w IRQ, albo przez
int
instrukcję z programu), CPU wypycha EFLAGS, następnie CS, a następnie EIP. (Są one automatycznie przywracane przeziret
instrukcję powrotu przerwania). System operacyjny zwykle przechowuje więcej informacji o stanie maszyny, obsługuje przerwanie, przywraca stan maszyny i kontynuuje.W wielu systemach operacyjnych * NIX (w tym Linux), wywołania systemowe są oparte na przerwaniach. Program umieszcza argumenty wywołania systemowego w rejestrach (EAX, EBX, ECX, EDX, itd.) I wywołuje przerwanie 0x80. Jądro ustawiło już IDT tak, aby zawierał obsługę przerwań na 0x80, która jest wywoływana, gdy otrzyma przerwanie 0x80. Następnie jądro odczytuje argumenty i odpowiednio wywołuje funkcję jądra. Może przechowywać zwrot w EAX / EBX. Wywołania systemowe zostały w dużej mierze zastąpione przez instrukcje
sysenter
isysexit
(lubsyscall
isysret
na AMD), które pozwalają na szybsze wejście do pierścienia 0.To przerwanie może mieć inne znaczenie w innym systemie operacyjnym. Koniecznie sprawdź jego dokumentację.
źródło
eax
służy do numer funkcji. asm.sourceforge.net/intro/hello.htmlJak wspomniano, powoduje przeskok sterowania do wektora przerwania 0x80. W praktyce oznacza to (przynajmniej pod Linuksem), że wywoływane jest wywołanie systemowe; dokładne wywołanie systemowe i argumenty są zdefiniowane przez zawartość rejestrów. Na przykład exit () można wywołać, ustawiając% eax na 1, a następnie „int 0x80”.
źródło
Mówi procesorowi, aby aktywował wektor przerwań 0x80, który w systemach operacyjnych Linux jest przerwaniem wywołania systemowego, używanym do wywoływania funkcji systemowych, takich jak
open()
dla plików, i tak dalej.źródło
int to nic innego jak przerwanie, tj. procesor wstrzyma bieżące wykonanie.
0x80 to nic innego jak wywołanie systemowe lub wywołanie jądra. tzn. funkcja systemowa zostanie wykonana.
Mówiąc konkretnie, 0x80 reprezentuje rt_sigtimedwait / init_module / restart_sys, różni się w zależności od architektury.
Więcej informacji można znaleźć pod adresem https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
źródło