| ... | @@ -75,6 +75,8 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct { | ... | @@ -75,6 +75,8 @@ pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct { |
| 75 | alignment: InternPool.Alignment, | 75 | alignment: InternPool.Alignment, |
| 76 | }), | 76 | }), |
| 77 | relocs: std.ArrayList(Reloc), | 77 | relocs: std.ArrayList(Reloc), |
| | 78 | first_free_reloc: Reloc.Index, |
| | 79 | last_free_reloc: Reloc.Index, |
| 78 | const_prog_node: std.Progress.Node, | 80 | const_prog_node: std.Progress.Node, |
| 79 | synth_prog_node: std.Progress.Node, | 81 | synth_prog_node: std.Progress.Node, |
| 80 | symbol_prog_node: std.Progress.Node, | 82 | symbol_prog_node: std.Progress.Node, |
| ... | @@ -1147,10 +1149,14 @@ pub const Reloc = extern struct { | ... | @@ -1147,10 +1149,14 @@ pub const Reloc = extern struct { |
| 1147 | loc: Symbol.Index, | 1149 | loc: Symbol.Index, |
| 1148 | target: Symbol.Index, | 1150 | target: Symbol.Index, |
| 1149 | flags: packed struct(u8) { | 1151 | flags: packed struct(u8) { |
| 1150 | // Indicates the addend is not known and should be recovered from the location itself. | 1152 | /// Indicates the addend is not known and should be recovered from the location itself. |
| 1151 | // COFF relocation tables don't encode the addend, only the location. | 1153 | /// COFF relocation tables don't encode the addend, only the location. |
| 1152 | recover_addend: bool, | 1154 | recover_addend: bool, |
| 1153 | _: u7 = 0, | 1155 | /// Set if this reloc is in the free list. |
| | 1156 | /// When set, `prev` / `next` refer to other relocs in the free list. |
| | 1157 | /// All other fields are undefined. |
| | 1158 | free: bool, |
| | 1159 | _: u6 = 0, |
| 1154 | }, | 1160 | }, |
| 1155 | | 1161 | |
| 1156 | pub const Type = extern union { | 1162 | pub const Type = extern union { |
| ... | @@ -1169,6 +1175,10 @@ pub const Reloc = extern struct { | ... | @@ -1169,6 +1175,10 @@ pub const Reloc = extern struct { |
| 1169 | none = std.math.maxInt(u32), | 1175 | none = std.math.maxInt(u32), |
| 1170 | _, | 1176 | _, |
| 1171 | | 1177 | |
| | 1178 | pub fn wrap(i: ?u32) Reloc.Index { |
| | 1179 | return @enumFromInt((i orelse return .none) + 1); |
| | 1180 | } |
| | 1181 | |
| 1172 | pub fn get(ri: Reloc.Index, coff: *Coff) *Reloc { | 1182 | pub fn get(ri: Reloc.Index, coff: *Coff) *Reloc { |
| 1173 | return &coff.relocs.items[@intFromEnum(ri)]; | 1183 | return &coff.relocs.items[@intFromEnum(ri)]; |
| 1174 | } | 1184 | } |
| ... | @@ -1490,7 +1500,24 @@ pub const Reloc = extern struct { | ... | @@ -1490,7 +1500,24 @@ pub const Reloc = extern struct { |
| 1490 | .none => {}, | 1500 | .none => {}, |
| 1491 | else => |next| next.get(coff).prev = reloc.prev, | 1501 | else => |next| next.get(coff).prev = reloc.prev, |
| 1492 | } | 1502 | } |
| | 1503 | |
| 1493 | reloc.* = undefined; | 1504 | reloc.* = undefined; |
| | 1505 | reloc.flags = .{ |
| | 1506 | .recover_addend = false, |
| | 1507 | .free = true, |
| | 1508 | }; |
| | 1509 | |
| | 1510 | const ri: Reloc.Index = .wrap(@intCast(reloc - coff.relocs.items.ptr)); |
| | 1511 | if (coff.last_free_reloc == .none) { |
| | 1512 | assert(coff.first_free_reloc == .none); |
| | 1513 | coff.first_free_reloc = ri; |
| | 1514 | coff.last_free_reloc = ri; |
| | 1515 | } else { |
| | 1516 | coff.last_free_reloc.get(coff).next = ri; |
| | 1517 | reloc.prev = coff.last_free_reloc; |
| | 1518 | reloc.next = .none; |
| | 1519 | coff.last_free_reloc = ri; |
| | 1520 | } |
| 1494 | } | 1521 | } |
| 1495 | | 1522 | |
| 1496 | comptime { | 1523 | comptime { |
| ... | @@ -1630,6 +1657,8 @@ fn create( | ... | @@ -1630,6 +1657,8 @@ fn create( |
| 1630 | }), | 1657 | }), |
| 1631 | .pending_uavs = .empty, | 1658 | .pending_uavs = .empty, |
| 1632 | .relocs = .empty, | 1659 | .relocs = .empty, |
| | 1660 | .first_free_reloc = .none, |
| | 1661 | .last_free_reloc = .none, |
| 1633 | .const_prog_node = .none, | 1662 | .const_prog_node = .none, |
| 1634 | .synth_prog_node = .none, | 1663 | .synth_prog_node = .none, |
| 1635 | .symbol_prog_node = .none, | 1664 | .symbol_prog_node = .none, |
| ... | @@ -3624,6 +3653,9 @@ const RelocAddend = union(enum) { | ... | @@ -3624,6 +3653,9 @@ const RelocAddend = union(enum) { |
| 3624 | pending: void, | 3653 | pending: void, |
| 3625 | }; | 3654 | }; |
| 3626 | | 3655 | |
| | 3656 | // TODO: There should be an API where the caller can indicate how many contiguous relocs they need |
| | 3657 | // and it should attempt to allocate these from from the free list if available. We can cache |
| | 3658 | // the run length of each segment on Reloc when `free` is set. |
| 3627 | pub fn addReloc( | 3659 | pub fn addReloc( |
| 3628 | coff: *Coff, | 3660 | coff: *Coff, |
| 3629 | loc_si: Symbol.Index, | 3661 | loc_si: Symbol.Index, |
| ... | @@ -3747,6 +3779,7 @@ fn addRelocAssumeCapacity( | ... | @@ -3747,6 +3779,7 @@ fn addRelocAssumeCapacity( |
| 3747 | .addend = if (addend == .pending) 0 else addend.known, | 3779 | .addend = if (addend == .pending) 0 else addend.known, |
| 3748 | .flags = .{ | 3780 | .flags = .{ |
| 3749 | .recover_addend = addend == .pending, | 3781 | .recover_addend = addend == .pending, |
| | 3782 | .free = false, |
| 3750 | }, | 3783 | }, |
| 3751 | }; | 3784 | }; |
| 3752 | switch (target.target_relocs) { | 3785 | switch (target.target_relocs) { |
| ... | @@ -3756,17 +3789,6 @@ fn addRelocAssumeCapacity( | ... | @@ -3756,17 +3789,6 @@ fn addRelocAssumeCapacity( |
| 3756 | target.target_relocs = ri; | 3789 | target.target_relocs = ri; |
| 3757 | } | 3790 | } |
| 3758 | | 3791 | |
| 3759 | // pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { | | |
| 3760 | // const diags = &coff.base.comp.link_diags; | | |
| 3761 | // return coff.loadInputInner(input) catch |err| switch (err) { | | |
| 3762 | // else => |e| return e, | | |
| 3763 | // error.MappedFileIo => return diags.fail( | | |
| 3764 | // "failed to write output file: {t}", | | |
| 3765 | // .{coff.mf.io_err.?}, | | |
| 3766 | // ), | | |
| 3767 | // }; | | |
| 3768 | // } | | |
| 3769 | | | |
| 3770 | fn failLoadInput( | 3792 | fn failLoadInput( |
| 3771 | coff: *Coff, | 3793 | coff: *Coff, |
| 3772 | err: LoadInputError, | 3794 | err: LoadInputError, |
| ... | @@ -5673,6 +5695,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { | ... | @@ -5673,6 +5695,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 5673 | | 5695 | |
| 5674 | var undef_indices: std.ArrayListUnmanaged(u32) = .empty; | 5696 | var undef_indices: std.ArrayListUnmanaged(u32) = .empty; |
| 5675 | for (coff.relocs.items, 0..) |reloc, reloc_i| { | 5697 | for (coff.relocs.items, 0..) |reloc, reloc_i| { |
| | 5698 | if (reloc.flags.free) continue; |
| 5676 | const target_sym = reloc.target.get(coff); | 5699 | const target_sym = reloc.target.get(coff); |
| 5677 | switch (target_sym.ni) { | 5700 | switch (target_sym.ni) { |
| 5678 | .none => { | 5701 | .none => { |
| ... | @@ -7321,13 +7344,6 @@ fn updateExportsInner( | ... | @@ -7321,13 +7344,6 @@ fn updateExportsInner( |
| 7321 | const gpa = zcu.gpa; | 7344 | const gpa = zcu.gpa; |
| 7322 | const ip = &zcu.intern_pool; | 7345 | const ip = &zcu.intern_pool; |
| 7323 | | 7346 | |
| 7324 | switch (exported) { | | |
| 7325 | .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), | | |
| 7326 | .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ | | |
| 7327 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), | | |
| 7328 | Value.fromInterned(uav).fmtValue(pt), | | |
| 7329 | }), | | |
| 7330 | } | | |
| 7331 | try coff.symbols.ensureUnusedCapacity(gpa, export_indices.len); | 7347 | try coff.symbols.ensureUnusedCapacity(gpa, export_indices.len); |
| 7332 | const exported_si: Symbol.Index = switch (exported) { | 7348 | const exported_si: Symbol.Index = switch (exported) { |
| 7333 | .nav => |nav| try coff.navSymbol(zcu, nav), | 7349 | .nav => |nav| try coff.navSymbol(zcu, nav), |
| ... | @@ -7337,6 +7353,14 @@ fn updateExportsInner( | ... | @@ -7337,6 +7353,14 @@ fn updateExportsInner( |
| 7337 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | 7353 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), |
| 7338 | ))), | 7354 | ))), |
| 7339 | }; | 7355 | }; |
| | 7356 | switch (exported) { |
| | 7357 | .nav => |nav| log.debug("updateExports({f}) = {d}", .{ ip.getNav(nav).fqn.fmt(ip), exported_si }), |
| | 7358 | .uav => |uav| log.debug("updateExports(@as({f}, {f})) = {d}", .{ |
| | 7359 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), |
| | 7360 | Value.fromInterned(uav).fmtValue(pt), |
| | 7361 | exported_si, |
| | 7362 | }), |
| | 7363 | } |
| 7340 | while (try coff.resolve(pt.tid)) {} | 7364 | while (try coff.resolve(pt.tid)) {} |
| 7341 | while (try coff.idle(pt.tid)) {} | 7365 | while (try coff.idle(pt.tid)) {} |
| 7342 | | 7366 | |
| ... | @@ -7349,7 +7373,7 @@ fn updateExportsInner( | ... | @@ -7349,7 +7373,7 @@ fn updateExportsInner( |
| 7349 | const @"export" = export_index.ptr(zcu); | 7373 | const @"export" = export_index.ptr(zcu); |
| 7350 | const name = @"export".opts.name.toSlice(ip); | 7374 | const name = @"export".opts.name.toSlice(ip); |
| 7351 | | 7375 | |
| 7352 | // TODO: add an errMsg if this conflicts with an existing global | 7376 | // TODO: add an errMsg if this conflicts with an existing symbol |
| 7353 | const export_si = try coff.globalSymbol(.{ | 7377 | const export_si = try coff.globalSymbol(.{ |
| 7354 | .name = name, | 7378 | .name = name, |
| 7355 | .lib_name = null, | 7379 | .lib_name = null, |
| ... | @@ -7360,7 +7384,7 @@ fn updateExportsInner( | ... | @@ -7360,7 +7384,7 @@ fn updateExportsInner( |
| 7360 | export_sym.section_number = exported_sym.section_number; | 7384 | export_sym.section_number = exported_sym.section_number; |
| 7361 | if (@"export".opts.linkage == .weak and !coff.isImage()) { | 7385 | if (@"export".opts.linkage == .weak and !coff.isImage()) { |
| 7362 | // exported_si needs to be ahead of export_si in the symbol table, | 7386 | // exported_si needs to be ahead of export_si in the symbol table, |
| 7363 | // so that its sti is known when creating the aux entry | 7387 | // so that its sti is known when creating the weak external aux entry |
| 7364 | try coff.pendingSymbolTableEntry(exported_si); | 7388 | try coff.pendingSymbolTableEntry(exported_si); |
| 7365 | export_sym.flags.weak_external_strat = .alias; | 7389 | export_sym.flags.weak_external_strat = .alias; |
| 7366 | export_sym.setValue(.{ .weak_alias_si = exported_si }); | 7390 | export_sym.setValue(.{ .weak_alias_si = exported_si }); |
| ... | @@ -7371,6 +7395,8 @@ fn updateExportsInner( | ... | @@ -7371,6 +7395,8 @@ fn updateExportsInner( |
| 7371 | const prev_alias_sym = prev_alias_si.get(coff); | 7395 | const prev_alias_sym = prev_alias_si.get(coff); |
| 7372 | switch (prev_alias_sym.flags.extra_tag) { | 7396 | switch (prev_alias_sym.flags.extra_tag) { |
| 7373 | .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }), | 7397 | .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }), |
| | 7398 | // This export should have been deleted |
| | 7399 | .next_alias_si => assert(prev_alias_sym.extra.next_alias_si == export_si), |
| 7374 | else => unreachable, | 7400 | else => unreachable, |
| 7375 | } | 7401 | } |
| 7376 | | 7402 | |
| ... | @@ -7474,10 +7500,21 @@ fn updateExportsInner( | ... | @@ -7474,10 +7500,21 @@ fn updateExportsInner( |
| 7474 | } | 7500 | } |
| 7475 | } | 7501 | } |
| 7476 | | 7502 | |
| 7477 | pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { | 7503 | pub fn deleteExport( |
| 7478 | _ = coff; | 7504 | coff: *Coff, |
| 7479 | _ = exported; | 7505 | exported: Zcu.Exported, |
| 7480 | _ = name; | 7506 | name: InternPool.NullTerminatedString, |
| | 7507 | ) void { |
| | 7508 | const zcu = coff.base.comp.zcu.?; |
| | 7509 | const ip = &zcu.intern_pool; |
| | 7510 | |
| | 7511 | const exported_si: Symbol.Index = switch (exported) { |
| | 7512 | .nav => |nav| coff.navs.get(nav).?, |
| | 7513 | .uav => |uav| coff.uavs.get(uav).?, |
| | 7514 | }; |
| | 7515 | |
| | 7516 | const name_slice = name.toSlice(ip); |
| | 7517 | log.debug("deleteExport({s}, {d})", .{ name_slice, exported_si }); |
| 7481 | | 7518 | |
| 7482 | // TODO: Delete from first / second linker member table | 7519 | // TODO: Delete from first / second linker member table |
| 7483 | // TODO: Delete from symbol table inside section | 7520 | // TODO: Delete from symbol table inside section |