Fatal error when calling ARM assembly function from C

0

I'm trying to implement an example from a book of calling an assembly function from C. But I keep getting a fatal error where the PC = fffffffe and therefore executing code outside of RAM or ROM.

Here is my C file, t.c:

int g;      // uninitialized global
int main()
{
    int a, b, c, d, e, f;       // local variables
    a = b = c = d = e = f = 1;  // values do not matter
    g = sum(a,b,c,d,e,f);       // call sum(), passing a,b,c,d,e,f
}

My assembly file, ts.s:

    .global start, sum
start:  ldr sp, =stack_top
        bl main         // call main() in c
stop:   b stop

sum:    // int sum(int a,b,c,d,e,f) { return a+b+c+d+e+f; }
        // upon entry, stack top contains e, f, passed by main() in C
// Establish stack frame
stmfd sp!, {fp, lr}     // push fp, lr
add   fp, sp, #4        // fp -> saved lr on stack

// Compute sum of all (6) parameters
add r0, r0, r1      // first 4 parameters are in r0-r1
add r0, r0, r2
add r0, r0, r3
ldr r3, [fp, #4]    // load e into r3
add r0, r0, r3      // add to sum in r0
ldr r3, [fp, #8]    // load f into r3
add r0, r0, r3      // add to sum in r0

// Return to caller
sub sp, fp, #4      // sp=fp-4 (point at saved FP)
ldmfd sp!, {fp, pc} // return to caller

Here is the linker script, t.ld:

ENTRY(start)        /* define start as the entry address */
SECTIONS        /* program sections */
{
    . = 0x10000;    /* loading address, required by QEMU */
    .text : { *(.text) }    /* all text in .text section */
    .data : { *(.data) }    /* all data in .data section */
    .bss  : { *(.bss)  }    /* all bss in .bss section */
    . =ALIGN(8);
     . =. + 0x1000;     /* 4 KB stack space */
    stack_top =.;   /* stack_top is a symbol exported by linker */
}

I assemble the files using the following:

arm-none-eabi-as -o ts.o ts.s
arm-none-eabi-gcc -c t.c
arm-none-eabi-ld -T t.ld -o t.elf t.o ts.o
arm-none-eabi-objcopy -O binary t.elf t.bin

Then execute with:

qemu-system-arm -M versatilepb -kernel t.bin -nographic -serial /dev/null

Here is the output:

QEMU 2.5.0 monitor - type 'help' for more information
(qemu) pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
qemu: fatal: Trying to execute code outside RAM or ROM at 0xfffffffe

R00=fffffffc R01=ffffffff R02=00000000 R03=ffffffff
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=ffffffff
R12=00000000 R13=42fffff0 R14=00010060 R15=fffffffe
PSR=400001f3 -Z-- T svc32
s00=00000000 s01=00000000 d00=0000000000000000
s02=00000000 s03=00000000 d01=0000000000000000
s04=00000000 s05=00000000 d02=0000000000000000
s06=00000000 s07=00000000 d03=0000000000000000
s08=00000000 s09=00000000 d04=0000000000000000
s10=00000000 s11=00000000 d05=0000000000000000
s12=00000000 s13=00000000 d06=0000000000000000
s14=00000000 s15=00000000 d07=0000000000000000
s16=00000000 s17=00000000 d08=0000000000000000
s18=00000000 s19=00000000 d09=0000000000000000
s20=00000000 s21=00000000 d10=0000000000000000
s22=00000000 s23=00000000 d11=0000000000000000
s24=00000000 s25=00000000 d12=0000000000000000
s26=00000000 s27=00000000 d13=0000000000000000
s28=00000000 s29=00000000 d14=0000000000000000
s30=00000000 s31=00000000 d15=0000000000000000
FPSCR: 00000000
Aborted (core dumped)

I am new to ARM assembly, so I'm not sure how the PC gets all the way to fffffffe. Any help would be appreciated, thank you!


So I've simplified both the C and asm file but still keep getting a fatal error.

Here is the updated C file:

int g;      // uninitialized global
int main()
{
    g = sum();
}

The ASM file:

    .global start, sum
start:  ldr sp, =stack_top
        bl main             // call main() in c
stop:   b stop

sum:
        push {lr}
        pop  {pc}

The linking script is the same as before. I still get the following error:

QEMU 2.5.0 monitor - type 'help' for more information
(qemu) pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
qemu: fatal: Trying to execute code outside RAM or ROM at 0xfffffffe

R00=00000000 R01=00000183 R02=00000100 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=43000004
R12=00000000 R13=43000000 R14=0001000c R15=fffffffe
PSR=400001f3 -Z-- T svc32
s00=00000000 s01=00000000 d00=0000000000000000
s02=00000000 s03=00000000 d01=0000000000000000
s04=00000000 s05=00000000 d02=0000000000000000
s06=00000000 s07=00000000 d03=0000000000000000
s08=00000000 s09=00000000 d04=0000000000000000
s10=00000000 s11=00000000 d05=0000000000000000
s12=00000000 s13=00000000 d06=0000000000000000
s14=00000000 s15=00000000 d07=0000000000000000
s16=00000000 s17=00000000 d08=0000000000000000
s18=00000000 s19=00000000 d09=0000000000000000
s20=00000000 s21=00000000 d10=0000000000000000
s22=00000000 s23=00000000 d11=0000000000000000
s24=00000000 s25=00000000 d12=0000000000000000
s26=00000000 s27=00000000 d13=0000000000000000
s28=00000000 s29=00000000 d14=0000000000000000
s30=00000000 s31=00000000 d15=0000000000000000
FPSCR: 00000000
Aborted (core dumped)

It has something to do with PUSH and POP. Replacing those two with MOV PC,LR the program runs and get no error.

c
assembly
arm
qemu
asked on Stack Overflow May 13, 2017 by Marco Lugo • edited May 14, 2017 by Marco Lugo

1 Answer

-1

strap.s

.globl _start
_start:
    mov sp,#0x10000
    bl main
hang:
    b hang


.globl sum
sum:
    stmfd sp!, {fp, lr}     // push fp, lr
    add   fp, sp, #4        // fp -> saved lr on stack

    // Compute sum of all (6) parameters
    add r0, r0, r1      // first 4 parameters are in r0-r1
    add r0, r0, r2
    add r0, r0, r3
    ldr r3, [fp, #4]    // load e into r3
    add r0, r0, r3      // add to sum in r0
    ldr r3, [fp, #8]    // load f into r3
    add r0, r0, r3      // add to sum in r0

    // Return to caller
    sub sp, fp, #4      // sp=fp-4 (point at saved FP)
    ldmfd sp!, {fp, pc} // return to caller

notmain.c

int sum ( int, int, int, int, int, int );

int g;      // uninitialized global
int main()
{
    int a, b, c, d, e, f;       // local variables
    a = b = c = d = e = f = 1;  // values do not matter
    g = sum(a,b,c,d,e,f);       // call sum(), passing a,b,c,d,e,f
}


/* memmap */
MEMORY
{
    ram  : ORIGIN = 0x00010000, LENGTH = 32K
}

SECTIONS
{
   .text : { *(.text*) } > ram
   .bss  : { *(.text*) } > ram
}


arm-linux-gnueabi-as --warn --fatal-warnings -march=armv5t strap.s -o strap.o
arm-linux-gnueabi-gcc -c -Wall -O2 -nostdlib -nostartfiles -ffreestanding -march=armv5t notmain.c -o notmain.o
notmain.c: In function ‘main’:
notmain.c:11:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
arm-linux-gnueabi-ld strap.o notmain.o -T memmap -o notmain.elf
arm-linux-gnueabi-objdump -D notmain.elf > notmain.list
arm-linux-gnueabi-objcopy notmain.elf -O binary notmain.bin



00010000 <_start>:
   10000:   e3a0d801    mov sp, #65536  ; 0x10000
   10004:   eb00000b    bl  10038 <main>

00010008 <hang>:
   10008:   eafffffe    b   10008 <hang>

0001000c <sum>:
   1000c:   e92d4800    push    {fp, lr}
   10010:   e28db004    add fp, sp, #4
   10014:   e0800001    add r0, r0, r1
   10018:   e0800002    add r0, r0, r2
   1001c:   e0800003    add r0, r0, r3
   10020:   e59b3004    ldr r3, [fp, #4]
   10024:   e0800003    add r0, r0, r3
   10028:   e59b3008    ldr r3, [fp, #8]
   1002c:   e0800003    add r0, r0, r3
   10030:   e24bd004    sub sp, fp, #4
   10034:   e8bd8800    pop {fp, pc}

00010038 <main>:
   10038:   e3a03001    mov r3, #1
   1003c:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
   10040:   e24dd00c    sub sp, sp, #12
   10044:   e1a02003    mov r2, r3
   10048:   e58d3004    str r3, [sp, #4]
   1004c:   e58d3000    str r3, [sp]
   10050:   e1a01003    mov r1, r3
   10054:   e1a00003    mov r0, r3
   10058:   ebffffeb    bl  1000c <sum>
   1005c:   e59f200c    ldr r2, [pc, #12]   ; 10070 <main+0x38>
   10060:   e5820000    str r0, [r2]
   10064:   e1a00003    mov r0, r3
   10068:   e28dd00c    add sp, sp, #12
   1006c:   e49df004    pop {pc}        ; (ldr pc, [sp], #4)
   10070:   00010074    andeq   r0, r1, r4, ror r0

Disassembly of section .bss:

00010074 <g>:
   10074:   00000000    andeq   r0, r0, r0

run it. ctrl-a then x to exit

qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.bin
pulseaudio: pa_context_connect() failed
pulseaudio: Reason: Connection refused
pulseaudio: Failed to initialize PA contextaudio: Could not init `pa' audio driver
QEMU: Terminated

no faults.

arm-none-eabi-as --warn --fatal-warnings -march=armv5t strap.s -o strap.o
arm-none-eabi-gcc -c -Wall -O2 -nostdlib -nostartfiles -ffreestanding -march=armv5t notmain.c -o notmain.o
notmain.c: In function ‘main’:
notmain.c:11:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
arm-none-eabi-ld strap.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf -O binary notmain.bin

again no faults.

What are the missing parts to your example that you didnt provide?

you can simplify your assembly a little bit if you care to, I can understand why to use the stack frame if you feel the need.

.globl sum
sum:
    push {r3,lr}

    add r0, r0, r1      
    add r0, r0, r2      
    add r0, r0, r3      
    ldr r3, [fp, #0x08]    
    add r0, r0, r3      
    ldr r3, [fp, #0x0C]    
    add r0, r0, r3      

    pop {r3,pc}
answered on Stack Overflow May 13, 2017 by old_timer

User contributions licensed under CC BY-SA 3.0