您尚未登录。

楼主 #1 2021-05-19 15:13:06

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

如题

离线

楼主 #2 2021-05-19 15:16:52

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

2021-05-19_151544.png

这个是怎么回事呢?

离线

#3 2021-05-19 15:21:46

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
已发帖子: 446
积分: 313.5
个人网站

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

Thumb-2 多数16位,部分32位,自动变长。

离线

楼主 #4 2021-05-19 15:24:18

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

aozima 说:

Thumb-2 多数16位,部分32位,自动变长。

怎么确定是 thumb,还是thumb-2呢?

离线

#5 2021-05-19 15:26:16

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
已发帖子: 446
积分: 313.5
个人网站

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

对了,1C和20这2个不是指令,是数据。
在6和12被相对寻址引用。

离线

楼主 #6 2021-05-19 15:26:30

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

thumb指令,相比较与arm代码,储存器的功耗也较低。

thumb指令,基本都是无条件的,一共有18条基本指令,全部指令都是16bit。

Thumb-2指令,由16bit、32bit的指令混合组成,一共有16条基本指令,

搜了一下, 确实如此, 可是我的 gcc 命令行没有指定 thumb-2, 而是:

$(ARMGNU)-gcc -c $(COPS) -mthumb notmain.c -o notmain.o

离线

#7 2021-05-19 17:23:12

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
已发帖子: 446
积分: 313.5
个人网站

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

我记得这里的BL看起好像是32位,实际上还是16位,但自动粘在一起了。

离线

楼主 #8 2021-05-19 17:30:41

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

aozima 说:

我记得这里的BL看起好像是32位,实际上还是16位,但自动粘在一起了。

我看左边那个地址, bl应该是 4字节

离线

#9 2021-05-19 19:02:05

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
已发帖子: 446
积分: 313.5
个人网站

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

原文链接 https://blog.csdn.net/zerglurker/article/details/39451123?utm_source=blogxgwz1

>这其实是一个误解,因为 长跳转是由两条跳转指令组成的。

=======================================================
最近因为工作的原因,经常接触到长跳转指令,但是总是弄不明白,跳转的目标地址怎么得来的
经过多方面的资料查找,和自己的反复推算,现在总算弄明白了
先上例子:
下面是几个实际遇到的机器码机器对应的反汇编
示例一 3950a4: f13d feaa =>bl 4d2dfc
示例二 395082: f13d fe40 =>bl 4d2d06
示例三 395044: F7FF FFAc =>bl 394fa0

大家是不是也奇怪为什么16位的thumb指令里面,会出现32位的指令。
开始我也是这么认为的
这其实是一个误解,因为 长跳转是由两条跳转指令组成的。
其实际机器码和和含义如下:
1 1 1 1  0 +11位地址偏移高位(off0)
0xF             13D
1 1 1 1  1 +11位地址偏移低位(off1)
0xF             EAA
还是以上述三个例子做示范,
其偏移如下:(偏移是将指令去除高五bit得来的,f13d->13d 高五bit是1111 0【001】||| feaa->6aa高五bit是1111 1【110】)
示例一 off0=0x13d off1=0x6aa
示例二 off0=0x13d off1=0x640
示例三 off0=0x7FF  off1=0x7AC

首先要做的事情是将两个11位合并为一个22位数(注意由于off1是11位,意味着其最高位为off0的最低位,off0的值要除2)
即 offmid = ((off0/2)<<12)|((off0%2)<<11)|(off1)
按照这样计算,几个示例的偏移中间量为:
offmid = 0x9eeaa
offmid = 0x9ee40
offmid = 0x3fffac
接着将这个值乘2,得到一个23位数
offmid1 = 0x13dd54
offmid1 = 0x13dc80
offmid1 = 0x7fff58
对于前面两个这是一个正数,最高位为0,所以不必取反保留原来的值
对于最后一个,最高位为1,是负数,要减1后取反
处理后,如下:
offmid2 = 0x13dd54
offmid2 = 0x13dc80
offmid2 = 0x8000a8
最高位为1,则表示向前跳转,最高位为0表示向后跳转
跳转的基址是当前指令的末尾,需要再追加4个字节
所以实际跳转值就是:
off = 0x3950a4+4+0x13dd54 = 0x4d2dfc
off = 0x395082+4+0x13dc80 = 0x4d2d06
off = 0x395044+4- 0x0000a8 = 0x394fa0

反过来再看一看,其实 长跳转的偏移是这么来的:

首先取当前位置和目标位置的偏移差
地址因为内存对齐的原因,必然是偶数(即最低位必然为0),所以偏移值只有23位有意义,最低位永远为0
又由于最高位为符号位,所以,只有22位存储了真正的值

然后取补码(正数的补码是源码,负数的补码是符号位不变,剩余数取反加1),这样可以去除符号位对值的影响,将结果变为一个真正的22位值

最后再将其拆分为两个11位数,分成两个跳转指令执行

这么一想,顺着看,结果一目了然;但是反汇编的时候,难度就大大增加了,呵呵
————————————————
版权声明:本文为CSDN博主「52编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/zerglurker/article/details/39451123

离线

楼主 #10 2021-05-19 20:39:31

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

感谢大佬解惑,虽然还是一知半解,容我去给IQ充值再来提问。

离线

楼主 #11 2021-05-20 10:25:03

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

strap.s

.arm
_reset:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x31       //输出1
        str     r1, [r0]
        ldr r0, =_thum_mode + 1
        bx r0

.thumb
_thum_mode:
        ldr r1, =0x32       //输出2
        str     r1, [r0]


        ldr r1, =0x33       //输出3
        str     r1, [r0]

@aozima 再请教大佬一个问题,为什么这个代码只能输出 1呢, 不能输出 2, 3

$ arm-linux-gnueabi-objdump -D strap.o

strap.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_reset>:
   0:   e59f0014        ldr     r0, [pc, #20]   ; 1c <_thum_mode+0x8>
   4:   e3a01031        mov     r1, #49 ; 0x31
   8:   e5801000        str     r1, [r0]
   c:   e59f000c        ldr     r0, [pc, #12]   ; 20 <_thum_mode+0xc>
  10:   e12fff10        bx      r0

00000014 <_thum_mode>:
  14:   4903            ldr     r1, [pc, #12]   ; (24 <_thum_mode+0x10>)
  16:   6001            str     r1, [r0, #0]
  18:   4903            ldr     r1, [pc, #12]   ; (28 <_thum_mode+0x14>)
  1a:   6001            str     r1, [r0, #0]
  1c:   101f1000        andsne  r1, pc, r0
  20:   00000015        andeq   r0, r0, r5, lsl r0
  24:   00000032        andeq   r0, r0, r2, lsr r0
  28:   00000033        andeq   r0, r0, r3, lsr r0

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:   00001941        andeq   r1, r0, r1, asr #18
   4:   61656100        cmnvs   r5, r0, lsl #2
   8:   01006962        tsteq   r0, r2, ror #18
   c:   0000000f        andeq   r0, r0, pc
  10:   00543505        subseq  r3, r4, r5, lsl #10
  14:   01080306        tsteq   r8, r6, lsl #6
  18:   Address 0x0000000000000018 is out of bounds.

我照着书本写的, 基于arm926, 明明切换到了thumb模式。

离线

#12 2021-05-20 14:53:38

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
已发帖子: 446
积分: 313.5
个人网站

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

1. 编译和链接时加  -mthumb-interwork

2. 跳转时,先跳到自动生成的 xx_from_thumb 和 xx_from_arm

   b1f0c:	002a      	movs	r2, r5
   b1f0e:	0020      	movs	r0, r4
   b1f10:	f018 ff2a 	bl	cad68 <__memmove_from_thumb> // 当前在thumb模式,调用arm模式的函数 

000cad68 <__memmove_from_thumb>: // 编译器自动生成的 interwork 代码
   cad68:	4778      	bx	pc
   cad6a:	46c0      	nop			; (mov r8, r8)
   cad6c:	eaffc71a 	b	bc9dc <memmove>

000bc9dc <memmove>:
   bc9dc:	e1500001 	cmp	r0, r1
   bc9e0:	e92d4070 	push	{r4, r5, r6, lr}
   ....
   bca48:	e8bd4070 	pop	{r4, r5, r6, lr}
   bca4c:	e12fff1e 	bx	lr


   136ac:	e1a05000 	mov	r5, r0
   136b0:	e1a00004 	mov	r0, r4
   136b4:	eb02ddd3 	bl	cae08 <__rt_ota_get_fw_version_from_arm> // 当前在ARM模式,调用thumb模式的函数 

000cae08 <__rt_ota_get_fw_version_from_arm>:
   cae08:	e59fc000 	ldr	ip, [pc]	; cae10 <__rt_ota_get_fw_version_from_arm+0x8>
   cae0c:	e12fff1c 	bx	ip
   cae10:	000b9261 	// 实际是 000b9260 thumb模式要奇数,用bx实现 跳转+切换

000b9260 <rt_ota_get_fw_version>:
   b9260:	b510      	push	{r4, lr}
   b9276:	bd10      	pop	{r4, pc}

3. ARM模式的汇编函数,需要添加 `.type xxx, %function`,否则由thumb模式下跳转过来时不会生成`__func_asm_arm_from_thumb`

asm.S

	.code 32
    .globl _exit
_exit:
b .

	.type func_asm_arm, %function
    .globl func_asm_arm
func_asm_arm:
	BX LR

	.code 16
	.thumb_func
    .globl func_asm_thumb
func_asm_thumb:
	BX LR

离线

楼主 #13 2021-05-21 09:26:05

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

@aozima 感谢大佬,我再学习学习。

离线

楼主 #14 2021-05-24 09:15:56

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

.arm
_reset:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x31       //输出1
        str     r1, [r0]
//      ldr r0, =_thumb_mode + 1
        adr r0, _thumb_mode + 1
        bx r0

.thumb
_thumb_mode:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x32       //输出2
        str     r1, [r0]

        ldr r1, =0x33       //输出3
        str     r1, [r0]

这样可以输出 123 了,  前面没有初始化 r0 寄存器.

再加上
        ldr r0, =_thumb_mode + 1
替换
        adr r0, _thumb_mode + 1

$ qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.bin
123

请问@aozima老大,为什么ldr指令不可以呢?

离线

楼主 #15 2021-05-24 12:15:45

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

这个代码不行:

.arm
_arm_mode:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x31       //输出1
        str     r1, [r0]
        ldr r6, =_thumb_mode + 1
        add r6, #1
//      adr r6, _thumb_mode + 1
        bx r6

.thumb
_thumb_mode:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x32       //输出2
        str     r1, [r0]


        ldr r1, =0x33       //输出3
        str     r1, [r0]

        ldr r1, =0x34       //输出4
        str     r1, [r0]

_loop:
        b _loop            //死循环


        bx lr           //跳回去

生成的代码:

$ arm-linux-gnueabi-objdump -D strap.o

strap.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_arm_mode>:
   0:   e59f0024        ldr     r0, [pc, #36]   ; 2c <_loop+0x6>
   4:   e3a01031        mov     r1, #49 ; 0x31
   8:   e5801000        str     r1, [r0]
   c:   e59f601c        ldr     r6, [pc, #28]   ; 30 <_loop+0xa>
  10:   e2866001        add     r6, r6, #1
  14:   e12fff16        bx      r6

00000018 <_thumb_mode>:
  18:   4804            ldr     r0, [pc, #16]   ; (2c <_loop+0x6>)
  1a:   4906            ldr     r1, [pc, #24]   ; (34 <_loop+0xe>)
  1c:   6001            str     r1, [r0, #0]
  1e:   4906            ldr     r1, [pc, #24]   ; (38 <_loop+0x12>)
  20:   6001            str     r1, [r0, #0]
  22:   4906            ldr     r1, [pc, #24]   ; (3c <_loop+0x16>)
  24:   6001            str     r1, [r0, #0]

00000026 <_loop>:
  26:   e7fe            b.n     26 <_loop>
  28:   4770            bx      lr
  2a:   10000000        andne   r0, r0, r0
  2e:   0019101f        andseq  r1, r9, pc, lsl r0
  32:   00320000        eorseq  r0, r2, r0
  36:   00330000        eorseq  r0, r3, r0
  3a:   00340000        eorseq  r0, r4, r0
        ...





这个是可以的:

.arm
_arm_mode:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x31       //输出1
        str     r1, [r0]
//      ldr r6, =_thumb_mode + 1
//      add r6, #1
        adr r6, _thumb_mode + 1
        bx r6

.thumb
_thumb_mode:
        ldr r0, =0x101f1000 //UART0发送寄存器地址
        ldr r1, =0x32       //输出2
        str     r1, [r0]


        ldr r1, =0x33       //输出3
        str     r1, [r0]

        ldr r1, =0x34       //输出4
        str     r1, [r0]

_loop:
        b _loop            //死循环


        bx lr           //跳回去

生成的代码:

$ arm-linux-gnueabi-objdump -D strap.o

strap.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_arm_mode>:
   0:   e59f0020        ldr     r0, [pc, #32]   ; 28 <_loop+0x6>
   4:   e3a01031        mov     r1, #49 ; 0x31
   8:   e5801000        str     r1, [r0]
   c:   e28f6001        add     r6, pc, #1
  10:   e12fff16        bx      r6

00000014 <_thumb_mode>:
  14:   4804            ldr     r0, [pc, #16]   ; (28 <_loop+0x6>)
  16:   4905            ldr     r1, [pc, #20]   ; (2c <_loop+0xa>)
  18:   6001            str     r1, [r0, #0]
  1a:   4905            ldr     r1, [pc, #20]   ; (30 <_loop+0xe>)
  1c:   6001            str     r1, [r0, #0]
  1e:   4905            ldr     r1, [pc, #20]   ; (34 <_loop+0x12>)
  20:   6001            str     r1, [r0, #0]

00000022 <_loop>:
  22:   e7fe            b.n     22 <_loop>
  24:   4770            bx      lr
  26:   10000000        andne   r0, r0, r0
  2a:   0032101f        eorseq  r1, r2, pc, lsl r0
  2e:   00330000        eorseq  r0, r3, r0
  32:   00340000        eorseq  r0, r4, r0

难道是ldr伪指令不能生成跳转到thumb?

离线

#16 2021-05-24 21:09:41

raspberryman
会员
注册时间: 2019-12-27
已发帖子: 503
积分: 465

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

离线

楼主 #17 2021-05-24 23:17:51

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

QQ截图20210524231541.png

QQ截图20210524231645.png

同样都是 0x15 给 R6, 为什么 上面的不行呢?

离线

楼主 #18 2021-05-25 10:19:20

奔跑的孩子
会员
注册时间: 2021-01-28
已发帖子: 51
积分: 31.5

Re: 请教大家一个问题,thumb状态下,每一条指令都是16bit长度吗?

2021-05-25_101634.png


感觉应该是qemu虚拟机的bug, 因为我用 MDK + GCC工具链 + 模拟调试, 发现编译出来的代码并无二致。

寄存器值一模一样。

离线

页脚

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

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