¿Qué significa "int 0x80" en código ensamblador?


Respuestas:


69

Pasa el control para interrumpir el vector 0x80

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

En Linux, eche un vistazo a esto : se usó para manejar system_call. Por supuesto, en otro sistema operativo esto podría significar algo totalmente diferente.


5
al abreviar la historia larga, las instrucciones significan que HACERLO para la instrucción fue antes.
Yuda Prawira

2
@YudaPrawira: debería pensar en las instrucciones anteriores como la configuración de args en registros, y int 0x80como un tipo especial de callfunción en el kernel (seleccionada por eax).
Peter Cordes

¿Por qué dijiste "FUE usado?" ¿Ya no se usa?
Liga

129

intsignifica interrumpir, y el número 0x80es el número de interrupción. Una interrupción transfiere el flujo del programa a quien esté manejando esa interrupción, que es una interrupción 0x80en este caso. En Linux, el 0x80controlador de interrupciones es el kernel y otros programas lo utilizan para realizar llamadas del sistema al kernel.

Se notifica al kernel sobre qué llamada al sistema desea realizar el programa, examinando el valor en el registro %eax(sintaxis AT&T y EAX en sintaxis Intel). Cada llamada al sistema tiene diferentes requisitos sobre el uso de los otros registros. Por ejemplo, un valor de 1in %eaxsignifica una llamada al sistema de exit(), y el valor de in %ebxcontiene el valor del código de estado para exit().


47

Tenga en cuenta que 0x80= 80h=128

Aquí puede ver que INTes solo una de las muchas instrucciones (en realidad, la representación en lenguaje ensamblador (o debería decir 'mnemónico')) que existe en el conjunto de instrucciones x86. También puede encontrar más información sobre estas instrucciones en el propio manual de Intel que se encuentra aquí .

Para resumir del PDF:

INT n / INTO / INT 3: procedimiento de llamada para interrumpir

La instrucción INT n genera una llamada al manejador de interrupciones o excepciones especificado con el operando de destino. El operando de destino especifica un vector de 0 a 255, codificado como un valor intermedio sin signo de 8 bits. La instrucción INT n es el mnemónico general para ejecutar una llamada generada por software a un controlador de interrupciones.

Como puede ver, 0x80 es el operando de destino en su pregunta. En este punto, la CPU sabe que debe ejecutar algún código que reside en el Kernel, pero ¿qué código? Eso está determinado por el vector de interrupción en Linux.

Una de las interrupciones de software de DOS más útiles fue la interrupción 0x21. Al llamarlo con diferentes parámetros en los registros (principalmente ah y al), puede acceder a varias operaciones de E / S, salida de cadena y más.

La mayoría de los sistemas Unix y sus derivados no utilizan interrupciones de software, con la excepción de la interrupción 0x80, que se utiliza para realizar llamadas al sistema. Esto se logra ingresando un valor de 32 bits correspondiente a una función del kernel en el registro EAX del procesador y luego ejecutando INT 0x80.

Eche un vistazo a esto, donde se muestran otros valores disponibles en las tablas del manejador de interrupciones:

ingrese la descripción de la imagen aquí

Como puede ver, la tabla indica que la CPU debe ejecutar una llamada al sistema. Puede encontrar la tabla de llamadas al sistema Linux aquí .

Entonces, al mover el valor 0x1 al registro EAX y llamar al INT 0x80 en su programa, puede hacer que el proceso ejecute el código en el Kernel que detendrá (saldrá) el proceso en ejecución actual (en Linux, CPU Intel x86).

Una interrupción de proceso no debe confundirse con una interrupción de software. Aquí hay una muy buena respuesta a este respecto.

Esta también es una buena fuente.


4
El enlace de la tabla de llamadas del sistema Linux está roto = \
Miguel Angelo

1
La mayoría de los sistemas Unix y sus derivados no utilizan interrupciones de software (excepto int 0x80) parece una forma extraña de decirlo. La int 0x80llamada ABI del sistema i386 Linux es extremadamente similar a la int 0x21ABI de DOS . Ponga un número de llamada en un registro (AH para DOS, EAX para Linux) y otros argumentos en otros registros, luego ejecute una instrucción de interrupción de software. La principal diferencia está en lo que le permiten hacer las llamadas al sistema (acceder al hardware directamente en DOS pero no en Linux), no en cómo las invoca.
Peter Cordes

Aquí hay un enlace de tabla de llamada al sistema no roto. syscalls.kernelgrok.com Simplemente amplíelo para mostrar todas las llamadas en la parte superior.
Ollien

Al usar linux de 64 bits, puede ver la llamada del sistema disponible en/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton

11

Ejemplo de llamada al sistema Linux mínimamente ejecutable

Linux configura el manejador de interrupciones para 0x80que implemente llamadas al sistema, una forma para que los programas de la zona de usuario se comuniquen con el kernel.

.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

Compilar y ejecutar con:

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

Resultado: el programa imprime en stdout:

hello world

y sale limpiamente.

No puede configurar sus propios controladores de interrupciones directamente desde el área de usuario porque solo tiene el anillo 3 y Linux le impide hacerlo .

GitHub aguas arriba . Probado en Ubuntu 16.04.

Mejores alternativas

int 0x80ha sido reemplazado por mejores alternativas para realizar llamadas al sistema: primero sysenter, luego VDSO.

x86_64 tiene una nueva syscallinstrucción .

Ver también: ¿Qué es mejor "int 0x80" o "syscall"?

Ejemplo mínimo de 16 bits

Primero, aprenda a crear un sistema operativo de cargador de arranque mínimo y ejecútelo en QEMU y hardware real, como he explicado aquí: https://stackoverflow.com/a/32483545/895245

Ahora puede ejecutar en modo real de 16 bits:

    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

Esto haría en orden:

  • Do 0.
  • Do 1.
  • hlt: dejar de ejecutar

Observe cómo el procesador busca el primer controlador en la dirección 0y el segundo en 4: que es una tabla de controladores llamada IVT , y cada entrada tiene 4 bytes.

Ejemplo mínimo que hace algo de IO para hacer visibles a los controladores.

Ejemplo de modo protegido mínimo

Los sistemas operativos modernos se ejecutan en el llamado modo protegido.

El manejo tiene más opciones en este modo, por lo que es más complejo, pero el espíritu es el mismo.

El paso clave es usar las instrucciones LGDT y LIDT, que señalan la dirección de una estructura de datos en memoria (la tabla de descriptores de interrupciones) que describe los controladores.

Ejemplo mínimo



4

La instrucción "int" provoca una interrupción.

¿Qué es una interrupción?

Respuesta simple: una interrupción, en pocas palabras, es un evento que interrumpe la CPU y le dice que ejecute una tarea específica.

Respuesta detallada :

La CPU tiene una tabla de Rutinas de servicio de interrupción (o ISR) almacenadas en la memoria. En Real (16-bit) Mode, este se almacena como la IVT , o I nterrupt V ector T capaz. El IVT normalmente se encuentra en 0x0000:0x0000(dirección física 0x00000) y es una serie de direcciones de desplazamiento de segmento que apuntan a los ISR. El sistema operativo puede reemplazar las entradas IVT preexistentes con sus propios ISR.

(Nota: el tamaño del IVT se fija en 1024 (0x400) bytes).

En el modo protegido (32 bits), la CPU utiliza un IDT. El IDT es una estructura de longitud variable que consta de descriptores (también conocidos como puertas), que informan a la CPU sobre los manejadores de interrupciones. La estructura de estos descriptores es mucho más compleja que las simples entradas de desplazamiento de segmento del IVT; aquí está:

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
 

* El IDT puede ser de tamaño variable, pero debe ser secuencial, es decir, si declara que su IDT es de 0x00 a 0x50, debe tener todas las interrupciones de 0x00 a 0x50. El sistema operativo no necesariamente los usa todos, por lo que el bit Presente permite que la CPU maneje adecuadamente las interrupciones que el sistema operativo no pretende manejar.

Cuando ocurre una interrupción (ya sea por un disparador externo (por ejemplo, un dispositivo de hardware) en un IRQ, o por la intinstrucción de un programa), la CPU presiona EFLAGS, luego CS y luego EIP. (Estos son restaurados automáticamente por iretla instrucción de retorno de interrupción). El sistema operativo generalmente almacena más información sobre el estado de la máquina, maneja la interrupción, restaura el estado de la máquina y continúa.

En muchos sistemas operativos * NIX (incluido Linux), las llamadas al sistema se basan en interrupciones. El programa coloca los argumentos de la llamada al sistema en los registros (EAX, EBX, ECX, EDX, etc.), y llama a la interrupción 0x80. El kernel ya ha configurado el IDT para que contenga un controlador de interrupciones en 0x80, que se llama cuando recibe la interrupción 0x80. El núcleo luego lee los argumentos e invoca una función del núcleo en consecuencia. Puede almacenar una devolución en EAX / EBX. Las llamadas al sistema han sido reemplazadas en gran medida por las instrucciones sysentery sysexit(o syscally sysreten AMD), que permiten una entrada más rápida en el anillo 0.

Esta interrupción podría tener un significado diferente en un sistema operativo diferente. Asegúrese de consultar su documentación.


Dato curioso: la llamada ABI del sistema i386 de FreeBSD pasa argumentos en la pila de espacio de usuario. Solo eaxse utiliza para el número de llamada al sistema. asm.sourceforge.net/intro/hello.html
Peter Cordes

2

Como se mencionó, hace que el control salte para interrumpir el vector 0x80. En la práctica, lo que esto significa (al menos en Linux) es que se invoca una llamada al sistema; la llamada y los argumentos exactos del sistema están definidos por el contenido de los registros. Por ejemplo, exit () se puede invocar estableciendo% eax en 1 seguido de 'int 0x80'.


1

Le dice a la CPU que active el vector de interrupción 0x80, que en los sistemas operativos Linux es la interrupción de la llamada al sistema, que se utiliza para invocar funciones del sistema como open()archivos, etc.


9
Estrictamente hablando, no le dice al kernel ... Le dice a la CPU, que busca el controlador en el IDT, que termina siendo un puntero a algún código del kernel.
asveikau

Cierto. Supongo que lo mejor sería decirle a la CPU que active el vector, y el vector (como parte del kernel) invoca la función.
Ámbar

que termina haciendo esto, que a su vez termina haciendo aquello, que luego hace esto, que luego va confuso . : / Amber tiene una respuesta que es comprensible ... eso es ...
Afzaal Ahmad Zeeshan

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.