tutorial registers lenguaje language instruction ensamblador assembly x86

assembly - registers - ¿Qué significa "int 0x80" en el código de ensamblado?



lenguaje ensamblador x86 (8)

int 0x80 es la instrucción en lenguaje ensamblador que se utiliza para invocar llamadas al sistema en Linux en procesadores x86 (es decir, compatibles con Intel).

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

¿Alguien puede explicar lo que hace el siguiente código ensamblador?

int 0x80


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 () puede invocarse configurando% eax en 1 seguido de ''int 0x80''.


La instrucción "int" causa 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 el modo Real (16 bits), este se almacena como el IVT , o interrumpe la capacidad del sensor. 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 de IVT preexistentes con sus propios ISR.

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

En modo protegido (32 bits), la CPU usa un IDT. El IDT es una estructura de longitud variable que consta de descriptores (también conocidos como compuertas), que informan a la CPU sobre los manejadores de interrupciones. La estructura de estos descriptores es mucho más compleja que las entradas simples 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 cada interrupción de 0x00 a 0x50. El sistema operativo no necesariamente los usa a todos, por lo que el bit Presente permite que la CPU maneje adecuadamente las interrupciones que el sistema operativo no intenta manejar.

Cuando se produce una interrupción (ya sea por un disparador externo (por ejemplo, un dispositivo de hardware) en una IRQ, o por la instrucción int de un programa), la CPU empuja a EFLAGS, luego a CS y luego a EIP. (Estos son restaurados automáticamente por iret , la 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 pone los argumentos a la llamada del sistema en los registros (EAX, EBX, ECX, EDX, etc.), y llama a la interrupción 0x80. El kernel ya ha configurado el IDT para contener un controlador de interrupción en 0x80, que se llama cuando recibe la interrupción 0x80. El kernel luego lee los argumentos e invoca una función del kernel en consecuencia. Puede almacenar un retorno en EAX / EBX. Las llamadas al sistema han sido reemplazadas en gran medida por las sysenter y sysexit (o syscall y sysret en 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 verificar su documentación.


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


Pasa el control para interrumpir el vector 0x80

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

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


Tenga en cuenta que 0x80 = 80h = 128

Puede ver here que INT es solo una de las muchas instrucciones (en realidad, la representación del lenguaje ensamblador (o debería decir ''mnemotécnico'')) 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 here .

Para resumir desde el PDF:

INT n / INTO / INT 3-Llamar al procedimiento de interrupción

La instrucción INT n genera una llamada al controlador de interrupción o excepción 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 la mnemotécnica general para ejecutar una llamada generada por software a un manejador 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 resida en el Kernel, pero ¿qué código? Eso está determinado por Interrupt Vector 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 (sobre todo ah y al), puede acceder a varias operaciones IO, salida de cadena y más.

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

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

Como puede ver, la tabla apunta a la CPU para ejecutar una llamada al sistema. Puede encontrar la tabla Llamar al sistema Linux here .

Entonces, moviendo el valor de 0x1 a EAX y llamando al INT 0x80 en su programa, puede hacer que el proceso ejecute el código en Kernel, lo que detendrá (saldrá) el proceso actual (en Linux, CPU Intel x86).

Una interrupción de hardware no debe confundirse con una interrupción de software. Here hay una muy buena respuesta a este respecto.

This también es una buena fuente.

Puedes ver int 80h en acción here .


int significa interrupción, y el número 0x80 es el número de interrupción. Una interrupción transfiere el flujo del programa a quien maneje esa interrupción, que es la interrupción 0x80 en este caso. En Linux, el controlador de interrupción 0x80 es el kernel, y otros programas lo utilizan para hacer llamadas al kernel.

El kernel recibe una notificación sobre la llamada al sistema que el programa quiere realizar, al examinar el valor en el registro %eax (sintaxis de gas y EAX en la sintaxis de Intel). Cada llamada al sistema tiene diferentes requisitos sobre el uso de los otros registros. Por ejemplo, un valor de 1 en %eax significa una llamada al sistema de exit() , y el valor en %ebx contiene el valor del código de estado para exit() .


Ejemplo mínimo de 16 bits

Primero, aprenda a crear un sistema operativo de gestor de arranque mínimo y ejecútelo en QEMU y hardware real, tal como lo explique aquí: https://.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 0 , y el segundo en 4 : es una tabla de controladores llamada IVT , y cada entrada tiene 4 bytes.

Ejemplo mínimo que hace algunos IO para hacer que los manejadores sean visibles.

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 interrupción) que describe los manejadores.

Ejemplo mínimo

Uso de Linux de 0x80

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

No puede configurar sus propios controladores directamente desde el territorio del usuario porque solo tiene el anillo 3 y Linux le impide hacerlo.

Hola ejemplo del mundo:

.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

Compila y ejecuta con:

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

Mejores alternativas

int 0x80 ha sido reemplazado por mejores alternativas:: primer sysenter , luego VDSO.

x86_64 tiene syscall .

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