Thumb指令集程序示例

Posted 家门Jm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thumb指令集程序示例相关的知识,希望对你有一定的参考价值。

在上节课中我们介绍CPU有两种工作状态,一种ARM状态,一种Thumb状态。
本节课主要介绍Thumb状态及Thumb指令集。

在012_relocate的程序基础上修改,创建013_thumb_014_003程序,并打开start.S和Makefile代码。

1. 对Makefile文件进行如下修改。

 

 1 all: led_on2.o uart.o init.o main.o start.o
 2     
 3     #arm-linux-ld -Ttext 0 -Tdata 0x3000000 start.o led_on2.o uart.o init.o main.o -o sdram.elf
 4     arm-linux-ld -T sdram.lds start.o led_on2.o uart.o init.o main.o -o sdram.elf
 5     arm-linux-objcopy -O binary -S sdram.elf sdram.bin
 6     arm-linux-objdump -D sdram.elf > sdram.dis
 7     
 8 %.o : %.c
 9     arm-linux-gcc -mthumb -c -o $@ $<
10 %.o : %.S
11     arm-linux-gcc -c -o $@ $<        # 在汇编文件中不需要做-mthumb的指定,在代码里边进行指定
12     
13 .PHONY: clean    
14 
15 clean:
16     rm *.bin *.o *.elf *.dis

 

2. 对start.S文件进行如下修改。

 1 .text
 2 .global _start
 3 .code 32        /* 表示后续指令使用ARM指令集 */
 4 
 5 _start:
 6 
 7 ...
 8 
 9 /* 怎么从 ARM_State 切换到 Thumb_State ? */
10     adr r0, thumb_func            /* 得到thumb_func标号的地址 */
11     add    r0, r0, #1                /* 为什么 +1 ?bit0 = 1 时, bx就会切换CPU State到thumb State     https://blog.csdn.net/u011449588/article/details/44634977 */
12     bx    r0             /* bx 命令后边那个值如果最低位为1的话,它会跳转到Thumb指令 */
13 
14 .code 16
15 thumb_func:
16 
17     bl sdram_init        /*  */
18     //bl sdram_init2    /* 用到有初始值的数组,不是位置无关码 */
19 
20 ...
21 
22 /* 调用main函数 */
23     //bl main            /* 使用BL命令相对跳转,程序仍然在NOR/片内SRAM上运行 */
24     /*ldr    pc,    =main*/    /* 绝对跳转,跳到SDRAM */
25     
26     ldr    r0, =main
27     mov pc, r0
28     
29 halt:
30     b halt

其中,(1) 最后不再允许使用ldr pc,  =main直接对PC进行赋值,而改用 ldr  r0, =main, mov  pc, r0  进行间接赋值。否则出现如下错误:

                

   (2) 其中 adr r0, thumb_func、add r0, r0, #1

  首先得到thumb_func 标号的地址,并且对其进行+1操作(∵32位处理器指令总是以4字节为单位进行存放,PC每次移动也是进行+4,一般最后一位bit0=0),这里进行+1后,使r0最后一位bit0=1。

  执行到bx r0时,若rm的bit0为1,则跳转时自动将CPSR中的标志T置位,即把目标地址的代码解释为Thumb代码,如果为bit0位为0的话,则跳转时自动将CPSR中的标志T复位,即把目标地址的代码解释为ARM代码。

  (3)再次进行编译后,出现如下错误:

          

  显示“memcpy”的错误,原因是出在init.c文件中的sdram_init2函数上。

 

3. 打开init.c文件

   找到init_init2函数后,进行如下修改:

 1 void sdram_init2(void)        /* 没有任何输出,推断这里应该是位置无关的 */  /* 这个函数并不会修改这个数组,它只是把这些值拷贝到寄存器里边去,∴可以加一个const*/
 2 {
 3     const static unsigned int  arr[] = {            // 使用static静态变量,静态变量就会放在数据段里,最终重定位时,
 4         0x22000000,        //BWSCON                            会把值从数据段中拷贝到arr[]数组多对应的地址去
 5         0x00000700,        //BANKCON0                
 6         0x00000700,        //BANKCON1                
 7         0x00000700,        //BANKCON2                在学习Thumb指令时,编译器用到memcpy函数导致make出错,原因是∵这些值肯定是保存在代码里边的,为了构造这个数组,
 8         0x00000700,        //BANKCON3                编译器把这些代码段里值拷贝到arr[]这个局部变量里。
 9         0x00000700,        //BANKCON4
10         0x00000700,        //BANKCON5
11         0x18001,        //BANKCON6
12         0x18001,        //BANKCON7
13         0x8404f5,        //REFRESH, HCLK=12MHZz: 0x008e07a3, HCLK=100MHz: 
14         0xb1,        //BANKSIZE
15         0x20,        //MRSRB6
16         0x20,        //MRSRB7
17         };
18     volatile unsigned int *p = (volatile unsigned int *)0x48000000;
19     int    i;
20 
21     for ( i=0;  i<13; i ++ )
22     {
23         *p = arr[i];
24         p ++;
25     }
26     
27 }

 

最后,通过ls -l进行查看生成的.bin文件的大小。

                 

使用Thumb指令后,

                

 

4. 看反汇编代码

  前边地址仍然是4字节相加,        

                

  其他指令除bl仍为4字节外,其他指令均变为2字节增长。    

                

总结:

  如果Flash空间比较小的话,可以使用Thumb指令集,但对于ARM系统、Linux系统,Flash 空间一般以M为单位,不需要省那么点空间。所以后续使用很少。

 

以上是关于Thumb指令集程序示例的主要内容,如果未能解决你的问题,请参考以下文章

Thumb指令集与ARM指令集的差别

什么时候需要 GAS ELF 指令 .type、.thumb、.size 和 .section?

为啥要使用thumb模式,与ARM相比较,Thumb代码的两大优势是啥?

ida Pro ARM指令集和Thumb指令集的切换

ARM指令和THUMB指令有啥区别

ARM处理器架构的Thumb指令集中关于IT指令的使用