如果我为Cortex-M4(LPC4357)编译GCC项目并使用-mcpu = cortex-m4,则开关浮点数不起作用(调用blx __addsf3,最终分支到stmia命令,这会导致错误中断,可能是由于错误的值在寄存器中).如果我使用-mcpu = cortex-m3进行编译,则会调用bl __addsf3,它具有不同的源并且有效.
我想我可能必须修复其他开关才能使浮点数与-mcpu = cortex-m4一起工作......我尝试了几件事,但这真的很奇怪.
相关的编译器和链接器开关:
编译器:-mthumb -mcpu = cortex-m4 -std = c99 -c -g -D DEBUG -D gcc
链接器:-nostartfiles -nostdlib -nodefaultlibs -fno-exceptions -mthumb -mcpu = cortex-m4 -mfloat-abi = hard -mfpu = fpv4-sp-d16 -O0 -lgcc -lc
你能告诉我在这里是否遗漏了一些明显的东西吗?
我一直在寻找ARM Cortex M3/M4/M4F中使用的操作码列表,没有运气.
有很多[在线]参考32位格式的ARM指令.
对Thumb-2指令的引用很少,但可用.
在-M变种中使用的版本,但是,我找不到!
ARM技术参考手册有一个"程序员模型"部分,其中列出了指令,每个指令的周期......但没有实际代码.
我找到了一个"权威指南",它有同样的问题.
信息必须在某处 - 你需要它来编写编译器.
我应该在哪里看?
对于电源转换应用,我们需要在ARM Cortex-M4平台上尽快进行各种浮点计算.
我们正在与Keil uVision合作开发.
我们想将一些变量声明为寄存器变量,但只能得到编译器的错误.
看起来这是非常有用的,因为FPU有32个寄存器,我们可以通过将数据存储在这些寄存器中而不是每次调用ISR时从RAM重新加载来节省大量周期.
我们尝试使用:
register float a1 __asm__("s0");
Run Code Online (Sandbox Code Playgroud)
但收到错误:未知的注册名称"s0"
这看起来很奇怪,因为在调试器接口中我可以看到编译器正在使用s0寄存器.如果我将寄存器声明为"r0",则没有错误,所以似乎某些地方缺少FPU支持,但不确定在哪里.
我看看Assembler控件字符串,似乎支持浮点:
--cpu Cortex-M4.fp --pd "__EVAL SETA 1" -g --apcs=interwork
-I D:\my_project
-I D:\Keil_v5\ARM\PACK\ARM\CMSIS\4.4.0\CMSIS\Include
Run Code Online (Sandbox Code Playgroud)
我们还尝试过:
__global_freg(1) float a1;
Run Code Online (Sandbox Code Playgroud)
这也不起作用.
有任何想法吗?
我使用嵌入式系统.通常这意味着我有一个小型微控制器,具有64 - 512 KB的RAM和128 - 1024 KB的闪存,如STM32.我更喜欢使用C++来编程这样的系统.但我还没有找到可接受的方法来处理常见的数据结构,如堆栈,队列,地图等.
当然,STL具有所有这些以及许多其他方便的东西,但是大多数STL容器需要支持异常和动态内存分配,这在嵌入式编程中通常是不合需要的.
我知道我们可以通过使用自定义分配器来避免这个问题,我们可以从静态对象池或类似的东西中分配内存.然而,我看到的主要问题是,当没有足够的分配空间将新元素插入容器时,我们无法可靠地处理这种情况.STL和我见过的其他类似stl的库提出了两个选择:
回调.好一点,但对我来说还不方便.
q.push(newElem); /* fails or just calls predefined callback
* when not enough space in queue.
*/
Run Code Online (Sandbox Code Playgroud)也许我错了.但在我看来,最好的方法是返回状态,通知调用者它没有足够的内存容器中的新元素.我想自己决定如何处理这个错误.例如,我想删除新元素,向调试日志发送消息并恢复正常的程序流.从我的角度看,它看起来更可靠.
换句话说,我想有这样的事情:
queue<uint32_t, 128> q;
// some code ...
queue::status sts = q.push(newElem);
if (sts != queue::OK)
LOG("Not enough space in queue\r\n");
// continue normal program execution ...
Run Code Online (Sandbox Code Playgroud)
有人建议如何处理那件事?
我正在尝试在C中编写一个概念证明,演示ARM Cortex-M3上堆栈中的内存缓冲区的代码执行.这将有助于证明正确使用ARM MPU可以防止此类攻击.我想一个快速而肮脏的方法来将一些代码放入堆栈中是从常规函数中复制它然后使用goto跳转到它,如下所示:
static void loopit(void)
{
printf("loopit\n");
while (1);
}
void attack(void)
{
uint8_t buffer[64] __attribute__((aligned(4)));
memcpy(buffer, loopit, sizeof(buffer));
goto *((void *) (int) buffer);
}
Run Code Online (Sandbox Code Playgroud)
我希望当我调用攻击函数时,它会将代码复制到堆栈中,跳转到它,打印消息并进入无限循环.但是,我在故障寄存器中使用以下值获得异常:
HFSR = 0x40000000
CFSR = 0x00020000
PSR = 0x60000000
Run Code Online (Sandbox Code Playgroud)
这似乎是UFSR中的INVSTATE位,表示"非法使用EPSR",我读到的通常是由于BX指令试图跳转到LSB设置为0的地址,处理器将其解释为函数其中包含非Thumb代码,但Cortex-M处理器仅允许Thumb代码.我看到memcpy被赋予了loopit函数的奇数地址,因为我假设编译器正在使用实际内存地址进行ORing 1.所以我认为解决方法是重写我的攻击函数,如下所示:
void attack(void)
{
uint8_t buffer[64] __attribute__((aligned(4)));
memcpy(buffer, ((int) loopit) & ~1, sizeof(buffer));
goto *((void *) ((int) buffer) | 1);
}
Run Code Online (Sandbox Code Playgroud)
但是在这之后我得到了一个与故障寄存器不同的异常:
HFSR = 0x40000000
CFSR = 0x00080000
PSR = 0x81000000
Run Code Online (Sandbox Code Playgroud)
这似乎没有任何意义,UFSR第3位设置意味着"处理器已尝试访问协处理器".看看PC,这次看起来跳跃成功了,这很好,但后来有些东西掉了轨道,CPU看起来正在执行奇怪的指令,而不是进入无限循环.我尝试在goto之前关闭中断并注释掉printf,但没有运气.有什么问题以及如何使其发挥作用?
我正在使用GCC为Cortex M7编译此代码:
// copy manually
void write_test_plain(uint8_t * ptr, uint32_t value)
{
*ptr++ = (u8)(value);
*ptr++ = (u8)(value >> 8);
*ptr++ = (u8)(value >> 16);
*ptr++ = (u8)(value >> 24);
}
// copy using memcpy
void write_test_memcpy(uint8_t * ptr, uint32_t value)
{
void *px = (void*)&value;
memcpy(ptr, px, 4);
}
int main(void)
{
extern uint8_t data[];
extern uint32_t value;
// i added some offsets to data to
// make sure the compiler cannot
// assume it's aligned in memory
write_test_plain(data …Run Code Online (Sandbox Code Playgroud) 我目前正在为Arm Cortex-M0 +微控制器开发固件,并且面临一个相当有趣的问题。我不是在寻找任何答案,而是想与其他开发人员分享问题,以便我(希望)对我所面临的问题有所了解。我将在下面描述它:
我有一个程序可以从外部闪存芯片动态加载(正确编译和链接)代码,然后直接在MCU RAM中执行。有趣的是,当逐步(通过调试器)运行时,我可以完美地执行RAM加载的代码,但是在自由运行时,它总是会崩溃(正式为HardFault)。我试图禁用所有中断,我仔细检查了指令,内存地址,字节对齐方式以及所有内容,但是我仍然无法查明异常的原因。
你们中有人对可能发生的事情有任何暗示吗?我非常想知道更多有关您的经历!谢谢,
更新1(30/05)
在这种情况下,自由运行意味着在分支到RAM之前不设置断点。每当我进入分支并在RAM中执行指令时,它将正确运行并返回。无论断点不在哪里(因此MCU都会通过分支进行缩放),都会观察到HardFault。请注意,即使在调试器启动但未设置断点的情况下启动,它也会崩溃。
更新2(30/05)
我正在使用Cypress S6E1C3系列Arm Cortex M0 + FM0 +微控制器。
更新3(30/05)
深入研究并使用代码后,我可以使其正常工作!但是,它给我带来的问题多于答案。阅读有关BLX指令(BLX)的ARM官方文档后,我发现分支地址的LSBit 确定了CPU指令模式(1导致它以Thumb模式运行)。通过显式设置该位,即使在自由运行模式下,我也可以使代码始终运行。事实是,RAM中的代码尚未在Thumb模式下进行编译,并且没有明显的原因说明为什么使用调试器逐步运行代码会导致指令模式发生变化...有什么想法吗?
K.
请参阅以下objdump特定功能的特定目标文件的行(func):
3c: e03a b.n 78 <func+0x78>
Run Code Online (Sandbox Code Playgroud)
现在,e03a目标系统(ARMv6-M)中的操作码显示跳转到的位置PC + 0x78。正确的解释是:
3c: e03a b.n B4 <func+0xB4>
Run Code Online (Sandbox Code Playgroud)
每个其他函数和文件都包含正确的b.n解释,并在其objdump转储中包含正确的值计算。由于某些原因,仅此功能会导致objdump“混淆”。
注意:func从开始0x0。
我无法想到这种情况的任何原因。而且由于我具有解析和使用objdump转储的工具,因此这对我造成了很大的问题。有什么合理的理由吗?
工具链: gcc-arm-none-eabi-4_9-2015q3
运行此工具链的平台: Ubuntu 16.04.2 LTS
编辑:我附加部分转储:
Disassembly of section i.func:
00000000 <func>:
0: b531 push {r0, r4, r5, lr}
2: b088 sub sp, #32
4: 2100 movs r1, #0
6: 9106 str r1, [sp, #24]
8: 482c ldr r0, [pc, #176] …Run Code Online (Sandbox Code Playgroud) ARM Cortex-M内核文档说,在执行异常条目堆栈框架时.这导致寄存器R0,R1,R2,R3,R12,LR,PC,xPSR被推到当前堆栈上.我的问题是为什么这种方式只推动那些寄存器而不是所有的上下文?例如,如果某些数据位于R5寄存器中,则异常处理程序使用该寄存器时将覆盖该数据.
异常处理程序本身的编译函数会推送一些寄存器(以及所有其他常规函数,因为异常处理函数没有区别),但经过大量调试后我发现事实并非总是如此,因为不同的变体寄存器被推送然后恢复.
我正在研究运行 Cortex-M4 处理器和 ARM/Thumb 指令集的 STM32l475 微控制器。我看(从objdump),有beq.n和bne.n在一个ARM程序的二进制生成的指令(I添加-mthumb标志编译该程序时)。但是,我在最新的ARMv7-M手册中没有找到这些分支指令。
谁能告诉我原因?以及手册中与这两条分支指令等效的指令有哪些?