Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

baremetal build with standard libraries #87

Open
mMerlin opened this issue Oct 17, 2015 · 2 comments
Open

baremetal build with standard libraries #87

mMerlin opened this issue Oct 17, 2015 · 2 comments

Comments

@mMerlin
Copy link

mMerlin commented Oct 17, 2015

Can someone help me out please! I am out of my previous areas here, and do not know the right question to ask, or the right place to ask it. What I currently want, is to create a program that will run standalone (no OS) on a A20-OLinuXino-Micro-4GB board, that needs to use (at least) some standard math libraries. Eventually, I will want to load it into NAND, and run it on powerup, but for now I am trying to manually load it (loady) from the U-Boot serial 'console', after booting from an SD card. Standalone is needed, because the linux distro level access to the hardware GPIO ports seems not very flexible, when working with more than one bit at a time, and quite slow. Too slow for the target application, and I did not really want to try modifying / adding a kernal module just to see if that would be fast enough.

I have been able to create bootable U-Boot images on SD cards from the repo, either building directly from the linux-sunxi distro that was supplied with the board, or by cross-compiling from a Fedora 21 machine. Same for the standalone hello_world program that came in the examples for U-boot, which can be loaded and run from the U-Boot console. My current testing does not use any math library. Just stdio and printf, to try to get the build process right.

Starting from, and simplifying, the hello_world standalone example and Makefile provided with the U-Boot sources, I created a minimal program, and a script to use fairly minimal build options, that still runs successfully when loaded from U-Boot.

I created a standard hello_world program, plus a script to use as similar as possible options to the the U-Boot standalone example, while still being able to execute it normally from a linux shell.

I then tried to adjusted the build options to replicate the result from the initial standalone example program. That is, being able to load and run it from the U-Boot 'console'. So far without success. With the latest test, executing the program from the console fails with:

software interrupt
pc : [<48000008>]          lr : [<48000008>]
sp : 7fb66da8  ip : 00000000     fp : 00000000
r10: 00000002  r9 : 7fb66f0c     r8 : 7fb67778
r7 : 7ffbbaf8  r6 : 00000001     r5 : 7fb6777c  r4 : 48000000
r3 : 00000000  r2 : 7fb6777c     r1 : 7fb6777c  r0 : 00000001
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...

Since the start point is (supposed to be) 0x48000000, that is right at the beginning.

For all cases, the procedure in the U-Boot console is:

loady
go 0x48000000

One of the current differences in the build paths, is the U-Boot environment is built with soft floating point. Changing to hard there fails because the needed libstubs.o is currently built with soft. Trying to build the standard program with soft in the linux environment complains about mismatch as well. Something to look at later.

Am I missing something obvious that is typically needed to build freestanding programs that are to run without and OS? Is it something that is specific to the ARM processor or board being used? Do I need to include something extra in the program to reference (again) something from the U-Boot code tree?

standalone hello_world.c for U-Boot environment

/*
 * Simple hello_world program to check creation of freestanding program to be run
 * standalone (without OS) from u-boot
 *
 * variant to check how the u-boot standalone programs are built
 */

#include <common.h>

int main (void)
{
    printf ("Hello World\n");
    return (0);
}

freestanding hello_world.c for sunxi environment

/*
 * Simple hello_world program to check creation of freestanding program to be run
 * standalone (without OS) from u-boot
 */

#include <stdio.h>

int main (void)
{
    printf ("Hello World\n");
    return (0);
}

build script for U-Boot environment

#! /bin/bash
HW="hello_world"

#clean
rm -f $HW $HW.o $HW.d $HW.s $HW.i $HW.su $HW.bin

FLOATA="soft"
INCLS="-I/home/olimex/u-boot-sunxi/include \
    -I/home/olimex/u-boot-sunxi/arch/arm/include"
OBJS="$HW.o \
    /home/olimex/u-boot-sunxi/examples/standalone/libstubs.o"
EGRP=
LPATHS=
LIBS=

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c $CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS \
    $HW.c -o $HW.o
echo

#link
ld.bfd -static $LNKOPTS $OBJS $LPATHS -o $HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary $HW $HW.bin

base build script for sunxi environment

#! /bin/bash
HW="hello_world"

#clean
rm -f $HW $HW.o $HW.d $HW.s $HW.i $HW.su $HW.bin

FLOATA="hard"
INCLS=
OBJS="/usr/lib/arm-linux-gnueabihf/crt1.o \
    /usr/lib/arm-linux-gnueabihf/crti.o \
    /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtbeginT.o \
    $HW.o"
EGRP="--end-group \
    /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtend.o \
    /usr/lib/arm-linux-gnueabihf/crtn.o"
LPATHS="-L/usr/lib/gcc/arm-linux-gnueabihf/4.6 \
    -L/usr/lib/arm-linux-gnueabihf \
    -L/usr/lib \
    -L/lib/arm-linux-gnueabihf \
    -L/usr/lib/arm-linux-gnueabihf"
LIBS="--start-group -lgcc -lgcc_eh -lc"

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c $CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS \
    $HW.c -o $HW.o
echo

#link
ld.bfd -static $LNKOPTS $OBJS $LPATHS -o $HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary $HW $HW.bin

current modified build script for sunxi, to run from U-Boot console

#! /bin/bash
HW="hello_world"

#clean
rm -f $HW $HW.o $HW.d $HW.s $HW.i $HW.su $HW.bin

FLOATA="hard"
INCLS=
OBJS="$HW.o"
EGRP=
LPATHS="-L/usr/lib/gcc/arm-linux-gnueabihf/4.6 \
    -L/usr/lib/arm-linux-gnueabihf \
    -L/usr/lib \
    -L/lib/arm-linux-gnueabihf \
    -L/usr/lib/arm-linux-gnueabihf"
LIBS="--start-group -lgcc -lgcc_eh -lc"

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c $CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS \
    $HW.c -o $HW.o
echo

#link
ld.bfd -static $LNKOPTS $OBJS $LPATHS -o $HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary $HW $HW.bin

output from script for the U-Boot environment

+ gcc -c -marm -mfloat-abi=soft -ffreestanding -D__KERNEL__ -I/home/olimex/u-boot-sunxi/include -I/home/olimex/u-boot-sunxi/arch/arm/include hello_world.c -o hello_world.o
+ echo
+ ld.bfd -static -Ttext 0x48000000 hello_world.o /home/olimex/u-boot-sunxi/examples/standalone/libstubs.o -o hello_world
ld.bfd: warning: cannot find entry symbol _start; defaulting to 48000000
+ echo
+ objcopy -O binary hello_world hello_world.bin

output from base script for the U-Boot environment

+ gcc -c -marm -mfloat-abi=hard -ffreestanding -D__KERNEL__ hello_world.c -o hello_world.o
+ echo
+ ld.bfd -static -Ttext 0x48000000 /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtbeginT.o hello_world.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.6 -L/usr/lib/arm-linux-gnueabihf -L/usr/lib -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf -o hello_world --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtend.o /usr/lib/arm-linux-gnueabihf/crtn.o
+ echo
+ objcopy -O binary hello_world hello_world.bin

output from modified script for the U-Boot environment

+ gcc -c -marm -mfloat-abi=hard -ffreestanding -D__KERNEL__ hello_world.c -o hello_world.o
+ echo
+ ld.bfd -static -Ttext 0x48000000 hello_world.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.6 -L/usr/lib/arm-linux-gnueabihf -L/usr/lib -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf -o hello_world --start-group -lgcc -lgcc_eh -lc
ld.bfd: warning: cannot find entry symbol _start; defaulting to 48000000
+ echo
+ objcopy -O binary hello_world hello_world.bin

the compiler defaults: gcc -v

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.6/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.3-14' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.6.3 (Debian 4.6.3-14)
@oliv3r
Copy link
Member

oliv3r commented Oct 19, 2015

Hey Phil,

just a quick note, how fast do you want the pins to toggle? I think I
once read somewhere that 300kHz is pretty much the max, though take that
with a big grain of salt ;)

On 17-10-15 03:41, Phil Duby wrote:

Can someone help me out please! I am out of my previous areas here,
and do not know the right question to ask, or the right place to ask
it. What I currently want, is to create a program that will run
standalone (no OS) on a A20-OLinuXino-Micro-4GB
https://www.olimex.com/Products/OLinuXino/A20/A20-OLinuXino-MICRO-4GB/
board, that needs to use (at least) some standard math libraries.
Eventually, I will want to load it into NAND, and run it on powerup,
but for now I am trying to manually load it (loady) from the U-Boot
https://github.com/linux-sunxi/u-boot-sunxi/wiki serial 'console',
after booting from an SD card. Standalone is needed, because the linux
distro level access to the hardware GPIO ports seems not very
flexible, when working with more than one bit at a time, and quite
slow. Too slow for the target application, and I did not really want
to try modifying / adding a kernal module just to see if that would be
fast enough.

I have been able to create bootable U-Boot images on SD cards from the
repo, either building directly from the linux-sunxi
http://linux-sunxi.org/Main_Page distro that was supplied with the
board, or by cross-compiling from a Fedora 21 machine. Same for the
standalone hello_world program that came in the examples for U-boot,
which can be loaded and run from the U-Boot console. My current
testing does not use any math library. Just stdio and printf, to try
to get the build process right.

Starting from, and simplifying, the hello_world standalone example and
Makefile provided with the U-Boot sources, I created a minimal
program, and a script to use fairly minimal build options, that still
runs successfully when loaded from U-Boot.

I created a standard hello_world program, plus a script to use as
similar as possible options to the the U-Boot standalone example,
while still being able to execute it normally from a linux shell.

I then tried to adjusted the build options to replicate the result
from the initial standalone example program. That is, being able to
load and run it from the U-Boot 'console'. So far without success.
With the latest test, executing the program from the console fails with:

|software interrupt
pc : [<48000008>] lr : [<48000008>]
sp : 7fb66da8 ip : 00000000 fp : 00000000
r10: 00000002 r9 : 7fb66f0c r8 : 7fb67778
r7 : 7ffbbaf8 r6 : 00000001 r5 : 7fb6777c r4 : 48000000
r3 : 00000000 r2 : 7fb6777c r1 : 7fb6777c r0 : 00000001
Flags: nZCv IRQs off FIQs off Mode SVC_32
Resetting CPU ...
|

Since the start point is (supposed to be) 0x48000000, that is right at
the beginning.

For all cases, the procedure in the U-Boot console is:

|loady
go 0x48000000
|

One of the current differences in the build paths, is the U-Boot
environment is built with soft floating point. Changing to hard there
fails because the needed libstubs.o is currently built with soft.
Trying to build the standard program with soft in the linux
environment complains about mismatch as well. Something to look at later.

Am I missing something obvious that is typically needed to build
freestanding programs that are to run without and OS? Is it something
that is specific to the ARM processor or board being used? Do I need
to include something extra in the program to reference (again)
something from the U-Boot code tree?

  standalone hello_world.c for U-Boot environment

/*

  • Simple hello_world program to check creation of freestanding program to be run
  • standalone (without OS) from u-boot
    *
  • variant to check how the u-boot standalone programs are built
    */

#include <common.h>

int main (void)
{
printf ("Hello World\n");
return (0);
}

  freestanding hello_world.c for sunxi environment

/*

  • Simple hello_world program to check creation of freestanding program to be run
  • standalone (without OS) from u-boot
    */

#include <stdio.h>

int main (void)
{
printf ("Hello World\n");
return (0);
}

  build script for U-Boot environment

#! /bin/bash
HW="hello_world"

#clean
rm -f$HW $HW.o$HW.d$HW.s$HW.i$HW.su$HW.bin

FLOATA="soft"
INCLS="-I/home/olimex/u-boot-sunxi/include
-I/home/olimex/u-boot-sunxi/arch/arm/include"
OBJS="$HW.o
/home/olimex/u-boot-sunxi/examples/standalone/libstubs.o"
EGRP=
LPATHS=
LIBS=

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c$CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS
$HW.c -o$HW.o
echo

#link
ld.bfd -static$LNKOPTS $OBJS $LPATHS -o$HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary$HW $HW.bin

  base build script for sunxi environment

#! /bin/bash
HW="hello_world"

#clean
rm -f$HW $HW.o$HW.d$HW.s$HW.i$HW.su$HW.bin

FLOATA="hard"
INCLS=
OBJS="/usr/lib/arm-linux-gnueabihf/crt1.o
/usr/lib/arm-linux-gnueabihf/crti.o
/usr/lib/gcc/arm-linux-gnueabihf/4.6/crtbeginT.o
$HW.o"
EGRP="--end-group
/usr/lib/gcc/arm-linux-gnueabihf/4.6/crtend.o
/usr/lib/arm-linux-gnueabihf/crtn.o"
LPATHS="-L/usr/lib/gcc/arm-linux-gnueabihf/4.6
-L/usr/lib/arm-linux-gnueabihf
-L/usr/lib
-L/lib/arm-linux-gnueabihf
-L/usr/lib/arm-linux-gnueabihf"
LIBS="--start-group -lgcc -lgcc_eh -lc"

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c$CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS
$HW.c -o$HW.o
echo

#link
ld.bfd -static$LNKOPTS $OBJS $LPATHS -o$HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary$HW $HW.bin

  current modified build script for sunxi, to run from U-Boot console

#! /bin/bash
HW="hello_world"

#clean
rm -f$HW $HW.o$HW.d$HW.s$HW.i$HW.su$HW.bin

FLOATA="hard"
INCLS=
OBJS="$HW.o"
EGRP=
LPATHS="-L/usr/lib/gcc/arm-linux-gnueabihf/4.6
-L/usr/lib/arm-linux-gnueabihf
-L/usr/lib
-L/lib/arm-linux-gnueabihf
-L/usr/lib/arm-linux-gnueabihf"
LIBS="--start-group -lgcc -lgcc_eh -lc"

LNKOPTS="-Ttext 0x48000000"
WARNINGS=
MACH="-marm -mfloat-abi=$FLOATA"
DIAG=
EMBD="-ffreestanding"
DEFS="-D__KERNEL__"
CMPOPTS=

set -x

#compile
gcc -c$CMPOPTS $MACH $EMBD $DIAG $WARNINGS $DEFS $INCLS
$HW.c -o$HW.o
echo

#link
ld.bfd -static$LNKOPTS $OBJS $LPATHS -o$HW $LIBS $EGRP
echo

#loadable binary
objcopy -O binary$HW $HW.bin

  output from script for the U-Boot environment

|+ gcc -c -marm -mfloat-abi=soft -ffreestanding -D__KERNEL__ -I/home/olimex/u-boot-sunxi/include -I/home/olimex/u-boot-sunxi/arch/arm/include hello_world.c -o hello_world.o

  • echo

  • ld.bfd -static -Ttext 0x48000000 hello_world.o /home/olimex/u-boot-sunxi/examples/standalone/libstubs.o -o hello_world
    ld.bfd: warning: cannot find entry symbol _start; defaulting to 48000000

  • echo

  • objcopy -O binary hello_world hello_world.bin
    |

    output from base script for the U-Boot environment

|+ gcc -c -marm -mfloat-abi=hard -ffreestanding -D__KERNEL__ hello_world.c -o hello_world.o

  • echo

  • ld.bfd -static -Ttext 0x48000000 /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtbeginT.o hello_world.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.6 -L/usr/lib/arm-linux-gnueabihf -L/usr/lib -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf -o hello_world --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/arm-linux-gnueabihf/4.6/crtend.o /usr/lib/arm-linux-gnueabihf/crtn.o

  • echo

  • objcopy -O binary hello_world hello_world.bin
    |

    output from modified script for the U-Boot environment

|+ gcc -c -marm -mfloat-abi=hard -ffreestanding -D__KERNEL__ hello_world.c -o hello_world.o

  • echo

  • ld.bfd -static -Ttext 0x48000000 hello_world.o -L/usr/lib/gcc/arm-linux-gnueabihf/4.6 -L/usr/lib/arm-linux-gnueabihf -L/usr/lib -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf -o hello_world --start-group -lgcc -lgcc_eh -lc
    ld.bfd: warning: cannot find entry symbol _start; defaulting to 48000000

  • echo

  • objcopy -O binary hello_world hello_world.bin
    |

    the compiler defaults: gcc -v

|Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.6/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.3-14' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.6.3 (Debian 4.6.3-14)
|


Reply to this email directly or view it on GitHub
#87.

Met vriendelijke groeten, Kind regards, 与亲切的问候

Olliver Schinagl
Software Engineer
Research & Development
Ultimaker B.V.

@mMerlin
Copy link
Author

mMerlin commented Oct 19, 2015

I think that speed is talking to the ports through the linux interface. I found another reference that said you could get 4 MHz through bare metal. In my testing, I actually got double that. I expect that is because the context was for toggling a single pin (port in a port group), which requires a read, mask, write sequence. For my case, I can write every pin in the group in a single operation. Since it appears that (at the raw hardware level, every read/write memory access to the I/O port location requires (eyeballing on the scope) 62.5 ns, that extra read cuts the maximum toggle rate by half.

For my application, I need to get the overall cycle time in the 100KHz range, which includes control of pins on multiple ports, plus some reasonably intensive math. I've got the hardware pin control setup, actually limited by the access speed of an attached ADC. Now I need to get the math part to work along with that.

For the original query, I am slowly learning more. I found the hidden .{xxxx}.cmd files in …/examples/standalone, so I can recreate libstubs with different options (hardware floating point), but I do not understand what libstubs is doing to facilitate a minimal hello world building to (depending on optimization flags) a 316 byte .bin, while a normal hello world, compile/linked as freestanding and static is over 400K. I have to assume that libstubs is providing accessing to internals of U-Boot, but I have not seen how that works. continuing forward (and sideways).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants