是否可以通过内联汇编访问硬件寄存器

时间:2016-05-16 11:55:44

标签: c assembly inline-assembly

我正在尝试通过内联汇编访问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

1 个答案:

答案 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的主体内部切换了部分,因此在链接时间之前,mainmain的结尾之间的距离是未知的,并且无法获取链接器最近填写这段元数据。 (.size必须是汇编时常数,而不仅仅是链接时常数。

就像人们评论的那样,你应该用C做完整件事,例如:与全球一样

#include <stdint.h>
volatile uint32_t *const GPIO17 = (uint32_t*)0x3F200000;  // address is const, contents aren't.

据推测,您需要要求操作系统访问该MMIO寄存器。操作系统的部分工作是阻止程序直接与硬件对话,并弄乱其他同时执行相同操作的程序。

即使您的代码已汇编,也不会链接,因为_start的定义将与libc运行时代码提供的定义冲突。

不要尝试在另一个函数内的inline asm中定义一个函数。如果你想这样做,写一个独立的功能。