| ... | ... | @@ -847,7 +847,8 @@ pub const Section = struct { |
| 847 | 847 | |
| 848 | 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 | 852 | no_library, |
| 852 | 853 | library, |
| 853 | 854 | alias, |
| ... | ... | @@ -880,9 +881,8 @@ pub const Symbol = struct { |
| 880 | 881 | extra_tag: ExtraTag, |
| 881 | 882 | type: Symbol.Type, |
| 882 | 883 | dll_storage_class: DllStorageClass, |
| 883 | | // Only defined for .alias_si and .alias_name |
| 884 | 884 | weak_external_strat: WeakExternalStrat, |
| 885 | | _: u6 = 0, |
| 885 | _: u5 = 0, |
| 886 | 886 | }, |
| 887 | 887 | /// Relocations contained within this symbol |
| 888 | 888 | loc_relocs: Reloc.Index, |
| ... | ... | @@ -915,12 +915,13 @@ pub const Symbol = struct { |
| 915 | 915 | /// don't create their own nodes: .input_section, .import_address_table |
| 916 | 916 | /// Images only. |
| 917 | 917 | node_offset: u32, |
| 918 | | /// This is a weak alias that can replace this symbol |
| 919 | | /// Globals only, images only. |
| 918 | /// Images: the weak alias that should replace this symbol if it is not resolved. |
| 919 | /// Objects: he target of a weak external that hasn't been assigned an sti yet. |
| 920 | /// Globals only. |
| 920 | 921 | weak_alias_si: Symbol.Index, |
| 921 | 922 | /// For weak externals that have an alias that is also an undef |
| 922 | 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 | 925 | /// Globals only, images only. |
| 925 | 926 | weak_alias_name: String, |
| 926 | 927 | /// Index of this symbol in the symbol table |
| ... | ... | @@ -2096,6 +2097,7 @@ fn initHeaders( |
| 2096 | 2097 | }); |
| 2097 | 2098 | } |
| 2098 | 2099 | |
| 2100 | // TODO: Lazily initialize this instead? |
| 2099 | 2101 | coff.import_table.ni = try coff.mf.addLastChildNode( |
| 2100 | 2102 | gpa, |
| 2101 | 2103 | (try coff.objectSectionMapIndex( |
| ... | ... | @@ -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 | 2573 | pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 { |
| 2562 | 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 | 2611 | .extra_tag = .size, |
| 2600 | 2612 | .type = .unknown, |
| 2601 | 2613 | .dll_storage_class = .default, |
| 2602 | | .weak_external_strat = undefined, |
| 2614 | .weak_external_strat = .none, |
| 2603 | 2615 | }, |
| 2604 | 2616 | .loc_relocs = .none, |
| 2605 | 2617 | .target_relocs = .none, |
| ... | ... | @@ -2686,8 +2698,8 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 2686 | 2698 | |
| 2687 | 2699 | const GlobalOptions = struct { |
| 2688 | 2700 | name: []const u8, |
| 2689 | | type: Symbol.Type = .unknown, |
| 2690 | 2701 | lib_name: ?[]const u8 = null, |
| 2702 | type: Symbol.Type = .unknown, |
| 2691 | 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 | 2761 | pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { |
| 2750 | 2762 | assert(!coff.isImage()); |
| 2751 | 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 | 2768 | const gpa = coff.base.comp.gpa; |
| 2755 | 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 | 2771 | coff.symbol_prog_node.increaseEstimatedTotalItems(1); |
| 2758 | | } |
| 2759 | 2772 | } |
| 2760 | 2773 | |
| 2761 | 2774 | fn navSection( |
| ... | ... | @@ -3040,15 +3053,20 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 3040 | 3053 | |
| 3041 | 3054 | const sym = si.get(coff); |
| 3042 | 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 | 3063 | var buf: [15]u8 = undefined; |
| 3046 | 3064 | const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType = |
| 3047 | 3065 | if (sym.gmi != .none) blk: { |
| 3048 | 3066 | const gn = sym.gmi.globalName(coff); |
| 3049 | 3067 | break :blk .{ |
| 3050 | 3068 | try coff.getOrPutSymbolName(gn.name.toSlice(coff), gn.name), |
| 3051 | | 0, |
| 3069 | @intFromBool(sym.flags.weak_external_strat != .none), |
| 3052 | 3070 | if (Symbol.Index.text.get(coff).section_number == sym.section_number) |
| 3053 | 3071 | .FUNCTION |
| 3054 | 3072 | else |
| ... | ... | @@ -3102,12 +3120,12 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 3102 | 3120 | |
| 3103 | 3121 | const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols); |
| 3104 | 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 | 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); |
| 3109 | | |
| 3110 | | sym.value.sti = .wrap(old_num_symbols); |
| 3127 | const old_value = sym.value; |
| 3128 | sym.setValue(.{ .sti = .wrap(old_num_symbols) }); |
| 3111 | 3129 | si.flushSymbolTableIndex(coff); |
| 3112 | 3130 | |
| 3113 | 3131 | const entry = coff.symbolTableEntryPtr(sym.value.sti).?; |
| ... | ... | @@ -3118,13 +3136,70 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 3118 | 3136 | .complex_type = complex_type, |
| 3119 | 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 | 3169 | entry.number_of_aux_symbols = num_aux_symbols; |
| 3123 | 3170 | if (coff.targetEndian() != native_endian) |
| 3124 | 3171 | std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry); |
| 3125 | 3172 | |
| 3126 | 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 | 3203 | .image_section => |sec_si| { |
| 3129 | 3204 | assert(si == sec_si); |
| 3130 | 3205 | const header = sym.section_number.header(coff); |
| ... | ... | @@ -3144,7 +3219,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 3144 | 3219 | break :aux_init; |
| 3145 | 3220 | }, |
| 3146 | 3221 | else => {}, |
| 3147 | | }; |
| 3222 | } |
| 3148 | 3223 | |
| 3149 | 3224 | unreachable; |
| 3150 | 3225 | } |
| ... | ... | @@ -3153,7 +3228,7 @@ fn flushSymbolTableEntry(coff: *Coff, si: Symbol.Index, pt: Zcu.PerThread) !void |
| 3153 | 3228 | }; |
| 3154 | 3229 | |
| 3155 | 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 | 3232 | .ABSOLUTE, |
| 3158 | 3233 | .DEBUG, |
| 3159 | 3234 | => unreachable, |
| ... | ... | @@ -6128,6 +6203,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6128 | 6203 | const opt_alt_search_name = coff.alternate_names.get(search_name); |
| 6129 | 6204 | const search_libs = if (is_late) switch (sym.flags.value_tag) { |
| 6130 | 6205 | .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) { |
| 6206 | .none => unreachable, |
| 6131 | 6207 | .no_library => false, |
| 6132 | 6208 | .library, |
| 6133 | 6209 | .alias, |
| ... | ... | @@ -7199,11 +7275,12 @@ fn updateExportsInner( |
| 7199 | 7275 | const exported_ni = exported_si.node(coff); |
| 7200 | 7276 | const exported_sym = exported_si.get(coff); |
| 7201 | 7277 | var prev_alias_si = exported_si; |
| 7278 | |
| 7202 | 7279 | for (export_indices) |export_index| { |
| 7203 | 7280 | const @"export" = export_index.ptr(zcu); |
| 7204 | 7281 | const name = @"export".opts.name.toSlice(ip); |
| 7205 | | // TODO: Add an errMsg if this conflicts with an existing global from an input |
| 7206 | | // first_export_si relies on this being a new symbol. |
| 7282 | |
| 7283 | // TODO: add an errMsg if this conflicts with an existing global |
| 7207 | 7284 | const export_si = try coff.globalSymbol(.{ |
| 7208 | 7285 | .name = name, |
| 7209 | 7286 | .lib_name = null, |
| ... | ... | @@ -7212,8 +7289,14 @@ fn updateExportsInner( |
| 7212 | 7289 | export_sym.ni = exported_ni; |
| 7213 | 7290 | export_sym.rva = exported_sym.rva; |
| 7214 | 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 | 7297 | defer export_si.applyTargetRelocs(coff, .none) catch unreachable; |
| 7216 | 7298 | |
| 7299 | // The last symbol in the alias list holds the size |
| 7217 | 7300 | const prev_alias_sym = prev_alias_si.get(coff); |
| 7218 | 7301 | switch (prev_alias_sym.flags.extra_tag) { |
| 7219 | 7302 | .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }), |