C函数调用

Posted zongzi10010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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    过后减少存储

技术分享图片

区分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




以上是关于C函数调用的主要内容,如果未能解决你的问题,请参考以下文章

VBS 环境下如何调用EXCEL内置函数

php 一个自定义的try..catch包装器代码片段,用于执行模型函数,使其成为一个单行函数调用

来自dispatch_async全局崩溃的C函数调用,但在主队列上工作

如何将数据从回收器适配器发送到片段 |如何从 recyclerview 适配器调用片段函数

如何测量代码片段的调用次数和经过时间

如何从片段 KOTLIN 中调用意图 [重复]