Cortex M3 .bss区域初始化的裸机启动代码


10

我从这里得到了启发,为手臂皮质M3设计了一个裸机启动代码。但是,我遇到以下问题:假设我声明了一个未初始化的全局变量,例如main.c中的unsigned char类型

#include ...
unsigned char var; 
...
int main()
{
 ...
}

这使得STM32 f103中的.bss区域开始于_BSS_START = 0x20000000并结束于_BSS_END = 0x20000001。现在,启动代码

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

尝试将整个.bss区域初始化为零。但是,在while循环内,指针增加了4个字节,因此在执行bss_start_p = 0x20000004的步骤之后,它将始终与bss_end_p不同,从而导致无限循环等。

有什么标准的解决方案吗?我是否想以某种方式“强制” .bss区域的尺寸为4的倍数?还是应该使用指向无符号字符的指针来遍历.bss区域?也许像这样:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```

使用少于。引导程序是出于汇编原因编写的。首先,您已经创建了.data问题。它是一本鸡肋的事/假设C可以使您至少依赖于.text,.bss和.data,但是您正在编写确保C代码能够正常工作的C代码,并在C代码中使用了需要可能以依赖C工作的C代码编写的引导程序。
old_timer

复制.data的代码与.bss非常相似,但是如果像上面的代码那样编写,则需要复制.data以便复制.data。
old_timer

Answers:


15

您可能会怀疑,这是因为无符号int数据类型的大小为4个字节。每个*bss_start_p = 0;语句实际上清除bss区域的四个字节。

bss内存范围需要正确对齐。您可以简单地定义_BSS_START和_BSS_END,以使总大小为4的倍数,但这通常可以通过允许链接描述文件定义开始和停止位置来处理。

例如,这是我的一个项目中的链接器部分:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

ALIGN(4)语句处理后事。

另外,您可能希望更改

while(bss_start_p != bss_end_p)

while(bss_start_p < bss_end_p)

这不会解决问题(因为您可能要清除的字节数比您希望的多1-3个),但可以将影响降到最低:)


@CMarius经过反省,我认为您的char指针想法很有用,尽管它需要更多的周期。但是我不确定下一个内存区域是否未对齐是否会出现后续问题,因此我不会在答案中提及它……
bitsmack

1
while(bss_start_p < bss_end_p - 1)然后按字节清除剩余的内存范围将消除最后的顾虑。
glglgl

4

标准解决方案是memset()

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

如果您不能使用标准库,则必须确定是否可以将内存区域的大小四舍五入为4个字节,然后继续使用unsigned int *; 或者如果您需要对此进行严格的规定,则在这种情况下,您需要使用unsigned char *

如果您将大小四舍五入,例如在第一个循环中,则bss_start_p实际上可能会大于,bss_end_p但这很容易用小于比较<而不是不平等测试来处理。

当然,您也可以用32位传输填充大部分的内存区域,而用8位传输填充最后的几个字节,但是这样做的好处不多,尤其是在这里,它只是一段启动代码。


1
非常同意的使用memset()。但是对齐到4个字节或多或少是必须的。那么为什么不这样做呢?
科多

3
引导程序使用memset的标准解决方案绝不是形状或形式,这太疯狂了。
old_timer

您不会使用同一语言来引导该语言
old_timer

2
引导程序代码和链接器脚本非常吻合,您会发现链接器脚本在至少4个字节的边界上对齐并调整.bss的大小以一次将指令的填充量提高4倍,这是很常见的。 (假设(最少)32位总线,这通常是用于arm的,但也有例外)
old_timer '19

3
@old_timer,用于将内存设置为特定值的标准C函数是memset(),而C似乎是他们正在编程的memset()函数。的简单实现也几乎就是那个循环,它并不太依赖于其他东西。由于这是一个微控制器,因此我也假设没有动态链接或进行此类操作(并且查看链接,没有,只是在调main()零循环之后的一个调用),因此编译器应该能够放入memset()该链接中。以及其他任何功能(或内联实现)。
ilkkachu


3

还有无数其他网站和示例。数以千计甚至数万。有众所周知的c库,其中包含链接程序脚本和boostrap代码,特别是newlib和glibc,但您还可以找到其他库。用C引导C毫无意义。

您的问题已得到回答,您正在尝试对可能不完全精确的事物进行精确比较,它可能不会在已知边界上开始,也可能不在已知边界上结束。因此,您可以做不到的事情,但是如果代码无法通过精确的比较工作,则意味着您将.bss归零到下一节,这可能会或可能不会导致不好的事情发生,因此只需替换为less than isnt解决方案。

TL; DR就可以了。您无需使用该语言来引导语言,可以肯定地摆脱它,但是这样做时您会玩火。如果您只是在学习如何执行此操作,则需要保持谨慎的态度,而不是傻瓜运气或尚未发现的事实。

链接描述文件和引导程序代码之间有着非常密切的关系,它们是已婚的,并在髋关节处连接在一起,如果没有其他组件,您将无法发展,从而导致大量失败。不幸的是,链接器脚本是由链接器定义的,而汇编语言是由汇编器定义的,因此当您更改工具链时,期望它们都必须重新编写。为什么要使用汇编语言?它不需要引导程序,通常是编译语言。如果您不想限制对语言的使用,C会这样做,这是从一个非常简单的东西开始的,它只具有最低的工具链特定要求,您不要假设.bss变量为零(如果从未使用该语言初始化变量,则代码的可读性较低) ,请尝试避免这种情况,因为局部变量不是正确的,因此必须在使用时加以注意。那么,为什么我们要谈论.bss和.data ???(全局变量对此级别的工作很有用,但这是另一个主题)。简单解决方案的另一条规则是不要在声明中初始化变量,而要在代码中完成。是的,会消耗更多的闪存,通常您有很多闪存,并非所有变量都使用常量进行初始化,反而最终会消耗指令。

从cortex-m设计中可以看出,他们可能一直认为根本没有引导程序代码,因此没有.data和.bss支持。大多数使用全局变量的人不能没有这样的生活:

我可以使用gnu工具链为所有cortex-ms制作一个更小巧但最小的功能示例,我不记得可以通过当前的9.xx或更高版本从5.xx开始,还是在3左右切换链接器脚本。 xx或4.xx,因为我学到了更多,而gnu改变了一些使我的第一个摔坏的东西。

引导程序:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

C代码的入口点:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

链接描述文件。

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

所有这些可能都较小,并且仍然可以使用,在这里添加了一些额外的东西只是为了看看它在起作用。

优化的构建和链接。

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

对于某些供应商,您希望使用0x08000000或0x01000000或其他类似的地址,因为闪存已映射到那里并在某些引导模式下镜像到0x00000000。有些仅在0x00000000处镜像了太多闪存,因此您希望向量表指向应用程序闪存空间不为零。由于它是基于向量表的,因此所有方法都有效。

首先请注意,cortex-ms是仅使用拇指的机器,无论出于何种原因,它们都强制使用了拇指函数地址,这意味着lsbit是奇数。知道您的工具后,.thumb_func指令会告诉gnu汇编程序下一个标签是thumb函数地址。在表中做+1事情会导致失败,不要被诱惑去做,正确地做。还有其他gnu汇编器方法来声明函数,这是最小的方法。

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

如果您没有正确设置向量表,它将无法启动。

可以说,只需要堆栈指针向量(如果您希望自己在代码中设置堆栈指针,则可以在其中放置任何内容)和复位向量。我没有特殊原因就把四个放在这里。通常放16,但想简化此示例。

那么,C引导程序需要做的最少工作是什么?1.设置堆栈指针2.零.bss 3.复制.data 4.分支到或调用C入口点

C入口点通常称为main()。但是某些工具链会看到main()并向代码中添加额外的垃圾。我故意使用其他名称。YMMV。

如果全部基于ram,则不需要.data的副本。作为cortex-m微控制器,在技术上是可行的,但可能性不大,因此需要复制数据.....如果有数据。

我的第一个示例和编码风格是不依赖于.data或.bss,如本示例所示。Arm照顾了堆栈指针,因此剩下的唯一事情就是调用入口点。我喜欢这样,以便切入点可以返回,许多人认为您永远都不要这样做。您可以这样做:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

而不是从centry()返回,并且没有重置处理程序代码。

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

链接器已将内容放到我们要求的位置。总体而言,我们有一个功能齐全的程序。

因此,首先要处理链接描述文件:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

强调名称rom和ram没有意义,它们仅连接部分之间链接器的点。

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

添加一些项目,以便我们可以看到工具做了什么

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

在这些部分中添加一些项目。并得到

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

这是我们在该实验中寻找的东西(请注意没有理由真正加载或运行任何代码...知道您的工具,学习它们)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

因此,我们在这里了解到的是,变量的位置在gnu链接器脚本中非常敏感。请注意data_rom_startdata_start的位置,但是为什么data_end起作用?病让你知道。已经理解为什么人们可能不想要弄乱链接描述脚本而只是简单编程...

因此,我们在这里了解到的另一件事是,链接器为我们对齐了data_rom_start,因此我们不需要ALIGN(4)。我们是否应该假设那将一直有效?

还要注意,在到达的过程中它填充了5个字节的.data,但是却将其填充了8个字节。没有任何ALIGN(),我们已经可以使用单词进行复制了。根据我们今天在计算机上使用此工具链所看到的情况,过去和将来是否可能如此?谁知道,即使ALIGN需要定期检查以确认某些新版本没有损坏,他们也会不时这样做。

为了安全起见,我们从该实验继续进行下去。

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

在内部移动末端以与其他人的行为保持一致。并没有改变它:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

另一项快速测试:

.globl bounce
bounce:
    nop
    bx lr

给予

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

无需在弹跳和.align之间填充

哦,对了,我现在记得为什么我不把_end__放在里面。因为它不起作用。

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

一些简单但可移植的代码与该链接描述文件结合

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

给予

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

我们可以在那里停下来或继续前进。如果我们以与链接脚本相同的顺序进行初始化,那么我们可以进入下一件事就可以了,因为我们还没有到达那里。和stm / ldm仅要求/希望使用字对齐地址,因此,如果更改为:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

首先在链接描述文件中使用bss,是的,您想要ble而不是bls。

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

这些循环会更快。现在,我不知道ahb总线是否可以为64位宽,但是对于全尺寸的臂,您将需要在64位边界上对齐这些东西。在32位边界而不是64位边界上的四个寄存器ldm / stm变成三个独立的总线事务,其中在64位边界上对齐的是单个事务,每个指令节省几个时钟。

因为我们正在做裸机,并且我们全权负责我们可以首先说bss的所有内容,然后对数据进行处理,然后如果有堆,那么堆栈会从上到下增长,所以如果我们将bss归零并溢出,只要我们从正确的地方,我们还没有使用该内存。然后我们将.data复制过来,并可能溢出到正常的堆中,无论堆是否存在,堆栈是否有足够的空间,因此我们不会踩任何人/任何东西(只要我们确保在链接程序脚本中这样做即可)。如果有问题,请增大ALIGN()的大小,以使我们始终将这些填充物放置在我们的空间内。

所以我的简单解决方案是接受还是放弃。欢迎修复所有错误,我没有在硬件或模拟器上运行此错误...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

将它们放在一起,您将获得:

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

请注意,这与arm-none-eabi-和arm-linux-gnueabi以及其他变体一起使用,因为没有使用酥油神器。

当您环顾四周时,您会发现人们会在他们的链接描述文件中疯狂地用酥油神仙的东西,巨大的厨房沉没物等疯狂。最好只是知道如何做(或者更好地掌握工具,以便您可以控制发生的事情),而不是依靠别人的东西而不知道它会在哪里破裂,因为您不了解和/或想研究它。

通常,不要以您希望使用较少引导程序的简单语言来引导具有相同语言的语言(在这种意义上,引导程序是指运行的代码未使用相同的编译器编译编译器)。这就是为什么C是在汇编中完成的,它没有引导程序要求,您只需从复位后的第一条指令开始即可。JAVA,请确保您可以用C编写jvm并使用asm引导该C,然后如果要使用C来引导该JAVA,但也可以在C中执行该JAVA。

因为我们在这些复制循环上控制假设,所以从定义上讲,它们比手动调整的memcpy / memset更紧密,更干净。

注意您的另一个问题是:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

如果这些是局部的,没问题,如果这些是全局的,则需要首先初始化.data才能使它们工作,如果尝试使用该技巧来执行.data,则您将失败。局部变量,可以正常工作。如果您出于某种原因决定创建静态本地人(我喜欢称它们为本地全局人),那么您又会遇到麻烦。每次您在声明中进行赋值时,您都应该考虑一下它,它是如何实现的以及它是安全/合理的。每次当您声明一个未声明的变量为零时,要进行相同的处理,如果一个局部变量不被假定为零,则如果它是全局变量,则为零。如果您从不认为它们为零,那么您就不必担心。


太棒了,这是我第二次超过答案中的最大字符数....
old_timer 19'Aug8

这个问题属于stackoverflow而非电气工程。
old_timer

同样依赖于您问题中的外部链接的表格也不是很好,如果链接在问题之前就消失了,那么问题可能就没有意义了。
old_timer

在这种情况下,您的标题和内容足以知道您正在尝试在特定的微控制器上引导C并徘徊于.bss和.data初始化
old_timer

但是在这种情况下,该网站被一个信息丰富的网站误导了。
old_timer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.