| 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,6 +11,7 @@ var stdout_buffer: [4000]u8 = undefined; |
| 11 | 11 | ||
| 12 | const Options = struct { | 12 | const Options = struct { |
| 13 | exports: bool, | 13 | exports: bool, |
| 14 | exports_sort: bool, | ||
| 14 | file_headers: bool, | 15 | file_headers: bool, |
| 15 | imports: bool, | 16 | imports: bool, |
| 16 | input_path: []const u8, | 17 | input_path: []const u8, |
| ... | @@ -53,6 +54,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -53,6 +54,7 @@ pub fn main(init: std.process.Init) !void { |
| 53 | var i: usize = 1; | 54 | var i: usize = 1; |
| 54 | 55 | ||
| 55 | var opt_exports: ?bool = null; | 56 | var opt_exports: ?bool = null; |
| 57 | var opt_exports_sort: ?bool = null; | ||
| 56 | var opt_file_headers: ?bool = null; | 58 | var opt_file_headers: ?bool = null; |
| 57 | var opt_imports: ?bool = null; | 59 | var opt_imports: ?bool = null; |
| 58 | var opt_input_path: ?[]const u8 = null; | 60 | var opt_input_path: ?[]const u8 = null; |
| ... | @@ -81,9 +83,11 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -81,9 +83,11 @@ pub fn main(init: std.process.Init) !void { |
| 81 | opt_section_headers = true; | 83 | opt_section_headers = true; |
| 82 | opt_symbols = true; | 84 | opt_symbols = true; |
| 83 | opt_relocs = true; | 85 | opt_relocs = true; |
| 84 | } else if (mem.eql(u8, arg, "--exports")) { | 86 | } else if (mem.startsWith(u8, arg, "--exports")) { |
| 85 | opt_exports = true; | 87 | opt_exports = true; |
| 86 | opt_linker_member = .second_linker; | 88 | opt_linker_member = .second_linker; |
| 89 | if (mem.eql(u8, arg["--exports".len..], "=sort")) | ||
| 90 | opt_exports_sort = true; | ||
| 87 | } else if (mem.eql(u8, arg, "--file-headers")) { | 91 | } else if (mem.eql(u8, arg, "--file-headers")) { |
| 88 | opt_file_headers = true; | 92 | opt_file_headers = true; |
| 89 | } else if (mem.eql(u8, arg, "--imports")) { | 93 | } else if (mem.eql(u8, arg, "--imports")) { |
| ... | @@ -156,6 +160,7 @@ pub fn main(init: std.process.Init) !void { | ... | @@ -156,6 +160,7 @@ pub fn main(init: std.process.Init) !void { |
| 156 | const opts: Options = .{ | 160 | const opts: Options = .{ |
| 157 | .input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}), | 161 | .input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}), |
| 158 | .exports = opt_exports orelse false, | 162 | .exports = opt_exports orelse false, |
| 163 | .exports_sort = opt_exports_sort orelse false, | ||
| 159 | .file_headers = opt_file_headers orelse false, | 164 | .file_headers = opt_file_headers orelse false, |
| 160 | .imports = opt_imports orelse false, | 165 | .imports = opt_imports orelse false, |
| 161 | .linker_member = opt_linker_member, | 166 | .linker_member = opt_linker_member, |
| ... | @@ -355,9 +360,12 @@ const coff = struct { | ... | @@ -355,9 +360,12 @@ const coff = struct { |
| 355 | const r = &fr.interface; | 360 | const r = &fr.interface; |
| 356 | r.toss(std.coff.archive_signature.len); | 361 | r.toss(std.coff.archive_signature.len); |
| 357 | 362 | ||
| 358 | var members: std.ArrayList(struct { | 363 | const Member = struct { |
| 359 | offset: u32, | 364 | offset: u32, |
| 360 | }) = .empty; | 365 | order: ?u32, |
| 366 | }; | ||
| 367 | |||
| 368 | var members: std.ArrayList(Member) = .empty; | ||
| 361 | defer members.deinit(gpa); | 369 | defer members.deinit(gpa); |
| 362 | var symbol_member_indices: std.ArrayList(u32) = .empty; | 370 | var symbol_member_indices: std.ArrayList(u32) = .empty; |
| 363 | defer symbol_member_indices.deinit(gpa); | 371 | defer symbol_member_indices.deinit(gpa); |
| ... | @@ -415,6 +423,10 @@ const coff = struct { | ... | @@ -415,6 +423,10 @@ const coff = struct { |
| 415 | for (0..num_symbols) |symbol_i| { | 423 | for (0..num_symbols) |symbol_i| { |
| 416 | const symbol = r.takeDelimiter(0) catch |err| | 424 | const symbol = r.takeDelimiter(0) catch |err| |
| 417 | return d.failParse("unable to read first linker member string table: {t}", .{err}); | 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 | const offset = std.mem.readInt(u32, offsets[symbol_i * 4 ..][0..4], .big); | 430 | const offset = std.mem.readInt(u32, offsets[symbol_i * 4 ..][0..4], .big); |
| 419 | try w.print("{f} {s}\n", .{ | 431 | try w.print("{f} {s}\n", .{ |
| 420 | fmtIntField(d, offset, .{ .kind = .va }), | 432 | fmtIntField(d, offset, .{ .kind = .va }), |
| ... | @@ -441,6 +453,7 @@ const coff = struct { | ... | @@ -441,6 +453,7 @@ const coff = struct { |
| 441 | for (0..num_members) |_| | 453 | for (0..num_members) |_| |
| 442 | members.addOneAssumeCapacity().* = .{ | 454 | members.addOneAssumeCapacity().* = .{ |
| 443 | .offset = try r.takeInt(u32, .little), | 455 | .offset = try r.takeInt(u32, .little), |
| 456 | .order = null, | ||
| 444 | }; | 457 | }; |
| 445 | 458 | ||
| 446 | const num_symbols = try r.takeInt(u32, .little); | 459 | const num_symbols = try r.takeInt(u32, .little); |
| ... | @@ -451,14 +464,42 @@ const coff = struct { | ... | @@ -451,14 +464,42 @@ const coff = struct { |
| 451 | if (dump_header) | 464 | if (dump_header) |
| 452 | try w.print( | 465 | try w.print( |
| 453 | \\{t: >16} type | 466 | \\{t: >16} type |
| 454 | \\ | {d} symbols | 467 | \\ | {f} symbols |
| 455 | \\ | {d} members | 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 | try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); | 476 | try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); |
| 460 | for (0..num_symbols) |_| | 477 | for (0..num_symbols) |order| { |
| 461 | symbol_member_indices.addOneAssumeCapacity().* = (try r.takeInt(u16, .little)) - 1; | 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 | if (d.opts.linker_member == .second_linker) { | 504 | if (d.opts.linker_member == .second_linker) { |
| 464 | if (d.element(.@"table-header")) | 505 | if (d.element(.@"table-header")) |
| ... | @@ -480,6 +521,9 @@ const coff = struct { | ... | @@ -480,6 +521,9 @@ const coff = struct { |
| 480 | else => |e| return e, | 521 | else => |e| return e, |
| 481 | }) |n| n else return d.failParse("unterminated string found in second linker member", .{}); | 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 | try w.print("{f} {s}\n", .{ | 527 | try w.print("{f} {s}\n", .{ |
| 484 | fmtIntField( | 528 | fmtIntField( |
| 485 | d, | 529 | d, |
| ... | @@ -844,8 +888,8 @@ const coff = struct { | ... | @@ -844,8 +888,8 @@ const coff = struct { |
| 844 | section_i + 1, | 888 | section_i + 1, |
| 845 | raw_name, | 889 | raw_name, |
| 846 | fmtIntField(d, section.header.virtual_address, .{ .kind = .va }), | 890 | fmtIntField(d, section.header.virtual_address, .{ .kind = .va }), |
| 847 | fmtIntField(d, section.header.virtual_size, .{ .kind = .size, .width = 9 }), | 891 | fmtIntField(d, section.header.virtual_size, .{ .kind = .size, .width = .{ .explicit = 9 } }), |
| 848 | fmtIntField(d, section.header.size_of_raw_data, .{ .kind = .size, .width = 9 }), | 892 | fmtIntField(d, section.header.size_of_raw_data, .{ .kind = .size, .width = .{ .explicit = 9 } }), |
| 849 | fmtIntField(d, section.header.pointer_to_raw_data, .{ .kind = .va }), | 893 | fmtIntField(d, section.header.pointer_to_raw_data, .{ .kind = .va }), |
| 850 | fmtIntField(d, section.header.pointer_to_relocations, .{ .kind = .va }), | 894 | fmtIntField(d, section.header.pointer_to_relocations, .{ .kind = .va }), |
| 851 | fmtIntField(d, section.header.pointer_to_linenumbers, .{ .kind = .va }), | 895 | fmtIntField(d, section.header.pointer_to_linenumbers, .{ .kind = .va }), |
| ... | @@ -1309,14 +1353,16 @@ const coff = struct { | ... | @@ -1309,14 +1353,16 @@ const coff = struct { |
| 1309 | 1353 | ||
| 1310 | const dll_name = (try r.takeDelimiter(0)).?; | 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 | try dumpHeader(d, Entry, &entry, struct {}); | 1358 | try dumpHeader(d, Entry, &entry, struct {}); |
| 1314 | 1359 | ||
| 1315 | try w.print( | 1360 | if (d.element(.@"table-header")) |
| 1316 | \\ | 1361 | try w.print( |
| 1317 | \\ Ord Hint Name | 1362 | \\ |
| 1318 | \\ | 1363 | \\ Ord Hint Name |
| 1319 | , .{}); | 1364 | \\ |
| 1365 | , .{}); | ||
| 1320 | 1366 | ||
| 1321 | const ilt_section = sectionContainingRva( | 1367 | const ilt_section = sectionContainingRva( |
| 1322 | rva_index, | 1368 | rva_index, |
| ... | @@ -1565,7 +1611,7 @@ const coff = struct { | ... | @@ -1565,7 +1611,7 @@ const coff = struct { |
| 1565 | 1611 | ||
| 1566 | const FormatIntField = struct { | 1612 | const FormatIntField = struct { |
| 1567 | val: ?u64, | 1613 | val: ?u64, |
| 1568 | width: usize, | 1614 | width: ?usize, |
| 1569 | zero_fill: bool, | 1615 | zero_fill: bool, |
| 1570 | }; | 1616 | }; |
| 1571 | 1617 | ||
| ... | @@ -1574,14 +1620,22 @@ const coff = struct { | ... | @@ -1574,14 +1620,22 @@ const coff = struct { |
| 1574 | val: anytype, | 1620 | val: anytype, |
| 1575 | params: struct { | 1621 | params: struct { |
| 1576 | kind: ?FieldKind = null, | 1622 | kind: ?FieldKind = null, |
| 1577 | width: ?usize = null, | 1623 | width: union(enum) { |
| 1624 | fit_max, | ||
| 1625 | auto, | ||
| 1626 | explicit: usize, | ||
| 1627 | } = .fit_max, | ||
| 1578 | zero_fill: bool = false, | 1628 | zero_fill: bool = false, |
| 1579 | }, | 1629 | }, |
| 1580 | ) std.fmt.Alt(FormatIntField, intFieldString) { | 1630 | ) std.fmt.Alt(FormatIntField, intFieldString) { |
| 1581 | return .{ | 1631 | return .{ |
| 1582 | .data = .{ | 1632 | .data = .{ |
| 1583 | .val = if (d.redacted(params.kind)) null else val, | 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 | .zero_fill = params.zero_fill, | 1639 | .zero_fill = params.zero_fill, |
| 1586 | }, | 1640 | }, |
| 1587 | }; | 1641 | }; |
| ... | @@ -1594,7 +1648,7 @@ const coff = struct { | ... | @@ -1594,7 +1648,7 @@ const coff = struct { |
| 1594 | .alignment = .right, | 1648 | .alignment = .right, |
| 1595 | .fill = if (field.zero_fill) '0' else ' ', | 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 | fn dumpFlags(w: *Io.Writer, comptime fmt: []const u8, comptime T: type, flags: *const T, cols: u32) !void { | 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,6 +1682,8 @@ const coff = struct { |
| 1628 | if (std.mem.startsWith(u8, name, "number_") or | 1682 | if (std.mem.startsWith(u8, name, "number_") or |
| 1629 | std.mem.startsWith(u8, name, "size")) | 1683 | std.mem.startsWith(u8, name, "size")) |
| 1630 | return .size; | 1684 | return .size; |
| 1685 | if (std.mem.startsWith(u8, name, "hint")) | ||
| 1686 | return .ord; | ||
| 1631 | return null; | 1687 | return null; |
| 1632 | } | 1688 | } |
| 1633 | 1689 | ||
| ... | @@ -1645,7 +1701,7 @@ const coff = struct { | ... | @@ -1645,7 +1701,7 @@ const coff = struct { |
| 1645 | switch (@typeInfo(field.type)) { | 1701 | switch (@typeInfo(field.type)) { |
| 1646 | .int => try d.w.print("{f} {s}\n", .{ fmtIntField(d, val.*, .{ | 1702 | .int => try d.w.print("{f} {s}\n", .{ fmtIntField(d, val.*, .{ |
| 1647 | .kind = comptime fieldKind(field.name), | 1703 | .kind = comptime fieldKind(field.name), |
| 1648 | .width = 16, | 1704 | .width = .{ .explicit = 16 }, |
| 1649 | }), field.name }), | 1705 | }), field.name }), |
| 1650 | .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field.name, val.* }), | 1706 | .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field.name, val.* }), |
| 1651 | .@"struct" => |s| { | 1707 | .@"struct" => |s| { |
| ... | @@ -1690,7 +1746,9 @@ const usage = | ... | @@ -1690,7 +1746,9 @@ const usage = |
| 1690 | \\Options: | 1746 | \\Options: |
| 1691 | \\ -h, --help Print this help and exit | 1747 | \\ -h, --help Print this help and exit |
| 1692 | \\ --all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols | 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 | \\ --file-headers Display file-format specific headers | 1752 | \\ --file-headers Display file-format specific headers |
| 1695 | \\ --imports Display imported symbols | 1753 | \\ --imports Display imported symbols |
| 1696 | \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2) | 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,6 +113,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 113 | .default => true, | 113 | .default => true, |
| 114 | .hidden, .protected => false, | 114 | .hidden, .protected => false, |
| 115 | }, | 115 | }, |
| 116 | .is_dll_import = @"extern".is_dll_import, | ||
| 116 | .force_pcrel_direct = switch (@"extern".relocation) { | 117 | .force_pcrel_direct = switch (@"extern".relocation) { |
| 117 | .any => false, | 118 | .any => false, |
| 118 | .pcrel => true, | 119 | .pcrel => true, |
| ... | @@ -171,7 +172,13 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -171,7 +172,13 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 171 | switch (lowered_inst.encoding.mnemonic) { | 172 | switch (lowered_inst.encoding.mnemonic) { |
| 172 | .call => { | 173 | .call => { |
| 173 | reloc.target = .{ .branch = target }; | 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 | continue :lowered_inst; | 182 | continue :lowered_inst; |
| 176 | }, | 183 | }, |
| 177 | else => {}, | 184 | else => {}, |
| ... | @@ -247,7 +254,25 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -247,7 +254,25 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 247 | else => unreachable, | 254 | else => unreachable, |
| 248 | } | 255 | } |
| 249 | } else if (emit.bin_file.cast(.coff2)) |_| { | 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 | .lea => try emit.encodeInst(try .new(.none, .lea, &.{ | 276 | .lea => try emit.encodeInst(try .new(.none, .lea, &.{ |
| 252 | lowered_inst.ops[0], | 277 | lowered_inst.ops[0], |
| 253 | .{ .mem = .initRip(.none, 0) }, | 278 | .{ .mem = .initRip(.none, 0) }, |
| ... | @@ -717,6 +742,7 @@ const RelocInfo = struct { | ... | @@ -717,6 +742,7 @@ const RelocInfo = struct { |
| 717 | const Symbol = struct { | 742 | const Symbol = struct { |
| 718 | symbol: link.File.SymbolId, | 743 | symbol: link.File.SymbolId, |
| 719 | is_extern: bool, | 744 | is_extern: bool, |
| 745 | is_dll_import: bool = false, | ||
| 720 | force_pcrel_direct: bool = false, | 746 | force_pcrel_direct: bool = false, |
| 721 | }; | 747 | }; |
| 722 | }; | 748 | }; |
src/link/Coff.zig+18-9| ... | @@ -2103,7 +2103,7 @@ fn initHeaders( | ... | @@ -2103,7 +2103,7 @@ fn initHeaders( |
| 2103 | coff.mf.flags.block_size, | 2103 | coff.mf.flags.block_size, |
| 2104 | .{ .read = true, .initialized = true }, | 2104 | .{ .read = true, .initialized = true }, |
| 2105 | )).symbol(coff).node(coff), | 2105 | )).symbol(coff).node(coff), |
| 2106 | .{ .alignment = .@"4", .moved = true }, | 2106 | .{ .alignment = .@"4" }, |
| 2107 | ); | 2107 | ); |
| 2108 | coff.nodes.appendAssumeCapacity(.import_directory_table); | 2108 | coff.nodes.appendAssumeCapacity(.import_directory_table); |
| 2109 | 2109 | ||
| ... | @@ -6115,6 +6115,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6115,6 +6115,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6115 | const imp_match = std.mem.startsWith(u8, global_name, imp_prefix); | 6115 | const imp_match = std.mem.startsWith(u8, global_name, imp_prefix); |
| 6116 | 6116 | ||
| 6117 | // Globals may have the __imp_ prefix already if they are undef externals from another input. | 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 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) | 6119 | const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) |
| 6119 | .{ gn.name, imp_match } | 6120 | .{ gn.name, imp_match } |
| 6120 | else name: { | 6121 | else name: { |
| ... | @@ -6722,10 +6723,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -6722,10 +6723,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 6722 | try input_symbol.si.flushMoved(coff); | 6723 | try input_symbol.si.flushMoved(coff); |
| 6723 | } | 6724 | } |
| 6724 | }, | 6725 | }, |
| 6725 | .import_directory_table => coff.targetStore( | 6726 | .import_directory_table => { |
| 6726 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, | 6727 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); |
| 6727 | coff.computeNodeRva(ni), | 6728 | if (size > 0) |
| 6728 | ), | 6729 | coff.targetStore( |
| 6730 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, | ||
| 6731 | coff.computeNodeRva(ni), | ||
| 6732 | ); | ||
| 6733 | }, | ||
| 6729 | .import_lookup_table => |import_index| coff.targetStore( | 6734 | .import_lookup_table => |import_index| coff.targetStore( |
| 6730 | &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, | 6735 | &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, |
| 6731 | coff.computeNodeRva(ni), | 6736 | coff.computeNodeRva(ni), |
| ... | @@ -6936,10 +6941,14 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -6936,10 +6941,14 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 6936 | } | 6941 | } |
| 6937 | }, | 6942 | }, |
| 6938 | .input_section => {}, | 6943 | .input_section => {}, |
| 6939 | .import_directory_table => coff.targetStore( | 6944 | .import_directory_table => { |
| 6940 | &coff.dataDirectoryPtr(.IMPORT).size, | 6945 | const prev_size = coff.targetLoad(&coff.dataDirectoryPtr(.IMPORT).size); |
| 6941 | @intCast(size), | 6946 | coff.targetStore( |
| 6942 | ), | 6947 | &coff.dataDirectoryPtr(.IMPORT).size, |
| 6948 | @intCast(size), | ||
| 6949 | ); | ||
| 6950 | if (prev_size == 0) try coff.flushMoved(ni); | ||
| 6951 | }, | ||
| 6943 | .import_lookup_table, | 6952 | .import_lookup_table, |
| 6944 | .import_address_table, | 6953 | .import_address_table, |
| 6945 | .import_hint_name_table, | 6954 | .import_hint_name_table, |
test/link.zig+21-12| ... | @@ -72,6 +72,7 @@ pub fn addCases(ctx: *LinkContext) void { | ... | @@ -72,6 +72,7 @@ pub fn addCases(ctx: *LinkContext) void { |
| 72 | if (ctx.includeTest("dynamic-lib-code")) |case| { | 72 | if (ctx.includeTest("dynamic-lib-code")) |case| { |
| 73 | const lib = case.addLibrary(.dynamic, .{ | 73 | const lib = case.addLibrary(.dynamic, .{ |
| 74 | .name = "lib", | 74 | .name = "lib", |
| 75 | .name_target = false, | ||
| 75 | .zig_source_bytes = | 76 | .zig_source_bytes = |
| 76 | \\export fn foo1() callconv(.c) u64 { | 77 | \\export fn foo1() callconv(.c) u64 { |
| 77 | \\ return 0x1122334411223344; | 78 | \\ return 0x1122334411223344; |
| ... | @@ -91,9 +92,9 @@ pub fn addCases(ctx: *LinkContext) void { | ... | @@ -91,9 +92,9 @@ pub fn addCases(ctx: *LinkContext) void { |
| 91 | if (ctx.target.result.os.tag == .windows) { | 92 | if (ctx.target.result.os.tag == .windows) { |
| 92 | case.verifyObjdump(lib.getEmittedImplib(), &.{ | 93 | case.verifyObjdump(lib.getEmittedImplib(), &.{ |
| 93 | "-s", | 94 | "-s", |
| 94 | "--exports", | 95 | "--exports=sort", |
| 95 | "--only-symbol=foo", | 96 | "--only-symbol=foo", |
| 96 | }, .{ .sub_name = "implib", .os = true }); | 97 | }, .{ .sub_name = "implib", .os = true, .arch = true }); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | const exe = case.addExecutable(.{ | 100 | const exe = case.addExecutable(.{ |
| ... | @@ -118,9 +119,13 @@ pub fn addCases(ctx: *LinkContext) void { | ... | @@ -118,9 +119,13 @@ pub fn addCases(ctx: *LinkContext) void { |
| 118 | if (ctx.includeTest("dynamic-lib-data")) |case| { | 119 | if (ctx.includeTest("dynamic-lib-data")) |case| { |
| 119 | const lib = case.addLibrary(.dynamic, .{ | 120 | const lib = case.addLibrary(.dynamic, .{ |
| 120 | .name = "lib", | 121 | .name = "lib", |
| 122 | .name_target = false, | ||
| 121 | .zig_source_bytes = | 123 | .zig_source_bytes = |
| 122 | \\export var array_foo: [2]u16 = .{ 0xffff, 0xabcd }; | 124 | \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; |
| 123 | \\export var strong_foo: usize = 0x1122334411223344; | 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,20 +136,24 @@ pub fn addCases(ctx: *LinkContext) void { |
| 131 | }, .{}); | 136 | }, .{}); |
| 132 | 137 | ||
| 133 | if (ctx.target.result.os.tag == .windows) { | 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 | const exe = case.addExecutable(.{ | 146 | const exe = case.addExecutable(.{ |
| 138 | .name = "test", | 147 | .name = "test", |
| 139 | .zig_source_bytes = | 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 | \\pub fn main() !u8 { | 149 | \\pub fn main() !u8 { |
| 144 | \\ return @intFromBool(0x2244668822451255 != | 150 | \\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true }); |
| 145 | \\ array_foo[1] + | 151 | \\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true }); |
| 146 | \\ strong_foo + | 152 | \\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true }); |
| 147 | \\ strong_foo_alias); | 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,7 +19,7 @@ xxxxxxxxxxxxxxxx size_of_data |
| 19 | NAME name_type | 19 | NAME name_type |
| 20 | symbol name | foo1 | 20 | symbol name | foo1 |
| 21 | import name | foo1 | 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 | 0 version | 23 | 0 version |
| 24 | 8664 machine (AMD64) | 24 | 8664 machine (AMD64) |
| 25 | 0 time_date_stamp | 25 | 0 time_date_stamp |
| ... | @@ -29,4 +29,4 @@ xxxxxxxxxxxxxxxx size_of_data | ... | @@ -29,4 +29,4 @@ xxxxxxxxxxxxxxxx size_of_data |
| 29 | NAME name_type | 29 | NAME name_type |
| 30 | symbol name | foo2 | 30 | symbol name | foo2 |
| 31 | import name | foo2 | 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,7 +185,8 @@ pub const Case = struct { |
| 185 | if (try snapshotNameInner(w, scope.link_libc, &sep)) | 185 | if (try snapshotNameInner(w, scope.link_libc, &sep)) |
| 186 | try w.writeAll(if (ctx.link_libc) "libc" else "no-libc"); | 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 | try w.writeAll("dmp"); | 190 | try w.writeAll("dmp"); |
| 190 | 191 | ||
| 191 | return try snapshot_name.toOwnedSlice(); | 192 | return try snapshot_name.toOwnedSlice(); |
test/standalone/shared_library/mathtest.zig+2| ... | @@ -1,3 +1,5 @@ | ... | @@ -1,3 +1,5 @@ |
| 1 | export var exported_var: i32 = 9999; | ||
| 2 | |||
| 1 | export fn add(a: i32, b: i32) i32 { | 3 | export fn add(a: i32, b: i32) i32 { |
| 2 | return a + b; | 4 | return a + b; |
| 3 | } | 5 | } |
test/standalone/shared_library/test.c+9| ... | @@ -7,7 +7,16 @@ | ... | @@ -7,7 +7,16 @@ |
| 7 | #include <stdint.h> | 7 | #include <stdint.h> |
| 8 | int32_t add(int32_t a, int32_t b); | 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 | int main(int argc, char **argv) { | 18 | int main(int argc, char **argv) { |
| 11 | assert(add(42, 1337) == 1379); | 19 | assert(add(42, 1337) == 1379); |
| 20 | assert(exported_var == 9999); | ||
| 12 | return 0; | 21 | return 0; |
| 13 | } | 22 | } |