pass by reference in assembly - pointers

I am trying to write a program to calculate the exponential of a number using ARM-C inter-working. I am using LPC1769(cortex m3) for debuuging. The following is the code:
/*here is the main.c file*/
#include<stdio.h>
#include<stdlib.h>
extern int Start (void);
extern int Exponentiatecore(int *m,int *n);
void print(int i);
int Exponentiate(int *m,int *n);
int main()
{
Start();
return 0;
}
int Exponentiate(int *m,int *n)
{
if (*n==0)
return 1;
else
{
int result;
result=Exponentiatecore(m,n);
return (result);
}
}
void print(int i)
{
printf("value=%d\n",i);
}
this is the assembly code which complements the above C code
.syntax unified
.cpu cortex-m3
.thumb
.align
.global Start
.global Exponentiatecore
.thumb
.thumb_func
Start:
mov r10,lr
ldr r0,=label1
ldr r1,=label2
bl Exponentiate
bl print
mov lr,r10
mov pc,lr
Exponentiatecore: // r0-&m, r1-&n
mov r9,lr
ldr r4,[r0]
ldr r2,[r1]
loop:
mul r4,r4
sub r2,#1
bne loop
mov r0,r4
mov lr,r9
mov pc,lr
label1:
.word 0x02
label2:
.word 0x03
however during the debug session, I encounter a Hardfault error for the execution of "Exponentiatecore(m,n)".
as seen in debug window.
Name : HardFault_Handler
Details:{void (void)} 0x21c <HardFault_Handler>
Default:{void (void)} 0x21c <HardFault_Handler>
Decimal:<error reading variable>
Hex:<error reading variable>
Binary:<error reading variable>
Octal:<error reading variable>
Am I making some stack corruption during alignment or is there a mistake in my interpretation?
please kindly help.
thankyou in advance

There are several problems with your code. The first is that you have an infinite loop because your SUB instruction is not setting the flags. Change it to SUBS. The next problem is that you're manipulating the LR register unnecessarily. You don't call other functions from Exponentiatecore, so don't touch LR. The last instruction of the function should be "BX LR" to return to the caller. Problem #3 is that your multiply instruction is wrong. Besides taking 3 parameters, if you multiplied the number by itself, it would grow too quickly. For example:
ExponentiateCore(10, 4);
Values through each loop:
R4 = 10, n = 4
R4 = 100, n = 3
R4 = 10000, n = 2
R4 = 100,000,000 n = 1
Problem #4 is that you're changing a non-volatile register (R4). Unless you save/restore them, you're only allowed to trash R0-R3. Try this instead:
Start:
stmfd sp!,{lr}
ldr r0,=label1
ldr r1,=label2
bl Exponentiatecore // no need to call C again
bl print
ldmfd sp!,{pc}
Exponentiatecore: // r0-&m, r1-&n
ldr r0,[r0]
mov r2,r0
ldr r1,[r1]
cmp r1,#0 // special case for exponent value of 0
moveq r0,#1
moveq pc,lr // early exit
loop:
mul r0,r0,r2 // multiply the original value by itself n times
subs r1,r1,#1
bne loop
bx lr

I just add
Start:
push {r4-r11,lr}
...
pop {r4-r11,pc}
Exponentiatecore: # r0-&m, r1-&n
push {r4-r11,lr}
...
pop {r4-r11,pc}
and clean bl print in Start and all work fine

Related

(M68k) Why is my value not getting passed into D0?

So I am writing a program and subroutine where this is basically the pseudocode.
int findmin(int* vals, int count){
if(count == 1){
return vals[0];
}else{
int minrest = findmin(vals+1,count-1);
if (minrest < vals[0]){
return minrest
}else{
return vals[0]
}
}
}
I basically have to put this into m68k assembly code. In the pictures is what i have so far. I think my logic is correct but for some reason all this does is printout my header and nothing else, I feel like for some reason I am not corectly storing my result into D0 where it should be. Is there a step I am missing or something that I am just completely off on? My prog4.s is my main that calls the subroutine
My prog4.s is my main that calls the subroutine
subroutine recursive function
The main code calls the subroutine like this:
pea vals
move.w D1, -(SP)
jsr findmin
adda.l #6, SP
The findmin subroutine makes next recursive call:
move.l A0, -(SP)
move.w D1, -(SP)
jsr findmin
adda.l #6, SP
The findmin subroutine retrieves its parameters like:
findmin:
link A6, #0
...
move.w 8(A6), D1
move.l 12(A6), A0 <<< Here is the error!
But wait, because of how you placed things on the stack, this is how the stack is laid out:
A6 RTS D1 A0
lower ==== ==== == ==== higher
^
SP == A6
The above shows that the word D1 is at 8(A6) and that the longword A0 is at 10(A6). That's 10 instead of 12.

What is the purpose of the LEA instructions in this function and what does the overall recursion do?

I have been trying to work out what the following recursive function does:
func4:
0x08048cfa <+0>: push edi
0x08048cfb <+1>: push esi
0x08048cfc <+2>: push ebx
0x08048cfd <+3>: mov ebx,DWORD PTR [esp+0x10] // First arg
0x08048d01 <+7>: mov edi,DWORD PTR [esp+0x14] // Second arg
0x08048d05 <+11>: test ebx,ebx // if (ebx == 0) { eax = 0; return ???;}
0x08048d07 <+13>: jle 0x8048d34 <func4+58>
0x08048d09 <+15>: mov eax,edi
0x08048d0b <+17>: cmp ebx,0x1 // if (ebx == 1) {return ???;}
0x08048d0e <+20>: je 0x8048d39 <func4+63>
0x08048d10 <+22>: sub esp,0x8
0x08048d13 <+25>: push edi
0x08048d14 <+26>: lea eax,[ebx-0x1]// eax = ebx-1
0x08048d17 <+29>: push eax
0x08048d18 <+30>: call 0x8048cfa <func4>
0x08048d1d <+35>: add esp,0x8 // esp += 8
0x08048d20 <+38>: lea esi,[edi+eax*1] // esi = edi + eax
0x08048d23 <+41>: push edi
0x08048d24 <+42>: sub ebx,0x2 // ebx -= 2
0x08048d27 <+45>: push ebx
0x08048d28 <+46>: call 0x8048cfa <func4>
0x08048d2d <+51>: add esp,0x10 // esp += 10
0x08048d30 <+54>: add eax,esi // eax += esi
0x08048d32 <+56>: jmp 0x8048d39 <func4+63>
0x08048d34 <+58>: mov eax,0x0 // eax = 0
0x08048d39 <+63>: pop ebx
0x08048d3a <+64>: pop esi
0x08048d3b <+65>: pop edi
0x08048d3c <+66>: ret
To date, I have figured out that it takes ebx, decrements it by one, passes it back to itself and recurses until it hits one of the base cases, then moves on to the next step of the recursion. However, I haven't fully understood what that branch of the recursion does, or what esp is doing in this context.
Any hints as to how to proceed? I have already stepped through it quite a few times with gdb, but have not really noticed any sort of pattern that would help me determine what is happening.
It seems that you don't know that the result is returned in the eax register. With that in mind the code is not difficult to understand. Assuming that the cdecl calling convention is used (because the stack is cleaned up by caller), it is same as this js function:
function func4(a, b)
{
if (a <= 0) return 0;
if (a == 1) return b;
return b + func4(a-1, b) + func4(a-2, b);
}
and is the asm code with comments
func4:
0x08048cfa <+0>: push edi ; save non-volatile registers
0x08048cfb <+1>: push esi
0x08048cfc <+2>: push ebx
0x08048cfd <+3>: mov ebx, [esp+0x10] ; ebx <- a
0x08048d01 <+7>: mov edi, [esp+0x14] ; edi <- b
0x08048d05 <+11>: test ebx, ebx ; if (a <= 0)
0x08048d07 <+13>: jle 0x8048d34 ; return 0
0x08048d09 <+15>: mov eax, edi ; result <- 0
0x08048d0b <+17>: cmp ebx, 0x1 ; if (a == 1)
0x08048d0e <+20>: je 0x8048d39 ; return result;
0x08048d10 <+22>: sub esp, 0x8 ; this is useless
0x08048d13 <+25>: push edi ; passing 2nd arguments
0x08048d14 <+26>: lea eax, [ebx-0x1] ;
0x08048d17 <+29>: push eax ; passing 1st arguments
0x08048d18 <+30>: call 0x8048cfa<func4> ; ax = func4(a - 1, b)
0x08048d1d <+35>: add esp, 0x8 ; clean up the stak after calling
0x08048d20 <+38>: lea esi, [edi+eax*1] ; temp = b + func4(a - 1, b)
0x08048d23 <+41>: push edi ; passing 2nd arguments
0x08048d24 <+42>: sub ebx, 0x2 ;
0x08048d27 <+45>: push ebx ; passing 1st arguments
0x08048d28 <+46>: call 0x8048cfa<func4> ; ax = func4(a - 2, b)
0x08048d2d <+51>: add esp, 0x10 ; clean up the stak and the useless 8 bytes
0x08048d30 <+54>: add eax, esi ; result = func4(a - 2, b) + temp
0x08048d32 <+56>: jmp 0x8048d39 ;
0x08048d34 <+58>: mov eax, 0x0 ; jump to here when a <= 0
0x08048d39 <+63>: pop ebx
0x08048d3a <+64>: pop esi
0x08048d3b <+65>: pop edi
0x08048d3c <+66>: ret
LEA is meant for calculating memory offsets, but it is widely used to doing fused multiplication and addition because it is quick and convenient. Two more advantages are: 1) you can assign the result to a register different from the source registers; 2) it doesn't affect the flags.

nth fibonacci number in NASM using a recursive procedure - [ASSEMBLY]

Here is the code which I used to solve the problem:
%include "io.mac"
section .data
msg1 db "Enter a positive number: ",0
msg2 db "fibonacci number is: ",0
space db " ",0
section .bss
section .text
global _start
_start:
PutStr msg1
GetLInt EBX
mov EDX,EBX
cmp EBX,1
jge result
jmp _start
result:
PutLInt EBX
PutStr space
PutStr msg2
call fibo
PutLInt EAX
nwln
.EXIT
fibo:
cmp EBX,2
jg fibo_helper
mov EAX,1
ret
fibo_helper:
dec EBX
call fibo
mov ECX,EAX
dec EBX
call fibo
ADD EAX,ECX
ret
But this code outputs the right way only for n<5..for the rest it just outputs n-1.
Can someone help me with this?
Your algorithm is recursive, but you are using registers to store intermediate values like local variables in C, thus roughly this happens (writing it from head, use debugger and single step over instructions to verify I got it right):
- fibo(ebx = 5): jumps to fibo_helper, ebx = 4 (--ebx), call fibo(ebx=4)
- fibo(ebx=4): -> helper -> call fibo(ebx=3)
- fibo(ebx=3): -> helper -> call fibo(ebx=2)
- fibo(ebx=2), eax=1, ret
- in helper after first call: ecx=1, --ebx, call fibo(ebx=1)
- fibo(ebx=1), eax=1, ret
- eax = 1 + ecx(1) = 2, ret
- in helper after first call: ecx=2, --ebx, call fibo(ebx=0)
- fibo(ebx=0), eax=1, ret
- eax = 1 + ecx(2) = 3, ret
- in helper after first call: ecx=3, --ebx, call fibo(ebx=-1)
- fibo(ebx=-1), eax=1, ret
- eax = 1 + ecx(3) = 4, ret
The registers are like "super globals", if you want to create recursive algorithm, you must preserve all values you need somewhere (dynamically, most likely on stack), which must survive the recursive call.
Google for some working x86 example (rather exampleS to see how even such simple implementation may differ), there must be ton of this stuff, even here on SO... And check some stack-usage vs recursion tutorial to get better idea how/when to preserve values.
edit: if you are smart enough and you have free hand to design custom calling convention for your recursive function, you may often minimize the stack memory requirements by clever design.
In this case you can for example design the fibo function in such way, that it will ADD value to eax (running sum), take input in ebx = n, which will be preserved (returns unmodified value). So eax will work both as input and output of the function.
Then you will have to first clear eax to zero before call:
... set ebx to "n" ...
xor eax,eax
call fibo
And the recursive function itself will be:
fibo:
cmp ebx,2
jg fibo_helper
inc eax ; sum += 1 (fib(1) = fib(2) = 1)
ret
fibo_helper:
dec ebx
call fibo ; sum += fib(n-1)
dec ebx
call fibo ; sum += fib(n-2)
add ebx,2 ; restore ebx to original value
ret
And the stack memory is then used only to track the call+ret pairs, i.e. recursion depth, no need to use it to preserve values.

Basic assembly in mov function pointers

I want to put a new value into a pointer (in the value that he point of him) but I fail.
The program push to the stack
offset result, num1 and num2
The maximize need to be in result...
Now I need your help
org 100h
jmp main
result dw ?
num0 dw ?
num1 dw ?
main:
mov bp,sp
push (offset result)
push num0
push num1
call max
MOV AX,num0
call print_num
PRINTN
MOV AX,num1
call print_num
PRINTN
MOV AX,result
call print_num
PRINTN
ret
max PROC
push bp
mov bp,sp
MOV AX,[BP+6]
MOV BX,[BP+4]
MOV CX,[BP+2]
CMP AX,BX
JGE BIG
MOV [CX],BX
BIG:
MOV [CX],AX
mov sp,bp
pop bp
ret
max ENDP
include magshimim.inc \\our program built for us defines for the inputs...
I want to do:
MOV [CX] , AX
but the emu8086 doesn't really like me :)
Thanks for your help!
Problems found:
"push (offset result)" seems to store the wrong value because of the parenthesis.
As soon as procedure "max" begins, BP is pushed on stack, so the parameters are no longer in BP+6, +4 and +2, they are in BP+8, +6 and +4.
"[CX]" can't be used as pointer, let's change it by BX.
It is necessary to skip label "BIG" in case CX is greater.
Here is the code with the little fixes :
org 100h
jmp main
result dw ?
num0 dw 5 ;VALUE TO TEST.
num1 dw 2 ;VALUE TO TEST.
main:
mov bp,sp
push offset result ;PARENTHESIS SEEM TO STORE THE WRONG VALUE.
push num0
push num1
call max
MOV AX,num0
call print_num
PRINTN
MOV AX,num1
call print_num
PRINTN
MOV AX,result
call print_num
PRINTN
ret
max PROC
push bp ;"BP" IN STACK. PARAMTERS ARE NO LONGER IN BP+6,+4,+2.
mov bp,sp
MOV BX,[BP+8] ;BX = RESULT'S ADDRESS.
MOV AX,[BP+6] ;AX = NUM0'S VALUE.
MOV CX,[BP+4] ;CX = NUM1'S VALUE.
CMP AX,CX
JGE BIG
MOV [BX],CX
jmp finish ;NECESSARY TO SKIP "BIG".
BIG:
MOV [BX],AX
; mov sp,bp
finish:
pop bp
ret
max ENDP

How to jump between floppy sectors in assembly? - use of NASM call far and retf?

I am new to programming in asm. I am trying to create a floppy that prints a message on the boot sector, jumps to sector 35 and prints the date, then jumps back to the boot sector and prints a prompt. I am having trouble (I think) jumping between the sectors... I had everything printing fine when it was all on the boot sector and I haven't changed the actual printing code. What I am getting currently is the first line of the message and then the date and prompt never print. The code is below; I am using NASM:
For the boot sector:
org 0x7c00 ;load to appropariate MBR location
start:
call cls ;call routine to clear screen
call dspmsg ;call routine to display message
mov ah,02h ;read disk sectors into memory
mov al,1 ;number of sectors to read/write (must be nonzero)
mov ch,1 ;cylinder number (0...79)
mov cl,18 ;sector number (1...18)
mov dh,0 ;head number (0...1)
mov dl,0 ;drive number (0...3, 0 for floppy)
mov bx, 0x1000
mov es,bx
mov bx,0x0000
int 13h
call word 0x1000:0x0000
push cs
pop ds
call dspmsg2
jmp $
%macro dsp 3
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is one
mov bh,0 ;Use video page of zero
mov bl,0AH ;Attribute
mov cx,%1 ;Character string length
mov dh,%2 ;position on row
mov dl,0 ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,%3 ;load the offset address of string into BP
int 10H
%endmacro
cls:
mov ah,06h ;function 06h (Scroll Screen)
mov al,0 ;scroll all lines
mov bh,0AH ;Attribute (light green on black)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10H ;BIOS Interrupt 10h (video services)
ret
msg: db 'OS321, made by CHRISTINE MCGINN (c) 2011'
dspmsg:
dsp 40,0,[msg]
ret
msg2: db '$'
dspmsg2:
;Display a message
dsp 1,2,[msg2]
ret
times 510-($-$$) db 0 ;Pad remainder of boot sector with 0s
dw 0xAA55 ;done setting the MBR
Then on sector 35:
org 0x0000
push cs
pop ds
call date
call cvtmo
call cvtday
call cvtcent
call cvtyear
call time
call cvthrs
call cvtmin
call cvtsec
call dsptimedate
retf
%macro dsp 3
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is one
mov bh,0 ;Use video page of zero
mov bl,0AH ;Attribute
mov cx,%1 ;Character string length
mov dh,%2 ;position on row
mov dl,0 ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,%3 ;load the offset address of string into BP
int 10H
%endmacro
%macro cvt 3
mov bh,%1 ;copy contents of %1 to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmdtfld + %2],bh
mov bh,%1
and bh,0fh
add bh,30h
mov [tmdtfld + %3],bh
%endmacro
date:
;Get date from the system
mov ah,04h ;function 04h (get RTC date)
int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock)
ret
;CH - Century
;CL - Year
;DH - Month
;DL - Day
cvtmo:
;Converts the system date from BCD to ASCII
cvt dh,9,10
ret
cvtday:
cvt dl,12,13
ret
cvtcent:
cvt ch,15,16
ret
cvtyear:
cvt cl,17,18
ret
time:
;Get time from the system
mov ah,02h
int 1Ah
ret
;CH - Hours
;CL - Minutes
;DH - Seconds
cvthrs:
;Converts the system time from BCD to ASCII
cvt ch,0,1
ret
cvtmin:
cvt cl,3,4
ret
cvtsec:
cvt dh,6,7
ret
tmdtfld: db '00:00:00 00/00/0000'
dsptimedate:
;Display the system time
dsp 19,1,[tmdtfld]
ret
times 512-($-$$) db 0 ;Pad remainder of sector with 0s
Thank you for any help you can offer!
You've pose the question in a confusing way. You seem to have two problems:
1) Reading arbitrary sectors from the floppy
2) Having programs in each sector that do something (e.g, print a string)
I'd organize my program as a floppy driver ("call floppy_read_sector(x)") [which might
use the bios to do most of the dirty work, but that's an implementation detail),
and as as set of seperate position-independent code blocks that did the various tasks
as subroutines.
Your boot sector code should contain the floppy driver and the high level logic
to read sector(n), call the subroutine in the buffer you read the sector into,
and then do the next sector. (You don't have a lot of room so I don't know
if you can squeeze all this into the boot sector. Welcome to assembly language
programming where counting bytes is important).
Then you have to organize the construction of the floppy disk somehow.
Usually in a world in which one creates bootable floppies, you are allowed to build
much more complicated programs to fill them up. Exercise left to the reader.

Resources