ChatGPT解决这个技术问题 Extra ChatGPT

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

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

 int 0x80  

u
user1534664

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

通过检查寄存器 %eax 中的值(AT&T 语法和 Intel 语法中的 EAX),通知内核程序想要进行哪个系统调用。每个系统调用对其他寄存器的使用都有不同的要求。例如,%eax 中的 1 值表示 exit() 的系统调用,%ebx 中的值保存 exit() 的状态码值。


j
jldupont

它将控制传递给中断向量 0x80

请参阅http://en.wikipedia.org/wiki/Interrupt_vector

在 Linux 上,查看 this:它用于处理 system_call。当然,在另一个操作系统上,这可能意味着完全不同的东西。


通过缩短长篇故事的说明,这意味着以前的指令是 DO IT。
@YudaPrawira:您应该将前面的指令视为在寄存器中设置 args,而 int 0x80 是内核中函数的一种特殊 call(由 eax 选择)。
你为什么说“被使用了”?它不再使用了吗?
K
Koray Tugay

请记住 0x80 = 80h = 128

您可以看到hereINT 只是 x86 指令集中存在的众多指令之一(实际上是它的汇编语言表示(或者我应该说是“助记符”))。您还可以在英特尔自己的手册 here 中找到有关此指令的更多信息。

从 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 来实现的。

请看一下中断处理程序表中其他可用值的显示位置:

https://i.stack.imgur.com/hIg8n.png

如您所见,该表指向 CPU 执行系统调用。您可以找到 Linux 系统调用表 here

因此,通过将值 0x1 移动到 EAX 寄存器并在程序中调用 INT 0x80,您可以使进程执行内核中的代码,这将停止(退出)当前正在运行的进程(在 Linux,x86 Intel CPU 上)。

不得将硬件中断与软件中断混淆。 Here 在这方面是一个很好的答案。

This 也是很好的来源。


Linux 系统调用表链接已损坏 =\
大多数 Unix 系统和衍生产品不使用软件中断(int 0x80 除外) 似乎是一种奇怪的说法。 int 0x80 i386 Linux 系统调用 ABI 与 DOS int 0x21 ABI 极为相似。将调用号放入寄存器(用于 DOS 的 AH,用于 Linux 的 EAX),并将其他参数放入其他寄存器中,然后运行软件中断指令。主要区别在于系统调用允许您做什么(直接在 DOS 中访问硬件,而不是在 Linux 中访问硬件),而不在于您调用它们的方式。
这是一个完整的系统调用表链接。 syscalls.kernelgrok.com 只需将其展开以在顶部显示所有呼叫。
使用 linux 64bits 时,您可以在 /usr/include/x86_64-linux-gnu/asm/unistd_64.h 看到可用的系统调用
C
Ciro Santilli Путлер Капут 六四事

最小可运行 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 and Linux prevents you from doing so

GitHub upstream。在 Ubuntu 16.04 上测试。

更好的选择

int 0x80 已被更好的系统调用替代方案所取代:首先是 sysenter,然后是 VDSO。

x86_64 有 a new syscall instruction

另请参阅:What is better "int 0x80" or "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

这将按顺序进行:

做0。

做1。

hlt:停止执行

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

Minimal example that does some IO 使处理程序可见。

最小保护模式示例

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

这种模式的处理方式比较多,所以比较复杂,但是精神是一样的。

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

Minimal example


T
Tom

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

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


C
Community

“int”指令导致中断。

什么是中断?

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

详细答案:

CPU 有一个存储在内存中的中断服务程序(或 ISR)表。在实数(16 位)模式下,这存储为 IVT,或 I中断 Vector T有能力的。 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 的每个中断。操作系统不一定会使用所有这些中断,因此 Present 位允许 CPU 正确处理操作系统不打算处理的中断。

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

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

这个中断在不同的操作系统中可能有不同的含义。请务必检查其文档。


有趣的事实:FreeBSD 的 i386 系统调用 ABI 在用户空间堆栈上传递参数。只有 eax 用于系统调用号。 asm.sourceforge.net/intro/hello.html
S
Steve Smith

如前所述,它会导致控制跳转到中断向量 0x80。实际上,这意味着(至少在 Linux 下)是调用系统调用;确切的系统调用和参数由寄存器的内容定义。例如,可以通过将 %eax 设置为 1 后跟“int 0x80”来调用 exit()。


A
Amber

它告诉 cpu 激活中断向量 0x80,它在 Linux 操作系统上是系统调用中断,用于调用系统函数,如文件的 open() 等。


严格来说,它并没有告诉内核......它告诉 CPU,它在 IDT 中查找处理程序,最终成为指向某些内核代码的指针。
真的。我想更好的措辞是告诉 CPU 激活向量,然后向量(作为内核的一部分)调用函数。
最终会这样做,最终会这样做,然后会这样做,然后会感到困惑。 :/ Amber 有一个可以理解的答案..就是这样..
P
Praveen Kumar Karthikeyan

int 只不过是一个中断,即处理器将暂停其当前执行。

0x80 只不过是系统调用或内核调用。即系统功能将被执行。

具体来说 0x80 代表 rt_sigtimedwait/init_module/restart_sys 它因架构而异。

有关详细信息,请参阅 https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md