【问题标题】:Simple example of Table Branch Byte (TBB) in arm thumb手臂拇指表分支字节 (TBB) 的简单示例
【发布时间】:2018-10-06 23:45:31
【问题描述】:

我正在尝试了解 TBB 在手臂装配中的工作原理。 我只是想找出一个简单的例子,但无论我的代码进入无限循环还是无法编译。

.syntax unified             
.thumb      

BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.global example_TBB
.thumb_func
 example_TBB:
 mov r1, #1

 ADR.W r0, BranchTable_Byte
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r2, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r3, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r4, #3
    b endTBB

 endTBB:

 bx lr

我相信应该发生的事情是,由于 r1=1,tbb 操作代码应该分支到案例 2,但是无论我玩了多久,我都会遇到无限循环和/或编译错误。

【问题讨论】:

  • 对于初学者,您必须在此函数内的堆栈中保留 r4,您不能修改它。 r0,r1,r2,r3 可以修改。
  • 如果您在 adr.w 之后立即返回,您是否可以根据需要看到 r0 中的表地址?

标签: assembly arm thumb


【解决方案1】:

所以.s

.globl _start
_start:
    bl example_TBB
    b .

tbb.s

.syntax unified
.thumb

BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.global example_TBB
.thumb_func
 example_TBB:
 mov r1, #1

 ADR.W r0, BranchTable_Byte
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r0, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r0, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r0, #3
    b endTBB

 endTBB:

 bx lr

为文本地址和数据地址创建一个位置并不重要,这是看工具在做什么

arm-none-eabi-ld -Ttext=0x1000 -Tdata=0x2000 so.o tbb.o -o so.elf

00001000 <_start>:
    1000:   fb000000    blx 100a <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <BranchTable_Byte>:
    1008:       svcmi   0x00060300

0000100a <example_TBB>:
    100a:   01f04f06    mvnseq  r4, r6, lsl #30
    100e:   af01        add r7, sp, #4
    1010:   08f2        lsrs    r2, r6, #3

你去,有一个大问题。一个表的 3 个字节的数据怎么能放在两个字节中?

您的代码暗示您可能想要这样做:

.syntax unified
.thumb
.data
BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.global example_TBB
.thumb_func
 example_TBB:
 mov r1, #1

 ADR.W r0, BranchTable_Byte
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r0, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r0, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r0, #3
    b endTBB

 endTBB:

 bx lr

哇,那更糟(嗯,它是一个 adr 不是加载地址)

00001000 <_start>:
    1000:   fa000000    blx 1008 <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <example_TBB>:
    1008:   f04f 0101   mov.w   r1, #1
    100c:   f2af 0004   subw    r0, pc, #4
    1010:   e8d0 f001   tbb [r0, r1]

00001014 <Case1>:
    1014:   f04f 0001   mov.w   r0, #1
    1018:   e005        b.n 1026 <endTBB>

0000101a <Case2>:
    101a:   f04f 0002   mov.w   r0, #2
    101e:   e002        b.n 1026 <endTBB>

00001020 <Case3>:
    1020:   f04f 0003   mov.w   r0, #3
    1024:   e7ff        b.n 1026 <endTBB>

00001026 <endTBB>:
    1026:   4770        bx  lr

Disassembly of section .data:

00002000 <__data_start>:
    2000:   Address 0x0000000000002000 is out of bounds.

您的表格有 3 个字节深,为了对齐目的将其设为 4 个字节

.syntax unified
.thumb
BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation
 .byte 0

.text
.global example_TBB
.thumb_func
 example_TBB:
 mov r1, #1

 ADR.W r0, BranchTable_Byte
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r0, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r0, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r0, #3
    b endTBB

 endTBB:

 bx lr

给予

00001000 <_start>:
    1000:   fa000001    blx 100c <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <BranchTable_Byte>:
    1008:   00060300    andeq   r0, r6, r0, lsl #6

0000100c <example_TBB>:
    100c:   f04f 0101   mov.w   r1, #1
    1010:   f2af 000c   subw    r0, pc, #12
    1014:   e8d0 f001   tbb [r0, r1]

现在 4 个字节适合 4 个字节要好得多。那很好。但更好的是,如果您将数据与代码内联,您应该对齐或者将数据放在后面......

.syntax unified
.thumb
BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.align
.global example_TBB
.thumb_func

 example_TBB:
 mov r1, #1
...

这也解决了它:

00001000 <_start>:
    1000:   fa000001    blx 100c <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <BranchTable_Byte>:
    1008:   00060300    andeq   r0, r6, r0, lsl #6

0000100c <example_TBB>:
    100c:   f04f 0101   mov.w   r1, #1
    1010:   f2af 000c   subw    r0, pc, #12
    1014:   e8d0 f001   tbb [r0, r1]

您可能希望您的表格在您指定的 .text 格式中。如果你把它放在 .data 中,那么假设这是一个微控制器,你必须从闪存到内存。但是你需要做一些稍微不同的事情。

.syntax unified
.thumb

.data
BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.global example_TBB
.thumb_func

 example_TBB:
 mov r1, #1

 ldr r0,=BranchTable_Byte
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r0, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r0, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r0, #3
    b endTBB

 endTBB:

 bx lr


Disassembly of section .text:

00001000 <_start>:
    1000:   fa000000    blx 1008 <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <example_TBB>:
    1008:   f04f 0101   mov.w   r1, #1
    100c:   4806        ldr r0, [pc, #24]   ; (1028 <endTBB+0x4>)
    100e:   e8d0 f001   tbb [r0, r1]

00001012 <Case1>:
    1012:   f04f 0001   mov.w   r0, #1
    1016:   e005        b.n 1024 <endTBB>

00001018 <Case2>:
    1018:   f04f 0002   mov.w   r0, #2
    101c:   e002        b.n 1024 <endTBB>

0000101e <Case3>:
    101e:   f04f 0003   mov.w   r0, #3
    1022:   e7ff        b.n 1024 <endTBB>

00001024 <endTBB>:
    1024:   4770        bx  lr
    1026:   20000000    andcs   r0, r0, r0
    ...

Disassembly of section .data:

00002000 <__data_start>:
    2000:   Address 0x0000000000002000 is out of bounds.

你不讨厌他们这样做吗?

.syntax unified
.thumb

.data
BranchTable_Byte:
 .byte 0 @; Case1 offset calculation
 .byte ((Case2-Case1)/2) @; Case2 offset calculation
 .byte ((Case3-Case1)/2) @; Case3 offset calculation

.text
.global example_TBB
.thumb_func

 example_TBB:
 mov r1, #1

 ldr r0,btbadd
 TBB [r0, r1] @; R1 is the index, R0 is the base address of the branch table

 Case1:
    @; an instruction sequence follows
    mov r0, #1
    b endTBB
 Case2:
    @; an instruction sequence follows
    mov r0, #2
    b endTBB
 Case3:
    @; an instruction sequence follows
    mov r0, #3
    b endTBB

.align
btbadd: .word BranchTable_Byte

 endTBB:

 bx lr

就这种方法而言,那就更好了。

Disassembly of section .text:

00001000 <_start>:
    1000:   fa000000    blx 1008 <example_TBB>
    1004:   eafffffe    b   1004 <_start+0x4>

00001008 <example_TBB>:
    1008:   f04f 0101   mov.w   r1, #1
    100c:   4805        ldr r0, [pc, #20]   ; (1024 <btbadd>)
    100e:   e8d0 f001   tbb [r0, r1]

00001012 <Case1>:
    1012:   f04f 0001   mov.w   r0, #1
    1016:   e007        b.n 1028 <endTBB>

00001018 <Case2>:
    1018:   f04f 0002   mov.w   r0, #2
    101c:   e004        b.n 1028 <endTBB>

0000101e <Case3>:
    101e:   f04f 0003   mov.w   r0, #3
    1022:   e001        b.n 1028 <endTBB>

00001024 <btbadd>:
    1024:   00002000    andeq   r2, r0, r0

00001028 <endTBB>:
    1028:   4770        bx  lr
    102a:   46c0        nop         ; (mov r8, r8)

Disassembly of section .data:

00002000 <__data_start>:
    2000:   Address 0x0000000000002000 is out of bounds.

但现在你有 .data 用于类似这样的东西,你不需要它是 .data。

请注意,如果您将其与已编译的代码链接,您的编译器可能符合 arm 调用约定,即您不能在函数中修改 r4,您必须保留它。这就是我修改你的代码的原因(我想你是在我为你移植到 gas 时从我这里得到的?)

叹息,我在 so.s. 中忘记了 .thumb。这很好,不是感兴趣的代码,不会在上面修复,但会在下面你可能想在代码中添加更多的偏执狂,为什么不用 .aligns 撒上它......

所以.s

.thumb
.globl _start
_start:
    .word 0x20001000
    .word reset
    .word loop
    .word loop

.thumb_func
loop: b loop
.thumb_func
reset:
    mov r0,#1
    bl example_TBB
    b .

tbb.s

.syntax unified
.thumb

.align
BranchTable_Byte:
    .byte ((Case0-Case0)/2)
    .byte ((Case1-Case0)/2)
    .byte ((Case2-Case0)/2)
    .byte ((Case3-Case0)/2)

.align
.global example_TBB
.thumb_func
example_TBB:
    and r0,#3
    adr.w r1, BranchTable_Byte
    tbb [r1, r0]

.align
Case0:
    mov r0, #1
    b endTBB
Case1:
    mov r0, #2
    b endTBB
Case2:
    mov r0, #3
    b endTBB
Case3:
    mov r0, #4
    b endTBB

.align
endTBB:
    bx lr

给予

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000013    stmdaeq r0, {r0, r1, r4}
 8000008:   08000011    stmdaeq r0, {r0, r4}
 800000c:   08000011    stmdaeq r0, {r0, r4}

08000010 <loop>:
 8000010:   e7fe        b.n 8000010 <loop>

08000012 <reset>:
 8000012:   2001        movs    r0, #1
 8000014:   f000 f804   bl  8000020 <example_TBB>
 8000018:   e7fe        b.n 8000018 <reset+0x6>
    ...

0800001c <BranchTable_Byte>:
 800001c:   09060300    stmdbeq r6, {r8, r9}

08000020 <example_TBB>:
 8000020:   f000 0003   and.w   r0, r0, #3
 8000024:   f2af 010c   subw    r1, pc, #12
 8000028:   e8d1 f000   tbb [r1, r0]

0800002c <Case0>:
 800002c:   f04f 0001   mov.w   r0, #1
 8000030:   e008        b.n 8000044 <endTBB>

08000032 <Case1>:
 8000032:   f04f 0002   mov.w   r0, #2
 8000036:   e005        b.n 8000044 <endTBB>

08000038 <Case2>:
 8000038:   f04f 0003   mov.w   r0, #3
 800003c:   e002        b.n 8000044 <endTBB>

0800003e <Case3>:
 800003e:   f04f 0004   mov.w   r0, #4
 8000042:   e7ff        b.n 8000044 <endTBB>

08000044 <endTBB>:
 8000044:   4770        bx  lr
 8000046:   46c0        nop         ; (mov r8, r8)

这是一个完整的程序,您可以在您的 stm32 上运行并使用 openocd 停止并在完成后检查寄存器以查看 r0 设置为什么。你也可以这样做

.syntax unified
.thumb
.globl _start
_start:
    mov r0,#1
    bl example_TBB
    b .

.align
BranchTable_Byte:
    .byte ((Case0-Case0)/2)
    .byte ((Case1-Case0)/2)
    .byte ((Case2-Case0)/2)
    .byte ((Case3-Case0)/2)

.align
.global example_TBB
.thumb_func
example_TBB:
    and r0,#3
    adr.w r1, BranchTable_Byte
    tbb [r1, r0]

.align
Case0:
    mov r0, #1
    b endTBB
Case1:
    mov r0, #2
    b endTBB
Case2:
    mov r0, #3
    b endTBB
Case3:
    mov r0, #4
    b endTBB

.align
endTBB:
    bx lr

0x20000000 处的 ram 链接

Disassembly of section .text:

20000000 <_start>:
20000000:   f04f 0001   mov.w   r0, #1
20000004:   f000 f804   bl  20000010 <example_TBB>
20000008:   e7fe        b.n 20000008 <_start+0x8>
2000000a:   46c0        nop         ; (mov r8, r8)

2000000c <BranchTable_Byte>:
2000000c:   09060300    stmdbeq r6, {r8, r9}

20000010 <example_TBB>:
20000010:   f000 0003   and.w   r0, r0, #3
20000014:   f2af 010c   subw    r1, pc, #12
20000018:   e8d1 f000   tbb [r1, r0]

2000001c <Case0>:
2000001c:   f04f 0001   mov.w   r0, #1
20000020:   e008        b.n 20000034 <endTBB>

20000022 <Case1>:
20000022:   f04f 0002   mov.w   r0, #2
20000026:   e005        b.n 20000034 <endTBB>

20000028 <Case2>:
20000028:   f04f 0003   mov.w   r0, #3
2000002c:   e002        b.n 20000034 <endTBB>

2000002e <Case3>:
2000002e:   f04f 0004   mov.w   r0, #4
20000032:   e7ff        b.n 20000034 <endTBB>

20000034 <endTBB>:
20000034:   4770        bx  lr
20000036:   46c0        nop         

然后你可以加载它、运行它、停止并检查 openocd 中的 r0 与你的 STM32 对话...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多