2017-05-11 6 views
1
; another attempt to terminate program with Esc that hooks 
; keyboard interrupt 
    [org 0x100] 
    jmp start 
    oldisr: dd 0 ; space for saving old isr 
; keyboard interrupt service routine 
kbisr: push ax 
    push es 
    mov ax, 0xb800 
    mov es, ax ; point es to video memory 
    in al, 0x60 ; read a char from keyboard port 
    cmp al, 0x2a ; is the key left shift 
    jne nextcmp ; no, try next comparison 
    mov byte [es:0], 'L' ; yes, print L at top left 
    jmp nomatch ; leave interrupt routine 
    nextcmp: cmp al, 0x36 ; is the key right shift 
    jne nomatch ; no, leave interrupt routine 
    mov byte [es:0], 'R' ; yes, print R at top left 
    nomatch: ; mov al, 0x20 
; out 0x20, al 
    pop es 
    pop ax 
    jmp far [cs:oldisr] ; call the original ISR 
; iret 
start: xor ax, ax 
    mov es, ax ; point es to IVT base 
    mov ax, [es:9*4] 
    mov [oldisr], ax ; save offset of old routine 
    mov ax, [es:9*4+2] 
    mov [oldisr+2], ax ; save segment of old routine 
    cli ; disable interrupts 
    mov word [es:9*4], kbisr ; store offset at n*4 
    mov [es:9*4+2], cs ; store segment at n*4+2 
    sti ; enable interrupts 
l1: mov ah, 0 ; service 0 – get keystroke 
    int 0x16 ; call BIOS keyboard service 
    cmp al, 27 ; is the Esc key pressed 
    jne l1 ; if no, check for next key 
    mov ax, 0x4c00 ; terminate program 
    int 0x21 

이 프로그램에서 oldIsr을 호출하기 위해 cs : offset 만 사용할 수있는 이유가 궁금합니다. 왜 그냥 CS ??? 이 라인어셈블리 16 비트 인터럽트

jmp far [cs:oldisr] ; call the original ISR 

는 IT 뒤에 목적은 무엇인가 AT

? 설명해주세요!

+0

답변이 필요한 정보 인 경우 ** 답변 **을 수락하십시오.방법 및 이유에 대한 자세한 내용은 여기를 참조하십시오. https://meta.stackexchange.com/a/5235/271768 –

답변

3

내부 16 비트 리얼 모드 인터럽트 처리기 코드에서는 세그먼트 레지스터의 값을 알 수 없으며 아무 것도 될 수 있습니다. 대개 최소한 ss:sp 스택이 합리적으로 유효하고 반환 주소와 처리기에 대한 몇 바이트를 저장할만큼 충분히 크고 cs이 처리기 코드에 고정되어 있다고 예상 할 수 있습니다. 이는 cs 값이 다를 경우 CPU가 일부 다른 지침이 아니라 당신의 것입니다. 그래서

은 오래된/알 수없는 ds를 저장 핸들러 변수의 데이터 세그먼트를 설정하고 ds: 접두사를 통해 접근, 다시 ds를 복원의 번거 로움을 피하기 위해, 다음 코드 자체, 그리고 주소로 변수를 가지고하는 것이 더 쉽습니다 그 값은 cs:oldisr으로, cs의 값이 필요한 것으로 알려져 있습니다.


좀 더 간단한 방법을 작성하려고합니다

mov ax,[si]

사용 디폴트로 ds (* 1), 즉 실제로 mov ax,[ds:si]을하고있다.

명시 적으로 mov ax,[cs:si]과 같은 세그먼트 레지스터를 작성하여 기본값을 무시할 수 있습니다. 16B 리얼 모드에서

실제 메모리 주소는 다음과 같습니다 segment_value * 16 + offset_value 코드가 당신의 ISR 처리기를 입력 않는 경우, 당신은 모르는

, 실행중인 코드는 인터럽트의 순간에 ds 또는 es에 무엇을했다 . 변수가 아니라 메모리의 어느 부분을 가리킬 수 있습니다.

하지만 알고 계시 겠지만, 은 처리기 명령어를 가리 킵니다. 그렇지 않으면 CPU가 cs:ip의 메모리에서 다음 명령어를 실행하므로 CPU가 다른 곳에서 명령어를 실행합니다.

ds을 사용하려면 처리기가 ds과 어떻게 관련이 있는지를 나타내는 예인 es을 유지/설정/복원해야합니다.

cs은 코드 세그먼트로 설정되어 스택에 보존되어 있으며 이전 처리기에서는 IRET이 복원합니다. bpss 기본적으로 사용


1)는 기본적 stos/movs/cmps 모두 dses 의해 사용되며, 단지 소스 ds는 대상의 es는 고정되고, 무시 될 수있다.

+0

좀 더 간단한 단어로 설명해 주시겠습니까? –

+0

고마워요. 요점이 생겼어. 내가 놓친 부분은 코드가 ISR 핸들러에 들어갈 때, 실행중인 코드가 인터럽트 순간에 ds 나 es에 무엇을 가지고 있는지 모를 수 있습니다. 변수가 아니라 메모리의 어느 부분을 가리킬 수 있습니다. 그런데 왜 그렇게됩니까? –

+0

uhm .. 실행중인 코드가 원하는대로 세그먼트 레지스터를 사용하고 있기 때문에? 비 인터럽트 16b 어셈블리 코드를 작성할 때'ss : sp'가 적당한 크기의 유효한 스택 메모리를 만들면'ds'와'es' (심지어'ss')를 사용하거나 'ss : sp'가 유효하지 않은 시간). 1MiB의 메모리 주소 공간을 사용할 수 있음을 기억하십시오 (이 시대에는 300-600KB의 컴퓨터가 30 년 이상 제조되지 않았기 때문에 * 1MiB의 물리적 RAM을 사용할 수 있음을 알고 있습니다). 그러나 16b 오프셋은 64KB이므로 코드는 더 많은 메모리에 액세스하기 위해 세그먼트 regs를 변경해야합니다. – Ped7g

관련 문제