【发布时间】:2015-05-01 20:35:52
【问题描述】:
我正在 ARM1176JZ-F 处理器 (RPi B+) 上试验裸机编程,同时尝试了解 C 运行时的作用。
我正在使用 arm-none-eabi-gcc 工具链交叉编译我用 C 编写的基本内核(归结为只在寄存器和内存中移入和移出几位),使用以下标志:
arm-none-eabi-gcc -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles foo.c
我在代码中的自动变量方面遇到了一些问题,需要一些指导!
首先,我不确定运行时库和“启动”例程之间的关系,它们是否相同,“-nostartfiles”实际上没有链接运行时,或者这些例程只是其中的一部分运行时库的工作?
其次,我不确定运行时与自动变量的关系如何,我注意到,虽然不会导致编译错误,但不起作用!
非常感谢任何指导!
编辑:参见下面的代码 sn-p。如果 |gpioBase| 的话,该程序似乎不能工作(但可以正常编译)和 |计时器|变量在主功能块中声明。
/*
* armc1.c
*
* flash PWR/ACT LEDs on RPi B+
*
**/
#include <stdint.h>
//variables declared outside function block, no runtime support = no automatic variables!
volatile uint32_t* gpioBase; //BCM2835 gpio base
volatile uint32_t time; //timer
int main(void) {
gpioBase = (uint32_t*)(0x20200000UL); //BCM2835 gpio physical address
//set outputs
gpioBase[3] = (1<<15); //GPFSEL3 @ 0x2020000C = 0b0..001..0, GPIO35 as output
gpioBase[4] = (1<<21); //GPFSEL4 @ 0x20200010 = 0b0..001..0, GPIO47 as output
//infinite loop, no OS
while(1) {
gpioBase[8] = (1<<3); //GPSET1-SET35 @ 0x20200020 = 1, GPIO35 on
gpioBase[8] = (1<<15); //GPSET1-SET47 @ 0x20200020 = 1, GPIO47 on
for(time = 0;time < 500000;time++); //waste time
gpioBase[11] = (1<<3); //GPCLR1-CLR35 @ 0x2020002C = 1, GPIO35 off
gpioBase[11] = (1<<15); //GPCLR1-CLR47 @ 0x2020002C = 1, GPIO47 off
for(time = 0;time < 500000;time++); //waste time
}
}
【问题讨论】:
-
“自动变量不起作用”是什么意思?你怎么知道他们不是?什么自动变量?你有最小的代码示例吗?
-
我猜你没有提供任何启动代码,其中包括定义堆栈位置和大小。自动变量是在堆栈上分配的,所以这可能是原因。
-
如果您在代码中只使用
_start:,则必须清除.bss(全局零变量)并为堆栈设置空间。通常,您通过链接描述文件控制地址布局。_start()应该在汇编程序中,因为如果编码正确,它不需要堆栈,也不需要.bss。可以用“C”编写,但它是非标准的,并且在汇编程序中可能更清晰,除非您对汇编程序一无所知;但是你可能无法让“C”工作。 -
帖子已编辑以包含示例代码。我正在尝试从程序集向上搭建到 C。我确实广泛了解 ARM 程序集,但我正在尝试尽可能多地做而不直接求助于它!我主要专注于尝试理解 C 运行时,您能否更清楚地了解“启动代码”和“_start:”标签的含义以及它的作用?
-
在 C 中,局部变量放在堆栈上,因此如果您不设置堆栈指针,代码将无法在运行时创建变量。相反,如果将它们放在 main 之前,它们将被编译到引导映像中,并因此由引导加载程序加载。开始标签只是引导加载程序放入内存的代码开始的位置。
标签: c linker arm bare-metal