我正在尝试通过内联汇编访问Broadcom ARM处理器上的硬件寄存器。我通过裸机编程访问了硬件寄存器,但现在我正在尝试使用asm将这些裸机编程代码合并到C文件中。这是我在Raspberry Pi 2上切换GPIO 17的代码:
void main() {
__asm__(
".section .init\n\t"
".globl _start\n\t"
"_start:"
"ldr r0,=0x3F200000\n\t"
"mov r1, #1\n\t"
"lsl r1, #21\n\t"
"str r1, [r0, #4]\n\t"
"loop$:\n\t"
"mov r1, #1\n\t"
"lsl r1, #17\n\t"
"str r1, [r0, #28]\n\t"
"mov r1, #1\n\t"
"lsl r1, #17\n\t"
"str r1, [r0, #40]\n\t"
"b loop$\n\t"
);
}
但是当我用gcc file.c编译它时
它会抛出以下错误
/tmp/ccrfp9mv.s: Assembler messages:
/tmp/ccrfp9mv.s: Error: .size expression for main does not evaluate to a constant
答案 0 :(得分:4)
您获得Error: .size expression for main does not evaluate to a constant
因为您更改了函数内的部分。正如您在godbolt compiler explorer上看到的那样,编译器将发出asm指令来计算ELF元数据,其行如:
.size main, .-main # size_of_main = current_pos - start_of_main
由于您在main
的主体内部切换了部分,因此在链接时间之前,main
与main
的结尾之间的距离是未知的,并且无法获取链接器最近填写这段元数据。 (.size
必须是汇编时常数,而不仅仅是链接时常数。
就像人们评论的那样,你应该用C做完整件事,例如:与全球一样
#include <stdint.h>
volatile uint32_t *const GPIO17 = (uint32_t*)0x3F200000; // address is const, contents aren't.
据推测,您需要要求操作系统访问该MMIO寄存器。操作系统的部分工作是阻止程序直接与硬件对话,并弄乱其他同时执行相同操作的程序。
即使您的代码已汇编,也不会链接,因为_start
的定义将与libc运行时代码提供的定义冲突。
不要尝试在另一个函数内的inline asm中定义一个函数。如果你想这样做,写一个独立的功能。