“Int 0x80” có nghĩa là gì trong mã hợp ngữ?


Câu trả lời:


69

Nó vượt qua điều khiển để ngắt vectơ 0x80

Xem http://en.wikipedia.org/wiki/Interrupt_vector

Trên Linux, hãy xem điều này : nó được sử dụng để xử lý system_call. Tất nhiên trên một hệ điều hành khác, điều này có thể có nghĩa là một cái gì đó hoàn toàn khác.


5
bằng cách rút ngắn câu chuyện dài rằng hướng dẫn có nghĩa là LÀM NÓ cho hướng dẫn là trước đây.
Yuda Prawira

2
@YudaPrawira: bạn nên nghĩ đến các hướng dẫn trước đó như thiết lập args trong thanh ghi và int 0x80như một kiểu đặc biệt của callmột hàm trong hạt nhân (được chọn bởi eax).
Peter Cordes

Tại sao bạn nói "ĐÃ ĐƯỢC SỬ DỤNG?" Nó không còn được sử dụng?
Liga

129

intnghĩa là ngắt, và number 0x80là số ngắt. Một ngắt chuyển luồng chương trình cho bất kỳ ai đang xử lý ngắt đó, ngắt 0x80trong trường hợp này. Trong Linux, 0x80trình xử lý ngắt là hạt nhân và được sử dụng để thực hiện các cuộc gọi hệ thống tới hạt nhân bởi các chương trình khác.

Kernel được thông báo về lệnh gọi hệ thống mà chương trình muốn thực hiện, bằng cách kiểm tra giá trị trong thanh ghi %eax(cú pháp AT&T và EAX trong cú pháp Intel). Mỗi lệnh gọi hệ thống có các yêu cầu khác nhau về việc sử dụng các thanh ghi khác. Ví dụ: giá trị 1in %eaxcó nghĩa là một lệnh gọi hệ thống exit()và giá trị trong %ebxgiữ giá trị của mã trạng thái cho exit().


47

Hãy ghi nhớ rằng 0x80=80h =128

Bạn có thể thấy ở đâyINTchỉ là một trong rất nhiều hướng dẫn (thực sự là đại diện hội Ngôn ngữ (hay tôi nên nói 'ghi nhớ') của nó) mà tồn tại trong tập lệnh x86. Bạn cũng có thể tìm thêm thông tin về hướng dẫn này trong sách hướng dẫn riêng của Intel tại đây .

Tóm tắt từ PDF:

INT n / INTO / INT 3 — Thủ tục gọi đến ngắt

Lệnh INT n tạo ra một cuộc gọi tới trình xử lý ngắt hoặc ngoại lệ được chỉ định với toán hạng đích. Toán hạng đích chỉ định một vectơ từ 0 đến 255, được mã hóa dưới dạng giá trị trung gian 8 bit không dấu. Lệnh INT n là cách ghi nhớ chung để thực hiện lệnh gọi do phần mềm tạo ra tới trình xử lý ngắt.

Như bạn có thể thấy 0x80toán hạng đích trong câu hỏi của bạn. Tại thời điểm này, CPU biết rằng nó sẽ thực thi một số mã nằm trong Kernel, nhưng mã nào? Điều đó được xác định bởi Vectơ ngắt trong Linux.

Một trong những ngắt phần mềm DOS hữu ích nhất là ngắt 0x21. Bằng cách gọi nó với các tham số khác nhau trong thanh ghi (chủ yếu là ah và al), bạn có thể truy cập các hoạt động IO khác nhau, đầu ra chuỗi và hơn thế nữa.

Hầu hết các hệ thống Unix và các dẫn xuất không sử dụng ngắt phần mềm, ngoại trừ ngắt 0x80, được sử dụng để thực hiện các cuộc gọi hệ thống. Điều này được thực hiện bằng cách nhập giá trị 32-bit tương ứng với một chức năng hạt nhân vào thanh ghi EAX của bộ xử lý và sau đó thực thi INT 0x80.

Vui lòng xem điều này, nơi các giá trị có sẵn khác trong bảng trình xử lý ngắt được hiển thị:

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy bảng chỉ CPU để thực hiện lệnh gọi hệ thống. Bạn có thể tìm thấy bảng Cuộc gọi Hệ thống Linux tại đây .

Vì vậy, bằng cách di chuyển giá trị 0x1 vào thanh ghi EAX và gọi INT 0x80 trong chương trình của bạn, bạn có thể làm cho quá trình thực thi mã trong Kernel sẽ dừng (thoát) quá trình đang chạy hiện tại (trên Linux, CPU Intel x86).

Không được nhầm lẫn ngắt phần cứng với ngắt phần mềm. Đây là một câu trả lời rất tốt về vấn đề này.

Đây cũng là một nguồn tốt.


4
Liên kết bảng Cuộc gọi Hệ thống Linux bị hỏng = \
Miguel Angelo

1
Hầu hết các hệ thống Unix và các dẫn xuất không sử dụng ngắt phần mềm (ngoại trừ int 0x80) có vẻ như là một cách nói kỳ lạ. Các int 0x80i386 hệ thống Linux gọi ABI là cực kỳ giống với DOS int 0x21ABI. Đặt một số cuộc gọi vào một thanh ghi (AH cho DOS, EAX cho Linux) và các args khác trong các thanh ghi khác, sau đó chạy một lệnh ngắt phần mềm. Sự khác biệt chính là ở những gì mà các lệnh gọi hệ thống cho phép bạn thực hiện (truy cập trực tiếp vào phần cứng trong DOS chứ không phải Linux) chứ không phải ở cách bạn gọi chúng.
Peter Cordes

Đây là một liên kết bảng syscall không bị hỏng. syscalls.kernelgrok.com Chỉ cần mở rộng nó để hiển thị tất cả các cuộc gọi ở trên cùng.
ollien

Khi sử dụng Linux 64bits, Bạn có thể thấy cuộc gọi hệ thống khả dụng vào/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton

11

Ví dụ về lệnh gọi hệ thống Linux có thể chạy tối thiểu

Linux thiết lập trình xử lý ngắt để 0x80nó thực hiện các lệnh gọi hệ thống, một cách để các chương trình vùng người dùng giao tiếp với hạt nhân.

.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

Biên dịch và chạy với:

as -o main.o main.S
ld -o main.out main.o
./main.out

Kết quả: chương trình in ra stdout:

hello world

và thoát ra ngoài sạch sẽ.

Bạn không thể đặt trình xử lý ngắt của riêng mình trực tiếp từ vùng người dùng vì bạn chỉ có vòng 3 và Linux ngăn bạn làm như vậy .

GitHub ngược dòng . Đã thử nghiệm trên Ubuntu 16.04.

Các lựa chọn thay thế tốt hơn

int 0x80đã được thay thế bởi các lựa chọn thay thế tốt hơn để thực hiện các cuộc gọi hệ thống: đầu tiên sysenter, sau đó là VDSO.

x86_64 có một syscallhướng dẫn mới .

Xem thêm: "int 0x80" hay "syscall" thì tốt hơn?

Ví dụ tối thiểu 16 bit

Trước tiên, hãy tìm hiểu cách tạo một hệ điều hành bootloader tối thiểu và chạy nó trên QEMU và phần cứng thực như tôi đã giải thích ở đây: https://stackoverflow.com/a/32483545/895245

Bây giờ bạn có thể chạy ở chế độ thực 16 bit:

    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

Điều này sẽ làm theo thứ tự:

  • Do 0.
  • Do 1.
  • hlt: ngừng thực hiện

Lưu ý cách bộ xử lý tìm kiếm trình xử lý đầu tiên tại địa chỉ 0và trình xử lý thứ hai tại 4: đó là một bảng trình xử lý được gọi là IVT và mỗi mục nhập có 4 byte.

Ví dụ tối thiểu thực hiện một số IO để hiển thị các trình xử lý.

Ví dụ về chế độ bảo vệ tối thiểu

Hệ điều hành hiện đại chạy ở chế độ được gọi là được bảo vệ.

Việc xử lý có nhiều lựa chọn hơn trong chế độ này, vì vậy nó phức tạp hơn, nhưng tinh thần là như nhau.

Bước quan trọng là sử dụng các lệnh LGDT và LIDT, các lệnh này trỏ đến địa chỉ của cấu trúc dữ liệu trong bộ nhớ (Bảng mô tả ngắt) mô tả các trình xử lý.

Ví dụ tối thiểu



4

Lệnh "int" gây ra ngắt.

Một sự gián đoạn là gì?

Câu trả lời đơn giản: Nói một cách đơn giản, ngắt là một sự kiện làm ngắt CPU và yêu cầu nó chạy một tác vụ cụ thể.

Câu trả lời chi tiết :

CPU có một bảng các Quy trình Dịch vụ Ngắt (hoặc ISR) được lưu trữ trong bộ nhớ. Trong Chế độ thực (16-bit), điều này được lưu trữ dưới dạng IVT hoặc I nterrupt V ector T có thể. IVT thường được đặt tại 0x0000:0x0000(địa chỉ thực0x00000 ), và nó là một loạt các địa chỉ bù phân đoạn trỏ đến ISR. Hệ điều hành có thể thay thế các mục IVT đã có từ trước bằng ISR của riêng nó.

(Lưu ý: Kích thước của IVT được cố định ở 1024 (0x400) byte.)

Trong Chế độ được bảo vệ (32-bit), CPU sử dụng IDT. IDT là một cấu trúc có độ dài thay đổi bao gồm các bộ mô tả (còn được gọi là các cổng), cho CPU biết về các bộ xử lý ngắt. Cấu trúc của các bộ mô tả này phức tạp hơn nhiều so với các mục bù phân đoạn đơn giản của IVT; nó đây:

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 có thể có kích thước thay đổi, nhưng nó phải tuần tự, tức là nếu bạn khai báo IDT của mình là từ 0x00 đến 0x50, bạn phải có mọi ngắt từ 0x00 đến 0x50. Hệ điều hành không nhất thiết phải sử dụng tất cả chúng, vì vậy bit Hiện tại cho phép CPU xử lý đúng các ngắt mà hệ điều hành không có ý định xử lý.

Khi một ngắt xảy ra (hoặc bởi một bộ kích hoạt bên ngoài (ví dụ như một thiết bị phần cứng) trong IRQ hoặc bởi intlệnh từ một chương trình), CPU sẽ đẩy EFLAGS, sau đó là CS và sau đó là EIP. (Chúng được tự động khôi phục bằng iretlệnh trả về ngắt.) Hệ điều hành thường lưu trữ thêm thông tin về trạng thái của máy, xử lý ngắt, khôi phục trạng thái máy và tiếp tục.

Trong nhiều HĐH * NIX (bao gồm cả Linux), các lệnh gọi hệ thống dựa trên ngắt. Chương trình đặt các đối số cho lệnh gọi hệ thống trong các thanh ghi (EAX, EBX, ECX, EDX, v.v.) và gọi ngắt 0x80. Kernel đã thiết lập IDT để chứa một trình xử lý ngắt trên 0x80, được gọi khi nó nhận được ngắt 0x80. Sau đó, hạt nhân đọc các đối số và gọi một hàm nhân tương ứng. Nó có thể lưu trữ lợi nhuận trong EAX / EBX. Các lệnh gọi hệ thống phần lớn đã được thay thế bằng sysentersysexit(hoặc syscallsysret trên AMD), cho phép vào vòng 0 nhanh hơn.

Ngắt này có thể có một ý nghĩa khác trong một hệ điều hành khác. Hãy chắc chắn để kiểm tra tài liệu của nó.


Thực tế thú vị: Lệnh gọi ABI của hệ thống i386 của FreeBSD chuyển các args trên ngăn xếp không gian người dùng. Chỉ eaxđược sử dụng cho số syscall. asm.sourceforge.net/intro/hello.html
Peter Cordes

2

Như đã đề cập, nó làm cho điều khiển nhảy tới vectơ ngắt 0x80. Trong thực tế, điều này có nghĩa là gì (ít nhất là trong Linux) là một lệnh gọi hệ thống được gọi ra; lệnh gọi hệ thống chính xác và các đối số được xác định bởi nội dung của các thanh ghi. Ví dụ: exit () có thể được gọi bằng cách đặt% eax thành 1, theo sau là 'int 0x80'.


1

Nó yêu cầu cpu kích hoạt vector ngắt 0x80, trên hệ điều hành Linux là ngắt lệnh gọi hệ thống, được sử dụng để gọi các chức năng hệ thống như open()đối với tệp, v.v.


9
Nói một cách chính xác, nó không nói với hạt nhân ... Nó nói với CPU, nơi tìm kiếm trình xử lý trong IDT, cuối cùng trở thành một con trỏ tới một số mã hạt nhân.
asveikau

Thật. Tôi cho rằng cụm từ tốt hơn sẽ là nó yêu cầu CPU kích hoạt vector và vector (như một phần của hạt nhân) gọi hàm.
Amber,

cái nào kết thúc làm điều này, inturn kết thúc làm điều đó, cái nào sau đó làm cái này, cái nào sau đó đến đó lẫn lộn . : / Amber có một câu trả lời đó là understandable..thats nó ..
Afzaal Ahmad Zeeshan

1

int không là gì khác ngoài một sự gián đoạn, tức là bộ xử lý sẽ đặt quá trình thực thi hiện tại của nó để giữ.

0x80 không là gì ngoài một lệnh gọi hệ thống hoặc lệnh gọi hạt nhân. tức là chức năng hệ thống sẽ được thực thi.

Cụ thể, 0x80 đại diện cho rt_sigtimedwait / init_module / restart_sys, nó thay đổi theo từng kiến ​​trúc.

Để biết thêm chi tiết, hãy tham khảo https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.