C 中的 PowerPC extsb

PowerPC extsb in C

我正在尝试将 PowerPC asm 片段转换为 C++。这是我到目前为止所做的:

PPC:
lis       r11, ((dword_83EEF800+0x10000)@h)
lis       r10, 0x20 # 0x207E90
addi      r11, r11, -0x800 # dword_83EEF800
ori       r10, r10, 0x7E90 # 0x207E90
lis       r9, 4 # 0x46E80
ori       r9, r9, 0x6E80 # 0x46E80
lwzx      r11, r11, r10
subf      r11, r11, r28
divw      r11, r11, r9
extsb     r3, r11 // Problem

C++:
DWORD r11 = 0x83EEF800 + 0x10000;
r11 += -0x800;
DWORD r10 = 0x207E90;
DWORD r9 = 0x46E80;
r11 = *(DWORD*)(r11 + r10);
r11 -= r28;
r11 /= r9;

现在我的问题是,我将如何用 C++ 编写 "extsb" 代码?文档说在这种情况下它采用 r11 的最低有效字节并将其存储到 r3 的低 8 位。然后它将位 56(在本例中为 24,因为它是一个 32 位寄存器)放入 r3 的剩余位。要获得 r11 的最低有效字节,我会这样做:

r11 & 0xFF

但我不确定如何获取第 24 位并用它来填充 r3 的剩余位。我只能使用原生C++!如果有人知道我如何将此 ppc 操作转换为 c++,请告诉我(如果我发布的转换后的 ppc 代码中存在任何重大错误,也请告诉我)。提前致谢!

参考:https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.alangref/idalangref_extsb_instruction.htm

最简单的 C 等效项是通过 int8_t:

的转换
r3 = (int32_t) (int8_t) r11;

extsb says the mnemonic is short for Extend Sign Byte. i.e. perform 2's complement sign-extension.

的文档条目的标题

看起来PowerPC docs number bits从左边开始,所以高位是bit 0,低位是bit 31,所以低8位的符号位是bit 24,这条指令就是表演 sign-extension.

#include <stdint.h>
int32_t sign_extend_8(int src) {
  return (int32_t) (int8_t) src;
}

编译为(gcc4.8 for PowerPC, -O3 -std=c++03,因为 Godbolt 没有安装较新的 PPC gcc):

    extsb %r3,%r3
    blr

这个也是,所以我们知道他们都是对的:

// requires 2's complement arithmetic right shifts
int32_t extsb_manual(uint32_t src) {
  src <<= 24;
  return ((int32_t)src) >> 24;  // signed right shift.
}

ISO C++ 说它是 implementation-dependent 当你移动一个负数时会发生什么,但大多数实现(和一些方言,例如 GNU C++)保证 2 的补码 sign-extension 用于右移。 IE。移动高位的副本。

这使您可以通过算术右移来广播位。例如foo >> 31 产生 0 或 -1(在 2 的补码系统中)。

i'm sorry, but im can't use c++11 :

#include <cstdint>stdint.h 不需要 C++11。它至少从 C++03 开始​​就存在,如果不是更早的话。 (Godbolt 的 PPC gcc4.8 似乎部分损坏,#include <cstdint> 出错,可能是因为它来自较新的 gcc。这就是为什么即使在 C++ 中我也使用 C <stdint.h> header。)


起初我假设 "the low 8 bits" 是 0-7,就像我见过的所有其他架构一样,第 24 位是高字节的一部分。这将是一条非常奇怪的指令,但您可以通过以下方式实现它(再次使用算术右移):

// requires 2's complement arithmetic right shifts
uint32_t extsb_wrong(uint32_t src) {
    int32_t signbits = src << (31-24);  // move bit 24 to the top (bit 31)
    signbits >>= 31;            // broadcast the sign bit

    // replace the low 8 of the 0 / -1 with the low 8 of the src    
    return ((uint32_t)signbits & ~0xFFU) | (src & 0xFFU);
}

这当然不会编译为 extsb。这是一堆实际的移位和 AND / ORing。