Assembly 如何将多个数据直接从标签加载到寄存器

Assembly 如何将多个数据直接从标签加载到寄存器,assembly,arm,Assembly,Arm,我想知道是否有办法将存储在内存中的字数组加载到寄存器数组中 我知道ldm可以用于一次加载多个寄存器,但我的理解是,您需要为它提供一个已经包含第一个元素的寄存器 是否有一些伪指令可以提供帮助?类似于ldm=array,{r0,r1,r2}(仿照实际伪指令ldr) 提前谢谢 见: 在传统的ARM中,有四种方法可以获得标签 target: .long 0xfeadbeef, 0xdeadfeed, 0xbaddad00 adr r0,目标 adrl r0,目标 ldr r0,=targe

我想知道是否有办法将存储在内存中的字数组加载到寄存器数组中

我知道ldm可以用于一次加载多个寄存器,但我的理解是,您需要为它提供一个已经包含第一个元素的寄存器

是否有一些伪指令可以提供帮助?类似于ldm=array,{r0,r1,r2}(仿照实际伪指令ldr)

提前谢谢

见:

在传统的ARM中,有四种方法可以获得标签

 target:
     .long 0xfeadbeef, 0xdeadfeed, 0xbaddad00
  • adr r0,目标
  • adrl r0,目标
  • ldr r0,=target
  • 子r0,pc,#(.+8-目标)
  • Thumb2添加了
    movw
    movt
    组合,但这不适用于您的用例

    第1、2、4项基本相同。第3项将一个地址作为常量添加到文本池中,并将该地址加载到寄存器中。类似C的东西

    int variable;
    const int *p = &variable;
    int *reg = p; /* load register from memory */
    
    是否有一些伪指令可以提供帮助?类似于ldm=array,{r0,r1,r2}(仿照实际伪指令ldr)

    此操作没有伪操作;您必须直接编写代码。

    鉴于上面的“目标”定义有三个值,您可以使用

     target:
         .long 0xfeadbeef, 0xdeadfeed, 0xbaddad00
     adr  r0, target
     ldm  r0, {r0-r2}  ; r0 as source/dest should work without write back
                       ; ldm r0, {r1-r3} maybe safer.
    
    伪操作未实现,因为这是“罕见的”,并且
    ldm
    具有限制性,不支持将PC偏移量作为源。大概

     ; I just thunk it.
     ldm pc, {r0-r2,pc}  ; pc is always '8' ahead, assuming arm mode.
     nop
     .long arg0, arg1, arg2, routine
    
    可能是可能的,但有限制,因为数据必须与代码一起定位,并且控制流也有限制。同样,这是一个罕见的用例,伪操作是为了更容易地将任意常量获取到通常需要的寄存器中。因此,只有
    ldm
    命令的直接编码。可能有些ARM CPU/架构不支持将同一寄存器作为目标;回写(rN!)绝对不支持。这取决于您针对的ARM CPU的类别。使用
    PC
    作为源代码可能更不可能在大型ARM cpu上工作。我建议使用第一个示例(rN!=r15),除非您的寄存器已经用完,并且使用的是已知的SOC/特定的ARM CPU


    ldrd
    指令是限制性的双字加载,但源代码具有更大的灵活性。您可以使用它加载两个值,而不需要单独的
    adr
    。比如说,

    ldr r0, r1, [pc, #offset]
    

    但它仅限于两个寄存器。目标寄存器需要是连续的,第一个是rN,其中
    N%2
    为零或N甚至是

    在最近的ARM上有加载一对寄存器的
    ldp
    。不确定附近的PC相对寻址模式是否可以使用
    ldm
    。如果数据距离较远,您仍然需要在寄存器中输入标签地址。您可以使用要加载的最后一个寄存器作为地址的暂存寄存器。@PeterCordes我认为
    ldm
    会将源代码加载到内部加载/存储管道寄存器中,因此在目标列表中使用加载将其加载是可以的。问题在于回写。从内存加载寄存器并写回结束值有点不合情理。但是OP不想这样。如果某个地方的某个ARM不支持
    ldm rN,{…,rN}
    ,我不会感到惊讶,但它应该可以工作。@artlessnoise:是的,我正在想象使用
    ldm
    而不写回覆盖地址寄存器。如果可能的话。(由于我在第一篇评论中提到了这种可能性,PC relative
    ldm
    是不可能的。指令使用指令字中的空格代替位移,用于加载寄存器的位图。感谢提醒,ldm需要寄存器中的指针,而不是正常的addr模式。)
    ldm
    不是真正的伪操作,而是真正的机器指令。除非你指的是存在的意义。手册确实说回写是可选的,但也说“Rn不能是PC”。(至少在Cortex-M3上是这样,这是谷歌为ldm ldmia推出的产品)。但是,如果指定写回后缀,则reglist不能包含Rn。这意味着无需写回就可以安全地覆盖地址寄存器。(同样,Cortex-M3的文档)