| ... | @@ -847,7 +847,8 @@ pub const Section = struct { | ... | @@ -847,7 +847,8 @@ pub const Section = struct { |
| 847 | | 847 | |
| 848 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; | 848 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; |
| 849 | | 849 | |
| 850 | pub const WeakExternalStrat = enum(u2) { | 850 | pub 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 symbol | 887 | /// 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_table | 915 | /// 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 symbol | 918 | /// 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 undef | 922 | /// For weak externals that have an alias that is also an undef |
| 922 | /// external, this is the name of the alias global that should | 923 | /// 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 table | 927 | /// Index of this symbol in the symbol table |
| ... | @@ -2096,6 +2097,7 @@ fn initHeaders( | ... | @@ -2096,6 +2097,7 @@ fn initHeaders( |
| 2096 | }); | 2097 | }); |
| 2097 | } | 2098 | } |
| 2098 | | 2099 | |
| | 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 | } |
| 2560 | | 2562 | |
| | 2563 | pub 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 | |
| 2561 | pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 { | 2573 | pub 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 { |
| 2686 | | 2698 | |
| 2687 | const GlobalOptions = struct { | 2699 | const 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 | }; |
| 2693 | | 2705 | |
| ... | @@ -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 { |
| 2749 | pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { | 2761 | pub 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; |
| 2753 | | 2766 | |
| | 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 | } |
| 2760 | | 2773 | |
| 2761 | fn navSection( | 2774 | fn 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 |
| 3040 | | 3053 | |
| 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 | }; |
| 3043 | | 3061 | |
| 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 | .FUNCTION | 3071 | .FUNCTION |
| 3054 | else | 3072 | 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 |
| 3102 | | 3120 | |
| 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); |
| 3105 | | 3124 | |
| 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()); |
| 3107 | | 3126 | |
| 3108 | coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols); | 3127 | const old_value = sym.value; |
| 3109 | | 3128 | sym.setValue(.{ .sti = .wrap(old_num_symbols) }); |
| 3110 | sym.value.sti = .wrap(old_num_symbols); | | |
| 3111 | si.flushSymbolTableIndex(coff); | 3129 | si.flushSymbolTableIndex(coff); |
| 3112 | | 3130 | |
| 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); |
| 3125 | | 3172 | |
| 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 | } |
| 3148 | | 3223 | |
| 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 | }; |
| 3154 | | 3229 | |
| 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 input | 7282 | |
| 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; |
| 7216 | | 7298 | |
| | 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 }), |