Alguém pode explicar o que o seguinte código assembly faz?
int 0x80
Alguém pode explicar o que o seguinte código assembly faz?
int 0x80
Respostas:
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.
int 0x80
como um tipo especial de call
para uma função no kernel (selecionada por eax
).
int
significa 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 0x80
neste caso. No Linux, o 0x80
manipulador 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 1
in %eax
significa uma chamada de sistema de exit()
e o valor in %ebx
contém o valor do código de status de exit()
.
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:
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.
int 0x80
chamada de sistema i386 Linux ABI é extremamente semelhante à int 0x21
ABI 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.
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
Exemplo de chamada de sistema Linux com execução mínima
O Linux configura o manipulador de interrupções para 0x80
que 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 0x80
foi substituído por melhores alternativas para fazer chamadas de sistema: primeiro sysenter
, depois VDSO.
x86_64 tem uma nova syscall
instruçã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 executarObserve como o processador procura o primeiro manipulador no endereço 0
e 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.
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).
A instrução "int" causa 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 int
instrução de um programa), a CPU empurra EFLAGS, depois CS e, em seguida, EIP. (Eles são restaurados automaticamente pela iret
instruçã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 sysenter
e sysexit
(ou syscall
e sysret
no 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.
eax
é usado para o número syscall. asm.sourceforge.net/intro/hello.html
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'.
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.
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