c - 在裸机程序中使用程序库

标签 c gcc arm static-libraries bare-metal

有人可以帮我吗!我不知道答案是一般的还是针对我正在使用的主板和软件版本的。我不在这里以前的领域,甚至不知道要问的正确问题。

在底部添加了编辑

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

创建裸机独立程序是否需要一些标准的gcc / ld标志,并包括一些库例程?除了-ffreestanding和-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


我已经可以通过回购在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


添加的编辑:

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

所需的数学代码/逻辑已经使用非常标准的(c99)代码写入了仿真程序。我只需要将其移植到裸机程序中即可。需要首先获得“数学”才能工作。

最佳答案

首先,我建议阅读这篇有关使用ARM和GNU http://www.state-machine.com/arm/Building_bare-metal_ARM_with_GNU.pdf进行Bare Metal编程的优秀论文。

然后,我将确保避免对Linux内核的任何系统调用(您没有该系统调用,并且编译器将尝试进行此操作),例如避免在void main()中返回值-无论如何都永远不会返回。

最后,我将使用newlib,或者,如果您需要使用库提供的一小部分子集,请编写一个自定义实现。

请记住,您使用的Allinner SoC并不是裸金属文档的最佳选择,但是您可以在http://www.soselectronic.com/a_info/resource/c/20_UM-V1.020130322.pdf处找到TRM,因此我将检查库(如果您决定使用它们)或您的代码是否需要一些特殊的东西。要初始化的硅硬件(某些互连结构,时钟和电源域等)。

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

关于c - 在裸机程序中使用程序库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33310656/

相关文章:

c++ - gcc 自动矢量化在缩减循环中失败

c++ - g++ 版本兼容性

c - bpkt ARM 指令卡住了我的嵌入式应用程序

c - C中的慢基数排序

c - 使用 phtreads 从 C 中的多个线程读取和写入不同位置的数组是否安全?

c++ - 在路径中找不到程序 "g++"和 "gcc"

arm - 堆栈指针和程序计数器有什么区别?

c - 单精度 float 在零附近时的近似分辨率是多少

c++ - 1<<25 在开放中意味着什么?

c - ARM 代码中的读-修改-写操作应该使用什么抽象