| 1 | pub fn addCases(ctx: *LinkContext) void { |
| 2 | if (ctx.target.result.isMinGW()) |
| 3 | @import("link/mingw.zig").addCases(ctx); |
| 4 | |
| 5 | if (ctx.includeTest("static-lib")) |case| { |
| 6 | const obj1 = case.addObject(.{ |
| 7 | .name = "obj1", |
| 8 | .name_prefix = false, |
| 9 | .name_target = false, |
| 10 | .use_llvm = true, |
| 11 | .use_lld = true, |
| 12 | .c_source_bytes = |
| 13 | \\int foo1 = 1; |
| 14 | \\int foo2 = 2; |
| 15 | \\unsigned int fooBar() { |
| 16 | \\ return foo1 + foo2; |
| 17 | \\} |
| 18 | , |
| 19 | }); |
| 20 | const obj2 = case.addObject(.{ |
| 21 | .name = "this_is_a_long_name", |
| 22 | .name_prefix = false, |
| 23 | .name_target = false, |
| 24 | .zig_source_bytes = |
| 25 | \\fn fooWeak() callconv(.c) usize { |
| 26 | \\ return 0xaabbccddaabbccdd; |
| 27 | \\} |
| 28 | \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; |
| 29 | \\export var foo_strong: usize = 0x1122334411223344; |
| 30 | \\comptime { |
| 31 | \\ @export(&fooWeak, .{ .name = "fooWeak", .linkage = .weak }); |
| 32 | \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong }); |
| 33 | \\} |
| 34 | , |
| 35 | }); |
| 36 | |
| 37 | const lib = case.addLibrary(.static, .{ |
| 38 | .name = "lib", |
| 39 | .name_prefix = false, |
| 40 | .name_target = false, |
| 41 | }); |
| 42 | lib.root_module.addObject(obj1); |
| 43 | lib.root_module.addObject(obj2); |
| 44 | |
| 45 | case.verifyObjdump(lib.getEmittedBin(), &.{ |
| 46 | "-s", |
| 47 | "--elements=file-type", |
| 48 | "--symbols", |
| 49 | "--only-symbol=foo", |
| 50 | }, .{ .use_llvm = true }); |
| 51 | |
| 52 | const exe = case.addExecutable(.{ |
| 53 | .name = "test", |
| 54 | .zig_source_bytes = |
| 55 | \\extern fn fooBar() c_uint; |
| 56 | \\extern fn fooWeak() usize; |
| 57 | \\extern var foo_array: [2]u16; |
| 58 | \\extern var foo_strong: usize; |
| 59 | \\extern var foo_strong_alias: usize; |
| 60 | \\pub fn main() !u8 { |
| 61 | \\ return @intFromBool(0xcd003365cd00df35 != fooBar() + |
| 62 | \\ fooWeak() + |
| 63 | \\ foo_array[1] + |
| 64 | \\ foo_strong + |
| 65 | \\ foo_strong_alias); |
| 66 | \\} |
| 67 | , |
| 68 | }); |
| 69 | exe.root_module.linkLibrary(lib); |
| 70 | |
| 71 | const run = case.addRunArtifact(exe); |
| 72 | run.addCheck(.{ .expect_term = .{ .exited = 0 } }); |
| 73 | } |
| 74 | |
| 75 | if (ctx.includeTest("tls")) |case| { |
| 76 | const obj = case.addObject(.{ |
| 77 | .name = "obj", |
| 78 | .zig_source_bytes = |
| 79 | \\threadlocal var threadlocal_var: u32 = 1234; |
| 80 | \\threadlocal var threadlocal_arr: [4]u16 = .{ 0x1111, 0x2222, 0x3333, 0x4444, }; |
| 81 | \\export fn threadlocal_read(a: *u32, b: *u16) void { |
| 82 | \\ a.* = threadlocal_var; |
| 83 | \\ b.* = threadlocal_arr[3]; |
| 84 | \\} |
| 85 | \\export fn threadlocal_write(a: u32, b: u16) void { |
| 86 | \\ threadlocal_var = a; |
| 87 | \\ threadlocal_arr[3] = b; |
| 88 | \\} |
| 89 | , |
| 90 | }); |
| 91 | |
| 92 | case.verifyObjdump(obj.getEmittedBin(), &.{ |
| 93 | "-s", |
| 94 | "--symbols", |
| 95 | "--only-symbol=threadlocal", |
| 96 | "--only-symbol=tls", |
| 97 | }, .{ .use_llvm = true }); |
| 98 | |
| 99 | const exe = case.addExecutable(.{ |
| 100 | .name = "test", |
| 101 | .zig_source_bytes = |
| 102 | \\extern fn threadlocal_read(a: *u32, b: *u16) void; |
| 103 | \\extern fn threadlocal_write(a: u32, b: u16) void; |
| 104 | \\threadlocal var threadlocal_foo: u64 = 0xcafecafecafecafe; |
| 105 | \\pub fn main() !u8 { |
| 106 | \\ var a: u32 = undefined; |
| 107 | \\ var b: u16 = undefined; |
| 108 | \\ threadlocal_read(&a, &b); |
| 109 | \\ if (a != 1234 or b != 0x4444) return 1; |
| 110 | \\ if (threadlocal_foo != 0xcafecafecafecafe) return 2; |
| 111 | \\ threadlocal_write(0xabcdabcd, 0x5555); |
| 112 | \\ threadlocal_foo = 1; |
| 113 | \\ threadlocal_read(&a, &b); |
| 114 | \\ if (a != 0xabcdabcd or b != 0x5555) return 3; |
| 115 | \\ if (threadlocal_foo != 1) return 4; |
| 116 | \\ return 0; |
| 117 | \\} |
| 118 | , |
| 119 | }); |
| 120 | exe.root_module.addObject(obj); |
| 121 | |
| 122 | const run = case.addRunArtifact(exe); |
| 123 | run.addCheck(.{ .expect_term = .{ .exited = 0 } }); |
| 124 | } |
| 125 | |
| 126 | if (ctx.includeTest("dynamic-lib-code")) |case| { |
| 127 | const lib = case.addLibrary(.dynamic, .{ |
| 128 | .name = "lib", |
| 129 | .name_target = false, |
| 130 | .zig_source_bytes = |
| 131 | \\export fn foo1() callconv(.c) u64 { |
| 132 | \\ return 0x1122334411223344; |
| 133 | \\} |
| 134 | \\export fn foo2() callconv(.c) u64 { |
| 135 | \\ return 0xaabbccddaabbccdd; |
| 136 | \\} |
| 137 | , |
| 138 | }); |
| 139 | |
| 140 | case.verifyObjdump(lib.getEmittedBin(), &.{ |
| 141 | "-s", |
| 142 | "--exports", |
| 143 | "--only-symbol=foo", |
| 144 | }, .{ .os = true }); |
| 145 | |
| 146 | if (ctx.target.result.os.tag == .windows) { |
| 147 | case.verifyObjdump(lib.getEmittedImplib(), &.{ |
| 148 | "-s", |
| 149 | "--exports=sort", |
| 150 | "--only-symbol=foo", |
| 151 | }, .{ .sub_name = "implib", .os = true, .arch = true }); |
| 152 | } |
| 153 | |
| 154 | const exe = case.addExecutable(.{ |
| 155 | .name = "test", |
| 156 | .zig_source_bytes = |
| 157 | \\extern fn foo1() u64; |
| 158 | \\pub fn main() !u8 { |
| 159 | \\ const foo2 = @extern( |
| 160 | \\ *const fn () callconv(.c) u64, |
| 161 | \\ .{ .name = "foo2", .is_dll_import = true }, |
| 162 | \\ ); |
| 163 | \\ return @intFromBool(0xbbde0021bbde0021 != foo1() + foo2()); |
| 164 | \\} |
| 165 | , |
| 166 | }); |
| 167 | exe.root_module.linkLibrary(lib); |
| 168 | |
| 169 | const run = case.addRunArtifact(exe); |
| 170 | run.addCheck(.{ .expect_term = .{ .exited = 0 } }); |
| 171 | } |
| 172 | |
| 173 | if (ctx.includeTest("dynamic-lib-data")) |case| { |
| 174 | const lib = case.addLibrary(.dynamic, .{ |
| 175 | .name = "lib", |
| 176 | .name_target = false, |
| 177 | .zig_source_bytes = |
| 178 | \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; |
| 179 | \\export var foo_strong: usize = 0x1122334411223344; |
| 180 | \\comptime { |
| 181 | \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong }); |
| 182 | \\} |
| 183 | , |
| 184 | }); |
| 185 | |
| 186 | case.verifyObjdump(lib.getEmittedBin(), &.{ |
| 187 | "-s", |
| 188 | "--exports", |
| 189 | "--only-symbol=foo", |
| 190 | }, .{}); |
| 191 | |
| 192 | if (ctx.target.result.os.tag == .windows) { |
| 193 | case.verifyObjdump(lib.getEmittedImplib(), &.{ |
| 194 | "-s", |
| 195 | "--exports=sort", |
| 196 | "--only-symbol=foo", |
| 197 | }, .{ .sub_name = "implib", .os = true, .arch = true }); |
| 198 | } |
| 199 | |
| 200 | const exe = case.addExecutable(.{ |
| 201 | .name = "test", |
| 202 | .zig_source_bytes = |
| 203 | \\pub fn main() !u8 { |
| 204 | \\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true }); |
| 205 | \\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true }); |
| 206 | \\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true }); |
| 207 | \\ return @intFromBool(0x2244668822451255 != |
| 208 | \\ foo_array[1] + |
| 209 | \\ foo_strong.* + |
| 210 | \\ foo_strong_alias.*); |
| 211 | \\} |
| 212 | , |
| 213 | }); |
| 214 | exe.root_module.linkLibrary(lib); |
| 215 | |
| 216 | const run = case.addRunArtifact(exe); |
| 217 | run.addCheck(.{ .expect_term = .{ .exited = 0 } }); |
| 218 | } |
| 219 | |
| 220 | if (ctx.includeTest("abs-symbol")) |case| { |
| 221 | const abs = case.addObject(.{ |
| 222 | .name = "abs", |
| 223 | .use_llvm = true, // TODO: .globl not supported on self-hosted |
| 224 | .use_lld = true, |
| 225 | .asm_source_bytes = |
| 226 | \\.globl foo |
| 227 | \\foo = 0xcafecafe |
| 228 | \\ |
| 229 | , |
| 230 | }); |
| 231 | |
| 232 | const abs_reloc = case.addObject(.{ |
| 233 | .name = "abs_reloc", |
| 234 | .use_llvm = true, // TODO: .globl not supported on self-hosted |
| 235 | .use_lld = true, |
| 236 | .asm_source_bytes = |
| 237 | \\.data |
| 238 | \\.globl foo_copy |
| 239 | \\foo_copy: |
| 240 | \\.long foo |
| 241 | , |
| 242 | }); |
| 243 | |
| 244 | case.verifyObjdump(abs_reloc.getEmittedBin(), &.{ |
| 245 | "-s", |
| 246 | "--relocs", |
| 247 | }, .{ .arch = true }); |
| 248 | |
| 249 | const exe = case.addExecutable(.{ |
| 250 | .name = "test", |
| 251 | .zig_source_bytes = |
| 252 | \\extern var foo_copy: u32; |
| 253 | \\pub fn main() !u8 { |
| 254 | \\ return @intFromBool(foo_copy != 0xcafecafe); |
| 255 | \\} |
| 256 | , |
| 257 | }); |
| 258 | exe.root_module.addObject(abs); |
| 259 | exe.root_module.addObject(abs_reloc); |
| 260 | |
| 261 | const run = case.addRunArtifact(exe); |
| 262 | run.addCheck(.{ .expect_term = .{ .exited = 0 } }); |
| 263 | |
| 264 | if (!ctx.use_llvm) { |
| 265 | const exe_reloc_err = case.addExecutable(.{ |
| 266 | .name = "test-reloc-err", |
| 267 | .zig_source_bytes = |
| 268 | \\extern const foo: u32; |
| 269 | \\pub fn main() !u8 { |
| 270 | \\ return @intFromBool(foo != 0xcafecafe); |
| 271 | \\} |
| 272 | , |
| 273 | }); |
| 274 | exe_reloc_err.root_module.addObject(abs); |
| 275 | case.expectLinkErrors(exe_reloc_err, .{ |
| 276 | .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/", |
| 277 | }); |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | if (ctx.includeTest("explicit-extern-lib-name")) |case| { |
| 282 | // TODO: Lld.zig does not look at explicit inputs to resolve explicit extern lib names |
| 283 | if (ctx.use_llvm) return; |
| 284 | |
| 285 | const lib1 = case.addLibrary(.dynamic, .{ |
| 286 | .name = "lib1", |
| 287 | .name_target = false, |
| 288 | .zig_source_bytes = |
| 289 | \\export fn foo() u8 { |
| 290 | \\ return 43; |
| 291 | \\} |
| 292 | , |
| 293 | }); |
| 294 | |
| 295 | const lib2 = case.addLibrary(.dynamic, .{ |
| 296 | .name = "lib2", |
| 297 | .name_target = false, |
| 298 | .zig_source_bytes = |
| 299 | \\export fn foo() u8 { |
| 300 | \\ return 42; |
| 301 | \\} |
| 302 | , |
| 303 | }); |
| 304 | |
| 305 | const lib3 = case.addLibrary(.static, .{ |
| 306 | .name = "lib3", |
| 307 | .zig_source_bytes = |
| 308 | \\extern fn foo() u8; |
| 309 | \\export fn callFoo() u8 { |
| 310 | \\ return foo(); |
| 311 | \\} |
| 312 | , |
| 313 | }); |
| 314 | |
| 315 | const exe = case.addExecutable(.{ |
| 316 | .name = "test", |
| 317 | .zig_source_bytes = |
| 318 | \\extern "explicit-extern-lib-name-lib2" fn foo() u8; |
| 319 | \\extern fn callFoo() u8; |
| 320 | \\pub fn main() !u8 { |
| 321 | \\ return foo() + callFoo(); |
| 322 | \\} |
| 323 | , |
| 324 | }); |
| 325 | exe.root_module.linkLibrary(lib1); |
| 326 | exe.root_module.linkLibrary(lib2); |
| 327 | // exe.root_module.addLibraryPath(.{ |
| 328 | // .generated = .{ |
| 329 | // .index = lib2.getEmittedBin().generated.index, |
| 330 | // .up = 1, |
| 331 | // }, |
| 332 | // }); |
| 333 | exe.root_module.linkLibrary(lib3); |
| 334 | |
| 335 | const run = case.addRunArtifact(exe); |
| 336 | run.addCheck(.{ .expect_term = .{ .exited = 84 } }); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | const LinkContext = @import("tests.zig").LinkContext; |
| 341 | const std = @import("std"); |