C代码调用一个汇编例程 - ARM

6

我目前正在为ARM Cortex M3开发一个引导加载程序。

我有两个功能,一个是用C编写的,另一个是用汇编语言编写的,但是当我尝试调用汇编函数时,我的程序会挂起并生成某种故障。

这些函数如下:

C:

extern void asmJump(void* Address) __attribute__((noreturn));

void load(void* Address)
{
    asmJump(Address);
}

组装:

.section .text

.global asmJump

asmJump:                   @ Accepts the address of the Vector Table
                           @ as its first parameter (passed in r0)

    ldr r2, [r0]           @ Move the stack pointer addr. to a temp register.
    ldr r3, [r0, #4]       @ Move the reset vector addr. to a temp register.

    mov sp, r2             @ Set the stack pointer

    bx  r3                 @ Jump to the reset vector

我的问题是这样的:
代码通过串口打印“Hello”,然后调用load。被加载的代码打印“Good Bye”,然后重置芯片。
如果我在load调用asmJump的部分慢慢步进,一切都正常。然而,当我让代码运行时,我的代码会出现一个“内存故障”。我知道这是一个内存故障,因为它以某种方式导致了一个“硬故障”(当我暂停4或5秒后,硬故障处理程序的无限循环正在执行)。
有人之前遇到过这个问题吗?如果是这样,请告诉我如何解决它。
正如你所看到的,我已经尝试使用函数属性来解决这个问题,但还没有找到解决方案。我希望有人能帮助我理解首先出现的问题是什么。
编辑:
感谢 @JoeHass 的回答,以及 @MartinRosenau 的评论。我后来找到了一个非常详细的解释,说明为什么我需要这个标签,链接在这里:this SO answer。虽然内容很长,但是非常值得一读。

1
如果您为引导加载程序和应用程序设置了不同的中断例程:您是否已禁用中断并将VTOR(向量表偏移寄存器)替换为第二个程序的向量表?在设置堆栈指针之前应完成此操作。 - user694733
2
  1. 你确定堆栈指针是正确的吗?
  2. 如果你的代码是 THUMB 代码,那么 r3 必须不是代码地址而是代码地址加 1!
- Martin Rosenau
1
在调用之前尝试刷新写缓冲区数据缓存指令缓存。你是从别处复制的代码吗?这听起来像是一个代码 != 数据问题或者流水线效应;这也解释了为什么在调试器中暂停时它能够工作。 - artless noise
@user694733 我没有禁用中断,但你说得对,我应该这样做。不过,一旦中断被服务,它应该返回到它之前执行的代码,即我的复位向量。 - nonsensickle
1)堆栈指针从向量表中检索,该向量表由链接器生成,因此我有信心它是正确的。2)这正是问题所在,Joe Hass的答案帮助我意识到了这一点。 - nonsensickle
@artlessnoise 我确实尝试使用 dsbisb 指令,但它们并不是问题所在。这是一个非常愚蠢的错误。我只是不知道如果链接器没有 .thumb_func 标志,我的汇编代码就不会被视为 Thumb 代码。 - nonsensickle
3个回答

8

我认为您需要告诉汇编器使用统一语法,并明确声明您的函数是一个thumb函数。 GNU汇编器有相应命令:

  .syntax unified
  .section .text
  .thumb_func
  .global asmJump
asmJump:
.syntax unified 指令告诉汇编器您正在使用现代汇编代码语法。我认为这是一些旧语法的不幸遗留物。 .thumb_func 指令告诉汇编器该函数将在Thumb模式下执行,因此用于符号 asmJump 的值其LSB设置为1。当Cortex-M执行分支时,它会检查目标地址的LSB是否为1。如果是,则目标代码将在Thumb模式下执行。由于这是Cortex-M唯一支持的模式,因此如果目标地址的LSB为0,则会发生故障。

成功了!我要去找一下为什么会成功,但是如果您能够耐心地详细解释一下,那对我来说将会非常有帮助。无论如何,您解决了我的问题,谢谢! - nonsensickle
1
再次感谢。我在另一个SO问题中找到了解释:https://dev59.com/vGox5IYBdhLWcg3wNBjS - nonsensickle
我尝试过在没有.syntax unified的情况下运行代码,但似乎失败了。我不确定为什么会这样。如果您有解释,请在您的答案中包含它。 - nonsensickle
1
对于那些来自x86的人:ARM在运行blxcall)指令时同时切换Thumb指令编码的开/关。这就是为什么.thumb_funct是每个函数的事情。 - Ciro Santilli OurBigBook.com

1

既然您提到了调试器可以工作,那就使用它吧!

查看故障状态寄存器以确定故障来源。也许不是asmJump崩溃,而是您调用的代码。


谢谢,我会的。我正在设置我的错误处理程序以便能够定位错误。 - nonsensickle

0

如果这是你的全部代码...我猜测你的SP更改导致了段错误或类似的问题。在更改之前,你应该保存你的SP,并在使用后恢复它。

ldr r6, =registerbackup
str sp, [r6]
#your code
...
ldr r6, =registerbackup
ldr sp, [r6]

通常情况下,您是正确的。但由于这是一个引导加载程序,我故意设置堆栈指针而没有备份选项。新的堆栈指针地址是我从正在尝试加载的代码的向量表中读取的。如果我没有表达清楚,对不起。 - nonsensickle
所以问题是一个手臂调用了一个拇指函数。就是这样。太好了,你找到了根本原因。 - TwoCode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接