blob: 378ed61e4ea3f8e14b56b7ba01f567ad82bc803b [file] [log] [blame]
// Copyright 2025 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 LIB_DL_TLS_DESC_RESOLVER_H_
#define LIB_DL_TLS_DESC_RESOLVER_H_
#include <lib/ld/tlsdesc.h>
#include <cassert>
#include <cstddef>
#include <memory>
#include <type_traits>
#include <fbl/intrusive_single_list.h>
#include "tlsdesc-runtime-dynamic.h"
namespace dl {
class Diagnostics;
// TlsDescResolver is used with elfldltl::MakeSymbolResolver, which specifies
// its API. For static TLS, it uses the <lib/ld/tlsdesc.h> implementation and
// its relocation protocol (based on the <lib/ld/tls.h> passive ABI). For
// dynamic TLS, it uses the tlsdesc-runtime-dynamic.h implementation with the
// relocation protocol described there.
class TlsDescResolver;
// When _dl_tlsdesc_runtime_dynamic_indirect is chosen for the runtime, it
// needs a TlsdescIndirect object to point to from the GOT. Those objects'
// lifetimes must be bound to the lifetime of the module containing that GOT.
// TlsdescIndirectList is a std::unique_ptr-owning list of address-stable
// objects; relocation has stored pointers into those objects in the GOT.
class TlsdescIndirectStorage;
using TlsdescIndirectList = fbl::SinglyLinkedList<std::unique_ptr<TlsdescIndirectStorage>>;
// TlsDescResolver is a tiny, trivial object meant to be ephemeral. It can be
// constructed directly in an rvalue argument to elfldltl::MakeSymbolResolver.
// The constructor requires two arguments: the current threshold between static
// TLS and dynamic TLS module IDs; and a reference to the TlsdescIndirectList
// owned by the RuntimeModule being relocated.
//
// The argument is the maximum TLS module ID handled by the <lib/ld/tlsdesc.h>
// runtime for static TLS cases. The first dynamic PT_TLS module, stored in
// _dl_tlsdesc_runtime_dynamic_blocks[0], has ID max_static_tls_modid + 1,
//
// The TlsdescIndirectList only needs to be default-constructed, and then
// eventually destroyed when the module's GOT is definitely no longer in use
// (or never was). It will never be touched again after this module's
// relocaton is complete; only elements' TlsdescIndirect contents will be read.
class TlsDescResolver : public ld::LocalRuntimeTlsDescResolver {
public:
using Base = ld::LocalRuntimeTlsDescResolver;
TlsDescResolver(size_type max_static_tls_modid, TlsdescIndirectList& indirect_list)
: max_static_tls_modid_(max_static_tls_modid), indirect_list_(indirect_list) {}
// The overload for undefined weak references can be used as is.
using Base::operator();
// For defined TLS symbols, the base class handles the static TLS modules.
// The dynamic TLS modules are handled in the Dynamic() method.
fit::result<bool, TlsDescGot> operator()(auto& diag, const auto& defn) const {
// The catch-all signature is needed to always override the base class, but
// this can only be used with dl::Diagnostics.
static_assert(std::is_same_v<Diagnostics, std::decay_t<decltype(diag)>>);
if (defn.tls_module_id() <= max_static_tls_modid_) {
return Base::operator()(diag, defn);
}
const size_type index = defn.tls_module_id() - max_static_tls_modid_ - 1;
return Dynamic(diag, index, defn.symbol().value);
}
private:
fit::result<bool, TlsDescGot> Dynamic(Diagnostics& diag, size_type index, size_type offset) const;
size_type max_static_tls_modid_;
TlsdescIndirectList& indirect_list_;
};
class TlsdescIndirectStorage final
: public fbl::SinglyLinkedListable<std::unique_ptr<TlsdescIndirectStorage>>,
private TlsdescIndirect {
public:
// These are only constructed once, and never moved or copied.
TlsdescIndirectStorage() = delete;
TlsdescIndirectStorage(const TlsdescIndirectStorage&) = delete;
TlsdescIndirectStorage(TlsdescIndirectStorage&&) = delete;
explicit TlsdescIndirectStorage(const TlsdescIndirect& values) noexcept
: TlsdescIndirect{values} {}
elfldltl::Elf<>::GotEntry<> got_value() const {
return reinterpret_cast<uintptr_t>(static_cast<const TlsdescIndirect*>(this));
}
};
} // namespace dl
#endif // LIB_DL_TLS_DESC_RESOLVER_H_