.text
.global _start
_start:
ldr sp, =4096
/* main只需要一个参数,通过r0传递 */
mov r0, #4
bl main
mov r0,#5
bl main
halt:
b halt
int main(int which)
{
unsigned int *gpfcon = (unsigned int *)0x56000050;
unsigned int *gpfdat = (unsigned int *)0x56000054;
if (which == 4)
*gpfcon = 0x100;
else if (which == 5)
*gpfcon = 0x400;
*gpfdat = 0x0;
return 0;
}
all:
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o led_on.o start.S
arm-linux-ld -Ttext 0 led_on.o main.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
arm-linux-objdump -D led_on.elf > led_on.dis
clean:
rm *.o *.elf *.bin
因为C函数要使用
栈要指向一块可读可写的内存,并且不与代码冲突
a. 保存局部变量
b. 保存lr等寄存器(加入在main函数中调用函数,返回地址要保存在lr寄存器中,会将之前的lr寄存器覆盖,因此要保存之前的Lr寄存器)
c. 保存调用者给被调用者传递的参数(通过r0-r3寄存器传递)
d. 保存被调用者的返回值给调用者(通过r0-r3寄存器传递)
e. 在函数中r4-r11可能被使用,因此需要在函数的入口保存他们,在函数的出口恢复他们。
nand启动时会将nand的前4K拷贝到内存中,因此下面的代码会在内存的前4K中
led_on.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
/* 设置栈,sp = 4096,在内存的顶部,我们的代码很小,在0地址处,与栈不会冲突 */
0: e3a0da01 mov sp, #4096 ; 0x1000
/* r0 = 4 */
4: e3a00004 mov r0, #4 ; 0x4
/* 调用main函数 */
8: eb000002 bl 18
/* r0 = 5 */
c: e3a00005 mov r0, #5 ; 0x5
/* 调用main函数 */
10: eb000000 bl 18
00000014 :
14: eafffffe b 14
00000018 :
/* ip = sp */
18: e1a0c00d mov ip, sp
/* 将fp,ip,lr,pc寄存器的值存放到sp处,同时更新sp的值
* 寄存器高标号放在高地址 */
* pc = 10 + 8 = 0x18 */
* 因此 PC = 0x18 存放在4092~4095
* 然后再次减 lr = 8 存放在4088~4091
* 然后再次减 ip = 4096 存放在4084~4097
* 然后再次减 fp = 未定义 存放在4080~4083
* 最后更新sp的值 sp = 4080
*/
1c: e92dd800 stmdb sp!, {fp, ip, lr, pc}
/* fp = ip - 4 = 4092 */
20: e24cb004 sub fp, ip, #4 ; 0x4
/* sp = sp - 12 */
/* 12用来存放局部变量 */
24: e24dd00c sub sp, sp, #12 ; 0xc
/* 把r0存放到fp-16=4092-16=4076处 */
28: e50b0010 str r0, [fp, #-16]
/* r3 = 0x56000000 */
2c: e3a03456 mov r3, #1442840576 ; 0x56000000
/* r3 = 0x56000000 + 0x50 = 0x56000050 */
30: e2833050 add r3, r3, #80 ; 0x50
/* r3存入fp-20 = 4092 - 20 = 4072地址处 */
/* 局部变量gpfcon保存在了栈中 */
34: e50b3014 str r3, [fp, #-20]
/* r3 = 0x56000000 */
38: e3a03456 mov r3, #1442840576 ; 0x56000000
/* r3 = r3 + 0x54 = 0x56000054 */
3c: e2833054 add r3, r3, #84 ; 0x54
/* r3存入fp-24 = 4092 - 24 = 4068地址处 */
/* 局部变量gpfdat保存在了栈中 */
40: e50b3018 str r3, [fp, #-24]
/* 从sp-16 = 4076的地址取值,即寄存器r0存放的参数值,存放到r3寄存器 */
44: e51b3010 ldr r3, [fp, #-16]
/* 比较r3与4 */
48: e3530004 cmp r3, #4 ; 0x4
/* 执行完调到60地址 */
4c: 1a000003 bne 60
/* r3 == 4时执行下面的代码 */
/* 从fp-20=4072的地址取值,得到了gpfcon变量的值,也就是0x56000050这个地址 */
50: e51b2014 ldr r2, [fp, #-20]
/* r3 = 0x100 */
54: e3a03c01 mov r3, #256 ; 0x100
/* 将0x100写入0x56000050这个地址 */
58: e5823000 str r3, [r2]
5c: ea000005 b 78
/* 从sp-16 = 4076的地址取值,即寄存器r0存放的参数值,存放到r3寄存器 */
60: e51b3010 ldr r3, [fp, #-16]
/* 比较r3与4 */
64: e3530005 cmp r3, #5 ; 0x5
/* 执行完调到78地址 */
68: 1a000002 bne 78
/* r3 == 5时执行下面的代码 */
/* 从fp-20=4072的地址取值,得到了gpfcon变量的值,也就是0x56000050这个地址 */
6c: e51b2014 ldr r2, [fp, #-20]
/* r3 = 0x400 */
70: e3a03b01 mov r3, #1024 ; 0x400
/* 将0x400写入0x56000050这个地址 */
74: e5823000 str r3, [r2]
/* 从4068的地址取值放到r3寄存器,得到了gpfdat的值,也就是0x560000054这个地址 */
78: e51b3018 ldr r3, [fp, #-24]
/* r2 = 0 */
7c: e3a02000 mov r2, #0 ; 0x0
/* 将0写入0x560000054这个地址 */
80: e5832000 str r2, [r3]
/* r3 = 0 */
84: e3a03000 mov r3, #0 ; 0x0
/* r0 = r3,r0保存返回值0 */
88: e1a00003 mov r0, r3
/* sp = fp - 12 = 4092 - 12 = 4080 */
/* 释放了局部变量,恢复栈 */
8c: e24bd00c sub sp, fp, #12 ; 0xc
/*
* 从栈中恢复寄存器,将sp的值加载到多个寄存器中
* 因此 fp存放4080~4083的值,等于原来保存的fp
* 然后再次增加 sp存放4084~4087的值,等于原来保存的ip,sp = 4096(程序刚开始ip = sp,保存了栈的值)
* 然后再次增加 pc存放4088~4091的值,等于原来保存的lr = 8
* pc = lr = 8,因此程序就会返回0x8的地址
* 最后再次增加 sp' = sp + 4 = 4096 ,由于sp后面无!号,sp修改后的地址并不存入sp中
*/
90: e89da800 ldmia sp, {fp, sp, pc}
Disassembly of section .comment:
/* 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.