어셈블리 코드에서 "int 0x80"은 무엇을 의미합니까?


답변:


69

제어를 인터럽트 벡터 0x80으로 전달합니다.

http://en.wikipedia.org/wiki/Interrupt_vector 참조

Linux에서 이것을 보세요 : system_call. 물론 다른 OS에서는 완전히 다른 의미 일 수 있습니다.


5
짧게 짧게 말하면 지침은 DO IT 가 이전에 있었다는 것을 의미 합니다.
Yuda Prawira 2011

2
@YudaPrawira : 이전 지침을 레지스터에 인수를 설정하는 것으로 생각해야 하며 커널의 함수에 int 0x80대한 특별한 종류 call(에서 선택 eax)로 생각해야합니다.
Peter Cordes

왜 "사용 했어?"라고 말했습니까? 더 이상 사용되지 않습니까?
Liga

129

int인터럽트를 의미하고 번호 0x80는 인터럽트 번호입니다. 인터럽트는 인터럽트를 처리하는 사람에게 프로그램 흐름을 전송합니다 0x80.이 경우에는 인터럽트 입니다. Linux에서 0x80인터럽트 처리기는 커널이며 다른 프로그램에서 커널에 대한 시스템 호출을 수행하는 데 사용됩니다.

커널은 레지스터의 값 %eax(AT & T 구문 및 Intel 구문의 EAX)을 검사하여 프로그램이 만들고자하는 시스템 호출에 대한 알림을받습니다 . 각 시스템 호출에는 다른 레지스터 사용에 대한 요구 사항이 다릅니다. 예를 들어 1in 값은 %eax의 시스템 호출을 의미하고 exit()in %ebx값은에 대한 상태 코드 값을 보유합니다 exit().


47

명심 0x80= 80h=128

당신은 볼 수 있습니다 여기에INTx86 명령어 세트에 존재하는 바로 많은 지시 사항 중 하나입니다 (실제로 어셈블리 언어 표현 (또는 나는 그것을 '연상')라고한다). 이 지침에 대한 자세한 내용은 여기 에서 찾을 수있는 인텔의 자체 설명서에서도 찾을 수 있습니다 .

PDF에서 요약하면 :

INT n / INTO / INT 3— 인터럽트 프로 시저 호출

INT n 명령어는 대상 피연산자로 지정된 인터럽트 또는 예외 처리기에 대한 호출을 생성합니다. 대상 피연산자는 8 비트 부호없는 중간 값으로 인코딩 된 0에서 255 사이의 벡터를 지정합니다. INT n 명령어는 인터럽트 핸들러에 대한 소프트웨어 생성 호출을 실행하기위한 일반적인 니모닉입니다.

보시다시피 0x80 은 질문 의 대상 피연산자 입니다. 이 시점에서 CPU는 커널에있는 일부 코드를 실행해야한다는 것을 알고 있지만 어떤 코드입니까? 이는 Linux의 인터럽트 벡터에 의해 결정됩니다.

가장 유용한 DOS 소프트웨어 인터럽트 중 하나는 인터럽트 0x21입니다. 레지스터의 다른 매개 변수 (대부분 ah 및 al)로 호출하면 다양한 IO 작업, 문자열 출력 등에 액세스 할 수 있습니다.

대부분의 Unix 시스템 및 파생 제품은 시스템 호출에 사용되는 인터럽트 0x80을 제외하고 소프트웨어 인터럽트를 사용하지 않습니다. 이는 커널 함수에 해당 하는 32 비트 값을 프로세서의 EAX 레지스터에 입력 한 다음 INT 0x80을 실행하여 수행됩니다.

인터럽트 처리기 테이블에서 사용 가능한 다른 값이 표시되는 곳을 살펴보십시오.

여기에 이미지 설명 입력

표에서 볼 수 있듯이 CPU는 시스템 호출을 실행합니다. 여기 에서 Linux 시스템 호출 테이블을 찾을 수 있습니다 .

따라서 값 0x1을 EAX 레지스터로 이동하고 프로그램에서 INT 0x80을 호출하여 현재 실행중인 프로세스 (Linux, x86 Intel CPU)를 중지 (종료)하는 커널의 코드를 프로세스가 실행하도록 할 수 있습니다.

하드웨어 인터럽트를 소프트웨어 인터럽트와 혼동해서는 안됩니다. 다음은 이 점에 아주 좋은 대답이다.

이것은 또한 좋은 소스입니다.


4
리눅스 시스템 호출 테이블 링크 \ = 고장
미겔 안젤로에게

1
대부분의 유닉스 시스템과 파생물은 소프트웨어 인터럽트를 사용하지 않습니다 (int 0x80 제외) . int 0x80I386 리눅스 시스템 호출 ABI는 DOS 매우 유사하다 int 0x21ABI. 레지스터에 호출 번호 (DOS의 경우 AH, Linux의 경우 EAX)를 입력하고 다른 레지스터에 다른 인수를 입력 한 다음 소프트웨어 인터럽트 명령을 실행합니다. 주요 차이점은 시스템 호출을 통해 수행 할 수있는 작업 (리눅스가 아닌 DOS에서 하드웨어에 직접 액세스)이 아니라 호출 방식에 있습니다.
Peter Cordes

다음은 깨지지 않은 syscall 테이블 링크입니다. syscalls.kernelgrok.com 상단에 모든 통화를 표시하려면 확장하기 만하면됩니다.
ollien

Linux 64 비트를 사용하는 경우/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton

11

최소 실행 가능한 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

결과 : 프로그램은 stdout에 인쇄합니다.

hello world

깨끗하게 종료됩니다.

사용자 영역에서 직접 인터럽트 처리기를 설정할 수는 없습니다. 링 3있고 Linux에서는이를 방지하기 때문 입니다.

GitHub 업스트림 . Ubuntu 16.04에서 테스트되었습니다.

더 나은 대안

int 0x80시스템 호출을위한 더 나은 대안으로 대체되었습니다 : 먼저 sysenter, 그 다음에는 VDSO.

x86_64에는 새로운 syscall명령어가 있습니다.

참조 : "int 0x80"또는 "syscall"이 더 나은 것은 무엇입니까?

최소 16 비트 예제

먼저 여기에서 설명한대로 최소 부트 로더 OS를 만들고 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

이것은 순서대로 수행됩니다.

  • Do 0.
  • Do 1.
  • hlt: 실행 중지

프로세서가 address에서 첫 번째 핸들러를 찾는 방법 0과 두 번째 핸들러를 찾는 방법에 유의하십시오 4. 이는 IVT 라는 핸들러 테이블 이며 각 항목에는 4 바이트가 있습니다.

핸들러를 표시하기 위해 일부 IO수행하는 최소 예제입니다 .

최소 보호 모드 예

최신 운영 체제는 소위 보호 모드에서 실행됩니다.

이 모드에서는 핸들링에 더 많은 옵션이 있으므로 더 복잡하지만 정신은 동일합니다.

핵심 단계는 처리기를 설명하는 메모리 내 데이터 구조 (인터럽트 설명자 테이블)의 주소를 가리키는 LGDT 및 LIDT 명령어를 사용하는 것입니다.

최소한의 예



4

"int"명령은 인터럽트를 발생시킵니다.

인터럽트 란 무엇입니까?

간단한 답변 : 간단히 말해 인터럽트는 CPU를 중단하고 특정 작업을 실행하도록 지시하는 이벤트입니다.

자세한 답변 :

CPU에는 메모리에 저장된 인터럽트 서비스 루틴 (또는 ISR) 테이블이 있습니다. 리얼 (16 비트) 모드에서, 이것은로 저장됩니다 IVT , 또는 I nterrupt V의 엑터 T 수. IVT는 일반적으로 0x0000:0x0000(물리적 주소 0x00000)에 있으며 ISR을 가리키는 일련의 세그먼트 오프셋 주소입니다. OS는 기존 IVT 항목을 자체 ISR로 대체 할 수 있습니다.

(참고 : 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까지의 모든 인터럽트가 있어야합니다. OS가 이들 모두를 반드시 사용하는 것은 아니므로 Present 비트를 사용하면 CPU가 OS가 처리하지 않을 인터럽트를 적절하게 처리 할 수 ​​있습니다.

인터럽트가 발생하면 (IRQ의 외부 트리거 (예 : 하드웨어 장치) 또는 int프로그램 의 명령에 의해 ) CPU는 EFLAGS, CS, EIP 순으로 푸시합니다. (이는 iret인터럽트 반환 명령 인에 의해 자동으로 복원됩니다 .) OS는 일반적으로 시스템 상태에 대한 추가 정보를 저장하고, 인터럽트를 처리하고, 시스템 상태를 복원하고, 계속합니다.

많은 * NIX OS (Linux 포함)에서 시스템 호출은 인터럽트 기반입니다. 프로그램은 레지스터 (EAX, EBX, ECX, EDX 등)의 시스템 호출에 인수를 넣고 인터럽트 0x80을 호출합니다. 커널은 이미 인터럽트 0x80을 수신 할 때 호출되는 0x80의 인터럽트 핸들러를 포함하도록 IDT를 설정했습니다. 그런 다음 커널은 인수를 읽고 그에 따라 커널 함수를 호출합니다. EAX / EBX에 반품을 저장할 수 있습니다. 시스템 호출은 크게 의해 대체되었습니다 sysentersysexit(또는 syscallsysret링 0으로 빠른 진입을 허용 지침, AMD에).

이 인터럽트는 다른 OS에서 다른 의미를 가질 수 있습니다. 설명서를 확인하십시오.


재미있는 사실 : FreeBSD의 i386 시스템 호출 ABI는 사용자 공간 스택에 인수를 전달합니다. eaxsyscall 번호 에만 사용됩니다. asm.sourceforge.net/intro/hello.html
피터 코르

2

언급했듯이 제어가 인터럽트 벡터 0x80으로 점프하도록합니다. 실제로 이것이 의미하는 것은 (적어도 Linux에서는) 시스템 호출이 호출된다는 것입니다. 정확한 시스템 호출과 인수는 레지스터의 내용에 의해 정의됩니다. 예를 들어, % eax를 1로 설정 한 다음 'int 0x80'을 설정하여 exit ()를 호출 할 수 있습니다.


1

CPU에게 인터럽트 벡터 0x80을 활성화하도록 지시합니다. Linux OS open()에서는 파일 등의 시스템 기능을 호출하는 데 사용되는 시스템 호출 인터럽트 입니다.


9
엄밀히 말하면 커널에게 알려주지 않습니다. CPU에 알려주고, IDT에서 핸들러를 조회하여 일부 커널 코드에 대한 포인터가됩니다.
asveikau

진실. 더 나은 표현은 CPU에 벡터를 활성화하도록 지시하고 벡터 (커널의 일부)가 함수를 호출하는 것입니다.
Amber

이는 다음 다음 간다 어떤이를 수행하는, 그 일을 끝을 어떤 inturn하는이, 일을 끝 혼동을 . : / 앰버는 .. understandable..thats 인 답이있다
Afzaal 아마드 Zeeshan

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.