组装 THUMB 指令以在 Cortex-M3 上执行



作为一个练习,我想让STM32F103从内部SRAM执行。这个想法是手工编写一些THUMB汇编,用arm-none-eabi-as组装,使用OpenOCD的mwh指令将机器代码加载到SRAM中,使用reg pc 0x20000000将PC设置为SRAM的开头,最后step几次。

这是我要执行的汇编代码。这基本上是一个毫无意义的循环。

# main.S
.thumb
.syntax unified
mov r0, #40
mov r1, #2
add r2, r0, r1
mvn r0, #0x20000000
bx r0

我需要获取机器代码,以便我可以将其加载到SRAM中,但是反汇编器输出似乎不正确。

$ arm-none-eabi-as -mthumb -mcpu=cortex-m3 -o main.o main.S
$ arm-none-eabi-objdump -d -m armv7 main.o
main.o:     file format elf32-littlearm

Disassembly of section .text:
00000000 <.text>:
0:   f04f 0028   mov.w   r0, #40 ; 0x28
4:   f04f 0102   mov.w   r1, #2
8:   eb00 0201   add.w   r2, r0, r1
c:   f06f 5000   mvn.w   r0, #536870912  ; 0x20000000
10:   4700        bx  r0

THUMB 指令的长度不应该是 16 位吗?我得到的机器代码每条指令需要 4 个字节。

STM32F103是基于 cortex-m3 的。 你需要从 st 文档开始,它说然后去 arms 网站获取 cortex-m3 技术参考手册。 因为它告诉您这是基于 armv7-m 架构的,因此您可以获得架构参考手册。 然后你可以开始编程。

以正常方式从闪存运行使用矢量表,从 ram 运行可能意味着这取决于启动引脚,但如果您想使用调试器下载程序,那么您就在正确的路径上,您只是在完成之前卡住了或停止了。

# main.S
.thumb
.syntax unified
mov r0, #40
mov r1, #2
add r2, r0, r1
mvn r0, #0x20000000
bx r0

您指定了统一的语法,也许在命令行 cortex-m3 上? 还是 armv7-m? 所以你最终得到了 thumb2 扩展,它们是 ARM 记录的两个 16 位半部分(armv7-m 架构参考手册向您展示了所有说明)。 它们是可变长度的,第一个被解码,第二个只是操作数。 非thumb2都是16位,bl/blx是两个独立的16位指令,但cortex-ms希望它们背靠背,在以前的内核上,你实际上可以将它们分开,以证明它们确实是两个不同的指令。

所以例如

.cpu cortex-m3
.thumb
.syntax unified
add r2, r0, r1
adds r2, r0, r1
00000000 <.text>:
0:   eb00 0201   add.w   r2, r0, r1
4:   1842        adds    r2, r0, r1

16位"全拇指变体"编码只带有标志,所以你必须添加;如果GNU汇编程序和你指定了统一的语法,大多数人会告诉你这样做,我个人不会。只是为了让你知道:

.cpu cortex-m3
.thumb
add r2, r0, r1
adds r2, r0, r1
so.s: Assembler messages:
so.s:6: Error: instruction not supported in Thumb16 mode -- `adds r2,r0,r1'

所以

.cpu cortex-m3
.thumb
add r2, r0, r1
add r2, r0, r1
00000000 <.text>:
0:   1842        adds    r2, r0, r1
2:   1842        adds    r2, r0, r1

只是为了警告你,以防你掉进那个陷阱。 而且你不只是喜欢反汇编程序使用添加吗?

无论如何。 所以这些很好,这些是

.cpu cortex-m3
.thumb
.syntax unified
mov r0, #40
mov r1, #2
add r2, r0, r1
mvn r0, #0x20000000
bx r0

00000000 <.text>:
0:   f04f 0028   mov.w   r0, #40 ; 0x28
4:   f04f 0102   mov.w   r1, #2
8:   eb00 0201   add.w   r2, r0, r1
c:   f06f 5000   mvn.w   r0, #536870912  ; 0x20000000
10:   4700        bx  r0

就像添加 mov 的 16 位编码一样,带有标志,所以

movs r0, #40
movs r1, #2
00000000 <.text>:
0:   2028        movs    r0, #40 ; 0x28
2:   2102        movs    r1, #2
4:   eb00 0201   add.w   r2, r0, r1
8:   f06f 5000   mvn.w   r0, #536870912  ; 0x20000000
c:   4700        bx  r0

我们知道现在添加

00000000 <.text>:
0:   2028        movs    r0, #40 ; 0x28
2:   2102        movs    r1, #2
4:   1842        adds    r2, r0, r1
6:   f06f 5000   mvn.w   r0, #536870912  ; 0x20000000
a:   4700        bx  r0

mvn 没有意义,你想分支到0x20000000两件事,首先你想要0x20000000而不是0xDFFFFFFF所以试试这个

0:   2028        movs    r0, #40 ; 0x28
2:   2102        movs    r1, #2
4:   1842        adds    r2, r0, r1
6:   f04f 5000   mov.w   r0, #536870912  ; 0x20000000
a:   4700        bx  r0

其次,这是一个 cortex-m,因此您无法将 bx 到切换到 arm 模式的偶数地址,但此处理器不会这样做,因此您会出错。 您需要 lsbit 集。 所以试试这个

.cpu cortex-m3
.thumb
.syntax unified
movs r0, #40
movs r1, #2
adds r2, r0, r1
ldr r0, =0x20000001
bx r0
00000000 <.text>:
0:   2028        movs    r0, #40 ; 0x28
2:   2102        movs    r1, #2
4:   1842        adds    r2, r0, r1
6:   4801        ldr r0, [pc, #4]    ; (c <.text+0xc>)
8:   4700        bx  r0
a:   0000        .short  0x0000
c:   20000001    .word   0x20000001

使用GNU汇编器,ldr equals将选择最有效的(最小指令)解决方案,如果它可以,否则它会从池中提取。

或者您可以这样做而不使用池

.cpu cortex-m3
.thumb
.syntax unified
movs r0, #40
movs r1, #2
adds r2, r0, r1
mov r0, #0x20000000
orr r0,r0,#1
bx r0

这让我的皮肤爬行,因为你想不添加,但如果这很重要,这将使它缩短半个字:

.cpu cortex-m3
.thumb
.syntax unified
movs r0, #40
movs r1, #2
adds r2, r0, r1
mov r0, #0x20000000
adds r0,#1
bx r0
00000000 <.text>:
0:   2028        movs    r0, #40 ; 0x28
2:   2102        movs    r1, #2
4:   1842        adds    r2, r0, r1
6:   f04f 5000   mov.w   r0, #536870912  ; 0x20000000
a:   3001        adds    r0, #1
c:   4700        bx  r0

然后你需要链接。 但。。。

.cpu cortex-m3
.thumb
.syntax unified
movs r0,#0
loop:
adds r0,#1
b loop

无需链接器脚本即可链接以快速完成此操作

arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0x20000000 so.o -o so.elf
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000020000000
arm-none-eabi-objdump -d so.elf

so.elf:     file format elf32-littlearm

Disassembly of section .text:
20000000 <_stack+0x1ff80000>:
20000000:   2000        movs    r0, #0
20000002 <loop>:
20000002:   3001        adds    r0, #1
20000004:   e7fd        b.n 20000002 <loop>

打开两个窗口,在一个启动 openocd 以连接到电路板/芯片

在另一个

telnet localhost 4444

当您收到 openocd 提示时,假设一切正常

halt
load_image so.elf
resume 0x20000000

或者您可以恢复0x20000001因为这感觉更好,但无论哪种方式,该工具都很好。 现在

halt
reg r0
resume
halt
reg r0
resume

作为一个 stm32 并且都是拇指变体指令,这个例子适用于我迄今为止听说过的任何 stm32。

您将看到的是 r0 它将增加,恢复和再次停止之间的人类时间将计数很多次,您可以看到数字变化以查看程序正在运行。

telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
> load_image so.elf
6 bytes written at address 0x20000000
downloaded 6 bytes in 0.001405s (4.170 KiB/s)
> resume 0x20000000
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x20000002 msp: 0x20001000
> reg r0
r0 (/32): 0x000ED40C
> resume 
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x20000002 msp: 0x20001000
> reg r0
r0 (/32): 0x001C8777
> 

如果你想把它放在闪存中,假设蓝色药丸(这是一个蓝色药丸吧?)没有写保护闪存,有些人有,但你可以很容易地删除它(会让你弄清楚,不一定容易,专业提示在某个时候涉及完整的电源周期)。

.cpu cortex-m3
.thumb
.syntax unified
.word 0x20001000
.word reset
.thumb_func
reset:
movs r0,#0
loop:
adds r0,#1
b loop
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0x08000000 so.o -o so.elf
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000008000000
arm-none-eabi-objdump -d so.elf

so.elf:     file format elf32-littlearm

Disassembly of section .text:
08000000 <_stack+0x7f80000>:
8000000:   20001000    .word   0x20001000
8000004:   08000009    .word   0x08000009
08000008 <reset>:
8000008:   2000        movs    r0, #0
0800000a <loop>:
800000a:   3001        adds    r0, #1
800000c:   e7fd        b.n 800000a <loop>

重置向量需要是处理程序 ORRED 的地址。并且向量表需要位于0x08000000(或0x00000000但您最终会想要0x08000000或0x02000000对于某些不是这个,0x08000000对于这个,请阅读文档)。

在远程登录中进入openocd

flash write_image erase so.elf
reset
halt
reg r0
resume
halt
reg r0
resume

现在它是在闪存中编程的,所以如果你关机,那就是它运行的方式。

OpenOCD将以这样的内容结束

Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints

然后是远程登录会话

telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0xa1000000 pc: 0x0800000a msp: 0x20001000
> flash write_image erase so.elf
auto erase enabled
device id = 0x20036410
flash size = 64kbytes
wrote 1024 bytes from file so.elf in 0.115819s (8.634 KiB/s)
> reset
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800000a msp: 0x20001000
> reg r0
r0 (/32): 0x002721D4
> resume
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800000a msp: 0x20001000
> reg r0
r0 (/32): 0x0041DF80
>       

如果您希望将闪存重置为RAM,则可以这样做

.cpu cortex-m3
.thumb
.syntax unified
.word 0x20001000
.word 0x20000001

电源循环,理想情况下它应该崩溃/故障,但如果你使用 openocd 像我们之前所做的那样在 ram 中放东西

flash.elf:     file format elf32-littlearm

Disassembly of section .text:
08000000 <_stack+0x7f80000>:
8000000:   20001000    .word   0x20001000
8000004:   20000001    .word   0x20000001

so.elf:     file format elf32-littlearm

Disassembly of section .text:
20000000 <_stack+0x1ff80000>:
20000000:   2000        movs    r0, #0
20000002 <loop>:
20000002:   3001        adds    r0, #1
20000004:   e7fd        b.n 20000002 <loop>
telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x0800000a msp: 0x20001000
> flash write_image erase flash.elf
auto erase enabled
device id = 0x20036410
flash size = 64kbytes
wrote 1024 bytes from file flash.elf in 0.114950s (8.699 KiB/s)
> load_image so.elf
6 bytes written at address 0x20000000
downloaded 6 bytes in 0.001399s (4.188 KiB/s)
> reset
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x20000002 msp: 0x20001000
> reg r0
r0 (/32): 0x001700E0
> resume
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x20000004 msp: 0x20001000
> reg r0
r0 (/32): 0x00245FF1
> resume
> halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x20000002 msp: 0x20001000
> reg r0
r0 (/32): 0x00311776
> 

而是电源循环

telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> halt
> reset
stm32f1x.cpu -- clearing lockup after double fault
target state: halted
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x01000003 pc: 0xfffffffe msp: 0x20000fe0
Polling target stm32f1x.cpu failed, trying to reexamine
stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
> halt
> 

是的,没有像预期/期望的那样满意。

注意 _start 来自默认链接器脚本中的 ENTRY(_start),它不是特殊的,也不是真正硬编码到工具中(对于 gcc 来说也不是主要的,它来自默认引导程序)。

所以你可以这样做

所以.s

.cpu cortex-m3
.thumb
.syntax unified
movs r0,#0
loop:
adds r0,#1
b loop

所以

MEMORY
{
hello : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text   : { *(.text*)   } > hello
}

arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -T so.ld so.o -o so.elf
arm-none-eabi-objdump -d so.elf
so.elf:     file format elf32-littlearm

Disassembly of section .text:
20000000 <loop-0x2>:
20000000:   2000        movs    r0, #0
20000002 <loop>:
20000002:   3001        adds    r0, #1
20000004:   e7fd        b.n 20000002 <loop>

_start警告消失了。 请注意,您在链接器脚本中创建的部分名称(在本例中为 hello)不必是 ram、rom、flash 等,它们可以是您想要的,是的,您可以使用链接器脚本执行此操作,但没有文件中的 MEMORY 部分,只有 SECTION。

如果您选择

arm-none-eabi-objcopy -O binary so.elf so.bin

OpenOCD可以读取ELF文件和其他一些文件,但是像这样的原始内存映像,您必须指定地址,否则您可能会0x00000000或谁知道什么

load_image so.bin 0x20000000

如果/当您获得一些核板时,您只需将 bin 文件复制到虚拟拇指驱动器,它会为您将其加载到目标 MCU 中,虚拟驱动器将重新加载或重新加载并显示 FAIL.TXT如果它不起作用的一种方式是如果您链接0x00000000而不是0x08000000。 不过,您不能以这种方式加载 sram,只需闪烁即可。 但我假设你有一个蓝色药丸而不是核板。

这是一个很长的答案。

简答题

这些是 thumb2 扩展名,它们的大小是两个半字。 有关说明说明,请参阅 armv7-m 架构参考手册。 它们非常适合这个芯片。

您可能想在openocd上使用load_image而不是mwh,但是如果您以正确的顺序排列半词,mwh将起作用。

理想情况下,您希望链接,尽管编写的代码或我的代码与位置无关,因此可以说您可以提取指令并使用 mwh。

该芯片具有从sram模式启动,该模式将/应该使用矢量表,而不仅仅是启动指令,您需要正确设置引导引脚并使用openocd之类的东西将程序加载到RAM中,然后重置(不是电源循环)。

MVN 移动负数或否定在这里不是正确的指令,您需要在使用 bx 之前设置 lsbit 因此您希望在寄存器中0x20000001,例如

ldr r0,=0x20000001
bx r0

对于 GNU 汇编程序,或

mov r0,#0x20000000
orr r0,#1
bx r0

但那是对于 ARMv7-M,对于 Cortex-M0、M0+ 一些 -M8,你不能使用这些指令,它们将不起作用。

.cpu cortex-m0
.thumb
.syntax unified
mov r0,#0x20000000
orr r0,#1
bx r0
arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:5: Error: cannot honor width suffix -- `mov r0,#0x20000000'
so.s:6: Error: cannot honor width suffix -- `orr r0,#1'

因此,使用 ldr = 伪指令或手动从池中加载,或加载0x2或0x20或类似的东西,然后移动它并加载另一个寄存器,用 1 和 orr 它或使用 add (yuck)。

编辑

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,=0x12345678
b .

00000000 <_start>:
0:   4800        ldr r0, [pc, #0]    ; (4 <_start+0x4>)
2:   e7fe        b.n 2 <_start+0x2>
4:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

如果它不能生成单个指令,那么它将生成一个 pc 相对负载并将变量放在文字池中,如果它能找到一个分支,则在分支之后的某个地方。

但你也可以自己做

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,myvalue
b .
.align
myvalue: .word 0x12345678

00000000 <_start>:
0:   4800        ldr r0, [pc, #0]    ; (4 <myvalue>)
2:   e7fe        b.n 2 <_start+0x2>
00000004 <myvalue>:
4:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

文字池是一个内存区域(在文本段中),用于存储常量。

unsigned int fun0 ( void )
{
return 0x12345678;
}
unsigned int fun1 ( void )
{
return 0x11223344;
}
00000000 <fun0>:
0:   e59f0000    ldr r0, [pc]    ; 8 <fun0+0x8>
4:   e12fff1e    bx  lr
8:   12345678    .word   0x12345678
0000000c <fun1>:
c:   e59f0000    ldr r0, [pc]    ; 14 <fun1+0x8>
10:   e12fff1e    bx  lr
14:   11223344    .word   0x11223344

让 C 编译器执行此操作并将其放在函数的末尾并不罕见。

.global fun1
.syntax unified
.arm
.fpu softvfp
.type   fun1, %function
fun1:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r0, .L6
bx  lr
.L7:
.align  2
.L6:
.word   287454020
.size   fun1, .-fun1

我没有为拇指/皮层-m构建它,但这很好,它会做同样的事情。 但是,说:

unsigned int fun0 ( void )
{
return 0x12345678;
}
unsigned int fun1 ( void )
{
return 0x00110011;
}
00000000 <fun0>:
0:   4800        ldr r0, [pc, #0]    ; (4 <fun0+0x4>)
2:   4770        bx  lr
4:   12345678    .word   0x12345678
00000008 <fun1>:
8:   f04f 1011   mov.w   r0, #1114129    ; 0x110011
c:   4770        bx  lr

因为我大致了解您可以立即用于各种 arm 指令集的内容。 同样

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,=0x12345678
ldr r1,=0x00110011
nop
nop
nop
b .
00000000 <_start>:
0:   4803        ldr r0, [pc, #12]   ; (10 <_start+0x10>)
2:   f04f 1111   mov.w   r1, #1114129    ; 0x110011
6:   bf00        nop
8:   bf00        nop
a:   bf00        nop
c:   e7fe        b.n c <_start+0xc>
e:   0000        .short  0x0000
10:   12345678    .word   0x12345678

通过使用ldr = thing,gnu汇编程序将选择最佳指令。 并非所有 arm 汇编程序都支持此功能(汇编语言由工具而不是目标定义),并且并非所有人都会选择最佳指令,如果某些人能够识别语法,则可能总是生成相对于 pc 的 ldr。

例如,它在某种程度上用于获取标签的地址

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,=mydataword
ldr r1,[r0]
add r1,#1
str r1,[r0]
bx lr
.data
mydataword: .word 0

在另一个段中,它无法在程序集时解决此问题,因此它为链接器留下了一个占位符

00000000 <_start>:
0:   4802        ldr r0, [pc, #8]    ; (c <_start+0xc>)
2:   6801        ldr r1, [r0, #0]
4:   f101 0101   add.w   r1, r1, #1
8:   6001        str r1, [r0, #0]
a:   4770        bx  lr
c:   00000000    .word   0x00000000
arm-none-eabi-ld -Ttext=0x1000 -Tdata=0x2000 so.o -o so.elf
arm-none-eabi-objdump -D so.elf
so.elf:     file format elf32-littlearm

Disassembly of section .text:
00001000 <_start>:
1000:   4802        ldr r0, [pc, #8]    ; (100c <_start+0xc>)
1002:   6801        ldr r1, [r0, #0]
1004:   f101 0101   add.w   r1, r1, #1
1008:   6001        str r1, [r0, #0]
100a:   4770        bx  lr
100c:   00002000    andeq   r2, r0, r0
Disassembly of section .data:
00002000 <__data_start>:
2000:   00000000

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,=somefun
ldr r1,[r0]
orr r1,#1
bx r1
.align
somefun:
nop
b .

即使在同一细分市场中

00000000 <_start>:
0:   4803        ldr r0, [pc, #12]   ; (10 <somefun+0x4>)
2:   6801        ldr r1, [r0, #0]
4:   f041 0101   orr.w   r1, r1, #1
8:   4708        bx  r1
a:   bf00        nop
0000000c <somefun>:
c:   bf00        nop
e:   e7fe        b.n e <somefun+0x2>
10:   0000000c    .word   0x0000000c

00001000 <_start>:
1000:   4803        ldr r0, [pc, #12]   ; (1010 <somefun+0x4>)
1002:   6801        ldr r1, [r0, #0]
1004:   f041 0101   orr.w   r1, r1, #1
1008:   4708        bx  r1
100a:   bf00        nop
0000100c <somefun>:
100c:   bf00        nop
100e:   e7fe        b.n 100e <somefun+0x2>
1010:   0000100c    andeq   r1, r0, r12

如果你让工具完成工作

.cpu cortex-m3
.thumb
.syntax unified
.globl _start
_start:
ldr r0,=somefun
ldr r1,[r0]
bx r1
.align
.thumb_func
somefun:
nop
b .

你不需要在lsbit中orr,该工具会为你完成

00001000 <_start>:
1000:   4802        ldr r0, [pc, #8]    ; (100c <somefun+0x4>)
1002:   6801        ldr r1, [r0, #0]
1004:   4708        bx  r1
1006:   bf00        nop
00001008 <somefun>:
1008:   bf00        nop
100a:   e7fe        b.n 100a <somefun+0x2>
100c:   00001009    andeq   r1, r0, r9

这些都是或大部分情况下,文字池被用来帮助处理像这样的指令集,该指令集的长度有些固定,因此对即时值有限制。

有时你可以帮助 gnu 汇编程序将池数据放在哪里

.cpu cortex-m3
.thumb
.syntax unified
.globl fun0
.thumb_func
fun0:
ldr r0,=0x12345678
bx lr
.globl fun1
.thumb_func
fun1:
ldr r0,=0x11223344
bx lr
.align
.word 0x111111
00000000 <fun0>:
0:   4802        ldr r0, [pc, #8]    ; (c <fun1+0x8>)
2:   4770        bx  lr
00000004 <fun1>:
4:   4802        ldr r0, [pc, #8]    ; (10 <fun1+0xc>)
6:   4770        bx  lr
8:   00111111    .word   0x00111111
c:   12345678    .word   0x12345678
10:   11223344    .word   0x11223344

但是如果我

.cpu cortex-m3
.thumb
.syntax unified
.globl fun0
.thumb_func
fun0:
ldr r0,=0x12345678
bx lr
.pool
.globl fun1
.thumb_func
fun1:
ldr r0,=0x11223344
bx lr
.align
.word 0x111111
00000000 <fun0>:
0:   4800        ldr r0, [pc, #0]    ; (4 <fun0+0x4>)
2:   4770        bx  lr
4:   12345678    .word   0x12345678
00000008 <fun1>:
8:   4801        ldr r0, [pc, #4]    ; (10 <fun1+0x8>)
a:   4770        bx  lr
c:   00111111    .word   0x00111111
10:   11223344    .word   0x11223344

所以

ldr r0,=something

表示在链接时或有时将某物的地址加载到 r0 中。 标签只是地址,只是值/数字,所以

ldr r0,=0x12345678

标签的意思是一样的,而是值本身,所以给我那个标签的地址,这是0x12345678的,把它放在r0中,所以这是这个概念的一个有趣的延伸,gas或某人想到了,可能是武器组装者,我不记得当时其他人也采用了它或改进了它或其他什么。 请注意,如果您想自己做,请这样做

ldr r0,something_address
b .
.align
something_address: .word something

因为某些东西是一个标签,它是一个地址,而这个值你不会把等号放在那里,所以等于只是为了LDR指令。 与向量表相同:

.word 0x20001000
.word reset

最后,您可以执行其中之一,以使函数地址正确用于所谓的拇指互通

.cpu cortex-m3
.thumb
.syntax unified
.word 0x20001000
.word reset
.word handler
.word broken
.thumb_func
reset:
b .
.type handler,%function
handler:
b .

broken:
b .
Disassembly of section .text:
08000000 <_stack+0x7f80000>:
8000000:   20001000    .word   0x20001000
8000004:   08000011    .word   0x08000011
8000008:   08000013    .word   0x08000013
800000c:   08000014    .word   0x08000014
08000010 <reset>:
8000010:   e7fe        b.n 8000010 <reset>
08000012 <handler>:
8000012:   e7fe        b.n 8000012 <handler>
08000014 <broken>:
8000014:   e7fe        b.n 8000014 <broken>

可以使用.thumb_func如果在拇指模式下您可以使用.type label,%函数在手臂模式和拇指模式下,您可以看到它在向量表中生成了正确的拇指地址,但在两者都未使用的情况下,损坏的标签未正确生成,因此向量会在 cortex-m 上出错。

有些人可悲地这样做:

.word reset + 1
.word handler + 1
.word broken + 1

尝试解决此问题,而不是按预期使用该工具。 其他用于arm/thumb的汇编语言意味着其他工具(ARM,Kiel等)有自己的语法和规则,这仅限于GNU汇编程序。

还要注意这个答案有多少只是命令行的东西,我检查了工具的输出并对其进行了操作,直到我得到我想要的东西,不必加载和运行代码来查看发生了什么。 只需使用这些工具。

编辑 2

阅读评论中的其余问题

.cpu cortex-m3
.thumb
.syntax unified
ldr r0,=0x12345678
nop
b .

00000000 <.text>:
0:   4801        ldr r0, [pc, #4]    ; (8 <.text+0x8>)
2:   bf00        nop
4:   e7fe        b.n 4 <.text+0x4>
6:   0000        .short  0x0000
8:   12345678    .word   0x12345678

将 .word 放在偏移量 6 处将是 ldr 的对齐错误,因此他们需要填充它以将其放在单词对齐地址处。

到目前为止,您应该已经从 ARM 的网站或其他地方下载了 armv7-m 架构参考手册。 您至少可以在我正在查看的文档(这些是不断发展的文档)中看到 T1 编码

imm32 = ZeroExtend(imm8:'00', 32); add = TRUE;

再往下走

Encoding T1 multiples of four in the range 0 to 1020

address = if add then (base + imm32) else (base - imm32);
data = MemU[address,4];
R[t] = data;

指令中编码的偏移量(即时)是相对于 pc 的字数。 PC 是"提前 2"或指令的地址加 4,因此对于 ldr r0 指令

0:   4801        ldr r0, [pc, #4]    ; (8 <.text+0x8>)
2:   bf00        nop
4:   e7fe        b.n 4 <.text+0x4>  <--- pc is here
6:   0000        .short  0x0000
8:   12345678    .word   0x12345678

8 - 4 = 4; 4>>2 = 1 所以距离PC1个字,指令0x48xx xx 0x4801表示一个字。 这里再次对齐使用此指令。

那么如果我们

.cpu cortex-m3
.thumb
.syntax unified
nop
ldr r0,=0x12345678
b .

00000000 <.text>:
0:   bf00        nop
2:   4801        ldr r0, [pc, #4]    ; (8 <.text+0x8>)
4:   e7fe        b.n 4 <.text+0x4>
6:   0000        .short  0x0000
8:   12345678    .word   0x12345678

这似乎坏了

Operation
if ConditionPassed() then
EncodingSpecificOperations();
base = Align(PC,4);
address = if add then (base + imm32) else (base - imm32);
data = MemU[address,4];
if t == 15 then
if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
else
R[t] = data;

当您看到所有伪代码时,在这种情况下为 6 的 pc

然后继续阅读文档以了解伪代码

计算指令的 PC 或对齐 (PC,4) 值。指令的 PC 值是其地址加上 Thumb 指令的 4。指令的 Align(PC,4) 值是其 PC 值与 0xFFFFFFFC 并强制其字对齐。

所以0x6&0xFFFFFFFC = 4。 8 - 4 = 4; 4>>2 = 1;所以0x4801。

如果我们强制使用 thumb2 指令

.cpu cortex-m3
.thumb
.syntax unified
ldr.w r0,=0x12345678
b .

它仍然对齐可能是为了使我们免于 thumb2 版本可以达到奇数值的错误

00000000 <.text>:
0:   f8df 0004   ldr.w   r0, [pc, #4]    ; 8 <.text+0x8>
4:   e7fe        b.n 4 <.text+0x4>
6:   0000        .short  0x0000
8:   12345678    .word   0x12345678

请注意指令末尾的 4,即 pc + 4,但如果我们尝试这样做呢:

.cpu cortex-m3
.thumb
.syntax unified
ldr.w r0,something
b .
something: .word 0x12345678

相关内容

  • 没有找到相关文章

最新更新