Function sinf from libm doesn't return on ARM QEMU machine

336 views Asked by At

I'm trying to run following code on ARM machine emulated with QEMU.

#include "math.h"

// Newlib doesn't implement this function.
void _exit(int status) {
    while (1);
}

int main() {
  float a = 1.25;

  float b = sinf(a);
  return 0;
}

Used toolchain:

$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.8.3 20131129 (release) [ARM/embedded-4_8-branch revision 205641]
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Code is compiled with:

arm-none-eabi-gcc -g -o math.elf math.c -lm

QEMU machine is started as:

$ qemu-system-arm -M realview-pbx-a9 -cpu cortex-a9 -kernel math.elf -nographic -serial /dev/null -s -S

GDB session looks like:

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00008104 in _start ()
(gdb) set $pc = 0x822c
(gdb) break *0x8240
Breakpoint 1 at 0x8240: file math.c, line 10.
(gdb) break *0x824c
Breakpoint 2 at 0x824c: file math.c, line 11.
(gdb) c
Continuing.

Breakpoint 1, main () at math.c:10
10    float b = sinf(a);
(gdb) c
Continuing.

Breakpoint 2 is set at the last line (return 0). As it can be seen from GDB session log the second breakpoint is never reached. Computing is just stuck inside sinf function. Any idea why?

I was experimenting with similar code written directly in ARM assembly and the result was the same.

2

There are 2 answers

0
mapod On BEST ANSWER

SP register was not initialized. Here is a working example in ARM assembly:

        .text
entry:  b start           
fval:   .single 0e1.25
        .align

start:  mov sp, #0x80000
        ldr r0, fval
        bl sinf 
stop:   b stop

Result is in R0 register.

0
mapod On

It looks like I misused gdb. I also tested the code on ARM-v6 machine:

$ qemu-system-arm -M versatilepb -cpu arm1176 -kernel math.elf -nographic -serial /dev/null -s -S
QEMU 1.7.50 monitor - type 'help' for more information
(qemu) audio: Could not init `oss' audio driver

and following gdb session returns correct result:

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00008104 in _start ()
(gdb) n
Single stepping until exit from function _start,
which has no line number information.
0x00009dec in memset ()
(gdb) set $pc = 0x822c
(gdb) n
8     float a = 1.25;
(gdb) n
10    float b = sinf(a);
(gdb) n
11    return 0;
(gdb) p/f $r0
$1 = 0.948984623
(gdb) 

Difference in this case is that initialization function is executed first, and then it is jumped to main function. In other words, scott is on the right path, some register initialization is needed. I'm just not sure that it is VFP instruction issue, because I got correct result on ARM-v6 machine. Of course, it works now on ARM-v7 as well.

It looks like I need to learn a little bit more about ARM assembly to find out necessary register initialization parameters.