有人可以解释以下汇编代码的作用吗?
int 0x80
int
表示中断,编号0x80
为中断号。中断将程序流传输给处理该中断的任何人,0x80
在这种情况下是中断。在 Linux 中,0x80
中断处理程序是内核,用于其他程序对内核进行系统调用。
%eax
通过检查寄存器中的值(AT&T 语法和 Intel 语法中的 EAX),通知内核程序想要进行哪个系统调用。每个系统调用对其他寄存器的使用都有不同的要求。例如,1
in的值%eax
表示 的系统调用exit()
,而 in 的值%ebx
保存 的状态码的值exit()
。
它将控制传递给中断向量 0x80
见http://en.wikipedia.org/wiki/Interrupt_vector
在 Linux 上,看看这个:它是用来处理system_call
. 当然,在另一个操作系统上,这可能意味着完全不同的东西。
请记住0x80
= 80h
=128
您可以在此处看到,这INT
只是 x86 指令集中存在的众多指令之一(实际上是它的汇编语言表示(或者我应该说是“助记符”))。您还可以在此处找到的英特尔自己的手册中找到有关此指令的更多信息。
从 PDF 中总结:
INT n/INTO/INT 3—调用中断程序
INT n 指令生成对目标操作数指定的中断或异常处理程序的调用。目标操作数指定一个从 0 到 255 的向量,编码为 8 位无符号中间值。INT n 指令是执行软件生成的中断处理程序调用的通用助记符。
如您所见, 0x80是您问题中的目标操作数。此时 CPU 知道它应该执行一些驻留在内核中的代码,但是什么代码呢?这是由 Linux 中的中断向量决定的。
最有用的 DOS 软件中断之一是中断 0x21。通过使用寄存器中的不同参数(主要是 ah 和 al)调用它,您可以访问各种 IO 操作、字符串输出等。
大多数 Unix 系统和衍生系统不使用软件中断,除了用于进行系统调用的中断 0x80。这是通过将对应于内核函数的 32 位值输入到处理器的 EAX 寄存器中,然后执行 INT 0x80 来实现的。
请看一下中断处理程序表中其他可用值的显示位置:
如您所见,该表指向 CPU 执行系统调用。您可以在此处找到 Linux 系统调用表。
因此,通过将值 0x1 移动到 EAX 寄存器并在程序中调用 INT 0x80,您可以使进程执行内核中的代码,这将停止(退出)当前正在运行的进程(在 Linux,x86 Intel CPU 上)。
不得将硬件中断与软件中断混淆。在这方面,这是一个非常好的答案。
这也是很好的来源。
最小可运行 Linux 系统调用示例
Linux 设置中断处理程序以0x80
实现系统调用,这是用户级程序与内核通信的一种方式。
.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
结果:程序打印到标准输出:
hello world
并干净地退出。
您不能直接从用户空间设置您自己的中断处理程序,因为您只有ring 3 而 Linux 阻止您这样做。
GitHub 上游. 在 Ubuntu 16.04 上测试。
更好的选择
int 0x80
已被更好的系统调用替代方案所取代:首先sysenter
是 ,然后是 VDSO。
x86_64 有一条新syscall
指令。
另请参阅:“int 0x80”或“syscall”哪个更好?
最小 16 位示例
首先学习如何创建一个最小的引导加载程序操作系统并在 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
: 停止执行注意处理器如何在 address 查找第一个处理程序,0
在4
: 查找第二个处理程序,这是一个称为IVT的处理程序表,每个条目有 4 个字节。
执行一些 IO以使处理程序可见的最小示例。
最小保护模式示例
现代操作系统以所谓的保护模式运行。
这种模式的处理方式比较多,所以比较复杂,但是精神是一样的。
关键步骤是使用 LGDT 和 LIDT 指令,它们指向描述处理程序的内存数据结构(中断描述符表)的地址。
int 0x80 是汇编语言指令,用于在 x86(即与 Intel 兼容的)处理器上的 Linux 中调用系统调用。
“int”指令导致中断。
简单的回答:简单地说,中断是中断 CPU 并告诉它运行特定任务的事件。
详细回答:
CPU 有一个存储在内存中的中断服务程序(或 ISR)表。在实数(16 位)模式下,这被存储为IVT或中断向量表。IVT 通常位于(物理地址),它是一系列指向 ISR 的段偏移地址。操作系统可以用它自己的 ISR 替换预先存在的 IVT 条目。0x0000:0x0000
0x00000
(注意:IVT 的大小固定为 1024 (0x400) 字节。)
在受保护(32 位)模式下,CPU 使用 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 的每个中断。操作系统不一定会使用所有这些中断,因此 Present 位允许 CPU 正确处理操作系统不打算处理的中断。
当中断发生时(通过 IRQ 中的外部触发器(例如硬件设备)或int
来自程序的指令),CPU 推送 EFLAGS,然后是 CS,然后是 EIP。(这些由iret
中断返回指令自动恢复。)操作系统通常会存储有关机器状态的更多信息,处理中断,恢复机器状态,然后继续。
在许多 *NIX 操作系统(包括 Linux)中,系统调用是基于中断的。程序将系统调用的参数放入寄存器(EAX、EBX、ECX、EDX 等)中,并调用中断 0x80。内核已经将 IDT 设置为在 0x80 上包含一个中断处理程序,当它接收到中断 0x80 时会调用该处理程序。然后内核读取参数并相应地调用内核函数。它可以在 EAX/EBX 中存储回报。系统调用已在很大程度上被sysenter
and sysexit
(或AMD 上的syscall
and sysret
)指令所取代,这允许更快地进入 ring 0。
这个中断在不同的操作系统中可能有不同的含义。请务必检查其文档。
它告诉 cpu 激活中断向量 0x80,这在 Linux 操作系统上是系统调用中断,用于调用open()
文件等系统函数。
如前所述,它会导致控制跳转到中断向量 0x80。实际上,这意味着(至少在 Linux 下)是调用系统调用;确切的系统调用和参数由寄存器的内容定义。例如,可以通过将 %eax 设置为 1 后跟“int 0x80”来调用 exit()。
int 只不过是一个中断,即处理器将暂停其当前执行。
0x80 只不过是系统调用或内核调用。即系统功能将被执行。
具体来说 0x80 代表 rt_sigtimedwait/init_module/restart_sys 它因架构而异。
有关更多详细信息,请参阅 https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md