Stuck in infinite loop in QEmu - c

I have the following code, where I am trying to add a new interrupt (int 0x21) for 16-bit mode of x86:
void main()
{
char* str = "Enter the string!\n\r";
makeInterrupt21();
interrupt(0x21,0,str,0,0);
}
The interrupt and the makeInterrupt21 functions are written in assembly. The interrupt function simply calls the interrupt number as given by the first argument with rest of the arguments determining the valuses of ax, bx, cx and dx registers respectively.
The makeInterrupt21 function sets the entry for the jump address of interrupt 0x21.
.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret
.global _makeInterrupt21
_makeInterrupt21:
push bp
mov bp, sp
push es
mov ax, #0x0
mov es, ax
mov bx, #0x84
mov ax, #interrupt21ServiceHandler
eseg
mov [bx], ax
eseg
mov [bx + 0x2], ds
pop es
pop bp
ret
.extern _handleInterrupt21
interrupt21ServiceHandler:
push dx
push cx
push bx
push ax
call _handleInterrupt21
ret
The handleInterrupt21 is the interrupt handler function for the interrupt 0x21 and is written in C:
void handleInterrupt21(int ax, int bx, int cx, int dx)
{
char* line;
line = bx;
switch (ax)
{
case 0x0:
printString(line);
break;
default:
printString("Error invalid arguments!");
break;
}
}
The printString function prints the string starting at the address given by the argument given to it:
int printString(char* string)
{
int i = 0;
while (*(string + i) != '\0')
{
char al = *(string + i);
char ah = 0xe;
int ax = ah * 256 + al;
interrupt(0x10,ax,0,0,0);
i++;
}
return i;
}
When I run this code on QEmu, I get into an infinite loop which prints:
Enter the string!
Enter the string!
Enter the string!
When I ran this on QEmu, I got the following error:
Program received signal SIGTRAP, Trace/breakpoint trap.
Could anyone explain why am I stuck in a loop?
EDIT:
Also please explain the meaning of breakpoint trap and why am I getting this error. I read a related question on this but I couldn't understand the answer.

Related

abnormal program termination turbo c

I am trying to run an combined code of C that calling assembly procedure, and I get abnormal program termination message.
Its very simple code, the assembly procedure scans a number and return the result to c.
;main code
#include<stdio.h>
extern long getPnum();
int main()
{
long x;
x = getPnum();
printf("%d", x);
return 0;
}
;getPNum
.MODEL SMALL
.STACK 100H
.DATA
NUM DD 0
.CODE
.386
PUBLIC _getPnum
_getPnum PROC NEAR
PUSH BP
MOV BP,SP
PUSH EAX
PUSH EBX
PUSH ECX
MOV EBX,10
SCAN:
MOV EAX,NUM
MUL EBX
MOV ECX,EAX
XOR EAX,EAX
MOV AH,1
INT 21H
CMP AL,13
JE NEXT
SUB AL,'0'
MOV AH,0
ADD ECX,EAX
MOV NUM,ECX
JMP SCAN
NEXT:
MOV AX,WORD PTR NUM
MOV DX,WORD PTR NUM+2
ADD SP,14
RET
_getPnum ENDP
END
I changed the %d to ld%, and now I get another error: Dimdie error
It's very strange when I run the DEBUGER I return the number through AX DX,and X gets the wrong value
debugger
result scrren
I Changed
ADD SP,14
RET
to
ADD SP,12
POP BP
RET
and now I don't get any errors, but the printed value is incorrect, despite that the returned value trough DX:AX is correct
BP must be restored when you leave the procedure.
Change
ADD SP,14
RET
to
ADD SP,12
POP BP
RET
Better is:
MOV SP, BP
POP BP
RET
BTW: Why do you push a bunch of registers which you don't restore at the end of the function?

Perfect number C-NASM program not working?

so basically the program prints the factors of a number and checks if the inputted number is a perfect number. However, all the program does is ask for the input and then crashes. I assume that it has an endless loop somewhere in the .asm file. What could be the problem? Any and all suggestions/replies is appreciated. :)
C program:
#include <stdio.h>
extern int factors(int a);
int main()
{
int a1, x;
ag: printf("Enter a number: ");
scanf("%d", &a1);
if(a1 >= 65536)
{
printf("Invalid number, Enter again\n");
goto ag;
}
x = factors(a1);
if(x == 1)
printf("%d is a perfect number\n", a1);
else
printf("%d is not a perfect number", a1);
getchar();
return 0;
}
NASM program:
segment .text
global _factors
_factors:
push ebp ; create stack frame
mov ebp, esp ; save stack
mov eax, [ebp + 8] ; first parameter
mov ebx, 00000001 ; initialize ebx to 1. ebx is the countere
mov ecx, eax ; more eax to ecx in order to preserve the number
agn:
cmp ebx, ecx ; check if the counter is equal to the number
je done
mov eax, ecx
xor dx, dx
div bx
inc ebx
cmp dx, 0
jne agn
mov word [fact], ax
lea dx, [fact]
mov ah, 09h
int 21h
jmp agn
done:
leave
ret
section .data
fact times 5 db "$"
sum times 5 db "$"

Assembly program to print 'a' to 'z' using stack, loop cx and dx

I've got an assignment to make an assembly program which print 'a' to 'z' vertically line by line using stack, loop cx and dx.
Can anyone help me please.
This is program of printing a to z, but i dont have an idea how to use stack cx and dx in my program:
.data
l1c db 0ah,0dh,"S"
.code
main proc
mov ax #data
mov ds,ax
mov al,48
mov cx,10
d:
mov dl,al
mov ah,2
int 21h
call linechange
inc al
loop d
mov ah,4ch
int 21h
main endp
;Procedure
linechange proc
lea dx,l1c
mov ah,9
int 21h
ret
linechnage endp
end main
(this is the program which i made by my self)
I guess your teacher wanted to avoid a "clever" solution like:
.MODEL SMALL
.STACK 1000h
.DATA
smart_out db 'a',13,10,'b',13,10,'b',13,10,'c',13,10,'d',13,10,'e',13,10
db 'f',13,10,'g',13,10,'h',13,10,'i',13,10,'j',13,10,'k',13,10
db 'l',13,10,'m',13,10,'n',13,10,'o',13,10,'p',13,10,'q',13,10
db 'r',13,10,'s',13,10,'t',13,10,'u',13,10,'v',13,10,'w',13,10
db 'x',13,10,'y',13,10,'z',13,10,'$'
.CODE
main:
mov ax, #data
mov ds, ax
mov ah, 9
mov dx, OFFSET smart_out
int 21h
mov ax, 4C00h
int 21h
END main
You are supposed to output this with a LOOP (CX needed). In a loop you need to preserve at least AX and CX since you never know if a procedure like INT 21h will change it. A call to INT 21h / 9 fulfills the third condition since it needs a value in DX:
.MODEL SMALL
.STACK 1000h ; Reserve space for stack and initialize stack pointer
.DATA
l1c db 0dh, 0ah, '$' ; Dollar-sign!
.CODE
main PROC
mov ax, #data
mov ds, ax
mov al, 'a'
mov cx, 26
d:
push ax ; Store AX (AL is a part of AX)
push cx ; Store CX
mov dl, al
mov ah, 2
int 21h
mov ah, 9
mov dx, OFFSET l1c
int 21h
pop cx ; Restore CX & AX in reversed push-order
pop ax
inc al
loop d ; Loops until cx == 0
mov ah, 4ch
int 21h
main ENDP
END main

When replacing keyboard interrupt (Interrupt 9) scanf doesn't appear to accept input [duplicate]

This question already has an answer here:
How to prevent duplicate chars when I press keys on the keyboard
(1 answer)
Closed 4 years ago.
I'm writing the main program in Turbo-C and the functions are in assembly. My code is as follows:
lastc.c:
#include <stdio.h>
#include <dos.h>
#include <string.h>
extern void eliminate_multiple_press(); // save old function adress in 32bit pointer
// setvect , add new function to inturupt 9
extern void uneliminate_multiple_press(); // restore old function to inturupt 9
int main()
{
char *str;
eliminate_multiple_press();
printf("Enter a string:\n");
scanf("%s",str);
printf("the string you entered:\n");
printf("%s\n",str);
uneliminate_multiple_press();
return 0;
}
lasta.asm:
.MODEL LARGE
PUBLIC _eliminate_multiple_press
PUBLIC _uneliminate_multiple_press
.STACK 100H
.DATA
INT9SAVE DD ?
hexa_code db 0
scan_code db 0
.CODE
KEY_HANDLER PROC FAR
PUSH AX
MOV AH,0
int 16h
mov scan_code,ah
mov hexa_code,al
POP AX
iRET
KEY_HANDLER ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_eliminate_multiple_press PROC FAR
PUSH AX
PUSH ES
MOV AX,0
MOV ES,AX
;INT9SAVE = GETVECT(9);
MOV AX,ES:[9*4] ; **ax=c1 hex =193 dec**
MOV WORD PTR INT9SAVE,AX
MOV AX,ES:[9*4+2] **ax=15c7 hex = 5575 dec**
MOV WORD PTR INT9SAVE+2,AX
;SETVECT(9,KEY_HANDLER);
CLI
MOV WORD PTR ES:[9*4],OFFSET KEY_HANDLER ; **ES stays 0**
MOV WORD PTR ES:[9*4+2],SEG KEY_HANDLER ; **ES stays 0**
STI
POP ES
POP AX
RET
_eliminate_multiple_press ENDP
;SETVECT(9,INT9SAVE);
_uneliminate_multiple_press PROC FAR
PUSH ES
PUSH AX
MOV AX,0
MOV ES,AX
CLI
MOV AX,WORD PTR INT9SAVE
MOV ES:[9*4],AX
MOV AX,WORD PTR INT9SAVE+2
MOV ES:[9*4+2],AX
STI
POP AX
POP ES
RET
_uneliminate_multiple_press ENDP
END
I can compile the files without error using this command:
tcc -ml -r- lastc.c lasta.asm
The goal of this code is to eliminate multiple (duplicate) key presses on the keyboard. If I type this sequence of characters:
334ffffghjjjj of my keyboard
The output on the screen should be
34fghj
The Problem
When I run the program lastc.exe it gets stuck at printf("enter a string:\n");. I guess I'm having a problem changing Interrupt 9h interrupt service routine to my new function key_handler
Function key_handler is not complete but at least it should END the function and continue to the end of the code
Why does my program appear to be doing nothing when the scanf is called?
Why are eliminate_multiple_press and uneliminate_multiple_press declared as interrupt handlers? They should be normal functions with a return of RET. They are being called as functions and are not intended as responses to an interrupt.
In your C program then:
extern void eliminate_multiple_press(); // save old function adress in 32bit pointer
// setvect , add new function to inturupt 9
extern void uneliminate_multiple_press(); // restore old function to inturupt 9
And your assembly, RET instead of IRET. And you don't need to save so many registers:
_eliminate_multiple_press PROC FAR
push ES
push AX
MOV AX,0
MOV ES,AX
;INT9SAVE = GETVECT(9);
MOV AX,ES:[9*4] ; **ax=c1 hex =193 dec**
MOV WORD PTR INT9SAVE,AX
MOV AX,ES:[9*4+2] **ax=15c7 hex = 5575 dec**
MOV WORD PTR INT9SAVE+2,AX
;SETVECT(9,KEY_HANDLER);
CLI
MOV WORD PTR ES:[9*4],OFFSET KEY_HANDLER ; **ES stays 0**
MOV WORD PTR ES:[9*4+2],SEG KEY_HANDLER ; **ES stays 0**
STI
POP AX
POP ES
RET
_eliminate_multiple_press ENDP
;SETVECT(9,INT9SAVE);
_uneliminate_multiple_press PROC FAR
PUSH ES
PUSH AX
MOV AX,0
MOV ES,AX
CLI
MOV AX,WORD PTR INT9SAVE
MOV ES:[9*4],AX
MOV AX,WORD PTR INT9SAVE+2
MOV ES:[9*4+2],AX ; Was "[27*4+2]" which is incorrect.
STI
POP AX
POP ES
RET
_uneliminate_multiple_press ENDP
An End Of Interrupt (EOI) is a signal sent to a Programmable Interrupt Controller (PIC) to
indicate the completion of interrupt processing for a given interrupt.
mov al,020h ; =EOI
out 020h,al

Handling A Keyboard Interrupt with Turbo C ++ 3.0

I have a project. That is a simple game , "Falling Blocks" . The game area is considered as a grid, which has 20x20 size. There will be falling blocks from top of the screen and a hero at the bottom, who will shoot the blocks. The aim of game is shooting blocks before they reach the bottom line. He always stays at the bottom line . Whenever the user press space button of the keyboard I will generate a bullet, and the hero moves on the bottom line with the right and left arrow keys. I do not have an idea about handling these keyboard interrupt with Turbo C ++ 3.0. It is forbidden that using "dos.h" and "int 21H", also. Could you give me hints about these project?
Edit: I have found this information but I could not understand how to implement it :
When a key is pressed on keyboard, an interrupt along with a scan code named “make code” is produced and when the key released a “break code” is produced by the keyboard controller. On a PC, keyboard is controlled by a chip and assigned to port numbers 60h and 61h. When a key is pressed on keyboard, scan value is put in register at 60h. You can get this scan code with the following command:
in al,60h
After getting the scan code, you have to reset the keyboard programming the command register of the chip at 61h with following commands:
in al,61h
or al,82h
out 61h,al
and al,7fh
out 61h,al
At the end of every interrupt service routine, you clear PIC service bit, sending End Of Interrupt (EOI) command, 20h to PIC port at address 20h.
mov al,20h
out 20h,al
File kbdc.c:
#include <stdio.h>
extern void SetNewIrq9Isr(void);
extern void RestoreOldIrq9Isr(void);
#define SCAN_BUF_SIZE 1024
extern volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
extern volatile unsigned ScanReadIdx;
extern volatile unsigned ScanWriteIdx;
const char ScanToChar[] =
"??1234567890-=??"
"QWERTYUIOP[]??AS"
"DFGHJKL;\"`?\\ZXCV"
"BNM,./??? ";
int IsScanCodeAvailable(void)
{
return ((ScanWriteIdx - ScanReadIdx) & (SCAN_BUF_SIZE - 1)) != 0;
}
unsigned char GetScanCode(void)
{
unsigned char code;
while (!IsScanCodeAvailable());
code = ScanBuf[ScanReadIdx];
ScanReadIdx++;
ScanReadIdx &= SCAN_BUF_SIZE - 1;
return code;
}
int main(void)
{
SetNewIrq9Isr();
printf("Press keys to see scan codes.\nPress ESC to exit.\n");
for (;;)
{
unsigned code, symbol;
code = GetScanCode();
symbol = code & 0x7F;
symbol = (symbol < sizeof(ScanToChar)) ? ScanToChar[symbol] : '?';
printf("scan code: 0x%02X, symbol: \"%c\"\n", code, (char)symbol);
if (code == 1)
{
break;
}
}
RestoreOldIrq9Isr();
return 0;
}
File kbda.asm:
GLOBAL _SetNewIrq9Isr, _RestoreOldIrq9Isr
GLOBAL _ScanBuf, _ScanReadIdx, _ScanWriteIdx
SEGMENT _TEXT PUBLIC CLASS=CODE USE16
; void SetNewIrq9Isr(void);
_SetNewIrq9Isr:
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, [es:bx]
mov [_pOldIrq9Isr], ax
mov word [es:bx], _NewIrq9Isr
mov ax, [es:bx + 2]
mov [_pOldIrq9Isr + 2], ax
mov [es:bx + 2], cs
sti
pop es
pop bx
ret
; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr:
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, [_pOldIrq9Isr]
mov [es:bx], ax
mov ax, [_pOldIrq9Isr + 2]
mov [es:bx + 2], ax
sti
pop es
pop bx
ret
_NewIrq9Isr:
pusha
push ds
mov ax, _DATA
mov ds, ax
in al, 60h
push ax
in al, 061h
mov ah, al
or al, 080h
out 061h, al
mov al, ah
out 061h, al
pop ax
; ScanBuf[ScanWriteIdx] = scan code;
; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
mov bx, [_ScanWriteIdx]
mov [_ScanBuf + bx], al
inc bx
and bx, 1023
mov [_ScanWriteIdx], bx
mov al, 20h
out 20h, al
pop ds
popa
iret
SEGMENT _DATA PUBLIC CLASS=DATA
_pOldIrq9Isr resd 1
; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf resb 1024
_ScanReadIdx dw 0
_ScanWriteIdx dw 0
Output:
Press keys to see scan codes.
Press ESC to exit.
scan code: 0x10, symbol: "Q"
scan code: 0x90, symbol: "Q"
scan code: 0x11, symbol: "W"
scan code: 0x91, symbol: "W"
scan code: 0x12, symbol: "E"
scan code: 0x92, symbol: "E"
scan code: 0x02, symbol: "1"
scan code: 0x82, symbol: "1"
scan code: 0x03, symbol: "2"
scan code: 0x83, symbol: "2"
scan code: 0x04, symbol: "3"
scan code: 0x84, symbol: "3"
scan code: 0x01, symbol: "?"
Now, some words on how to compile this.
Compile the assembly file with NASM using nasm.exe -f obj kbda.asm. It'll produce kbda.obj. Create a project in Borland/Turbo C/C++ IDE, include in it kbdc.c and kbda.obj. Make sure the code is going to be compiled in the small or tiny memory model (basically, we need to make sure SetNewIrq9Isr() and RestoreOldIrq9Isr() are going to be called as near functions). Compile it.
There are a few caveats.
First, none of the getc(), gets(), scanf(), etc functions will work if called between SetNewIrq9Isr() and RestoreOldIrq9Isr(). They will hang the program.
Second, the code doesn't keep track of the shift, control and alt keys. What it means to you is that, if you run this program from within the IDE by pressing ctrl+F9, when the program finishes, the IDE will most likely think ctrl is still being held down. To "unlock" the keyboard you'll have to press and release ctrl. The same may apply to other similar keys if they're held down when this program starts. You can include extra code to wait until all of shift, control and alt are released. I believe you can find their current state in the BIOS data area.
You can, of course, convert the assembly file from NASM syntax to TASM syntax and compile it with TASM. I'm simply using free tools, Turbo C++ 1.01 and NASM.
UPDATE: Here's the asm file for TASM:
PUBLIC _SetNewIrq9Isr, _RestoreOldIrq9Isr
PUBLIC _ScanBuf, _ScanReadIdx, _ScanWriteIdx
.386
_TEXT SEGMENT PUBLIC 'CODE' USE16
ASSUME CS:_TEXT, DS:_DATA
; void SetNewIrq9Isr(void);
_SetNewIrq9Isr PROC NEAR
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, es:[bx]
mov _pOldIrq9IsrOfs, ax
mov word ptr es:[bx], offset _NewIrq9Isr
mov ax, es:[bx + 2]
mov _pOldIrq9IsrSeg, ax
mov es:[bx + 2], cs
sti
pop es
pop bx
ret
_SetNewIrq9Isr ENDP
; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr PROC NEAR
push bx
push es
mov bx, 9 * 4
mov ax, 0
mov es, ax
cli
mov ax, _pOldIrq9IsrOfs
mov es:[bx], ax
mov ax, _pOldIrq9IsrSeg
mov es:[bx + 2], ax
sti
pop es
pop bx
ret
_RestoreOldIrq9Isr ENDP
_NewIrq9Isr PROC NEAR
pusha
push ds
mov ax, _DATA
mov ds, ax
in al, 60h
push ax
in al, 061h
mov ah, al
or al, 080h
out 061h, al
mov al, ah
out 061h, al
pop ax
; ScanBuf[ScanWriteIdx] = scan code;
; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
mov bx, _ScanWriteIdx
mov _ScanBuf[bx], al
inc bx
and bx, 1023
mov _ScanWriteIdx, bx
mov al, 20h
out 20h, al
pop ds
popa
iret
_NewIrq9Isr ENDP
_TEXT ENDS
_DATA SEGMENT PUBLIC 'DATA' USE16
_pOldIrq9IsrOfs dw ?
_pOldIrq9IsrSeg dw ?
; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf db 1024 dup (?)
_ScanReadIdx dw 0
_ScanWriteIdx dw 0
_DATA ENDS
END
You compile it using tasm.exe /ml kbda.asm. The rest is the same.
I also took a similar course back in the days. Basically what you need to do, is to catch the keyboard interrupt before it handled by the system keyboard interrupt handler.
You need to create your own interrupt handler, and the bind it to the keyboard interrupt.
once you're done with your work, call the original system keyboard interrupt handler.

Resources