您尚未登录。

楼主 #1 2018-05-03 18:47:35

xinxiaoci
会员
注册时间: 2018-04-18
已发帖子: 71
积分: 71

c程序控制led灯及反汇编代码分析

《单片机小白转嵌入式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)

离线

#2 2018-05-03 19:05:22

awfans
会员
注册时间: 2018-04-03
已发帖子: 264
积分: 264

Re: c程序控制led灯及反汇编代码分析

非常详细, 感谢分享!

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn


东莞哇酷科技有限公司开发