关于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也许并无此作用。


### 关于Keil Startup文件的信息 #### 用途 Startup文件用于初始化硬件并设置堆栈指针,定义中断向量表以及提供系统启动所需的其他功能。这些文件通常由汇编语言编写,在程序执行前完成必要的准备工作[^1]。 #### 配置 对于基于STM32系列MCU(如CH32F103C8T6)开发的应用项目而言,startup文件一般位于工程目录下的特定路径中,并且需要根据所使用的内核版本选择合适的启动代码。例如,如果使用的是Cortex-M3架构,则应选用对应的`startup_ch32v103.s`或其他相似命名的文件作为项目的入口点。 为了确保正确加载和运行应用程序,还需要在链接脚本里指定该文件的位置及其属性。这可以通过修改`.ld`文件中的输入部分来实现: ```makefile SECTIONS { .isr_vector : { KEEP(*(.isr_vector)) /* 中断向量表 */ } > FLASH ... } ``` 此外,在IDE环境中也需要适当调整一些配置项以便支持此过程。比如,在KEIL uVision中可以按照如下方式进行操作: - 打开目标设备对话框(Target Options),切换到“Output”标签页; - 勾选“Create HEX File”,以确保生成适合烧写的十六进制格式文件; - 切换至“Listing”标签页,确认已启用列表文件(Listing Files)选项,这样可以在构建过程中查看详细的装配指令输出; 最后,记得将上述提到的startup源码加入到工程项目当中去,使其成为整个编译流程的一部分[^2]。 #### 示例 下面给出一段简单的ARM Cortex-M3架构适用的startup汇编代码片段供参考: ```assembly ; startup_ch32v103.s - Minimal startup code for CH32F103C8T6 microcontroller. AREA RESET, DATA, READONLY EXPORT __Vectors THUMB __Vectors DCD _estack ; Top of Stack DCD Reset_Handler ; Reset Handler ... Reset_Handler PROC LDR sp, =_estack ; Set stack pointer to top of RAM BL main ; Call C/C++ program entry point (main function) B . ENDP _estack EQU 0x20000000 + 0x8000 ; Adjust according to actual SRAM size and layout ALIGN END ``` 这段代码实现了基本的功能——设置了初始堆栈位置并将控制权交给主函数(main)。实际应用可能还需增加更多处理逻辑,具体取决于芯片特性和需求[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值