This patch adds a new header file, "core/unaligned.hh", which defines a new operation, unaligned_cast<T*>(p). This works exctly like reinterpret_cast<T*>(p) except it is safe to use even when the address of p is not a multiple of alignof(T). A long comment in the header file explains why this unaligned_cast<> is necessary on some esoteric architectures and to quiet gcc's -fsanitize=alignment. The header file also defines a new template for holding an unaligned version of type - unaligned<T>. unaligned<T> is almost identical to our existing net::packed<>, so the next patch will implement net::packed in terms of unaligned<>. The unaligned_cast<> and unaligned<> templates are of course generally useful outside the network code, which is why I wanted them out of the networking header files and namespace. Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
67 lines
2.7 KiB
C++
67 lines
2.7 KiB
C++
/*
|
|
* This file is open source software, licensed to you under the terms
|
|
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
|
|
* distributed with this work for additional information regarding copyright
|
|
* ownership. You may not use this file except in compliance with the License.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
/*
|
|
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
// The following unaligned_cast<T*>(p) is a portable replacement for
|
|
// reinterpret_cast<T*>(p) which should be used every time address p
|
|
// is not guaranteed to be properly aligned to alignof(T).
|
|
//
|
|
// On architectures like x86 and ARM, where unaligned access is allowed,
|
|
// unaligned_cast will behave the same as reinterpret_cast and will generate
|
|
// the same code.
|
|
//
|
|
// Certain architectures (e.g., MIPS) make it extremely slow or outright
|
|
// forbidden to use ordinary machine instructions on a primitive type at an
|
|
// unaligned addresses - e.g., access a uint32_t at an address which is not
|
|
// a multiple of 4. Gcc's "undefined behavior sanitizer" (enabled in our debug
|
|
// build) also catches such unaligned accesses and reports them as errors,
|
|
// even when running on x86.
|
|
//
|
|
// Therefore, reinterpret_cast<int32_t*> on an address which is not guaranteed
|
|
// to be a multiple of 4 may generate extremely slow code or runtime errors,
|
|
// and must be avoided. The compiler needs to be told about the unaligned
|
|
// access, so it can generate reasonably-efficient code for the access
|
|
// (in MIPS, this means generating two instructions "lwl" and "lwr", instead
|
|
// of the one instruction "lw" which faults on unaligned/ access). The way to
|
|
// tell the compiler this is with __attribute__((packed)). This will also
|
|
// cause the sanitizer not to generate runtime alignment checks for this
|
|
// access.
|
|
|
|
template <typename T>
|
|
struct unaligned {
|
|
T raw;
|
|
unaligned() = default;
|
|
unaligned(T x) : raw(x) {}
|
|
unaligned& operator=(const T& x) { raw = x; return *this; }
|
|
operator T() const { return raw; }
|
|
} __attribute__((packed));
|
|
|
|
template <typename T, typename F>
|
|
inline auto unaligned_cast(F* p) {
|
|
return reinterpret_cast<unaligned<std::remove_pointer_t<T>>*>(p);
|
|
}
|
|
|
|
template <typename T, typename F>
|
|
inline auto unaligned_cast(const F* p) {
|
|
return reinterpret_cast<const unaligned<std::remove_pointer_t<T>>*>(p);
|
|
}
|