我正在尝试将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

最佳答案

extsb 的文档条目的标题说,助记符是扩展符号字节的缩写。即执行2's complement sign-extension.

看起来好像是PowerPC文档编号从左开始的数字位,因此高位是位0,低位是位31。低8位的符号位因此是24位,此指令仅执行符号扩展。

#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++表示,当您移负数时会发生什么取决于实现,但是大多数实现(以及某些方言,例如GNU C++)都保证右移时2的补码符号扩展。即移入高位副本。

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



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

起初,我以为“低8位”是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。这是一堆实际的移位和与/或运算。

09-04 12:03