| author | |
| committer | |
| log | 1b95427715b58cf4cd6df63fc9a7a8d200ca5d47 |
| tree | 97e700f4bc3c22369cfd9cc904d91c4fc39b0f7a |
| parent | 72bc140ad16a4a2dbe632129ea9068630e019277 |
x86_64: emit the correct encodings for loading / calling .is_dll_import externs
Coff: fix emitting an empty import directory
objdump: add --exports=sort for sorting implibs in snapshots (self-hosted outputs members in a different order than llvm)
objdump: fix some missed redactions / filters / elements calls
test: add dllimport standalone test12 files changed, 250 insertions(+), 48 deletions(-)
lib/compiler/objdump.zig+80-22| ... | ... | @@ -11,6 +11,7 @@ var stdout_buffer: [4000]u8 = undefined; |
| 11 | 11 | |
| 12 | 12 | const Options = struct { |
| 13 | 13 | exports: bool, |
| 14 | exports_sort: bool, | |
| 14 | 15 | file_headers: bool, |
| 15 | 16 | imports: bool, |
| 16 | 17 | input_path: []const u8, |
| ... | ... | @@ -53,6 +54,7 @@ pub fn main(init: std.process.Init) !void { |
| 53 | 54 | var i: usize = 1; |
| 54 | 55 | |
| 55 | 56 | var opt_exports: ?bool = null; |
| 57 | var opt_exports_sort: ?bool = null; | |
| 56 | 58 | var opt_file_headers: ?bool = null; |
| 57 | 59 | var opt_imports: ?bool = null; |
| 58 | 60 | var opt_input_path: ?[]const u8 = null; |
| ... | ... | @@ -81,9 +83,11 @@ pub fn main(init: std.process.Init) !void { |
| 81 | 83 | opt_section_headers = true; |
| 82 | 84 | opt_symbols = true; |
| 83 | 85 | opt_relocs = true; |
| 84 | } else if (mem.eql(u8, arg, "--exports")) { | |
| 86 | } else if (mem.startsWith(u8, arg, "--exports")) { | |
| 85 | 87 | opt_exports = true; |
| 86 | 88 | opt_linker_member = .second_linker; |
| 89 | if (mem.eql(u8, arg["--exports".len..], "=sort")) | |
| 90 | opt_exports_sort = true; | |
| 87 | 91 | } else if (mem.eql(u8, arg, "--file-headers")) { |
| 88 | 92 | opt_file_headers = true; |
| 89 | 93 | } else if (mem.eql(u8, arg, "--imports")) { |
| ... | ... | @@ -156,6 +160,7 @@ pub fn main(init: std.process.Init) !void { |
| 156 | 160 | const opts: Options = .{ |
| 157 | 161 | .input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}), |
| 158 | 162 | .exports = opt_exports orelse false, |
| 163 | .exports_sort = opt_exports_sort orelse false, | |
| 159 | 164 | .file_headers = opt_file_headers orelse false, |
| 160 | 165 | .imports = opt_imports orelse false, |
| 161 | 166 | .linker_member = opt_linker_member, |
| ... | ... | @@ -355,9 +360,12 @@ const coff = struct { |
| 355 | 360 | const r = &fr.interface; |
| 356 | 361 | r.toss(std.coff.archive_signature.len); |
| 357 | 362 | |
| 358 | var members: std.ArrayList(struct { | |
| 363 | const Member = struct { | |
| 359 | 364 | offset: u32, |
| 360 | }) = .empty; | |
| 365 | order: ?u32, | |
| 366 | }; | |
| 367 | ||
| 368 | var members: std.ArrayList(Member) = .empty; | |
| 361 | 369 | defer members.deinit(gpa); |
| 362 | 370 | var symbol_member_indices: std.ArrayList(u32) = .empty; |
| 363 | 371 | defer symbol_member_indices.deinit(gpa); |
| ... | ... | @@ -415,6 +423,10 @@ const coff = struct { |
| 415 | 423 | for (0..num_symbols) |symbol_i| { |
| 416 | 424 | const symbol = r.takeDelimiter(0) catch |err| |
| 417 | 425 | return d.failParse("unable to read first linker member string table: {t}", .{err}); |
| 426 | ||
| 427 | if (!filterMatches(d.opts.symbol_filters, symbol.?)) | |
| 428 | continue; | |
| 429 | ||
| 418 | 430 | const offset = std.mem.readInt(u32, offsets[symbol_i * 4 ..][0..4], .big); |
| 419 | 431 | try w.print("{f} {s}\n", .{ |
| 420 | 432 | fmtIntField(d, offset, .{ .kind = .va }), |
| ... | ... | @@ -441,6 +453,7 @@ const coff = struct { |
| 441 | 453 | for (0..num_members) |_| |
| 442 | 454 | members.addOneAssumeCapacity().* = .{ |
| 443 | 455 | .offset = try r.takeInt(u32, .little), |
| 456 | .order = null, | |
| 444 | 457 | }; |
| 445 | 458 | |
| 446 | 459 | const num_symbols = try r.takeInt(u32, .little); |
| ... | ... | @@ -451,14 +464,42 @@ const coff = struct { |
| 451 | 464 | if (dump_header) |
| 452 | 465 | try w.print( |
| 453 | 466 | \\{t: >16} type |
| 454 | \\ | {d} symbols | |
| 455 | \\ | {d} members | |
| 467 | \\ | {f} symbols | |
| 468 | \\ | {f} members | |
| 456 | 469 | \\ |
| 457 | , .{ expected_kind, num_symbols, num_members }); | |
| 470 | , .{ | |
| 471 | expected_kind, | |
| 472 | fmtIntField(d, num_symbols, .{ .kind = .size, .width = .auto }), | |
| 473 | fmtIntField(d, num_members, .{ .kind = .size, .width = .auto }), | |
| 474 | }); | |
| 458 | 475 | |
| 459 | 476 | try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); |
| 460 | for (0..num_symbols) |_| | |
| 461 | symbol_member_indices.addOneAssumeCapacity().* = (try r.takeInt(u16, .little)) - 1; | |
| 477 | for (0..num_symbols) |order| { | |
| 478 | const index = (try r.takeInt(u16, .little)) - 1; | |
| 479 | if (index >= members.items.len) | |
| 480 | return d.failParse("invalid member index 0x{x} in seconds linker member indices array", .{index}); | |
| 481 | ||
| 482 | symbol_member_indices.addOneAssumeCapacity().* = index; | |
| 483 | ||
| 484 | if (members.items[index].order == null) | |
| 485 | members.items[index].order = @intCast(order); | |
| 486 | } | |
| 487 | ||
| 488 | if (d.opts.exports and d.opts.exports_sort) { | |
| 489 | std.sort.pdq(Member, members.items, {}, struct { | |
| 490 | fn lessThan(ctx: void, lhs: Member, rhs: Member) bool { | |
| 491 | _ = ctx; | |
| 492 | if (lhs.order == null and rhs.order == null) | |
| 493 | return lhs.offset < rhs.offset | |
| 494 | else if (lhs.order) |lhs_order| | |
| 495 | return if (rhs.order) |rhs_order| lhs_order < rhs_order else false | |
| 496 | else if (rhs.order) |rhs_order| | |
| 497 | return if (lhs.order) |lhs_order| lhs_order < rhs_order else true | |
| 498 | else | |
| 499 | unreachable; | |
| 500 | } | |
| 501 | }.lessThan); | |
| 502 | } | |
| 462 | 503 | |
| 463 | 504 | if (d.opts.linker_member == .second_linker) { |
| 464 | 505 | if (d.element(.@"table-header")) |
| ... | ... | @@ -480,6 +521,9 @@ const coff = struct { |
| 480 | 521 | else => |e| return e, |
| 481 | 522 | }) |n| n else return d.failParse("unterminated string found in second linker member", .{}); |
| 482 | 523 | |
| 524 | if (!filterMatches(d.opts.symbol_filters, symbol_name)) | |
| 525 | continue; | |
| 526 | ||
| 483 | 527 | try w.print("{f} {s}\n", .{ |
| 484 | 528 | fmtIntField( |
| 485 | 529 | d, |
| ... | ... | @@ -844,8 +888,8 @@ const coff = struct { |
| 844 | 888 | section_i + 1, |
| 845 | 889 | raw_name, |
| 846 | 890 | fmtIntField(d, section.header.virtual_address, .{ .kind = .va }), |
| 847 | fmtIntField(d, section.header.virtual_size, .{ .kind = .size, .width = 9 }), | |
| 848 | fmtIntField(d, section.header.size_of_raw_data, .{ .kind = .size, .width = 9 }), | |
| 891 | fmtIntField(d, section.header.virtual_size, .{ .kind = .size, .width = .{ .explicit = 9 } }), | |
| 892 | fmtIntField(d, section.header.size_of_raw_data, .{ .kind = .size, .width = .{ .explicit = 9 } }), | |
| 849 | 893 | fmtIntField(d, section.header.pointer_to_raw_data, .{ .kind = .va }), |
| 850 | 894 | fmtIntField(d, section.header.pointer_to_relocations, .{ .kind = .va }), |
| 851 | 895 | fmtIntField(d, section.header.pointer_to_linenumbers, .{ .kind = .va }), |
| ... | ... | @@ -1309,14 +1353,16 @@ const coff = struct { |
| 1309 | 1353 | |
| 1310 | 1354 | const dll_name = (try r.takeDelimiter(0)).?; |
| 1311 | 1355 | |
| 1312 | try w.print("Import table entry for {s}:\n", .{dll_name}); | |
| 1356 | if (d.element(.@"header-name")) | |
| 1357 | try w.print("Import table entry for {s}:\n", .{dll_name}); | |
| 1313 | 1358 | try dumpHeader(d, Entry, &entry, struct {}); |
| 1314 | 1359 | |
| 1315 | try w.print( | |
| 1316 | \\ | |
| 1317 | \\ Ord Hint Name | |
| 1318 | \\ | |
| 1319 | , .{}); | |
| 1360 | if (d.element(.@"table-header")) | |
| 1361 | try w.print( | |
| 1362 | \\ | |
| 1363 | \\ Ord Hint Name | |
| 1364 | \\ | |
| 1365 | , .{}); | |
| 1320 | 1366 | |
| 1321 | 1367 | const ilt_section = sectionContainingRva( |
| 1322 | 1368 | rva_index, |
| ... | ... | @@ -1565,7 +1611,7 @@ const coff = struct { |
| 1565 | 1611 | |
| 1566 | 1612 | const FormatIntField = struct { |
| 1567 | 1613 | val: ?u64, |
| 1568 | width: usize, | |
| 1614 | width: ?usize, | |
| 1569 | 1615 | zero_fill: bool, |
| 1570 | 1616 | }; |
| 1571 | 1617 | |
| ... | ... | @@ -1574,14 +1620,22 @@ const coff = struct { |
| 1574 | 1620 | val: anytype, |
| 1575 | 1621 | params: struct { |
| 1576 | 1622 | kind: ?FieldKind = null, |
| 1577 | width: ?usize = null, | |
| 1623 | width: union(enum) { | |
| 1624 | fit_max, | |
| 1625 | auto, | |
| 1626 | explicit: usize, | |
| 1627 | } = .fit_max, | |
| 1578 | 1628 | zero_fill: bool = false, |
| 1579 | 1629 | }, |
| 1580 | 1630 | ) std.fmt.Alt(FormatIntField, intFieldString) { |
| 1581 | 1631 | return .{ |
| 1582 | 1632 | .data = .{ |
| 1583 | 1633 | .val = if (d.redacted(params.kind)) null else val, |
| 1584 | .width = params.width orelse @typeInfo(@TypeOf(val)).int.bits / 4, | |
| 1634 | .width = switch (params.width) { | |
| 1635 | .fit_max => @typeInfo(@TypeOf(val)).int.bits / 4, | |
| 1636 | .auto => null, | |
| 1637 | .explicit => |w| w, | |
| 1638 | }, | |
| 1585 | 1639 | .zero_fill = params.zero_fill, |
| 1586 | 1640 | }, |
| 1587 | 1641 | }; |
| ... | ... | @@ -1594,7 +1648,7 @@ const coff = struct { |
| 1594 | 1648 | .alignment = .right, |
| 1595 | 1649 | .fill = if (field.zero_fill) '0' else ' ', |
| 1596 | 1650 | }); |
| 1597 | } else try w.splatByteAll('x', field.width); | |
| 1651 | } else try w.splatByteAll('x', field.width orelse 1); | |
| 1598 | 1652 | } |
| 1599 | 1653 | |
| 1600 | 1654 | fn dumpFlags(w: *Io.Writer, comptime fmt: []const u8, comptime T: type, flags: *const T, cols: u32) !void { |
| ... | ... | @@ -1628,6 +1682,8 @@ const coff = struct { |
| 1628 | 1682 | if (std.mem.startsWith(u8, name, "number_") or |
| 1629 | 1683 | std.mem.startsWith(u8, name, "size")) |
| 1630 | 1684 | return .size; |
| 1685 | if (std.mem.startsWith(u8, name, "hint")) | |
| 1686 | return .ord; | |
| 1631 | 1687 | return null; |
| 1632 | 1688 | } |
| 1633 | 1689 | |
| ... | ... | @@ -1645,7 +1701,7 @@ const coff = struct { |
| 1645 | 1701 | switch (@typeInfo(field.type)) { |
| 1646 | 1702 | .int => try d.w.print("{f} {s}\n", .{ fmtIntField(d, val.*, .{ |
| 1647 | 1703 | .kind = comptime fieldKind(field.name), |
| 1648 | .width = 16, | |
| 1704 | .width = .{ .explicit = 16 }, | |
| 1649 | 1705 | }), field.name }), |
| 1650 | 1706 | .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field.name, val.* }), |
| 1651 | 1707 | .@"struct" => |s| { |
| ... | ... | @@ -1690,7 +1746,9 @@ const usage = |
| 1690 | 1746 | \\Options: |
| 1691 | 1747 | \\ -h, --help Print this help and exit |
| 1692 | 1748 | \\ --all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols |
| 1693 | \\ --exports Display exported symbols. In the case of COFF import libraries, display import headers. | |
| 1749 | \\ --exports[=sort] Display exported symbols. | |
| 1750 | \\ In the case of COFF import libraries, displays the symbol list and import headers. | |
| 1751 | \\ Specify =sort to optionally sort the import headers by symbol name. | |
| 1694 | 1752 | \\ --file-headers Display file-format specific headers |
| 1695 | 1753 | \\ --imports Display imported symbols |
| 1696 | 1754 | \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2) |
src/codegen/x86_64/Emit.zig+28-2| ... | ... | @@ -113,6 +113,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 113 | 113 | .default => true, |
| 114 | 114 | .hidden, .protected => false, |
| 115 | 115 | }, |
| 116 | .is_dll_import = @"extern".is_dll_import, | |
| 116 | 117 | .force_pcrel_direct = switch (@"extern".relocation) { |
| 117 | 118 | .any => false, |
| 118 | 119 | .pcrel => true, |
| ... | ... | @@ -171,7 +172,13 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 171 | 172 | switch (lowered_inst.encoding.mnemonic) { |
| 172 | 173 | .call => { |
| 173 | 174 | reloc.target = .{ .branch = target }; |
| 174 | try emit.encodeInst(lowered_inst, reloc_info); | |
| 175 | if (target.is_dll_import and emit.bin_file.cast(.coff2) != null) { | |
| 176 | try emit.encodeInst(try .new(.none, .call, &.{ | |
| 177 | .{ .mem = .initRip(.ptr, 0) }, | |
| 178 | }, emit.lower.target), reloc_info); | |
| 179 | } else { | |
| 180 | try emit.encodeInst(lowered_inst, reloc_info); | |
| 181 | } | |
| 175 | 182 | continue :lowered_inst; |
| 176 | 183 | }, |
| 177 | 184 | else => {}, |
| ... | ... | @@ -247,7 +254,25 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 247 | 254 | else => unreachable, |
| 248 | 255 | } |
| 249 | 256 | } else if (emit.bin_file.cast(.coff2)) |_| { |
| 250 | switch (lowered_inst.encoding.mnemonic) { | |
| 257 | if (reloc.target.is_dll_import) switch (lowered_inst.encoding.mnemonic) { | |
| 258 | .lea => try emit.encodeInst(try .new(.none, .mov, &.{ | |
| 259 | lowered_inst.ops[0], | |
| 260 | .{ .mem = .initRip(.ptr, 0) }, | |
| 261 | }, emit.lower.target), reloc_info), | |
| 262 | .mov => { | |
| 263 | try emit.encodeInst(try .new(.none, .mov, &.{ | |
| 264 | lowered_inst.ops[0], | |
| 265 | .{ .mem = .initRip(.ptr, 0) }, | |
| 266 | }, emit.lower.target), reloc_info); | |
| 267 | try emit.encodeInst(try .new(.none, .mov, &.{ | |
| 268 | lowered_inst.ops[0], | |
| 269 | .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{ | |
| 270 | .reg = lowered_inst.ops[0].reg.to64(), | |
| 271 | } }) }, | |
| 272 | }, emit.lower.target), &.{}); | |
| 273 | }, | |
| 274 | else => unreachable, | |
| 275 | } else switch (lowered_inst.encoding.mnemonic) { | |
| 251 | 276 | .lea => try emit.encodeInst(try .new(.none, .lea, &.{ |
| 252 | 277 | lowered_inst.ops[0], |
| 253 | 278 | .{ .mem = .initRip(.none, 0) }, |
| ... | ... | @@ -717,6 +742,7 @@ const RelocInfo = struct { |
| 717 | 742 | const Symbol = struct { |
| 718 | 743 | symbol: link.File.SymbolId, |
| 719 | 744 | is_extern: bool, |
| 745 | is_dll_import: bool = false, | |
| 720 | 746 | force_pcrel_direct: bool = false, |
| 721 | 747 | }; |
| 722 | 748 | }; |
src/link/Coff.zig+18-9| ... | ... | @@ -2103,7 +2103,7 @@ fn initHeaders( |
| 2103 | 2103 | coff.mf.flags.block_size, |
| 2104 | 2104 | .{ .read = true, .initialized = true }, |
| 2105 | 2105 | )).symbol(coff).node(coff), |
| 2106 | .{ .alignment = .@"4", .moved = true }, | |
| 2106 | .{ .alignment = .@"4" }, | |
| 2107 | 2107 | ); |
| 2108 | 2108 | coff.nodes.appendAssumeCapacity(.import_directory_table); |
| 2109 | 2109 | |
| ... | ... | @@ -6115,6 +6115,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6115 | 6115 | const imp_match = std.mem.startsWith(u8, global_name, imp_prefix); |
| 6116 | 6116 | |
| 6117 | 6117 | // Globals may have the __imp_ prefix already if they are undef externals from another input. |
| 6118 | assert(sym.flags.dll_storage_class != .dllexport); | |
| 6118 | 6119 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) |
| 6119 | 6120 | .{ gn.name, imp_match } |
| 6120 | 6121 | else name: { |
| ... | ... | @@ -6722,10 +6723,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 6722 | 6723 | try input_symbol.si.flushMoved(coff); |
| 6723 | 6724 | } |
| 6724 | 6725 | }, |
| 6725 | .import_directory_table => coff.targetStore( | |
| 6726 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, | |
| 6727 | coff.computeNodeRva(ni), | |
| 6728 | ), | |
| 6726 | .import_directory_table => { | |
| 6727 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); | |
| 6728 | if (size > 0) | |
| 6729 | coff.targetStore( | |
| 6730 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, | |
| 6731 | coff.computeNodeRva(ni), | |
| 6732 | ); | |
| 6733 | }, | |
| 6729 | 6734 | .import_lookup_table => |import_index| coff.targetStore( |
| 6730 | 6735 | &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, |
| 6731 | 6736 | coff.computeNodeRva(ni), |
| ... | ... | @@ -6936,10 +6941,14 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 6936 | 6941 | } |
| 6937 | 6942 | }, |
| 6938 | 6943 | .input_section => {}, |
| 6939 | .import_directory_table => coff.targetStore( | |
| 6940 | &coff.dataDirectoryPtr(.IMPORT).size, | |
| 6941 | @intCast(size), | |
| 6942 | ), | |
| 6944 | .import_directory_table => { | |
| 6945 | const prev_size = coff.targetLoad(&coff.dataDirectoryPtr(.IMPORT).size); | |
| 6946 | coff.targetStore( | |
| 6947 | &coff.dataDirectoryPtr(.IMPORT).size, | |
| 6948 | @intCast(size), | |
| 6949 | ); | |
| 6950 | if (prev_size == 0) try coff.flushMoved(ni); | |
| 6951 | }, | |
| 6943 | 6952 | .import_lookup_table, |
| 6944 | 6953 | .import_address_table, |
| 6945 | 6954 | .import_hint_name_table, |
test/link.zig+21-12| ... | ... | @@ -72,6 +72,7 @@ pub fn addCases(ctx: *LinkContext) void { |
| 72 | 72 | if (ctx.includeTest("dynamic-lib-code")) |case| { |
| 73 | 73 | const lib = case.addLibrary(.dynamic, .{ |
| 74 | 74 | .name = "lib", |
| 75 | .name_target = false, | |
| 75 | 76 | .zig_source_bytes = |
| 76 | 77 | \\export fn foo1() callconv(.c) u64 { |
| 77 | 78 | \\ return 0x1122334411223344; |
| ... | ... | @@ -91,9 +92,9 @@ pub fn addCases(ctx: *LinkContext) void { |
| 91 | 92 | if (ctx.target.result.os.tag == .windows) { |
| 92 | 93 | case.verifyObjdump(lib.getEmittedImplib(), &.{ |
| 93 | 94 | "-s", |
| 94 | "--exports", | |
| 95 | "--exports=sort", | |
| 95 | 96 | "--only-symbol=foo", |
| 96 | }, .{ .sub_name = "implib", .os = true }); | |
| 97 | }, .{ .sub_name = "implib", .os = true, .arch = true }); | |
| 97 | 98 | } |
| 98 | 99 | |
| 99 | 100 | const exe = case.addExecutable(.{ |
| ... | ... | @@ -118,9 +119,13 @@ pub fn addCases(ctx: *LinkContext) void { |
| 118 | 119 | if (ctx.includeTest("dynamic-lib-data")) |case| { |
| 119 | 120 | const lib = case.addLibrary(.dynamic, .{ |
| 120 | 121 | .name = "lib", |
| 122 | .name_target = false, | |
| 121 | 123 | .zig_source_bytes = |
| 122 | \\export var array_foo: [2]u16 = .{ 0xffff, 0xabcd }; | |
| 123 | \\export var strong_foo: usize = 0x1122334411223344; | |
| 124 | \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; | |
| 125 | \\export var foo_strong: usize = 0x1122334411223344; | |
| 126 | \\comptime { | |
| 127 | \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong }); | |
| 128 | \\} | |
| 124 | 129 | , |
| 125 | 130 | }); |
| 126 | 131 | |
| ... | ... | @@ -131,20 +136,24 @@ pub fn addCases(ctx: *LinkContext) void { |
| 131 | 136 | }, .{}); |
| 132 | 137 | |
| 133 | 138 | if (ctx.target.result.os.tag == .windows) { |
| 134 | // TODO: objdump implib on windows | |
| 139 | case.verifyObjdump(lib.getEmittedImplib(), &.{ | |
| 140 | "-s", | |
| 141 | "--exports=sort", | |
| 142 | "--only-symbol=foo", | |
| 143 | }, .{ .sub_name = "implib", .os = true, .arch = true }); | |
| 135 | 144 | } |
| 136 | 145 | |
| 137 | 146 | const exe = case.addExecutable(.{ |
| 138 | 147 | .name = "test", |
| 139 | 148 | .zig_source_bytes = |
| 140 | \\extern var array_foo: [2]u16; | |
| 141 | \\extern var strong_foo: usize; | |
| 142 | \\extern var strong_foo_alias: usize; | |
| 143 | 149 | \\pub fn main() !u8 { |
| 144 | \\ return @intFromBool(0x2244668822451255 != | |
| 145 | \\ array_foo[1] + | |
| 146 | \\ strong_foo + | |
| 147 | \\ strong_foo_alias); | |
| 150 | \\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true }); | |
| 151 | \\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true }); | |
| 152 | \\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true }); | |
| 153 | \\ return @intFromBool(0x2244668822451255 != | |
| 154 | \\ foo_array[1] + | |
| 155 | \\ foo_strong.* + | |
| 156 | \\ foo_strong_alias.*); | |
| 148 | 157 | \\} |
| 149 | 158 | , |
| 150 | 159 | }); |
test/link/snapshots/abs-symbol.x86_64.dmp created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | xxxxxxxx ADDR32 xxxxxxxx UNDEF | foo |
test/link/snapshots/dynamic-lib-code.implib-windows.dmp+2-2| ... | ... | @@ -19,7 +19,7 @@ xxxxxxxxxxxxxxxx size_of_data |
| 19 | 19 | NAME name_type |
| 20 | 20 | symbol name | foo1 |
| 21 | 21 | import name | foo1 |
| 22 | dll | dynamic-lib-code-lib-x86_64-windows.win10...win11_dt-msvc-Debug-llvm-lld-libc.dll | |
| 22 | dll | dynamic-lib-code-lib.dll | |
| 23 | 23 | 0 version |
| 24 | 24 | 8664 machine (AMD64) |
| 25 | 25 | 0 time_date_stamp |
| ... | ... | @@ -29,4 +29,4 @@ xxxxxxxxxxxxxxxx size_of_data |
| 29 | 29 | NAME name_type |
| 30 | 30 | symbol name | foo2 |
| 31 | 31 | import name | foo2 |
| 32 | dll | dynamic-lib-code-lib-x86_64-windows.win10...win11_dt-msvc-Debug-llvm-lld-libc.dll | |
| 32 | dll | dynamic-lib-code-lib.dll |
test/link/snapshots/dynamic-lib-code.implib-x86_64-windows.dmp created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | 0 date | |
| 2 | 0 user_id | |
| 3 | 0 group_id | |
| 4 | 0 file_mode | |
| 5 | xxxxxxxxxxxxxxxx size | |
| 6 | second_linker type | |
| 7 | | x symbols | |
| 8 | | x members | |
| 9 | xxxxxxxx __imp_foo1 | |
| 10 | xxxxxxxx __imp_foo2 | |
| 11 | xxxxxxxx foo1 | |
| 12 | xxxxxxxx foo2 | |
| 13 | 0 version | |
| 14 | 8664 machine (AMD64) | |
| 15 | 0 time_date_stamp | |
| 16 | xxxxxxxxxxxxxxxx size_of_data | |
| 17 | xxxxxxxxxxxxxxxx hint | |
| 18 | CODE import_type | |
| 19 | NAME name_type | |
| 20 | symbol name | foo1 | |
| 21 | import name | foo1 | |
| 22 | dll | dynamic-lib-code-lib.dll | |
| 23 | 0 version | |
| 24 | 8664 machine (AMD64) | |
| 25 | 0 time_date_stamp | |
| 26 | xxxxxxxxxxxxxxxx size_of_data | |
| 27 | xxxxxxxxxxxxxxxx hint | |
| 28 | CODE import_type | |
| 29 | NAME name_type | |
| 30 | symbol name | foo2 | |
| 31 | import name | foo2 | |
| 32 | dll | dynamic-lib-code-lib.dll |
test/link/snapshots/dynamic-lib-data.dmp created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | Export directory: | |
| 2 | 0 flags | |
| 3 | 0 time_date_stamp | |
| 4 | 0.00 version | |
| 5 | xxxxxxxxxxxxxxxx name_rva | |
| 6 | 1 ordinal_base | |
| 7 | xxxxxxxxxxxxxxxx number_of_entries | |
| 8 | xxxxxxxxxxxxxxxx number_of_names | |
| 9 | xxxxxxxxxxxxxxxx export_address_table_rva | |
| 10 | xxxxxxxxxxxxxxxx name_pointer_table_rva | |
| 11 | xxxxxxxxxxxxxxxx ordinal_table_rva | |
| 12 | xxxx xxxx xxxxxxxx | foo_array | |
| 13 | xxxx xxxx xxxxxxxx | foo_strong | |
| 14 | xxxx xxxx xxxxxxxx | foo_strong_alias |
test/link/snapshots/dynamic-lib-data.implib-x86_64-windows.dmp created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | 0 date | |
| 2 | 0 user_id | |
| 3 | 0 group_id | |
| 4 | 0 file_mode | |
| 5 | xxxxxxxxxxxxxxxx size | |
| 6 | second_linker type | |
| 7 | | x symbols | |
| 8 | | x members | |
| 9 | xxxxxxxx __imp_foo_array | |
| 10 | xxxxxxxx __imp_foo_strong | |
| 11 | xxxxxxxx __imp_foo_strong_alias | |
| 12 | 0 version | |
| 13 | 8664 machine (AMD64) | |
| 14 | 0 time_date_stamp | |
| 15 | xxxxxxxxxxxxxxxx size_of_data | |
| 16 | xxxxxxxxxxxxxxxx hint | |
| 17 | DATA import_type | |
| 18 | NAME name_type | |
| 19 | symbol name | foo_array | |
| 20 | import name | foo_array | |
| 21 | dll | dynamic-lib-data-lib.dll | |
| 22 | 0 version | |
| 23 | 8664 machine (AMD64) | |
| 24 | 0 time_date_stamp | |
| 25 | xxxxxxxxxxxxxxxx size_of_data | |
| 26 | xxxxxxxxxxxxxxxx hint | |
| 27 | DATA import_type | |
| 28 | NAME name_type | |
| 29 | symbol name | foo_strong | |
| 30 | import name | foo_strong | |
| 31 | dll | dynamic-lib-data-lib.dll | |
| 32 | 0 version | |
| 33 | 8664 machine (AMD64) | |
| 34 | 0 time_date_stamp | |
| 35 | xxxxxxxxxxxxxxxx size_of_data | |
| 36 | xxxxxxxxxxxxxxxx hint | |
| 37 | DATA import_type | |
| 38 | NAME name_type | |
| 39 | symbol name | foo_strong_alias | |
| 40 | import name | foo_strong_alias | |
| 41 | dll | dynamic-lib-data-lib.dll |
test/src/Link.zig+2-1| ... | ... | @@ -185,7 +185,8 @@ pub const Case = struct { |
| 185 | 185 | if (try snapshotNameInner(w, scope.link_libc, &sep)) |
| 186 | 186 | try w.writeAll(if (ctx.link_libc) "libc" else "no-libc"); |
| 187 | 187 | |
| 188 | if (sep == '-') try w.writeByte('.'); | |
| 188 | if (sep == '-') sep = '.'; | |
| 189 | try w.writeByte(sep); | |
| 189 | 190 | try w.writeAll("dmp"); |
| 190 | 191 | |
| 191 | 192 | return try snapshot_name.toOwnedSlice(); |
test/standalone/shared_library/mathtest.zig+2| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | export var exported_var: i32 = 9999; | |
| 2 | ||
| 1 | 3 | export fn add(a: i32, b: i32) i32 { |
| 2 | 4 | return a + b; |
| 3 | 5 | } |
test/standalone/shared_library/test.c+9| ... | ... | @@ -7,7 +7,16 @@ |
| 7 | 7 | #include <stdint.h> |
| 8 | 8 | int32_t add(int32_t a, int32_t b); |
| 9 | 9 | |
| 10 | #if _WIN32 | |
| 11 | #define IMPORT __declspec(dllimport) | |
| 12 | #else | |
| 13 | #define IMPORT | |
| 14 | #endif | |
| 15 | ||
| 16 | extern IMPORT int32_t exported_var; | |
| 17 | ||
| 10 | 18 | int main(int argc, char **argv) { |
| 11 | 19 | assert(add(42, 1337) == 1379); |
| 20 | assert(exported_var == 9999); | |
| 12 | 21 | return 0; |
| 13 | 22 | } |