4

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

gst
  • 1,251
  • 1
  • 14
  • 32
  • I have no idea what your mistake is but +1 for the things you have already tried. – rekire Mar 21 '13 at 08:17
  • @rekire is it some kind of sarcasm or an appreciation? – gst Mar 21 '13 at 08:19
  • 1
    An appreciation: IMHO it is uncommon that new users do its *homework* in a such good way. – rekire Mar 21 '13 at 08:22
  • According to [this forum post](http://www.keil.com/forum/14555/) you can get the PC where the exception occurred using this in the hard fault exception handler: `MRS R0,PSP` / `LDR R1,[R0,#24]`. Once you know which instruction is causing the hard fault it should be easier to figure out why. – Michael Mar 21 '13 at 08:39
  • @Michael thanks for the suggestion. The hard fault is caused due to the value pushed in link register during the switch from 1. first switch from assembly to C--- bl Exponentiate (lr=0x27B) 2. second switch from C to assembly--- result=Exponentiatecore(m,n); (lr=0xfffffff9) I understand that I am corrupting the return value, but then how do I save the lr value in first switch?? – gst Mar 21 '13 at 11:44
  • @ Michael, I am not changing the SP here (no PSP). Did you mean MRS R0,MSP/ LDR R1,[R0,#0]. ?? – gst Mar 21 '13 at 14:00

2 Answers2

3

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
BitBank
  • 8,500
  • 3
  • 28
  • 46
  • " your SUB instruction is not setting the flags". It's been a while since I last read the ARM docs, but since this is Thumb code I'm pretty sure that the arithmetic ops always behave as if they had an `S` suffix. – Michael Mar 21 '13 at 16:38
  • I usually don't use Thumb, so that makes sense. The Cortex M3 supports Thumb-2 which looks more like ARM instructions. The original crash is probably from changing R4 and R9 without preserving them. – BitBank Mar 21 '13 at 16:57
  • just a small representation of what I am doing....#1 C--> assembly(start routine)--->#2 C function(Exponentiate)---> #3 assembly (Exponentiatecore()).... i am still unable to rectify the stack corruption error. Thanks in advance – gst Mar 21 '13 at 18:28
  • Thanks a lot BitBank. i have implemented the changes as per your suggestions.It works partly #1 But I am calling the Start from main.c file so a switch to assembly and hence i save the lr value.. #2 Branch with link to Exponentiate(int *,int *) function from assembly and hence one more switch.#3 now again branch to Exponentiatecore(m,n) from C to assembly. After the execution of 3rd step, the hardfault still occurs. By Michael's suggestion I found the faulting instruction is this line result=Exponentiatecore(m,n); ..after the execution of this line the stack pointer is getting corrupted. – gst Mar 21 '13 at 18:34
  • @BitBank the start() routine is right there in the top of assembly file. from start the C Exponentiate() function is called. One more thing the program works fine when the third branch(exponentiatecore) is omitted.in this case there is no hardfault. "result= Exponentiatecore(m,n)" is where the problem resides. :( :( – gst Mar 21 '13 at 18:37
  • Is it necessary to use Thumb mode? ARM instructions are easier to work with. – BitBank Mar 21 '13 at 18:58
  • I agree with you BitBank but cortex m3 uses thumb2 instructions, and hence am forced to use it – gst Mar 21 '13 at 19:05
  • @VenkateshKuppan so what's your current code that doesn't work? I assume there must be some, that's not scribbling over the callee saved registers. Btw. also read http://stackoverflow.com/questions/261419/arm-to-c-calling-convention-registers-to-save it should explain #4 problem mentioned by BitBank. – domen Apr 16 '13 at 10:31
  • @domen the return value is getting corrupted. result=Exponentiatecore(m,n)--- this is the place where I encounter a hard fault error. – gst Apr 16 '13 at 16:47
1

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

cosinus0
  • 601
  • 1
  • 4
  • 15