Co oznacza „int 0x80” w kodzie asemblera?


Odpowiedzi:


69

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.


5
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().


47

Pamiętaj, że 0x80= 80h=128

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ń:

wprowadź opis obrazu tutaj

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.


4
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 .

GitHub upstream . Testowane na Ubuntu 16.04.

Lepsze alternatywy

int 0x80zostało zastąpione lepszymi alternatywami wykonywania wywołań systemowych: najpierw sysenter, a następnie VDSO.

x86_64 ma nową syscallinstrukcję .

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:

    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.

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



4

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 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”.


1

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.


9
Ś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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.