Interrupt 10h not working

2019-01-29 06:11发布

问题:

I am getting segmentation fault in the program below.
This is for set the cursor on the top-left of the screen. But why i am getting segmentation fault on this program? Thanks for the replies.

section .text
global main
main:
    mov ah, 2
    mov bh, 1
    mov dh, 0
    mov dl, 0
    int 10h

I think that the problem is the protected mode that i am working. This is an 16-bit instruction and i am trying this in a 32-bit machine! Am i correct?

I am running this program in a Linux Ubuntu distribution 32-bits. THe processor is AMD C-60.

回答1:

BIOS interrupts are 16-bit code. Your OS has put the CPU in 32-bit protected mode. The hardware will allow a switch back to 16-bit real mode (there are hoops to jump through) but the OS won't allow it. Wouldn't be very "protected" if it did. It is "protected" from US, my friend!

I think what you probably want to look into is "vt100" terminal emulation. By rights, a "robust" program would consult the "termcaps" file to make sure vt100 emulation is available before attempting to use it. My experience is that it's "usually" available on a "desktop Linux" box, so I just ASSume it's there. Worst that can happen (I think) is garbage on the screen if we ASSume wrong.

This example doesn't do exactly what you want. It saves the current cursor position (lord knows where), moves the cursor to a new position, prints a message, and goes back to the original cursor position. You'll need to look up the "home cursor" command ("ESC [h"? lookitup). Just write it to stdout, same as "hello world". You can get colors and stuff, too.

; nasm -f elf32 mygem.asm
; ld -o mygem mygem.o -melf_i386

global _start

section .data
savecursor db 1Bh, '[s'
.len equ $ - savecursor

unsavecursor db 1Bh, '[u'
.len equ $ - unsavecursor

getcursor db 1Bh, '[6n'
.len equ $ - getcursor

setcursor db 1Bh, '[10;20H'
.len equ $ - setcursor

msg db "Hello, new cursor position!"
.len equ $ - msg

section .text
_start:

mov ecx, savecursor
mov edx, savecursor.len
call write_stdout


mov ecx, setcursor
mov edx, setcursor.len
call write_stdout

mov ecx, msg
mov edx, msg.len
call write_stdout

mov ecx, unsavecursor
mov edx, unsavecursor.len
call write_stdout

exit:
mov eax, 1
xor ebx, ebx
int 80h

;------------------------
write_stdout:    
push eax
push ebx
mov eax, 4
mov ebx, 1
int 80h
pop ebx
pop eax
ret
;---------------------


回答2:

Try the following:

org 100h
section .text
global main
main:
    mov ah, 2
    mov bh, 1
    mov dh, 0
    mov dl, 0
    int 10h

Please read this:

This org 100h actually tells assembly that our program will begin at offset 100h. Why is this necessary? It is because all running programs have Process Control Block (PCB) with it. It's sort of thing for operating system to manage stuffs, So, it's better for us not to interfere with that unless you're doing advanced stuff. After that, we have a jump, right? Then after that jump, you put all your data in, right? That's how we cope with this chaos. The unconditional jump ensures the space for data so that it does not interfere with code. and vice versa. It is usually the case when the code interferes with data, it will cause hangups, blue screen of death and so on, --again -- UNLESS you are an assembly guru that knows what you're doing (like doing some self-modification code stuff and similar arcane tricks).


For linux you should work only with system calls this is a well documented tutorial, you put in eax the number of the sys call and jump to it/ switch into kernel mode with int 80h:

section .data
    hello:     db 'Hello world!',10    ; 'Hello world!' plus a linefeed character
    helloLen:  equ $-hello             ; Length of the 'Hello world!' string
                                       ; (I'll explain soon)

section .text
    global _start

_start:
    mov eax,4            ; The system call for write (sys_write)
    mov ebx,1            ; File descriptor 1 - standard output
    mov ecx,hello        ; Put the offset of hello in ecx
    mov edx,helloLen     ; helloLen is a constant, so we don't need to say
                         ;  mov edx,[helloLen] to get it's actual value
    int 80h              ; Call the kernel

    mov eax,1            ; The system call for exit (sys_exit)
    mov ebx,0            ; Exit with return code of 0 (no error)
    int 80h