《单片机小白转嵌入式Linux学习记录,基于S3C2440----目录》
低位存放在低地址:小字节序 小端 little endian
高位存放在低地址:大字节序 大端 big endian
一般ARM芯片都是小字节顺序
编写c程序控制led
a.谁来调用main函数
b.main函数中的局部变量保存在内存中,这个内存地址是多少?
答:我们需要写一个汇编代码,给main函数设置内存(栈),然后调用main函数;局部变量保存在栈中,栈对应一块内存。
----------------------------------------------
start.S 汇编代码
.text
.global _start
_start:
/* 设置内存:sp 栈 */
ldr sp,=4096 /* nand启动设置在内部ram的顶部4k位置 */
//ldr sp,=0x40000000+4096 /* nor启动 */
/* 调用main函数 */
bl main
/* 死循环 */
halt:
b halt
-----------------------------------------------
led.c c代码
int main()
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;//控制寄存器
unsigned int *pGPFDAT = (unsigned int *)0x56000054;//数据寄存器
/* 配置GPF5为输出引脚 */
*pGPFCON=0x400;
/* 设置GPF5输出0 */
*pGPFDAT=0;
return 0;
}
----------------------------------------------
Makefile 文件
all:
arm-linux-gcc -c -o start.o start.S
arm-linux-gcc -c -o led.o led.c
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.dis反汇编
led.elf: file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
0: e3a0da01 mov sp, #4096 ; 0x1000
4: eb000000 bl c <main> ;调用main函数 并把返回地址保存在lr中 lr=0x08
00000008 <halt>:
8: eafffffe b 8 <halt>
0000000c <main>:
c: e1a0c00d mov ip, sp ;ip保存了栈顶的值 4096
10: e92dd800 stmdb sp!, {fp, ip, lr, pc} ;保存fp,ip,lr,pc 更新sp的值 sp=4096-4*4=4080
14: e24cb004 sub fp, ip, #4 ; 0x4 ;fp=ip-4=4096-4=4092
18: e24dd008 sub sp, sp, #8 ; 0x8 ;sp=sp-8=4080-8=4072
1c: e3a03456 mov r3, #1442840576 ; 0x56000000 ;r3=0x56000000
20: e2833050 add r3, r3, #80 ; 0x50 ;r3=r3+0x50=0x56000050 pGPFCON寄存器
24: e50b3010 str r3, [fp, #-16] ;将r3的值保存在fp-16的内存(栈)中 fp-16=4092-16=4076 (*(int *)4076)=0x56000050
28: e3a03456 mov r3, #1442840576 ; 0x56000000 ;r3=0x56000000
2c: e2833054 add r3, r3, #84 ; 0x54 ;r3=r3+0x54=0x56000054
30: e50b3014 str r3, [fp, #-20] ;将r3的值写入fp-20的内存(栈)中 fp-20=4092-20=4072 (*(int *)4072)=0x56000054
34: e51b2010 ldr r2, [fp, #-16] ;读取fp-16内存中的值到r2 r2=(*(int *)4076)=0x56000050
38: e3a03b01 mov r3, #1024 ; 0x400 ;r3=0x400 GPF5寄存器
3c: e5823000 str r3, [r2] ;将r3的值写入r2指向的内存中 (*(int *)0x56000050)=0x400 GPF5为输出模式
40: e51b2014 ldr r2, [fp, #-20] ;同上面三行代码(*(int *)0x56000054)=0 输出低电平 点亮LED
44: e3a03000 mov r3, #0 ; 0x0
48: e5823000 str r3, [r2]
4c: e3a03000 mov r3, #0 ; 0x0 ;r3=0
50: e1a00003 mov r0, r3 ;r0=r3=0 r0-r3 用于调用者与被调用者之间传递参数
54: e24bd00c sub sp, fp, #12 ; 0xc ;sp=fp-12=4092-12=4080
58: e89da800 ldmia sp, {fp, sp, pc} ;从4080位置开始还原进入函数之前的fp=fp,sp=ip,pc=lr=0x08 所以程序跳转至0x08位置执行
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.
-----------------------------------------------------
汇编指令
add,sub
举例:
add r0,r1,#4 ;r0=r1+4
add r0,r1,r2 ;r0=r1+r2
sub r0,r1,#4 ;r0=r1-4
sub r0,r1,r2 ;r0=r1-r2
bl break link 跳转并保存返回地址
举例:
bl c <main> ;跳转到内存0x0c 并保存下一条指令的地址,用于调用返回
ldm ;many 读内存,写入多个cpu寄存器
stm ;把多个cpu寄存器的值写入内存
ldmia ;ia 先读后蹭
stmdb ;db 先减后存
举例:
stmdb sp!,{fp,ip,lr,pc} ;1> 大括号中的cpu寄存器的存取顺序与,书写顺序无关。高编号cpu寄存器存
在高地址。
;2> sp! : ! 表示sp=sp最终被修改后的值,假如sp初始值是4096 那么运行该
条汇编后sp的值为4080
执行流程:
1.sp=4096-4=4092
2.将pc寄存器的值存入4092指向的内存(栈)中
3.sp=4092-4=4088
4.将lr寄存器的值存入4088指向的内存(栈)中
5.sp=4088-4=4084
6.将ip寄存器的值存入4084指向的内存(栈)中
7.sp=4084-4=4080
8.将fp寄存器的值存入4080指向的内存(栈)中
9.将当前的栈指针更新
->4096
pc值
->4092
lr值
->4088
ip值
->4084
fp值
->4080
ldmia sp,{fp,sp,pc} ; sp 无 ! 号,表示sp修改后的值不存入sp
; 先读后增,假如sp的初始值为4080
执行流程:
1.fp=内存(栈)中fp的值(4080内存指向的值)
2.sp=4080+4=4084
3.sp=内存(栈)中ip的值(4084内存指向的值)
4.sp=4084+4=4088
5.pc=内存(栈)中lr的值(4088内存指向的值)
6.sp=4088+4=4092
最近编辑记录 xinxiaoci (2018-05-03 18:52:10)
离线
非常详细, 感谢分享!
离线