直接修改bin文件改变点亮的LED

直接修改bin文件改变点亮的LED

不管我们在计算机上做了多么复杂的动作,包括编写C语言代码、汇编代码、makefile文件等,最后都只不过是为了得到一个bin文件。因此,原则上当我们失去所有工具时,只要你足够强大,就能拿着一些官方文档直接制作bin文件,然后点亮一个LED灯。

一. 点亮LED1

在JZ2440中,LED原理图如下所示:
在这里插入图片描述直接修改bin文件改变点亮的LED_第1张图片
从上面两张图可知,JZ2440的LED为低电平启动,LED与GPIO引脚对应关系如下:

二极管 引脚
nLED_1 GPF4
nLED_2 GPF5
nLED_4 GPF6

接下来,打开S3C2440A芯片手册,找到PORT F CONTROL REGISTERS(GPFCON, GPFDAT) ,如下图所示:
直接修改bin文件改变点亮的LED_第2张图片
从上图可知,GPFCON的地址为0X56000050GFPDAT的地址为0X56000054,并且GPFCON[9:8]控制GPF4,将这两位设置成01就能够将GPF4设置成输出。
再来看GPFDAT寄存器表格:
直接修改bin文件改变点亮的LED_第3张图片
Description可知,写1就是高电平,写0就是低电平。
点点LED1的汇编代码led1.S如下所示

.text								//代码段
.global _start
_start:
	//配置GFPCON,GPFCON[9:8]写为01
	ldr r1,=0x56000050  			
	ldr r0,=0x100
	str r0,[r1]
	
	//配置GPFDAT,简单粗暴全部写0即可将LED1点亮
	ldr r1,=0x56000054
	ldr r0,=0
	str r0,[r1]

//死循环 防止CPU乱执行
halt:
	b halt

并编写Makefile文件

all:
	arm-linux-gcc -c -o led1.o led1.S					#编译
	arm-linux-ld -Ttext 0 led1.o -o led1.elf			#链接
	arm-linux-objcopy -O binary -S led1.elf led1.bin  	#elf转换为bin文件
clean:
		rm *.bin *.o *.elf

将bin文件烧写到JZ2440右边第一个LED就亮了。

从上面的代码可知,S3C2440点亮LED比起STM32要简单许多,前面没有时钟配置的操作。猜测是S3C2440的定位不是低功耗单片机,因此时钟默认都是打开的,然后直接配置控制寄存器和数据寄存器就可以。

二. 分析反汇编文件

在命令行中输入:

arm-linux-objdump -D led1.elf >led1.dis

就可得到led.bin的反汇编文件,注意反汇编文件是.dis。该文件内容如下:

led1.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:	e59f1014 	ldr	r1, [pc, #20]	; 1c <.text+0x1c>
   4:	e3a00c01 	mov	r0, #256		; 0x100
   8:	e5810000 	str	r0, [r1]
   c:	e59f100c 	ldr	r1, [pc, #12]	; 20 <.text+0x20>
  10:	e3a00000 	mov	r0, #0	; 0x0
  14:	e5810000 	str	r0, [r1]

00000018 :
  18:	eafffffe 	b	18 
  1c:	56000050 	undefined
  20:	56000054 	undefined

其中第一列是指令的地址,第二列是机器指令码,第三列是反汇编出来的汇编码。
看第一条指令:

0:	e59f1014 	ldr	r1, [pc, #20]

对应的是ldr r1,=0x560000500x56000050的地址是0x1c,那为什么是[pc,#20]呢?
首先,#20表示十进制数20,[pc,#20]表示将pc的值加上20。
然后,arm采用流水线的形式执行指令。当CPU在执行A地址的指令时,地址A+4的指令就会被译码,而地址A+8的指令就会被加载。因此,pc=当前执行指令的地址+8
最后,[pc,#20]就是0+8+20=28=0X1c,就和0x56000050的地址对应上了

接下来看最关键的两条指令

 4:	e3a00c01 	mov	r0, #256   

 10:	e3a00000 	mov	r0, #0	; 0x0

4:是配置寄存,10:是写入数据寄存器,由于输出低电平直接写全0就可以了,修改代码只要修改4:这一句。

三. 修改led1.bin文件

先来看看led1.bin的内容,这里用Hex Editor Neo打开。
直接修改bin文件改变点亮的LED_第4张图片
为了方便查看,点击View Group By Double words
可以看到,led1.bin文件的16进制码和led1.dis文件的机器码是按顺序对应的。
因此,只要修改01列的数据就可以了。

现在,打开ARM Architecture Reference Manual.pdf(可直接google得到)查看mov指令的格式。
直接修改bin文件改变点亮的LED_第5张图片
再来看看
e3a00c01的二进制形式:
直接修改bin文件改变点亮的LED_第6张图片
[31:28]不用管
[27:21]mov指令的格式一致
[20:16]不懂,也不管了
[15:12]代表寄存器编号,这里是R0,因此全0就可以了
[11:0]shifter_operand,要重点说明一下。

[11:0]又分为[11:8](记为rotate)和[7:0](记为immed_8),mov r0, #256中的#256就是由shifter_operand转化而来。转化关系如下:
立即数=immed_8 >> 2*rotate
#2560X100,可表示成0x1循环右移24(总共32位)位来表示,因此,[11:8]=1100b=0xc=12,而2*12=24

为了点亮nLED_2,要将GPFCON[11:10]设置成01b,汇编语句为

ldr r0,=0x400

0x400可以表示成0x1循环右移22位,因此:
rotate=11=0xb
immed_8=0x01
shifter_operand=0xb01
led1.bin文件的01列改为e3a00b01,另存为led2.bin,然后将led2.bin烧写到JZ2440就可以看到中间的LED被点亮了。

你可能感兴趣的:(嵌入式学习笔记)