C函数调用


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 main
halt:
    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.dis
clean:
    rm *.bin *.o *.elf *.dis

查看下反汇编的代码

led.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:   e3a0da01    mov sp, #4096   ; 0x1000
   4:   eb000000    bl  c <main>

00000008 <halt>:
   8:   eafffffe    b   8 <halt>

0000000c <main>:
   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函数的流程

  1. 保存sp
  2. 保存lr和pc,以及会被改变的寄存器的值
  3. 数据处理完后把寄存器恢复

汇编解析

LDMED    LDMIB    预先增加装载
LDMFD    LDMIA    过后增加装载
LDMEA    LDMDB    预先减少装载
LDMFA    LDMDA    过后减少装载

STMFA    STMIB    预先增加存储
STMEA    STMIA    过后增加存储
STMFD    STMDB    预先减少存储
STMED    STMDA    过后减少存储

mark

区分NAND和NOR启动

NAND启动的时候,代码是在NAND中,但实际上是上电自动copy代码到片内RAM,也就是实际是在片内RAM运行,可读可写.通过判断0地址是否可写即可判断

//1.读出0地址的值备份到r0
mov r1,#0
ldr r0,[r1]

//r1=0
//2.在0地址写入0
//把r1的值写入[r1]所在内存
str r1,[r1]

//3.读出0地址的值
ldr r2,[r1]

//4.比较 写入的值和读出的值
cmp r2,r1

ldr 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 main

halt:
    b halt

参数调用

遵循ATPCS原则,r0~r4存放参数,lr为返回地址,参考ATPCS规则.md

转载于:https://www.cnblogs.com/zongzi10010/p/10023525.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值