I am trying to fix this part of an abandonware program因为I failed to find an alternative program .
尽你所能 see the data of PUSH instructions顺序错误,而以太坊是大端机器(地址正确表示,因为它们使用较小的类型)。
另一种方法是运行 porosity.exe --code '0x61004b60026319e44e32' --disassm
u256
类型定义为
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
这是一个 minimal example to reproduce the bug :
#include <sstream>
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_int.hpp>
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
int main() {
std::stringstream stream;
u256 data=0xFEDEFA;
for (int i = 0; i<5; ++i) { // print only the first 5 digits
uint8_t dataByte = int(data & 0xFF);
data >>= 8;
stream << std::setfill('0') << std::setw(sizeof(char) * 2) << std::hex << int(dataByte) << " ";
}
std::cout << stream.str();
}
所以数字被转换为字符串,每个字节之间有一个空格(并且只有第一个字节)。
但后来我遇到了字节序问题:字节以相反的顺序打印。我的意思是,例如,31722
在我的机器上写成 8a 02 02
而在为大端目标编译时写成 02 02 8a
。
因为我不知道要调用哪个 boost 函数,所以我 modified the code :
#include <sstream>
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_int.hpp>
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
int main() {
std::stringstream stream;
u256 data=0xFEDEFA;
for (int i = 0; i<5; ++i) {
uint8_t dataByte = int(data >> ((32 - i - 1) * 8));
stream << std::setfill('0') << std::setw(sizeof(char) * 2) << std::hex << int(dataByte) << " ";
}
std::cout << stream.str();
}
现在,为什么我的 256 位整数大部分打印为 00 00 00 00 00
系列?
最佳答案
顺便说一句,这不是字节序问题;您没有对对象表示进行字节访问。您将其作为 256 位整数进行操作,并使用 data & 0xFF
一次简单地请求低 8 位。
如果您确实知道 objective-c 实现的字节序,以及 boost
对象的数据布局,您可以使用 unsigned char*
按降序地址顺序有效地循环它。
您引入字节顺序的概念只是因为它与字节反转相关联,而这正是您想要做的。 但这真的很低效,只需以另一种方式循环遍历 bigint 的字节即可。
我对推荐一个特定的解决方案犹豫不决,因为我不知道什么可以有效编译。但是你可能想要这样的东西而不是提前字节反转:
for (outer loop) {
uint64_t chunk = data >> (64*3); // grab the highest 64-bit chunk
data <<= 64; // and shift everything up
// alternative: maybe keep a shift-count in a variable instead of modifying `data`
// Then pick apart the chunk into its component bytes, in MSB first order
for (int = 0 ; i<8 ; i++) {
unsigned tmp = (chunk >> 56) & 0xFF;
// do something with it
chunk <<= 8; // bring the next byte to the top
}
}
在内部循环中,比使用两次移位更有效的方法是使用 rotate 将高字节移到底部(对于 & 0xFF
),同时向上移动低字节。
Best practices for circular shift (rotate) operations in C++
在外层循环中,如果 boost::multiprecision::number
有任何内置 block 的高效索引的 API,则 IDK;如果是这样,使用它可能更有效。
我使用嵌套循环是因为我假设 data <<= 8
的编译效率不是特别高, (data >> (256-8)) & 0xFF
也不会。但这就是您从顶部而不是底部获取字节的方式。
另一个选项是将数字转换为字符串的标准技巧:将字符按降序存储到缓冲区中。一个 256 位(32 字节)的数字将占用 64 个十六进制数字,并且您需要在它们之间再留出 32 个字节的空格。
例如:
// 97 = 32 * 2 + 32, plus 1 byte for an implicit-length C string terminator
// plus another 1 for an extra space
char buf[98]; // small enough to use automatic storage
char *outp = buf+96; // pointer to the end
*outp = 0; // terminator
const char *hex_lut = "0123456789abcdef";
for (int i=0 ; i<32 ; i++) {
uint8_t byte = data & 0xFF;
*--outp = hex_lut[byte >> 4];
*--outp = hex_lut[byte & 0xF];
*--outp = ' ';
data >>= 8;
}
// outp points at an extra ' '
outp++;
// outp points at the first byte of a string like "12 ab cd"
stream << outp;
如果你想把它分成 block 并在其中放一个换行符,你也可以这样做。
如果您对一次性将 8、16 或 32 字节数据高效转换为十六进制感兴趣,请参阅 How to convert a number to hex? 了解一些 x86 SIMD 方式。 asm 应该很容易移植到 C++ 内在函数。 (您可以使用 SIMD 随机播放来处理从小端整数加载后将字节放入 MSB 优先的打印顺序。)
您还可以使用 SIMD 洗牌在存储到内存之前使用空格分隔您的十六进制数字对,就像您在这里显然想要的那样。
您添加的代码中的错误:
So I added this code before the loop above:
for(unsigned int i=0,data,_data;i<33;++i)
unsigned i, data, _data
声明了 unsigned int
类型的新变量,这些变量隐藏了 data
和 _data
之前的声明。该循环对循环范围外的 data
或 _data
的影响为零。 (并且包含 UB,因为您读取 _data
和 data
而没有初始化它们。)
如果这些变量实际上仍然是外部范围的 u256
变量,那么除了效率之外我没有看到明显的问题,但也许我也遗漏了明显的问题。我看起来并没有很努力,因为使用 64x 256 位移位和 32x OR 似乎是一个可怕的想法。 可能它可以完全优化掉,或者在具有它们的 ISA 上进入 bswap
字节反转指令,但我对此表示怀疑。尤其是 boost::multiprecision::number
包装函数的额外复杂性。
关于c++ - 如何将boost多精度整数从小端转换为大端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58153194/