我试图了解如何实现带移位的ARM add,例如

sym.imp.__libc_start_main :                                                                                                                                                           

.plt:0x000082bc 00c68fe2 add ip, pc, 0, 12; after execution ip=0x82c4
.plt:0x000082c0 08ca8ce2 add ip, ip, 8, 20; after execution ip=0x102c4
.plt:0x000082c4 48fdbce5 ldr pc, [ip, 0xd48]!


我想知道这行

.plt:0x000082c0 08ca8ce2 add ip, ip, 8, 20;


它将把#0x8000添加到ip寄存器中。我的问题是为什么#0x8000

我会假设是:

ip = ip + (8<<20)


所以0x800000却更像是

ip = ip + (8<<(20-8))


为什么?我总是必须从班次中减去8吗?

#1 楼

这是32位系统上的循环移位。

循环移位


在计算机编程中,循环移位(或按位旋转)是
移位运算符,用于移位其操作数的所有位。与
算术移位不同,循环移位不会保留数字的符号
,也不会将数字的指数与其有效位数(有时称为尾数)区分开。与逻辑移位不同,空位
位置不填充零,而是填充不按顺序移位的位



了解代码

第一行:
由于在add ip, pc上的旋转操作仍为0,因此将其简单地翻译为#0。行:
让我们分解操作码并理解有问题的行:
由于字节顺序,应该这样阅读操作码:IP = PC + (0 << 12) = PC + 0 -始终执行此指令

e28cca08-立即添加

e-Rd是ip

28-Rn是ip

c-8向右旋转20

事实是,它不是c,而是a 08,因为我们使用的是32位系统,并且是循环移位。 >
这是一个C代码,基于Wikipedi的示例显示循环移位a:

#include <stdint.h>  // for uint32_t, to get 32bit-wide rotates, regardless of the size of int.
#include <limits.h>  // for CHAR_BIT

uint32_t rotl32 (uint32_t value, unsigned int count) {
    const unsigned int mask = (CHAR_BIT*sizeof(value)-1);
    count &= mask;
    return (value<<count) | (value>>( (-count) & mask ));
}

uint32_t rotr32 (uint32_t value, unsigned int count) {
    const unsigned int mask = (CHAR_BIT*sizeof(value)-1);
    count &= mask;
    return (value>>count) | (value<<( (-count) & mask ));
}

int main()
{
    printf("Result: 0x%x\n",rotr32(8,20));
    return 0;
}


代码将输出:

Result: 0x8000


评论


我看到它向右旋转而不是向左旋转,谢谢!顺便说一句。行中“不是8 << 20,而是8 <<(32-12)”的错字应为8 >>(32-12)

–生锈
17年8月21日在19:14

#2 楼

在arm的正式文档中提出

当s = 1且RD = R15(PC)时,此指令用于保存状态寄存器CPSR,而不进行计算