O que significa “int 0x80” no código assembly?

Respostas:

70

Ele passa o controle para interromper o vetor 0x80

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

No Linux, dê uma olhada nisso : era usado para lidar system_call. Claro que em outro sistema operacional isso pode significar algo totalmente diferente.

jldupont
fonte
5
por encurtar uma longa história, instruções significam que FAZER para instrução era antes.
Yuda Prawira
2
@YudaPrawira: você deve pensar nas instruções anteriores como configurando args em registradores e int 0x80como um tipo especial de callpara uma função no kernel (selecionada por eax).
Peter Cordes
Por que você disse "FOI usado?" Não é mais usado?
Liga
131

intsignifica interrupção, e o número 0x80é o número da interrupção. Uma interrupção transfere o fluxo do programa para quem está lidando com essa interrupção, que é a interrupção 0x80neste caso. No Linux, o 0x80manipulador de interrupção é o kernel, e é usado para fazer chamadas de sistema ao kernel por outros programas.

O kernel é notificado sobre qual chamada de sistema o programa deseja fazer, examinando o valor no registro %eax(sintaxe AT&T e EAX na sintaxe Intel). Cada chamada do sistema tem requisitos diferentes sobre o uso dos outros registros. Por exemplo, um valor de 1in %eaxsignifica uma chamada de sistema de exit()e o valor in %ebxcontém o valor do código de status de exit().

Polat Tuzla
fonte
47

Lembre-se de que 0x80= 80h=128

Você pode ver aqui que INTé apenas uma das muitas instruções (na verdade, a representação em Assembly Language (ou devo dizer 'mnemônico') dela) que existe no conjunto de instruções x86. Você também pode encontrar mais informações sobre esta instrução no próprio manual da Intel, encontrado aqui .

Para resumir do PDF:

INT n / INTO / INT 3 - Chamada para interromper o procedimento

A instrução INT n gera uma chamada para o manipulador de interrupção ou exceção especificado com o operando de destino. O operando de destino especifica um vetor de 0 a 255, codificado como um valor intermediário sem sinal de 8 bits. A instrução INT n é o mnemônico geral para executar uma chamada gerada por software para um manipulador de interrupção.

Como você pode ver, 0x80 é o operando de destino em sua pergunta. Neste ponto a CPU sabe que deve executar algum código que reside no Kernel, mas qual código? Isso é determinado pelo vetor de interrupção no Linux.

Uma das interrupções de software DOS mais úteis foi a interrupção 0x21. Ao chamá-lo com diferentes parâmetros nos registradores (principalmente ah e al), você pode acessar várias operações IO, saída de string e muito mais.

A maioria dos sistemas Unix e derivados não usam interrupções de software, com exceção da interrupção 0x80, usada para fazer chamadas de sistema. Isso é feito inserindo um valor de 32 bits correspondente a uma função do kernel no registro EAX do processador e, em seguida, executando INT 0x80.

Dê uma olhada nisso, onde outros valores disponíveis nas tabelas do manipulador de interrupção são mostrados:

insira a descrição da imagem aqui

Como você pode ver, a tabela indica que a CPU deve executar uma chamada de sistema. Você pode encontrar a tabela Linux System Call aqui .

Portanto, movendo o valor 0x1 para o registrador EAX e chamando o INT 0x80 em seu programa, você pode fazer o processo executar o código no Kernel que irá parar (sair) do processo em execução atual (no Linux, CPU Intel x86).

Uma interrupção de hardware não deve ser confundida com uma interrupção de software. Aqui está uma resposta muito boa a esse respeito.

Esta também é uma boa fonte.

Koray Tugay
fonte
4
O link da tabela de Chamada do Sistema Linux está quebrado = \
Miguel Angelo
1
A maioria dos sistemas Unix e derivados não usam interrupções de software (exceto int 0x80) parece uma maneira estranha de colocar isso. A int 0x80chamada de sistema i386 Linux ABI é extremamente semelhante à int 0x21ABI DOS . Coloque um número de telefone em um registro (AH para DOS, EAX para Linux) e outros argumentos em outros registros e execute uma instrução de interrupção de software. A principal diferença está no que as chamadas do sistema permitem que você faça (acesse o hardware diretamente no DOS, mas não no Linux), não em como você as invoca.
Peter Cordes
Aqui está um link de tabela syscall não quebrado. syscalls.kernelgrok.com Basta expandi-lo para mostrar todas as chamadas no topo.
ollien
Ao usar o Linux 64bits, você pode ver a chamada do sistema disponível em/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton
12

Exemplo de chamada de sistema Linux com execução mínima

O Linux configura o manipulador de interrupções para 0x80que implemente chamadas de sistema, uma forma de os programas do espaço do usuário se comunicarem com o 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

Compile e execute com:

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

Resultado: o programa imprime em stdout:

hello world

e sai de forma limpa.

Você não pode definir seus próprios manipuladores de interrupção diretamente do userland porque você só tem o anel 3 e o Linux o impede de fazer isso .

GitHub upstream . Testado no Ubuntu 16.04.

Melhores alternativas

int 0x80foi substituído por melhores alternativas para fazer chamadas de sistema: primeiro sysenter, depois VDSO.

x86_64 tem uma nova syscallinstrução .

Consulte também: O que é melhor "int 0x80" ou "syscall"?

Exemplo mínimo de 16 bits

Primeiro aprenda como criar um sistema operacional de bootloader mínimo e executá-lo em QEMU e hardware real, conforme expliquei aqui: https://stackoverflow.com/a/32483545/895245

Agora você pode executar em 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

Isso faria em ordem:

  • Do 0.
  • Do 1.
  • hlt: parar de executar

Observe como o processador procura o primeiro manipulador no endereço 0e o segundo em 4: ou seja, uma tabela de manipuladores chamada IVT , e cada entrada tem 4 bytes.

Exemplo mínimo que faz algum IO para tornar os manipuladores visíveis.

Exemplo de modo de proteção mínima

Os sistemas operacionais modernos funcionam no chamado modo protegido.

O manuseio tem mais opções neste modo, por isso é mais complexo, mas o espírito é o mesmo.

A etapa principal é usar as instruções LGDT e LIDT, que apontam o endereço de uma estrutura de dados na memória (a tabela do descritor de interrupção) que descreve os manipuladores.

Exemplo mínimo

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fonte
9

int 0x80 é a instrução em linguagem assembly usada para invocar chamadas de sistema em processadores Linux em x86 (ou seja, compatível com Intel).

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

Tom
fonte
4

A instrução "int" causa uma interrupção.

O que é uma interrupção?

Resposta Simples: Uma interrupção, simplesmente, é um evento que interrompe a CPU e diz a ela para executar uma tarefa específica.

Resposta detalhada :

A CPU possui uma tabela de Rotinas de Serviço de Interrupção (ou ISRs) armazenada na memória. Na real (16 bits) Modo, esta é armazenada como o IVT , ou eu nterrupt V ector T capaz. O IVT está normalmente localizado em 0x0000:0x0000(endereço físico 0x00000) e é uma série de endereços de deslocamento de segmento que apontam para os ISRs. O sistema operacional pode substituir as entradas IVT pré-existentes por seus próprios ISRs.

(Observação: o tamanho do IVT é fixado em 1.024 (0x400) bytes.)

No modo protegido (32 bits), a CPU usa um IDT. O IDT é uma estrutura de comprimento variável que consiste em descritores (também conhecidos como portas), que informam à CPU sobre os manipuladores de interrupção. A estrutura desses descritores é muito mais complexa do que as simples entradas de deslocamento de segmento do IVT; Aqui 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
 

* O IDT pode ser de tamanho variável, mas deve ser sequencial, ou seja, se você declarar que seu IDT é de 0x00 a 0x50, você deve ter todas as interrupções de 0x00 a 0x50. O SO não necessariamente usa todos eles, então o bit Presente permite que a CPU lide apropriadamente com as interrupções que o SO não pretende controlar.

Quando ocorre uma interrupção (por um acionador externo (por exemplo, um dispositivo de hardware) em um IRQ ou pela intinstrução de um programa), a CPU empurra EFLAGS, depois CS e, em seguida, EIP. (Eles são restaurados automaticamente pela iretinstrução de retorno de interrupção.) O SO geralmente armazena mais informações sobre o estado da máquina, lida com a interrupção, restaura o estado da máquina e continua.

Em muitos sistemas operacionais * NIX (incluindo Linux), as chamadas do sistema são baseadas em interrupções. O programa coloca os argumentos para a chamada do sistema nos registros (EAX, EBX, ECX, EDX, etc.), e chama a interrupção 0x80. O kernel já configurou o IDT para conter um manipulador de interrupção em 0x80, que é chamado quando recebe a interrupção 0x80. O kernel então lê os argumentos e invoca uma função de kernel de acordo. Pode armazenar uma devolução em EAX / EBX. As chamadas do sistema foram amplamente substituídas pelas instruções sysentere sysexit(ou syscalle sysretno AMD), que permitem uma entrada mais rápida no anel 0.

Esta interrupção pode ter um significado diferente em um sistema operacional diferente. Certifique-se de verificar sua documentação.

Adrian
fonte
Curiosidade: a chamada de sistema i386 do FreeBSD, ABI, passa args na pilha de espaço do usuário. Só eaxé usado para o número syscall. asm.sourceforge.net/intro/hello.html
Peter Cordes
2

Como mencionado, faz com que o controle salte para o vetor de interrupção 0x80. Na prática, o que isso significa (pelo menos no Linux) é que uma chamada de sistema é invocada; a chamada de sistema exata e os argumentos são definidos pelo conteúdo dos registradores. Por exemplo, exit () pode ser invocado definindo% eax como 1 seguido por 'int 0x80'.

Steve Smith
fonte
1

Ele instrui a cpu a ativar o vetor de interrupção 0x80, que nos sistemas operacionais Linux é a interrupção de chamada do sistema, usada para invocar funções do sistema, como open()para arquivos, etc.

Âmbar
fonte
9
A rigor, não diz ao kernel ... Diz à CPU, que procura o handler no IDT, que acaba sendo um ponteiro para algum código do kernel.
asveikau
Verdadeiro. Suponho que a melhor formulação seria dizer à CPU para ativar o vetor, e o vetor (como parte do kernel) invoca a função.
Amber
que acaba fazendo isso, que por sua vez acaba fazendo aquilo, que depois faz isso, que aí vai confuso . : / Amber tem uma resposta que é compreensível ... é isso ..
Afzaal Ahmad Zeeshan
1

int nada mais é do que uma interrupção, ou seja, o processador irá colocar sua execução atual em espera.

0x80 nada mais é que uma chamada de sistema ou chamada de kernel. ou seja, a função do sistema será executada.

Para ser específico, 0x80 representa rt_sigtimedwait / init_module / restart_sys e varia de arquitetura para arquitetura.

Para obter mais detalhes, consulte https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md

Praveen Kumar Karthikeyan
fonte