1.bss段初始化
变量 | 存放位置 |
初始化的全局变量 | 数据段 |
局部变量 | 栈 |
malloc函数分配的 | 堆 |
未初始的全局变量 | bss段 |
说明:全局变量在未赋初值时,会被保留到bss段。
测试:
#include <stdio.h> int bss_test; int main() { bss_test=100; return 0; }
arm-linux-gcc bss.c -o bss
arm-linux-readelf -a bss >bssdump
vim bssdump(看全局变量的地址是否在bss段的起始于结束地址之间)
编写程序清零bss段
1 clear_bss: 2 ldr r0,=bss_start 3 ldr r1,=bss_end 4 cmp r0,r1 5 moveq pc,lr 6 7 clean_loop: 8 mov r2,#0 9 str r2,[r0],#4 10 cmp r0,r1 11 bne clean_loop 12 mov pc,lr
2.跃入C
点亮led的C程序
1 #define GPKCON (volatile unsigned long*)0x7f008800 2 #define GPKDAT (volatile unsigned long*)0x7f008808 3 4 int gboot_main() 5 { 6 *(GPKCON) = 0x11110000; 7 *(GPKDAT) = 0xa0; 8 9 return 0; 10 }
3.C与汇编混合编程
3.1 汇编调用C函数
把函数名赋予PC指针ldr pc,=gboot_main
3.2 C函数调用汇编
在前面点亮led中light_led函数声明为全局的(汇编中被其他程序引用)
#define GPKCON 0x7f008800 #define GPKDAT 0x7f008808 .global light_led light_led: ldr r0, =GPKCON ldr r1, =0x11110000 str r1, [r0] ldr r0, =GPKDAT ldr r1, =0xa0 str r1, [r0] mov pc, lr
3.3 C中内嵌汇编
3.3.1 格式
__asm__(
汇编语句部分
:输出部分
:输入部分
:破坏描述部分
);
注:C内嵌汇编以关键字”__asm__”或”asm”开始,下辖四个部分,各部分之间使用":"分开, 第一部分是必须写的,后面三部分是可以省略,但是分号:不能省略
汇编语句部分:汇编语句的集合,可以包含多条汇编语句,每条语句之间需要使用换行符 “ ”隔开或使用分号“ ; ”隔开
输出部分:在汇编中被修改的C变量列表
输入部分: 作为参数输入到汇编中的变量列表
破坏描述部分: 执行汇编指令会破坏的寄存器描述
3.3.2 范例
向cp15 c1寄存器写入数值
void write_p15_c1 (unsigned long value) { __asm__( “mcr p15, 0, %0, c1, c0, 0 ” : : “r” (value) @编译器选择一个R*寄存器(通用寄存器) : "memory"); }
向cp15 c1寄存器读出数值
unsigned long read_p15_c1 (void) { unsigned long value; __asm__( “mrc p15, 0, %0, c1, c0, 0 ” : “=r” (value) @ ’=‘ 表示只写操作数,用于输出部分 : : "memory"); return value; }
3.3.3 优化
unsigned long old; unsigned long temp; __asm__ volatile( "mrs %0, cpsr " "orr %1, %0, #128 “ "msr cpsr_c, %1 " : "=r“ (old), "=r“ (temp) : : "memory"); }
使用volatile来告诉编译器,不要对接下来的这部分代码优化
测试
1 #define GPKCON 0x7f008800 2 #define GPKDAT 0x7f008808 3 int gboot_main() 4 { 5 //*(GPKCON) = 0X11110000; 6 //*(GPKDAT) = 0xa0; 7 __asm__( 8 "ldr r1, =0x11110000 " 9 "str r1, [%0] " 10 11 "ldr r1, =0xa0 " 12 "str r1, [%1] " 13 : 14 :"r"(GPKCON),"r"(GPKDAT) 15 :"r1" 16 ); 17 return 0; 18 }