[assembly] 어셈블리 코드에서 “int 0x80″은 무엇을 의미합니까?

누군가 다음 어셈블리 코드의 기능을 설명 할 수 있습니까?

 int 0x80



답변

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

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

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


답변

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

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


답변

명심 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)를 중지 (종료)하는 커널의 코드를 프로세스가 실행하도록 할 수 있습니다.

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

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


답변

최소 실행 가능한 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 명령어를 사용하는 것입니다.

최소한의 예


답변

int 0x80은 x86 (즉, Intel 호환) 프로세서의 Linux에서 시스템 호출을 호출하는 데 사용되는 어셈블리 언어 명령어입니다.

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


답변

“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에서 다른 의미를 가질 수 있습니다. 설명서를 확인하십시오.


답변

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