blob: 44299912d54468d099376bc22175cf496b324ba2 [file] [log] [blame]
// Copyright 2023 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.
#include <lib/ld/abi.h>
#include <lib/ld/module.h>
#include <lib/ld/tls.h>
#include "ensure-test-thread-pointer.h"
#include "test-start.h"
#include "tls-dep.h"
[[gnu::used, gnu::retain]] alignas(64) constinit thread_local int tls_data = 23;
[[gnu::used, gnu::retain]] constinit thread_local char tls_bss[2];
using Traits = elfldltl::TlsTraits<>;
constexpr size_t kExpectedAlign = 64;
static_assert(kExpectedAlign >= kTlsDepAlign);
constexpr size_t kAlignedExecOffset =
Traits::kTlsLocalExecOffset == 0
? 0
: (Traits::kTlsLocalExecOffset + kExpectedAlign - 1) & -kExpectedAlign;
constexpr size_t kExecOffset = Traits::kTlsNegative ? -kExpectedAlign : kAlignedExecOffset;
constexpr size_t kShlibOffset =
Traits::kTlsNegative ? -(kExpectedAlign + kTlsDepAlignedTotalSize)
: ((kExecOffset + sizeof(int) * 2 + kTlsDepAlign - 1) & -kTlsDepAlign);
constexpr size_t kExpectedSize = Traits::kTlsNegative ? kExpectedAlign + kTlsDepAlignedTotalSize
: kShlibOffset + kTlsDepTotalSize;
constexpr ptrdiff_t kTpOffsetForDepData = std::bit_cast<ptrdiff_t>(kShlibOffset);
constexpr ptrdiff_t kTpOffsetForDepBss = std::bit_cast<ptrdiff_t>(kShlibOffset + kTlsDepAlign);
extern "C" int64_t TestStart() {
const auto modules = ld::AbiLoadedModules(ld::abi::_ld_abi);
const auto& exec_module = *modules.begin();
const auto& shlib_module = FindTlsDep(modules);
if (exec_module.tls_modid != 1) {
return 1;
}
if (shlib_module.tls_modid != 2) {
return 2;
}
if (ld::abi::_ld_abi.static_tls_modules.size() != 2) {
return 3;
}
const auto& exec_tls = ld::abi::_ld_abi.static_tls_modules.front();
const auto& shlib_tls = ld::abi::_ld_abi.static_tls_modules.back();
if (exec_tls.tls_initial_data.size_bytes() != sizeof(tls_data)) {
return 4;
}
if (shlib_tls.tls_initial_data.size_bytes() != sizeof(tls_dep_data)) {
return 5;
}
if (*reinterpret_cast<const int*>(exec_tls.tls_initial_data.data()) != 23) {
return 6;
}
if (*reinterpret_cast<const int*>(shlib_tls.tls_initial_data.data()) != kTlsDepDataValue) {
return 7;
}
if (exec_tls.tls_bss_size != sizeof(tls_bss)) {
return 8;
}
if (shlib_tls.tls_bss_size != kTlsDepBssSize) {
return 9;
}
if (exec_tls.tls_alignment != 64) {
return 10;
}
if (shlib_tls.tls_alignment != kTlsDepAlign) {
return 11;
}
if (ld::abi::_ld_abi.static_tls_offsets.size() != 2) {
return 12;
}
if (ld::abi::_ld_abi.static_tls_offsets.front() != kExecOffset) {
return 13;
}
if (ld::abi::_ld_abi.static_tls_offsets.back() != kShlibOffset) {
return 14;
}
if (ld::abi::_ld_abi.static_tls_layout.alignment() != kExpectedAlign) {
return 15;
}
if (ld::abi::_ld_abi.static_tls_layout.size_bytes() != kExpectedSize) {
return 16;
}
if (ld::TlsInitialExecOffset(ld::abi::_ld_abi, 2) != kTpOffsetForDepData) {
return 18;
}
int tls_block[2] = {123, 456};
ld::TlsModuleInit(exec_tls, std::as_writable_bytes(std::span(tls_block)));
if (tls_block[0] != 23) {
return 19;
}
if (tls_block[1] != 0) {
return 20;
}
if (EnsureTestThreadPointer()) {
// The compiler will emit IE accesses here and the dynamic linker will fill
// in the GOT entries with offsets at startup. Verify that the offsets
// match what we expect.
if (ld::TpRelativeToOffset(&tls_dep_data) != kTpOffsetForDepData) {
return 21;
}
// Ideally this would generate an IE reloc with an addend, but in fact both
// compilers seem never to do that and always just generate a reloc to the
// symbol and then add 1 to the materialized pointer.
if (ld::TpRelativeToOffset(&tls_dep_bss[1]) != kTpOffsetForDepBss + 1) {
return 22;
}
}
return 17;
}