STM32F103C8 裸机与链接器脚本 GCC

STM32F103C8 bare metal with linker scripts GCC

我正在尝试在汇编中编写裸机代码并使用 GCC 工具链编译 + link 它。 据我所知,正确的步骤是遵循以下步骤:

  1. 重启后 - MCU 必须检查向量 table 并执行重置处理程序,我在此处初始化堆栈指针。
  2. 执行主要代码。 为了完成这个任务,我还需要相应的 linker 脚本。当我尝试执行 linker 时,它抛出语法错误。 请指教:
  3. linker 脚本中需要更正的内容
  4. 更正 vtable 和处理程序执行顺序。

代码:

stack_size      =       0x400
stack_start     =       0x20000000+stack_size
gpiob_base      =       0x40010C00
rcc_base        =       0x40021000
rcc_apb2enr     =       rcc_base+0x18
gpio_crl        =       gpiob_base
gpiob_odr       =       gpiob_base+0x0C

                .syntax unified
                .cpu cortex-m3
                .thumb
                .global main
                .global vtable
main:
                LDR R0, =rcc_apb2enr
                LDR R1, [R0]
                LDR R2, =0x8 // Activate 3rd bit in registry
                ORR R1, R2
                STR R1, [R0]

                // Configure GPIO_CRL
                LDR R0, =gpio_crl
                LDR R1, [R0]
                LDR R2, =0xFFFFFF00
                AND R1,R1,R2
                ORR R1, R1, #0x20
                STR R1, [R0] // Reset register

                //Configure GPIOB_ODR
                LDR R0, =gpiob_odr
                LDR R1, [R0]
                ORR R1, #0x2
                STR R1, [R0]
                B .
vtable:
        .word   stack_start
        .word   reset_handler

reset_handler:
                B main

链接描述文件:

/* - STM32F103C8T6 - Medium Density device
 * - RAM: 20K, Flash:64K CPU: 72MHz
*/
ENTRY(reset_handler);
MEMORY {
        RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
        FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}

SECTIONS
{
        /* Section that stores program instructions (code) */
        .text : {
                . = ALIGN(4);
                KEEP(*(.vtable))
                *(.text)
                *(.text*)
                *(.rodata)
                *(.rodata*)
                . = ALIGN(4);
        } > FLASH

        _data_flash = .;

        // Section that store initialized data - variables
        .data : AT(_data_flash){
                . = ALIGN(4);
                _data_begin = .;
                *(.data)
                *(.data*)
                . = ALIGN(4);
                _data_end = .;
        }  > RAM

        /* Section that stores uninitialized data */
        .bss :{
                _bss_begin = .;
                _bss_start_ = _bss_begin;
                *(.bss)
                *(.bss*)
                *(COMMON)
                . = ALIGN(4);
                _bss_end = .;
                _bss_end_ = _bss_end;
        } > RAM

        /* Here we define stack */
        _stack_size = 1024;
        _stack_end = ORIGIN(RAM)+LENGTH(RAM);
        _stack_begin = _stack_end - _stack_size;
        . = _stack_begin;
    ._stack :{
                . = . + _stack_size;
        } > RAM
}



._stack :{
                . = . + _stack_size;
        } > RAM
}

程序反汇编:

pi@mylab:~/assembly $ arm-none-eabi-objdump --disassemble bp.o

bp.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <main>:
   0:   480d            ldr     r0, [pc, #52]   ; (38 <reset_handler+0x4>)
   2:   6801            ldr     r1, [r0, #0]
   4:   f04f 0208       mov.w   r2, #8
   8:   ea41 0102       orr.w   r1, r1, r2
   c:   6001            str     r1, [r0, #0]
   e:   480b            ldr     r0, [pc, #44]   ; (3c <reset_handler+0x8>)
  10:   6801            ldr     r1, [r0, #0]
  12:   f06f 02ff       mvn.w   r2, #255        ; 0xff
  16:   ea01 0102       and.w   r1, r1, r2
  1a:   f041 0120       orr.w   r1, r1, #32
  1e:   6001            str     r1, [r0, #0]
  20:   4807            ldr     r0, [pc, #28]   ; (40 <reset_handler+0xc>)
  22:   6801            ldr     r1, [r0, #0]
  24:   f041 0102       orr.w   r1, r1, #2
  28:   6001            str     r1, [r0, #0]
  2a:   e7fe            b.n     2a <main+0x2a>

0000002c <isr_vector>:
  2c:   20000400        .word   0x20000400
  30:   00000034        .word   0x00000034

00000034 <reset_handler>:
  34:   f7ff bffe       b.w     0 <main>
  38:   40021018        .word   0x40021018
  3c:   40010c00        .word   0x40010c00
  40:   40010c0c        .word   0x40010c0c

对于你正在做的事情,你可以从更简单的开始。

flash.s

stack_size      =       0x400
stack_start     =       0x20000000+stack_size
gpiob_base      =       0x40010C00
rcc_base        =       0x40021000
rcc_apb2enr     =       rcc_base+0x18
gpio_crl        =       gpiob_base
gpiob_odr       =       gpiob_base+0x0C


.syntax unified
.cpu cortex-m3
.thumb

vtable:
    .word   stack_start
    .word   reset_handler


.thumb_func
reset_handler:
    B main

main:
    LDR R0, =rcc_apb2enr
    LDR R1, [R0]
    LDR R2, =0x8 // Activate 3rd bit in registry
    ORR R1, R2
    STR R1, [R0]

    // Configure GPIO_CRL
    LDR R0, =gpio_crl
    LDR R1, [R0]
    LDR R2, =0xFFFFFF00
    AND R1,R1,R2
    ORR R1, R1, #0x20
    STR R1, [R0] // Reset register

    //Configure GPIOB_ODR
    LDR R0, =gpiob_odr
    LDR R1, [R0]
    ORR R1, #0x2
    STR R1, [R0]
    B .

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
}

建造

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy -O binary so.elf so.bin

检查(应该始终对新项目执行此操作)

so.elf:     file format elf32-littlearm


Disassembly of section .text:

08000000 <vtable>:
 8000000:   20000400    andcs   r0, r0, r0, lsl #8
 8000004:   08000009    stmdaeq r0, {r0, r3}

08000008 <reset_handler>:
 8000008:   e7ff        b.n 800000a <main>

0800000a <main>:
 800000a:   480b        ldr r0, [pc, #44]   ; (8000038 <main+0x2e>)
 800000c:   6801        ldr r1, [r0, #0]
 800000e:   f04f 0208   mov.w   r2, #8
 8000012:   ea41 0102   orr.w   r1, r1, r2
 8000016:   6001        str r1, [r0, #0]
...

因此,只需将向量 table 放在正确的位置,并且重置处理程序地址正确(地址与 1 或),这就有一半的机会工作。

还可以看到它正在生成 thumb2 代码(如果你最终使用 cortex-m0 并且不修复你的 build/code 最容易从 cortex-m0 开始,它会咬你,它适用于所有这些然后如果需要 select thumb2.YMMV)

现在,如果您有其他对象,在这种情况下,带有向量 table、flash.o 的对象,需要成为命令行上的第一个对象,才能成为第一个 .text解析并放入二进制文件中。

您可以将事情复杂化以标记向量 tables 的特殊部分(请注意,您可以随意调用部分但有一些限制,不必将其称为向量或 vector_table,等等除非你愿意)。然后,您将需要在源代码等中添加更多链接器内容和更多代码。因为您必须在命令行上获得正确的内容才能开始,并且您必须投入工作以获取正确的代码,包括指令。为什么要创建更多没有价值的工作,只需将向量 table 放在正确的位置,靠近重置处理程序。 YMMV.

所以你的矢量 table 接近代码的末尾,而不是第一件事。基本上你要求 table 在错误的地方。它是。您首先需要它以适应此代码的其余部分。接下来,由于您在 table 中引用重置处理程序的地址,您需要函数地址而不仅仅是地址,您需要将该标签声明为一个函数,以便它为 thumb/arm 工作。对于缩略图函数,您可以在标签前的某处使用快捷方式 .thumb_func(不必是之前的行),它将触发 gnu 汇编程序找到的下一个标签作为缩略图函数。因为这是靠近顶部的单个 .thumb 下的所有单个文件,所以到 main 的分支是可以的。理想情况下,您可能也想声明一个函数,当然,如果您正在为非 cortex-m 手臂进行 arm/thumb 交互操作,则需要在全局 asm 函数中进行此操作。

同时适用于 arm 和 thumb gnu 汇编器的另一种方法是

.type functionname, %function
functionname:

您的链接描述文件对于此任务过于复杂。我确定您正在努力解决这个问题。

您使用了正确的地址,但您拆解的是对象而不是小精灵。但是根据你的代码,它仍然会构建错误。

您正在链接描述文件中声明一个堆栈(我倾向于非常讨厌它,但有些人喜欢它,YMMV)。但是您没有在向量 table 中使用该链接描述文件变量,您使用的是计算值。这个程序没有坏掉,但有一点需要注意。

堆栈正在由向量table设置,因此您可以使用它(可以调用函数)。我推荐

bl main
b .

在reset handler中,然后main可以选择无限循环或者return你是safe/fine.

如果您没有在向量中正确设置堆栈地址 table 那么您可能会在那里遇到麻烦。

注意 odr 很好,但您可能需要查看 bsrr 寄存器。对于单个端口位更灵活。并且将位“打开”并不会打开所有板上的 LED“打开”,一些 gpio 连接到另一端并且您将其接地以将其打开。所以请注意这一点并查看原理图或文档。