“ int 0x80” หมายถึงอะไรในรหัสแอสเซมบลี


คำตอบ:


70

ผ่านการควบคุมเพื่อขัดจังหวะเวกเตอร์ 0x80

ดูhttp://en.wikipedia.org/wiki/Interrupt_vector

บน Linux มีลักษณะที่นี้system_callมันถูกนำมาใช้ในการจัดการ แน่นอนในระบบปฏิบัติการอื่นอาจหมายถึงสิ่งที่แตกต่างไปจากเดิมโดยสิ้นเชิง


5
โดยย่อเรื่องยาวนั่นคือคำแนะนำหมายความว่าDO ITสำหรับการเรียนการสอนเป็นมาก่อน
ยุดาปวีรา

2
@YudaPrawira: คุณควรนึกถึงคำแนะนำก่อนหน้านี้เช่นการตั้งค่า args ในรีจิสเตอร์และint 0x80เป็นชนิดพิเศษของcallฟังก์ชันในเคอร์เนล (เลือกโดยeax)
Peter Cordes

ทำไมคุณถึงพูดว่า "ใช้ไปแล้ว" มันไม่ได้ใช้อีกต่อไป?
ลีกา

131

intหมายถึงการขัดจังหวะและตัวเลข0x80คือหมายเลขขัดจังหวะ การขัดจังหวะจะถ่ายโอนโฟลว์โปรแกรมไปยังใครก็ตามที่จัดการการขัดจังหวะนั้นซึ่งจะถูกขัดจังหวะ0x80ในกรณีนี้ ใน Linux 0x80ตัวจัดการขัดจังหวะคือเคอร์เนลและใช้เพื่อเรียกระบบไปยังเคอร์เนลโดยโปรแกรมอื่น

เคอร์เนลได้รับแจ้งเกี่ยวกับระบบที่เรียกโปรแกรมที่ต้องการสร้างโดยตรวจสอบค่าในรีจิสเตอร์%eax(ไวยากรณ์ AT&T และ EAX ในไวยากรณ์ของ Intel) การเรียกระบบแต่ละครั้งมีข้อกำหนดที่แตกต่างกันเกี่ยวกับการใช้รีจิสเตอร์อื่น ๆ ยกตัวอย่างเช่นค่า1ใน%eaxหมายถึงการเรียกระบบของexit()และค่าในการเก็บค่าของรหัสสถานะสำหรับ%ebxexit()


47

จำไว้ว่า0x80= 80h=128

คุณสามารถดูได้ที่นี่นั่นINTเป็นเพียงหนึ่งในหลาย ๆ คำสั่ง (จริงๆแล้วคือการแสดงภาษาแอสเซมบลี (หรือฉันควรจะพูดว่า 'ช่วยในการจำ') ที่มีอยู่ในชุดคำสั่ง x86 นอกจากนี้คุณยังสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับการเรียนการสอนนี้พบคู่มือ Intel ของตัวเองที่นี่

สรุปจาก PDF:

INT n / INTO / INT 3 - Call to Interrupt Procedure

คำสั่ง INT n สร้างการเรียกไปยังตัวจัดการการขัดจังหวะหรือตัวจัดการข้อยกเว้นที่ระบุด้วยตัวถูกดำเนินการปลายทาง ตัวถูกดำเนินการปลายทางระบุเวกเตอร์ตั้งแต่ 0 ถึง 255 ซึ่งเข้ารหัสเป็นค่ากลางที่ไม่ได้ลงนาม 8 บิต คำสั่ง INT n เป็นเครื่องมือช่วยจำทั่วไปสำหรับการเรียกใช้ซอฟต์แวร์ที่สร้างขึ้นไปยังตัวจัดการขัดจังหวะ

อย่างที่คุณเห็น0x80คือตัวถูกดำเนินการปลายทางในคำถามของคุณ ณ จุดนี้ CPU รู้ว่าควรรันโค้ดบางตัวที่อยู่ใน Kernel แต่รหัสอะไร? ที่กำหนดโดย Interrupt Vector ใน Linux

การขัดจังหวะซอฟต์แวร์ DOS ที่มีประโยชน์ที่สุดอย่างหนึ่งคือการขัดจังหวะ 0x21 ด้วยการเรียกใช้พารามิเตอร์ที่แตกต่างกันในรีจิสเตอร์ (ส่วนใหญ่เป็น ah และ al) คุณสามารถเข้าถึงการดำเนินการต่างๆของ IO เอาต์พุตสตริงและอื่น ๆ

ระบบ Unix และอนุพันธ์ส่วนใหญ่ไม่ใช้ซอฟต์แวร์ขัดจังหวะยกเว้นการขัดจังหวะ 0x80 ซึ่งใช้ในการโทรระบบ สิ่งนี้ทำได้โดยการป้อนค่า32 บิตที่สอดคล้องกับฟังก์ชันเคอร์เนลในรีจิสเตอร์ EAX ของโปรเซสเซอร์จากนั้นเรียกใช้ INT 0x80

โปรดดูที่สิ่งนี้ซึ่งแสดงค่าอื่น ๆ ในตารางตัวจัดการขัดจังหวะ

ป้อนคำอธิบายภาพที่นี่

ดังที่คุณเห็นตารางชี้ให้ CPU ดำเนินการเรียกระบบ คุณสามารถค้นหาตารางระบบ Linux โทรที่นี่

ดังนั้นโดยการย้ายค่า 0x1 ไปที่ EAX register และเรียก INT 0x80 ในโปรแกรมของคุณคุณสามารถทำให้กระบวนการดำเนินการโค้ดใน Kernel ซึ่งจะหยุด (ออก) กระบวนการทำงานปัจจุบัน (บน Linux, x86 Intel CPU)

ต้องไม่สับสนระหว่างฮาร์ดแวร์ขัดจังหวะกับซอฟต์แวร์ขัดจังหวะ นี่คือคำตอบที่ดีมากสำหรับเรื่องนี้

นอกจากนี้ยังเป็นแหล่งที่ดี


4
ลิงค์ตารางการเรียกระบบ Linux เสีย = \
มิเกลแองเจโล

1
ระบบ Unix และอนุพันธ์ส่วนใหญ่ไม่ใช้ซอฟต์แวร์ขัดจังหวะ (ยกเว้น int 0x80)ดูเหมือนจะเป็นวิธีที่แปลก การint 0x80เรียกระบบ i386 Linux ABI นั้นคล้ายกับ DOS int 0x21ABI มาก ใส่หมายเลขโทรลงในรีจิสเตอร์ (AH สำหรับ DOS, EAX สำหรับ Linux) และอาร์กิวเมนต์อื่น ๆ ในรีจิสเตอร์อื่น ๆ จากนั้นรันคำสั่งการขัดจังหวะซอฟต์แวร์ ความแตกต่างที่สำคัญคือสิ่งที่ระบบเรียกให้คุณทำ (เข้าถึงฮาร์ดแวร์โดยตรงใน DOS แต่ไม่ใช่ Linux) ไม่ใช่วิธีที่คุณเรียกใช้
Peter Cordes

นี่คือลิงค์ตาราง syscall ที่ไม่เสีย syscalls.kernelgrok.comเพียงแค่ขยายเพื่อแสดงการโทรทั้งหมดที่ด้านบน
ollien

เมื่อใช้ linux 64bits คุณสามารถดูการโทรของระบบได้ที่/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ตัน

12

ตัวอย่างการเรียกระบบ Linux ที่รันได้น้อยที่สุด

Linux ตั้งค่าตัวจัดการขัดจังหวะเพื่อ0x80ให้ดำเนินการเรียกระบบซึ่งเป็นวิธีสำหรับโปรแกรม userland ในการสื่อสารกับเคอร์เนล

.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

รวบรวมและเรียกใช้ด้วย:

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

ผลลัพธ์: โปรแกรมพิมพ์ไปยัง stdout:

hello world

และออกอย่างหมดจด

คุณไม่สามารถตั้งไสขัดจังหวะของคุณเองโดยตรงจาก userland เพราะคุณมีเพียงแหวนที่ 3 และลินุกซ์ป้องกันคุณจากการทำเช่นนั้น

GitHub อัปสตรีม ทดสอบบน Ubuntu 16.04

ทางเลือกอื่นที่ดีกว่า

int 0x80ถูกแทนที่ด้วยทางเลือกที่ดีกว่าสำหรับการโทรระบบ: อันดับแรกตามsysenterด้วย VDSO

x86_64 มีใหม่syscallการเรียนการสอน

ดูเพิ่มเติม: "int 0x80" หรือ "syscall" ดีกว่าอย่างไร

ตัวอย่าง 16 บิตขั้นต่ำ

ก่อนอื่นเรียนรู้วิธีสร้างระบบปฏิบัติการ bootloader ขั้นต่ำและเรียกใช้บน QEMU และฮาร์ดแวร์จริงตามที่ฉันได้อธิบายไว้ที่นี่: https://stackoverflow.com/a/32483545/895245

ตอนนี้คุณสามารถทำงานในโหมดจริง 16 บิต:

    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

สิ่งนี้จะทำตามลำดับ:

  • Do 0.
  • Do 1.
  • hlt: หยุดดำเนินการ

สังเกตว่าโปรเซสเซอร์ค้นหาตัวจัดการตัวแรกที่แอดเดรส0อย่างไรและตัวที่สองที่4: นั่นคือตารางของตัวจัดการที่เรียกว่าIVTและแต่ละรายการมี 4 ไบต์

ตัวอย่างน้อยที่สุดที่ทำ IO บางตัวเพื่อให้ตัวจัดการมองเห็นได้

ตัวอย่างโหมดป้องกันน้อยที่สุด

ระบบปฏิบัติการสมัยใหม่ทำงานในโหมดป้องกันที่เรียกว่า

การจัดการมีตัวเลือกมากขึ้นในโหมดนี้ดังนั้นจึงซับซ้อนกว่า แต่จิตวิญญาณก็เหมือนกัน

ขั้นตอนสำคัญคือการใช้คำแนะนำ LGDT และ LIDT ซึ่งจะชี้ที่อยู่ของโครงสร้างข้อมูลในหน่วยความจำ (ตาราง Interrupt Descriptor) ที่อธิบายตัวจัดการ

ตัวอย่างน้อยที่สุด



4

คำสั่ง "int" ทำให้เกิดการขัดจังหวะ

การขัดจังหวะคืออะไร?

คำตอบง่ายๆ: อินเทอร์รัปต์พูดง่ายๆคือเหตุการณ์ที่ขัดขวางซีพียูและบอกให้รันงานเฉพาะ

คำตอบโดยละเอียด :

CPU มีตาราง Interrupt Service Routines (หรือ ISR) ที่เก็บไว้ในหน่วยความจำ ในโหมดจริง (16 บิต) สิ่งนี้จะถูกจัดเก็บเป็นIVTหรือI nterrupt V ector T able โดยทั่วไป IVT จะอยู่ที่0x0000:0x0000(ที่อยู่จริง0x00000) และเป็นชุดของที่อยู่ออฟเซ็ตเซกเมนต์ที่ชี้ไปที่ ISR ระบบปฏิบัติการอาจแทนที่รายการ IVT ที่มีอยู่แล้วด้วย ISR ของตัวเอง

(หมายเหตุ: ขนาดของ IVT ถูกกำหนดไว้ที่ 1024 (0x400) ไบต์)

ในโหมดป้องกัน (32 บิต) ซีพียูจะใช้ IDT IDT เป็นโครงสร้างความยาวตัวแปรที่ประกอบด้วยตัวบอก (หรือที่เรียกว่าประตู) ซึ่งบอก CPU เกี่ยวกับตัวจัดการขัดจังหวะ โครงสร้างของตัวบ่งชี้เหล่านี้มีความซับซ้อนมากกว่ารายการออฟเซ็ตแบบง่ายของ IVT นี่คือ:

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 อาจมีขนาดแปรผัน แต่ต้องเป็นลำดับเช่นถ้าคุณประกาศ IDT ของคุณเป็น 0x00 ถึง 0x50 คุณต้องมีการขัดจังหวะทุกครั้งตั้งแต่ 0x00 ถึง 0x50 ระบบปฏิบัติการไม่จำเป็นต้องใช้ทั้งหมดดังนั้นบิตปัจจุบันจึงช่วยให้ซีพียูจัดการกับการขัดจังหวะอย่างเหมาะสมที่ระบบปฏิบัติการไม่ต้องการจัดการ

เมื่อเกิดการขัดจังหวะ (ไม่ว่าจะโดยทริกเกอร์ภายนอก (เช่นอุปกรณ์ฮาร์ดแวร์) ใน IRQ หรือโดยintคำสั่งจากโปรแกรม) CPU จะดัน EFLAGS จากนั้น CS และตามด้วย EIP (สิ่งเหล่านี้จะถูกเรียกคืนโดยอัตโนมัติโดยiretคำสั่งขัดจังหวะการส่งคืน) ระบบปฏิบัติการมักจะจัดเก็บข้อมูลเพิ่มเติมเกี่ยวกับสถานะของเครื่องจัดการการขัดจังหวะคืนค่าสถานะเครื่องและดำเนินการต่อ

ในระบบปฏิบัติการ * NIX จำนวนมาก (รวมถึง Linux) การเรียกใช้ระบบจะถูกขัดจังหวะ โปรแกรมใส่อาร์กิวเมนต์ให้กับการเรียกระบบในรีจิสเตอร์ (EAX, EBX, ECX, EDX ฯลฯ .. ) และโทรขัดจังหวะ 0x80 เคอร์เนลได้ตั้งค่า IDT ให้มี interrupt handler บน 0x80 แล้วซึ่งเรียกเมื่อได้รับ interrupt 0x80 จากนั้นเคอร์เนลจะอ่านอาร์กิวเมนต์และเรียกใช้ฟังก์ชันเคอร์เนลตามนั้น อาจจัดเก็บผลตอบแทนใน EAX / EBX การเรียกระบบส่วนใหญ่ถูกแทนที่ด้วยคำแนะนำsysenterและsysexit(หรือsyscallและsysretบน AMD) ซึ่งช่วยให้เข้าสู่วงแหวน 0 ได้เร็วขึ้น

การขัดจังหวะนี้อาจมีความหมายที่แตกต่างกันในระบบปฏิบัติการอื่น อย่าลืมตรวจสอบเอกสารประกอบ


ข้อเท็จจริงที่น่าสนใจ: การเรียกระบบ i386 ของ FreeBSD ABI ส่ง args บนสแต็กพื้นที่ผู้ใช้ เพียงeaxใช้สำหรับจำนวน syscall asm.sourceforge.net/intro/hello.html
Peter Cordes

2

ดังที่กล่าวไว้มันทำให้การควบคุมข้ามไปขัดจังหวะเวกเตอร์ 0x80 ในทางปฏิบัติสิ่งนี้หมายความว่า (อย่างน้อยใน Linux) คือการเรียกระบบถูกเรียกใช้ การเรียกระบบและอาร์กิวเมนต์ที่แน่นอนถูกกำหนดโดยเนื้อหาของรีจิสเตอร์ ตัวอย่างเช่นสามารถเรียก exit () ได้โดยตั้งค่า% eax เป็น 1 ตามด้วย "int 0x80"


1

มันบอกให้ซีพียูเปิดใช้งานอินเทอร์รัปต์เวกเตอร์ 0x80 ซึ่งบน Linux OSes คือการขัดจังหวะการโทรระบบที่ใช้ในการเรียกใช้ฟังก์ชันระบบเช่นopen()ไฟล์และอื่น ๆ


9
พูดอย่างเคร่งครัดมันไม่ได้บอกเคอร์เนล ... มันบอก CPU ซึ่งค้นหาตัวจัดการใน IDT ซึ่งจะกลายเป็นตัวชี้ไปยังโค้ดเคอร์เนลบางตัว
asveikau

จริง. ฉันคิดว่าวลีที่ดีกว่าคือมันบอกให้ CPU เปิดใช้งานเวกเตอร์และเวกเตอร์ (เป็นส่วนหนึ่งของเคอร์เนล) เรียกใช้ฟังก์ชัน
อำพัน

ซึ่งสิ้นสุดการทำเช่นนี้ซึ่ง inturn ปลายขึ้นทำที่ซึ่งไม่นี้ซึ่งจากนั้นจะไปที่นั่นสับสน : / แอมเบอร์มีคำตอบที่เข้าใจ.. นั่นมัน ..
Afzaal Ahmad Zeeshan

1

int คืออะไรนอกจากการหยุดชะงักกล่าวคือโปรเซสเซอร์จะหยุดการดำเนินการปัจจุบันไว้

0x80 ไม่ใช่แค่การเรียกระบบหรือการเรียกเคอร์เนล กล่าวคือฟังก์ชันระบบจะถูกเรียกใช้งาน

ในการเป็น 0x80 ที่เฉพาะเจาะจงหมายถึง rt_sigtimedwait / init_module / restart_sys ซึ่งแตกต่างกันไปในแต่ละสถาปัตยกรรม

ดูรายละเอียดเพิ่มเติมได้ที่ https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.