我正在尝试将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
。这是一堆实际的移位和与/或运算。