目录
title: C函数调用
tags: ARM date: 2018-10-14 16:37:10 ---C函数调用
设置SP
C函数启动需要设置堆栈,因为局部变量都是存在堆栈的,函数调用也需要栈
但是2440中NAND启动和NOR启动的时候,片内RAM的地址是不一样的.
- NOR,0x4000,0000+4K
- NAND,0+4K
SP分析
从NAND启动的代码分析
//start.S//.text.global _start_start: /* 设置内存: sp 栈 */ ldr sp, =4096 /* nand启动 */ //ldr sp, =0x40000000+4096 /* nor启动 */ /* 调用main */ bl mainhalt: b halt///main.c///int main(){ unsigned int *pGPFCON = (unsigned int *)0x56000050; unsigned int *pGPFDAT = (unsigned int *)0x56000054; /* 配置GPF4为输出引脚 */ *pGPFCON = 0x100; /* 设置GPF4输出0 */ *pGPFDAT = 0; return 0;}//makefile/all: arm-linux-gcc -c -o led.o led.c arm-linux-gcc -c -o start.o start.S arm-linux-ld -Ttext 0 start.o led.o -o led.elf arm-linux-objcopy -O binary -S led.elf led.bin arm-linux-objdump -D led.elf > led.disclean: rm *.bin *.o *.elf *.dis
查看下反汇编的代码
led.elf: file format elf32-littlearmDisassembly of section .text:00000000 <_start>: 0: e3a0da01 mov sp, #4096 ; 0x1000 4: eb000000 bl c00000008 : 8: eafffffe b 8 0000000c : c: e1a0c00d mov ip, sp 10: e92dd800 stmdb sp!, {fp, ip, lr, pc} 14: e24cb004 sub fp, ip, #4 ; 0x4 18: e24dd008 sub sp, sp, #8 ; 0x8 1c: e3a03456 mov r3, #1442840576 ; 0x56000000 20: e2833050 add r3, r3, #80 ; 0x50 24: e50b3010 str r3, [fp, #-16] 28: e3a03456 mov r3, #1442840576 ; 0x56000000 2c: e2833054 add r3, r3, #84 ; 0x54 30: e50b3014 str r3, [fp, #-20] 34: e51b2010 ldr r2, [fp, #-16] 38: e3a03c01 mov r3, #256 ; 0x100 3c: e5823000 str r3, [r2] 40: e51b2014 ldr r2, [fp, #-20] 44: e3a03000 mov r3, #0 ; 0x0 48: e5823000 str r3, [r2] 4c: e3a03000 mov r3, #0 ; 0x0 50: e1a00003 mov r0, r3 54: e24bd00c sub sp, fp, #12 ; 0xc 58: e89da800 ldmia sp, {fp, sp, pc}Disassembly of section .comment:00000000 <.comment>: 0: 43434700 cmpmi r3, #0 ; 0x0 4: 4728203a undefined 8: 2029554e eorcs r5, r9, lr, asr #10 c: 2e342e33 mrccs 14, 1, r2, cr4, cr3, {1} 10: Address 0x10 is out of bounds.
main函数的流程
- 保存sp
- 保存lr和pc,以及会被改变的寄存器的值
- 数据处理完后把寄存器恢复
汇编解析
LDMED LDMIB 预先增加装载LDMFD LDMIA 过后增加装载LDMEA LDMDB 预先减少装载LDMFA LDMDA 过后减少装载STMFA STMIB 预先增加存储STMEA STMIA 过后增加存储STMFD STMDB 预先减少存储STMED STMDA 过后减少存储
区分NAND和NOR启动
NAND启动的时候,代码是在NAND中,但实际上是上电自动copy代码到片内RAM,也就是实际是在片内RAM运行,可读可写.通过判断0地址是否可写即可判断
//1.读出0地址的值备份到r0mov r1,#0ldr r0,[r1]//r1=0//2.在0地址写入0//把r1的值写入[r1]所在内存str r1,[r1]//3.读出0地址的值ldr r2,[r1]//4.比较 写入的值和读出的值cmp r2,r1ldr sp, =0x40000000+4096 /* 先假设是nor启动 *///如果相等则是nand启动moveq sp, #4096 /* nand启动 */streq r0, [r1] /* 恢复原来的值 */
完整调用如下
.text.global _start_start: /* 关闭看门狗 */ ldr r0, =0x53000000 ldr r1, =0 str r1, [r0] /* 设置内存: sp 栈 */ /* 分辨是nor/nand启动 * 写0到0地址, 再读出来 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动 * 否则就是nor启动 */ mov r1, #0 ldr r0, [r1] /* 读出原来的值备份 */ str r1, [r1] /* 0->[0] */ ldr r2, [r1] /* r2=[0] */ cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */ ldr sp, =0x40000000+4096 /* 先假设是nor启动 */ moveq sp, #4096 /* nand启动 */ streq r0, [r1] /* 恢复原来的值 */ bl mainhalt: b halt
参数调用
遵循ATPCS原则,r0~r4存放参数,lr为返回地址,参考