【问题标题】:Getting an label address to a register on THUMB assembly - Armv5获取标签地址到 THUMB 程序集上的寄存器 - Armv5
【发布时间】:2019-12-26 23:38:59
【问题描述】:

我正在尝试获取拇指组件中标签的地址,但遇到了一些问题。

我已经阅读了this post,但这对我没有帮助,我会解释原因。

我正在用 Thumb 程序集编写一个简单的程序(不幸的是我不能使用 Thumb2)。

让我们考虑这段代码:

 .arch armv5te
 .syntax unified
 .text     

 .thumb
 .thumb_func
 thumbnow:
 0x0       PUSH {LR}
 0x2       LDR R0, =loadValues
 0x4       POP {PC}
 .align
 loadValues:
 0x8        .word 0xdeadbee1
 0xC        .word 0xdeadbee2
 0x10       .word 0xdeadbee3

我正在使用 arm-linux-gnueabi 工具链来组装它。

我的微控制器没有 MMU,所以内存地址是静态的,没有虚拟页面等。

我想要做的事情是让 R0 的值在此处为 0x8,这样我就可以像这样访问三个单词:

LDR R1, [R0]
LDR R2, [R0,#4]
LDR R3, [R0,#8]

这在 LDR 中是不可能的,因为字中的值不可能适合 MOV 命令。汇编器的文档指出,如果该值不能适合 MOV 命令,那么它将将该值放入文字池中。

所以我的问题是,如果地址的内容不适合 MOV 命令,是否可以在 Thumb 程序集中获取标签的实际地址?

【问题讨论】:

  • 是的,你让工具把它放在附近的水池里,它就可以到达那里。 gnu 汇编器会将 ldr 转换为 pc 相对负载。它不是为你做的吗?
  • 它确实适用于文字池,但我的问题(主要出于好奇)是是否有可能实际获取实际数据的地址,而不是文字池实例的地址。
  • 与固定长度指令集中的任何立即数一样,您在有效位的数量方面受到限制。 arm、mips、risc-v 等 thumb 和 16 位 mips(和 16 位 risc-v)指令会进一步限制您,所以一般不会。它不适用于所有情况。这种愿望的另一个问题是地址是在组装期间而不是在链接时间确定的,因此可以说他们可以为相对于 pc 的加载进行编码,然后放弃该常数并在链接时使其成为相对于 pc 的添加。但没有,也许那是语言问题(目标的每种汇编语言都特定于工具)
  • 如果你在gnu assembler for arm上使用ldr,如果它知道当时的值并且合适的话,它可以使它成为mov。人们希望它也能将 ldr 切换为 adr 伪指令的等效项,但没有。一个实验是将 adr 与不适合的立即数一起使用,看看汇编器是否失败,或者将其转换为 ldr 加 add 或其他东西。

标签: gcc assembly arm reverse-engineering thumb


【解决方案1】:

从这里开始

.thumb

    ldr r0,=hello
    adr r0,hello

nop
nop
nop
nop
hello:
    .word 0,1,2,3

取消链接

00000000 <hello-0xc>:
   0:   4806        ldr r0, [pc, #24]   ; (1c <hello+0x10>)
   2:   a002        add r0, pc, #8  ; (adr r0, c <hello>)
   4:   46c0        nop         ; (mov r8, r8)
   6:   46c0        nop         ; (mov r8, r8)
   8:   46c0        nop         ; (mov r8, r8)
   a:   46c0        nop         ; (mov r8, r8)

0000000c <hello>:
   c:   00000000    andeq   r0, r0, r0
  10:   00000001    andeq   r0, r0, r1
  14:   00000002    andeq   r0, r0, r2
  18:   00000003    andeq   r0, r0, r3
  1c:   0000000c    andeq   r0, r0, r12

链接

00001000 <hello-0xc>:
    1000:   4806        ldr r0, [pc, #24]   ; (101c <hello+0x10>)
    1002:   a002        add r0, pc, #8  ; (adr r0, 100c <hello>)
    1004:   46c0        nop         ; (mov r8, r8)
    1006:   46c0        nop         ; (mov r8, r8)
    1008:   46c0        nop         ; (mov r8, r8)
    100a:   46c0        nop         ; (mov r8, r8)

0000100c <hello>:
    100c:   00000000    andeq   r0, r0, r0
    1010:   00000001    andeq   r0, r0, r1
    1014:   00000002    andeq   r0, r0, r2
    1018:   00000003    andeq   r0, r0, r3
    101c:   0000100c    andeq   r1, r0, r12

两种方式 r0 都会将地址返回到数据的开头,然后您可以从调用者或任何地方偏移到该数据的开头。

编辑

.thumb
adr r0,hello
nop
nop
nop

 arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:2: Error: address calculation needs a strongly defined nearby symbol

因此,该工具不会为您将其变成池中的负载。

对于您想要做的事情,我认为 pc 相对添加 (adr) 是您将获得的最好的。您可以尝试其他工具链,因为所有这些都是特定于语言和工具链的(汇编语言是由汇编器而不是目标定义的,并且对于每个工具链(带有汇编器),语言可能会有所不同)。随着时间的推移,在 gnu 中,链接器和汇编器协同工作的方式发生了变化,链接器修补了它不习惯的东西。

您当然可以进入链接器并向其添加代码以执行此优化,问题很可能是在链接时链接器正在寻找解决池中的地址,这对它来说很容易做到'不必更改指令,汇编器必须为链接器留下信息,这不仅仅是用地址填充这个内存位置,或者你修改gas以允许adr工作,然后如果链接器无法解析它在指令中,然后链接器会因错误而退出。'

或者您可以硬编码您想要的内容并对其进行维护。我不确定为什么 adr 解决方案不够。

mov r0,#8 是有效的拇指指令。

【讨论】:

  • 注意答案在上一篇文章的答案中,所以这在技术上是重复的。
  • 我认为我有什么问题,我明天试试,我会发送更新:) 非常感谢你的回答!
  • 你是对的,我很困惑,因为 adr 命令不在 ARMV5 手册中,我“不太聪明”认为 ARMV5 不支持它。然后你这么说,我意识到这是一条伪指令,汇编器会将其转换为体系结构支持的东西。非常感谢您抽出宝贵时间,我知道这似乎是一个愚蠢的问题,但它帮助我对这个主题有了更好的直觉。
  • 如果有疑问,请尝试最坏的情况,汇编程序无法识别它......这就是我所做的,我猜很幸运。
猜你喜欢
  • 2013-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多