我在Cortex-M3中读到的只是拇指,每当我们写入PC时,我们必须确保目标地址LSB为'1'以确保处理器保持在拇指模式。
此外,当我们使用'BX reg'时,reg值必须为LSB = 1才能启用拇指模式。
我们在cortex-m3中使用'B标签'的情况怎么样?由于16位/ 32位指令与偶数地址对齐,因此'label'将具有LSB = 0的值。 “B标签”不等同于“PC:= label”吗?
“B标签”和“BL标签”特殊情况下PC的写入不会影响处理器模式吗?
谢谢。
答案 0 :(得分:1)
“B标签”不等同于“PC:=标签”吗?
实际上PC := PC + offset * 2
在指令中编码了偏移量。汇编器/链接器必须计算此偏移量。
有关指令编码的详细信息,请参阅Armv7-M的ARM体系结构参考手册。
“B标签”和“BL标签”特殊情况下PC的写入不会影响处理器模式吗?
是。最后一位在B(L) label
指令中不编码,因此无法更改拇指模式位。
答案 1 :(得分:1)
目标地址需要为bx(和blx)指令设置lsbit为1,当进入pc时,1被剥离。 b指令是pc相对的,arm文档中显示的数学表明它是偶数。
一般情况下,如果让工具完成工作,您无论如何都不必担心这一点。
thumb.s
.thumb
.globl _start
_start:
b reset
nop
nop
.thumb_func
reset:
nop
nop
nop
nop
ldr r0,=reset
bx r0
然后
arm-none-eabi-as thumb.s -o thumb.o
arm-none-eabi-ld -Ttext=0x1000 thumb.o -o thumb.elf
arm-none-eabi-objdump -D thumb.elf
给出了
thumb.elf: file format elf32-littlearm
Disassembly of section .text:
00001000 <_start>:
1000: e001 b.n 1006 <reset>
1002: 46c0 nop ; (mov r8, r8)
1004: 46c0 nop ; (mov r8, r8)
00001006 <reset>:
1006: 46c0 nop ; (mov r8, r8)
1008: 46c0 nop ; (mov r8, r8)
100a: 46c0 nop ; (mov r8, r8)
100c: 46c0 nop ; (mov r8, r8)
100e: 4801 ldr r0, [pc, #4] ; (1014 <reset+0xe>)
1010: 4700 bx r0
1012: 10070000 andne r0, r7, r0
...
分支机构负责自己
1000: e001 b.n 1006 <reset>
...
00001006 <reset>:
分支中的编码以16位数量为单位而不是字节单位,然后将它乘以2(移位)以获得始终为偶数的字节地址。 pc永远不会奇怪,它是你输入bx或blx的值是奇数。
现在因为我在重置之前使用了.thumb_func告诉汇编程序这是一个拇指标签而不是一个手臂标签。所以,当我说,请将重置地址加载到r0,汇编器然后为值0x00001007分配了一些数据,这在反汇编中显示出奇怪但它就在那里。他们为我们设置了lsbit
00001006 <reset>:
...
100e: 4801 ldr r0, [pc, #4] ; (1014 <reset+0xe>)
1010: 4700 bx r0
1012: 10070000 andne r0, r7, r0
现在,如果您要删除.thumb_func
100c: 46c0 nop ; (mov r8, r8)
100e: 4801 ldr r0, [pc, #4] ; (1014 <reset+0xe>)
1010: 4700 bx r0
1012: 10060000 andne r0, r6, r0
汇编程序认为它是一个arm地址,并且没有设置lsbit,这段代码会崩溃。现在,如果你担心它,你总是可以添加额外的orr r0,#1但这实际上只是一个黑客。了解您使用的装配器如何将标签声明为拇指标签而不是手臂。是的,gnu汇编程序知道这个代码段是拇指似乎很愚蠢,因为我们告诉它但它不能弄清楚拇指代码中的标签是......拇指标签。非常愚蠢的工具。
我认为还有其他更详细的gnu汇编程序指令,它们也允许你声明这个函数或拇指标签或其他什么。当然,每个汇编程序都是不同的,所以不要认为gnu汇编程序指令适用于其他汇编程序指令。
如果混合C和asm,C编译器不是傻瓜,它知道-mthumb使得所有函数和全局变量(标签)都是拇指,并且根据代码中使用它们的方式和位置,链接器会放置正确的值。它甚至可以为你正确切换模式,主要是拇指代码,主要是手臂代码,它为你切换模式的代码放置了一个蹦床。或反之亦然,至少我看到该工具这样做(并在堆栈溢出答案中多次演示)。我不记得是否让它工作起来很棘手你应该总是定期拆解并确保链接器正在为你做这件事,否则你可以做到这一点,或者你总是可以自己做这件事。
所以
请记住,只有bx和blx需要为拇指设置lsbit,并且需要重置两个lsbits才能分支到arm。 blx和bx指令将删除该lsbit并在pc中留下偶数pc(非常简单的做一个mov r0,pc然后用拇指代码查看)。
理想情况下,无条件和条件分支(不是bx)永远不应该将模式转换为手臂,拇指转换为拇指。同样的bl,但我已经看到gnu工具帮助解决这个问题,如果你想要你的代码纯净然后将地址加载到工具必须正确的寄存器中,否则整个工具链是失败的,而blx而不是bl那个标签并不依赖于工具链为你做蹦床。