authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:37-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:27:17-04:00
logbd50917c0d86cc45c46cb10868e5e4da6d87c58f
treeb8c878fe0c18af7cdfda239f7ea00a90f0fc1357
parent1b95427715b58cf4cd6df63fc9a7a8d200ca5d47

Coff: emit weak externals


5 files changed, 149 insertions(+), 69 deletions(-)

src/link/Coff.zig+105-22
...@@ -847,7 +847,8 @@ pub const Section = struct {...@@ -847,7 +847,8 @@ pub const Section = struct {
847847
848pub const GlobalName = struct { name: String, lib_name: String.Optional };848pub const GlobalName = struct { name: String, lib_name: String.Optional };
849849
850pub const WeakExternalStrat = enum(u2) {850pub const WeakExternalStrat = enum(u3) {
851 none,
851 no_library,852 no_library,
852 library,853 library,
853 alias,854 alias,
...@@ -880,9 +881,8 @@ pub const Symbol = struct {...@@ -880,9 +881,8 @@ pub const Symbol = struct {
880 extra_tag: ExtraTag,881 extra_tag: ExtraTag,
881 type: Symbol.Type,882 type: Symbol.Type,
882 dll_storage_class: DllStorageClass,883 dll_storage_class: DllStorageClass,
883 // Only defined for .alias_si and .alias_name
884 weak_external_strat: WeakExternalStrat,884 weak_external_strat: WeakExternalStrat,
885 _: u6 = 0,885 _: u5 = 0,
886 },886 },
887 /// Relocations contained within this symbol887 /// Relocations contained within this symbol
888 loc_relocs: Reloc.Index,888 loc_relocs: Reloc.Index,
...@@ -915,12 +915,13 @@ pub const Symbol = struct {...@@ -915,12 +915,13 @@ pub const Symbol = struct {
915 /// don't create their own nodes: .input_section, .import_address_table915 /// don't create their own nodes: .input_section, .import_address_table
916 /// Images only.916 /// Images only.
917 node_offset: u32,917 node_offset: u32,
918 /// This is a weak alias that can replace this symbol918 /// Images: the weak alias that should replace this symbol if it is not resolved.
919 /// Globals only, images only.919 /// Objects: he target of a weak external that hasn't been assigned an sti yet.
920 /// Globals only.
920 weak_alias_si: Symbol.Index,921 weak_alias_si: Symbol.Index,
921 /// For weak externals that have an alias that is also an undef922 /// For weak externals that have an alias that is also an undef
922 /// external, this is the name of the alias global that should923 /// external, this is the name of the alias global that should
923 /// be generated if this symbol is not resolved.924 /// be generated and resolved if this symbol is not resolved.
924 /// Globals only, images only.925 /// Globals only, images only.
925 weak_alias_name: String,926 weak_alias_name: String,
926 /// Index of this symbol in the symbol table927 /// Index of this symbol in the symbol table
...@@ -2096,6 +2097,7 @@ fn initHeaders(...@@ -2096,6 +2097,7 @@ fn initHeaders(
2096 });2097 });
2097 }2098 }
20982099
2100 // TODO: Lazily initialize this instead?
2099 coff.import_table.ni = try coff.mf.addLastChildNode(2101 coff.import_table.ni = try coff.mf.addLastChildNode(
2100 gpa,2102 gpa,
2101 (try coff.objectSectionMapIndex(2103 (try coff.objectSectionMapIndex(
...@@ -2558,6 +2560,16 @@ pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) ?*align(2) s...@@ -2558,6 +2560,16 @@ pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, si: Symbol.Index) ?*align(2) s
2558 }2560 }
2559}2561}
25602562
2563pub fn symbolTableWeakExternalAuxEntryPtr(coff: *Coff, si: Symbol.Index) ?*align(2) std.coff.WeakExternalDefinition {
2564 const sti = si.get(coff).value.sti;
2565 if (symbolTableEntryPtr(coff, sti)) |entry| {
2566 assert(entry.storage_class == .WEAK_EXTERNAL and entry.number_of_aux_symbols == 1);
2567 return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1)));
2568 } else {
2569 return null;
2570 }
2571}
2572
2561pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 {2573pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 {
2562 return @ptrCast(@alignCast(coff.symbol_table.strings_ni.slice(&coff.mf)[0..@sizeOf(u32)]));2574 return @ptrCast(@alignCast(coff.symbol_table.strings_ni.slice(&coff.mf)[0..@sizeOf(u32)]));
2563}2575}
...@@ -2599,7 +2611,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {...@@ -2599,7 +2611,7 @@ fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index {
2599 .extra_tag = .size,2611 .extra_tag = .size,
2600 .type = .unknown,2612 .type = .unknown,
2601 .dll_storage_class = .default,2613 .dll_storage_class = .default,
2602 .weak_external_strat = undefined,2614 .weak_external_strat = .none,
2603 },2615 },
2604 .loc_relocs = .none,2616 .loc_relocs = .none,
2605 .target_relocs = .none,2617 .target_relocs = .none,
...@@ -2686,8 +2698,8 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {...@@ -2686,8 +2698,8 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String {
26862698
2687const GlobalOptions = struct {2699const GlobalOptions = struct {
2688 name: []const u8,2700 name: []const u8,
2689 type: Symbol.Type = .unknown,
2690 lib_name: ?[]const u8 = null,2701 lib_name: ?[]const u8 = null,
2702 type: Symbol.Type = .unknown,
2691 dll_storage_class: Symbol.DllStorageClass = .default,2703 dll_storage_class: Symbol.DllStorageClass = .default,
2692};2704};
26932705
...@@ -2749,13 +2761,14 @@ pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index {...@@ -2749,13 +2761,14 @@ pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index {
2749pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void {2761pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void {
2750 assert(!coff.isImage());2762 assert(!coff.isImage());
2751 const sym = si.get(coff);2763 const sym = si.get(coff);
2752 assert(sym.ni != .none or sym.gmi != .none);2764 if (sym.flags.value_tag == .sti and sym.value.sti != .none)
2765 return;
27532766
2767 assert(sym.ni != .none or sym.gmi != .none);
2754 const gpa = coff.base.comp.gpa;2768 const gpa = coff.base.comp.gpa;
2755 const pending_gop = try coff.symbol_table.pending.getOrPut(gpa, si);2769 const pending_gop = try coff.symbol_table.pending.getOrPut(gpa, si);
2756 if (!pending_gop.found_existing) {2770 if (!pending_gop.found_existing)
2757 coff.symbol_prog_node.increaseEstimatedTotalItems(1);2771 coff.symbol_prog_node.increaseEstimatedTotalItems(1);
2758 }
2759}2772}
27602773
2761fn navSection(2774fn navSection(
...@@ -3040,15 +3053,20 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3040,15 +3053,20 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
30403053
3041 const sym = si.get(coff);3054 const sym = si.get(coff);
3042 assert(sym.ni != .none or sym.gmi != .none);3055 assert(sym.ni != .none or sym.gmi != .none);
3056 const existing_sti = switch (sym.flags.value_tag) {
3057 .sti => sym.value.sti,
3058 .weak_alias_si => .none,
3059 else => unreachable,
3060 };
30433061
3044 const entry = coff.symbolTableEntryPtr(sym.value.sti) orelse entry: {3062 const entry = coff.symbolTableEntryPtr(existing_sti) orelse entry: {
3045 var buf: [15]u8 = undefined;3063 var buf: [15]u8 = undefined;
3046 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =3064 const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType =
3047 if (sym.gmi != .none) blk: {3065 if (sym.gmi != .none) blk: {
3048 const gn = sym.gmi.globalName(coff);3066 const gn = sym.gmi.globalName(coff);
3049 break :blk .{3067 break :blk .{
3050 try coff.getOrPutSymbolName(gn.name.toSlice(coff), gn.name),3068 try coff.getOrPutSymbolName(gn.name.toSlice(coff), gn.name),
3051 0,3069 @intFromBool(sym.flags.weak_external_strat != .none),
3052 if (Symbol.Index.text.get(coff).section_number == sym.section_number)3070 if (Symbol.Index.text.get(coff).section_number == sym.section_number)
3053 .FUNCTION3071 .FUNCTION
3054 else3072 else
...@@ -3102,12 +3120,12 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3102,12 +3120,12 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
31023120
3103 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);3121 const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols);
3104 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;3122 const new_num_symbols = old_num_symbols + 1 + num_aux_symbols;
3123 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);
31053124
3106 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());3125 try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf());
31073126
3108 coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols);3127 const old_value = sym.value;
31093128 sym.setValue(.{ .sti = .wrap(old_num_symbols) });
3110 sym.value.sti = .wrap(old_num_symbols);
3111 si.flushSymbolTableIndex(coff);3129 si.flushSymbolTableIndex(coff);
31123130
3113 const entry = coff.symbolTableEntryPtr(sym.value.sti).?;3131 const entry = coff.symbolTableEntryPtr(sym.value.sti).?;
...@@ -3118,13 +3136,70 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3118,13 +3136,70 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3118 .complex_type = complex_type,3136 .complex_type = complex_type,
3119 .base_type = .NULL,3137 .base_type = .NULL,
3120 };3138 };
3121 entry.storage_class = if (sym.gmi == .none) .STATIC else .EXTERNAL;3139
3140 entry.storage_class = if (sym.flags.extra_tag == .next_alias_si) storage: {
3141 // TODO: Could avoid this ordering issue by flushing these in fifo order, instead of lifo
3142 // TODO: Instead keep a map of si -> sti (remove it from sym.value) and walk in forwards order
3143 // Update any existing aux symbols for weak externals that reference this symbol
3144 var any_weak_external = false;
3145 var alias_sym = sym;
3146 while (alias_sym.flags.extra_tag == .next_alias_si) {
3147 const alias_si = alias_sym.extra.next_alias_si;
3148 alias_sym = alias_si.get(coff);
3149 assert(alias_sym.ni == sym.ni);
3150
3151 if (alias_sym.flags.weak_external_strat != .none) {
3152 switch (alias_sym.flags.value_tag) {
3153 .sti => if (coff.symbolTableWeakExternalAuxEntryPtr(alias_si)) |aux_ptr|
3154 coff.targetStore(&aux_ptr.tag_index, sym.value.sti.unwrap().?),
3155 .weak_alias_si => {},
3156 else => unreachable,
3157 }
3158
3159 any_weak_external = true;
3160 }
3161 }
3162
3163 break :storage if (any_weak_external or sym.gmi != .none) .EXTERNAL else .STATIC;
3164 } else if (sym.gmi == .none)
3165 .STATIC
3166 else
3167 .EXTERNAL;
3168
3122 entry.number_of_aux_symbols = num_aux_symbols;3169 entry.number_of_aux_symbols = num_aux_symbols;
3123 if (coff.targetEndian() != native_endian)3170 if (coff.targetEndian() != native_endian)
3124 std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry);3171 std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry);
31253172
3126 if (num_aux_symbols > 0) aux_init: {3173 if (num_aux_symbols > 0) aux_init: {
3127 if (sym.gmi == .none) switch (coff.getNode(sym.ni)) {3174 if (sym.gmi != .none) {
3175 entry.section_number = .UNDEFINED;
3176 entry.storage_class = .WEAK_EXTERNAL;
3177
3178 const alias_si = old_value.weak_alias_si;
3179 const alias_sym = alias_si.get(coff);
3180 const tag_index = alias_sym.value.sti.unwrap() orelse tag_index: {
3181 // The alias will update `tag_index` when it is flushed
3182 assert(coff.symbol_table.pending.contains(alias_si));
3183 break :tag_index 0;
3184 };
3185
3186 const aux_ptr = coff.symbolTableWeakExternalAuxEntryPtr(si).?;
3187 aux_ptr.* = .{
3188 .tag_index = tag_index,
3189 .flag = switch (sym.flags.weak_external_strat) {
3190 .none => unreachable,
3191 .no_library => .SEARCH_NOLIBRARY,
3192 .library => .SEARCH_LIBRARY,
3193 .alias => .SEARCH_ALIAS,
3194 .anti_dependency => .ANTI_DEPENDENCY,
3195 },
3196 .unused = @splat(0),
3197 };
3198 if (coff.targetEndian() != native_endian)
3199 std.mem.byteSwapAllFields(std.coff.SectionDefinition, .@"2", aux_ptr);
3200
3201 break :aux_init;
3202 } else switch (coff.getNode(sym.ni)) {
3128 .image_section => |sec_si| {3203 .image_section => |sec_si| {
3129 assert(si == sec_si);3204 assert(si == sec_si);
3130 const header = sym.section_number.header(coff);3205 const header = sym.section_number.header(coff);
...@@ -3144,7 +3219,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3144,7 +3219,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3144 break :aux_init;3219 break :aux_init;
3145 },3220 },
3146 else => {},3221 else => {},
3147 };3222 }
31483223
3149 unreachable;3224 unreachable;
3150 }3225 }
...@@ -3153,7 +3228,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void...@@ -3153,7 +3228,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void
3153 };3228 };
31543229
3155 coff.targetStore(&entry.value, switch (sym.section_number) {3230 coff.targetStore(&entry.value, switch (sym.section_number) {
3156 .UNDEFINED => sym.size(),3231 .UNDEFINED => if (entry.storage_class == .WEAK_EXTERNAL) 0 else sym.size(),
3157 .ABSOLUTE,3232 .ABSOLUTE,
3158 .DEBUG,3233 .DEBUG,
3159 => unreachable,3234 => unreachable,
...@@ -6128,6 +6203,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6128,6 +6203,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6128 const opt_alt_search_name = coff.alternate_names.get(search_name);6203 const opt_alt_search_name = coff.alternate_names.get(search_name);
6129 const search_libs = if (is_late) switch (sym.flags.value_tag) {6204 const search_libs = if (is_late) switch (sym.flags.value_tag) {
6130 .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) {6205 .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) {
6206 .none => unreachable,
6131 .no_library => false,6207 .no_library => false,
6132 .library,6208 .library,
6133 .alias,6209 .alias,
...@@ -7199,11 +7275,12 @@ fn updateExportsInner(...@@ -7199,11 +7275,12 @@ fn updateExportsInner(
7199 const exported_ni = exported_si.node(coff);7275 const exported_ni = exported_si.node(coff);
7200 const exported_sym = exported_si.get(coff);7276 const exported_sym = exported_si.get(coff);
7201 var prev_alias_si = exported_si;7277 var prev_alias_si = exported_si;
7278
7202 for (export_indices) |export_index| {7279 for (export_indices) |export_index| {
7203 const @"export" = export_index.ptr(zcu);7280 const @"export" = export_index.ptr(zcu);
7204 const name = @"export".opts.name.toSlice(ip);7281 const name = @"export".opts.name.toSlice(ip);
7205 // TODO: Add an errMsg if this conflicts with an existing global from an input7282
7206 // first_export_si relies on this being a new symbol.7283 // TODO: add an errMsg if this conflicts with an existing global
7207 const export_si = try coff.globalSymbol(.{7284 const export_si = try coff.globalSymbol(.{
7208 .name = name,7285 .name = name,
7209 .lib_name = null,7286 .lib_name = null,
...@@ -7212,8 +7289,14 @@ fn updateExportsInner(...@@ -7212,8 +7289,14 @@ fn updateExportsInner(
7212 export_sym.ni = exported_ni;7289 export_sym.ni = exported_ni;
7213 export_sym.rva = exported_sym.rva;7290 export_sym.rva = exported_sym.rva;
7214 export_sym.section_number = exported_sym.section_number;7291 export_sym.section_number = exported_sym.section_number;
7292 if (@"export".opts.linkage == .weak and !coff.isImage()) {
7293 try coff.pendingSymbolTableEntry(exported_si);
7294 export_sym.flags.weak_external_strat = .alias;
7295 export_sym.setValue(.{ .weak_alias_si = exported_si });
7296 }
7215 defer export_si.applyTargetRelocs(coff, .none) catch unreachable;7297 defer export_si.applyTargetRelocs(coff, .none) catch unreachable;
72167298
7299 // The last symbol in the alias list holds the size
7217 const prev_alias_sym = prev_alias_si.get(coff);7300 const prev_alias_sym = prev_alias_si.get(coff);
7218 switch (prev_alias_sym.flags.extra_tag) {7301 switch (prev_alias_sym.flags.extra_tag) {
7219 .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }),7302 .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }),
test/link.zig+17-15
...@@ -44,7 +44,7 @@ pub fn addCases(ctx: *LinkContext) void {...@@ -44,7 +44,7 @@ pub fn addCases(ctx: *LinkContext) void {
44 "--elements=file-type",44 "--elements=file-type",
45 "--symbols",45 "--symbols",
46 "--only-symbol=foo",46 "--only-symbol=foo",
47 }, .{});47 }, .{ .use_llvm = true });
4848
49 const exe = case.addExecutable(.{49 const exe = case.addExecutable(.{
50 .name = "test",50 .name = "test",
...@@ -192,20 +192,6 @@ pub fn addCases(ctx: *LinkContext) void {...@@ -192,20 +192,6 @@ pub fn addCases(ctx: *LinkContext) void {
192 "--relocs",192 "--relocs",
193 }, .{ .arch = true });193 }, .{ .arch = true });
194194
195 const exe_reloc_err = case.addExecutable(.{
196 .name = "test-reloc-err",
197 .zig_source_bytes =
198 \\extern const foo: usize;
199 \\pub fn main() !u8 {
200 \\ return @intFromBool(foo != 0xcafecafe);
201 \\}
202 ,
203 });
204 exe_reloc_err.root_module.addObject(abs);
205 case.expectLinkErrors(exe_reloc_err, .{
206 .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/",
207 });
208
209 const exe = case.addExecutable(.{195 const exe = case.addExecutable(.{
210 .name = "test",196 .name = "test",
211 .zig_source_bytes =197 .zig_source_bytes =
...@@ -220,6 +206,22 @@ pub fn addCases(ctx: *LinkContext) void {...@@ -220,6 +206,22 @@ pub fn addCases(ctx: *LinkContext) void {
220206
221 const run = case.addRunArtifact(exe);207 const run = case.addRunArtifact(exe);
222 run.addCheck(.{ .expect_term = .{ .exited = 0 } });208 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
209
210 if (!ctx.use_llvm) {
211 const exe_reloc_err = case.addExecutable(.{
212 .name = "test-reloc-err",
213 .zig_source_bytes =
214 \\extern const foo: u32;
215 \\pub fn main() !u8 {
216 \\ return @intFromBool(foo != 0xcafecafe);
217 \\}
218 ,
219 });
220 exe_reloc_err.root_module.addObject(abs);
221 case.expectLinkErrors(exe_reloc_err, .{
222 .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/",
223 });
224 }
223 }225 }
224}226}
225227
test/link/snapshots/dynamic-lib-code.implib-windows.dmp deleted-32
...@@ -1,32 +0,0 @@
1 0 date
2 0 user_id
3 0 group_id
4 0 file_mode
5xxxxxxxxxxxxxxxx size
6 second_linker type
7 | 7 symbols
8 | 5 members
9xxxxxxxx __imp_foo1
10xxxxxxxx __imp_foo2
11xxxxxxxx foo1
12xxxxxxxx foo2
13 0 version
14 8664 machine (AMD64)
15 0 time_date_stamp
16xxxxxxxxxxxxxxxx size_of_data
17 0 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
26xxxxxxxxxxxxxxxx size_of_data
27 0 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/static-lib.llvm.dmp created+15
...@@ -0,0 +1,15 @@
1lib.lib: COFF archive
2lib.lib(obj1.obj): COFF object
3xxxx 00000000 1 NULL() EXTERNAL | fooBar
4xxxx 00000000 2 NULL EXTERNAL | foo1
5xxxx 00000004 2 NULL EXTERNAL | foo2
6lib.lib(this_is_a_long_name.obj): COFF object
7xxxx 00000000 1 NULL() STATIC | this_is_a_long_name.fooWeak
8xxxx 00000000 2 NULL STATIC | this_is_a_long_name.foo_strong
9xxxx 00000008 2 NULL STATIC | this_is_a_long_name.foo_array
10xxxx 00000000 2 NULL EXTERNAL | foo_strong
11xxxx 00000000 2 NULL EXTERNAL | foo_strong_alias
12xxxx 00000008 2 NULL EXTERNAL | foo_array
13xxxx 00000000 UNDEF NULL WEAK_EXTERNAL | fooWeak
14 | Weak External [falls back to 00000025 via SEARCH_ALIAS]
15xxxx 00000000 1 NULL() EXTERNAL | .weak.fooWeak.default.foo_strong
test/link/snapshots/static-lib.no-llvm.dmp created+12
...@@ -0,0 +1,12 @@
1lib.lib: COFF archive
2lib.lib(obj1.obj): COFF object
3xxxx 00000000 1 NULL() EXTERNAL | fooBar
4xxxx 00000000 2 NULL EXTERNAL | foo1
5xxxx 00000004 2 NULL EXTERNAL | foo2
6lib.lib(this_is_a_long_name.obj): COFF object
7xxxx 00000000 UNDEF NULL() WEAK_EXTERNAL | fooWeak
8 | Weak External [falls back to 00000012 via SEARCH_ALIAS]
9xxxx 00000010 2 NULL EXTERNAL | foo_array
10xxxx 00000000 2 NULL EXTERNAL | foo_strong_alias
11xxxx 00000000 2 NULL EXTERNAL | foo_strong
12xxxx 00000000 4 NULL() EXTERNAL | this_is_a_long_name.fooWeak