[开发工具]

STM32的C与汇编语言混合编程

[复制链接]
29|1
手机看帖
扫描二维码
随时随地手机跟帖
yeates333|  楼主 | 2024-12-23 13:00 | 显示全部楼层 |阅读模式
一、混合编程

C语言还是有其局限性。有些硬件地址是没有地址一说的。比如处理器的寄存器,协处理器和协处理器的寄存器,系统控制器等。这些硬件资源是不可能使用C语言指针来访问的,这时就只好应用汇编指令了。

  • 汇编程序中调用C语言函数
  • 汇编程序使用C语言中定义的全局变量、、
  • C语言中使用汇编程序中定义的全局变量
  • C语言中使用汇编程序中定义的全局变量
  • C语言中内嵌汇编指令
二、C语言嵌套汇编调用函数操作1. 无参数

① C语言程序调用汇编语言函数

  • main.c
#include<stdio.h>extern void Init_1();int main(){        Init_1();        return 0;}
  • fun.c
        AREA My_Function,CODE,READONLY ;固定格式        EXPORT Init_1                Init_1        MOV R1,#0        MOV R2,#0        LOOP         CMP R1,#10        BHS LOOP_END        ADD R2,#1        ADD R1,#1        B LOOPLOOP_END        NOP                END

② 在arm编程里,函数调用过程中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧

  • 在汇编函数那一行前设置断点,即可看到c语言调用汇编函数


  • 主要操作在子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧里,在第一阶段中主要对R1 R2 进行基本操作
  • 寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
  • 寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
  • 寄存器 r15 是程序计数器 pc。它不能用于任何其它用途。

③ 调试


2. 有参数
  • main2.c
# include<stdio.h>extern int Init_1(int x);int main(){                int xx = Init_1(10);        printf("%d", xx);                return 0;}
  • func2.s
        AREA        MY_Function,CODE,READONLY        EXPORT         Init_1  ; Init_1        ADD R0,#100     ; 将传入的值+100        MOV PC,LR                ; 返回R0                LOOP        ; 写在最左边的是程序段的段名,执行跳转程序时用到        CMP R1,#10          ; 比较R1和10的大小        BHS LOOP_END            ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句        ADD R2,#1          ; j++        ADD R1,#1     ; i++        B LOOP                  ; 循环        LOOP_END        NOP                END  ; 必须空格后再写END,不然会被认为是段名,表示程序结束

① 设置断点

  • 起始设R0为100 进行R1 R2 等操作,

    ② 调试


    0x6E=110
    ARM中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧里。
    因此Init_1(10)传入的10放到了R0,由MOV PC,LR返回110.
三、汇编语言嵌入C语言
  • main3.c
# include<stdio.h>extern void        Init_1(void);int get5(void);int main(){                printf("Begin...\n");        Init_1();                return 0;}int get5(){        return 5;}
  • func3.s
        AREA        MY_Function,CODE,READONLY        EXPORT         Init_1  ; 与在c文件中定义的Init_1函数关联起来        IMPORT  get5    ; 声明get5 为外部引用; 高级语言中的声明和使用变量其实是对板子寄存器的使用,所以我们只需要直接使用寄存器即可Init_1        MOV R1,#0     ; 设R1寄存器为i        MOV R2,#0          ; 设R2寄存器为j        LOOP        ; 写在最左边的是程序段的段名,执行跳转程序时用到        CMP R1,#10          ; 比较R1和10的大小        BHS LOOP_END            ; 如果R1大于等于10,则跳转到LOOP_END程序段,反之忽略该语句,直接执行下面的语句        ADD R2,#1          ; j++        ADD R1,#1     ; i++        BL get5            ; 调用get5,返回的值传入R0        B LOOP                  ; 循环        LOOP_END        NOP                                END  ; 必须空格后再写END,不然会被认为是段名,表示程序结束

① 设置断点


② 调试

  • 调试R0变为5

  • R1 和R2发生累加变化



四、总结

在arm编程里,函数调用过程中,子函数的参数值传递按顺序存放在r0,r1,r2,r3里,超过4个参数值传递放栈帧

  • r0-r3 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。—如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
  • r4-r11 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。r11 是栈帧指针 fp。
  • r12 是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。
  • 寄存器 r13 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
  • 寄存器 r14 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
  • 寄存器 r15 是程序计数器 pc。它不能用于任何其它用途。

使用特权

评论回复
小明的同学| | 2024-12-23 13:59 | 显示全部楼层
很奇怪,如果这个嵌入的汇编不用汇编,那么用C能达到相同的作用吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

1288

帖子

1

粉丝