| ... | @@ -82,6 +82,26 @@ pub fn build(b: *Build) void { | ... | @@ -82,6 +82,26 @@ pub fn build(b: *Build) void { |
| 82 | elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = glibc_target })); | 82 | elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = glibc_target })); |
| 83 | elf_step.dependOn(testTlsDso(b, .{ .target = glibc_target })); | 83 | elf_step.dependOn(testTlsDso(b, .{ .target = glibc_target })); |
| 84 | elf_step.dependOn(testTlsGd(b, .{ .target = glibc_target })); | 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 | fn testAbsSymbols(b: *Build, opts: Options) *Step { | 107 | fn testAbsSymbols(b: *Build, opts: Options) *Step { |
| ... | @@ -1924,37 +1944,871 @@ fn testTlsGd(b: *Build, opts: Options) *Step { | ... | @@ -1924,37 +1944,871 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 1924 | return test_step; | 1944 | return test_step; |
| 1925 | } | 1945 | } |
| 1926 | | 1946 | |
| 1927 | fn testTlsStatic(b: *Build, opts: Options) *Step { | 1947 | fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { |
| 1928 | const test_step = addTestStep(b, "tls-static", opts); | 1948 | const test_step = addTestStep(b, "tls-gd-no-plt", opts); |
| 1929 | | 1949 | |
| 1930 | const exe = addExecutable(b, "test", opts); | 1950 | const obj = addObject(b, "obj", opts); |
| 1931 | addCSourceBytes(exe, | 1951 | addCSourceBytes(obj, |
| 1932 | \\#include <stdio.h> | 1952 | \\#include <stdio.h> |
| 1933 | \\_Thread_local int a = 10; | 1953 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x1 = 1; |
| 1934 | \\_Thread_local int b; | 1954 | \\__attribute__((tls_model("global-dynamic"))) static _Thread_local int x2; |
| 1935 | \\_Thread_local char c = 'a'; | 1955 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x3; |
| 1936 | \\int main(int argc, char* argv[]) { | 1956 | \\__attribute__((tls_model("global-dynamic"))) extern _Thread_local int x4; |
| 1937 | \\ printf("%d %d %c\n", a, b, c); | 1957 | \\int get_x5(); |
| 1938 | \\ a += 1; | 1958 | \\int get_x6(); |
| 1939 | \\ b += 1; | 1959 | \\int main() { |
| 1940 | \\ c += 1; | 1960 | \\ x2 = 2; |
| 1941 | \\ printf("%d %d %c\n", a, b, c); | 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 | \\ return 0; | 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 | exe.linkLibC(); | 2243 | exe.linkLibC(); |
| 1946 | | 2244 | |
| 1947 | const run = addRunArtifact(exe); | 2245 | const run = addRunArtifact(exe); |
| 1948 | run.expectStdOutEqual( | 2246 | run.expectStdOutEqual("3 0 5 0 0 0\n"); |
| 1949 | \\10 0 a | 2247 | test_step.dependOn(&run.step); |
| 1950 | \\11 1 b | 2248 | |
| 1951 | \\ | 2249 | return test_step; |
| 1952 | ); | 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 | test_step.dependOn(&run.step); | 2269 | test_step.dependOn(&run.step); |
| 1954 | | 2270 | |
| 1955 | return test_step; | 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 | const Options = struct { | 2812 | const Options = struct { |
| 1959 | target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux }, | 2813 | target: CrossTarget = .{ .cpu_arch = .x86_64, .os_tag = .linux }, |
| 1960 | optimize: std.builtin.OptimizeMode = .Debug, | 2814 | optimize: std.builtin.OptimizeMode = .Debug, |