【发布时间】:2016-01-23 11:32:33
【问题描述】:
谁能帮帮我!我不知道答案是一般性的,还是特定于我正在使用的主板和软件版本。我不在我以前的领域,甚至不知道要问的正确问题。
在底部添加编辑
我目前想要的是创建一个程序,该程序将在A20-OLinuXino-Micro-4GB 板上独立运行(裸机;无操作系统),需要使用(至少)一些标准数学库调用。最终,我想将它加载到 NAND 中,并在上电时运行它,但现在我正在尝试从 U-Boot (github.com/linux-sunxi/u-boot-sunxi/) 手动加载它 (loady) 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
我已经能够从 repo 为 SD 卡上的开发板创建可引导的 U-Boot 映像,可以直接从开发板随附的 linux-sunxi 发行版构建,也可以从 Fedora 21 机器交叉编译.与 U-boot 示例中的独立 hello_world 程序相同,可以从 U-Boot 控制台加载和运行。
但是,将示例程序减少到最低限度,然后添加需要 math.h、-lm 和 -lc 的代码会失败(在各种迭代中)并出现“软件中断”或“未定义操作”类型错误。原始示例程序与 -lgcc 链接,但稍作检查表明库中实际上没有包含任何内容。相同的二进制文件是在没有库的情况下创建的,所以问题可能是“将 any 库与裸机程序一起使用需要什么?”
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 (100Hz) 范围内的完整周期时间,其中包括从单个端口读取所有引脚,并在其他端口上写入几个引脚,与所连接 ADC 芯片的时序限制同步( 3 个 ADC 读取)。我有裸机代码在大约 2.1µs 内完成(模拟)该过程。现在我需要添加数学来处理这些值,其输出将设置更多输出。未来计划的改进包括使用 SIMD 进行数学运算,并将第二个内核专用于数学运算,而第一个内核负责 GPIO 并“提供”计算。
所需的数学代码/逻辑已使用非常标准的 (c99) 代码写入模拟程序。我只需要将它移植到裸机程序中。需要先学习“数学”。
【问题讨论】:
-
我会在已经安装的操作系统上使用专用的 Android GPIO 驱动程序,这样就绕过了可怕的 nighm.. 尝试在没有硬件调试器的情况下运行可启动映像的艰苦工作。 ''软件中断'或'未定义操作'类型错误' - 是的,这在很长一段时间内都是正常的,当试图在开发板上从零开始工作时:(
-
是的,这一切都是可行的。你追求什么数学,只是软浮动或其他什么?许多库(例如 printf 是一个非常重的库)至少有一些系统依赖项,甚至是数学库(除以零处理程序)。因此,如果您想使用库存的未修改库,则需要对系统调用进行某种替换,例如 newlib,但它不太可能完全替换您需要的所有内容。我认为您需要从非 printf hello world 开始,要么闪烁一个 LED(典型),要么将一些字节从 uart 中推出。
-
进行编译、链接、引导和运行,您已经完成了 80% 的工作。然后要么找到干净的裸机库(需求不大,所以不太可能),或者采用现有的并提取你想要的部分并使它们干净,或者添加它们需要的调用以允许它们编译。例如,newlib 使后端变得简单,您可以通过并更改所有函数以返回适当的传递失败而不实际执行任何操作,添加更多行,然后非常繁重的 printf 实际上可以将内容吐出 uart例子。
-
我真的不建议在移动应用程序 SoC 上使用裸机深入研究。对于初学者来说,这里提出的问题实际上与标题问题几乎没有关系,而且您已经证明您拥有一切可以了解事物如何工作的知识。您很幸运,引导加载程序的异常处理程序确切地告诉您出了什么问题:反汇编您的二进制文件并查看该地址处的指令是什么(提示:它将是一个浮点指令)。咦,怎么没定义?好吧,您没有为您启用 FPU 的操作系统...
-
基本数学无论是定点还是浮点数在某种程度上都在libgcc中,如果你使用gcc链接那么它可以找到libgcc,如果你使用ld(使控制引导代码和内存映射更容易) 那么你必须在链接器命令行上显式添加 libgcc (它的路径),至少这是我的经验。您可能必须为除以零和它想要的任何其他东西创建一个虚拟函数,以便它没有错误地链接。
标签: c gcc arm static-libraries bare-metal