繁体   English   中英

汇编代码中的“int 0x80”是什么意思?

[英]What does "int 0x80" mean in assembly code?

有人可以解释以下汇编代码的作用吗?

 int 0x80  

int表示中断,数字0x80是中断号。 中断将程序流传输给处理该中断的任何人,在本例中为中断0x80 在 Linux 中, 0x80中断处理程序是内核,用于其他程序对内核进行系统调用。

通过检查寄存器%eax (AT&T 语法和 Intel 语法中的 EAX)中的值,内核被告知程序想要进行哪个系统调用。 每个系统调用对其他寄存器的使用都有不同的要求。 例如, %eax的值1表示exit()的系统调用,而%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 : 停止执行

请注意处理器如何在地址0处查找第一个处理程序,在4处查找第二个处理程序:这是一个称为IVT的处理程序表,每个条目有 4 个字节。

执行一些 IO以使处理程序可见的最小示例

最小保护模式示例

现代操作系统以所谓的保护模式运行。

这种模式的处理有更多的选择,所以更复杂,但精神是一样的。

关键步骤是使用 LGDT 和 LIDT 指令,它们指向描述处理程序的内存数据结构(中断描述符表)的地址。

最小的例子

int 0x80 是汇编语言指令,用于在 x86(即 Intel 兼容)处理器上的 Linux 中调用系统调用。

http://www.linfo.org/int_0x80.html

“int”指令导致中断。

什么是中断?

简单回答:中断,简单地说,就是中断 CPU 并告诉它运行特定任务的事件。

详细解答

CPU 有一个存储在内存中的中断服务程序(或 ISR)表。 在真实的(16位)的模式下,该被存储为IVT,nterrupt V厄克托Ť能。 IVT 通常位于0x0000:0x0000 (物理地址0x00000 ),它是一系列指向 ISR 的段偏移地址。 操作系统可以用它自己的 ISR 替换预先存在的 IVT 条目。

(注意: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 的每个中断。 OS 不一定使用所有这些,因此 Present 位允许 CPU 正确处理 OS 不打算处理的中断。

当中断发生时(通过 IRQ 中的外部触发器(例如硬件设备),或程序中的int指令),CPU 推送 EFLAGS,然后是 CS,然后是 EIP。 (这些由iret自动恢复,中断返回指令。)操作系统通常会存储更多关于机器状态的信息,处理中断,恢复机器状态,然后继续。

在许多 *NIX 操作系统(包括 Linux)中,系统调用是基于中断的。 程序将系统调用的参数放入寄存器(EAX、EBX、ECX、EDX 等),并调用中断 0x80。 内核已经将 IDT 设置为在 0x80 上包含一个中断处理程序,当它接收到中断 0x80 时会调用该处理程序。 然后内核读取参数并相应地调用内核函数。 它可以在 EAX/EBX 中存储回报。 系统调用在很大程度上被换成了sysentersysexit (或syscallsysret上AMD)指令,允许更快的进入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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM