1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker *
5*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker * are met:
8*8d67ca89SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker * distribution.
14*8d67ca89SAndroid Build Coastguard Worker *
15*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker */
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker #define STATIC_TLS_LAYOUT_TEST
30*8d67ca89SAndroid Build Coastguard Worker
31*8d67ca89SAndroid Build Coastguard Worker #include "private/bionic_elf_tls.h"
32*8d67ca89SAndroid Build Coastguard Worker
33*8d67ca89SAndroid Build Coastguard Worker #include <string>
34*8d67ca89SAndroid Build Coastguard Worker #include <tuple>
35*8d67ca89SAndroid Build Coastguard Worker
36*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
37*8d67ca89SAndroid Build Coastguard Worker
38*8d67ca89SAndroid Build Coastguard Worker #include <android-base/silent_death_test.h>
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker #include "private/bionic_tls.h"
41*8d67ca89SAndroid Build Coastguard Worker
42*8d67ca89SAndroid Build Coastguard Worker using namespace std::string_literals;
43*8d67ca89SAndroid Build Coastguard Worker
44*8d67ca89SAndroid Build Coastguard Worker struct AlignedSizeFlat {
45*8d67ca89SAndroid Build Coastguard Worker size_t size = 0;
46*8d67ca89SAndroid Build Coastguard Worker size_t align = 1;
47*8d67ca89SAndroid Build Coastguard Worker size_t skew = 0;
48*8d67ca89SAndroid Build Coastguard Worker };
49*8d67ca89SAndroid Build Coastguard Worker
unflatten_size(AlignedSizeFlat flat)50*8d67ca89SAndroid Build Coastguard Worker static TlsAlignedSize unflatten_size(AlignedSizeFlat flat) {
51*8d67ca89SAndroid Build Coastguard Worker return TlsAlignedSize{.size = flat.size,
52*8d67ca89SAndroid Build Coastguard Worker .align = TlsAlign{
53*8d67ca89SAndroid Build Coastguard Worker .value = flat.align,
54*8d67ca89SAndroid Build Coastguard Worker .skew = flat.skew,
55*8d67ca89SAndroid Build Coastguard Worker }};
56*8d67ca89SAndroid Build Coastguard Worker }
57*8d67ca89SAndroid Build Coastguard Worker
TEST(static_tls_layout,reserve_tp_pair)58*8d67ca89SAndroid Build Coastguard Worker TEST(static_tls_layout, reserve_tp_pair) {
59*8d67ca89SAndroid Build Coastguard Worker auto reserve_tp = [](const AlignedSizeFlat& before, const AlignedSizeFlat& after,
60*8d67ca89SAndroid Build Coastguard Worker StaticTlsLayout layout = {}) {
61*8d67ca89SAndroid Build Coastguard Worker auto allocs = layout.reserve_tp_pair(unflatten_size(before), unflatten_size(after));
62*8d67ca89SAndroid Build Coastguard Worker return std::make_tuple(layout, allocs);
63*8d67ca89SAndroid Build Coastguard Worker };
64*8d67ca89SAndroid Build Coastguard Worker
65*8d67ca89SAndroid Build Coastguard Worker StaticTlsLayout layout;
66*8d67ca89SAndroid Build Coastguard Worker StaticTlsLayout::TpAllocations allocs;
67*8d67ca89SAndroid Build Coastguard Worker
68*8d67ca89SAndroid Build Coastguard Worker // Simple case.
69*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 8, .align = 2}, {.size = 16, .align = 2});
70*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.before);
71*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8u, allocs.tp);
72*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8u, allocs.after);
73*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(24u, layout.size());
74*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(2u, layout.align_);
75*8d67ca89SAndroid Build Coastguard Worker
76*8d67ca89SAndroid Build Coastguard Worker // Zero-sized `before`
77*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 0}, {.size = 64, .align = 8});
78*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.before);
79*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.tp);
80*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.after);
81*8d67ca89SAndroid Build Coastguard Worker
82*8d67ca89SAndroid Build Coastguard Worker // Zero-sized `after`
83*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 64, .align = 8}, {.size = 0});
84*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.before);
85*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(64u, allocs.tp);
86*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(64u, allocs.after);
87*8d67ca89SAndroid Build Coastguard Worker
88*8d67ca89SAndroid Build Coastguard Worker // The `before` allocation is shifted forward to the TP.
89*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 1}, {.size = 64, .align = 8});
90*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(7u, allocs.before);
91*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8u, allocs.tp);
92*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8u, allocs.after);
93*8d67ca89SAndroid Build Coastguard Worker
94*8d67ca89SAndroid Build Coastguard Worker // Alignment gap between `before` and TP.
95*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 9, .align = 4}, {.size = 1});
96*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.before);
97*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(12u, allocs.tp);
98*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(12u, allocs.after);
99*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(13u, layout.size());
100*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(4u, layout.align_);
101*8d67ca89SAndroid Build Coastguard Worker
102*8d67ca89SAndroid Build Coastguard Worker // Alignment gap between `before` and TP.
103*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 9, .align = 4}, {.size = 128, .align = 64});
104*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(52u, allocs.before);
105*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(64u, allocs.tp);
106*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(64u, allocs.after);
107*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(192u, layout.size());
108*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(64u, layout.align_);
109*8d67ca89SAndroid Build Coastguard Worker
110*8d67ca89SAndroid Build Coastguard Worker // Skew-aligned `before` with low alignment.
111*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) =
112*8d67ca89SAndroid Build Coastguard Worker reserve_tp({.size = 1, .align = 4, .skew = 1}, {.size = 64, .align = 8});
113*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(5u, allocs.before);
114*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8u, allocs.tp);
115*8d67ca89SAndroid Build Coastguard Worker
116*8d67ca89SAndroid Build Coastguard Worker // Skew-aligned `before` with high alignment.
117*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 48, .align = 64, .skew = 17}, {.size = 1});
118*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(17u, allocs.before);
119*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(128u, allocs.tp);
120*8d67ca89SAndroid Build Coastguard Worker
121*8d67ca89SAndroid Build Coastguard Worker // An unrelated byte precedes the pair in the layout. Make sure `before` is
122*8d67ca89SAndroid Build Coastguard Worker // still aligned.
123*8d67ca89SAndroid Build Coastguard Worker layout = {};
124*8d67ca89SAndroid Build Coastguard Worker layout.reserve_type<char>();
125*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) = reserve_tp({.size = 12, .align = 16}, {.size = 1}, layout);
126*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(16u, allocs.before);
127*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(32u, allocs.tp);
128*8d67ca89SAndroid Build Coastguard Worker
129*8d67ca89SAndroid Build Coastguard Worker // Skew-aligned `after`.
130*8d67ca89SAndroid Build Coastguard Worker std::tie(layout, allocs) =
131*8d67ca89SAndroid Build Coastguard Worker reserve_tp({.size = 32, .align = 8}, {.size = 16, .align = 4, .skew = 3});
132*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(0u, allocs.before);
133*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(32u, allocs.tp);
134*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(35u, allocs.after);
135*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(51u, layout.size());
136*8d67ca89SAndroid Build Coastguard Worker }
137*8d67ca89SAndroid Build Coastguard Worker
138*8d67ca89SAndroid Build Coastguard Worker // A "NUM_words" literal is the size in bytes of NUM words of memory.
operator ""_words(unsigned long long i)139*8d67ca89SAndroid Build Coastguard Worker static size_t operator""_words(unsigned long long i) {
140*8d67ca89SAndroid Build Coastguard Worker return i * sizeof(void*);
141*8d67ca89SAndroid Build Coastguard Worker }
142*8d67ca89SAndroid Build Coastguard Worker
143*8d67ca89SAndroid Build Coastguard Worker using static_tls_layout_DeathTest = SilentDeathTest;
144*8d67ca89SAndroid Build Coastguard Worker
TEST_F(static_tls_layout_DeathTest,arm)145*8d67ca89SAndroid Build Coastguard Worker TEST_F(static_tls_layout_DeathTest, arm) {
146*8d67ca89SAndroid Build Coastguard Worker #if !defined(__arm__) && !defined(__aarch64__)
147*8d67ca89SAndroid Build Coastguard Worker GTEST_SKIP() << "test only applies to arm32/arm64 targets";
148*8d67ca89SAndroid Build Coastguard Worker #endif
149*8d67ca89SAndroid Build Coastguard Worker
150*8d67ca89SAndroid Build Coastguard Worker auto reserve_exe = [](const AlignedSizeFlat& config) {
151*8d67ca89SAndroid Build Coastguard Worker StaticTlsLayout layout;
152*8d67ca89SAndroid Build Coastguard Worker TlsSegment seg = {.aligned_size = unflatten_size(config)};
153*8d67ca89SAndroid Build Coastguard Worker layout.reserve_exe_segment_and_tcb(&seg, "prog");
154*8d67ca89SAndroid Build Coastguard Worker return layout;
155*8d67ca89SAndroid Build Coastguard Worker };
156*8d67ca89SAndroid Build Coastguard Worker
157*8d67ca89SAndroid Build Coastguard Worker auto underalign_error = [](size_t align, size_t offset) {
158*8d67ca89SAndroid Build Coastguard Worker return R"(error: "prog": executable's TLS segment is underaligned: )"s
159*8d67ca89SAndroid Build Coastguard Worker R"(alignment is )"s +
160*8d67ca89SAndroid Build Coastguard Worker std::to_string(align) + R"( \(skew )" + std::to_string(offset) +
161*8d67ca89SAndroid Build Coastguard Worker R"(\), needs to be at least (32 for ARM|64 for ARM64) Bionic)"s;
162*8d67ca89SAndroid Build Coastguard Worker };
163*8d67ca89SAndroid Build Coastguard Worker
164*8d67ca89SAndroid Build Coastguard Worker // Amount of memory needed for negative TLS slots, given a segment p_align of
165*8d67ca89SAndroid Build Coastguard Worker // 8 or 16 words.
166*8d67ca89SAndroid Build Coastguard Worker const size_t base8 = __BIONIC_ALIGN(-MIN_TLS_SLOT, 8) * sizeof(void*);
167*8d67ca89SAndroid Build Coastguard Worker const size_t base16 = __BIONIC_ALIGN(-MIN_TLS_SLOT, 16) * sizeof(void*);
168*8d67ca89SAndroid Build Coastguard Worker
169*8d67ca89SAndroid Build Coastguard Worker StaticTlsLayout layout;
170*8d67ca89SAndroid Build Coastguard Worker
171*8d67ca89SAndroid Build Coastguard Worker // An executable with a single word.
172*8d67ca89SAndroid Build Coastguard Worker layout = reserve_exe({.size = 1_words, .align = 8_words});
173*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8 + MIN_TLS_SLOT * sizeof(void*), layout.offset_bionic_tcb());
174*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8, layout.offset_thread_pointer());
175*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8 + 8_words, layout.offset_exe());
176*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8 + 9_words, layout.size());
177*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8_words, layout.align_);
178*8d67ca89SAndroid Build Coastguard Worker
179*8d67ca89SAndroid Build Coastguard Worker // Simple underalignment case.
180*8d67ca89SAndroid Build Coastguard Worker EXPECT_DEATH(reserve_exe({.size = 1_words, .align = 1_words}), underalign_error(1_words, 0));
181*8d67ca89SAndroid Build Coastguard Worker
182*8d67ca89SAndroid Build Coastguard Worker // Skewed by 1 word is OK.
183*8d67ca89SAndroid Build Coastguard Worker layout = reserve_exe({.size = 1_words, .align = 8_words, .skew = 1_words});
184*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8, layout.offset_thread_pointer());
185*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8 + 9_words, layout.offset_exe());
186*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base8 + 10_words, layout.size());
187*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(8_words, layout.align_);
188*8d67ca89SAndroid Build Coastguard Worker
189*8d67ca89SAndroid Build Coastguard Worker // Skewed by 2 words would overlap Bionic slots, regardless of the p_align
190*8d67ca89SAndroid Build Coastguard Worker // value.
191*8d67ca89SAndroid Build Coastguard Worker EXPECT_DEATH(reserve_exe({.size = 1_words, .align = 8_words, .skew = 2_words}),
192*8d67ca89SAndroid Build Coastguard Worker underalign_error(8_words, 2_words));
193*8d67ca89SAndroid Build Coastguard Worker EXPECT_DEATH(reserve_exe({.size = 1_words, .align = 0x1000, .skew = 2_words}),
194*8d67ca89SAndroid Build Coastguard Worker underalign_error(0x1000, 2_words));
195*8d67ca89SAndroid Build Coastguard Worker
196*8d67ca89SAndroid Build Coastguard Worker // Skewed by 8 words is OK again.
197*8d67ca89SAndroid Build Coastguard Worker layout = reserve_exe({.size = 1_words, .align = 16_words, .skew = 8_words});
198*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16, layout.offset_thread_pointer());
199*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16 + 8_words, layout.offset_exe());
200*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16 + 9_words, layout.size());
201*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(16_words, layout.align_);
202*8d67ca89SAndroid Build Coastguard Worker
203*8d67ca89SAndroid Build Coastguard Worker // Skewed by 9 words is also OK. (The amount of skew doesn't need to be a
204*8d67ca89SAndroid Build Coastguard Worker // multiple of anything.)
205*8d67ca89SAndroid Build Coastguard Worker layout = reserve_exe({.size = 1_words, .align = 16_words, .skew = 9_words});
206*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16, layout.offset_thread_pointer());
207*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16 + 9_words, layout.offset_exe());
208*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(base16 + 10_words, layout.size());
209*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(16_words, layout.align_);
210*8d67ca89SAndroid Build Coastguard Worker
211*8d67ca89SAndroid Build Coastguard Worker // Skew with large alignment.
212*8d67ca89SAndroid Build Coastguard Worker layout = reserve_exe({.size = 1_words, .align = 256_words, .skew = 8_words});
213*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(256_words, layout.offset_thread_pointer());
214*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(264_words, layout.offset_exe());
215*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(265_words, layout.size());
216*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(256_words, layout.align_);
217*8d67ca89SAndroid Build Coastguard Worker }
218