unaligned access store on intel processor
考虑下面的示例。它在标记行出现 gcc 5.4 的段错误时
我用
我在 Intel i5-5200U 上运行它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <vector> #include <memory> #include <cstdint> using namespace std; __attribute__ ((noinline)) void SerializeTo(const vector<uint64_t>& v, uint8_t* dest) { for (size_t i = 0; i < v.size(); ++i) { *reinterpret_cast<uint64_t*>(dest) = v[i]; // Segfaults here. dest += sizeof(uint64_t); } } int main() { std::vector<uint64_t> d(64); unique_ptr<uint8_t[]> tmp(new uint8_t[1024]); SerializeTo(d, tmp.get() + 6); return 0; } |
您在数组中步进了 6 个字节,所以它现在未对齐。编译器无法知道它必须避免需要对齐的指令;这就是类型双关语是未定义行为的原因。
在 c 中合法地执行类型双关的方法很少。
魔术函数
1 2 3 4 5 6 7 | __attribute__ ((noinline)) void SerializeTo(const vector<uint64_t>& v, uint8_t* dest) { for (size_t i = 0; i < v.size(); ++i) { std::memcpy(dest, std::addressof(v[i]), sizeof(v[i])); dest += sizeof(uint64_t); } } |
结果输出与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | SerializeTo(std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned char*): # @SerializeTo(std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned char*) mov rax, qword ptr [rdi] cmp qword ptr [rdi + 8], rax je .LBB0_3 xor ecx, ecx .LBB0_2: # =>This Inner Loop Header: Depth=1 mov rax, qword ptr [rax + 8*rcx] mov qword ptr [rsi + 8*rcx], rax add rcx, 1 mov rax, qword ptr [rdi] mov rdx, qword ptr [rdi + 8] sub rdx, rax sar rdx, 3 cmp rcx, rdx jb .LBB0_2 .LBB0_3: ret |
https://godbolt.org/g/ReGA9N