I am trying to fix this part of an abandonware program是因为I failed to find an alternative program。
正如您可以看到的,see the data of PUSH instructions的顺序是错误的,而Ethereum是一台高字节顺序的机器(地址被正确表示,因为它们使用的是较小的类型)。
另一种方法是运行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序列
发布于 2019-09-29 16:06:02
顺便说一句,这不是字节序问题;您不是在对对象表示进行字节访问。您将其作为256位整数进行操作,并使用data & 0xFF一次只请求低8位。
如果您确实知道目标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
}
}在内部循环中,比使用两次移位更有效的方法是使用旋转将高位字节移到底部(对于& 0xFF),同时向上移动低位字节。Best practices for circular shift (rotate) operations in C++
在外部循环中,IDK if boost::multiprecision::number有任何用于高效索引内建块的API;如果有,使用这些API可能会更有效。
我使用嵌套循环是因为我假设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;如果你想把它分成块来换行,你也可以这样做。
如果您对一次8、16或32字节的数据有效转换为十六进制感兴趣,请参阅How to convert a number to hex? 中的一些x86 SIMD ways。asm应该可以很容易地移植到C++内部。(您可以使用SIMD shuffles处理从little-endian整数加载后将字节放入MSB优先打印顺序。)
您还可以使用SIMD shuffle来分隔您的十六进制数字对,然后再存储到内存中,就像您显然想要的那样。
您添加的代码中存在错误:
,所以我在上面的循环之前添加了这段代码:
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包装器函数。
https://stackoverflow.com/questions/58153194
复制相似问题