| ... | ... | @@ -82,6 +82,26 @@ pub fn build(b: *Build) void { |
| 82 | 82 | elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = glibc_target })); |
| 83 | 83 | elf_step.dependOn(testTlsDso(b, .{ .target = glibc_target })); |
| 84 | 84 | elf_step.dependOn(testTlsGd(b, .{ .target = glibc_target })); |
| 85 | elf_step.dependOn(testTlsGdNoPlt(b, .{ .target = glibc_target })); |
| 86 | elf_step.dependOn(testTlsGdToIe(b, .{ .target = glibc_target })); |
| 87 | elf_step.dependOn(testTlsIe(b, .{ .target = glibc_target })); |
| 88 | elf_step.dependOn(testTlsLargeAlignment(b, .{ .target = glibc_target })); |
| 89 | elf_step.dependOn(testTlsLargeTbss(b, .{ .target = glibc_target })); |
| 90 | elf_step.dependOn(testTlsLargeStaticImage(b, .{ .target = glibc_target })); |
| 91 | elf_step.dependOn(testTlsLd(b, .{ .target = glibc_target })); |
| 92 | elf_step.dependOn(testTlsLdDso(b, .{ .target = glibc_target })); |
| 93 | elf_step.dependOn(testTlsLdNoPlt(b, .{ .target = glibc_target })); |
| 94 | // https://github.com/ziglang/zig/issues/17430 |
| 95 | // elf_step.dependOn(testTlsNoPic(b, .{ .target = glibc_target })); |
| 96 | // TODO |
| 97 | // elf_step.dependOn(testTlsOffsetAlignment(b, .{ .target = glibc_target })); |
| 98 | elf_step.dependOn(testTlsPic(b, .{ .target = glibc_target })); |
| 99 | elf_step.dependOn(testTlsSmallAlignment(b, .{ .target = glibc_target })); |
| 100 | elf_step.dependOn(testWeakExports(b, .{ .target = glibc_target })); |
| 101 | elf_step.dependOn(testWeakUndefsDso(b, .{ .target = glibc_target })); |
| 102 | elf_step.dependOn(testZNow(b, .{ .target = glibc_target })); |
| 103 | elf_step.dependOn(testZStackSize(b, .{ .target = glibc_target })); |
| 104 | elf_step.dependOn(testZText(b, .{ .target = glibc_target })); |
| 85 | 105 | } |
| 86 | 106 | |
| 87 | 107 | fn testAbsSymbols(b: *Build, opts: Options) *Step { |
| ... | ... | @@ -1924,37 +1944,871 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 1924 | 1944 | return test_step; |
| 1925 | 1945 | } |
| 1926 | 1946 | |
| 1927 | | fn testTlsStatic(b: *Build, opts: Options) *Step { |
| 1928 | | const test_step = addTestStep(b, "tls-static", opts); |
| 1947 | fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { |
| 1948 | const test_step = addTestStep(b, "tls-gd-no-plt", opts); |
| 1929 | 1949 | |
| 1930 | | const exe = addExecutable(b, "test", opts); |
| 1931 | | addCSourceBytes(exe, |
| 1950 | const obj = addObject(b, "obj", opts); |
| 1951 | addCSourceBytes(obj, |
| 1932 | 1952 | \\#include <stdio.h> |
| 1933 | | \\_Thread_local int a = 10; |
| 1934 | | \\_Thread_local int b; |
| 1935 | | \\_Thread_local char c = 'a'; |
| 1936 | | \\int main(int argc, char* argv[]) { |
| 1937 | | \\ printf("%d %d %c\n", a, b, c); |
| 1938 | | \\ a += 1; |
| 1939 | | \\ b += 1; |
| 1940 | | \\ c += 1; |
| 1941 | | \\ printf("%d %d %c\n", a, b, c); |
| 1953 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1; |
| 1954 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x2; |
| 1955 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x3; |
| 1956 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x4; |
| 1957 | \\int get_x5(); |
| 1958 | \\int get_x6(); |
| 1959 | \\int main() { |
| 1960 | \\ x2 = 2; |
| 1961 | \\ |
| 1962 | \\ printf("%d %d %d %d %d %d\n", x1, x2, x3, x4, get_x5(), get_x6()); |
| 1963 | \\ return 0; |
| 1964 | \\} |
| 1965 | , &.{"-fno-plt"}); |
| 1966 | obj.force_pic = true; |
| 1967 | obj.linkLibC(); |
| 1968 | |
| 1969 | const a_so = addSharedLibrary(b, "a", opts); |
| 1970 | addCSourceBytes(a_so, |
| 1971 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x3 = 3; |
| 1972 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x5 = 5; |
| 1973 | \\int get_x5() { return x5; } |
| 1974 | , &.{"-fno-plt"}); |
| 1975 | |
| 1976 | const b_so = addSharedLibrary(b, "b", opts); |
| 1977 | addCSourceBytes(b_so, |
| 1978 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x4 = 4; |
| 1979 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x6 = 6; |
| 1980 | \\int get_x6() { return x6; } |
| 1981 | , &.{"-fno-plt"}); |
| 1982 | // b_so.link_relax = false; // TODO |
| 1983 | |
| 1984 | { |
| 1985 | const exe = addExecutable(b, "main1", opts); |
| 1986 | exe.addObject(obj); |
| 1987 | exe.linkLibrary(a_so); |
| 1988 | exe.linkLibrary(b_so); |
| 1989 | exe.linkLibC(); |
| 1990 | |
| 1991 | const run = addRunArtifact(exe); |
| 1992 | run.expectStdOutEqual("1 2 3 4 5 6\n"); |
| 1993 | test_step.dependOn(&run.step); |
| 1994 | } |
| 1995 | |
| 1996 | { |
| 1997 | const exe = addExecutable(b, "main2", opts); |
| 1998 | exe.addObject(obj); |
| 1999 | exe.linkLibrary(a_so); |
| 2000 | exe.linkLibrary(b_so); |
| 2001 | exe.linkLibC(); |
| 2002 | // exe.link_relax = false; // TODO |
| 2003 | |
| 2004 | const run = addRunArtifact(exe); |
| 2005 | run.expectStdOutEqual("1 2 3 4 5 6\n"); |
| 2006 | test_step.dependOn(&run.step); |
| 2007 | } |
| 2008 | |
| 2009 | return test_step; |
| 2010 | } |
| 2011 | |
| 2012 | fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 2013 | const test_step = addTestStep(b, "tls-gd-to-ie", opts); |
| 2014 | |
| 2015 | const a_o = addObject(b, "a", opts); |
| 2016 | addCSourceBytes(a_o, |
| 2017 | \\#include <stdio.h> |
| 2018 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1; |
| 2019 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x2 = 2; |
| 2020 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int x3; |
| 2021 | \\int foo() { |
| 2022 | \\ x3 = 3; |
| 2023 | \\ |
| 2024 | \\ printf("%d %d %d\n", x1, x2, x3); |
| 1942 | 2025 | \\ return 0; |
| 1943 | 2026 | \\} |
| 1944 | 2027 | , &.{}); |
| 2028 | a_o.linkLibC(); |
| 2029 | a_o.force_pic = true; |
| 2030 | |
| 2031 | const b_o = addObject(b, "b", opts); |
| 2032 | addCSourceBytes(b_o, |
| 2033 | \\int foo(); |
| 2034 | \\int main() { foo(); } |
| 2035 | , &.{}); |
| 2036 | b_o.force_pic = true; |
| 2037 | |
| 2038 | { |
| 2039 | const dso = addSharedLibrary(b, "a", opts); |
| 2040 | dso.addObject(a_o); |
| 2041 | |
| 2042 | const exe = addExecutable(b, "main", opts); |
| 2043 | exe.addObject(b_o); |
| 2044 | exe.linkLibrary(dso); |
| 2045 | exe.linkLibC(); |
| 2046 | |
| 2047 | const run = addRunArtifact(exe); |
| 2048 | run.expectStdOutEqual("1 2 3\n"); |
| 2049 | test_step.dependOn(&run.step); |
| 2050 | } |
| 2051 | |
| 2052 | { |
| 2053 | const dso = addSharedLibrary(b, "a", opts); |
| 2054 | dso.addObject(a_o); |
| 2055 | // dso.link_relax = false; // TODO |
| 2056 | |
| 2057 | const exe = addExecutable(b, "main", opts); |
| 2058 | exe.addObject(b_o); |
| 2059 | exe.linkLibrary(dso); |
| 2060 | exe.linkLibC(); |
| 2061 | |
| 2062 | const run = addRunArtifact(exe); |
| 2063 | run.expectStdOutEqual("1 2 3\n"); |
| 2064 | test_step.dependOn(&run.step); |
| 2065 | } |
| 2066 | |
| 2067 | // { |
| 2068 | // const dso = addSharedLibrary(b, "a", opts); |
| 2069 | // dso.addObject(a_o); |
| 2070 | // dso.link_z_nodlopen = true; |
| 2071 | |
| 2072 | // const exe = addExecutable(b, "main", opts); |
| 2073 | // exe.addObject(b_o); |
| 2074 | // exe.linkLibrary(dso); |
| 2075 | |
| 2076 | // const run = addRunArtifact(exe); |
| 2077 | // run.expectStdOutEqual("1 2 3\n"); |
| 2078 | // test_step.dependOn(&run.step); |
| 2079 | // } |
| 2080 | |
| 2081 | // { |
| 2082 | // const dso = addSharedLibrary(b, "a", opts); |
| 2083 | // dso.addObject(a_o); |
| 2084 | // dso.link_relax = false; |
| 2085 | // dso.link_z_nodlopen = true; |
| 2086 | |
| 2087 | // const exe = addExecutable(b, "main", opts); |
| 2088 | // exe.addObject(b_o); |
| 2089 | // exe.linkLibrary(dso); |
| 2090 | |
| 2091 | // const run = addRunArtifact(exe); |
| 2092 | // run.expectStdOutEqual("1 2 3\n"); |
| 2093 | // test_step.dependOn(&run.step); |
| 2094 | // } |
| 2095 | |
| 2096 | return test_step; |
| 2097 | } |
| 2098 | |
| 2099 | fn testTlsIe(b: *Build, opts: Options) *Step { |
| 2100 | const test_step = addTestStep(b, "tls-ie", opts); |
| 2101 | |
| 2102 | const dso = addSharedLibrary(b, "a", opts); |
| 2103 | addCSourceBytes(dso, |
| 2104 | \\#include <stdio.h> |
| 2105 | \\__attribute__((tls_model("initial-exec"))) static _Thread_local int foo; |
| 2106 | \\__attribute__((tls_model("initial-exec"))) static _Thread_local int bar; |
| 2107 | \\void set() { |
| 2108 | \\ foo = 3; |
| 2109 | \\ bar = 5; |
| 2110 | \\} |
| 2111 | \\void print() { |
| 2112 | \\ printf("%d %d ", foo, bar); |
| 2113 | \\} |
| 2114 | , &.{}); |
| 2115 | dso.linkLibC(); |
| 2116 | |
| 2117 | const main_o = addObject(b, "main", opts); |
| 2118 | addCSourceBytes(main_o, |
| 2119 | \\#include <stdio.h> |
| 2120 | \\_Thread_local int baz; |
| 2121 | \\void set(); |
| 2122 | \\void print(); |
| 2123 | \\int main() { |
| 2124 | \\ baz = 7; |
| 2125 | \\ print(); |
| 2126 | \\ set(); |
| 2127 | \\ print(); |
| 2128 | \\ printf("%d\n", baz); |
| 2129 | \\} |
| 2130 | , &.{}); |
| 2131 | main_o.linkLibC(); |
| 2132 | |
| 2133 | const exp_stdout = "0 0 3 5 7\n"; |
| 2134 | |
| 2135 | { |
| 2136 | const exe = addExecutable(b, "main", opts); |
| 2137 | exe.addObject(main_o); |
| 2138 | exe.linkLibrary(dso); |
| 2139 | exe.linkLibC(); |
| 2140 | |
| 2141 | const run = addRunArtifact(exe); |
| 2142 | run.expectStdOutEqual(exp_stdout); |
| 2143 | test_step.dependOn(&run.step); |
| 2144 | } |
| 2145 | |
| 2146 | { |
| 2147 | const exe = addExecutable(b, "main", opts); |
| 2148 | exe.addObject(main_o); |
| 2149 | exe.linkLibrary(dso); |
| 2150 | exe.linkLibC(); |
| 2151 | // exe.link_relax = false; // TODO |
| 2152 | |
| 2153 | const run = addRunArtifact(exe); |
| 2154 | run.expectStdOutEqual(exp_stdout); |
| 2155 | test_step.dependOn(&run.step); |
| 2156 | } |
| 2157 | |
| 2158 | return test_step; |
| 2159 | } |
| 2160 | |
| 2161 | fn testTlsLargeAlignment(b: *Build, opts: Options) *Step { |
| 2162 | const test_step = addTestStep(b, "tls-large-alignment", opts); |
| 2163 | |
| 2164 | const a_o = addObject(b, "a", opts); |
| 2165 | addCSourceBytes(a_o, |
| 2166 | \\__attribute__((section(".tdata1"))) |
| 2167 | \\_Thread_local int x = 42; |
| 2168 | , &.{"-std=c11"}); |
| 2169 | a_o.force_pic = true; |
| 2170 | |
| 2171 | const b_o = addObject(b, "b", opts); |
| 2172 | addCSourceBytes(b_o, |
| 2173 | \\__attribute__((section(".tdata2"))) |
| 2174 | \\_Alignas(256) _Thread_local int y[] = { 1, 2, 3 }; |
| 2175 | , &.{"-std=c11"}); |
| 2176 | b_o.force_pic = true; |
| 2177 | |
| 2178 | const c_o = addObject(b, "c", opts); |
| 2179 | addCSourceBytes(c_o, |
| 2180 | \\#include <stdio.h> |
| 2181 | \\extern _Thread_local int x; |
| 2182 | \\extern _Thread_local int y[]; |
| 2183 | \\int main() { |
| 2184 | \\ printf("%d %d %d %d\n", x, y[0], y[1], y[2]); |
| 2185 | \\} |
| 2186 | , &.{}); |
| 2187 | c_o.force_pic = true; |
| 2188 | c_o.linkLibC(); |
| 2189 | |
| 2190 | { |
| 2191 | const dso = addSharedLibrary(b, "a", opts); |
| 2192 | dso.addObject(a_o); |
| 2193 | dso.addObject(b_o); |
| 2194 | |
| 2195 | const exe = addExecutable(b, "main", opts); |
| 2196 | exe.addObject(c_o); |
| 2197 | exe.linkLibrary(dso); |
| 2198 | exe.linkLibC(); |
| 2199 | |
| 2200 | const run = addRunArtifact(exe); |
| 2201 | run.expectStdOutEqual("42 1 2 3\n"); |
| 2202 | test_step.dependOn(&run.step); |
| 2203 | } |
| 2204 | |
| 2205 | { |
| 2206 | const exe = addExecutable(b, "main", opts); |
| 2207 | exe.addObject(a_o); |
| 2208 | exe.addObject(b_o); |
| 2209 | exe.addObject(c_o); |
| 2210 | exe.linkLibC(); |
| 2211 | |
| 2212 | const run = addRunArtifact(exe); |
| 2213 | run.expectStdOutEqual("42 1 2 3\n"); |
| 2214 | test_step.dependOn(&run.step); |
| 2215 | } |
| 2216 | |
| 2217 | return test_step; |
| 2218 | } |
| 2219 | |
| 2220 | fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 2221 | const test_step = addTestStep(b, "tls-large-tbss", opts); |
| 2222 | |
| 2223 | const exe = addExecutable(b, "main", opts); |
| 2224 | addAsmSourceBytes(exe, |
| 2225 | \\.globl x, y |
| 2226 | \\.section .tbss,"awT",@nobits |
| 2227 | \\x: |
| 2228 | \\.zero 1024 |
| 2229 | \\.section .tcommon,"awT",@nobits |
| 2230 | \\y: |
| 2231 | \\.zero 1024 |
| 2232 | ); |
| 2233 | addCSourceBytes(exe, |
| 2234 | \\#include <stdio.h> |
| 2235 | \\extern _Thread_local char x[1024000]; |
| 2236 | \\extern _Thread_local char y[1024000]; |
| 2237 | \\int main() { |
| 2238 | \\ x[0] = 3; |
| 2239 | \\ x[1023] = 5; |
| 2240 | \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]); |
| 2241 | \\} |
| 2242 | , &.{}); |
| 1945 | 2243 | exe.linkLibC(); |
| 1946 | 2244 | |
| 1947 | 2245 | const run = addRunArtifact(exe); |
| 1948 | | run.expectStdOutEqual( |
| 1949 | | \\10 0 a |
| 1950 | | \\11 1 b |
| 1951 | | \\ |
| 1952 | | ); |
| 2246 | run.expectStdOutEqual("3 0 5 0 0 0\n"); |
| 2247 | test_step.dependOn(&run.step); |
| 2248 | |
| 2249 | return test_step; |
| 2250 | } |
| 2251 | |
| 2252 | fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step { |
| 2253 | const test_step = addTestStep(b, "tls-large-static-image", opts); |
| 2254 | |
| 2255 | const exe = addExecutable(b, "main", opts); |
| 2256 | addCSourceBytes(exe, "_Thread_local int x[] = { 1, 2, 3, [10000] = 5 };", &.{}); |
| 2257 | addCSourceBytes(exe, |
| 2258 | \\#include <stdio.h> |
| 2259 | \\extern _Thread_local int x[]; |
| 2260 | \\int main() { |
| 2261 | \\ printf("%d %d %d %d %d\n", x[0], x[1], x[2], x[3], x[10000]); |
| 2262 | \\} |
| 2263 | , &.{}); |
| 2264 | exe.force_pic = true; |
| 2265 | exe.linkLibC(); |
| 2266 | |
| 2267 | const run = addRunArtifact(exe); |
| 2268 | run.expectStdOutEqual("1 2 3 0 5\n"); |
| 1953 | 2269 | test_step.dependOn(&run.step); |
| 1954 | 2270 | |
| 1955 | 2271 | return test_step; |
| 1956 | 2272 | } |
| 1957 | 2273 | |
| 2274 | fn testTlsLd(b: *Build, opts: Options) *Step { |
| 2275 | const test_step = addTestStep(b, "tls-ld", opts); |
| 2276 | |
| 2277 | const main_o = addObject(b, "main", opts); |
| 2278 | addCSourceBytes(main_o, |
| 2279 | \\#include <stdio.h> |
| 2280 | \\extern _Thread_local int foo; |
| 2281 | \\static _Thread_local int bar; |
| 2282 | \\int *get_foo_addr() { return &foo; } |
| 2283 | \\int *get_bar_addr() { return &bar; } |
| 2284 | \\int main() { |
| 2285 | \\ bar = 5; |
| 2286 | \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar); |
| 2287 | \\ return 0; |
| 2288 | \\} |
| 2289 | , &.{"-ftls-model=local-dynamic"}); |
| 2290 | main_o.force_pic = true; |
| 2291 | main_o.linkLibC(); |
| 2292 | |
| 2293 | const a_o = addObject(b, "a", opts); |
| 2294 | addCSourceBytes(a_o, "_Thread_local int foo = 3;", &.{"-ftls-model=local-dynamic"}); |
| 2295 | a_o.force_pic = true; |
| 2296 | |
| 2297 | const exp_stdout = "3 5 3 5\n"; |
| 2298 | |
| 2299 | { |
| 2300 | const exe = addExecutable(b, "main", opts); |
| 2301 | exe.addObject(main_o); |
| 2302 | exe.addObject(a_o); |
| 2303 | exe.linkLibC(); |
| 2304 | |
| 2305 | const run = addRunArtifact(exe); |
| 2306 | run.expectStdOutEqual(exp_stdout); |
| 2307 | test_step.dependOn(&run.step); |
| 2308 | } |
| 2309 | |
| 2310 | { |
| 2311 | const exe = addExecutable(b, "main", opts); |
| 2312 | exe.addObject(main_o); |
| 2313 | exe.addObject(a_o); |
| 2314 | exe.linkLibC(); |
| 2315 | // exe.link_relax = false; // TODO |
| 2316 | |
| 2317 | const run = addRunArtifact(exe); |
| 2318 | run.expectStdOutEqual(exp_stdout); |
| 2319 | test_step.dependOn(&run.step); |
| 2320 | } |
| 2321 | |
| 2322 | return test_step; |
| 2323 | } |
| 2324 | |
| 2325 | fn testTlsLdDso(b: *Build, opts: Options) *Step { |
| 2326 | const test_step = addTestStep(b, "tls-ld-dso", opts); |
| 2327 | |
| 2328 | const dso = addSharedLibrary(b, "a", opts); |
| 2329 | addCSourceBytes(dso, |
| 2330 | \\static _Thread_local int def, def1; |
| 2331 | \\int f0() { return ++def; } |
| 2332 | \\int f1() { return ++def1 + def; } |
| 2333 | , &.{"-ftls-model=local-dynamic"}); |
| 2334 | |
| 2335 | const exe = addExecutable(b, "main", opts); |
| 2336 | addCSourceBytes(exe, |
| 2337 | \\#include <stdio.h> |
| 2338 | \\extern int f0(); |
| 2339 | \\extern int f1(); |
| 2340 | \\int main() { |
| 2341 | \\ int x = f0(); |
| 2342 | \\ int y = f1(); |
| 2343 | \\ printf("%d %d\n", x, y); |
| 2344 | \\ return 0; |
| 2345 | \\} |
| 2346 | , &.{}); |
| 2347 | exe.linkLibrary(dso); |
| 2348 | exe.linkLibC(); |
| 2349 | |
| 2350 | const run = addRunArtifact(exe); |
| 2351 | run.expectStdOutEqual("1 2\n"); |
| 2352 | test_step.dependOn(&run.step); |
| 2353 | |
| 2354 | return test_step; |
| 2355 | } |
| 2356 | |
| 2357 | fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { |
| 2358 | const test_step = addTestStep(b, "tls-ld-no-plt", opts); |
| 2359 | |
| 2360 | const a_o = addObject(b, "a", opts); |
| 2361 | addCSourceBytes(a_o, |
| 2362 | \\#include <stdio.h> |
| 2363 | \\extern _Thread_local int foo; |
| 2364 | \\static _Thread_local int bar; |
| 2365 | \\int *get_foo_addr() { return &foo; } |
| 2366 | \\int *get_bar_addr() { return &bar; } |
| 2367 | \\int main() { |
| 2368 | \\ bar = 5; |
| 2369 | \\ |
| 2370 | \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar); |
| 2371 | \\ return 0; |
| 2372 | \\} |
| 2373 | , &.{ "-ftls-model=local-dynamic", "-fno-plt" }); |
| 2374 | a_o.linkLibC(); |
| 2375 | a_o.force_pic = true; |
| 2376 | |
| 2377 | const b_o = addObject(b, "b", opts); |
| 2378 | addCSourceBytes(b_o, "_Thread_local int foo = 3;", &.{ "-ftls-model=local-dynamic", "-fno-plt" }); |
| 2379 | b_o.force_pic = true; |
| 2380 | |
| 2381 | { |
| 2382 | const exe = addExecutable(b, "main", opts); |
| 2383 | exe.addObject(a_o); |
| 2384 | exe.addObject(b_o); |
| 2385 | exe.linkLibC(); |
| 2386 | |
| 2387 | const run = addRunArtifact(exe); |
| 2388 | run.expectStdOutEqual("3 5 3 5\n"); |
| 2389 | test_step.dependOn(&run.step); |
| 2390 | } |
| 2391 | |
| 2392 | { |
| 2393 | const exe = addExecutable(b, "main", opts); |
| 2394 | exe.addObject(a_o); |
| 2395 | exe.addObject(b_o); |
| 2396 | exe.linkLibC(); |
| 2397 | // exe.link_relax = false; // TODO |
| 2398 | |
| 2399 | const run = addRunArtifact(exe); |
| 2400 | run.expectStdOutEqual("3 5 3 5\n"); |
| 2401 | test_step.dependOn(&run.step); |
| 2402 | } |
| 2403 | |
| 2404 | return test_step; |
| 2405 | } |
| 2406 | |
| 2407 | fn testTlsNoPic(b: *Build, opts: Options) *Step { |
| 2408 | const test_step = addTestStep(b, "tls-no-pic", opts); |
| 2409 | |
| 2410 | const exe = addExecutable(b, "main", opts); |
| 2411 | addCSourceBytes(exe, |
| 2412 | \\#include <stdio.h> |
| 2413 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int foo; |
| 2414 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int bar; |
| 2415 | \\int *get_foo_addr() { return &foo; } |
| 2416 | \\int *get_bar_addr() { return &bar; } |
| 2417 | \\int main() { |
| 2418 | \\ foo = 3; |
| 2419 | \\ bar = 5; |
| 2420 | \\ |
| 2421 | \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar); |
| 2422 | \\ return 0; |
| 2423 | \\} |
| 2424 | , .{}); |
| 2425 | addCSourceBytes(exe, |
| 2426 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo; |
| 2427 | , &.{}); |
| 2428 | exe.force_pic = false; |
| 2429 | exe.linkLibC(); |
| 2430 | |
| 2431 | const run = addRunArtifact(exe); |
| 2432 | run.expectStdOutEqual("3 5 3 5\n"); |
| 2433 | test_step.dependOn(&run.step); |
| 2434 | |
| 2435 | return test_step; |
| 2436 | } |
| 2437 | |
| 2438 | fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step { |
| 2439 | const test_step = addTestStep(b, "tls-offset-alignment", opts); |
| 2440 | |
| 2441 | const dso = addSharedLibrary(b, "a", opts); |
| 2442 | addCSourceBytes(dso, |
| 2443 | \\#include <assert.h> |
| 2444 | \\#include <stdlib.h> |
| 2445 | \\ |
| 2446 | \\// .tdata |
| 2447 | \\_Thread_local int x = 42; |
| 2448 | \\// .tbss |
| 2449 | \\__attribute__ ((aligned(64))) |
| 2450 | \\_Thread_local int y = 0; |
| 2451 | \\ |
| 2452 | \\void *verify(void *unused) { |
| 2453 | \\ assert((unsigned long)(&y) % 64 == 0); |
| 2454 | \\ return NULL; |
| 2455 | \\} |
| 2456 | , &.{}); |
| 2457 | dso.linkLibC(); |
| 2458 | |
| 2459 | const exe = addExecutable(b, "main", opts); |
| 2460 | addCSourceBytes(exe, |
| 2461 | \\#include <pthread.h> |
| 2462 | \\#include <dlfcn.h> |
| 2463 | \\#include <assert.h> |
| 2464 | \\void *(*verify)(void *); |
| 2465 | \\ |
| 2466 | \\int main() { |
| 2467 | \\ void *handle = dlopen("a.so", RTLD_NOW); |
| 2468 | \\ assert(handle); |
| 2469 | \\ *(void**)(&verify) = dlsym(handle, "verify"); |
| 2470 | \\ assert(verify); |
| 2471 | \\ |
| 2472 | \\ pthread_t thread; |
| 2473 | \\ |
| 2474 | \\ verify(NULL); |
| 2475 | \\ |
| 2476 | \\ pthread_create(&thread, NULL, verify, NULL); |
| 2477 | \\ pthread_join(thread, NULL); |
| 2478 | \\} |
| 2479 | , &.{}); |
| 2480 | exe.linkLibrary(dso); |
| 2481 | exe.linkLibC(); |
| 2482 | exe.linkSystemLibrary2("dl", .{}); |
| 2483 | exe.linkSystemLibrary2("pthread", .{}); |
| 2484 | exe.force_pic = true; |
| 2485 | |
| 2486 | const run = addRunArtifact(exe); |
| 2487 | run.expectExitCode(0); |
| 2488 | test_step.dependOn(&run.step); |
| 2489 | |
| 2490 | return test_step; |
| 2491 | } |
| 2492 | |
| 2493 | fn testTlsPic(b: *Build, opts: Options) *Step { |
| 2494 | const test_step = addTestStep(b, "tls-pic", opts); |
| 2495 | |
| 2496 | const obj = addObject(b, "obj", opts); |
| 2497 | addCSourceBytes(obj, |
| 2498 | \\#include <stdio.h> |
| 2499 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int foo; |
| 2500 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int bar; |
| 2501 | \\int *get_foo_addr() { return &foo; } |
| 2502 | \\int *get_bar_addr() { return &bar; } |
| 2503 | \\int main() { |
| 2504 | \\ bar = 5; |
| 2505 | \\ |
| 2506 | \\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar); |
| 2507 | \\ return 0; |
| 2508 | \\} |
| 2509 | , &.{}); |
| 2510 | obj.linkLibC(); |
| 2511 | obj.force_pic = true; |
| 2512 | |
| 2513 | const exe = addExecutable(b, "main", opts); |
| 2514 | addCSourceBytes(exe, |
| 2515 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3; |
| 2516 | , &.{}); |
| 2517 | exe.addObject(obj); |
| 2518 | exe.linkLibC(); |
| 2519 | |
| 2520 | const run = addRunArtifact(exe); |
| 2521 | run.expectStdOutEqual("3 5 3 5\n"); |
| 2522 | test_step.dependOn(&run.step); |
| 2523 | |
| 2524 | return test_step; |
| 2525 | } |
| 2526 | |
| 2527 | fn testTlsSmallAlignment(b: *Build, opts: Options) *Step { |
| 2528 | const test_step = addTestStep(b, "tls-small-alignment", opts); |
| 2529 | |
| 2530 | const a_o = addObject(b, "a", opts); |
| 2531 | addAsmSourceBytes(a_o, |
| 2532 | \\.text |
| 2533 | \\.byte 0 |
| 2534 | ); |
| 2535 | a_o.force_pic = true; |
| 2536 | |
| 2537 | const b_o = addObject(b, "b", opts); |
| 2538 | addCSourceBytes(b_o, "_Thread_local char x = 42;", &.{"-std=c11"}); |
| 2539 | b_o.force_pic = true; |
| 2540 | |
| 2541 | const c_o = addObject(b, "c", opts); |
| 2542 | addCSourceBytes(c_o, |
| 2543 | \\#include <stdio.h> |
| 2544 | \\extern _Thread_local char x; |
| 2545 | \\int main() { |
| 2546 | \\ printf("%d\n", x); |
| 2547 | \\} |
| 2548 | , &.{}); |
| 2549 | c_o.linkLibC(); |
| 2550 | c_o.force_pic = true; |
| 2551 | |
| 2552 | { |
| 2553 | const exe = addExecutable(b, "main", opts); |
| 2554 | exe.addObject(a_o); |
| 2555 | exe.addObject(b_o); |
| 2556 | exe.addObject(c_o); |
| 2557 | exe.linkLibC(); |
| 2558 | |
| 2559 | const run = addRunArtifact(exe); |
| 2560 | run.expectStdOutEqual("42\n"); |
| 2561 | test_step.dependOn(&run.step); |
| 2562 | } |
| 2563 | |
| 2564 | { |
| 2565 | const dso = addSharedLibrary(b, "a", opts); |
| 2566 | dso.addObject(a_o); |
| 2567 | dso.addObject(b_o); |
| 2568 | |
| 2569 | const exe = addExecutable(b, "main", opts); |
| 2570 | exe.addObject(c_o); |
| 2571 | exe.linkLibrary(dso); |
| 2572 | exe.linkLibC(); |
| 2573 | |
| 2574 | const run = addRunArtifact(exe); |
| 2575 | run.expectStdOutEqual("42\n"); |
| 2576 | test_step.dependOn(&run.step); |
| 2577 | } |
| 2578 | |
| 2579 | return test_step; |
| 2580 | } |
| 2581 | |
| 2582 | fn testTlsStatic(b: *Build, opts: Options) *Step { |
| 2583 | const test_step = addTestStep(b, "tls-static", opts); |
| 2584 | |
| 2585 | const exe = addExecutable(b, "test", opts); |
| 2586 | addCSourceBytes(exe, |
| 2587 | \\#include <stdio.h> |
| 2588 | \\_Thread_local int a = 10; |
| 2589 | \\_Thread_local int b; |
| 2590 | \\_Thread_local char c = 'a'; |
| 2591 | \\int main(int argc, char* argv[]) { |
| 2592 | \\ printf("%d %d %c\n", a, b, c); |
| 2593 | \\ a += 1; |
| 2594 | \\ b += 1; |
| 2595 | \\ c += 1; |
| 2596 | \\ printf("%d %d %c\n", a, b, c); |
| 2597 | \\ return 0; |
| 2598 | \\} |
| 2599 | , &.{}); |
| 2600 | exe.linkLibC(); |
| 2601 | |
| 2602 | const run = addRunArtifact(exe); |
| 2603 | run.expectStdOutEqual( |
| 2604 | \\10 0 a |
| 2605 | \\11 1 b |
| 2606 | \\ |
| 2607 | ); |
| 2608 | test_step.dependOn(&run.step); |
| 2609 | |
| 2610 | return test_step; |
| 2611 | } |
| 2612 | |
| 2613 | fn testWeakExports(b: *Build, opts: Options) *Step { |
| 2614 | const test_step = addTestStep(b, "weak-exports", opts); |
| 2615 | |
| 2616 | const obj = addObject(b, "obj", opts); |
| 2617 | addCSourceBytes(obj, |
| 2618 | \\#include <stdio.h> |
| 2619 | \\__attribute__((weak)) int foo(); |
| 2620 | \\int main() { |
| 2621 | \\ printf("%d\n", foo ? foo() : 3); |
| 2622 | \\} |
| 2623 | , &.{}); |
| 2624 | obj.linkLibC(); |
| 2625 | obj.force_pic = true; |
| 2626 | |
| 2627 | { |
| 2628 | const dso = addSharedLibrary(b, "a", opts); |
| 2629 | dso.addObject(obj); |
| 2630 | dso.linkLibC(); |
| 2631 | |
| 2632 | const check = dso.checkObject(); |
| 2633 | check.checkInDynamicSymtab(); |
| 2634 | check.checkContains("UND NOTYPE WEAK DEFAULT foo"); |
| 2635 | test_step.dependOn(&check.step); |
| 2636 | } |
| 2637 | |
| 2638 | { |
| 2639 | const exe = addExecutable(b, "main", opts); |
| 2640 | exe.addObject(obj); |
| 2641 | exe.linkLibC(); |
| 2642 | |
| 2643 | const check = exe.checkObject(); |
| 2644 | check.checkInDynamicSymtab(); |
| 2645 | check.checkNotPresent("UND NOTYPE WEAK DEFAULT foo"); |
| 2646 | test_step.dependOn(&check.step); |
| 2647 | |
| 2648 | const run = addRunArtifact(exe); |
| 2649 | run.expectStdOutEqual("3\n"); |
| 2650 | test_step.dependOn(&run.step); |
| 2651 | } |
| 2652 | |
| 2653 | return test_step; |
| 2654 | } |
| 2655 | |
| 2656 | fn testWeakUndefsDso(b: *Build, opts: Options) *Step { |
| 2657 | const test_step = addTestStep(b, "weak-undef-dso", opts); |
| 2658 | |
| 2659 | const dso = addSharedLibrary(b, "a", opts); |
| 2660 | addCSourceBytes(dso, |
| 2661 | \\__attribute__((weak)) int foo(); |
| 2662 | \\int bar() { return foo ? foo() : -1; } |
| 2663 | , &.{}); |
| 2664 | |
| 2665 | { |
| 2666 | const exe = addExecutable(b, "main", opts); |
| 2667 | addCSourceBytes(exe, |
| 2668 | \\#include <stdio.h> |
| 2669 | \\int bar(); |
| 2670 | \\int main() { printf("bar=%d\n", bar()); } |
| 2671 | , &.{}); |
| 2672 | exe.linkLibrary(dso); |
| 2673 | exe.linkLibC(); |
| 2674 | |
| 2675 | const run = addRunArtifact(exe); |
| 2676 | run.expectStdOutEqual("bar=-1\n"); |
| 2677 | test_step.dependOn(&run.step); |
| 2678 | } |
| 2679 | |
| 2680 | { |
| 2681 | const exe = addExecutable(b, "main", opts); |
| 2682 | addCSourceBytes(exe, |
| 2683 | \\#include <stdio.h> |
| 2684 | \\int foo() { return 5; } |
| 2685 | \\int bar(); |
| 2686 | \\int main() { printf("bar=%d\n", bar()); } |
| 2687 | , &.{}); |
| 2688 | exe.linkLibrary(dso); |
| 2689 | exe.linkLibC(); |
| 2690 | |
| 2691 | const run = addRunArtifact(exe); |
| 2692 | run.expectStdOutEqual("bar=5\n"); |
| 2693 | test_step.dependOn(&run.step); |
| 2694 | } |
| 2695 | |
| 2696 | return test_step; |
| 2697 | } |
| 2698 | |
| 2699 | fn testZNow(b: *Build, opts: Options) *Step { |
| 2700 | const test_step = addTestStep(b, "z-now", opts); |
| 2701 | |
| 2702 | const obj = addObject(b, "obj", opts); |
| 2703 | addCSourceBytes(obj, "int main() { return 0; }", &.{}); |
| 2704 | obj.force_pic = true; |
| 2705 | |
| 2706 | { |
| 2707 | const dso = addSharedLibrary(b, "a", opts); |
| 2708 | dso.addObject(obj); |
| 2709 | |
| 2710 | const check = dso.checkObject(); |
| 2711 | check.checkInDynamicSection(); |
| 2712 | check.checkContains("NOW"); |
| 2713 | test_step.dependOn(&check.step); |
| 2714 | } |
| 2715 | |
| 2716 | { |
| 2717 | const dso = addSharedLibrary(b, "a", opts); |
| 2718 | dso.addObject(obj); |
| 2719 | dso.link_z_lazy = true; |
| 2720 | |
| 2721 | const check = dso.checkObject(); |
| 2722 | check.checkInDynamicSection(); |
| 2723 | check.checkNotPresent("NOW"); |
| 2724 | test_step.dependOn(&check.step); |
| 2725 | } |
| 2726 | |
| 2727 | return test_step; |
| 2728 | } |
| 2729 | |
| 2730 | fn testZStackSize(b: *Build, opts: Options) *Step { |
| 2731 | const test_step = addTestStep(b, "z-stack-size", opts); |
| 2732 | |
| 2733 | const exe = addExecutable(b, "main", opts); |
| 2734 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 2735 | exe.stack_size = 0x800000; |
| 2736 | exe.linkLibC(); |
| 2737 | |
| 2738 | const check = exe.checkObject(); |
| 2739 | check.checkStart(); |
| 2740 | check.checkExact("program headers"); |
| 2741 | check.checkExact("type GNU_STACK"); |
| 2742 | check.checkExact("memsz 800000"); |
| 2743 | test_step.dependOn(&check.step); |
| 2744 | |
| 2745 | return test_step; |
| 2746 | } |
| 2747 | |
| 2748 | fn testZText(b: *Build, opts: Options) *Step { |
| 2749 | const test_step = addTestStep(b, "z-text", opts); |
| 2750 | |
| 2751 | // Previously, following mold, this test tested text relocs present in a PIE executable. |
| 2752 | // However, as we want to cover musl AND glibc, it is now modified to test presence of |
| 2753 | // text relocs in a DSO which is then linked with an executable. |
| 2754 | // According to Rich and this thread https://www.openwall.com/lists/musl/2020/09/25/4 |
| 2755 | // musl supports only a very limited number of text relocations and only in DSOs (and |
| 2756 | // rightly so!). |
| 2757 | |
| 2758 | const a_o = addObject(b, "a", opts); |
| 2759 | addAsmSourceBytes(a_o, |
| 2760 | \\.globl fn1 |
| 2761 | \\fn1: |
| 2762 | \\ sub $8, %rsp |
| 2763 | \\ movabs ptr, %rax |
| 2764 | \\ call *%rax |
| 2765 | \\ add $8, %rsp |
| 2766 | \\ ret |
| 2767 | ); |
| 2768 | |
| 2769 | const b_o = addObject(b, "b", opts); |
| 2770 | addCSourceBytes(b_o, |
| 2771 | \\int fn1(); |
| 2772 | \\int fn2() { |
| 2773 | \\ return 3; |
| 2774 | \\} |
| 2775 | \\void *ptr = fn2; |
| 2776 | \\int fnn() { |
| 2777 | \\ return fn1(); |
| 2778 | \\} |
| 2779 | , &.{}); |
| 2780 | b_o.force_pic = true; |
| 2781 | |
| 2782 | const dso = addSharedLibrary(b, "a", opts); |
| 2783 | dso.addObject(a_o); |
| 2784 | dso.addObject(b_o); |
| 2785 | dso.link_z_notext = true; |
| 2786 | |
| 2787 | const exe = addExecutable(b, "main", opts); |
| 2788 | addCSourceBytes(exe, |
| 2789 | \\#include <stdio.h> |
| 2790 | \\int fnn(); |
| 2791 | \\int main() { |
| 2792 | \\ printf("%d\n", fnn()); |
| 2793 | \\} |
| 2794 | , &.{}); |
| 2795 | exe.linkLibrary(dso); |
| 2796 | exe.linkLibC(); |
| 2797 | |
| 2798 | const run = addRunArtifact(exe); |
| 2799 | run.expectStdOutEqual("3\n"); |
| 2800 | test_step.dependOn(&run.step); |
| 2801 | |
| 2802 | // Check for DT_TEXTREL in a DSO |
| 2803 | const check = dso.checkObject(); |
| 2804 | check.checkInDynamicSection(); |
| 2805 | // check.checkExact("TEXTREL 0"); // TODO fix in CheckObject parser |
| 2806 | check.checkContains("FLAGS TEXTREL"); |
| 2807 | test_step.dependOn(&check.step); |
| 2808 | |
| 2809 | return test_step; |
| 2810 | } |
| 2811 | |
| 1958 | 2812 | const Options = struct { |
| 1959 | 2813 | target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux }, |
| 1960 | 2814 | optimize: std.builtin.OptimizeMode = .Debug, |