一. 汇编调用 C
1. 初始化栈
2. 初始化BSS段 (BSS 段是C语言存放未初始化的全局变量,或者初始化为0 的全局变量)
3 .使用 r0 ,r1, r2, r3 给函数传参,如果多于 4 个参数使用栈的方式传参
4. 返回值放在 r0, r1 中,最大32位数据, 一般使用 r0 就可以满足要求
例子: 汇编文件 start.s
.text @ 表示汇编文件开始 /****初始化栈*****/ ldr sp, =0x40000100 mov r0, #0x5 mov r1, #0x6 /***初始化bss段***/ @ bss段地址由链接时编译器分配 ldr r2, =__bss_start @ BSS 起始地址 ldr r3, =__bss_end__ @ BSS 结束地址 mov r4, #0x00000000 clbss_l: teq r2, r3 @ r2, r3 中存放的是BSS段起始和结束地址 strne r4, [r2] @ 把r4 中的数据写入 r2中存放的地址中,teq结果不成立写入,也就是把bss段写0 addne r2, r2, #1 @ 起始地址开始偏移一个字节,teq不成立的清苦下 bne clbss_l @ teq 不成立,表示还没有清除完bss 段, bl _main @ 跳转到执行的C 函数名 .end @ 伪操作 , 表示汇编文件结束
main.c
int aa; int _main(int a, int b) { int t=0; t = a+ b; return t; }
链接文件: map.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { ./Objects/start.o(.text) *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) } __bss_end__ = .; }
测试: 申请一个全局变量,int aa; 占4字节的BSS 段所以起始和结束地址相差4 字节,所以会在清楚BSS 执行循环4次
二. C调用汇编
C 语言调用 汇编时 只要汇编实现的函数通过 .global 声明成全局函数即可在 C语言中调用
关于参数的传递:
C 函数的参数,传递给汇编放在寄存器 r0,r1,r2,r3 中;汇编会使用 寄存器 r0 接受调用汇编函数的返回值
例子: start.s汇编文件
.text /****初始化栈*****/ ldr sp, =0x40000100 mov r0, #0x5 mov r1, #0x6 /* 汇编跳转到 C 中 */ /* 初始化bss段 */ @ bss段地址由链接时编译器分配 ldr r2, =__bss_start @ BSS 起始地址 ldr r3, =__bss_end__ @ BSS 结束地址 mov r4, #0x00000000 clbss_l: teq r2, r3 @ r2, r3 中存放的是BSS段起始和结束地址 strne r4, [r2] @ 把r4 中的数据写入 r2中存放的地址中,teq结果不成立写入,也就是把bss段写0 addne r2, r2, #1 @ 起始地址开始偏移一个字节,teq不成立的清苦下 bne clbss_l @ teq 不成立,表示还没有清除完bss 段, bl _main @ 跳转到执行的C 函数名 , lr 中会保存下一条指令的地址, 也就是 b loop /* 汇编函数, 在C 中调用 */ .global add_fun @ 声明为全局函数,使外部可调用 add_fun: add r2, r1, r0 @ 把 r1和r0中的数据相加 放在r2 中 mov r0, r2 @ 使用寄存器 r0 存放调用汇编函数时返回的结果 mov pc, lr @ lr 寄存器中保存 C 跳转到汇编时的下一条指令地址 , 重新付给 PC 继续执行loop: b loop .end
测试: