| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_SONAME_H_ |
| #define SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_SONAME_H_ |
| |
| #include <cassert> |
| #include <cstdint> |
| #include <string_view> |
| #include <type_traits> |
| |
| #if __cpp_impl_three_way_comparison >= 201907L |
| #include <compare> |
| #endif |
| |
| #include "abi-ptr.h" |
| #include "abi-span.h" |
| #include "gnu-hash.h" |
| |
| namespace elfldltl { |
| |
| // This provides an optimized type for holding a DT_SONAME / DT_NEEDED string. |
| // It always hashes the string to make equality comparisons faster. |
| template <class Elf = Elf<>, class AbiTraits = LocalAbiTraits> |
| class Soname { |
| public: |
| constexpr Soname() = default; |
| |
| constexpr Soname(const Soname&) = default; |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, |
| typename = std::enable_if_t<std::is_constructible_v<Ptr, const char*>>> |
| constexpr explicit Soname(std::string_view name) |
| : name_(name.data()), size_(static_cast<uint32_t>(name.size())), hash_(GnuHashString(name)) { |
| assert(size_ == name.size()); |
| } |
| |
| constexpr Soname& operator=(const Soname&) noexcept = default; |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, |
| typename = std::enable_if_t<std::is_constructible_v<Ptr, const char*>>> |
| constexpr Soname& operator=(std::string_view name) noexcept { |
| *this = Soname{name}; |
| return *this; |
| } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr std::string_view str() const { |
| return {name_.get(), size_}; |
| } |
| |
| // This can only be used if the std::string_view used in construction is |
| // known to point to a NUL-terminated string, such as a string literal or a |
| // DT_STRTAB entry. |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr const char* c_str() const { |
| assert(name_.get()[size_] == '\0'); |
| return name_.get(); |
| } |
| |
| constexpr uint32_t hash() const { return hash_; } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator==(const Soname& other) const { |
| return other.hash_ == hash_ && other.str() == str(); |
| } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator!=(const Soname& other) const { |
| return other.hash_ != hash_ || other.str() != str(); |
| } |
| |
| #if __cpp_impl_three_way_comparison >= 201907L |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr auto operator<=>(const Soname& other) const { |
| return str() <=> other.str(); |
| } |
| |
| #else // No operator<=>. |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator<(const Soname& other) const { |
| return str() < other.str(); |
| } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator<=(const Soname& other) const { |
| return str() <= other.str(); |
| } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator>(const Soname& other) const { |
| return str() > other.str(); |
| } |
| |
| template <typename Ptr = AbiPtr<const char, Elf, AbiTraits>, typename = decltype(Ptr{}.get())> |
| constexpr bool operator>=(const Soname& other) const { |
| return str() >= other.str(); |
| } |
| |
| #endif // operator<=> |
| |
| private: |
| // This stores a pointer and 32-bit length directly rather than just using |
| // std::string_view so that the whole object is still only two 64-bit words. |
| // Crucially, both x86-64 and AArch64 ABIs pass and return trivial two-word |
| // objects in registers but anything larger in memory, so this keeps passing |
| // Soname as cheap as passing std::string_view. This limits lengths to 4GiB, |
| // which is far more than the practical limit. |
| AbiPtr<const char, Elf, AbiTraits> name_; |
| typename Elf::Word size_ = 0; |
| typename Elf::Word hash_ = 0; |
| |
| public: |
| // <lib/ld/remote-abi-transcriber.h> introspection API. These aliases must |
| // be public, but can't be defined lexically before the private: section that |
| // declares the members; so this special public: section is at the end. |
| |
| using AbiLocal = Soname<Elf, LocalAbiTraits>; |
| |
| template <template <class...> class Template> |
| using AbiBases = Template<>; |
| |
| template <template <auto...> class Template> |
| using AbiMembers = Template<&Soname::name_, &Soname::size_, &Soname::hash_>; |
| }; |
| |
| } // namespace elfldltl |
| |
| #endif // SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_SONAME_H_ |