So, I have a function that prints nCr. The user asks for input from the user, and my function inculcates the recursive function for getting nCr:
int nCr(int n, int r){
if (r == 0 || r == n){
return 1;
} else {
return (nCr(n-1, r-1) + nCr(n-1, r));
}
}
This is the function I did when I try to convert it into NASM:
nCr:
mov ebp, esp
cmp word[ebp + 4], 0
je baseCase
mov ax, word[ebp + 6]
cmp word[ebp + 4], ax
je baseCase
cont:
dec ax
mov bx, word[ebp + 4]
dec bx
sub esp, 2
push ax
push bx
call nCr ;call nCr(n-1, r-1)
pop ax
mov ebp, esp
mov word[ebp + 8], ax
mov ax, 0
sub esp, 2
push ax
push word[ebp + 4]
call nCr ; call nCr(n-1, r)
pop ax
mov ebp, esp
add word[ebp + 8], ax
ret 4
baseCase:
mov word[ebp + 8], 1
ret 4
I tested it out with 3 and 2 and I got a segmentation fault (core dumped) error message. Is there something that I need to do or change in this block of code (assume that the inputs are converted into integers from ASCII characters)?
Related
I'm trying to design an algorithm in NASM which is supposed to compute the nth Fibonacci number. I wrote some code, but, when run, it outputs only 1 and I cannot understand why. My idea was to call Fibonacci for n-1 and for n-2, where the parameter n is stored within AX register, and the result is stored at BX.
%include "io.inc"
section .text
global CMAIN
CMAIN:
mov ebp, esp; for correct debugging
xor eax, eax
xor ebx, ebx
push word 12
call fibonacci
pop word [trash]
PRINT_UDEC 1, ax
ret
fibonacci: push ebp
mov ebp, esp
mov ax, [ebp + 8];se incarca ax cu parametrul primit prin stiva
cmp ax, 0
jne l1
mov bx, 0
jmp l3
l1: cmp ax, 1
jne l2
mov bx, 1
jmp l3
l2: sub ax, 2;n-2
push ax
call fibonacci
pop dx;resotre the stack
mov [ebp - 2], bx
mov ax, [ebp + 8];se incarca bx cu parametrul prinit prin stiva
sub ax, 1;n-1
push ax
call fibonacci
pop dx;restore the stack
add bx, [ebp - 2]
l3: mov esp, ebp
pop ebp
ret
section .data
trash dw 1
I am getting a stack overflow error at the position 'Call CalcProd' (within the function itself, not in main). Any idea why?
Here are relevant variable declarations:
Num1 DWORD 12
Num2 DWORD 7
Prod DWORD 0
Here is my function linkage and call in Main:
;----------------------CalcProd LINKAGE------------------
PUSH Num1
PUSH Num2
PUSH OFFSET Prod
CALL CalcProd
;--------------------------------------------------------
Here is my function:
;-------------------------CalcProd-------------------------
;calculates the product of the Num1 * Num2
;e.g. CalcProd(5,3) = 5+5+5 = 15
;params: Num1 and Num2 are passed in on the stack
;output: the product is put into the Prod variable
;------------------------------------------------------------
CalcProd proc
N1 EQU 16[ebp]
N2 EQU 12[ebp]
P EQU 8[ebp]
;necessary
PUSH ebp
MOV ebp,esp
MOV ecx,N2
;if (Num2 == 0)
CMP ecx,0
JE baseCase
;else return CalcProd(Num1,Num2-1)
DEC ecx
;PUSH ecx ; Num2-1
MOV N2,ecx
CALL CalcProd
;adds number to itself here
MOV esi,P
MOV eax,N1
ADD [esi],eax
baseCase:
MOV esp,ebp
POP ebp
ret 12
CalcProd endp
;the fix:
;else return CalcProd(Num1,Num2-1)
;DEC ecx
;PUSH Num1
;PUSH ecx
;PUSH OFFSET Prod
;CALL CalcProd
The following is my code. The block in hex2dec works successfully for converting a single hexadecimal number to decimal number. It would be really helpful if someone could point out where I was going wrong in the use of array. Thanks.
DATA SEGMENT
NUM DW 1234H,9H,15H
RES DB 3*10 DUP ('$','$','$')
SIZE DB 3
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE
START:
MOV AX, DATA
MOV DS,AX
MOV DI,0
LOOP3:
MOV AX,NUM[DI]
LEA SI,RES[DI]
CALL HEX2DEC
LEA DX,RES[DI]
MOV AH,9
INT 21H
INC DI
CMP DI,3
JL LOOP3
MOV AH,4CH ; end program
INT 21H
CODE ENDS
HEX2DEC PROC NEAR
MOV CX,0
MOV BX,10
LOOP1:
MOV DX,0
DIV BX
ADD DL,30H
PUSH DX
INC CX
CMP AX,9
JG LOOP1
ADD AL,30H
MOV [SI],AL
LOOP2:
POP AX
INC SI
MOV [SI],AL
LOOP LOOP2
RET
HEX2DEC ENDP
END START
MOV AX,NUM[DI]
LEA SI,RES[DI]
LEA DX,RES[DI]
You are treating DI as an array index like we use in any of the high level languages. In assembly programming we only use displacements aka offsets in the array.
In your program, since the NUM array is composed of words, you need to give the DI register successively the values 0, 2, and 4.
ADD DI, 2
CMP DI, 6
JB LOOP3
Also it would be best to not treat the RES as an array. Just consider it a buffer and always use it from the start.
RES DB 10 DUP (0)
...
LEA SI, RES
CALL HEX2DEC
LEA DX, RES
A better version of HEX2DEC avoids the ugly prefixed "0" on the single digit numbers:
HEX2DEC PROC NEAR
XOR CX, CX <--- Same as MOV CX,0
MOV BX,10
LOOP1:
XOR DX, DX <--- Same as MOV DX,0
DIV BX
ADD DL, 30H
PUSH DX
INC CX
TEST AX, AX
JNZ LOOP1
LOOP2:
POP AX
MOV [SI], AL
INC SI
LOOP LOOP2
MOV AL, "$" <--- Add this to use DOS function 09h
MOV [SI], AL
RET
HEX2DEC ENDP
;==============================================================================================
; recursive procedure:
; supersum(int x)
; returns 1*2 + 2*3 + 3*4 + ... + i*(i+1)
supersum PROC
push ebp ; start of every procedure
mov ebp, esp
push ebx
; Actual subproc calc here
mov eax, [ebp +8] ; returning eax to the original called value
cmp eax,1
je basecase
dec eax ; (n-1) ; its just a lie...
mov recnum, eax ; saving dec val for call
mul double ; 2(n-1)
mov rhs, eax ; the right hand side is finished
push recnum
call sumseries ; a_(n-1)
add esp, 4
definition:
add eax, rhs ; a_(n-1)+ 2(n-1)
jmp skp
basecase: ; a_1 = 0
mov eax, 0
mov rhs, 2
jmp definition
skp:
pop ebx
pop ebp
ret
supersum ENDP
;============================================================================
The explicit definition of the serries I'm trying to get is 1*2 + 2*3 + 3*4 ... + i(i+1).
I've got the math for it down and I found that the recursive definition for the series is a_n = a_(n-1) + 2(n-1) with a_1 = 0 as a base case. I'm trying to figure out why this code keeps giving me the even series: {2,4,6,8,10 ...} instead of the series I'm trying to calculate
Allright folks, let's hope this is an easy one: I need to access an array to achieve double-buffering (I use mode 13h) in 16-bit TASM. BUT: No matter if I use "OFFSET", "BYTE PTR [Array]", "BYTE PTR Array", or whatever I have tried already, the program reads/writes to the incorrect memory block, which is partly behind the actual start of the array.
Heres my (for now not really optimised and very messy) code:
.MODEL MEDIUM
.STACK
.DATA
XPos DW 0
YPos DB 0
Color DB 0
BoxX1 DW 0
BoxY1 DB 0
BoxX2 DW 0
BoxY2 DB 0
VPage DB 64010 DUP(0) ;TODO: Size *might* be incorrect.
PageSeg DW 0
.CODE
SetVGA13 PROC
MOV AX, 0013h ;Screen mode 13.
INT 10h ;Set screen mode to AX.
MOV AX, 0A000h ;Screen segment.
MOV ES, AX ;You can't affect segment registers
RET
ENDP
;-------DrawPixel---------------
; WORD XPos = x
; WORD YPos = y
; BYTE Color = colour
;-------------------------------
DrawPixel PROC
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
;ADD ES, DI
MOV ES:[DI],AL
;MOV ES:[DI],AL
RET
ENDP
DrawBox PROC
MOV CL, [BoxY1]
YLoop:
MOV BL, CL
PUSH CX
MOV CX, [BoxX1]
XLoop:
MOV [XPos], CX
MOV [YPos], BL
MOV [Color],CL
CALL DrawPixel
INC CX
CMP CX, [BoxX2]
JNZ XLoop
POP CX
INC CL
CMP CL, [BoxY2]
JNZ YLoop
RET
ENDP
WaitFrame PROC
PUSH DX
; Port #03DA contains VGA status
MOV DX, 03DAh
IN AL, DX
WaitRetrace:
; Bit 3 will be on if we're in retrace
TEST AL, 08h
JNZ WaitRetrace
EndRefresh:
IN AL, DX
TEST AL, 08h
JZ EndRefresh
POP DX
RET
ENDP
RestoreVideo PROC
; Return to text mode
MOV AX, 03h
INT 10h
RET
ENDP
ClearScreen PROC
XOR CX, CX
;MOV ES, [PageSeg]
ClearLoop:
MOV DI, CX
;MOV ES, [PageSeg]
MOV BX, OFFSET VPage
ADD BX, CX
MOV AL, [BX];VPage[DI];ES:[DI]
MOV [Color],AL
MOV AX, 0A000h
MOV ES, AX
MOV AL, [Color]
MOV ES:[DI],AL
INC CX
CMP CX, 64000
JNZ ClearLoop
RET
ENDP
Main:
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
CALL SetVGA13
;CALL MakePalette
MOV [BoxX1],33
MOV [BoxY1],33
MOV [BoxX2],99
MOV [BoxY2],99
;LOOP
GameLoop:
;DRAW
;CALL DrawBox
CALL ClearScreen
;CALL WaitFrame
;INPUT
MOV DX, 60h
IN AL, DX
CMP AL, 75
JNZ NotLeft
SUB [BoxX1],1
SUB [BoxX2],1
NotLeft:
IN AL, DX
CMP AL, 77
JNZ NotRight
ADD [BoxX1],1
ADD [BoxX2],1
NotRight:
CMP AL, 1
JNZ GameLoop
;END PROGRAM
Error:
;CALL ClearScreen
CALL RestoreVideo
MOV AH, 4Ch
INT 21h
END Main
This code shows a rainbow coloured box that you can move around with the left and right arrow keys,
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
That is my sad attempt to getbthe pointer to my buffer, but doesnt return the correct one
Sorry that my question was not done, i realised that when i got out of bed immediately for some reason.
Although this is not how I would code things, I'll offer up a couple of suggestions that may get you closer to resolving your problems.
When your executable loads the DS and ES registers originally point to the DOS PSP for your program. In your case you need to at least point DS to your DATA segment. The DATA segment that is filled in at run time by the DOS EXE loader can be referenced in your code by prefixing the segment name with an # (AT) symbol. So you can replace this code:
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
With this:
;INITIALISE
MOV BX, #DATA ; Set up DS with our program's DATA segment
MOV DS, BX
MOV [PageSeg],BX ; VPage is in DATA segment, move segment to PageSeg
In your DrawPixel code you'll need to add the VPage offset to DI. Replace this code:
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
MOV ES:[DI],AL
with:
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
ADD DI, OFFSET VPage ; We need to add VPage's offset
; from beginning of PageSeg
MOV ES:[DI],AL
Video mode 13h is 320x200x256 colors. The amount of video ram that is needed would be 320*200*1 = 64000. This could be changed from:
VPage DB 64010 DUP(0) ;TODO: Size *might* be incorrect.
to:
VPage DB 64000 DUP(0)
With these changes the program seems to display a rainbow box and moves left and right on the screen with the arrow keys.
There may be other bugs but I don't know what you were trying to achieve. This code could be simplified greatly. My changes were the minimal ones to work with the way you coded your program and make it somewhat functional.