汇编代码要注意有些要顶格,有些要加空格,不然编译会有问题
(一)堆的设置问题
在发动代码 B__mian指令后,程序没有跳到main函数处,而是进入了异常中止。
原因:经过反汇编,能够看到,在履行B__mian指令后,并不是当即跳到main函数处,而是先跳到__main库函数进口,再履行一些仓库的复制等初始化操作,最终跳到main函数处。出现异常,或许是堆或栈的设置有问题。(在一个比方中发现把堆得开端地址改小就能够了)
(二)ARM在RAM中调试问题
IROM1:0x4000000 0x10000 (有必要将IROM1地址设置到RAM空间)
IRAM1:0x4010000 0x8000
RAM.ini 文件中
PC = 0x04000000;
(三)怎么指定某段代码的运转空间
挑选该文件(*.c),鼠标右键(options for File *.c)—->Memory Assignment 可指定该文件代码运转的空间(能够运转在FLASH,也能够指定在RAM)
(四)MDK生成bin文件
能够用ARM自带的fromelf.exe将*.axf文件转换成*.bin文件
Options for Target—->user—->run #1—–>
C:/Keil/ARM/BIN31/fromelf.exe –bin -o ./output/Axf_To_Bin.bin ./output/Axf_To_Bin.axf
(四)编译后的代码意义
Program Size: Code=2356 RO-data=32 RW-data=28 ZI-data=1292
================================================================================
Total RO Size (Code + RO Data) 2388 ( 2.33kB)
Total RW Size (RW Data + ZI Data) 1320 ( 1.29kB)
Total ROM Size (Code + RO Data + RW Data) 2416 ( 2.36kB)
================================================================================
Execution Region RW_IRAM1 (Base: 0x04000000, Size: 0x00000528, Max: 0x00018000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x04000000 0x0000001c Data RW 89 .data main.o
0x0400001c 0x00000004 PAD
0x04000020 0x00000508 Zero RW 1 STACK str91x.o
Code表明程序代码量
RO-data 表明固定常量(const 变量)
RW-data 表明初始化常量(char gloab_test =5)
ZI -data 表明未初始化初始化常量,便是零(char gloab_test =0)
烧写到FALSH的空间:Code + RO Data + RW Data
RAM空间: RW Data + ZI Data
发动代码中,显然有个RW Data 复制进程,其实还应该包含初ZI -data 清零进程,堆和栈的初始化进程,这些应该在B__mian指令后完结,只要经过反汇编能够看到
(五)未对齐的数据指针
C和C++编程规范规则,指向某一数据类型的指针,有必要和该类型的数据地址对齐方法共同,所以ARM 编译器希望程序中的 C 指针指向存储器中字对齐地址,由于这可使编译器生成更高效的代码。
比方,假如界说一个指向 int 数据类型的指针,用该指针读取一个字,ARM 编译器将运用LDR 指令来完结此操作。假如读取的地址为四的倍数(即在一个字的鸿沟)即能正确读取。可是,假如该地址不是四的倍数,那么,一条 LDR 指令回来一个循环移位成果,而不是履行真实的未对齐字载入。循环移位成果取决于该地址向关于字的鸿沟的偏移量和体系所运用的端序(Endianness)。例如,假如代码要求从指针指向的地址 0x8006 载入数据,即要载入 0x8006、0x8007、0x8008 和 0x8009 四字节的内容。可是,在 ARM 处理器上,这个存取操作载入了0x8004、0x8005、0x8006 和 0x8007 字节的内容。这就是在未对齐的地址上运用指针存取所得到的循环移位成果。
因此,假如想将指针界说到一个指定地址(即该地址为非自然鸿沟对齐),那么在界说该指针时,有必要运用 __packed 限制符来界说指针: 例如,
__packedint *pi; // 指针指向一个非字对其内存地址
运用了_packed限制符限制之后,ARM 编译器将发生字节存取指令(LDRB或STRB指令)来存取内存,这样就不必考虑指针对齐问题。所生成的代码是字节存取的一个序列,或许取决于编译选项、跟变量对齐相关的移位和屏蔽。但这会导致体系功能和代码密度的丢失。
值得注意的是,不能运用 __packed 限制的指针来存取存储器映射的外围寄存器,由于 ARM 编译程序可运用多个存储器存取来获取数据。因此,或许对实践存取地址邻近的方位进行存取,而这些邻近的方位或许对应于其它外部寄存器。当运用了位字段(Bitfield)时, ARM 程序将拜访整个结构体,而非指定字段。
(六) Ro Base设置
链接文件选项中,应将映像文件的Ro Base地址设置到映像文件实践运转的开端地址。例如,将Ro Base设置成0x30000000,把它下载到0x0地址开端履行是不正确,有必要将该代码复制到0x30000000开端地址处才干开端正确履行,或许将Ro Base 设置到0x0地址
(七)__irq关键字
汇编调用C中止函数
汇编文件相关代码(*.s)
IMPORT IRQ_Handler ;不能顶格写
IRQ_Addr DCD IRQ_Handler
C文件相关代码(*.c)
__irq void IRQ_Handler (void) {
if (IRQSIG & 0x00000004) { // Timer 0 Interrupt
T0CLRI = 1; // Clear Timer 0 Interrupt
T0_Tick++; // Increment Timer 0 Tick
}
}
“__irq”专门用来声明IRQ中止服务程序,假如用“__irq”来声明一个函数,那么该函数表明一个IRQ中止服务程序,编译器便会主动在该函数内部添加中止现场维护的代码