在裸机金属程序中使用库

时间:2015-10-23 20:12:22

标签: c gcc arm static-libraries bare-metal

请有人帮帮我!我不知道答案是否一般,或者特定于我正在使用的电路板和软件版本。我离开了以前的区域,甚至不知道要问的正确问题。

在底部添加了编辑

我目前想要的是创建一个程序,它将在A20-OLinuXino-Micro-4GB板上运行独立(裸机;无操作系统),需要使用(至少)一些标准的数学库调用。最后,我想将它加载到NAND中,然后在上电时运行它,但是现在我试图从U-Boot手动加载它(loady)(github.com/linux-sunxi/u-boot-sunxi/ wiki)串口'控制台',从SD卡启动后。需要独立,因为一次使用多个位(端口组中的端口)时,Linux发行版级别对硬件GPIO端口的访问不是很灵活,而且非常慢。目标应用程序太慢了,我真的不想尝试修改/添加内核模块,只是为了看看它是否足够快。

是否需要一些标准的gcc / ld标志来创建裸机独立程序,并包含一些库例程?超越-ereestanding和-static?是否需要一些特殊的胶水代码?还有其他一些我甚至都没有想过的东西吗?

如果找到并查看Beagleboard裸机编程(stackoverflow.com/questions/6870712/beagleboard-bare-metal-programming)。答案有很好的信息,但是汇编程序,并没有引用任何库。 Application hangs when calling printf to uart with bare metal raspberry pi可能会显示问题的原因。 (当前)底部答案指出了VFP的问题,我已经遇到了软/硬浮点选项的问题。这显示了一些汇编程序代码,但我遗漏了有关如何添加包装器/粘合剂以与c代码组合的详细信息。我的汇编程序编码生锈了,但是会在hello_world的开头添加等效代码(至少在引用sin()函数之前(可能)会使事情正常工作吗?可能会将它添加到libstubs代码中。

我正在使用另一个A20主板作为主要开发环境。

$ gcc --version gcc (Debian 4.6.3-14) 4.6.3 Copyright (C) 2011 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.

$ ld.bfd --version GNU ld (GNU Binutils for Debian) 2.22 Copyright
2011 Free Software Foundation, Inc. This program is free software; you
may redistribute it under the terms of the GNU General Public License
version 3 or (at your option) a later version. This program has
absolutely no warranty.

$ uname -a Linux a20-OLinuXino 3.4.67+ #6 SMP PREEMPT Fri Nov 1
17:32:40 EET 2013 armv7l GNU/Linux

我已经能够从repo为SD卡上的电路板创建可启动的U-Boot映像,可以直接从随板提供的linux-sunxi发行版构建,也可以从Fedora交叉编译21台机器。 U-boot示例中的独立hello_world程序也是如此,可以从U-Boot控制台加载和运行。

但是,将示例程序减少到最低限度,然后添加需要math.h,-lm和-lc的代码会因“软件中断”或“未定义操作”类型错误而失败(在各种迭代中)。原始示例程序与-lgcc链接,但稍微检查显示库中实际上没有包含任何内容。相同的二进制文件是在没有库的情况下创建的,所以问题可能是“使用裸机程序使用任何库需要什么?”

sun7i# go 0x48000000
## Starting application at 0x48000000 ...
Hello math World
undefined instruction
pc : [<48000010>]          lr : [<4800000c>]
sp : 7fb66da0  ip : 7fb672c0     fp : 00000000
r10: 00000002  r9 : 7fb66f0c     r8 : 7fb67778
r7 : 7ffbbaf8  r6 : 00000001     r5 : 7fb6777c  r4 : 48000000
r3 : 00000083  r2 : 7ffbc7fc     r1 : 0000000a  r0 : 00000011
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...

为了达到这个目的,我不得不调整构建选项,以指定硬件浮点,因为这就是基础库的编译方式。

以下是相应的源和构建脚本文件

hello_world.c

#include <common.h>
#include <math.h>

int hello_world (void)
{
    double tst;
    tst = 0.33333333333;
    printf ("Hello math World\n");
    tst = sin(0.5);
//  printf ("sin test %d : %d\n", (int)tst, (int)(1000 * tst));
    return (0);
}

构建脚本

#! /bin/bash
UBOOT="/home/olimex/u-boot-sunxi"
SRC="$UBOOT/examples/standalone"
#INCLS="-nostdinc -isystem /usr/lib/gcc/arm-linux-gnueabihf/4.6/include -I$UBOOT/include -I$UBOOT/arch/arm/include"
INCLS="-I$UBOOT/include -I$UBOOT/arch/arm/include"
#-v
GCCOPTS="\
 -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x4a000000\
 -Wall -Wstrict-prototypes -Wno-format-security\
 -fno-builtin -ffreestanding -Os -fno-stack-protector\
 -g -fstack-usage -Wno-format-nonliteral -fno-toplevel-reorder\
 -DCONFIG_ARM -D__ARM__ -marm -mno-thumb-interwork\
 -mabi=aapcs-linux -mword-relocations -march=armv7-a\
 -ffunction-sections -fdata-sections -fno-common -ffixed-r9\
 -mhard-float -pipe"
# -msoft-float -pipe
OBJS="hello_world.o libstubs.o"

LDOPTS="--verbose -g -Ttext 0x48000000"
#--verbose
#LIBS="-static -L/usr/lib/gcc/arm-linux-gnueabihf/4.6 -lm -lc"
LIBS="-static -lm -lc"
#-lgcc

gcc -Wp,-MD,stubs.o.d $INCLS $GCCOPTS -D"KBUILD_STR(s)=#s"\
 -D"KBUILD_BASENAME=KBUILD_STR(stubs)"\
 -D"KBUILD_MODNAME=KBUILD_STR(stubs)"\
 -c -o stubs.o $SRC/stubs.c

ld.bfd -r -o libstubs.o stubs.o

gcc -Wp,-MD,hello_world.o.d $INCLS $GCCOPTS -D"KBUILD_STR(s)=#s"\
 -D"KBUILD_BASENAME=KBUILD_STR(hello_world)"\
 -D"KBUILD_MODNAME=KBUILD_STR(hello_world)"\
 -c -o hello_world.o hello_world.c

ld.bfd $LDOPTS -o hello_world -e hello_world $OBJS $LIBS

objcopy -O binary hello_world hello_world.bin

EDITS补充道:

要成为其中一部分的应用程序需要一些相当高速的GPIO和一些数学函数。应该只需要sin()和sqrt()。我之前对GPIO的测试得到了单个引脚(端口组中的端口)的切换,最高可达8MHz。应用的限制需要在10μs(100Hhz)范围内获得完整的周期时间,包括从单个端口读取所有引脚,并在其他端口上写入几个引脚,与所连接的ADC芯片的时序限制同步( 3 ADC读取)。我有裸金属代码在大约2.1μs内进行(模拟)该过程。现在我需要添加数学来处理值,其输出将设置更多输出。未来计划的改进包括使用SIMD进行数学计算,并将第二个核心专用于数学,而第一个进行GPIO并“提供”计算。

所需的数学代码/逻辑已经使用非常标准的(c99)代码写入模拟程序。我只需要将它移植到裸机程序中。需要让'数学'先工作。

1 个答案:

答案 0 :(得分:0)

首先,我建议阅读这篇关于使用ARM和GNU进行裸机编程的优秀论文http://rextester.com/LRMW38599

然后,我会确保你避免任何系统调用Linux内核(你没有,你的编译器会尝试制作),例如避免返回void main()中的值 - 无论如何都不应该返回。

最后,我要么使用newlib,要么如果你需要使用一小部分库提供的,编写自定义实现

请记住,您使用的是Allinner SoC,这不是最好的裸机文档,但您可以在http://www.state-machine.com/arm/Building_bare-metal_ARM_with_GNU.pdf找到TRM,因此我会检查库(如果您决定使用它们)或您的代码需要一些特殊的硅硬件进行初始化(某些互连结构,时钟和电源域等)。

我强烈建议,如果你只需要使用sin()和类似的东西,只需部署你自己的。