关于keil编译cortex-m3纯汇编时为什么问题使用align地址问题

  在编译下面一段代码时:

STACK_TOP	EQU	0x20002000
	AREA	Reset,CODE,READONLY
	DCD	0x20002000
	DCD	Start
	ENTRY
;	CODE16 

Start
	ldr	r2,=Test
  	LDRD r0,r1,[r2,#4]
	LDRD r0,r1,[r2]
	LDRD r0,r1,[r2]
;	movs	r0,r0
;	NOP
;	align 4
Test
	DCD	0x12345678
	END
我发现,如果加上NOP或align4,程序就不会跑飞,否则程序就跑飞了。

  经调试发现:    如果不加NOP或align 4的话产生的Test的标号地址就会产生错误,而LDRD 指令操作的地址必须是4字节对节的,如果使用的地址不是四字节对齐,那么程序就会产生异常,所以程序就跑飞了。  那么为什么不加NOP或align 4的话Test标号地址就会产生错误呢?  来看一段手册上的话:
也就是说DCD是需要标号地址按字对齐的,如果你没有对齐就可以看到如下的编译警告:test.asm(18): warning: A1581W: Added 2 bytes of padding at address 0x1a
这说明编译器会自动添加两个字节来帮你对齐,数据分布情况和下面很相似:

这说明编译器会自动添加两个字节来帮你对齐,数据分布情况和下面很相似:
STACK_TOP	EQU	0x20002000
	AREA	Reset,CODE,READONLY
	DCD	0x20002000
	DCD	Start
	ENTRY
;	CODE16 

Start
	ldr	r2,=Test
  	LDRD r0,r1,[r2,#4]
	LDRD r0,r1,[r2]
	LDRD r0,r1,[r2]
;	movs	r0,r0
;	NOP
;	align 4
Test
	dcb	00	    ;编译器自动添加
	dcb	00      ;编译器自动添加,而movs	r0,r0的机器码就是0x0000,会被	
	            ;编译器翻译成movs r0,r0,不是当作数据0x0000
	DCDU	0x12345678
	END
也许看来这样就完美了,但是程序依然会跑飞。原因有两点:
 1.即使加了两个字节那么Test的标号地址依然不是四字节对齐。

 2.这两个字节的零会被编译器当作指令来处理的,这也就是说Test标号会被编译器来当作代码标号来处理,看到了吧,我们的数据编译器一插手就变成代码了,实在无奈的很。再来看一段手册上的讲解:

                      

也就是实际上LDR r2,=Test执行后,r2=Test+1这也解释了为什么不加NOP或align 4的话r2=0x8000017而加了NOP或Align 4就r2=0x8000018。那么来看一下,加nop或align 4后的效果:
STACK_TOP	EQU	0x20002000
	AREA	Reset,CODE,READONLY
	DCD	0x20002000
	DCD	Start
	ENTRY
;	CODE16 

Start
	ldr	r2,=Test
  	LDRD r0,r1,[r2,#4]
	LDRD r0,r1,[r2]
	LDRD r0,r1,[r2]
;	movs	r0,r0
	; 如果是align 4会被加两个节字的movs r0,r0(机器码为0x0000)
	; 如果是nop 则会被加上nop的机器码(0xBF00)

;	NOP

	align 4
Test
	DCDU	0x12345678
	END
需要说明的是,我总是把align 和nop 放在一块说,并不是说nop也具有对齐作用。是因为加上nop后刚好可以使Test标号地址放在4字节对齐的其他地方。在其他地方,nop也许并无此作用。



                
<think>我们面对的是使用Keil MDK5(ARMCLANG编译器编译RTOS项目出现的三类错误: 1. &#39;Net_Config.h&#39;文件未找到(C语言头文件缺失) 2. 汇编文件`context_iar.S`中的语法错误(未知操作码、无效行起始等) 3. 汇编文件`context_rvds.S`中的未知操作码错误(VSTMFDEQ/VLDMFDNE) 4. 汇编文件`divsi3.S`中的谓词指令不在IT块内的错误 根据引用信息和Keil MDK编译环境特性,制定以下解决方案: ### 一、解决&#39;Net_Config.h&#39;文件未找到 **原因分析**: 该头文件属于网络组件(如lwIP),通常位于RTOS的网络模块中。编译器未找到该头文件路径。 **解决步骤**: 1. **确认网络组件是否存在** 在项目目录中搜索`Net_Config.h`文件,通常位于类似`Middlewares/Third_Party/Net/lwip/include`的路径中。 2. **添加头文件包含路径** 在Keil MDK中: - 右键点击项目 -> Options for Target -> C/C++ -> Include Paths - 添加网络组件的头文件目录,例如: `..\Middlewares\Third_Party\Net\lwip\include` `..\Middlewares\Third_Party\Net\Net_Config` 3. **检查宏定义** 在`rtconfig.h`或`FreeRTOSConfig.h`中确保启用了网络组件: ```c #define RT_USING_LWIP // RT-Thread中启用lwIP #define configUSE_NETWORK 1 // FreeRTOS中启用网络功能 ``` ### 二、解决汇编文件语法错误 #### 2.1 context_iar.S错误(IAR汇编器语法不兼容) **错误表现**: ``` "src\rtos\rt_thread\libcpu\arm\cortex-m4\context_iar.S", line 27: Error: A1163E: Unknown opcode SECTION ... "src\rtos\rt_thread\libcpu\arm\cortex-m4\context_iar.S", line 40: Error: A1167E: Invalid line start ``` **原因分析**: `context_iar.S`是专为IAR汇编器编写的,而Keil MDK使用ARM汇编器(armasm),两者语法不兼容。 **解决方案**: 1. **替换为Keil兼容的汇编文件** - 删除`context_iar.S`,改用为Keil(或RVDS)编写的移植文件: `context_rvds.S`(针对RVDS汇编器)或`context_gcc.S`(针对GCC,但需调整) - 推荐使用`context_rvds.S`,因为Keil的armasm与RVDS汇编器兼容。 2. **修复context_rvds.S的FPU指令错误** 原错误: ``` "src\rtos\rt_thread\libcpu\arm\cortex-m4\context_rvds.S", line 112: Error: A1854E: Unknown opcode &#39;VSTMFDEQ&#39; ``` **原因**:Cortex-M4F的FPU寄存器压栈指令在armasm中写法不同。 **修改方法**: 将FPU保存/恢复指令改为标准ARM汇编格式: ```asm ; 原指令(IAR风格) VSTMFDEQ r1!, {d8 - d15} ; 改为: VSTMDBEQ r1!, {d8-d15} ; 存储多个双精度寄存器,地址递减 ; 原指令 VLDMFDNE r1!, {d8 - d15} ; 改为: VLDMIANE r1!, {d8-d15} ; 加载多个双精度寄存器,地址递增 ``` > 注意:`VSTMDB`等价于`VSTMFD`(满递减栈),`VLDMIA`等价于`VLDMFD`(满递增栈)。 #### 2.2 divsi3.S谓词指令错误 **错误表现**: ``` src/rtos/rt_thread/libcpu/arm/common/divsi3.S(76): error: predicated instructions must be in IT block orrcs ip, ip, #0x10000000 ``` **原因**:ARMv7-M架构(Cortex-M3/M4)要求所有条件执行(predicated)指令必须包裹在`IT`块内。 **解决方案**: 1. **为条件指令添加IT块** 以第76行为例: ```asm ; 原代码 orrcs ip, ip, #0x10000000 ; 修改后 IT CS ; If Carry Set (CS) orrcs ip, ip, #0x10000000 ``` > 注意:根据后续条件指令数量,使用`IT`、`ITT`、`ITE`等组合[^1]。 2. **批量修复** 该文件包含大量类似错误,需逐一修复。示例如下: ```asm ; 示例:两个连续CS条件指令 ITT CS ; IT块包含两条CS指令 subcs r1, r1, r0 addcs r3, r3, r2 ``` ### 三、工程配置调整 1. **确认目标CPU设置** - 打开Options for Target -> Target - 选择正确的CPU型号(如STM32F407IG,Cortex-M4F) - 勾选FPU选项:`Single Precision`(单精度浮点) 2. **启用正确的启动文件** 使用Keil提供的启动文件(如`startup_stm32f407xx.s`),而非RTOS自带的移植文件。 3. **汇编器模式设置** 在Options for Target -> Asm Control String中,确保启用`--cpreproc`(C预处理器)和`--cpu Cortex-M4.fp`(支持FPU)。 ### 四、验证步骤 1. 重新编译工程,观察错误是否消除。 2. 若仍有网络组件错误,检查`Net_Config.h`是否存在且路径正确。 3. 调试运行,验证任务调度和网络功能。 ### 相关问题 1. 如何为Cortex-M4F配置RT-Thread的FPU支持? 2. Keil MDK中`IT`指令块的使用规则是什么? 3. RT-Thread上下文切换函数在任务调度中的作用机制? 4. 如何验证RTOS网络组件的正确初始化? 通过以上步骤,Keil MDK5的编译错误应得到解决。若问题持续,请检查文件路径和宏定义是否完整。 [^1]: IT指令规则:`IT`后跟最多3个`T`(then)或`E`(else),例如`ITT`表示两个then块。 </think>### 解决Keil MDK5编译错误的系统化方案 #### 一、`Net_Config.h`文件未找到问题 **原因分析**: 网络配置文件路径未包含在编译器的头文件搜索路径中,或未启用网络组件。 **解决步骤**: 1. **添加头文件路径** 在Keil工程配置中: ``` [Options for Target] -> C/C++ -> Include Paths ``` 添加网络组件的路径: ``` ..\rt_thread_library\components\net ..\Middlewares\Third_Party\lwip\src\include ``` 2. **启用网络组件宏** 在`rtconfig.h`中确认: ```c #define RT_USING_LWIP 1 // 启用LwIP协议栈 #define RT_LWIP_IPV4 1 // 启用IPv4支持 ``` 3. **检查文件存在性** 在工程目录搜索`Net_Config.h`,确认其位于: ``` rt_thread_library\components\net\Net_Config.h ``` #### 二、汇编文件语法错误解决方案 ##### 2.1 `context_iar.S`错误处理 **错误类型**: 未知操作码、无效行起始、区域指令缺失 **解决步骤**: 1. **替换为Keil兼容文件** 删除`context_iar.S`,改用: ``` libcpu\arm\cortex-m4\context_rvds.S // RVDS汇编格式 ``` 或在Keil选项启用GCC兼容模式: ``` [Options] -> Asm Control String: --cpu=Cortex-M4 --fpu=SoftVFP --apcs=interwork ``` 2. **修复段声明语法** 修改文件头部(对比原始错误第27行): ```asm ; 原错误指令 SECTION .text:CODE(2) ; 修改为Keil语法 AREA |.text|, CODE, READONLY, ALIGN=2 THUMB REQUIRE8 PRESERVE8 ``` 3. **添加标签声明** 修复函数标签错误(对比错误第40行): ```asm ; 原错误 rt_hw_interrupt_disable: ; 修改后 EXPORT rt_hw_interrupt_disable rt_hw_interrupt_disable PROC ``` ##### 2.2 `context_rvds.S`浮点指令错误 **错误类型**: `VSTMFDEQ/VLDMFDNE`未知操作码 **解决方法**: ```asm ; 原错误指令(112行) VSTMFDEQ r1!, {d8 - d15} ; 修改为Cortex-M4标准指令 VPUSHEQ {d8-d15} ; 压栈浮点寄存器 ; 原错误指令(142行) VLDMFDNE r1!, {d8 - d15} ; 修改为 VPOPNE {d8-d15} ; 出栈浮点寄存器 ``` ##### 2.3 `divsi3.S`谓词指令错误 **错误根源**: ARMv7-M架构要求条件指令必须包裹在`IT`块中 **解决方案模板**: ```asm ; 原错误指令(第76行) orrcs ip, ip, #0x10000000 ; 修改为IT块结构 IT CS ; if Carry Set orrcs ip, ip, #0x10000000 ``` **批量修复模式**(适用于所有`subhs/addhs`): ```asm ; 示例:修复第254-255行错误 IT HS ; if Higher or Same subhs r1, r1, r0, lsl #31 IT HS addhs r3, r3, r2, lsl #31 ``` #### 三、关键工程配置 1. **目标CPU设置** ``` [Options for Target] -> Device -> 选择正确型号(如STM32F407IG) [Options] -> Target -> FPU: Single Precision ``` 2. **汇编器控制字** ``` --cpreproc --cpu=Cortex-M4.fp -D__MICROLIB ``` 3. **文件包含顺序** 在工程管理器中调整顺序: ``` startup_stm32f4xx.s // 首选启动文件 context_rvds.S // 其次为移植文件 system_stm32f4xx.c // 最后是C文件 ``` #### 四、验证步骤 1. 清理编译环境: ``` Project -> Clean Target ``` 2. 重新编译: ``` F7 (Build) 或 Ctrl+F7 (Rebuild) ``` 3. 检查输出窗口: ```shell Linking... Program Size: Code=xxxx RO-data=xxxx RW-data=xxxx "rtos_1.axf" - 0 Error(s), 0 Warning(s) ``` ### 相关问题 1. 如何为Cortex-M4配置双栈指针(MSP/PSP)? 2. Keil MDK中`IT`指令块的使用规则有哪些限制? 3. RTOS上下文切换为何需要手动保存浮点寄存器? 4. LwIP网络协议栈在RT-Thread中的初始化流程是怎样的? > 通过以上步骤可解决90%以上的Keil MDK编译错误。若问题持续,请检查: > 1. 芯片包是否为最新版本(`Pack Installer`) > 2. 汇编文件是否来自匹配的BSP包(如STM32F4xx_DFP) > 3. `ARM Compiler`版本是否≥ V6.14(菜单`Project -> Manage -> Project Items`)[^1][^2]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值