在ARM cortex m0中,第一条指令是什么?

时间:2015-04-27 05:03:25

标签: assembly arm cortex-m machine-language

我正在尝试学习使用cortex m0处理器。我有一个stm32f0开发板,可以让我查看每个地址的每一位并轻松上传一个新的二进制文件。我一直在阅读一些学习很多规则和功能的手册,但仍然不知道程序计数器在重置时的起始位置,它所期望的参数类型,我甚至不知道如何编写类似添加的内容或二进制形式的str / ldr。 我读过的手册中是否遗漏了这些基本知识?

它说m0有一个完整的下降堆栈,但似乎建议起点位于另一端(0x00000000)。如果一个向量表可以用非专业人士的术语来解释那就太棒了。

2 个答案:

答案 0 :(得分:4)

全尺寸臂(cortex-A等)地址0x00000000例如是自身执行的复位指令,有点奇怪,你经常会看到一个地址列表,但这就是他们这样做的方式。对于cortex-m,它们不仅使用地址列表,而且硬件设计符合EABI,因为它允许您将C函数名称放在表中而不必进行少量组装(除了向量表之外)本身)。

例如,使用gnu汇编程序。

;@-----------------------
.cpu cortex-m0
.thumb
;@-----------------------

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang
.thumb_func
hang:   b .

在深入研究之前,您需要访问目前位于infocenter.arm.com的内容,然后在架构下,然后使用armv6-m获取armv6-m体系结构参考手册(适用于v6m的ARM ARM)。这些链接已经存在了很长时间,但自然可以改变,他们确实称之为并且区分了建筑参考手册和技术参考手册。体系结构参考手册通常涵盖该体系结构中的系列。 TRM通常涵盖特定核心的特定核心或修订号。可能值得在信息中心页面的其他地方获得。

我正在考虑我所假设的armv6m ARM ARM的rev C:ARM DDI 0419C

搜索"向量表"在文档中找到可能或可能不在同一部分的内容:

表B1-4向量表格式

此表显示地址空间中的偏移0为SP_main。这是主堆栈指针的重置值。

之后,表中的字偏移是异常编号,在arm世界中字是4个字节,因此异常编号1在地址空间中偏移4,异常2在8处,依此类推。

总是需要一段时间才能找到。也在armv6m手臂上。

  

B1.5.2例外号码定义

异常号1复位2是nmi,依此类推。我们关心重置。

这意味着在ARMS ADDRESS SPACE的地址0x00000000处我们可以选择预先加载堆栈地址,如果我们想在bootstrap代码中也设置堆栈,我们可以不用,一个地方必须做到但不是两个。

然后在ARMS ADDRESS SPACE的地址0x00000004处,我们放置了重置处理程序的地址。

所以在组装,编译和链接我的例子中的代码之后我得到了

Disassembly of section .text:

08000000 <_start>:
 8000000:       20001000        andcs   r1, r0, r0
 8000004:       08000041        stmdaeq r0, {r0, r6}
 8000008:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 800000c:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000010:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000014:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000018:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 800001c:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000020:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000024:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000028:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 800002c:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000030:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000034:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 8000038:       08000047        stmdaeq r0, {r0, r1, r2, r6}
 800003c:       08000047        stmdaeq r0, {r0, r1, r2, r6}

08000040 <reset>:
 8000040:       f000 f80a       bl      8000058 <notmain>
 8000044:       e7ff            b.n     8000046 <hang>

08000046 <hang>:
 8000046:       e7fe            b.n     8000046 <hang>

你可以看到,在gnu汇编程序放置.thumb_func的情况下,在标签之前将该标签作为一个函数或地址,因此可以调用bx或blx指令,因此需要设置bx或blx需要的lsbit正确分支(bl不关心)。链接器自动修复向量表中的地址。例如,在偏移量0x40处复位获得0x41。

现在为什么这个代码不是为地址0x00000000构建的?!那是因为你必须超越arm文档到芯片供应商文档,arm不制作芯片他们制作处理器核心和一些逻辑来支持它们,你去st或nxp或ti或任何人找到其余的故事特别是地址空间中的bootflash在哪里。毫无疑问,在这种情况下,正常启动的臂地址空间中的地址0x08000000处的压力被映射到0x00000000,一些芯片将具有多个启动闪存并且取决于带(输入引脚连接高或低或各种组合)一个闪存或另一个闪存将被永久地或在一段时间内映射到地址零。

皮质m0(和m1)是基于皮质m3的armv6m,m4是基于armv7m的。巨大的区别后者支持拇指指令集的thumb2扩展(以前未定义的指令成为两个半字指令32位指令的前半部分,不要与32位臂模式指令混淆)并且有大约150个左右的新thumb2指令添加到皮质m3然后皮质m4有一个浮点单位的一小部分(只有一个浮点大小,可能是单个)和所有随附的指令(基本上是coproessor指令重新定义)。这使得cortex-m0的生活更容易,只有16位指令(是的,bl实际上是在文档中定义为两个独立的指令,如果你愿意,你可以分别编码)。

目前armv6m ARM ARM还包含指令集定义

  

第A5章Thumb指令集编码

看着

A6.7.17 CMP (immediate)

(我的部分编号可能不会保持不变或将来匹配,他们的文档通常不会发生太大变化或从一个变化到下一个,但你永远不会知道)。

首先要注意的是编码

Encoding T1 All versions of the Thumb instruction set.

这意味着支持拇指的每个人都支持这个指令(从armv4回到现在)

然后是语法

CMP <Rn>,#<imm8>

统一语法可能与此文档语法不同,也理解ARM有自己的工具链,因此定义的语法特定于其汇编程序。汇编语言不是汇编程序专门定义的标准,汇编程序是解析它的程序。 Gnu汇编程序是一个单独的东西,不必遵循这个文档,它主要是这样,但arm也启动了这个统一的语法,允许一定比例的汇编语言汇编到thumb,thumb2扩展和arm指令集而无需重写,如果你没有指定三者中的哪一个,你仍然可以很快地绑好你的双手。

你可以在这条指令中看到高位必须是00101位15:11,这就是处理器知道这是比较立即的方式。 Rn是寄存器r0到r7,无论你使用哪一个(要访问r8到r15,你必须使用其他mov指令允许16位指令,他们必须将大多数指令保存到较低的7个寄存器以保存指令编码中的位) 。然后低8位是从0到255的直线常数值(其他手臂/拇指立即编码不是那么直接,拇指与手臂使用不同的编码,所以你必须阅读手册)。

我强烈建议如果你想看到编码然后用汇编语言汇编然后反汇编,让希望调试的工具链为你完成工作,然后尝试对你看到的内容进行反向工程并将其与手册相匹配。头部刮擦器是奇怪的地址,但是这些是有记录的(虽然不一定是你希望的)然后是任何相对的pc,当你用它做什么时,电脑是两个指令,它不是真的有管道,但是反向兼容性并设置一个标准,即arm / thumb标准是前面的两条指令。因此,在计算或逆向工程计算pc相对地址时,这就是数学总是关闭4个字节的原因。

与大多数处理器一样,程序员或至少你信任的程序员借用他们的代码就是设置堆栈指针的程序员。你可以把它放在你想要的地方,arm核心本身,也不知道芯片供应商将如何处理实现,也不知道编译器真的知道或想知道所有可能的芯片,所以你程序员必须告诉工具链,然后告诉臂处理器你想要堆栈的位置。传统上使用降序堆栈,您希望从高地址开始。首先看一下pop和push指令以及伪代码,看看arm首先按寄存器数量递减4次(推送),然后写入这些地址,然后在出路时调整sp。因此,如果你的ram以0x2001FFFF结束,你可以安全地将你的堆栈指针放在0x20020000,推送的第一件事就是0x2001FFFC。 (好吧不是第一件事,但堆栈的底部是那里)其他非臂处理器工作方式不同,有不同的规则,有些你根本无法得到堆栈指针,有些你可以,但重置值是正确的,有些像你需要担心的武器。完整大小的手臂你有多个堆栈指针可以管理,你也可以让堆栈上升或下降,虽然我不会因为你可以反对谷物。

答案 1 :(得分:3)

对于所有Cortex-M,存储器映射中的前两个字(分别在地址0和4处)应该是您的初始堆栈指针和您想要开始执行的第一条指令的地址。

通常情况下,您将堆栈放在可用的最高RAM地址,并使用链接描述文件在地址4的程序的入口点地址。